├── GameData
└── ConfigurableContainers
│ ├── Parts
│ ├── Models
│ │ ├── blue.png
│ │ ├── grey.png
│ │ ├── brown.png
│ │ ├── green.png
│ │ ├── orange.png
│ │ ├── warning.png
│ │ ├── dark-green.png
│ │ ├── light-blue.png
│ │ └── light-grey.png
│ ├── B9_Aerospace_ProceduralWings_Patch.cfg
│ ├── DodoLabs_Patch.cfg
│ ├── Mk3HypersonicSystems_Patch.cfg
│ ├── Benjee10_X-37B_Patch.cfg
│ ├── KerboNerdLaboratories.cfg
│ ├── MiningExpansion_Patch.cfg
│ ├── SpaceY-Lifters_Patch.cfg
│ ├── Mk2Expansion_Patch.cfg
│ ├── PlanetaryBaseInc_Patch.cfg
│ ├── SpaceY-Expanded_Patch.cfg
│ ├── ModRocketSys_Patch.cfg
│ ├── MakingHistory_Patch.cfg
│ └── NearFuturePropulsion_Patch.cfg
│ ├── GPO_Patch.cfg
│ └── ConfigurableContainers.version
├── CC.UI
├── Assets
│ ├── icons.meta
│ ├── Prefabs
│ │ ├── TankControls.prefab.meta
│ │ └── TankManagerUI.prefab.meta
│ ├── ConfigurableContainers.unity.meta
│ └── Prefabs.meta
├── cc_ui.bundle_bundle.xml.meta
├── cc_ui.bundle_bundle.xml
├── Interfaces
│ ├── ITankInfo.cs
│ └── ITankManager.cs
├── AssemblyInfo.cs
├── TankManagerUI.cs
├── CC.UI.csproj
├── TestTankInfo.cs
├── TankConfigsControl.cs
├── AddTankControl.cs
└── TankControlsUI.cs
├── .gitignore
├── modconfig.yaml
├── IntrusivePatches
├── CC_INTRUSIVE_PATCHES.md
└── GameData
│ └── ConfigurableContainers
│ └── IntrusivePatches
│ └── B9Parts_Patch.cfg
├── LICENSE
├── ConfigurableContainers-Intrusive.netkan
├── Properties
└── AssemblyInfo.cs
├── ConfigurableContainers.netkan
├── SwitchableTankManagerUI.cs
├── README.md
├── Cryogenics
├── ActiveCooling.cs
├── CryogenicsParams.cs
└── ResourceBoiloff.cs
├── AbstractResourceTank.cs
├── VolumeConfigsLibrary.cs
├── ChangeLog.md
├── ModuleTankManager.cs
├── ConfigurableContainers.csproj
├── VolumeConfiguration.cs
└── SwitchableTankType.cs
/GameData/ConfigurableContainers/Parts/Models/blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/allista/ConfigurableContainers/HEAD/GameData/ConfigurableContainers/Parts/Models/blue.png
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/Models/grey.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/allista/ConfigurableContainers/HEAD/GameData/ConfigurableContainers/Parts/Models/grey.png
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/Models/brown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/allista/ConfigurableContainers/HEAD/GameData/ConfigurableContainers/Parts/Models/brown.png
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/Models/green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/allista/ConfigurableContainers/HEAD/GameData/ConfigurableContainers/Parts/Models/green.png
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/Models/orange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/allista/ConfigurableContainers/HEAD/GameData/ConfigurableContainers/Parts/Models/orange.png
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/Models/warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/allista/ConfigurableContainers/HEAD/GameData/ConfigurableContainers/Parts/Models/warning.png
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/Models/dark-green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/allista/ConfigurableContainers/HEAD/GameData/ConfigurableContainers/Parts/Models/dark-green.png
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/Models/light-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/allista/ConfigurableContainers/HEAD/GameData/ConfigurableContainers/Parts/Models/light-blue.png
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/Models/light-grey.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/allista/ConfigurableContainers/HEAD/GameData/ConfigurableContainers/Parts/Models/light-grey.png
--------------------------------------------------------------------------------
/CC.UI/Assets/icons.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 2c1e5a23a39c23fa3b4bea2d4d4ac036
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/CC.UI/cc_ui.bundle_bundle.xml.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d9d8303196052210bb4dde82f012e83f
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName: cc_ui.bundle
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/CC.UI/Assets/Prefabs/TankControls.prefab.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 745de9f96f0d14ff198644051c2d750f
3 | PrefabImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName: cc_ui.bundle
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/CC.UI/Assets/Prefabs/TankManagerUI.prefab.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0c932d60b9a184fa592392518f4bfb41
3 | PrefabImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName: cc_ui.bundle
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #should it start with a comment?
2 | *~
3 | *.mdb
4 | *.dll
5 | .idea
6 | obj
7 | Releases
8 | Screenshots
9 | /GameData/ConfigurableContainers/VolumeConfigs.user
10 | /CC.UI/CC.UI.csproj.DotSettings
11 | /GameData/ConfigurableContainers/Parts/@thumbs
12 |
--------------------------------------------------------------------------------
/CC.UI/Assets/ConfigurableContainers.unity.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9f9188a84a24046d7beab5a833b33c22
3 | timeCreated: 1541940155
4 | licenseType: Free
5 | DefaultImporter:
6 | externalObjects: {}
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/CC.UI/Assets/Prefabs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6ecb38cd66d8a492bbca117c22b62f03
3 | folderAsset: yes
4 | timeCreated: 1542002145
5 | licenseType: Free
6 | DefaultImporter:
7 | externalObjects: {}
8 | userData:
9 | assetBundleName:
10 | assetBundleVariant:
11 |
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/GPO_Patch.cfg:
--------------------------------------------------------------------------------
1 | @PART[*]:NEEDS[GPOSpeedFuelPump]:HAS[@MODULE[ModuleTankManager],!MODULE[GPOSpeedPump]]:FINAL
2 | {
3 | MODULE
4 | {
5 | name = GPOSpeedPump
6 | }
7 | }
8 |
9 | @PART[*]:NEEDS[GPOSpeedFuelPump]:HAS[@MODULE[ModuleSwitchableTank],!MODULE[GPOSpeedPump]]:FINAL
10 | {
11 | MODULE
12 | {
13 | name = GPOSpeedPump
14 | }
15 | }
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/B9_Aerospace_ProceduralWings_Patch.cfg:
--------------------------------------------------------------------------------
1 | // B9 Procedural Wings conversion
2 |
3 | @PART[B9_Aero_Wing_Procedural_TypeA]:NEEDS[B9_Aerospace_ProceduralWings&!modularFuelTanks&!RealFuels]:AFTER[B9_Aerospace_ProceduralWings]
4 | {
5 | //tankless manager mimics the behaviour of the B9-PW builtin fuel switcher which,
6 | //by default, does not include any resource
7 | MODULE
8 | {
9 | name = ModuleTankManager
10 | Volume = 3.84
11 | DoCostPatch = True
12 | DoMassPatch = True
13 | IncludeTankTypes = LiquidChemicals
14 | }
15 | }
16 | //:mode=c#:
17 |
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/ConfigurableContainers.version:
--------------------------------------------------------------------------------
1 | {
2 | "NAME":"ConfigurableContainers",
3 | "URL":"https://github.com/allista/ConfigurableContainers/tree/master/GameData/ConfigurableContainers/ConfigurableContainers.version",
4 | "DOWNLOAD":"https://spacedock.info/mod/1002/Configurable%20Containers",
5 | "CHANGE_LOG_URL":"",
6 | "VERSION":
7 | {
8 | "MAJOR":2,
9 | "MINOR":6,
10 | "PATCH":2,
11 | "BUILD":1
12 | },
13 | "KSP_VERSION_MIN":
14 | {
15 | "MAJOR":1,
16 | "MINOR":12,
17 | "PATCH":3
18 | },
19 | "KSP_VERSION_MAX":
20 | {
21 | "MAJOR":1,
22 | "MINOR":12,
23 | "PATCH":3
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/modconfig.yaml:
--------------------------------------------------------------------------------
1 | dll_path: ../GameData/000_AT_Utils/Plugins/ConfigurableContainers.dll
2 | archive_path: Releases
3 | github_url: allista/ConfigurableContainers
4 | spacedock_mod_id: 1002
5 | game_data_path: GameData
6 | additional_data_paths:
7 | - '../GameData'
8 | - 'IntrusivePatches'
9 | exclude_patterns:
10 | - '*/@thumbs/*'
11 | - '*/config.xml'
12 | - '*.user'
13 | - '*.orig'
14 | - '*.mdb'
15 | - '*.pdb'
16 | - '*/System.*.dll'
17 | - '*/Mono.*.dll'
18 | - '*/Unity*.dll'
19 | - 'GameData/000_AT_Utils/Plugins/AnimatedConverters.dll'
20 | - 'GameData/000_AT_Utils/Plugins/002_MultiAnimators.dll'
21 | - 'GameData/000_AT_Utils/Plugins/SubmodelResizer.dll'
22 | - 'GameData/000_AT_Utils/ResourceHack.cfg'
23 |
--------------------------------------------------------------------------------
/CC.UI/cc_ui.bundle_bundle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Allis Tauri
4 | allista@gmail.com
5 |
6 |
7 |
8 |
9 |
10 | at_utils_ui.bundle
11 |
12 |
--------------------------------------------------------------------------------
/IntrusivePatches/CC_INTRUSIVE_PATCHES.md:
--------------------------------------------------------------------------------
1 | # Intrusive Patches of Configurable Containers
2 |
3 | Intrusive patches are a set of Module Manager patches that remove other fuel switcher modules (like InterstellarFuelSwitch, FSFuelSwitch) or modify their configs (like removing fuel switching from B9PartSwitch) from many/all parts and replace them with the Configurable Containers' ones.
4 |
5 | You should use these with care on a progressed game with many ships in flight, because such transition is never fully reversible. That is, if you include these patches and then decide to remove them, your in-flight ships will not be returned to the _exact_ state they were in before.
6 |
7 | So I can't say it emphatically enough:
8 |
9 | **!!! BACKUP YOUR SAVES !!!**
10 |
11 | Having said that, I want to ensure you I do whatever I can to make the use of these patches safe. And generally it *is* indeed safe.
12 |
--------------------------------------------------------------------------------
/CC.UI/Interfaces/ITankInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace CC.UI
4 | {
5 | public interface ITankInfo
6 | {
7 | ITankManager Manager { get; }
8 | string TankType { get; }
9 |
10 | IList SupportedResources { get; }
11 | IList SupportedTypes { get; }
12 | string CurrentResource { get; }
13 | bool Valid { get; }
14 |
15 | float Volume { get; }
16 |
17 | double Amount { get; }
18 | double MaxAmount { get; }
19 | float ResourceDensity { get; }
20 |
21 |
22 | float ResourceAmountInVolume(float volume);
23 | float VolumeForResourceAmount(float amount);
24 | void SetVolume(float volume, bool update_amount);
25 | void ChangeTankType(string tankTypeName);
26 | void ChangeResource(string resourceName);
27 | void SetAmount(float newAmount);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/CC.UI/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | // General Information about an assembly is controlled through the following
4 | // set of attributes. Change these attribute values to modify the information
5 | // associated with an assembly.
6 | [assembly: AssemblyTitle("CC.UI")]
7 | [assembly: AssemblyDescription("UI logic assembly")]
8 | [assembly: AssemblyConfiguration("")]
9 | [assembly: AssemblyCompany("")]
10 | [assembly: AssemblyProduct("CC.UI")]
11 | [assembly: AssemblyCopyright("Copyright © Allis Tauri 2020")]
12 | [assembly: AssemblyTrademark("")]
13 | [assembly: AssemblyCulture("")]
14 |
15 | // Version information for an assembly consists of the following four values:
16 | //
17 | // Major Version
18 | // Minor Version
19 | // Build Number
20 | // Revision
21 | //
22 | // You can specify all the values or you can default the Build and Revision Numbers
23 | // by using the '*' as shown below:
24 | // [assembly: AssemblyVersion("1.0.*")]
25 | #if NIGHTBUILD
26 | [assembly: AssemblyVersion("1.0.*")]
27 | #else
28 | [assembly: AssemblyVersion("1.0.0.0")]
29 | #endif
30 |
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Allis Tauri
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/CC.UI/Interfaces/ITankManager.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace CC.UI
4 | {
5 | public interface ITankManagerCapabilities
6 | {
7 | bool AddRemoveEnabled { get; }
8 | bool ConfirmRemove { get; }
9 | bool TypeChangeEnabled { get; }
10 | bool VolumeChangeEnabled { get; }
11 | bool FillEnabled { get; }
12 | bool EmptyEnabled { get; }
13 | }
14 |
15 | public interface ITankManager
16 | {
17 | string Title { get; }
18 | IList SupportedTypes { get; }
19 | IList SupportedTankConfigs { get; }
20 | float Volume { get; }
21 | float AvailableVolume { get; }
22 | IReadOnlyCollection Tanks { get; }
23 | ITankManagerCapabilities Capabilities { get; }
24 |
25 | string OnVolumeChanged(string tankType, float volume);
26 |
27 | string GetTypeInfo(string tankType);
28 |
29 | bool AddTank(string tankType, float volume);
30 | bool RemoveTank(ITankInfo tank);
31 |
32 | bool AddTankConfig(string configName);
33 | bool RemoveTankConfig(string configName);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/ConfigurableContainers-Intrusive.netkan:
--------------------------------------------------------------------------------
1 | {
2 | "spec_version" : "v1.4",
3 | "identifier" : "ConfigurableContainers-Intrusive",
4 | "name" : "Configurable Containers Intrusive Patches",
5 | "$kref" : "#/ckan/spacedock/1002",
6 | "abstract" : "This set of patches converts parts that use other fuel switchers to Configurable Containers framework.",
7 | "author" : [ "allista" ],
8 | "license" : "MIT",
9 |
10 | "resources":
11 | {
12 | "homepage" : "http://forum.kerbalspaceprogram.com/index.php?/topic/150104-12-configurable-containers",
13 | "bugtracker" : "https://github.com/allista/ConfigurableContainers/issues",
14 | "repository" : "https://github.com/allista/ConfigurableContainers"
15 | },
16 |
17 | "depends":
18 | [
19 | { "name": "ModuleManager" },
20 | { "name": "AT-Utils" }
21 | ],
22 |
23 | "supports":
24 | [
25 | { "name": "B9" },
26 | { "name": "B9AerospaceHX" }
27 | ],
28 |
29 | "install":
30 | [
31 | {
32 | "file": "IntrusivePatches/GameData/ConfigurableContainers",
33 | "install_to": "GameData"
34 | }
35 | ]
36 | }
37 |
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/DodoLabs_Patch.cfg:
--------------------------------------------------------------------------------
1 | //Configurable Containers patch for DodoLabs
2 |
3 | //Rocket Fuel Tanks
4 | //Automatically generated using PyKSPutils library
5 | @PART[emutank2]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[DodoLabs]
6 | {
7 | !RESOURCE[LiquidFuel]
8 | {
9 |
10 | }
11 | !RESOURCE[Oxidizer]
12 | {
13 |
14 | }
15 | MODULE
16 | {
17 | name = ModuleTankManager
18 | Volume = 1.111111 //81.0 units of LF: conversion rate is 0.013717 m3/u
19 | DoCostPatch = True
20 | DoMassPatch = True
21 | TANK
22 | {
23 | name = LFO
24 | Volume = 100.0
25 | }
26 | }
27 | }
28 |
29 | @PART[emutank1]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[DodoLabs]
30 | {
31 | !RESOURCE[LiquidFuel]
32 | {
33 |
34 | }
35 | !RESOURCE[Oxidizer]
36 | {
37 |
38 | }
39 | MODULE
40 | {
41 | name = ModuleTankManager
42 | Volume = 4.444444 //324.0 units of LF: conversion rate is 0.013717 m3/u
43 | DoCostPatch = True
44 | DoMassPatch = True
45 | TANK
46 | {
47 | name = LFO
48 | Volume = 100.0
49 | }
50 | }
51 | }
52 | //:mode=c#:
53 |
--------------------------------------------------------------------------------
/IntrusivePatches/GameData/ConfigurableContainers/IntrusivePatches/B9Parts_Patch.cfg:
--------------------------------------------------------------------------------
1 | // Patch B9 and B9 HX Parts with fuel
2 | @PART[*B9*]:HAS[@MODULE[ModuleB9PartSwitch]:HAS[#baseVolume[>0]]]:NEEDS[B9_Aerospace|B9_Aerospace_HX]:FINAL
3 | {
4 | MODULE
5 | {
6 | name = ModuleTankManager
7 | Volume = #$../MODULE[ModuleB9PartSwitch]/baseVolume$
8 | @Volume *= 0.00578038 //923747740083 (extra digits that I took out)
9 | DoCostPatch = True
10 | DoMassPatch = True
11 | TANK
12 | {
13 | name = LFO //I'm thinking the default should be really be liquid fuel but I'm not sure,
14 | Volume = 100.0
15 | }
16 | }
17 |
18 | @MODULE[ModuleB9PartSwitch],*
19 | {
20 | @SUBTYPE[*],*
21 | {
22 | !tankType = DEL // Get rid of the B9PartSwitch fuel switch without deleting the texture switching and creating weird z-fighting issues
23 | }
24 | }
25 | }
26 | //For the cockpits with monoprop
27 | @PART[*B9*]:HAS[@MODULE[ModuleCommand]&@RESOURCE[MonoPropellant]]:NEEDS[B9_Aerospace]
28 | {
29 | MODULE
30 | {
31 | name = ModuleSwitchableTank
32 | Volume = #$../RESOURCE[MonoPropellant]/maxAmount$
33 | @Volume *= .002717 //now fixed to not be 1,000 times too high
34 | InitialAmount = 0.0
35 | DoCostPatch = True
36 | DoMassPatch = True
37 | ChooseTankType = True
38 | TankType = LiquidChemicals
39 | CurrentResource = MonoPropellant
40 | }
41 | !RESOURCE[MonoPropellant] {}
42 | }
43 |
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/Mk3HypersonicSystems_Patch.cfg:
--------------------------------------------------------------------------------
1 | //Configurable Containers patch for Mk3HypersonicSystems
2 |
3 | //LiquidFuel Tanks
4 | //Automatically generated using PyKSPutils library
5 | @PART[Mk3LiftingBodyEdge]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[Mk3HypersonicSystems]
6 | {
7 | !RESOURCE[LiquidFuel]
8 | {
9 |
10 | }
11 | MODULE
12 | {
13 | name = ModuleTankManager
14 | Volume = 0.925926 //150.0 units of LiquidFuel: conversion rate is 0.006173 m3/u
15 | DoCostPatch = True
16 | DoMassPatch = True
17 | TANK
18 | {
19 | TankType = LiquidChemicals
20 | CurrentResource = LiquidFuel
21 | InitialAmount = 1.0
22 | Volume = 100.0
23 | }
24 | }
25 | }
26 |
27 | @PART[Mk3EdgeRootExtension]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[Mk3HypersonicSystems]
28 | {
29 | !RESOURCE[LiquidFuel]
30 | {
31 |
32 | }
33 | MODULE
34 | {
35 | name = ModuleTankManager
36 | Volume = 0.555556 //90.0 units of LiquidFuel: conversion rate is 0.006173 m3/u
37 | DoCostPatch = True
38 | DoMassPatch = True
39 | TANK
40 | {
41 | TankType = LiquidChemicals
42 | CurrentResource = LiquidFuel
43 | InitialAmount = 1.0
44 | Volume = 100.0
45 | }
46 | }
47 | }
48 | //:mode=c#:
49 |
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/Benjee10_X-37B_Patch.cfg:
--------------------------------------------------------------------------------
1 | //Configurable Containers patch for Benjee10_X-37B
2 |
3 | //Rocket Fuel Tanks
4 | //Automatically generated using PyKSPutils library
5 | @PART[x-37_lfoSlice]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[Benjee10_X-37B]
6 | {
7 | !RESOURCE[LiquidFuel]
8 | {
9 |
10 | }
11 | !RESOURCE[Oxidizer]
12 | {
13 |
14 | }
15 | MODULE
16 | {
17 | name = ModuleTankManager
18 | Volume = 2.469136 //180.0 units of LF: conversion rate is 0.013717 m3/u
19 | DoCostPatch = True
20 | DoMassPatch = True
21 | TANK
22 | {
23 | name = LFO
24 | Volume = 100.0
25 | }
26 | }
27 | }
28 | //MonoPropellant Tanks
29 | //Automatically generated using PyKSPutils library
30 | @PART[x-37_monoSlice]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[Benjee10_X-37B]
31 | {
32 | !RESOURCE[MonoPropellant]
33 | {
34 |
35 | }
36 | MODULE
37 | {
38 | name = ModuleTankManager
39 | Volume = 0.271739 //100.0 units of MonoPropellant: conversion rate is 0.002717 m3/u
40 | DoCostPatch = True
41 | DoMassPatch = True
42 | TANK
43 | {
44 | TankType = LiquidChemicals
45 | CurrentResource = MonoPropellant
46 | InitialAmount = 1.0
47 | Volume = 100.0
48 | }
49 | }
50 | }
51 | //:mode=c#:
52 |
--------------------------------------------------------------------------------
/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // AssemblyInfo.cs
2 | //
3 | // Author:
4 | // Allis Tauri
5 | //
6 | // Copyright (c) 2016 Allis Tauri
7 |
8 | using System;
9 | using System.Reflection;
10 |
11 | // Information about this assembly is defined by the following attributes.
12 | // Change them to the values specific to your project.
13 |
14 | [assembly: AssemblyTitle("ConfigurableContainers")]
15 | [assembly: AssemblyDescription("Plugin for developers of part addons for Kerbal Space Program")]
16 | [assembly: AssemblyConfiguration("")]
17 | [assembly: AssemblyCompany("")]
18 | [assembly: AssemblyProduct("")]
19 | [assembly: AssemblyCopyright("Allis Tauri")]
20 | [assembly: AssemblyTrademark("")]
21 | [assembly: AssemblyCulture("")]
22 |
23 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
24 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
25 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
26 |
27 | #if NIGHTBUILD
28 | [assembly: AssemblyVersion("2.6.*")]
29 | #else
30 | [assembly: AssemblyVersion("2.6.2.1")]
31 | #endif
32 | [assembly: KSPAssembly("ConfigurableContainers", 2, 6)]
33 |
34 | // The following attributes are used to specify the signing key for the assembly,
35 | // if desired. See the Mono documentation for more information about signing.
36 |
37 | //[assembly: AssemblyDelaySign(false)]
38 | //[assembly: AssemblyKeyFile("")]
39 |
40 | namespace AT_Utils
41 | {
42 | public class CCModInfo : KSP_AVC_Info
43 | {
44 | public CCModInfo()
45 | {
46 | MinKSPVersion = new Version(1, 12, 3);
47 | MaxKSPVersion = new Version(1, 12, 3);
48 |
49 | VersionURL =
50 | "https://github.com/allista/ConfigurableContainers/tree/master/GameData/ConfigurableContainers/ConfigurableContainers.version";
51 | UpgradeURL = "https://spacedock.info/mod/1002/Configurable%20Containers";
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/KerboNerdLaboratories.cfg:
--------------------------------------------------------------------------------
1 | @PART[HPJT-01]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]]:AFTER[KerboNerdLaboratories]
2 | {
3 | !RESOURCE[HyperPlutonium]
4 | {
5 |
6 | }
7 | MODULE
8 | {
9 | name = ModuleTankManager
10 | Volume = 4.2093793
11 | DoCostPatch = True
12 | DoMassPatch = True
13 | TANK
14 | {
15 | TankType = Radioactives
16 | CurrentResource = HyperPlutonium
17 | InitialAmount = 1.0
18 | Volume = 100.0
19 | }
20 | }
21 | }
22 |
23 | @PART[HPSFA-01]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]]:AFTER[KerboNerdLaboratories]
24 | {
25 | !RESOURCE[HyperPlutonium]
26 | {
27 |
28 | }
29 | MODULE
30 | {
31 | name = ModuleTankManager
32 | Volume = 2.5256276
33 | DoCostPatch = True
34 | DoMassPatch = True
35 | TANK
36 | {
37 | TankType = Radioactives
38 | CurrentResource = HyperPlutonium
39 | InitialAmount = 1.0
40 | Volume = 100.0
41 | }
42 | }
43 | }
44 |
45 | @PART[HPSFA-02]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]]:AFTER[KerboNerdLaboratories]
46 | {
47 | !RESOURCE[HyperPlutonium]
48 | {
49 |
50 | }
51 | MODULE
52 | {
53 | name = ModuleTankManager
54 | Volume = 0.87695404
55 | DoCostPatch = True
56 | DoMassPatch = True
57 | TANK
58 | {
59 | TankType = Radioactives
60 | CurrentResource = HyperPlutonium
61 | InitialAmount = 1.0
62 | Volume = 100.0
63 | }
64 | }
65 | }
66 |
67 | @PART[HPSFA-03]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]]:AFTER[KerboNerdLaboratories]
68 | {
69 | !RESOURCE[HyperPlutonium]
70 | {
71 |
72 | }
73 | MODULE
74 | {
75 | name = ModuleTankManager
76 | Volume = 0.35078161
77 | DoCostPatch = True
78 | DoMassPatch = True
79 | TANK
80 | {
81 | TankType = Radioactives
82 | CurrentResource = HyperPlutonium
83 | InitialAmount = 1.0
84 | Volume = 100.0
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/ConfigurableContainers.netkan:
--------------------------------------------------------------------------------
1 | {
2 | "spec_version" : "v1.4",
3 | "identifier" : "ConfigurableContainers",
4 | "$kref" : "#/ckan/spacedock/1002",
5 | "$vref" : "#/ckan/ksp-avc",
6 | "abstract" : "This mod converts all the stock fuel tanks and resource containers so that you can change the resource(s) they hold in Editor and in Flight.",
7 | "author" : [ "allista" ],
8 | "license" : "MIT",
9 |
10 | "resources":
11 | {
12 | "homepage" : "http://forum.kerbalspaceprogram.com/index.php?/topic/150104-12-configurable-containers",
13 | "bugtracker" : "https://github.com/allista/ConfigurableContainers/issues",
14 | "repository" : "https://github.com/allista/ConfigurableContainers"
15 | },
16 |
17 | "depends":
18 | [
19 | { "name": "ModuleManager" },
20 | { "name": "AT-Utils" }
21 | ],
22 |
23 | "suggests":
24 | [
25 | { "name": "KSP-AVC" },
26 | { "name": "CommunityResourcePack" }
27 | ],
28 |
29 | "supports":
30 | [
31 | { "name": "B9-PWings-Fork" },
32 | { "name": "BluedogDB" },
33 | { "name": "DodoLabsStockalikeElectron" },
34 | { "name": "FuelTanksPlus" },
35 | { "name": "Goodspeed" },
36 | { "name": "Hangar" },
37 | { "name": "KWRocketryRebalanced" },
38 | { "name": "KerbalPlanetaryBaseSystems" },
39 | { "name": "Mk-X" },
40 | { "name": "Mk2Expansion" },
41 | { "name": "Mk3Expansion" },
42 | { "name": "Mk3HypersonicSystems" },
43 | { "name": "ModularRocketSystem" },
44 | { "name": "ModularRocketSystemsLITE" },
45 | { "name": "MunarIndustriesFTX" },
46 | { "name": "NearFuturePropulsion" },
47 | { "name": "OPTReconfig" },
48 | { "name": "OPTSpacePlaneParts" },
49 | { "name": "RaginCaucasian" },
50 | { "name": "ReStockPlus" },
51 | { "name": "SpaceY-Expanded" },
52 | { "name": "SpaceY-Lifters" },
53 | { "name": "StandardPropulsionSystems" },
54 | { "name": "StockalikeMiningExtension" },
55 | { "name": "StreamlineEnginesRCSsandfueltanks" },
56 | { "name": "TALSphericalToroidalPack" },
57 | { "name": "TweakScale" }
58 | ],
59 |
60 | "conflicts":
61 | [
62 | { "name": "ModularFuelTanks" },
63 | { "name": "RealFuels" }
64 | ],
65 |
66 | "install":
67 | [
68 | {
69 | "file": "GameData/ConfigurableContainers",
70 | "install_to": "GameData"
71 | }
72 | ]
73 | }
74 |
--------------------------------------------------------------------------------
/SwitchableTankManagerUI.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using AT_Utils.UI;
3 | using CC.UI;
4 | using UnityEngine;
5 | using UnityEngine.EventSystems;
6 |
7 | namespace AT_Utils
8 | {
9 | public static class CC_UI
10 | {
11 | public static readonly UIBundle AssetBundle = UIBundle.Create("000_AT_Utils/cc_ui.bundle");
12 | }
13 |
14 | public class SwitchableTankManagerUI : UIWindowBase
15 | {
16 | private readonly SwitchableTankManager manager;
17 |
18 | public SwitchableTankManagerUI(SwitchableTankManager manager) : base(CC_UI.AssetBundle)
19 | {
20 | this.manager = manager ?? throw new ArgumentNullException(nameof(manager));
21 | }
22 |
23 | protected override void init_controller()
24 | {
25 | base.init_controller();
26 | Controller.closeButton.onClick.AddListener(Close);
27 | Controller.colorSettingsButton.onClick.AddListener(toggleColors);
28 | Controller.onPointerEnterEvent.AddListener(highlightPart);
29 | Controller.onPointerExitEvent.AddListener(highlightPartDefault);
30 | Controller.SetTankManager(manager);
31 | if(manager != null)
32 | pos = manager.uiPos;
33 | }
34 |
35 | private void highlightPart(PointerEventData _)
36 | {
37 | var part = manager?.part;
38 | if(part != null)
39 | part.HighlightAlways(Colors.Active.color);
40 | }
41 |
42 | private void highlightPartDefault(PointerEventData _)
43 | {
44 | var part = manager?.part;
45 | if(part != null)
46 | part.SetHighlightDefault();
47 | }
48 |
49 | public override void SyncState()
50 | {
51 | base.SyncState();
52 | if(manager != null)
53 | manager.uiPos = pos;
54 | }
55 |
56 | protected override void onClose()
57 | {
58 | base.onClose();
59 | highlightPartDefault(null);
60 | }
61 |
62 | public void Toggle(MonoBehaviour monoBehaviour) => Toggle(monoBehaviour, !manager.EnablePartControls);
63 |
64 | public void OnLateUpdate()
65 | {
66 | if(!IsShown)
67 | return;
68 | if(manager.EnablePartControls)
69 | {
70 | Close();
71 | return;
72 | }
73 | if(FlightGlobals.ready && manager.part != null)
74 | Controller.gameObject.SetActive(manager.part.vessel == FlightGlobals.ActiveVessel);
75 | Controller.UpdateDisplay();
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/MiningExpansion_Patch.cfg:
--------------------------------------------------------------------------------
1 | //Configurable Containers patch for MiningExpansion
2 |
3 | //Ore Tanks
4 | //Automatically generated using PyKSPutils library
5 | @PART[SMX_Mk2Oretank]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[MiningExpansion]
6 | {
7 | !RESOURCE[Ore]
8 | {
9 |
10 | }
11 | MODULE
12 | {
13 | name = ModuleTankManager
14 | Volume = 2.972973 //550.0 units of Ore: conversion rate is 0.005405 m3/u
15 | DoCostPatch = True
16 | DoMassPatch = True
17 | TANK
18 | {
19 | TankType = Soil
20 | CurrentResource = Ore
21 | InitialAmount = 0.0
22 | Volume = 100.0
23 | }
24 | }
25 | }
26 |
27 | @PART[SMX_Size3OreTank]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[MiningExpansion]
28 | {
29 | !RESOURCE[Ore]
30 | {
31 |
32 | }
33 | MODULE
34 | {
35 | name = ModuleTankManager
36 | Volume = 24.324324 //4500.0 units of Ore: conversion rate is 0.005405 m3/u
37 | DoCostPatch = True
38 | DoMassPatch = True
39 | TANK
40 | {
41 | TankType = Soil
42 | CurrentResource = Ore
43 | InitialAmount = 0.0
44 | Volume = 100.0
45 | }
46 | }
47 | }
48 |
49 | @PART[SMX_Mk3OreTank]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[MiningExpansion]
50 | {
51 | !RESOURCE[Ore]
52 | {
53 |
54 | }
55 | MODULE
56 | {
57 | name = ModuleTankManager
58 | Volume = 21.621622 //4000.0 units of Ore: conversion rate is 0.005405 m3/u
59 | DoCostPatch = True
60 | DoMassPatch = True
61 | TANK
62 | {
63 | TankType = Soil
64 | CurrentResource = Ore
65 | InitialAmount = 0.0
66 | Volume = 100.0
67 | }
68 | }
69 | }
70 |
71 | @PART[SMX_Size0OreTank]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[MiningExpansion]
72 | {
73 | !RESOURCE[Ore]
74 | {
75 |
76 | }
77 | MODULE
78 | {
79 | name = ModuleTankManager
80 | Volume = 0.27027 //50.0 units of Ore: conversion rate is 0.005405 m3/u
81 | DoCostPatch = True
82 | DoMassPatch = True
83 | TANK
84 | {
85 | TankType = Soil
86 | CurrentResource = Ore
87 | InitialAmount = 0.0
88 | Volume = 100.0
89 | }
90 | }
91 | }
92 | //:mode=c#:
93 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Configurable Containers
2 |
3 | ## Requirements
4 |
5 | * [ModuleManager](http://forum.kerbalspaceprogram.com/index.php?/topic/50533-12)
6 | * [AT_Utils](https://github.com/allista/AT_Utils) (already includeds)
7 |
8 | ## For Players
9 |
10 | This mod converts fuel tanks and resource containers so that you can change the resource(s) they hold in Editor and in Flight.
11 |
12 | ## Supported Mods
13 |
14 | Configurable Containers support many part packs and mods:
15 |
16 | * **TweakScale**
17 | * **ProceduralParts**
18 | * Parts ++with stock resources++ converted:
19 | * Stock
20 | * KW Rocketry
21 | * Mk2 Expansion
22 | * Mk3 Expansion
23 | * SpaceY-Lifters
24 | * SpaceY-Expanded
25 | * Fuel Tanks Plus
26 | * Modular Rocket Systems
27 | * Standard Propulsion Systems
28 | * Near Future Propulsion
29 | * Spherical and Toroidal Tank Pack
30 | * OPT Spaceplane Parts (made by octarine-noise)
31 | * ...more will come.
32 | * Supported resources:
33 | * Stock
34 | * TAC Life Support
35 | * Extrapalentary Launchapads
36 | * Near Future Propulsion
37 | * All USI
38 | * All KSPIE
39 | * ...more will come.
40 |
41 | ### Types of the Containers
42 |
43 | _Tank Type_ is a set of resources that, gamewise, have something in common. For example gases, or liquid chemicals, or metals. There are also two kinds of configurable containers.
44 |
45 | * **Simple** containers belong to a single Tank Type (which can be changed in Editor) and can hold only a single resource. In flight this resource may be changed only if the container is empty, and only within its Tank Type.
46 | * **Compound** containers are in fact collections of simple containers inside of a single part. In Editor you can partition the inside space of such part, creating as many simple containers as you need. The only restriction imposed by KSP is that a part cannot have two identical resources stored. So if you have two containers for liquid chemicals in a part, only one of them can hold Liquid Fuel.
47 |
48 | Compound containers have a dedicated user interface so as not to clutter part menu:
49 |
50 | 
51 |
52 | ## For Modders
53 |
54 | ### CC is a part of the [AT_Utils](https://github.com/allista/AT_Utils) framework.
55 |
56 | It provides the **SwitchableTank** module that allows for creation of container parts for predefined sets of resources **switchable in-flight**. Sets are configured in a separate .cfg file and are intended to contain similar things like gases (one set), liquid chemicals (another) and so on.
57 |
58 | Another module Configurable Containers provide is the **TankManager** which enables _in-editor_ partitioning of a container, effectively converting it into a set of independent SwitchableTanks.
59 |
60 | The third, utility module named **SimpleTextureSwitcher** allows you to cycle through a predefined set of textures for the model or a part of the model, so a container may be easily identified. *It is now part of the main AT_Utils.dll, not the CC itself.*
61 |
--------------------------------------------------------------------------------
/CC.UI/TankManagerUI.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using AT_Utils.UI;
4 | using UnityEngine;
5 | using UnityEngine.UI;
6 |
7 | namespace CC.UI
8 | {
9 | public class TankManagerUI : ScreenBoundRect
10 | {
11 | public int
12 | maxTitleLength = 50;
13 |
14 | public AddTankControl
15 | addTankControl;
16 |
17 | public TankConfigsControl
18 | tankConfigsControl;
19 |
20 | public Text
21 | partTitleLabel,
22 | volumeLabel;
23 |
24 | public Button
25 | closeButton,
26 | colorSettingsButton;
27 |
28 | public RectTransform
29 | tanksScroll;
30 |
31 | public GameObject
32 | tankControlPrefab;
33 |
34 | private ITankManager tankManager;
35 | public Dictionary tankControls = new Dictionary();
36 |
37 | public void SetTankManager(ITankManager newTankManager)
38 | {
39 | if(newTankManager == tankManager)
40 | return;
41 | foreach(var t in tankControls.Values)
42 | Destroy(t.gameObject);
43 | tankControls.Clear();
44 | tankManager = newTankManager;
45 | addTankControl.SetTankManager(tankManager);
46 | tankConfigsControl.SetTankManager(tankManager);
47 | if(tankManager == null)
48 | return;
49 | UpdateDisplay();
50 | }
51 |
52 | public void UpdateDisplay()
53 | {
54 | var title = tankManager.Title;
55 | partTitleLabel.text = title.Length <= maxTitleLength + 3
56 | ? title
57 | : $"{title.Substring(0, maxTitleLength)}...";
58 | volumeLabel.text =
59 | $"{FormatUtils.formatVolume(tankManager.AvailableVolume)} / {FormatUtils.formatVolume(tankManager.Volume)}";
60 | addTankControl.gameObject.SetActive(tankManager.Capabilities.AddRemoveEnabled);
61 | tankConfigsControl.gameObject.SetActive(tankManager.Capabilities.AddRemoveEnabled);
62 | updateTankControls();
63 | }
64 |
65 | private void updateTankControls()
66 | {
67 | var newTanks = new HashSet();
68 | foreach(var tank in tankManager.Tanks)
69 | {
70 | newTanks.Add(tank);
71 | if(tankControls.ContainsKey(tank))
72 | continue;
73 | var newTankControlObj = Instantiate(tankControlPrefab, tanksScroll);
74 | if(newTankControlObj == null)
75 | {
76 | Debug.LogError($"Unable to instantiate prefab: {tankControlPrefab}");
77 | continue;
78 | }
79 | newTankControlObj.transform.SetAsLastSibling();
80 | var newTankControl = newTankControlObj.GetComponent();
81 | if(newTankControl == null)
82 | {
83 | Debug.LogError($"No {nameof(TankControlsUI)} in prefab {tankControlPrefab}");
84 | continue;
85 | }
86 | newTankControl.managerUI = this;
87 | newTankControl.SetTank(tank);
88 | tankControls.Add(tank, newTankControl);
89 | }
90 | foreach(var tank in tankControls.ToList())
91 | {
92 | if(newTanks.Contains(tank.Key))
93 | {
94 | tank.Value.UpdateDisplay();
95 | continue;
96 | }
97 | Destroy(tank.Value.gameObject);
98 | tankControls.Remove(tank.Key);
99 | }
100 | tankConfigsControl.EnableControls(tankManager.Tanks.Count > 0);
101 | }
102 |
103 | #if DEBUG
104 | protected override void Start()
105 | {
106 | base.Start();
107 | if(Application.isEditor)
108 | SetTankManager(new TestTankManager());
109 | }
110 | #endif
111 | }
112 |
113 | public class TankManagerUIPart : MonoBehaviour
114 | {
115 | public TankManagerUI managerUI;
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/CC.UI/CC.UI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {3E7AA3AB-1064-4A2E-9D8F-0E20B83A2249}
8 | Library
9 | CC.UI
10 | CC.UI
11 | v4.8
12 | Properties
13 | 512
14 | 7.3
15 |
16 |
17 |
18 | true
19 | full
20 | false
21 | ..\..\Unity\Assets\Plugins
22 | DEBUG;
23 | prompt
24 | 4
25 | false
26 |
27 |
28 | true
29 | ..\..\Unity\Assets\Plugins
30 | prompt
31 | 4
32 | false
33 |
34 |
35 | ..\..\Unity\Assets\Plugins
36 | NIGHTBUILD
37 | true
38 |
39 |
40 |
41 | ..\..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\System.dll
42 | False
43 |
44 |
45 | ..\..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\System.Core.dll
46 | False
47 |
48 |
49 | ..\..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\UnityEngine.dll
50 | False
51 |
52 |
53 | ..\..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\UnityEngine.CoreModule.dll
54 | False
55 |
56 |
57 | ..\..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\UnityEngine.UI.dll
58 | False
59 |
60 |
61 |
62 |
63 | {0b711e55-8312-144f-53ad-eda5a8cee04a}
64 | AT_Utils.UI
65 | False
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/CC.UI/TestTankInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using UnityEngine;
5 |
6 | namespace CC.UI
7 | {
8 | #if DEBUG
9 | public class TestTankManager : ITankManager
10 | {
11 | public string Title { get; }
12 | public IList SupportedTypes { get; }
13 | public IList SupportedTankConfigs { get; }
14 | public float Volume { get; }
15 | public float AvailableVolume { get; private set; }
16 | public float AvailableVolumePercent { get; private set; }
17 |
18 | private readonly List Tanks;
19 | IReadOnlyCollection ITankManager.Tanks => Tanks;
20 |
21 | private class TestTankManagerCapabilities : ITankManagerCapabilities
22 | {
23 | public bool AddRemoveEnabled => true;
24 | public bool ConfirmRemove => true;
25 | public bool TypeChangeEnabled => true;
26 | public bool VolumeChangeEnabled => true;
27 | public bool FillEnabled => true;
28 | public bool EmptyEnabled => true;
29 | }
30 |
31 | private readonly TestTankManagerCapabilities Capabilities = new TestTankManagerCapabilities();
32 | ITankManagerCapabilities ITankManager.Capabilities => Capabilities;
33 |
34 | public void UpdateAvailableVolume()
35 | {
36 | AvailableVolume = Volume - Tanks.Aggregate(0f, (res, t) => res + t.Volume);
37 | AvailableVolumePercent = AvailableVolume / Volume * 100;
38 | }
39 |
40 | public string OnVolumeChanged(string tankType, float volume) => null;
41 |
42 | public string GetTypeInfo(string tankType) => $"{tankType}: This is a test info.";
43 |
44 | public bool AddTank(string tankType, float volume)
45 | {
46 | var tankInfo = new TestTankInfo(tankType, Mathf.Min(volume, AvailableVolume), this);
47 | Tanks.Add(tankInfo);
48 | UpdateAvailableVolume();
49 | return true;
50 | }
51 |
52 | public bool RemoveTank(ITankInfo tank) => Tanks.Remove(tank as TestTankInfo);
53 |
54 | public bool AddTankConfig(string configName)
55 | {
56 | if(!SupportedTankConfigs.Contains(configName))
57 | SupportedTankConfigs.Add(configName);
58 | return true;
59 | }
60 |
61 | public bool RemoveTankConfig(string configName) => SupportedTankConfigs.Remove(configName);
62 |
63 | public TestTankManager()
64 | {
65 | SupportedTypes = new List
66 | {
67 | "LiquidChemicals",
68 | "Components",
69 | "Soil",
70 | "Type 1",
71 | "Type 2",
72 | "Type 3",
73 | "Type 4",
74 | "Type 5"
75 | };
76 | SupportedTankConfigs = new List { "LFO", "LoX", "CA" };
77 | Volume = 15.79089f;
78 | AvailableVolume = Volume;
79 | AvailableVolumePercent = 100;
80 | Tanks = new List();
81 | Title = "Big Resource Tank - with a long long, very long name indeed!";
82 | }
83 | }
84 |
85 | public class TestTankInfo : ITankInfo
86 | {
87 | private TestTankManager Manager;
88 | ITankManager ITankInfo.Manager => Manager;
89 | public string TankType { get; private set; }
90 | public IList SupportedResources { get; }
91 | public IList SupportedTypes => Manager.SupportedTypes;
92 | public string CurrentResource { get; private set; }
93 | private float UsefulVolumeRatio { get; }
94 | public float Volume { get; private set; }
95 | public double MaxAmount => ResourceAmountInVolume(Volume);
96 | public double Amount { get; private set; }
97 | private float UnitsPerVolume { get; }
98 | public float ResourceDensity { get; }
99 | public bool Valid => CurrentResource != "Oxidizer";
100 | public float ResourceAmountInVolume(float volume) => volume * UnitsPerVolume * UsefulVolumeRatio;
101 |
102 | public float VolumeForResourceAmount(float amount) => amount / UnitsPerVolume / UsefulVolumeRatio;
103 |
104 |
105 | public TestTankInfo(string tankType, float volume, TestTankManager manager)
106 | {
107 | Manager = manager;
108 | SupportedResources = new List { "MonoPropellant", "Oxidizer", "MaterialKits", "SpecializedParts" };
109 | TankType = tankType;
110 | CurrentResource = SupportedResources[0];
111 | UsefulVolumeRatio = 1;
112 | UnitsPerVolume = 1500f;
113 | ResourceDensity = 0.0012f;
114 | Volume = volume;
115 | Amount = MaxAmount * 0.78f;
116 | }
117 |
118 | public void SetVolume(float volume, bool update_amount)
119 | {
120 | volume = Mathf.Clamp(volume, 0, Manager.Volume);
121 | if(update_amount)
122 | Amount *= volume / Volume;
123 | Volume = volume;
124 | Manager.UpdateAvailableVolume();
125 | }
126 |
127 | public void ChangeTankType(string tankTypeName)
128 | {
129 | TankType = tankTypeName;
130 | }
131 |
132 | public void ChangeResource(string resourceName)
133 | {
134 | CurrentResource = resourceName;
135 | }
136 |
137 | public void SetAmount(float newAmount)
138 | {
139 | Amount = Math.Min(MaxAmount, newAmount);
140 | }
141 | }
142 | #endif
143 | }
144 |
--------------------------------------------------------------------------------
/CC.UI/TankConfigsControl.cs:
--------------------------------------------------------------------------------
1 | using AT_Utils.UI;
2 | using UnityEngine.Events;
3 | using UnityEngine.UI;
4 |
5 | namespace CC.UI
6 | {
7 | public class TankConfigsControl : TankManagerUIPart
8 | {
9 | public InputField
10 | configNameField;
11 |
12 | public Dropdown
13 | configsDropdown;
14 |
15 | public TooltipTrigger
16 | configsDropdownTooltip;
17 |
18 | public Button
19 | addConfigButton,
20 | updateConfigButton,
21 | deleteConfigButton;
22 |
23 | public AddTankControl addTankControl;
24 |
25 | private bool addUpdateEnabled;
26 |
27 | private ITankManager tankManager;
28 |
29 | private void Awake()
30 | {
31 | configsDropdown.onValueChanged.AddListener(updateConfigsDropdownTooltip);
32 | addConfigButton.onClick.AddListener(onAddConfig);
33 | updateConfigButton.onClick.AddListener(onUpdateConfig);
34 | deleteConfigButton.onClick.AddListener(onDeleteConfig);
35 | configNameField.onValueChanged.AddListener(onConfigNameChanged);
36 | EnableControls(false);
37 | }
38 |
39 | private void OnDestroy()
40 | {
41 | configsDropdown.onValueChanged.RemoveAllListeners();
42 | addConfigButton.onClick.RemoveAllListeners();
43 | updateConfigButton.onClick.RemoveAllListeners();
44 | deleteConfigButton.onClick.RemoveAllListeners();
45 | configNameField.onValueChanged.RemoveAllListeners();
46 | }
47 |
48 | public void EnableControls(bool enable)
49 | {
50 | addUpdateEnabled = enable;
51 | updateControls();
52 | }
53 |
54 | private void updateControls()
55 | {
56 | var noDialogOpen = !DialogFactory.ContextIsActive(this);
57 | addConfigButton.SetInteractable(addUpdateEnabled
58 | && noDialogOpen
59 | && !string.IsNullOrEmpty(configNameField.text));
60 | updateConfigButton.SetInteractable(addUpdateEnabled
61 | && noDialogOpen);
62 | deleteConfigButton.SetInteractable(noDialogOpen
63 | && tankManager != null
64 | && tankManager.SupportedTankConfigs.Count > 0);
65 | configsDropdown.SetInteractable(noDialogOpen);
66 | configNameField.SetInteractable(noDialogOpen);
67 | }
68 |
69 | public void SetTankManager(ITankManager manager)
70 | {
71 | if(tankManager == manager)
72 | return;
73 | tankManager = manager;
74 | if(tankManager == null)
75 | return;
76 | updateConfigsDropdown();
77 | EnableControls(tankManager.Tanks.Count > 0);
78 | }
79 |
80 | private void updateConfigsDropdown()
81 | {
82 | configsDropdown.SetOptionsSafe(UI_Utils.namesToOptions(tankManager.SupportedTankConfigs, false));
83 | updateConfigsDropdownTooltip(configsDropdown.value);
84 | addTankControl.UpdateTankTypes();
85 | }
86 |
87 | private void updateConfigsDropdownTooltip(int index)
88 | {
89 | if(index >= 0 && index < tankManager.SupportedTankConfigs.Count)
90 | configsDropdownTooltip.SetText(tankManager.GetTypeInfo(tankManager.SupportedTankConfigs[index]));
91 | else
92 | configsDropdownTooltip.SetText("Select tank preset to edit");
93 | }
94 |
95 | private void onConfigNameChanged(string newConfigName) =>
96 | addConfigButton.SetInteractable(addUpdateEnabled && !string.IsNullOrEmpty(newConfigName));
97 |
98 | private void onUpdateConfig() => updateConfig(tankManager.SupportedTankConfigs[configsDropdown.value]);
99 |
100 | private void updateConfig(string tankConfig, UnityAction onSuccess = null)
101 | {
102 | DialogFactory.Danger($"Are you sure you want to {Colors.Warning.Tag("overwrite")} "
103 | + $"the {Colors.Selected1.Tag(tankConfig)} preset?",
104 | () =>
105 | {
106 | if(!tankManager.AddTankConfig(tankConfig))
107 | return;
108 | updateConfigsDropdown();
109 | onSuccess?.Invoke();
110 | },
111 | onDestroy: updateControls,
112 | context: this);
113 | updateControls();
114 | }
115 |
116 | private void onAddConfig()
117 | {
118 | var tankConfig = configNameField.text;
119 | if(string.IsNullOrEmpty(tankConfig))
120 | return;
121 | if(tankManager.SupportedTankConfigs.Contains(tankConfig))
122 | updateConfig(tankConfig, () => configNameField.text = "");
123 | else if(tankManager.AddTankConfig(tankConfig))
124 | {
125 | configNameField.text = "";
126 | updateConfigsDropdown();
127 | }
128 | }
129 |
130 | private void onDeleteConfig()
131 | {
132 | var tankConfig = tankManager.SupportedTankConfigs[configsDropdown.value];
133 | DialogFactory.Danger($"Are you sure you want to {Colors.Danger.Tag("delete")} "
134 | + $"the {Colors.Selected1.Tag(tankConfig)} preset?",
135 | () =>
136 | {
137 | if(tankManager.RemoveTankConfig(tankConfig))
138 | updateConfigsDropdown();
139 | },
140 | onDestroy: updateControls,
141 | context: this);
142 | updateControls();
143 | }
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/Cryogenics/ActiveCooling.cs:
--------------------------------------------------------------------------------
1 | // ResourceBoiloff.cs
2 | //
3 | // Author:
4 | // Allis Tauri
5 | //
6 | // Copyright (c) 2016 Allis Tauri
7 |
8 | using System;
9 | using JetBrains.Annotations;
10 |
11 | namespace AT_Utils
12 | {
13 | public class ActiveCooling : ResourceBoiloff
14 | {
15 | [UsedImplicitly] public new const string NODE_NAME = "RES_COOLING";
16 |
17 | [Persistent] public double CoolingEfficiency;
18 | private double Efficiency = 0.17f;
19 |
20 | [Persistent] public bool Enabled = true;
21 | [Persistent] public bool IsCooling;
22 |
23 | private double MaxPower = 10;
24 |
25 | public ActiveCooling(ModuleSwitchableTank tank) : base(tank) { }
26 |
27 | public double PowerConsumptionAt300K
28 | {
29 | get
30 | {
31 | var CoreDeltaT = CoreDeltaTAt300K(out _, out var resThermalMass);
32 | return Math.Min(CoreDeltaT
33 | * resThermalMass
34 | * (300 - boiloffTemperature)
35 | / boiloffTemperature
36 | / Efficiency
37 | / CryogenicsParams.Instance.ElectricCharge2kJ,
38 | MaxPower);
39 | }
40 | }
41 |
42 | ///
43 | /// Converts the amount of heat that needs to be retrieved from the core to the amount of work that is
44 | /// required to transfer that heat to the part's skin.
45 | ///
46 | protected double Q2W => (part.skinTemperature - CoreTemperature) / CoreTemperature / Efficiency;
47 |
48 | public override void SetResource(PartResource res)
49 | {
50 | base.SetResource(res);
51 | if(cryo_info == null)
52 | return;
53 | MaxPower = Math.Min(CryogenicsParams.Instance.MaxSpecificCoolerPower * res.maxAmount * specificHeatCapacity,
54 | CryogenicsParams.Instance.MaxAbsoluteCoolerPower);
55 | Efficiency = cryo_info.CoolingEfficiency;
56 | }
57 |
58 | protected override void UpdateCoreTemperature(double deltaTime)
59 | {
60 | var last_core_temp = CoreTemperature;
61 | base.UpdateCoreTemperature(deltaTime);
62 | IsCooling = false;
63 | if(!Enabled)
64 | return;
65 | if(part.skinTemperature / part.skinMaxTemp > PhysicsGlobals.TemperatureGaugeThreshold)
66 | goto disable;
67 | var temperature_excess = CoreTemperature - boiloffTemperature;
68 | // Utils.Log("Skin.T {}, dTemp {}", part.skinTemperature, temperature_excess);//debug
69 | if(temperature_excess < 0)
70 | {
71 | var electric_charge_needed = Math.Abs(CoreTemperature - last_core_temp)
72 | * resource.amount
73 | * specificHeatCapacity
74 | * Q2W
75 | / CryogenicsParams.Instance.ElectricCharge2kJ;
76 | var electric_charge = electric_charge_needed / deltaTime > MaxPower
77 | ? MaxPower * deltaTime
78 | : electric_charge_needed;
79 | CoolingEfficiency = electric_charge / electric_charge_needed;
80 | // Utils.Log("Would Consume {}/{}, Power {}/{}, Efficiency {}",
81 | // electric_charge, electric_charge_needed, electric_charge/deltaTime, MaxPower, CoolingEfficiency);//debug
82 | return;
83 | }
84 | if(Math.Abs(deltaTime - TimeWarp.fixedDeltaTime) < 1e-5)
85 | {
86 | var q2w = Q2W;
87 | var resThermalMass = resource.amount * specificHeatCapacity;
88 | var electric_charge_needed =
89 | temperature_excess * resThermalMass * q2w / CryogenicsParams.Instance.ElectricCharge2kJ;
90 | if(electric_charge_needed / deltaTime > MaxPower)
91 | electric_charge_needed = MaxPower * deltaTime;
92 | var electric_charge =
93 | part.vessel.RequestResource(part, Utils.ElectricCharge.id, electric_charge_needed, false);
94 | if(electric_charge / electric_charge_needed < CryogenicsParams.Instance.ShutdownThreshold)
95 | {
96 | Utils.Message("Not enough energy, CryoCooler is disabled.");
97 | goto disable;
98 | }
99 | IsCooling = true;
100 | var energy_extracted = electric_charge / q2w * CryogenicsParams.Instance.ElectricCharge2kJ;
101 | var cooled = energy_extracted / resThermalMass;
102 | CoolingEfficiency = cooled / temperature_excess;
103 | CoreTemperature -= cooled;
104 | part.AddSkinThermalFlux(energy_extracted / TimeWarp.fixedDeltaTime);
105 | // Utils.Log("Consumed {}, Power {}/{}, Cooled {}/{}, SkinTempRate {}",
106 | // electric_charge, electric_charge/deltaTime, MaxPower, cooled, temperature_excess);//debug
107 | return;
108 | }
109 | if(CoolingEfficiency > 0) //catch up after being unloaded
110 | {
111 | IsCooling = true;
112 | CoreTemperature -= temperature_excess * CoolingEfficiency;
113 | // Utils.Log("Efficiency {}, Cooled {}/{}",
114 | // CoolingEfficiency, temperature_excess*CoolingEfficiency, temperature_excess);//debug
115 | return;
116 | }
117 | disable:
118 | {
119 | CoolingEfficiency = 0;
120 | IsCooling = false;
121 | Enabled = false;
122 | }
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/Cryogenics/CryogenicsParams.cs:
--------------------------------------------------------------------------------
1 | // CryogenicsParams.cs
2 | //
3 | // Author:
4 | // Allis Tauri
5 | //
6 | // Copyright (c) 2016 Allis Tauri
7 |
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Diagnostics.CodeAnalysis;
11 |
12 | namespace AT_Utils
13 | {
14 | [SuppressMessage("ReSharper", "MemberCanBePrivate.Global"),
15 | SuppressMessage("ReSharper", "ConvertToConstant.Global"),
16 | SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Global")]
17 | public class CryogenicsParams : ConfigNodeObject
18 | {
19 | public new const string NODE_NAME = "CRYOGENICS";
20 |
21 | private const string config_path = "ConfigurableContainers/Cryogenics/";
22 |
23 | ///
24 | /// The absolute zero, 0K.
25 | ///
26 | public const double AbsZero = -273.15;
27 |
28 | private static CryogenicsParams instance;
29 |
30 | private readonly Dictionary Resources = new Dictionary();
31 |
32 | ///
33 | /// How much kJs does 1 electric charge contain?
34 | ///
35 | [Persistent]
36 | public float ElectricCharge2kJ = 10;
37 |
38 | ///
39 | /// Limits energy transfer between the resource volume and the rest of the part.
40 | /// kW/m/K
41 | ///
42 | [Persistent]
43 | public float InsulationConductivity = 1e-3f;
44 |
45 | ///
46 | /// The fraction of the tank's volume that is used for insulation
47 | ///
48 | [Persistent]
49 | public float InsulationVolumeFraction = 0.02f;
50 |
51 | ///
52 | /// Maximum total power consumption of any cooler (Ec/s)
53 | ///
54 | [Persistent]
55 | public float MaxAbsoluteCoolerPower = 500;
56 |
57 | ///
58 | /// Maximum power consumption of a cooler (Ec/s) per unit thermal mass
59 | ///
60 | [Persistent]
61 | public float MaxSpecificCoolerPower = 1;
62 |
63 | ///
64 | /// If the power supply drops below this fraction, the cooler is automatically disabled
65 | ///
66 | [Persistent]
67 | public float ShutdownThreshold = 0.99f;
68 |
69 | ///
70 | /// Used when no VaporizationHeat is provided for a resource to estimate it
71 | ///
72 | [Persistent]
73 | public float SpecificHeat2VaporizationHeat = 1000;
74 |
75 | public static CryogenicsParams Instance
76 | {
77 | get
78 | {
79 | if(instance != null)
80 | return instance;
81 | instance = new CryogenicsParams();
82 | var node = GameDatabase.Instance.GetConfigNode(config_path + NODE_NAME);
83 | if(node != null)
84 | instance.Load(node);
85 | else
86 | Utils.Log("CryogenicsParams NODE not found: {}", config_path + NODE_NAME);
87 | return instance;
88 | }
89 | }
90 |
91 | ///
92 | /// Retrieve the cryogenic resource info for the given part resource.
93 | ///
94 | /// The cryogenic resource info.
95 | /// The part resource.
96 | public CryoResource GetResource(PartResource r)
97 | {
98 | return Resources.TryGetValue(r.resourceName, out var res) ? res : null;
99 | }
100 |
101 | ///
102 | /// Calculates conductivity of insulation of a given spherical volume.
103 | ///
104 | /// The insulator conductivity in kW/K.
105 | /// Volume of a tank.
106 | public static double GetInsulatorConductivity(double volume)
107 | {
108 | return -Instance.InsulationConductivity
109 | * Math.Pow(48 * Math.PI * Math.PI * volume / Instance.InsulationVolumeFraction, 1 / 3f);
110 | }
111 |
112 | #if DEBUG
113 | public static void Reload()
114 | {
115 | var node = ConfigNode.Load(CustomConfig.GameDataFolder("ConfigurableContainers", "Cryogenics.cfg"));
116 | if(node == null)
117 | {
118 | Utils.Log("Unable to read Cryogenics.cfg");
119 | return;
120 | }
121 | if(instance == null)
122 | instance = new CryogenicsParams();
123 | instance.LoadFrom(node);
124 | Utils.Log("CryogenicsParams reloaded:\n{}", instance);
125 | }
126 | #endif
127 |
128 | public override void Load(ConfigNode node)
129 | {
130 | base.Load(node);
131 | Resources.Clear();
132 | foreach(var n in node.GetNodes(CryoResource.NODE_NAME))
133 | {
134 | var res = FromConfig(n);
135 | Resources.Add(res.name, res);
136 | }
137 | }
138 |
139 | [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
140 | public class CryoResource : ConfigNodeObject
141 | {
142 | // ReSharper disable once MemberHidesStaticFromOuterClass
143 | public new const string NODE_NAME = "RESOURCE";
144 | [Persistent] public float BoiloffTemperature = 120;
145 | [Persistent] public float CoolingEfficiency = 0.3f;
146 |
147 | [Persistent] public string name = "";
148 | [Persistent] public float VaporizationHeat = -1;
149 |
150 | public double GetVaporizationHeat(PartResource r)
151 | {
152 | return VaporizationHeat > 0
153 | ? VaporizationHeat
154 | : r.info.specificHeatCapacity * Instance.SpecificHeat2VaporizationHeat;
155 | }
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/SpaceY-Lifters_Patch.cfg:
--------------------------------------------------------------------------------
1 | //Configurable Containers patch for SpaceY-Lifters
2 |
3 | //Rocket Fuel Tanks
4 | //Automatically generated using PyKSPutils library
5 | @PART[SYtank3mCone]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Lifters]
6 | {
7 | !RESOURCE[LiquidFuel]
8 | {
9 |
10 | }
11 | !RESOURCE[Oxidizer]
12 | {
13 |
14 | }
15 | MODULE
16 | {
17 | name = ModuleTankManager
18 | Volume = 11.111111 //810.0 units of LF: conversion rate is 0.013717 m3/u
19 | DoCostPatch = True
20 | DoMassPatch = True
21 | TANK
22 | {
23 | name = LFO
24 | Volume = 100.0
25 | }
26 | }
27 | }
28 |
29 | @PART[SYtank5mCone2]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Lifters]
30 | {
31 | !RESOURCE[LiquidFuel]
32 | {
33 |
34 | }
35 | !RESOURCE[Oxidizer]
36 | {
37 |
38 | }
39 | MODULE
40 | {
41 | name = ModuleTankManager
42 | Volume = 33.333333 //2430.0 units of LF: conversion rate is 0.013717 m3/u
43 | DoCostPatch = True
44 | DoMassPatch = True
45 | TANK
46 | {
47 | name = LFO
48 | Volume = 100.0
49 | }
50 | }
51 | }
52 |
53 | @PART[SYtank5mL0375]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Lifters]
54 | {
55 | !RESOURCE[LiquidFuel]
56 | {
57 |
58 | }
59 | !RESOURCE[Oxidizer]
60 | {
61 |
62 | }
63 | MODULE
64 | {
65 | name = ModuleTankManager
66 | Volume = 77.777778 //5670.0 units of LF: conversion rate is 0.013717 m3/u
67 | DoCostPatch = True
68 | DoMassPatch = True
69 | TANK
70 | {
71 | name = LFO
72 | Volume = 100.0
73 | }
74 | }
75 | }
76 |
77 | @PART[SYtank5mL1500]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Lifters]
78 | {
79 | !RESOURCE[LiquidFuel]
80 | {
81 |
82 | }
83 | !RESOURCE[Oxidizer]
84 | {
85 |
86 | }
87 | MODULE
88 | {
89 | name = ModuleTankManager
90 | Volume = 311.111111 //22680.0 units of LF: conversion rate is 0.013717 m3/u
91 | DoCostPatch = True
92 | DoMassPatch = True
93 | TANK
94 | {
95 | name = LFO
96 | Volume = 100.0
97 | }
98 | }
99 | }
100 |
101 | @PART[SYtank5mL01875]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Lifters]
102 | {
103 | !RESOURCE[LiquidFuel]
104 | {
105 |
106 | }
107 | !RESOURCE[Oxidizer]
108 | {
109 |
110 | }
111 | MODULE
112 | {
113 | name = ModuleTankManager
114 | Volume = 38.888889 //2835.0 units of LF: conversion rate is 0.013717 m3/u
115 | DoCostPatch = True
116 | DoMassPatch = True
117 | TANK
118 | {
119 | name = LFO
120 | Volume = 100.0
121 | }
122 | }
123 | }
124 |
125 | @PART[SYtank5mL0750]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Lifters]
126 | {
127 | !RESOURCE[LiquidFuel]
128 | {
129 |
130 | }
131 | !RESOURCE[Oxidizer]
132 | {
133 |
134 | }
135 | MODULE
136 | {
137 | name = ModuleTankManager
138 | Volume = 155.555556 //11340.0 units of LF: conversion rate is 0.013717 m3/u
139 | DoCostPatch = True
140 | DoMassPatch = True
141 | TANK
142 | {
143 | name = LFO
144 | Volume = 100.0
145 | }
146 | }
147 | }
148 |
149 | @PART[SYtank3mCone2]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Lifters]
150 | {
151 | !RESOURCE[LiquidFuel]
152 | {
153 |
154 | }
155 | !RESOURCE[Oxidizer]
156 | {
157 |
158 | }
159 | MODULE
160 | {
161 | name = ModuleTankManager
162 | Volume = 16.666667 //1215.0 units of LF: conversion rate is 0.013717 m3/u
163 | DoCostPatch = True
164 | DoMassPatch = True
165 | TANK
166 | {
167 | name = LFO
168 | Volume = 100.0
169 | }
170 | }
171 | }
172 |
173 | @PART[SYtank5m3mAdapter]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Lifters]
174 | {
175 | !RESOURCE[LiquidFuel]
176 | {
177 |
178 | }
179 | !RESOURCE[Oxidizer]
180 | {
181 |
182 | }
183 | MODULE
184 | {
185 | name = ModuleTankManager
186 | Volume = 58.333333 //4252.5 units of LF: conversion rate is 0.013717 m3/u
187 | DoCostPatch = True
188 | DoMassPatch = True
189 | TANK
190 | {
191 | name = LFO
192 | Volume = 100.0
193 | }
194 | }
195 | }
196 |
197 | @PART[SYtank5mL1125]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Lifters]
198 | {
199 | !RESOURCE[LiquidFuel]
200 | {
201 |
202 | }
203 | !RESOURCE[Oxidizer]
204 | {
205 |
206 | }
207 | MODULE
208 | {
209 | name = ModuleTankManager
210 | Volume = 233.333333 //17010.0 units of LF: conversion rate is 0.013717 m3/u
211 | DoCostPatch = True
212 | DoMassPatch = True
213 | TANK
214 | {
215 | name = LFO
216 | Volume = 100.0
217 | }
218 | }
219 | }
220 | //:mode=c#:
221 |
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/Mk2Expansion_Patch.cfg:
--------------------------------------------------------------------------------
1 | //Configurable Containers patch for Mk2Expansion
2 |
3 | //Rocket Fuel Tanks
4 | //Automatically generated using PyKSPutils library
5 | @PART[M2X_InverterFuselage]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[Mk2Expansion]
6 | {
7 | !RESOURCE[LiquidFuel]
8 | {
9 |
10 | }
11 | !RESOURCE[Oxidizer]
12 | {
13 |
14 | }
15 | MODULE
16 | {
17 | name = ModuleTankManager
18 | Volume = 4.938272 //360.0 units of LF: conversion rate is 0.013717 m3/u
19 | DoCostPatch = True
20 | DoMassPatch = True
21 | TANK
22 | {
23 | name = LFO
24 | Volume = 100.0
25 | }
26 | }
27 | }
28 |
29 | @PART[M2X_HypersonicNose]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[Mk2Expansion]
30 | {
31 | !RESOURCE[LiquidFuel]
32 | {
33 |
34 | }
35 | !RESOURCE[Oxidizer]
36 | {
37 |
38 | }
39 | MODULE
40 | {
41 | name = ModuleTankManager
42 | Volume = 2.469136 //180.0 units of LF: conversion rate is 0.013717 m3/u
43 | DoCostPatch = True
44 | DoMassPatch = True
45 | TANK
46 | {
47 | name = LFO
48 | Volume = 100.0
49 | }
50 | }
51 | }
52 |
53 | @PART[M2X_linearTricoupler]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[Mk2Expansion]
54 | {
55 | !RESOURCE[LiquidFuel]
56 | {
57 |
58 | }
59 | !RESOURCE[Oxidizer]
60 | {
61 |
62 | }
63 | MODULE
64 | {
65 | name = ModuleTankManager
66 | Volume = 4.938272 //360.0 units of LF: conversion rate is 0.013717 m3/u
67 | DoCostPatch = True
68 | DoMassPatch = True
69 | TANK
70 | {
71 | name = LFO
72 | Volume = 100.0
73 | }
74 | }
75 | }
76 |
77 | @PART[M2X_Short25adapter]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[Mk2Expansion]
78 | {
79 | !RESOURCE[LiquidFuel]
80 | {
81 |
82 | }
83 | !RESOURCE[Oxidizer]
84 | {
85 |
86 | }
87 | MODULE
88 | {
89 | name = ModuleTankManager
90 | Volume = 2.469136 //180.0 units of LF: conversion rate is 0.013717 m3/u
91 | DoCostPatch = True
92 | DoMassPatch = True
93 | TANK
94 | {
95 | name = LFO
96 | Volume = 100.0
97 | }
98 | }
99 | }
100 |
101 | @PART[M2X_625tricoupler]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[Mk2Expansion]
102 | {
103 | !RESOURCE[LiquidFuel]
104 | {
105 |
106 | }
107 | !RESOURCE[Oxidizer]
108 | {
109 |
110 | }
111 | MODULE
112 | {
113 | name = ModuleTankManager
114 | Volume = 1.234568 //90.0 units of LF: conversion rate is 0.013717 m3/u
115 | DoCostPatch = True
116 | DoMassPatch = True
117 | TANK
118 | {
119 | name = LFO
120 | Volume = 100.0
121 | }
122 | }
123 | }
124 |
125 | @PART[M2X_SpadeTail]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[Mk2Expansion]
126 | {
127 | !RESOURCE[LiquidFuel]
128 | {
129 |
130 | }
131 | !RESOURCE[Oxidizer]
132 | {
133 |
134 | }
135 | MODULE
136 | {
137 | name = ModuleTankManager
138 | Volume = 1.234568 //90.0 units of LF: conversion rate is 0.013717 m3/u
139 | DoCostPatch = True
140 | DoMassPatch = True
141 | TANK
142 | {
143 | name = LFO
144 | Volume = 100.0
145 | }
146 | }
147 | }
148 |
149 | @PART[M2X_Mk2bicoupler]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[Mk2Expansion]
150 | {
151 | !RESOURCE[LiquidFuel]
152 | {
153 |
154 | }
155 | !RESOURCE[Oxidizer]
156 | {
157 |
158 | }
159 | MODULE
160 | {
161 | name = ModuleTankManager
162 | Volume = 4.938272 //360.0 units of LF: conversion rate is 0.013717 m3/u
163 | DoCostPatch = True
164 | DoMassPatch = True
165 | TANK
166 | {
167 | name = LFO
168 | Volume = 100.0
169 | }
170 | }
171 | }
172 |
173 | @PART[M2X_XHub]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[Mk2Expansion]
174 | {
175 | !RESOURCE[LiquidFuel]
176 | {
177 |
178 | }
179 | !RESOURCE[Oxidizer]
180 | {
181 |
182 | }
183 | MODULE
184 | {
185 | name = ModuleTankManager
186 | Volume = 2.469136 //180.0 units of LF: conversion rate is 0.013717 m3/u
187 | DoCostPatch = True
188 | DoMassPatch = True
189 | TANK
190 | {
191 | name = LFO
192 | Volume = 100.0
193 | }
194 | }
195 | }
196 |
197 | @PART[M2X_LHub]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[Mk2Expansion]
198 | {
199 | !RESOURCE[LiquidFuel]
200 | {
201 |
202 | }
203 | !RESOURCE[Oxidizer]
204 | {
205 |
206 | }
207 | MODULE
208 | {
209 | name = ModuleTankManager
210 | Volume = 1.851852 //135.0 units of LF: conversion rate is 0.013717 m3/u
211 | DoCostPatch = True
212 | DoMassPatch = True
213 | TANK
214 | {
215 | name = LFO
216 | Volume = 100.0
217 | }
218 | }
219 | }
220 |
221 | @PART[M2X_THub]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[Mk2Expansion]
222 | {
223 | !RESOURCE[LiquidFuel]
224 | {
225 |
226 | }
227 | !RESOURCE[Oxidizer]
228 | {
229 |
230 | }
231 | MODULE
232 | {
233 | name = ModuleTankManager
234 | Volume = 2.469136 //180.0 units of LF: conversion rate is 0.013717 m3/u
235 | DoCostPatch = True
236 | DoMassPatch = True
237 | TANK
238 | {
239 | name = LFO
240 | Volume = 100.0
241 | }
242 | }
243 | }
244 | //:mode=c#:
245 |
--------------------------------------------------------------------------------
/AbstractResourceTank.cs:
--------------------------------------------------------------------------------
1 | // AbstractResourceTank.cs
2 | //
3 | // Author:
4 | // Allis Tauri
5 | //
6 | // Copyright (c) 2016 Allis Tauri
7 |
8 | using JetBrains.Annotations;
9 | using UnityEngine;
10 |
11 | namespace AT_Utils
12 | {
13 | public abstract class AbstractResourceTank : SerializableFiledsPartModule, IPartCostModifier, IPartMassModifier,
14 | IModuleInfo
15 | {
16 | ///
17 | /// The difference between the Part.cost and the initial value of the GetModuleCost.
18 | /// Used when the Patch flag is set.
19 | ///
20 | [KSPField(isPersistant = true)]
21 | public float CostPatch;
22 |
23 | ///
24 | /// If set, this flag causes the Module to save the initial difference between the
25 | /// Part.cost and GetModuleCost value so that the total part cost is unchanged.
26 | ///
27 | [KSPField(isPersistant = true)]
28 | public bool DoCostPatch;
29 |
30 | ///
31 | /// If set, this flag causes the Module to save the initial difference between the
32 | /// Part.mass and GetModuleMass value so that the total part cost is unchanged.
33 | ///
34 | [KSPField(isPersistant = true)]
35 | public bool DoMassPatch;
36 |
37 | ///
38 | /// The difference between the Part.mass and the initial value of the GetModuleMass.
39 | /// Used when the Patch flag is set.
40 | ///
41 | [KSPField(isPersistant = true)]
42 | public float MassPatch;
43 |
44 | ///
45 | /// The config node provided to OnLoad.
46 | ///
47 | [SerializeField]
48 | public ConfigNode ModuleSave;
49 |
50 | ///
51 | /// If true, the module save was received not in the flight scene.
52 | ///
53 | [KSPField(isPersistant = true)]
54 | public bool ModuleSaveFromPrefab;
55 |
56 | ///
57 | /// The volume of a tank in m^3. It is defined in a config or calculated from the part volume in editor.
58 | /// Cannot be changed in flight.
59 | ///
60 | [KSPField(isPersistant = true)]
61 | public float Volume = -1f;
62 |
63 | ///
64 | /// This is called within the GetModuleCost to calculate the cost of the tank.
65 | ///
66 | protected abstract float TankCost(float defaultCost);
67 |
68 | ///
69 | /// This is called within the GetModuleCost to calculate the cost of tank resources.
70 | ///
71 | /// If true, returns the cost of maxAmount of resources; of current amount otherwise.
72 | protected abstract float ResourcesCost(bool maxAmount = true);
73 |
74 | ///
75 | /// This is called within the GetModuleMass to calculate the mass of the tank.
76 | ///
77 | protected abstract float TankMass(float defaultMass);
78 |
79 | ///
80 | /// This is called within the GetModuleMass to calculate the mass of tank resources.
81 | ///
82 | /// If true, returns the mass of maxAmount of resources; of current amount otherwise.
83 | protected abstract float ResourcesMass(bool maxAmount = true);
84 |
85 | public override void OnLoad(ConfigNode node)
86 | {
87 | base.OnLoad(node);
88 | ModuleSaveFromPrefab = HighLogic.LoadedScene == GameScenes.LOADING;
89 | }
90 |
91 | public override void OnStart(StartState state)
92 | {
93 | base.OnStart(state);
94 | //this means the module was added by MM patch to an existing part
95 | if(HighLogic.LoadedSceneIsFlight && ModuleSaveFromPrefab)
96 | init_from_part();
97 | }
98 |
99 | protected abstract void init_from_part();
100 |
101 | #region IPart*Modifiers
102 | public virtual float GetModuleCost(float defaultCost, ModifierStagingSituation sit)
103 | {
104 | var cost = TankCost(defaultCost);
105 | if(DoCostPatch)
106 | {
107 | CostPatch = -Mathf.Min(cost + ResourcesCost(false), defaultCost);
108 | DoCostPatch = false;
109 | }
110 | var res = part.partInfo != null && part.partInfo.partPrefab == part
111 | ? ResourcesCost(false)
112 | : ResourcesCost();
113 | return cost + res + CostPatch;
114 | }
115 |
116 | public virtual ModifierChangeWhen GetModuleCostChangeWhen()
117 | {
118 | return ModifierChangeWhen.CONSTANTLY;
119 | }
120 |
121 | //this is not called by PartListTooltip.GetPartStats
122 | public virtual float GetModuleMass(float defaultMass, ModifierStagingSituation sit)
123 | {
124 | var mass = TankMass(defaultMass);
125 | // ReSharper disable once InvertIf
126 | if(DoMassPatch)
127 | {
128 | MassPatch = -Mathf.Min(mass, defaultMass);
129 | DoMassPatch = false;
130 | }
131 | return mass + MassPatch;
132 | }
133 |
134 | public virtual ModifierChangeWhen GetModuleMassChangeWhen()
135 | {
136 | return ModifierChangeWhen.CONSTANTLY;
137 | }
138 | #endregion
139 |
140 | #region IModInfo
141 | public override string GetInfo()
142 | {
143 | return "";
144 | }
145 |
146 | public virtual string GetModuleTitle()
147 | {
148 | return KSPUtil.PrintModuleName(moduleName);
149 | }
150 |
151 | public virtual string GetPrimaryField()
152 | {
153 | var info = "Additional Mass:\n";
154 | var tank = DoMassPatch ? 0 : TankMass(part.mass);
155 | var res = ResourcesMass(false);
156 | if(tank > 0)
157 | info += Utils.formatMass(tank) + " internals";
158 | if(res > 0)
159 | info += (tank > 0 ? "+" : "") + Utils.formatMass(res) + " resources";
160 | return tank > 0 || res > 0 ? info : "";
161 | }
162 |
163 | public Callback GetDrawModulePanelCallback()
164 | {
165 | return null;
166 | }
167 | #endregion
168 |
169 | #if DEBUG
170 | [UsedImplicitly]
171 | [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Module")]
172 | public string ThisModule = "";
173 |
174 | public override void OnAwake()
175 | {
176 | base.OnAwake();
177 | {
178 | ThisModule = GetType().Name;
179 | }
180 | }
181 | #endif
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/PlanetaryBaseInc_Patch.cfg:
--------------------------------------------------------------------------------
1 | //Configurable Containers patch for PlanetaryBaseInc
2 |
3 | //Rocket Fuel Tanks
4 | //Automatically generated using PyKSPutils library
5 | @PART[KKAOSS_small_Rocket_Fuel_Tank]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[PlanetaryBaseInc]
6 | {
7 | !RESOURCE[LiquidFuel]
8 | {
9 |
10 | }
11 | !RESOURCE[Oxidizer]
12 | {
13 |
14 | }
15 | MODULE
16 | {
17 | name = ModuleTankManager
18 | Volume = 1.234568 //90.0 units of LF: conversion rate is 0.013717 m3/u
19 | DoCostPatch = True
20 | DoMassPatch = True
21 | TANK
22 | {
23 | name = LFO
24 | Volume = 100.0
25 | }
26 | }
27 | }
28 |
29 | @PART[KKAOSS_Rocket_Fuel_Tank]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[PlanetaryBaseInc]
30 | {
31 | !RESOURCE[LiquidFuel]
32 | {
33 |
34 | }
35 | !RESOURCE[Oxidizer]
36 | {
37 |
38 | }
39 | MODULE
40 | {
41 | name = ModuleTankManager
42 | Volume = 2.469136 //180.0 units of LF: conversion rate is 0.013717 m3/u
43 | DoCostPatch = True
44 | DoMassPatch = True
45 | TANK
46 | {
47 | name = LFO
48 | Volume = 100.0
49 | }
50 | }
51 | }
52 |
53 | @PART[KKAOSS_Fuel_Tank_small]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[PlanetaryBaseInc]
54 | {
55 | !RESOURCE[LiquidFuel]
56 | {
57 |
58 | }
59 | !RESOURCE[Oxidizer]
60 | {
61 |
62 | }
63 | MODULE
64 | {
65 | name = ModuleTankManager
66 | Volume = 4.938272 //360.0 units of LF: conversion rate is 0.013717 m3/u
67 | DoCostPatch = True
68 | DoMassPatch = True
69 | TANK
70 | {
71 | name = LFO
72 | Volume = 100.0
73 | }
74 | }
75 | }
76 |
77 | @PART[KKAOSS_Fuel_Tank]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[PlanetaryBaseInc]
78 | {
79 | !RESOURCE[LiquidFuel]
80 | {
81 |
82 | }
83 | !RESOURCE[Oxidizer]
84 | {
85 |
86 | }
87 | MODULE
88 | {
89 | name = ModuleTankManager
90 | Volume = 9.876543 //720.0 units of LF: conversion rate is 0.013717 m3/u
91 | DoCostPatch = True
92 | DoMassPatch = True
93 | TANK
94 | {
95 | name = LFO
96 | Volume = 100.0
97 | }
98 | }
99 | }
100 |
101 | @PART[KKAOSS_adapter_g]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[PlanetaryBaseInc]
102 | {
103 | !RESOURCE[LiquidFuel]
104 | {
105 |
106 | }
107 | !RESOURCE[Oxidizer]
108 | {
109 |
110 | }
111 | MODULE
112 | {
113 | name = ModuleTankManager
114 | Volume = 0.617284 //45.0 units of LF: conversion rate is 0.013717 m3/u
115 | DoCostPatch = True
116 | DoMassPatch = True
117 | TANK
118 | {
119 | name = LFO
120 | Volume = 100.0
121 | }
122 | }
123 | }
124 | //LiquidFuel Tanks
125 | //Automatically generated using PyKSPutils library
126 | @PART[KKAOSS_Liquid_Fuel_Tank]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[PlanetaryBaseInc]
127 | {
128 | !RESOURCE[LiquidFuel]
129 | {
130 |
131 | }
132 | MODULE
133 | {
134 | name = ModuleTankManager
135 | Volume = 1.234568 //200.0 units of LiquidFuel: conversion rate is 0.006173 m3/u
136 | DoCostPatch = True
137 | DoMassPatch = True
138 | TANK
139 | {
140 | TankType = LiquidChemicals
141 | CurrentResource = LiquidFuel
142 | InitialAmount = 1.0
143 | Volume = 100.0
144 | }
145 | }
146 | }
147 | //MonoPropellant Tanks
148 | //Automatically generated using PyKSPutils library
149 | @PART[KKAOSS_RCS_Tank]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[PlanetaryBaseInc]
150 | {
151 | !RESOURCE[MonoPropellant]
152 | {
153 |
154 | }
155 | MODULE
156 | {
157 | name = ModuleTankManager
158 | Volume = 0.951087 //350.0 units of MonoPropellant: conversion rate is 0.002717 m3/u
159 | DoCostPatch = True
160 | DoMassPatch = True
161 | TANK
162 | {
163 | TankType = LiquidChemicals
164 | CurrentResource = MonoPropellant
165 | InitialAmount = 1.0
166 | Volume = 100.0
167 | }
168 | }
169 | }
170 | //XenonGas Tanks
171 | //Automatically generated using PyKSPutils library
172 | @PART[KKAOSS_Xenon_Tank]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[PlanetaryBaseInc]
173 | {
174 | !RESOURCE[XenonGas]
175 | {
176 |
177 | }
178 | MODULE
179 | {
180 | name = ModuleSwitchableTank
181 | Volume = 0.472335 //5250.0 units of XenonGas: conversion rate is 0.000090 m3/u
182 | InitialAmount = 1.0
183 | DoCostPatch = True
184 | DoMassPatch = True
185 | ChooseTankType = False
186 | TankType = Gases
187 | CurrentResource = XenonGas
188 | }
189 | }
190 | //Ore Tanks
191 | //Automatically generated using PyKSPutils library
192 | @PART[KKAOSS_Small_Ore_Tank]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[PlanetaryBaseInc]
193 | {
194 | !RESOURCE[Ore]
195 | {
196 |
197 | }
198 | MODULE
199 | {
200 | name = ModuleTankManager
201 | Volume = 1.081081 //200.0 units of Ore: conversion rate is 0.005405 m3/u
202 | DoCostPatch = True
203 | DoMassPatch = True
204 | TANK
205 | {
206 | TankType = Soil
207 | CurrentResource = Ore
208 | InitialAmount = 0.0
209 | Volume = 100.0
210 | }
211 | }
212 | }
213 |
214 | @PART[KKAOSS_Ore_Tank]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[PlanetaryBaseInc]
215 | {
216 | !RESOURCE[Ore]
217 | {
218 |
219 | }
220 | MODULE
221 | {
222 | name = ModuleTankManager
223 | Volume = 2.162162 //400.0 units of Ore: conversion rate is 0.005405 m3/u
224 | DoCostPatch = True
225 | DoMassPatch = True
226 | TANK
227 | {
228 | TankType = Soil
229 | CurrentResource = Ore
230 | InitialAmount = 0.0
231 | Volume = 100.0
232 | }
233 | }
234 | }
235 | //:mode=c#:
236 |
--------------------------------------------------------------------------------
/VolumeConfigsLibrary.cs:
--------------------------------------------------------------------------------
1 | // VolumeConfigsLibrary.cs
2 | //
3 | // Author:
4 | // Allis Tauri
5 | //
6 | // Copyright (c) 2016 Allis Tauri
7 |
8 | using System.Collections.Generic;
9 | using System.Linq;
10 |
11 | namespace AT_Utils
12 | {
13 | public static class VolumeConfigsLibrary
14 | {
15 | public const string USER_FILE = "VolumeConfigs.user";
16 |
17 | private static SortedList presets;
18 |
19 | private static SortedList user_configs;
20 | public static string UserFile => CustomConfig.GameDataFolder("ConfigurableContainers", USER_FILE);
21 |
22 | ///
23 | /// The library of tank configurations provided by mods.
24 | ///
25 | public static SortedList PresetConfigs
26 | {
27 | get
28 | {
29 | if(presets != null)
30 | return presets;
31 | var nodes = GameDatabase.Instance.GetConfigNodes(VolumeConfiguration.NODE_NAME);
32 | presets = new SortedList(nodes.Length);
33 | foreach(var n in nodes)
34 | {
35 | Utils.Debug("Parsing preset tank configuration:\n{}", n);
36 | var cfg = ConfigNodeObject.FromConfig(n);
37 | if(!cfg.Valid)
38 | {
39 | var msg = $"ConfigurableContainers: configuration \"{cfg.name}\" is INVALID.";
40 | Utils.Message(6, msg);
41 | Utils.Error(msg);
42 | continue;
43 | }
44 | try
45 | {
46 | presets.Add(cfg.name, cfg);
47 | }
48 | catch
49 | {
50 | Utils.Warning("SwitchableTankType: ignoring duplicate configuration of '{}' configuration. "
51 | + "Use ModuleManager to change the existing one.",
52 | cfg.name);
53 | }
54 | }
55 | Utils.Debug("Parsed presets: {}", presets);
56 | return presets;
57 | }
58 | }
59 |
60 | ///
61 | /// The library of tank configurations saved by the user.
62 | ///
63 | /// The user configs.
64 | public static SortedList UserConfigs
65 | {
66 | get
67 | {
68 | if(user_configs != null)
69 | return user_configs;
70 | user_configs = new SortedList();
71 | var node = CustomConfig.LoadNode(UserFile);
72 | Utils.Debug("Loading user configurations from:\n{}\n{}", UserFile, node);
73 | if(node == null)
74 | return user_configs;
75 | foreach(var n in node.GetNodes(VolumeConfiguration.NODE_NAME))
76 | {
77 | var cfg = ConfigNodeObject.FromConfig(n);
78 | if(!cfg.Valid)
79 | {
80 | var msg = $"ConfigurableContainers: configuration \"{cfg.name}\" is INVALID.";
81 | Utils.Message(6, msg);
82 | Utils.Error(msg);
83 | continue;
84 | }
85 | if(SwitchableTankType.HaveTankType(cfg.name))
86 | cfg.name += " [cfg]";
87 | if(PresetConfigs.ContainsKey(cfg.name))
88 | cfg.name += " [usr]";
89 | add_unique(cfg, user_configs);
90 | }
91 | Utils.Debug("Parsed user presets: {}", user_configs);
92 | return user_configs;
93 | }
94 | }
95 |
96 | private static void add_unique(VolumeConfiguration cfg, IDictionary db)
97 | {
98 | var index = 1;
99 | var basename = cfg.name;
100 | while(db.ContainsKey(cfg.name))
101 | cfg.name = string.Concat(basename, " ", index++);
102 | db.Add(cfg.name, cfg);
103 | }
104 |
105 | private static void save_user_configs()
106 | {
107 | var node = new ConfigNode();
108 | UserConfigs.ForEach(c => c.Value.SaveInto(node));
109 | if(CustomConfig.SaveNode(node, UserFile))
110 | return;
111 | Utils.Message("Unable to save tank configurations.");
112 | }
113 |
114 | public static void AddConfig(VolumeConfiguration cfg)
115 | {
116 | add_unique(cfg, UserConfigs);
117 | save_user_configs();
118 | }
119 |
120 | public static void AddOrSave(VolumeConfiguration cfg)
121 | {
122 | if(UserConfigs.ContainsKey(cfg.name))
123 | UserConfigs[cfg.name] = cfg;
124 | else
125 | UserConfigs.Add(cfg.name, cfg);
126 | save_user_configs();
127 | }
128 |
129 | public static bool RemoveConfig(string cfg_name)
130 | {
131 | if(!UserConfigs.Remove(cfg_name))
132 | return false;
133 | save_user_configs();
134 | return true;
135 | }
136 |
137 | public static List AllConfigNames(string[] include, string[] exclude)
138 | {
139 | var names = new List();
140 | if(include != null && include.Length > 0)
141 | exclude = SwitchableTankType.TankTypeNames(null, include).ToArray();
142 | if(exclude != null && exclude.Length > 0)
143 | {
144 | names.AddRange(
145 | from cfg in PresetConfigs
146 | where cfg.Value.ContainsTypes(exclude)
147 | select cfg.Value.name);
148 | names.AddRange(
149 | from cfg in UserConfigs
150 | where cfg.Value.ContainsTypes(exclude)
151 | select cfg.Value.name);
152 | }
153 | else
154 | {
155 | names.AddRange(PresetConfigs.Keys);
156 | names.AddRange(UserConfigs.Keys);
157 | }
158 | return names;
159 | }
160 |
161 | public static VolumeConfiguration GetConfig(string name)
162 | {
163 | if(string.IsNullOrEmpty(name))
164 | return null;
165 | if(PresetConfigs.TryGetValue(name, out var cfg))
166 | return cfg;
167 | if(UserConfigs.TryGetValue(name, out cfg))
168 | return cfg;
169 | return null;
170 | }
171 |
172 | public static string GetConfigInfo(string name, float volume_conversion = 1)
173 | {
174 | var config = GetConfig(name);
175 | return config == null ? string.Empty : config.Info(volume_conversion);
176 | }
177 |
178 | public static bool HaveUserConfig(string name)
179 | {
180 | return UserConfigs.ContainsKey(name);
181 | }
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/CC.UI/AddTankControl.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using AT_Utils.UI;
4 | using UnityEngine;
5 | using UnityEngine.UI;
6 |
7 | namespace CC.UI
8 | {
9 | public class AddTankControl : TankManagerUIPart
10 | {
11 | public enum VolumeUnits { CUBIC_METERS, PARTS }
12 |
13 | private static readonly Dictionary unitNames = new Dictionary
14 | {
15 | { VolumeUnits.CUBIC_METERS, "m3" }, { VolumeUnits.PARTS, "%" }
16 | };
17 |
18 | private static readonly int numUnits = Enum.GetNames(typeof(VolumeUnits)).Length;
19 |
20 | public Dropdown
21 | tankTypeDropdown;
22 |
23 | public TooltipTrigger
24 | tankTypeTooltip;
25 |
26 | public InputField
27 | volumeField;
28 |
29 | public Button
30 | unitsSwitchButton,
31 | maxVolumeButton,
32 | halfVolumeButton,
33 | addButton;
34 |
35 | public Text
36 | unitsLabel;
37 |
38 | public Colorizer
39 | volumeFieldColorizer;
40 |
41 | public TooltipTrigger
42 | volumeFieldTooltip;
43 |
44 | public ITankManager tankManager;
45 | public VolumeUnits currentUnits = VolumeUnits.CUBIC_METERS;
46 |
47 | public void SetTankManager(ITankManager newTankManager)
48 | {
49 | if(newTankManager == tankManager)
50 | return;
51 | tankManager = newTankManager;
52 | if(tankManager == null)
53 | return;
54 | UpdateTankTypes();
55 | }
56 |
57 | private void Awake()
58 | {
59 | updateUnitsLabel();
60 | tankTypeDropdown.onValueChanged.AddListener(updateTankTypeDropdownTooltip);
61 | volumeField.onValueChanged.AddListener(onVolumeChange);
62 | unitsSwitchButton.onClick.AddListener(onUnitsSwitch);
63 | maxVolumeButton.onClick.AddListener(setMaxVolume);
64 | halfVolumeButton.onClick.AddListener(setHalfVolume);
65 | addButton.onClick.AddListener(addTank);
66 | volumeNotOk("Enter the volume to create a new tank");
67 | }
68 |
69 | private void OnDestroy()
70 | {
71 | tankTypeDropdown.onValueChanged.RemoveAllListeners();
72 | volumeField.onValueChanged.RemoveAllListeners();
73 | unitsSwitchButton.onClick.RemoveAllListeners();
74 | maxVolumeButton.onClick.RemoveAllListeners();
75 | halfVolumeButton.onClick.RemoveAllListeners();
76 | addButton.onClick.RemoveAllListeners();
77 | }
78 |
79 | private float partsToVolume(float value) => tankManager.AvailableVolume * value;
80 |
81 | private float volumeToParts(float value) =>
82 | tankManager.AvailableVolume > 0
83 | ? value / tankManager.AvailableVolume
84 | : 0;
85 |
86 | private string tankType => tankManager.SupportedTypes[tankTypeDropdown.value];
87 |
88 | private void onUnitsSwitch()
89 | {
90 | var oldUnits = currentUnits;
91 | currentUnits = (VolumeUnits)(((int)currentUnits + 1) % numUnits);
92 | updateUnitsLabel();
93 | if(string.IsNullOrEmpty(volumeField.text) || !float.TryParse(volumeField.text, out var volume))
94 | return;
95 | // ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
96 | switch(currentUnits)
97 | {
98 | case VolumeUnits.CUBIC_METERS when oldUnits == VolumeUnits.PARTS:
99 | setVolume(volume / 100);
100 | break;
101 | case VolumeUnits.PARTS when oldUnits == VolumeUnits.CUBIC_METERS:
102 | setVolume(volumeToParts(volume));
103 | break;
104 | }
105 | }
106 |
107 | private void updateUnitsLabel()
108 | {
109 | unitsLabel.text = unitNames[currentUnits];
110 | }
111 |
112 | public void UpdateTankTypes()
113 | {
114 | if(tankManager == null)
115 | return;
116 | tankTypeDropdown.SetOptionsSafe(UI_Utils.namesToOptions(tankManager.SupportedTypes));
117 | updateTankTypeDropdownTooltip(tankTypeDropdown.value);
118 | }
119 |
120 | private void updateTankTypeDropdownTooltip(int index) =>
121 | tankTypeTooltip.SetText(tankManager.GetTypeInfo(tankManager.SupportedTypes[index]));
122 |
123 | private void setMaxVolume() => setVolume(1, true);
124 |
125 | private void setHalfVolume() => setVolume(0.5f, true);
126 |
127 | private void setVolume(float part, bool updateState = false)
128 | {
129 | var newVolume = currentUnits == VolumeUnits.CUBIC_METERS
130 | ? partsToVolume(part)
131 | : part * 100;
132 | volumeField.SetTextWithoutNotify(newVolume.ToString("G9"));
133 | if(!updateState)
134 | return;
135 | if(tankManager.AvailableVolume > 0)
136 | volumeOk(tankManager.OnVolumeChanged(tankType,
137 | currentUnits == VolumeUnits.CUBIC_METERS
138 | ? newVolume
139 | : partsToVolume(part)));
140 | else
141 | volumeNotOk("No free space left");
142 | }
143 |
144 |
145 | private void volumeNotOk(string error)
146 | {
147 | volumeFieldColorizer.SetColor(Colors.Danger);
148 | volumeFieldTooltip.SetText(error);
149 | addButton.SetInteractable(false);
150 | }
151 |
152 | private void volumeOk(string tooltip = null)
153 | {
154 | volumeFieldColorizer.SetColor(Colors.Neutral);
155 | volumeFieldTooltip.SetText(tooltip ?? "Volume of the new tank");
156 | addButton.SetInteractable(true);
157 | }
158 |
159 | private void onVolumeChange(string value)
160 | {
161 | if(!float.TryParse(value, out var newValue))
162 | {
163 | volumeNotOk("Entered value is not a number");
164 | return;
165 | }
166 | if(newValue <= 0)
167 | {
168 | volumeNotOk("Enter positive number");
169 | return;
170 | }
171 | string info = null;
172 | // ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
173 | switch(currentUnits)
174 | {
175 | case VolumeUnits.CUBIC_METERS:
176 | if(newValue > tankManager.AvailableVolume)
177 | {
178 | volumeNotOk("Entered volume is greater than the available volume");
179 | return;
180 | }
181 | info = tankManager.OnVolumeChanged(tankType, newValue);
182 | break;
183 | case VolumeUnits.PARTS:
184 | if(newValue > 100)
185 | {
186 | volumeNotOk("Entered volume is greater than the available volume");
187 | return;
188 | }
189 | info = tankManager.OnVolumeChanged(tankType, partsToVolume(newValue / 100));
190 | break;
191 | }
192 | volumeOk(info);
193 | }
194 |
195 | private void addTank()
196 | {
197 | if(!float.TryParse(volumeField.text, out var tankVolume))
198 | return;
199 | if(currentUnits == VolumeUnits.PARTS)
200 | tankVolume = Mathf.Clamp(partsToVolume(tankVolume / 100),
201 | 0,
202 | tankManager.AvailableVolume);
203 | if(!tankManager.AddTank(tankType, tankVolume))
204 | return;
205 | volumeField.SetTextWithoutNotify("");
206 | addButton.SetInteractable(false);
207 | managerUI.UpdateDisplay();
208 | }
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/SpaceY-Expanded_Patch.cfg:
--------------------------------------------------------------------------------
1 | //Configurable Containers patch for SpaceY-Expanded
2 |
3 | //Rocket Fuel Tanks
4 | //Automatically generated using PyKSPutils library
5 | @PART[SYtank7mL03750]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Expanded]
6 | {
7 | !RESOURCE[LiquidFuel]
8 | {
9 |
10 | }
11 | !RESOURCE[Oxidizer]
12 | {
13 |
14 | }
15 | MODULE
16 | {
17 | name = ModuleTankManager
18 | Volume = 177.777778 //12960.0 units of LF: conversion rate is 0.013717 m3/u
19 | DoCostPatch = True
20 | DoMassPatch = True
21 | TANK
22 | {
23 | name = LFO
24 | Volume = 100.0
25 | }
26 | }
27 | }
28 |
29 | @PART[SYtank10mL22500]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Expanded]
30 | {
31 | !RESOURCE[LiquidFuel]
32 | {
33 |
34 | }
35 | !RESOURCE[Oxidizer]
36 | {
37 |
38 | }
39 | MODULE
40 | {
41 | name = ModuleTankManager
42 | Volume = 1866.666667 //136080.0 units of LF: conversion rate is 0.013717 m3/u
43 | DoCostPatch = True
44 | DoMassPatch = True
45 | TANK
46 | {
47 | name = LFO
48 | Volume = 100.0
49 | }
50 | }
51 | }
52 |
53 | @PART[SYtank10mL15000]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Expanded]
54 | {
55 | !RESOURCE[LiquidFuel]
56 | {
57 |
58 | }
59 | !RESOURCE[Oxidizer]
60 | {
61 |
62 | }
63 | MODULE
64 | {
65 | name = ModuleTankManager
66 | Volume = 1244.444444 //90720.0 units of LF: conversion rate is 0.013717 m3/u
67 | DoCostPatch = True
68 | DoMassPatch = True
69 | TANK
70 | {
71 | name = LFO
72 | Volume = 100.0
73 | }
74 | }
75 | }
76 |
77 | @PART[SYtank10mL07500]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Expanded]
78 | {
79 | !RESOURCE[LiquidFuel]
80 | {
81 |
82 | }
83 | !RESOURCE[Oxidizer]
84 | {
85 |
86 | }
87 | MODULE
88 | {
89 | name = ModuleTankManager
90 | Volume = 622.222222 //45360.0 units of LF: conversion rate is 0.013717 m3/u
91 | DoCostPatch = True
92 | DoMassPatch = True
93 | TANK
94 | {
95 | name = LFO
96 | Volume = 100.0
97 | }
98 | }
99 | }
100 |
101 | @PART[SYtank7m5mAdapter2]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Expanded]
102 | {
103 | !RESOURCE[LiquidFuel]
104 | {
105 |
106 | }
107 | !RESOURCE[Oxidizer]
108 | {
109 |
110 | }
111 | MODULE
112 | {
113 | name = ModuleTankManager
114 | Volume = 133.333333 //9720.0 units of LF: conversion rate is 0.013717 m3/u
115 | DoCostPatch = True
116 | DoMassPatch = True
117 | TANK
118 | {
119 | name = LFO
120 | Volume = 100.0
121 | }
122 | }
123 | }
124 |
125 | @PART[SYtank10mL03750]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Expanded]
126 | {
127 | !RESOURCE[LiquidFuel]
128 | {
129 |
130 | }
131 | !RESOURCE[Oxidizer]
132 | {
133 |
134 | }
135 | MODULE
136 | {
137 | name = ModuleTankManager
138 | Volume = 311.111111 //22680.0 units of LF: conversion rate is 0.013717 m3/u
139 | DoCostPatch = True
140 | DoMassPatch = True
141 | TANK
142 | {
143 | name = LFO
144 | Volume = 100.0
145 | }
146 | }
147 | }
148 |
149 | @PART[SYtank7mCone1]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Expanded]
150 | {
151 | !RESOURCE[LiquidFuel]
152 | {
153 |
154 | }
155 | !RESOURCE[Oxidizer]
156 | {
157 |
158 | }
159 | MODULE
160 | {
161 | name = ModuleTankManager
162 | Volume = 100.0 //7290.0 units of LF: conversion rate is 0.013717 m3/u
163 | DoCostPatch = True
164 | DoMassPatch = True
165 | TANK
166 | {
167 | name = LFO
168 | Volume = 100.0
169 | }
170 | }
171 | }
172 |
173 | @PART[SYtank7mL15000]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Expanded]
174 | {
175 | !RESOURCE[LiquidFuel]
176 | {
177 |
178 | }
179 | !RESOURCE[Oxidizer]
180 | {
181 |
182 | }
183 | MODULE
184 | {
185 | name = ModuleTankManager
186 | Volume = 711.111111 //51840.0 units of LF: conversion rate is 0.013717 m3/u
187 | DoCostPatch = True
188 | DoMassPatch = True
189 | TANK
190 | {
191 | name = LFO
192 | Volume = 100.0
193 | }
194 | }
195 | }
196 |
197 | @PART[SYtank7mL07500]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Expanded]
198 | {
199 | !RESOURCE[LiquidFuel]
200 | {
201 |
202 | }
203 | !RESOURCE[Oxidizer]
204 | {
205 |
206 | }
207 | MODULE
208 | {
209 | name = ModuleTankManager
210 | Volume = 355.555556 //25920.0 units of LF: conversion rate is 0.013717 m3/u
211 | DoCostPatch = True
212 | DoMassPatch = True
213 | TANK
214 | {
215 | name = LFO
216 | Volume = 100.0
217 | }
218 | }
219 | }
220 |
221 | @PART[SYtank7m5mAdapter]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Expanded]
222 | {
223 | !RESOURCE[LiquidFuel]
224 | {
225 |
226 | }
227 | !RESOURCE[Oxidizer]
228 | {
229 |
230 | }
231 | MODULE
232 | {
233 | name = ModuleTankManager
234 | Volume = 177.777778 //12960.0 units of LF: conversion rate is 0.013717 m3/u
235 | DoCostPatch = True
236 | DoMassPatch = True
237 | TANK
238 | {
239 | name = LFO
240 | Volume = 100.0
241 | }
242 | }
243 | }
244 |
245 | @PART[SYtank10m7mAdapter]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Expanded]
246 | {
247 | !RESOURCE[LiquidFuel]
248 | {
249 |
250 | }
251 | !RESOURCE[Oxidizer]
252 | {
253 |
254 | }
255 | MODULE
256 | {
257 | name = ModuleTankManager
258 | Volume = 236.444444 //17236.8 units of LF: conversion rate is 0.013717 m3/u
259 | DoCostPatch = True
260 | DoMassPatch = True
261 | TANK
262 | {
263 | name = LFO
264 | Volume = 100.0
265 | }
266 | }
267 | }
268 |
269 | @PART[SYadapter7m3mX4]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[SpaceY-Expanded]
270 | {
271 | !RESOURCE[LiquidFuel]
272 | {
273 |
274 | }
275 | !RESOURCE[Oxidizer]
276 | {
277 |
278 | }
279 | MODULE
280 | {
281 | name = ModuleTankManager
282 | Volume = 24.691358 //1800.0 units of LF: conversion rate is 0.013717 m3/u
283 | DoCostPatch = True
284 | DoMassPatch = True
285 | TANK
286 | {
287 | name = LFO
288 | Volume = 100.0
289 | }
290 | }
291 | }
292 | //:mode=c#:
293 |
--------------------------------------------------------------------------------
/Cryogenics/ResourceBoiloff.cs:
--------------------------------------------------------------------------------
1 | // Boiloff.cs
2 | //
3 | // Author:
4 | // Allis Tauri
5 | //
6 | // Copyright (c) 2016 Allis Tauri
7 |
8 | using System;
9 | using JetBrains.Annotations;
10 | using UnityEngine;
11 |
12 | namespace AT_Utils
13 | {
14 | public class ResourceBoiloff : ConfigNodeObject
15 | {
16 | [UsedImplicitly] public new const string NODE_NAME = "RES_BOILOFF";
17 |
18 | protected readonly Part part;
19 | protected PartResource resource;
20 | protected CryogenicsParams.CryoResource cryo_info;
21 | private readonly ModuleSwitchableTank tank;
22 |
23 | ///
24 | /// Current temperature of the resource mass.
25 | ///
26 | [Persistent]
27 | public double CoreTemperature = -1;
28 |
29 | ///
30 | /// The last UT the core temperature was updated.
31 | ///
32 | [Persistent]
33 | public double LastUpdateTime = -1;
34 |
35 | ///
36 | /// The temperature (K) at which the boiloff occurs.
37 | ///
38 | protected double boiloffTemperature;
39 |
40 | ///
41 | /// The vaporization heat of the resource per unit.
42 | ///
43 | protected double vaporizationHeat;
44 |
45 | ///
46 | /// The heat capacity of the resource per unit.
47 | ///
48 | protected double specificHeatCapacity;
49 |
50 | ///
51 | /// The insulator conductivity in kW/s.
52 | ///
53 | protected double insulatorConductivity;
54 |
55 | ///
56 | /// This is true if the SetResource is successful, false otherwise.
57 | ///
58 | public bool Valid => cryo_info != null;
59 |
60 | protected double temperatureTransfer(
61 | double deltaTime,
62 | double partThermalMass,
63 | double resThermalMass,
64 | double partT,
65 | double resT,
66 | out double equilibriumT
67 | )
68 | {
69 | var totalThermalMass = partThermalMass + resThermalMass;
70 | equilibriumT = (partT * partThermalMass + resT * resThermalMass) / totalThermalMass;
71 | return 1
72 | - Math.Exp(deltaTime
73 | * insulatorConductivity
74 | * totalThermalMass
75 | / (partThermalMass + resThermalMass));
76 | }
77 |
78 | protected double CoreDeltaTAt300K(out double partThermalMass, out double resThermalMass)
79 | {
80 | resThermalMass = resource.amount * specificHeatCapacity;
81 | partThermalMass = part.mass * PhysicsGlobals.StandardSpecificHeatCapacity * part.thermalMassModifier;
82 | var transfer = temperatureTransfer(1,
83 | partThermalMass,
84 | resThermalMass,
85 | 300,
86 | boiloffTemperature,
87 | out var equilibriumT);
88 | // Utils.Log("Eq.T {}, C.dT {}, conductivity {}, (P.tM {} + C.tM {})/(P.tM*C.tM) = {}, transfer {}",
89 | // equilibriumT, (equilibriumT-boiloffTemperature)*transfer,
90 | // insulatorConductivity,
91 | // partThermalMass, resThermalMass, (partThermalMass+resThermalMass)/(resThermalMass*partThermalMass),
92 | // transfer);//debug
93 | return (equilibriumT - boiloffTemperature) * transfer;
94 | }
95 |
96 | public double BoiloffAt300K
97 | {
98 | get
99 | {
100 | var CoreDeltaT = CoreDeltaTAt300K(out _, out _);
101 | return resource.amount * (1 - Math.Exp(-CoreDeltaT * specificHeatCapacity / vaporizationHeat));
102 | }
103 | }
104 |
105 | public ResourceBoiloff(ModuleSwitchableTank tank)
106 | {
107 | this.tank = tank;
108 | part = tank.part;
109 | }
110 |
111 | public virtual void SetResource(PartResource res)
112 | {
113 | if(res == null)
114 | {
115 | resource = null;
116 | cryo_info = null;
117 | return;
118 | }
119 | resource = res;
120 | cryo_info = CryogenicsParams.Instance.GetResource(res);
121 | if(cryo_info == null)
122 | return;
123 | boiloffTemperature = cryo_info.BoiloffTemperature;
124 | specificHeatCapacity = res.info.specificHeatCapacity * res.info.density;
125 | vaporizationHeat = cryo_info.GetVaporizationHeat(res) * res.info.density;
126 | UpdateInsulation();
127 | }
128 |
129 | public void UpdateInsulation()
130 | {
131 | insulatorConductivity = CryogenicsParams.GetInsulatorConductivity(tank.Volume);
132 | }
133 |
134 | protected virtual void UpdateCoreTemperature(double deltaTime)
135 | {
136 | var resThermalMass = resource.amount * specificHeatCapacity;
137 | var partThermalMass = Math.Max(part.thermalMass - resThermalMass, 1e-3);
138 | var transfer = temperatureTransfer(deltaTime,
139 | partThermalMass,
140 | resThermalMass,
141 | part.temperature,
142 | CoreTemperature,
143 | out var equilibriumT);
144 | var CoreDeltaT = (equilibriumT - CoreTemperature) * transfer;
145 | var PartDeltaT = (equilibriumT - part.temperature) * transfer;
146 | part.AddThermalFlux(PartDeltaT * part.thermalMass / TimeWarp.fixedDeltaTime);
147 | // Utils.Log("P.T {} > Eq.T {} < C.T {}, P.dT {}, C.dT {}, conductivity {}, (P.tM {} + C.tM {})/(P.tM*C.tM) = {}, transfer {}",
148 | // part.temperature, equilibriumT, CoreTemperature, PartDeltaT, CoreDeltaT,
149 | // insulatorConductivity,
150 | // partThermalMass, resThermalMass, (partThermalMass+resThermalMass)/(resThermalMass*partThermalMass),
151 | // transfer);//debug
152 | CoreTemperature += CoreDeltaT;
153 | }
154 |
155 | public virtual void FixedUpdate()
156 | {
157 | if(!HighLogic.LoadedSceneIsFlight
158 | || resource == null
159 | || part == null
160 | || cryo_info == null
161 | || resource.amount <= 0)
162 | return;
163 | if(LastUpdateTime < 0)
164 | CoreTemperature = resource.amount > 0
165 | ? Math.Max(boiloffTemperature - 10, PhysicsGlobals.SpaceTemperature)
166 | : part.temperature;
167 | var deltaTime = GetDeltaTime();
168 | // Utils.Log("deltaTime: {}, fixedDeltaTime {}", deltaTime, TimeWarp.fixedDeltaTime);//debug
169 | if(deltaTime < 0)
170 | return;
171 | UpdateCoreTemperature(deltaTime);
172 | var dTemp = CoreTemperature - boiloffTemperature;
173 | if(dTemp <= 0)
174 | return;
175 | var boiled_off = resource.amount * (1 - Math.Exp(-dTemp * specificHeatCapacity / vaporizationHeat));
176 | if(boiled_off > resource.amount)
177 | boiled_off = resource.amount;
178 | // Utils.Log("last amount {}, amount {}, boiled off {}",
179 | // resource.amount, resource.amount-boiled_off, boiled_off);//debug
180 | resource.amount -= boiled_off;
181 | if(resource.amount < 1e-9)
182 | resource.amount = 0;
183 | CoreTemperature = boiloffTemperature;
184 | }
185 |
186 | private double GetDeltaTime()
187 | {
188 | if(Time.timeSinceLevelLoad < 1 || !FlightGlobals.ready)
189 | return -1;
190 | if(LastUpdateTime < 0)
191 | {
192 | LastUpdateTime = Planetarium.GetUniversalTime();
193 | return TimeWarp.fixedDeltaTime;
194 | }
195 | var time = Planetarium.GetUniversalTime();
196 | var dT = time - LastUpdateTime;
197 | LastUpdateTime = time;
198 | return dT;
199 | }
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/ChangeLog.md:
--------------------------------------------------------------------------------
1 | # Configurable Containers Change Log
2 |
3 | ## v2.6.2.1 / 2022-04-01
4 |
5 | * Compiled for KSP 1.12.3
6 | * Internal project changes for CI/CD
7 |
8 | ## v2.6.2
9 |
10 | * Compatible with KSP-1.11.1
11 | * UI: using G9 formatter instead of R for better performance
12 | * API: removed `ITankManager.AvailableVolumePercent`
13 |
14 | ## v2.6.1
15 |
16 | * **Parts**
17 | * **Hangar**: allow surface attachment of all the containers
18 | * Fixed CC behaviour in symmetry groups
19 | * Fixed resource amount update when tank volume is changed
20 | (by APR or TweakScale)
21 | * Fixed part cloning when the part is resized by TweakScale
22 | * Fixed UI not showing when the `VolumeConfigs.user` file is absent
23 | * Using bundle shipped with AT_Utils
24 |
25 | ## v2.6.0 - **New UI**
26 |
27 | * **Reimplemented tank manager UI from scratch with uGUI framework**
28 | * **Fixed counterparts rescaling with TweakScale**
29 | * Improved tank types/configs tooltips by emphasizing with bold font
30 | * Minor performance improvements
31 |
32 | ## v2.5.0.1
33 |
34 | * Compiled against KSP-1.10
35 |
36 | ## v2.5.0
37 |
38 | * **Moved CC configs to AT_Utils GameData and removed CC-Core**
39 | * Added resource **max amount and max mass display**
40 | * **Added new patches**
41 | * Dodo Labs - Stockalike Electron
42 | * Mk2 Hypersonic Systems
43 | * Mk-X
44 | * Hyper Propulsion
45 | * **Updated** patches
46 | * BDB
47 | * Mk2 Expansion
48 | * ReStock+
49 | * Only filter parts with **B9 Part Switch** if it has SUBTYPE with
50 | a tankType defined. This allowed to **add CC to several parts** that
51 | only had mesh/node variants, not the resource switching. **Affects**
52 | * Bluedog Design Bureau
53 | * Mk2 Expansion
54 | * Mk3 Expansion
55 | * Moved hangar resource tanks to FuelTank category
56 | * Removed the OPT patch since OPT Reconfig provides its own now
57 | * Minor fixes and improvements
58 | * Updated the list of supported mods in netkan
59 |
60 | ## v2.4.8.3
61 |
62 | * Compiled against AT_Utils 1.9.3
63 |
64 | ## v2.4.8.2
65 |
66 | * **Compatible with KSP-1.9**
67 | * Compiled against AT_Utils 1.9.2
68 |
69 | ## v2.4.8.1
70 |
71 | * Compiled against AT_Utils 1.9.1
72 |
73 | ## v2.4.8
74 |
75 | * Hangar patch:
76 | * Added a procedural fuel tank made from Procedural Adapter
77 | * In APR ResourceUpdater no longer handles dynamic resources
78 | * Corrected LH2O ratio in CryoEngines tank config
79 | * Added CryoCooling variant of LH2O tank config
80 | * Fixed InvalidOperationException on tank add/remove
81 |
82 | ## v2.4.7.1
83 |
84 | * Updated AT_Utils
85 |
86 | ## v2.4.7
87 |
88 | * Supports KSP-1.8.1
89 | * IFS is fully compatible with CC patches
90 | * Rebalanced "Snacks and Soil" tank config to keep 1u food to 1u soil
91 | as suggested in #30 by @LouisCyfer
92 | * Small performance improvements.
93 |
94 | ## v2.4.6
95 |
96 | * **Added patches**
97 | * Mining Expansion
98 | * Kerbal Planetary Base System
99 | * ReStock+
100 | * Streamline - Engines and Tanks
101 | * **Updated patches**
102 | * Bluedog Design Bureau
103 | * Mk2 Expansion
104 | * Mk3 Expansion
105 | * Near Future Propulsion
106 | * Mk2.5 Spaceplane Parts
107 | * Squad
108 | * Corrected a typo in squad xenon tanks' names
109 |
110 | ## v2.4.5
111 |
112 | * Added ability to change UI color scheme at runtime
113 | * Added "C" button to the tank manager window titlebar which summons the Color Scheme dialog
114 |
115 | ## v2.4.4
116 |
117 | * Compatible with KSP-1.7
118 | * Fixed MM Warnings (multiple NEEDS)
119 | * Fixed in-editor part cloning/symmetry bug (issue #31)
120 |
121 | ## v2.4.3.2 -4
122 |
123 | * Version bumps due to updates of AT_Utils.
124 |
125 | ## v2.4.3.1
126 |
127 | * SpecializedParts are also used by GC now
128 |
129 | ## v2.4.3
130 |
131 | * Added patches for Bluedog Design Bureau and Making History Expansion.
132 |
133 | ## v2.4.2
134 |
135 | * Renamed Resource to CryoResource for clarity and to prevent name clashes.
136 | * Twealscaled tanks retain volume on load. Fixed #22.
137 | * Corrected calculation of ModuleSaveFromPrefab flag.
138 | * Removed support for ProceduralParts =(
139 | * Added SpareParts to Components TankType for DangIt.
140 | * Removed FOR[ConfigurableContainers] stanza, changed ref to KSP 1.4.1
141 | * Updater Squad patch
142 | * Supporting KWRocketryRebalanced. Can't support multiple KWR flavors.
143 | * Well, it's possible with multiple .ckans, but I don't have the time =\
144 | * Updated patches for Mk2/Mk3Exp, FTPlus, Mk2Plane
145 |
146 | ## v2.4.1.1
147 |
148 | * Fixed Cryogenic/CryoCooling NEEDS, fixed KarbonitePlus requirement for Metal.
149 | * Update TankTypes.cfg
150 | * added Snacks support (Snacks --> Food, Soil --> Soil)
151 | * modified KolonyTools support --> ColonySupplies are visible/usable/transferable even if USI-LS is not installed
152 | * Added Chemicals to LiquidChemicals for KolonyTools.
153 | * Attempt to fix #10 using the patch suggested by @Starwaster.
154 | * Fixed issues:
155 | * 16 - Attempting to change configuration when none exists results in NullReferenceException
156 | * 18 - Tweakscaled tank saved prior to installation of CC gets capacity reset to un-scaled value
157 | * 20 - Lag/freeze when placing tanks in VAB
158 |
159 | ## v2.4.1
160 |
161 | * All tanks except high-pressure now use TankManager. Wings use IncludeTankType to restrict contents to liquid chemicals.
162 | * Updated patches:
163 | * Stock
164 | * FuleTanks+
165 | * ModularRockeSystems
166 | * NearFuture
167 | * KWRocketry
168 | * Mk3 Expansion
169 | * Added patches:
170 | * Mk2.5 spaceplane parts
171 | * Fuel Tank Expansion
172 | * B9 Procedural Wings
173 | * Added patch for B9 mods **made by ShadyAct** to *IntrusivePatches* optional folder. See the archive structure and the included readme file for details.
174 | * Part info now respects Include/ExcludeTankTypes options.
175 | * CC modules are now properly initialized when they're added to existing parts (in flight) by MM. **This should fix most of incompatibility with other fuel switches.**
176 |
177 | ## v2.4.0.6
178 |
179 | * Compatible with KSP-1.3
180 | * Fixed Metal tank type as pointed out by TheKurgan.
181 | * Removed Plutonium-238 as it is internal resource for USI
182 |
183 | ## v2.4.0.5
184 |
185 | * Corrected CKAN metadata.
186 | * Small bugfixes.
187 |
188 | ## v2.4.0.4
189 |
190 | * Added patch for GPOSpeedFuelPump for time being.
191 |
192 | ## v2.4.0.3
193 |
194 | * Added FindTankType by resource_name method to TankType library.
195 | * Added ForceSwitchResource method to SwitchableTank.
196 | * GroundConstruction will be using MaterialKits, so added it to Components TankType users.
197 | * Use round-trip format for the volume field.
198 |
199 | ## v2.4.0.2
200 |
201 | * Fixed TankManager initialization with disabled AddRemove capability.
202 | * Fixed TankManager initialization using empty config.
203 | * Fixed in-flight tank creation.
204 |
205 | ## v2.4.0.1
206 |
207 | * Added patch for **OPT Spaceplane Parts** made by **octarine-noise**
208 | * Small bugfixes.
209 |
210 | ## v2.4.0
211 |
212 | * Compiled against KSP-1.2.2.
213 | * Added boiloff and active cooling for cryogenic resources based on simple thermodynamics.
214 | * Added CryoCooling tank type.
215 | * Added KSPIE resources to TankTypes.cfg.
216 | * Added tooltips with Info to TankType choosers.
217 | * Replaced Tank Type dropdown list with the LeftRightChooser.
218 |
219 | ## v2.3.1
220 |
221 | * Corrected Cryogenic tank type parameters.
222 | * Fixed Food tank type.
223 | * In Editor automatically remove current resource when trying to switch it or the tank type.
224 | * Fixed Soil TANKTYPE definition.
225 | * Fixed installation directive in CC-Core.netkan
226 | * Fixed ProceduralParts bug and return to VAB bug. Closed #3 and #4.
227 |
228 | ## v2.3.0
229 |
230 | * Added per-tank volume editing and volume definition in % along with m3.
231 | * Added support for:
232 | * **Tweak Scale**
233 | * **Procedural Parts**
234 | * Parts ++with stock resources++ converted:
235 | * Stock
236 | * KW Rocketry
237 | * Mk2 Expansion
238 | * Mk3 Expansion
239 | * SpaceY-Lifters
240 | * SpaceY-Expanded
241 | * Fuel Tanks Plus
242 | * Modular Rocket Systems
243 | * Standard Propulsion Systems
244 | * Near Future Propulsion
245 | * Spherical and Toroidal Tank Pack
246 | * Supported resources:
247 | * Stock
248 | * TAC Life Support
249 | * Extrapalentary Launchapads
250 | * Near Future Propulsion
251 | * All USI
252 | * *Some* of KSPIE
253 | * Different TankTypes can now have different additional mass
254 | * Added Tank Types:
255 | * Battery
256 | * Cryogenic
257 | * Added Tank Setups:
258 | * TAC Life Support -- with food, water and oxigen. Made by **Bit Fiddler**.
259 | * LH2O -- with Liquid Hydrogen and Oxidizer for CryoEngines.
260 | * Corrected unit/volume ratios for:
261 | * Monopropellant
262 | * Argon Gas
263 | * Liquid Hydrogen
264 | * Liquid Methane (which mod uses it?)
265 | * Karbonite
266 |
--------------------------------------------------------------------------------
/ModuleTankManager.cs:
--------------------------------------------------------------------------------
1 | // ModuleTankManager.cs
2 | //
3 | // Author:
4 | // Allis Tauri
5 | //
6 | // Copyright (c) 2016 Allis Tauri
7 |
8 | using CC.UI;
9 | using JetBrains.Annotations;
10 |
11 | namespace AT_Utils
12 | {
13 | public class ModuleTankManager : AbstractResourceTank, ITankManagerHost, ITankManagerCapabilities
14 | {
15 | private SwitchableTankManager tank_manager;
16 |
17 | public SwitchableTankManager GetTankManager()
18 | {
19 | return tank_manager;
20 | }
21 |
22 | public override string GetInfo()
23 | {
24 | var info = $"Max. Volume: {Utils.formatVolume(Volume)}\n";
25 | if(ModuleSave != null)
26 | info += SwitchableTankManager.GetInfo(this, ModuleSave);
27 | return info.Trim();
28 | }
29 |
30 | protected override float TankCost(float defaultCost)
31 | {
32 | if(ModuleSave == null || tank_manager != null)
33 | return 0;
34 | var volumes = ConfigNodeObject.FromConfig(ModuleSave);
35 | return volumes.Cost();
36 | }
37 |
38 | protected override float TankMass(float defaultMass)
39 | {
40 | if(ModuleSave == null || tank_manager != null)
41 | return 0;
42 | var volumes = ConfigNodeObject.FromConfig(ModuleSave);
43 | return volumes.AddMass();
44 | }
45 |
46 | protected override float ResourcesCost(bool maxAmount = true)
47 | {
48 | if(ModuleSave == null || tank_manager != null)
49 | return 0;
50 | var volumes = ConfigNodeObject.FromConfig(ModuleSave);
51 | return volumes.ResourceCost(maxAmount);
52 | }
53 |
54 | protected override float ResourcesMass(bool maxAmount = true)
55 | {
56 | if(ModuleSave == null || tank_manager != null)
57 | return 0;
58 | var volumes = ConfigNodeObject.FromConfig(ModuleSave);
59 | return volumes.ResourceMass(maxAmount);
60 | }
61 |
62 | private void init_tank_manager()
63 | {
64 | if(tank_manager != null)
65 | return;
66 | tank_manager = new SwitchableTankManager(this);
67 | if(ModuleSave == null)
68 | {
69 | this.Log("ModuleSave is null. THIS SHOULD NEVER HAPPEN!");
70 | return;
71 | }
72 | ModuleSave.SetValue("Volume", Volume);
73 | tank_manager.Load(ModuleSave);
74 | var used_volume = tank_manager.TanksVolume;
75 | if(used_volume > Volume)
76 | {
77 | this.Log(
78 | "WARNING: Volume limit is less than the total volume " + "of preconfigured tanks: {} - {} = {}",
79 | Volume,
80 | used_volume,
81 | Volume - used_volume);
82 | Volume = used_volume;
83 | }
84 | tank_manager.Volume = Volume;
85 | }
86 |
87 | protected override void init_from_part()
88 | {
89 | if(ModuleSave == null)
90 | ModuleSave = new ConfigNode("MODULE");
91 | var volume = VolumeConfiguration.FromResources(part.Resources);
92 | if(volume == null)
93 | {
94 | Utils.Message("TankManager module is added to a part with unknown resource!\n"
95 | + "This is an error in MM patch.\n"
96 | + "TankManager module is disabled.");
97 | this.EnableModule(false);
98 | part.Modules.Remove(this);
99 | return;
100 | }
101 | volume.name = ModuleSave.GetValue("name");
102 | ModuleSave.RemoveValue("Volume");
103 | ModuleSave.RemoveNodes(TankVolume.NODE_NAME);
104 | volume.Save(ModuleSave);
105 | Volume = volume.Volume;
106 | DoCostPatch = false;
107 | DoMassPatch = true;
108 | // this.Log("ModuleSave was initialized from part in flight: {}", ModuleSave);//debug
109 | }
110 |
111 | public override void OnLoad(ConfigNode node)
112 | {
113 | base.OnLoad(node);
114 | ModuleSave = node;
115 | //FIXME: does not work, because MM does not add this value
116 | //if its an existing part and CC was just added by MM patch
117 | ModuleSaveFromPrefab |= node.GetValue("MM_REINITIALIZE") != null;
118 | }
119 |
120 | public override void OnSave(ConfigNode node)
121 | {
122 | base.OnSave(node);
123 | if(tank_manager != null)
124 | tank_manager.Save(node);
125 | else
126 | ModuleSave.CopyTo(node);
127 | }
128 |
129 | public override void OnStart(StartState state)
130 | {
131 | base.OnStart(state);
132 | init_tank_manager();
133 | #if DEBUG
134 | tank_manager.EnablePartControls = false;
135 | #else
136 | tank_manager.EnablePartControls = !HighLogic.LoadedSceneIsEditor && tank_manager.TanksCount < 2;
137 | #endif
138 | var editTankEvent = Events[nameof(EditTanks)];
139 | Utils.EnableEvent(editTankEvent, !tank_manager.EnablePartControls);
140 | if(HighLogic.LoadedSceneIsFlight)
141 | editTankEvent.guiName = "Manage Tanks";
142 | }
143 |
144 | private void OnDestroy()
145 | {
146 | tank_manager?.UI?.Close();
147 | }
148 |
149 | public void Rescale(float relative_scale, bool update_amounts = false)
150 | {
151 | Volume *= relative_scale;
152 | if(tank_manager == null)
153 | return;
154 | // temporarily set tank manager volume to max.float
155 | // to be able to rescale all tanks without clamping
156 | tank_manager.Volume = float.MaxValue;
157 | tank_manager.RescaleTanks(relative_scale, update_amounts);
158 | // then check if the resulting tanks volume exceeds the rescaled total volume
159 | // and increase the later if needed
160 | if(tank_manager.TanksVolume > Volume)
161 | Volume = tank_manager.TanksVolume;
162 | // finally, update tank manager volume
163 | tank_manager.Volume = Volume;
164 | }
165 |
166 | //interface for ProceduralParts
167 | [UsedImplicitly]
168 | [KSPEvent(guiActive = false, active = true)]
169 | private void OnPartVolumeChanged(BaseEventDetails data)
170 | {
171 | var volName = data.Get("volName");
172 | var newTotalVolume = (float)data.Get("newTotalVolume");
173 | if(volName == "Tankage" && !newTotalVolume.Equals(Volume))
174 | Rescale(newTotalVolume / Volume, HighLogic.LoadedSceneIsEditor);
175 | }
176 |
177 | //interface for TweakScale
178 | [UsedImplicitly]
179 | [KSPEvent(guiActive = false, active = true)]
180 | private void OnPartScaleChanged(BaseEventDetails data)
181 | {
182 | var scale = data.Get("factorRelative");
183 | if(!scale.Equals(1))
184 | Rescale(scale * scale * scale, HighLogic.LoadedSceneIsEditor);
185 | }
186 |
187 | //workaround for ConfigNode non-serialization
188 | public override void OnBeforeSerialize()
189 | {
190 | if(tank_manager != null)
191 | {
192 | ModuleSave = new ConfigNode();
193 | Save(ModuleSave);
194 | }
195 | base.OnBeforeSerialize();
196 | }
197 |
198 | #region ITankManagerCapabilities
199 | public bool AddRemoveEnabled => HighLogic.LoadedSceneIsEditor;
200 | public bool ConfirmRemove => !HighLogic.LoadedSceneIsEditor;
201 | public bool TypeChangeEnabled => HighLogic.LoadedSceneIsEditor;
202 | public bool VolumeChangeEnabled => HighLogic.LoadedSceneIsEditor;
203 | public bool FillEnabled => HighLogic.LoadedSceneIsEditor;
204 | public bool EmptyEnabled => HighLogic.LoadedSceneIsEditor;
205 | #endregion
206 |
207 | #region GUI
208 | [KSPEvent(guiActive = true, guiActiveEditor = true, guiName = "Edit Tanks", active = true)]
209 | public void EditTanks() => tank_manager?.UI.Toggle(this);
210 |
211 | private void LateUpdate()
212 | {
213 | tank_manager?.UI.OnLateUpdate();
214 | }
215 | #endregion
216 | }
217 |
218 | public class TankManagerUpdater : ModuleUpdater
219 | {
220 | protected override void on_rescale(ModulePair mp, Scale scale)
221 | {
222 | if(!scale.relative.volume.Equals(1))
223 | mp.module.Rescale(scale.relative.volume, true);
224 | }
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/ConfigurableContainers.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {BD074812-7105-46D7-A252-53C20DAB698B}
7 | Library
8 | AT_Utils
9 | ConfigurableContainers
10 | v4.8
11 |
12 |
13 |
14 | true
15 | full
16 | false
17 | ..\GameData\000_AT_Utils\Plugins
18 | DEBUG;ENABLE_PROFILER;NIGHTBUILD
19 | prompt
20 | 4
21 | false
22 |
23 |
24 | full
25 | true
26 | ..\GameData\000_AT_Utils\Plugins
27 | prompt
28 | 4
29 | false
30 |
31 |
32 | true
33 | ..\GameData\000_AT_Utils\Plugins
34 | 4
35 | NIGHTBUILD
36 |
37 |
38 |
39 | ..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\System.dll
40 | False
41 |
42 |
43 | ..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\Assembly-CSharp.dll
44 | False
45 |
46 |
47 | ..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\System.Core.dll
48 | False
49 |
50 |
51 | ..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\UnityEngine.dll
52 | False
53 |
54 |
55 | ..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\KSPAssets.dll
56 | False
57 |
58 |
59 | ..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\Mono.Cecil.dll
60 | False
61 |
62 |
63 | ..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\System.Xml.dll
64 | False
65 |
66 |
67 | ..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\UnityEngine.CoreModule.dll
68 | False
69 |
70 |
71 | ..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\UnityEngine.IMGUIModule.dll
72 | False
73 |
74 |
75 | ..\..\KSP-test\KSP_test_1.12.3\KSP_Data\Managed\UnityEngine.UI.dll
76 | False
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | {19ABDD5C-1F12-4D67-B72E-E36071ABFF2C}
97 | AnisotropicPartResizer
98 | False
99 |
100 |
101 | {64CC36A2-0610-4F74-9F31-3D4E22866B7E}
102 | AT_Utils
103 | False
104 |
105 |
106 | {0b711e55-8312-144f-53ad-eda5a8cee04a}
107 | AT_Utils.UI
108 | False
109 |
110 |
111 | {3e7aa3ab-1064-4a2e-9d8f-0e20b83a2249}
112 | CC.UI
113 | True
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/ModRocketSys_Patch.cfg:
--------------------------------------------------------------------------------
1 | //Configurable Containers patch for ModRocketSys
2 |
3 | //Rocket Fuel Tanks
4 | //Automatically generated using PyKSPutils library
5 | @PART[NBwhiteJumbo]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[ModRocketSys]
6 | {
7 | !RESOURCE[LiquidFuel]
8 | {
9 |
10 | }
11 | !RESOURCE[Oxidizer]
12 | {
13 |
14 | }
15 | MODULE
16 | {
17 | name = ModuleTankManager
18 | Volume = 39.506173 //2880.0 units of LF: conversion rate is 0.013717 m3/u
19 | DoCostPatch = True
20 | DoMassPatch = True
21 | TANK
22 | {
23 | name = LFO
24 | Volume = 100.0
25 | }
26 | }
27 | }
28 |
29 | @PART[NBradialMiniTank]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[ModRocketSys]
30 | {
31 | !RESOURCE[LiquidFuel]
32 | {
33 |
34 | }
35 | !RESOURCE[Oxidizer]
36 | {
37 |
38 | }
39 | MODULE
40 | {
41 | name = ModuleTankManager
42 | Volume = 0.987654 //72.0 units of LF: conversion rate is 0.013717 m3/u
43 | DoCostPatch = True
44 | DoMassPatch = True
45 | TANK
46 | {
47 | name = LFO
48 | Volume = 100.0
49 | }
50 | }
51 | }
52 |
53 | @PART[NB0mtank1]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[ModRocketSys]
54 | {
55 | !RESOURCE[LiquidFuel]
56 | {
57 |
58 | }
59 | !RESOURCE[Oxidizer]
60 | {
61 |
62 | }
63 | MODULE
64 | {
65 | name = ModuleTankManager
66 | Volume = 0.308642 //22.5 units of LF: conversion rate is 0.013717 m3/u
67 | DoCostPatch = True
68 | DoMassPatch = True
69 | TANK
70 | {
71 | name = LFO
72 | Volume = 100.0
73 | }
74 | }
75 | }
76 |
77 | @PART[NBjumboThreeQ]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[ModRocketSys]
78 | {
79 | !RESOURCE[LiquidFuel]
80 | {
81 |
82 | }
83 | !RESOURCE[Oxidizer]
84 | {
85 |
86 | }
87 | MODULE
88 | {
89 | name = ModuleTankManager
90 | Volume = 29.62963 //2160.0 units of LF: conversion rate is 0.013717 m3/u
91 | DoCostPatch = True
92 | DoMassPatch = True
93 | TANK
94 | {
95 | name = LFO
96 | Volume = 100.0
97 | }
98 | }
99 | }
100 |
101 | @PART[NBhalfJumbo]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[ModRocketSys]
102 | {
103 | !RESOURCE[LiquidFuel]
104 | {
105 |
106 | }
107 | !RESOURCE[Oxidizer]
108 | {
109 |
110 | }
111 | MODULE
112 | {
113 | name = ModuleTankManager
114 | Volume = 19.753086 //1440.0 units of LF: conversion rate is 0.013717 m3/u
115 | DoCostPatch = True
116 | DoMassPatch = True
117 | TANK
118 | {
119 | name = LFO
120 | Volume = 100.0
121 | }
122 | }
123 | }
124 |
125 | @PART[NBminiOrange]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[ModRocketSys]
126 | {
127 | !RESOURCE[LiquidFuel]
128 | {
129 |
130 | }
131 | !RESOURCE[Oxidizer]
132 | {
133 |
134 | }
135 | MODULE
136 | {
137 | name = ModuleTankManager
138 | Volume = 9.876543 //720.0 units of LF: conversion rate is 0.013717 m3/u
139 | DoCostPatch = True
140 | DoMassPatch = True
141 | TANK
142 | {
143 | name = LFO
144 | Volume = 100.0
145 | }
146 | }
147 | }
148 |
149 | @PART[NBconeTank3m]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[ModRocketSys]
150 | {
151 | !RESOURCE[LiquidFuel]
152 | {
153 |
154 | }
155 | !RESOURCE[Oxidizer]
156 | {
157 |
158 | }
159 | MODULE
160 | {
161 | name = ModuleTankManager
162 | Volume = 29.62963 //2160.0 units of LF: conversion rate is 0.013717 m3/u
163 | DoCostPatch = True
164 | DoMassPatch = True
165 | TANK
166 | {
167 | name = LFO
168 | Volume = 100.0
169 | }
170 | }
171 | }
172 |
173 | @PART[NBconeTank2m]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[ModRocketSys]
174 | {
175 | !RESOURCE[LiquidFuel]
176 | {
177 |
178 | }
179 | !RESOURCE[Oxidizer]
180 | {
181 |
182 | }
183 | MODULE
184 | {
185 | name = ModuleTankManager
186 | Volume = 3.703704 //270.0 units of LF: conversion rate is 0.013717 m3/u
187 | DoCostPatch = True
188 | DoMassPatch = True
189 | TANK
190 | {
191 | name = LFO
192 | Volume = 100.0
193 | }
194 | }
195 | }
196 | //LiquidFuel Tanks
197 | //Automatically generated using PyKSPutils library
198 | @PART[NB0mtankJet1]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[ModRocketSys]
199 | {
200 | !RESOURCE[LiquidFuel]
201 | {
202 |
203 | }
204 | MODULE
205 | {
206 | name = ModuleTankManager
207 | Volume = 0.308642 //50.0 units of LiquidFuel: conversion rate is 0.006173 m3/u
208 | DoCostPatch = True
209 | DoMassPatch = True
210 | TANK
211 | {
212 | TankType = LiquidChemicals
213 | CurrentResource = LiquidFuel
214 | InitialAmount = 1.0
215 | Volume = 100.0
216 | }
217 | }
218 | }
219 |
220 | @PART[NB0mtankJet2]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[ModRocketSys]
221 | {
222 | !RESOURCE[LiquidFuel]
223 | {
224 |
225 | }
226 | MODULE
227 | {
228 | name = ModuleTankManager
229 | Volume = 0.617284 //100.0 units of LiquidFuel: conversion rate is 0.006173 m3/u
230 | DoCostPatch = True
231 | DoMassPatch = True
232 | TANK
233 | {
234 | TankType = LiquidChemicals
235 | CurrentResource = LiquidFuel
236 | InitialAmount = 1.0
237 | Volume = 100.0
238 | }
239 | }
240 | }
241 | //MonoPropellant Tanks
242 | //Automatically generated using PyKSPutils library
243 | @PART[NBmonoprop3m]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[ModRocketSys]
244 | {
245 | !RESOURCE[MonoPropellant]
246 | {
247 |
248 | }
249 | MODULE
250 | {
251 | name = ModuleTankManager
252 | Volume = 4.565217 //1680.0 units of MonoPropellant: conversion rate is 0.002717 m3/u
253 | DoCostPatch = True
254 | DoMassPatch = True
255 | TANK
256 | {
257 | TankType = LiquidChemicals
258 | CurrentResource = MonoPropellant
259 | InitialAmount = 1.0
260 | Volume = 100.0
261 | }
262 | }
263 | }
264 |
265 | @PART[NBinterstageDecoupler3m]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[ModRocketSys]
266 | {
267 | !RESOURCE[MonoPropellant]
268 | {
269 |
270 | }
271 | MODULE
272 | {
273 | name = ModuleTankManager
274 | Volume = 0.543478 //200.0 units of MonoPropellant: conversion rate is 0.002717 m3/u
275 | DoCostPatch = True
276 | DoMassPatch = True
277 | TANK
278 | {
279 | TankType = LiquidChemicals
280 | CurrentResource = MonoPropellant
281 | InitialAmount = 1.0
282 | Volume = 100.0
283 | }
284 | }
285 | }
286 | //XenonGas Tanks
287 | //Automatically generated using PyKSPutils library
288 | @PART[NBxenonSphere1m]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[ModRocketSys]
289 | {
290 | !RESOURCE[XenonGas]
291 | {
292 |
293 | }
294 | MODULE
295 | {
296 | name = ModuleSwitchableTank
297 | Volume = 1.124606 //12500.0 units of XenonGas: conversion rate is 0.000090 m3/u
298 | InitialAmount = 1.0
299 | DoCostPatch = True
300 | DoMassPatch = True
301 | ChooseTankType = False
302 | TankType = Gases
303 | CurrentResource = XenonGas
304 | }
305 | }
306 |
307 | @PART[NBxenonSphere]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[ModRocketSys]
308 | {
309 | !RESOURCE[XenonGas]
310 | {
311 |
312 | }
313 | MODULE
314 | {
315 | name = ModuleSwitchableTank
316 | Volume = 0.125956 //1400.0 units of XenonGas: conversion rate is 0.000090 m3/u
317 | InitialAmount = 1.0
318 | DoCostPatch = True
319 | DoMassPatch = True
320 | ChooseTankType = False
321 | TankType = Gases
322 | CurrentResource = XenonGas
323 | }
324 | }
325 | //:mode=c#:
326 |
--------------------------------------------------------------------------------
/VolumeConfiguration.cs:
--------------------------------------------------------------------------------
1 | // VolumeConfiguration.cs
2 | //
3 | // Author:
4 | // Allis Tauri
5 | //
6 | // Copyright (c) 2016 Allis Tauri
7 |
8 | using System.Collections.Generic;
9 | using System.Linq;
10 |
11 | namespace AT_Utils
12 | {
13 | public class BaseVolume : ConfigNodeObject
14 | {
15 | public new const string NODE_NAME = "VOLUME";
16 | [Persistent] public float Volume = 1;
17 |
18 | public virtual string Info(float volume_conversion = 1)
19 | {
20 | return $"{Utils.formatVolume(Volume * volume_conversion)}";
21 | }
22 |
23 | public virtual float AddMass(float volume_conversion = 1)
24 | {
25 | return 0f;
26 | }
27 |
28 | public virtual float Cost(float volume_conversion = 1)
29 | {
30 | return 0f;
31 | }
32 |
33 | public virtual float ResourceCost(bool maxAmount = true, float volume_conversion = 1)
34 | {
35 | return 0f;
36 | }
37 |
38 | public virtual float ResourceMass(bool maxAmount = true, float volume_conversion = 1)
39 | {
40 | return 0f;
41 | }
42 |
43 | public virtual float ResourceAmount(bool maxAmount = true, float volume_conversion = 1)
44 | {
45 | return 0f;
46 | }
47 |
48 | public virtual bool ContainsType(string tank_type)
49 | {
50 | return false;
51 | }
52 | }
53 |
54 |
55 | public class TankVolume : BaseVolume
56 | {
57 | public new const string NODE_NAME = "TANK";
58 | [Persistent] public string CurrentResource;
59 | [Persistent] public float InitialAmount;
60 |
61 | [Persistent] public string TankType;
62 |
63 | public SwitchableTankType Type => SwitchableTankType.GetTankType(TankType);
64 |
65 | public override float AddMass(float volume_conversion = 1)
66 | {
67 | var t = Type;
68 | return t?.AddMass(Volume * volume_conversion) ?? 0;
69 | }
70 |
71 | public override float Cost(float volume_conversion = 1)
72 | {
73 | var t = Type;
74 | return t?.Cost(Volume * volume_conversion) ?? 0;
75 | }
76 |
77 | public override float ResourceCost(bool maxAmount = true, float volume_conversion = 1)
78 | {
79 | try
80 | {
81 | var t = Type;
82 | var res = t.Resources[CurrentResource];
83 | var cost = res.def.unitCost * res.UnitsPerLiter * t.UsefulVolume(Volume) * volume_conversion * 1000;
84 | return maxAmount ? cost : cost * InitialAmount;
85 | }
86 | catch
87 | {
88 | return 0;
89 | }
90 | }
91 |
92 | public override float ResourceMass(bool maxAmount = true, float volume_conversion = 1)
93 | {
94 | try
95 | {
96 | var t = Type;
97 | var res = t.Resources[CurrentResource];
98 | var mass = res.def.density * res.UnitsPerLiter * t.UsefulVolume(Volume) * volume_conversion * 1000;
99 | return maxAmount ? mass : mass * InitialAmount;
100 | }
101 | catch
102 | {
103 | return 0;
104 | }
105 | }
106 |
107 | public override float ResourceAmount(bool maxAmount = true, float volume_conversion = 1)
108 | {
109 | try
110 | {
111 | var t = Type;
112 | var res = t.Resources[CurrentResource];
113 | var amount = res.UnitsPerLiter * t.UsefulVolume(Volume) * volume_conversion * 1000;
114 | return maxAmount ? amount : amount * InitialAmount;
115 | }
116 | catch
117 | {
118 | return 0;
119 | }
120 | }
121 |
122 | public override string Info(float volume_conversion = 1)
123 | {
124 | var haveResource = !string.IsNullOrEmpty(CurrentResource);
125 | var info = StringBuilderCache.Acquire();
126 | info.Append($"- {TankType}");
127 | if(haveResource)
128 | info.Append($"\n {CurrentResource}");
129 | info.Append($"\n {Utils.formatVolume(Volume * volume_conversion)}");
130 | if(haveResource)
131 | {
132 | info.Append($"\n {Utils.formatBigValue(ResourceAmount(true, volume_conversion), "u")}");
133 | info.Append($"\n {Utils.formatBigValue(ResourceMass(true, volume_conversion), "t")}");
134 | }
135 | info.Append($"\n {Cost(volume_conversion):F1}");
136 | if(InitialAmount > 0)
137 | info.Append($"+{ResourceCost(false, volume_conversion):F1}");
138 | info.Append(" Cr");
139 | return info.ToStringAndRelease().Trim();
140 | }
141 |
142 | public override bool ContainsType(string tank_type)
143 | {
144 | return TankType == tank_type;
145 | }
146 |
147 | public static TankVolume FromResource(PartResource res)
148 | {
149 | var tank = new TankVolume();
150 | var tank_type = SwitchableTankType.FindTankType(res.resourceName);
151 | if(tank_type == null)
152 | return null;
153 | tank.TankType = tank_type.name;
154 | tank.CurrentResource = res.resourceName;
155 | tank.Volume = (float)(res.maxAmount
156 | / tank_type.Resources[res.resourceName].UnitsPerLiter
157 | / 1000
158 | / tank_type.UsefulVolumeRatio);
159 | tank.InitialAmount = (float)(res.amount / res.maxAmount);
160 | return tank;
161 | }
162 | }
163 |
164 |
165 | public class VolumeConfiguration : BaseVolume
166 | {
167 | public new const string NODE_NAME = "TANKCONF";
168 |
169 | ///
170 | /// The name of a configuration.
171 | ///
172 | [Persistent]
173 | public string name = "";
174 |
175 | public readonly List Volumes = new List();
176 | public float TotalVolume { get { return Volumes.Aggregate(0f, (v, t) => v + t.Volume); } }
177 | public bool Valid => Volumes.Count > 0 && TotalVolume > 0;
178 |
179 | public override void Load(ConfigNode node)
180 | {
181 | Volumes.Clear();
182 | base.Load(node);
183 | var volumes = node.GetNodes();
184 | for(var i = 0; i < volumes.Length; i++)
185 | {
186 | var v = volumes[i];
187 | switch(v.name)
188 | {
189 | case TankVolume.NODE_NAME:
190 | {
191 | var preset = VolumeConfigsLibrary.GetConfig(v.GetValue("name"));
192 | if(preset != null)
193 | {
194 | if(!float.TryParse(v.GetValue("Volume"), out var volume))
195 | volume = 100f;
196 | var cfg = preset.Clone();
197 | cfg.Volume = volume;
198 | Volumes.Add(cfg);
199 | }
200 | else
201 | {
202 | Volumes.Add(FromConfig(v));
203 | }
204 | break;
205 | }
206 | case NODE_NAME:
207 | Volumes.Add(FromConfig(v));
208 | break;
209 | }
210 | }
211 | }
212 |
213 | public override void Save(ConfigNode node)
214 | {
215 | base.Save(node);
216 | Volumes.ForEach(t => t.SaveInto(node));
217 | }
218 |
219 | public override string Info(float volume_conversion = 1)
220 | {
221 | if(!Valid)
222 | return $"{name}: configuration invalid";
223 | var info = StringBuilderCache.Acquire();
224 | volume_conversion = Volume * volume_conversion / TotalVolume;
225 | Volumes.ForEach(v =>
226 | {
227 | info.AppendLine(v.Info(volume_conversion));
228 | info.AppendLine();
229 | });
230 | return info.ToStringAndRelease().Trim();
231 | }
232 |
233 | public override float AddMass(float volume_conversion = 1)
234 | {
235 | volume_conversion = Volume * volume_conversion / TotalVolume;
236 | return Volumes.Aggregate(0f, (s, v) => s + v.AddMass(volume_conversion));
237 | }
238 |
239 | public override float Cost(float volume_conversion = 1)
240 | {
241 | volume_conversion = Volume * volume_conversion / TotalVolume;
242 | return Volumes.Aggregate(0f, (s, v) => s + v.Cost(volume_conversion));
243 | }
244 |
245 | public override float ResourceCost(bool maxAmount = true, float volume_conversion = 1)
246 | {
247 | volume_conversion = Volume * volume_conversion / TotalVolume;
248 | return Volumes.Aggregate(0f, (s, v) => s + v.ResourceCost(maxAmount, volume_conversion));
249 | }
250 |
251 | public override float ResourceMass(bool maxAmount = true, float volume_conversion = 1)
252 | {
253 | volume_conversion = Volume * volume_conversion / TotalVolume;
254 | return Volumes.Aggregate(0f, (s, v) => s + v.ResourceMass(maxAmount, volume_conversion));
255 | }
256 |
257 | public override bool ContainsType(string tank_type)
258 | {
259 | return Volumes.Any(v => v.ContainsType(tank_type));
260 | }
261 |
262 | public bool ContainsTypes(IEnumerable tank_types)
263 | {
264 | return tank_types.Any(ContainsType);
265 | }
266 |
267 | public static VolumeConfiguration FromResources(IEnumerable resources)
268 | {
269 | var volume = new VolumeConfiguration();
270 | foreach(var res in resources)
271 | {
272 | var tank = TankVolume.FromResource(res);
273 | if(tank == null)
274 | return null;
275 | volume.Volumes.Add(tank);
276 | }
277 | volume.Volume = volume.TotalVolume;
278 | return volume;
279 | }
280 | }
281 | }
282 |
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/MakingHistory_Patch.cfg:
--------------------------------------------------------------------------------
1 | //Configurable Containers patch for SquadExpansion/MakingHistory/Parts
2 |
3 | //Rocket Fuel Tanks
4 | //Automatically generated using PyKSPutils library
5 | @PART[Size1p5_Size0_Adapter_01]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
6 | {
7 | !RESOURCE[LiquidFuel]
8 | {
9 |
10 | }
11 | !RESOURCE[Oxidizer]
12 | {
13 |
14 | }
15 | MODULE
16 | {
17 | name = ModuleTankManager
18 | Volume = 0.987654 //72.0 units of LF: conversion rate is 0.013717 m3/u
19 | DoCostPatch = True
20 | DoMassPatch = True
21 | TANK
22 | {
23 | name = LFO
24 | Volume = 100.0
25 | }
26 | }
27 | }
28 |
29 | @PART[Size1p5_Size1_Adapter_02]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
30 | {
31 | !RESOURCE[LiquidFuel]
32 | {
33 |
34 | }
35 | !RESOURCE[Oxidizer]
36 | {
37 |
38 | }
39 | MODULE
40 | {
41 | name = ModuleTankManager
42 | Volume = 0.987654 //72.0 units of LF: conversion rate is 0.013717 m3/u
43 | DoCostPatch = True
44 | DoMassPatch = True
45 | TANK
46 | {
47 | name = LFO
48 | Volume = 100.0
49 | }
50 | }
51 | }
52 |
53 | @PART[Size4_Tank_03]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
54 | {
55 | !RESOURCE[LiquidFuel]
56 | {
57 |
58 | }
59 | !RESOURCE[Oxidizer]
60 | {
61 |
62 | }
63 | MODULE
64 | {
65 | name = ModuleTankManager
66 | Volume = 158.024691 //11520.0 units of LF: conversion rate is 0.013717 m3/u
67 | DoCostPatch = True
68 | DoMassPatch = True
69 | TANK
70 | {
71 | name = LFO
72 | Volume = 100.0
73 | }
74 | }
75 | }
76 |
77 | @PART[Size4_Tank_01]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
78 | {
79 | !RESOURCE[LiquidFuel]
80 | {
81 |
82 | }
83 | !RESOURCE[Oxidizer]
84 | {
85 |
86 | }
87 | MODULE
88 | {
89 | name = ModuleTankManager
90 | Volume = 39.506173 //2880.0 units of LF: conversion rate is 0.013717 m3/u
91 | DoCostPatch = True
92 | DoMassPatch = True
93 | TANK
94 | {
95 | name = LFO
96 | Volume = 100.0
97 | }
98 | }
99 | }
100 |
101 | @PART[Size1p5_Tank_02]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
102 | {
103 | !RESOURCE[LiquidFuel]
104 | {
105 |
106 | }
107 | !RESOURCE[Oxidizer]
108 | {
109 |
110 | }
111 | MODULE
112 | {
113 | name = ModuleTankManager
114 | Volume = 2.716049 //198.0 units of LF: conversion rate is 0.013717 m3/u
115 | DoCostPatch = True
116 | DoMassPatch = True
117 | TANK
118 | {
119 | name = LFO
120 | Volume = 100.0
121 | }
122 | }
123 | }
124 |
125 | @PART[Size4_Tank_02]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
126 | {
127 | !RESOURCE[LiquidFuel]
128 | {
129 |
130 | }
131 | !RESOURCE[Oxidizer]
132 | {
133 |
134 | }
135 | MODULE
136 | {
137 | name = ModuleTankManager
138 | Volume = 79.012346 //5760.0 units of LF: conversion rate is 0.013717 m3/u
139 | DoCostPatch = True
140 | DoMassPatch = True
141 | TANK
142 | {
143 | name = LFO
144 | Volume = 100.0
145 | }
146 | }
147 | }
148 |
149 | @PART[Size1p5_Tank_03]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
150 | {
151 | !RESOURCE[LiquidFuel]
152 | {
153 |
154 | }
155 | !RESOURCE[Oxidizer]
156 | {
157 |
158 | }
159 | MODULE
160 | {
161 | name = ModuleTankManager
162 | Volume = 5.555556 //405.0 units of LF: conversion rate is 0.013717 m3/u
163 | DoCostPatch = True
164 | DoMassPatch = True
165 | TANK
166 | {
167 | name = LFO
168 | Volume = 100.0
169 | }
170 | }
171 | }
172 |
173 | @PART[Size3_Size4_Adapter_01]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
174 | {
175 | !RESOURCE[LiquidFuel]
176 | {
177 |
178 | }
179 | !RESOURCE[Oxidizer]
180 | {
181 |
182 | }
183 | MODULE
184 | {
185 | name = ModuleTankManager
186 | Volume = 39.506173 //2880.0 units of LF: conversion rate is 0.013717 m3/u
187 | DoCostPatch = True
188 | DoMassPatch = True
189 | TANK
190 | {
191 | name = LFO
192 | Volume = 100.0
193 | }
194 | }
195 | }
196 |
197 | @PART[Size1p5_Size1_Adapter_01]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
198 | {
199 | !RESOURCE[LiquidFuel]
200 | {
201 |
202 | }
203 | !RESOURCE[Oxidizer]
204 | {
205 |
206 | }
207 | MODULE
208 | {
209 | name = ModuleTankManager
210 | Volume = 3.703704 //270.0 units of LF: conversion rate is 0.013717 m3/u
211 | DoCostPatch = True
212 | DoMassPatch = True
213 | TANK
214 | {
215 | name = LFO
216 | Volume = 100.0
217 | }
218 | }
219 | }
220 |
221 | @PART[Size4_EngineAdapter_01]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
222 | {
223 | !RESOURCE[LiquidFuel]
224 | {
225 |
226 | }
227 | !RESOURCE[Oxidizer]
228 | {
229 |
230 | }
231 | MODULE
232 | {
233 | name = ModuleTankManager
234 | Volume = 55.555556 //4050.0 units of LF: conversion rate is 0.013717 m3/u
235 | DoCostPatch = True
236 | DoMassPatch = True
237 | TANK
238 | {
239 | name = LFO
240 | Volume = 100.0
241 | }
242 | }
243 | }
244 |
245 | @PART[Size1p5_Size2_Adapter_01]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
246 | {
247 | !RESOURCE[LiquidFuel]
248 | {
249 |
250 | }
251 | !RESOURCE[Oxidizer]
252 | {
253 |
254 | }
255 | MODULE
256 | {
257 | name = ModuleTankManager
258 | Volume = 7.407407 //540.0 units of LF: conversion rate is 0.013717 m3/u
259 | DoCostPatch = True
260 | DoMassPatch = True
261 | TANK
262 | {
263 | name = LFO
264 | Volume = 100.0
265 | }
266 | }
267 | }
268 |
269 | @PART[Size1p5_Tank_04]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
270 | {
271 | !RESOURCE[LiquidFuel]
272 | {
273 |
274 | }
275 | !RESOURCE[Oxidizer]
276 | {
277 |
278 | }
279 | MODULE
280 | {
281 | name = ModuleTankManager
282 | Volume = 11.111111 //810.0 units of LF: conversion rate is 0.013717 m3/u
283 | DoCostPatch = True
284 | DoMassPatch = True
285 | TANK
286 | {
287 | name = LFO
288 | Volume = 100.0
289 | }
290 | }
291 | }
292 |
293 | @PART[Size4_Tank_04]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
294 | {
295 | !RESOURCE[LiquidFuel]
296 | {
297 |
298 | }
299 | !RESOURCE[Oxidizer]
300 | {
301 |
302 | }
303 | MODULE
304 | {
305 | name = ModuleTankManager
306 | Volume = 316.049383 //23040.0 units of LF: conversion rate is 0.013717 m3/u
307 | DoCostPatch = True
308 | DoMassPatch = True
309 | TANK
310 | {
311 | name = LFO
312 | Volume = 100.0
313 | }
314 | }
315 | }
316 |
317 | @PART[Size1p5_Tank_01]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
318 | {
319 | !RESOURCE[LiquidFuel]
320 | {
321 |
322 | }
323 | !RESOURCE[Oxidizer]
324 | {
325 |
326 | }
327 | MODULE
328 | {
329 | name = ModuleTankManager
330 | Volume = 1.358025 //99.0 units of LF: conversion rate is 0.013717 m3/u
331 | DoCostPatch = True
332 | DoMassPatch = True
333 | TANK
334 | {
335 | name = LFO
336 | Volume = 100.0
337 | }
338 | }
339 | }
340 | //MonoPropellant Tanks
341 | //Automatically generated using PyKSPutils library
342 | @PART[Size1p5_Monoprop]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
343 | {
344 | !RESOURCE[MonoPropellant]
345 | {
346 |
347 | }
348 | MODULE
349 | {
350 | name = ModuleTankManager
351 | Volume = 1.086957 //400.0 units of MonoPropellant: conversion rate is 0.002717 m3/u
352 | DoCostPatch = True
353 | DoMassPatch = True
354 | TANK
355 | {
356 | TankType = LiquidChemicals
357 | CurrentResource = MonoPropellant
358 | InitialAmount = 1.0
359 | Volume = 100.0
360 | }
361 | }
362 | }
363 |
364 | @PART[monopropMiniSphere]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]
365 | {
366 | !RESOURCE[MonoPropellant]
367 | {
368 |
369 | }
370 | MODULE
371 | {
372 | name = ModuleTankManager
373 | Volume = 0.02038 //7.5 units of MonoPropellant: conversion rate is 0.002717 m3/u
374 | DoCostPatch = True
375 | DoMassPatch = True
376 | TANK
377 | {
378 | TankType = LiquidChemicals
379 | CurrentResource = MonoPropellant
380 | InitialAmount = 1.0
381 | Volume = 100.0
382 | }
383 | }
384 | }
385 | //:mode=c#:
386 |
--------------------------------------------------------------------------------
/SwitchableTankType.cs:
--------------------------------------------------------------------------------
1 | // SwitchableTankType.cs
2 | //
3 | // Author:
4 | // Allis Tauri
5 | //
6 | // Copyright (c) 2016 Allis Tauri
7 |
8 | using System.Collections.Generic;
9 | using System.Linq;
10 |
11 | namespace AT_Utils
12 | {
13 | ///
14 | /// Type of a switchable tank.
15 | /// Defines resources that a tank of this type can hold,
16 | /// how much units of each resource a liter of volume contains,
17 | /// and portion of part's volume that can be used by the tank.
18 | ///
19 | public class SwitchableTankType : ConfigNodeObject
20 | {
21 | public new const string NODE_NAME = "TANKTYPE";
22 |
23 | ///
24 | /// The additional mass of a tank of this type per volume.
25 | ///
26 | [Persistent]
27 | public float AddMassPerVolume = 0f;
28 |
29 | ///
30 | /// If the resources in this tank should boiloff with time.
31 | ///
32 | [Persistent]
33 | public bool Boiloff;
34 |
35 | ///
36 | /// If the resources in this tank should be actively cooled until below the boiloff temperature.
37 | ///
38 | [Persistent]
39 | public bool Cooling;
40 |
41 | private string info;
42 |
43 | ///
44 | /// The name of the tank type.
45 | /// It is possible to edit these nodes with MM using NODE[name] syntax.
46 | ///
47 | [Persistent]
48 | public string name;
49 |
50 | ///
51 | /// The string list of resources a tank of this type can hold. Format:
52 | /// ResourceName1 units_per_liter; ResourceName2 units_per_liter2; ...
53 | ///
54 | [Persistent]
55 | public string PossibleResources;
56 |
57 | ///
58 | /// The cost of a tank of this type per tank surface.
59 | ///
60 | [Persistent]
61 | public float TankCostPerSurface = 1f;
62 |
63 | ///
64 | /// The cost of a tank of this type per tank volume.
65 | ///
66 | [Persistent]
67 | public float TankCostPerVolume = 0f;
68 |
69 | ///
70 | /// The portion of a part's volume the tank can use.
71 | ///
72 | [Persistent]
73 | public float UsefulVolumeRatio = 1f;
74 |
75 | public SortedList Resources { get; private set; }
76 | public bool Valid => Resources != null && Resources.Count > 0;
77 | public IList ResourceNames => Resources.Keys;
78 | public TankResource DefaultResource => Resources.Values[0];
79 |
80 | public TankResource this[string resourceName]
81 | {
82 | get
83 | {
84 | try
85 | {
86 | return Resources[resourceName];
87 | }
88 | catch
89 | {
90 | return null;
91 | }
92 | }
93 | }
94 |
95 | public string Info
96 | {
97 | get
98 | {
99 | if(!Valid)
100 | return "";
101 | if(info != null)
102 | return info;
103 | var _info = StringBuilderCache.Acquire();
104 | _info.AppendLine("Tank can hold:");
105 | foreach(var r in ResourceNames)
106 | _info.AppendLine(
107 | $"- {Resources[r].Name}: {Utils.formatUnits(Resources[r].UnitsPerLiter)}/L");
108 | var useful_volume = UsefulVolume(100);
109 | if(useful_volume < 100)
110 | _info.AppendLine($"Only {useful_volume:F0}% of the volume is used for resources.");
111 | if(Boiloff || Cooling)
112 | _info.AppendLine("Tank is thermally insulated.\nEquipped with boil-off valve.");
113 | if(Cooling)
114 | _info.AppendLine("Equipped with Active Cooling System.");
115 | info = _info.ToStringAndRelease().Trim();
116 | return info;
117 | }
118 | }
119 |
120 | public float Cost(float volume)
121 | {
122 | return volume * TankCostPerVolume + Utils.CubeSurface(volume) * TankCostPerSurface;
123 | }
124 |
125 | public float AddMass(float volume)
126 | {
127 | return volume * AddMassPerVolume;
128 | }
129 |
130 | public float GetEffectiveVolumeRatio()
131 | {
132 | var useful_volume = UsefulVolumeRatio;
133 | if(Boiloff || Cooling)
134 | useful_volume -= CryogenicsParams.Instance.InsulationVolumeFraction;
135 | return useful_volume < 0 ? 0 : useful_volume;
136 | }
137 |
138 | public float UsefulVolume(float volume) => volume * GetEffectiveVolumeRatio();
139 |
140 | public override void Load(ConfigNode node)
141 | {
142 | base.Load(node);
143 | Resources = TankResource.ParseResourcesToSortedList(PossibleResources);
144 | }
145 |
146 | #region Tank Type Library
147 | ///
148 | /// The library of preconfigured tank types.
149 | ///
150 | public static SortedList TankTypes
151 | {
152 | get
153 | {
154 | if(_tank_types != null)
155 | return _tank_types;
156 | var nodes = GameDatabase.Instance.GetConfigNodes(NODE_NAME);
157 | _tank_types = new SortedList();
158 | for(int i = 0, nodesLength = nodes.Length; i < nodesLength; i++)
159 | {
160 | var n = nodes[i];
161 | #if DEBUG
162 | Utils.Log("\n{}", n.ToString());
163 | #endif
164 | var tank_type = FromConfig(n);
165 | if(!tank_type.Valid)
166 | {
167 | var msg =
168 | $"[ConfigurableContainers] '{tank_type.name}' tank type has no resources. Skipping.";
169 | Utils.Message(6, msg);
170 | Utils.Warning(msg);
171 | continue;
172 | }
173 | try
174 | {
175 | _tank_types.Add(tank_type.name, tank_type);
176 | }
177 | catch
178 | {
179 | Utils.Error(
180 | $"SwitchableTankType: ignoring duplicate configuration of {tank_type.name} tank type. Use ModuleManager to change the existing one.");
181 | }
182 | }
183 | return _tank_types;
184 | }
185 | }
186 |
187 | private static SortedList _tank_types;
188 |
189 | ///
190 | /// Sorted list of tank type names.
191 | ///
192 | public static List TankTypeNames(string[] include = null, string[] exclude = null)
193 | {
194 | IEnumerable names;
195 | if(include != null && include.Length > 0)
196 | names = TankTypes.Keys.Where(n => include.IndexOf(n) >= 0);
197 | else if(exclude != null && exclude.Length > 0)
198 | names = TankTypes.Keys.Where(n => exclude.IndexOf(n) < 0);
199 | else
200 | names = TankTypes.Keys;
201 | return names.ToList();
202 | }
203 |
204 | ///
205 | /// Determines if the library contains the specified tank type.
206 | ///
207 | /// Tank type name.
208 | public static bool HaveTankType(string tank_type)
209 | {
210 | return TankTypes.ContainsKey(tank_type);
211 | }
212 |
213 | ///
214 | /// Returns the TankType from the library, if it exists; null otherwise.
215 | ///
216 | /// Tank type name.
217 | public static SwitchableTankType GetTankType(string tank_type)
218 | {
219 | return TankTypes.TryGetValue(tank_type, out var t) ? t : null;
220 | }
221 |
222 | ///
223 | /// Finds the first tank type containing the specified resource.
224 | ///
225 | /// The tank type.
226 | /// Resource name.
227 | public static SwitchableTankType FindTankType(string resource_name)
228 | {
229 | foreach(var t in TankTypes)
230 | if(t.Value.Resources.ContainsKey(resource_name))
231 | return t.Value;
232 | return null;
233 | }
234 |
235 | ///
236 | /// Returns TankType.Info for a type, if it exists; string.Empty otherwise.
237 | ///
238 | /// Tank type name.
239 | public static string GetTankTypeInfo(string tank_type)
240 | {
241 | return TankTypes.TryGetValue(tank_type, out var t) ? t.Info : string.Empty;
242 | }
243 |
244 | ///
245 | /// Returns info string describing available tank types
246 | ///
247 | public static string TypesInfo(string[] include = null, string[] exclude = null)
248 | {
249 | var info = StringBuilderCache.Acquire();
250 | info.AppendLine("Supported Tank Types:");
251 | TankTypeNames(include, exclude).ForEach(t => info.AppendLine($"- {t}"));
252 | return info.ToStringAndRelease().Trim();
253 | }
254 | #endregion
255 | }
256 |
257 |
258 | ///
259 | /// A Part Resource Definition complemented with Units Per Liter ratio.
260 | ///
261 | public class TankResource : ResourceWrapper
262 | {
263 | public float UnitsPerLiter { get; private set; }
264 | public float UnitsPerVolume { get; private set; }
265 |
266 | public PartResourceDefinition def => PartResourceLibrary.Instance.GetDefinition(Name);
267 |
268 | public override void LoadDefinition(string resource_definition)
269 | {
270 | var upl = load_definition(resource_definition);
271 | if(!Valid)
272 | return;
273 | UnitsPerLiter = upl;
274 | UnitsPerVolume = upl * 1000;
275 | }
276 | }
277 | }
278 |
--------------------------------------------------------------------------------
/CC.UI/TankControlsUI.cs:
--------------------------------------------------------------------------------
1 | using AT_Utils.UI;
2 | using UnityEngine.Events;
3 | using UnityEngine.UI;
4 |
5 | namespace CC.UI
6 | {
7 | public class TankControlsUI : TankManagerUIPart
8 | {
9 | public Button
10 | deleteButton,
11 | fullTankButton,
12 | emptyTankButton,
13 | editVolumeButton,
14 | editMaxAmountButton,
15 | editMaxMassButton;
16 |
17 | public Text
18 | resourceVolume,
19 | resourceMaxAmount,
20 | resourceAmount,
21 | resourceMaxMass,
22 | resourceMass,
23 | tankFullness;
24 |
25 | public Dropdown
26 | tankTypeDropdown,
27 | resourceDropdown;
28 |
29 | public TooltipTrigger
30 | tankTypeTooltip;
31 |
32 | public Colorizer
33 | resourceAmountColorizer;
34 |
35 | public PanelledUI
36 | volumeDisplay;
37 |
38 | public FloatController
39 | volumeEditor;
40 |
41 | private ITankInfo tank;
42 |
43 | private void updateResourcesDropdown() =>
44 | resourceDropdown.options = UI_Utils.namesToOptions(tank.SupportedResources);
45 |
46 | private void updateTankTypeDropdownTooltip(string tankType) =>
47 | tankTypeTooltip.SetText(tank.Manager.GetTypeInfo(tankType));
48 |
49 | public void SetTank(ITankInfo newTank)
50 | {
51 | if(newTank == tank)
52 | return;
53 | tank = newTank;
54 | if(tank == null)
55 | return;
56 | tankTypeDropdown.SetOptionsSafe(UI_Utils.namesToOptions(tank.SupportedTypes));
57 | updateTankTypeDropdownTooltip(tank.SupportedTypes[tankTypeDropdown.value]);
58 | updateResourcesDropdown();
59 | UpdateDisplay();
60 | }
61 |
62 | public void UpdateDisplay()
63 | {
64 | tankTypeDropdown.SetInteractable(tank.Manager.Capabilities.TypeChangeEnabled);
65 | editVolumeButton.SetInteractable(tank.Manager.Capabilities.VolumeChangeEnabled);
66 | editMaxAmountButton.SetInteractable(editVolumeButton.interactable);
67 | editMaxMassButton.SetInteractable(editVolumeButton.interactable);
68 | deleteButton.gameObject.SetActive(tank.Manager.Capabilities.AddRemoveEnabled);
69 | resourceVolume.text = FormatUtils.formatVolume(tank.Volume);
70 | if(tank.Valid)
71 | {
72 | editMaxAmountButton.gameObject.SetActive(true);
73 | tankFullness.gameObject.SetActive(true);
74 | fullTankButton.gameObject.SetActive(tank.Manager.Capabilities.FillEnabled);
75 | emptyTankButton.gameObject.SetActive(tank.Manager.Capabilities.EmptyEnabled);
76 | resourceMaxAmount.text = FormatUtils.formatBigValue((float)tank.MaxAmount, "u");
77 | resourceAmount.text = FormatUtils.formatBigValue((float)tank.Amount, "u");
78 | tankFullness.text = (tank.Amount / tank.MaxAmount).ToString("P1");
79 | resourceAmountColorizer.SetColor(Colors.Selected1);
80 | if(tank.ResourceDensity > 0)
81 | {
82 | editMaxMassButton.gameObject.SetActive(true);
83 | resourceMass.gameObject.SetActive(true);
84 | resourceMaxMass.text = FormatUtils.formatMass((float)(tank.MaxAmount * tank.ResourceDensity));
85 | resourceMass.text = FormatUtils.formatMass((float)(tank.Amount * tank.ResourceDensity));
86 | }
87 | else
88 | {
89 | editMaxMassButton.gameObject.SetActive(false);
90 | resourceMass.gameObject.SetActive(false);
91 | }
92 | }
93 | else
94 | {
95 | editMaxAmountButton.gameObject.SetActive(false);
96 | editMaxMassButton.gameObject.SetActive(false);
97 | resourceMass.gameObject.SetActive(false);
98 | tankFullness.gameObject.SetActive(false);
99 | fullTankButton.gameObject.SetActive(false);
100 | emptyTankButton.gameObject.SetActive(false);
101 | resourceAmount.text = "TANK CONFIGURATION IS INVALID";
102 | resourceAmountColorizer.SetColor(Colors.Danger);
103 | }
104 | var resourcesDropdownUpdated = false;
105 | if(!string.IsNullOrEmpty(tank.TankType)
106 | && (tankTypeDropdown.value >= tank.SupportedTypes.Count
107 | || tank.TankType != tank.SupportedTypes[tankTypeDropdown.value]))
108 | {
109 | tankTypeDropdown.SetValueWithoutNotify(tank.SupportedTypes.IndexOf(tank.TankType));
110 | updateTankTypeDropdownTooltip(tank.TankType);
111 | updateResourcesDropdown();
112 | resourcesDropdownUpdated = true;
113 | }
114 | // ReSharper disable once InvertIf
115 | if(!string.IsNullOrEmpty(tank.CurrentResource)
116 | && (resourceDropdown.value >= tank.SupportedResources.Count
117 | || tank.CurrentResource != tank.SupportedResources[resourceDropdown.value]))
118 | {
119 | if(!resourcesDropdownUpdated)
120 | updateResourcesDropdown();
121 | resourceDropdown.SetValueWithoutNotify(tank.SupportedResources.IndexOf(tank.CurrentResource));
122 | }
123 | }
124 |
125 | private void Awake()
126 | {
127 | volumeDisplay.SetActive(true);
128 | volumeEditor.SetActive(false);
129 | editVolumeButton.onClick.AddListener(showVolumeEditor);
130 | editMaxAmountButton.onClick.AddListener(showMaxAmountEditor);
131 | editMaxMassButton.onClick.AddListener(showMaxMassEditor);
132 | tankTypeDropdown.onValueChanged.AddListener(changeTankType);
133 | resourceDropdown.onValueChanged.AddListener(changeResource);
134 | fullTankButton.onClick.AddListener(fillTank);
135 | emptyTankButton.onClick.AddListener(emptyTank);
136 | deleteButton.onClick.AddListener(onDelete);
137 | }
138 |
139 | private void OnDestroy()
140 | {
141 | editVolumeButton.onClick.RemoveAllListeners();
142 | editMaxAmountButton.onClick.RemoveAllListeners();
143 | editMaxMassButton.onClick.RemoveAllListeners();
144 | tankTypeDropdown.onValueChanged.RemoveAllListeners();
145 | resourceDropdown.onValueChanged.RemoveAllListeners();
146 | fullTankButton.onClick.RemoveAllListeners();
147 | emptyTankButton.onClick.RemoveAllListeners();
148 | deleteButton.onClick.RemoveAllListeners();
149 | }
150 |
151 | private void onDelete()
152 | {
153 | if(tank.Manager.Capabilities.ConfirmRemove)
154 | DialogFactory
155 | .Danger($"Are you sure you want to {Colors.Danger.Tag("delete")} this tank?",
156 | deleteSelf);
157 | else
158 | deleteSelf();
159 | }
160 |
161 | private void deleteSelf()
162 | {
163 | if(!tank.Manager.RemoveTank(tank))
164 | return;
165 | if(managerUI != null)
166 | managerUI.UpdateDisplay();
167 | else
168 | Destroy(gameObject);
169 | }
170 |
171 | private void hideEditor()
172 | {
173 | volumeEditor.onDoneEditing.RemoveAllListeners();
174 | volumeEditor.SetActive(false);
175 | volumeDisplay.SetActive(true);
176 | }
177 |
178 | private void showEditor(string units, float value, float max, UnityAction onDone)
179 | {
180 | volumeEditor.suffix.text = units;
181 | volumeEditor.Max = max;
182 | volumeEditor.SetStep(volumeEditor.Max / 10);
183 | volumeEditor.SetValueWithoutNotify(value);
184 | volumeEditor.onDoneEditing.AddListener(onDone);
185 | volumeDisplay.SetActive(false);
186 | volumeEditor.SetActive(true);
187 | }
188 |
189 | private void showVolumeEditor()
190 | {
191 | if(tank == null)
192 | return;
193 | showEditor(
194 | "m3",
195 | tank.Volume,
196 | tank.Volume + tank.Manager.AvailableVolume,
197 | changeTankVolume
198 | );
199 | }
200 |
201 | private void changeTankVolume(float newVolume)
202 | {
203 | if(tank == null)
204 | return;
205 | tank.SetVolume(newVolume, true);
206 | hideEditor();
207 | UpdateDisplay();
208 | }
209 |
210 | private void showMaxAmountEditor()
211 | {
212 | if(tank == null)
213 | return;
214 | showEditor(
215 | "u",
216 | (float)tank.MaxAmount,
217 | tank.ResourceAmountInVolume(tank.Volume + tank.Manager.AvailableVolume),
218 | changeTankMaxAmount
219 | );
220 | }
221 |
222 | private void changeTankMaxAmount(float newMaxAmount)
223 | {
224 | if(tank == null)
225 | return;
226 | changeTankVolume(tank.VolumeForResourceAmount(newMaxAmount));
227 | }
228 |
229 | private void showMaxMassEditor()
230 | {
231 | if(tank == null)
232 | return;
233 | showEditor(
234 | "t",
235 | (float)(tank.MaxAmount * tank.ResourceDensity),
236 | tank.ResourceAmountInVolume(tank.Volume + tank.Manager.AvailableVolume) * tank.ResourceDensity,
237 | changeTankMaxMass
238 | );
239 | }
240 |
241 | private void changeTankMaxMass(float newMaxMass)
242 | {
243 | if(tank == null)
244 | return;
245 | changeTankMaxAmount(newMaxMass / tank.ResourceDensity);
246 | }
247 |
248 | private void fillTank()
249 | {
250 | if(tank == null)
251 | return;
252 | tank.SetAmount((float)tank.MaxAmount);
253 | UpdateDisplay();
254 | }
255 |
256 | private void emptyTank()
257 | {
258 | if(tank == null)
259 | return;
260 | tank.SetAmount(0);
261 | UpdateDisplay();
262 | }
263 |
264 | private void changeTankType(int index)
265 | {
266 | if(tank == null)
267 | return;
268 | var tankType = tank.SupportedTypes[index];
269 | tank.ChangeTankType(tankType);
270 | updateTankTypeDropdownTooltip(tankType);
271 | updateResourcesDropdown();
272 | UpdateDisplay();
273 | }
274 |
275 | private void changeResource(int index)
276 | {
277 | if(tank == null)
278 | return;
279 | tank.ChangeResource(tank.SupportedResources[index]);
280 | UpdateDisplay();
281 | }
282 | }
283 | }
284 |
--------------------------------------------------------------------------------
/GameData/ConfigurableContainers/Parts/NearFuturePropulsion_Patch.cfg:
--------------------------------------------------------------------------------
1 | //Configurable Containers patch for NearFuturePropulsion
2 |
3 | //XenonGas Tanks
4 | //Automatically generated using PyKSPutils library
5 | @PART[xenon-125-1]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
6 | {
7 | !RESOURCE[XenonGas]
8 | {
9 |
10 | }
11 | MODULE
12 | {
13 | name = ModuleSwitchableTank
14 | Volume = 2.159244 //24000.0 units of XenonGas: conversion rate is 0.000090 m3/u
15 | InitialAmount = 1.0
16 | DoCostPatch = True
17 | DoMassPatch = True
18 | ChooseTankType = False
19 | TankType = Gases
20 | CurrentResource = XenonGas
21 | }
22 | }
23 |
24 | @PART[xenon-125-3]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
25 | {
26 | !RESOURCE[XenonGas]
27 | {
28 |
29 | }
30 | MODULE
31 | {
32 | name = ModuleSwitchableTank
33 | Volume = 0.539811 //6000.0 units of XenonGas: conversion rate is 0.000090 m3/u
34 | InitialAmount = 1.0
35 | DoCostPatch = True
36 | DoMassPatch = True
37 | ChooseTankType = False
38 | TankType = Gases
39 | CurrentResource = XenonGas
40 | }
41 | }
42 |
43 | @PART[xenon-125-2]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
44 | {
45 | !RESOURCE[XenonGas]
46 | {
47 |
48 | }
49 | MODULE
50 | {
51 | name = ModuleSwitchableTank
52 | Volume = 1.079622 //12000.0 units of XenonGas: conversion rate is 0.000090 m3/u
53 | InitialAmount = 1.0
54 | DoCostPatch = True
55 | DoMassPatch = True
56 | ChooseTankType = False
57 | TankType = Gases
58 | CurrentResource = XenonGas
59 | }
60 | }
61 |
62 | @PART[xenon-25-1]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
63 | {
64 | !RESOURCE[XenonGas]
65 | {
66 |
67 | }
68 | MODULE
69 | {
70 | name = ModuleSwitchableTank
71 | Volume = 17.273954 //192000.0 units of XenonGas: conversion rate is 0.000090 m3/u
72 | InitialAmount = 1.0
73 | DoCostPatch = True
74 | DoMassPatch = True
75 | ChooseTankType = False
76 | TankType = Gases
77 | CurrentResource = XenonGas
78 | }
79 | }
80 |
81 | @PART[xenon-25-2]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
82 | {
83 | !RESOURCE[XenonGas]
84 | {
85 |
86 | }
87 | MODULE
88 | {
89 | name = ModuleSwitchableTank
90 | Volume = 8.636977 //96000.0 units of XenonGas: conversion rate is 0.000090 m3/u
91 | InitialAmount = 1.0
92 | DoCostPatch = True
93 | DoMassPatch = True
94 | ChooseTankType = False
95 | TankType = Gases
96 | CurrentResource = XenonGas
97 | }
98 | }
99 |
100 | @PART[xenon-25-3]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
101 | {
102 | !RESOURCE[XenonGas]
103 | {
104 |
105 | }
106 | MODULE
107 | {
108 | name = ModuleSwitchableTank
109 | Volume = 4.318489 //48000.0 units of XenonGas: conversion rate is 0.000090 m3/u
110 | InitialAmount = 1.0
111 | DoCostPatch = True
112 | DoMassPatch = True
113 | ChooseTankType = False
114 | TankType = Gases
115 | CurrentResource = XenonGas
116 | }
117 | }
118 |
119 | @PART[xenon-radial-125-1]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
120 | {
121 | !RESOURCE[XenonGas]
122 | {
123 |
124 | }
125 | MODULE
126 | {
127 | name = ModuleSwitchableTank
128 | Volume = 0.674764 //7500.0 units of XenonGas: conversion rate is 0.000090 m3/u
129 | InitialAmount = 1.0
130 | DoCostPatch = True
131 | DoMassPatch = True
132 | ChooseTankType = False
133 | TankType = Gases
134 | CurrentResource = XenonGas
135 | }
136 | }
137 | //ArgonGas Tanks
138 | //Automatically generated using PyKSPutils library
139 | @PART[argon-0625-3]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
140 | {
141 | !RESOURCE[ArgonGas]
142 | {
143 |
144 | }
145 | MODULE
146 | {
147 | name = ModuleSwitchableTank
148 | Volume = 0.1407 //28000.0 units of ArgonGas: conversion rate is 0.000005 m3/u
149 | InitialAmount = 1.0
150 | DoCostPatch = True
151 | DoMassPatch = True
152 | ChooseTankType = False
153 | TankType = Gases
154 | CurrentResource = ArgonGas
155 | }
156 | }
157 |
158 | @PART[argon-0625-2]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
159 | {
160 | !RESOURCE[ArgonGas]
161 | {
162 |
163 | }
164 | MODULE
165 | {
166 | name = ModuleSwitchableTank
167 | Volume = 0.2814 //56000.0 units of ArgonGas: conversion rate is 0.000005 m3/u
168 | InitialAmount = 1.0
169 | DoCostPatch = True
170 | DoMassPatch = True
171 | ChooseTankType = False
172 | TankType = Gases
173 | CurrentResource = ArgonGas
174 | }
175 | }
176 |
177 | @PART[argon-0625-1]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
178 | {
179 | !RESOURCE[ArgonGas]
180 | {
181 |
182 | }
183 | MODULE
184 | {
185 | name = ModuleSwitchableTank
186 | Volume = 0.5628 //112000.0 units of ArgonGas: conversion rate is 0.000005 m3/u
187 | InitialAmount = 1.0
188 | DoCostPatch = True
189 | DoMassPatch = True
190 | ChooseTankType = False
191 | TankType = Gases
192 | CurrentResource = ArgonGas
193 | }
194 | }
195 |
196 | @PART[argon-25-2]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
197 | {
198 | !RESOURCE[ArgonGas]
199 | {
200 |
201 | }
202 | MODULE
203 | {
204 | name = ModuleSwitchableTank
205 | Volume = 25.728 //5120000.0 units of ArgonGas: conversion rate is 0.000005 m3/u
206 | InitialAmount = 1.0
207 | DoCostPatch = True
208 | DoMassPatch = True
209 | ChooseTankType = False
210 | TankType = Gases
211 | CurrentResource = ArgonGas
212 | }
213 | }
214 |
215 | @PART[argon-25-3]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
216 | {
217 | !RESOURCE[ArgonGas]
218 | {
219 |
220 | }
221 | MODULE
222 | {
223 | name = ModuleSwitchableTank
224 | Volume = 12.864 //2560000.0 units of ArgonGas: conversion rate is 0.000005 m3/u
225 | InitialAmount = 1.0
226 | DoCostPatch = True
227 | DoMassPatch = True
228 | ChooseTankType = False
229 | TankType = Gases
230 | CurrentResource = ArgonGas
231 | }
232 | }
233 |
234 | @PART[argon-25-1]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
235 | {
236 | !RESOURCE[ArgonGas]
237 | {
238 |
239 | }
240 | MODULE
241 | {
242 | name = ModuleSwitchableTank
243 | Volume = 51.456 //10240000.0 units of ArgonGas: conversion rate is 0.000005 m3/u
244 | InitialAmount = 1.0
245 | DoCostPatch = True
246 | DoMassPatch = True
247 | ChooseTankType = False
248 | TankType = Gases
249 | CurrentResource = ArgonGas
250 | }
251 | }
252 |
253 | @PART[argon-125-2]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
254 | {
255 | !RESOURCE[ArgonGas]
256 | {
257 |
258 | }
259 | MODULE
260 | {
261 | name = ModuleSwitchableTank
262 | Volume = 3.216 //640000.0 units of ArgonGas: conversion rate is 0.000005 m3/u
263 | InitialAmount = 1.0
264 | DoCostPatch = True
265 | DoMassPatch = True
266 | ChooseTankType = False
267 | TankType = Gases
268 | CurrentResource = ArgonGas
269 | }
270 | }
271 |
272 | @PART[argon-125-1]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
273 | {
274 | !RESOURCE[ArgonGas]
275 | {
276 |
277 | }
278 | MODULE
279 | {
280 | name = ModuleSwitchableTank
281 | Volume = 6.432 //1280000.0 units of ArgonGas: conversion rate is 0.000005 m3/u
282 | InitialAmount = 1.0
283 | DoCostPatch = True
284 | DoMassPatch = True
285 | ChooseTankType = False
286 | TankType = Gases
287 | CurrentResource = ArgonGas
288 | }
289 | }
290 |
291 | @PART[argon-125-3]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
292 | {
293 | !RESOURCE[ArgonGas]
294 | {
295 |
296 | }
297 | MODULE
298 | {
299 | name = ModuleSwitchableTank
300 | Volume = 1.608 //320000.0 units of ArgonGas: conversion rate is 0.000005 m3/u
301 | InitialAmount = 1.0
302 | DoCostPatch = True
303 | DoMassPatch = True
304 | ChooseTankType = False
305 | TankType = Gases
306 | CurrentResource = ArgonGas
307 | }
308 | }
309 |
310 | @PART[argon-radial-125-1]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
311 | {
312 | !RESOURCE[ArgonGas]
313 | {
314 |
315 | }
316 | MODULE
317 | {
318 | name = ModuleSwitchableTank
319 | Volume = 0.3216 //64000.0 units of ArgonGas: conversion rate is 0.000005 m3/u
320 | InitialAmount = 1.0
321 | DoCostPatch = True
322 | DoMassPatch = True
323 | ChooseTankType = False
324 | TankType = Gases
325 | CurrentResource = ArgonGas
326 | }
327 | }
328 |
329 | @PART[argon-radial-0625-1]:HAS[!MODULE[InterstellarFuelSwitch],!MODULE[FSfuelSwitch],!MODULE[ModuleB9PartSwitch]:HAS[@SUBTYPE:HAS[#tankType]]]:NEEDS[!modularFuelTanks&!RealFuels]:AFTER[NearFuturePropulsion]
330 | {
331 | !RESOURCE[ArgonGas]
332 | {
333 |
334 | }
335 | MODULE
336 | {
337 | name = ModuleSwitchableTank
338 | Volume = 0.07236 //14400.0 units of ArgonGas: conversion rate is 0.000005 m3/u
339 | InitialAmount = 1.0
340 | DoCostPatch = True
341 | DoMassPatch = True
342 | ChooseTankType = False
343 | TankType = Gases
344 | CurrentResource = ArgonGas
345 | }
346 | }
347 | //:mode=c#:
348 |
--------------------------------------------------------------------------------