コード例 #1
0
        public void GameSceneEvent(GameScenes scene)
        {
            KCT_GUI.HideAll();

            if (scene == GameScenes.MAINMENU)
            {
                KCTGameStates.Reset();
                KCTGameStates.IsFirstStart = false;
                InputLockManager.RemoveControlLock("KCTLaunchLock");
                KCTGameStates.ActiveKSCName = Utilities._defaultKscId;
                KCTGameStates.ActiveKSC     = new KSCItem(Utilities._defaultKscId);
                KCTGameStates.KSCs          = new List <KSCItem>()
                {
                    KCTGameStates.ActiveKSC
                };
                KCTGameStates.LastKnownTechCount = 0;

                if (PresetManager.Instance != null)
                {
                    PresetManager.Instance.ClearPresets();
                    PresetManager.Instance = null;
                }

                return;
            }

            KCTGameStates.MiscellaneousTempUpgrades = 0;

            if (PresetManager.PresetLoaded() && !PresetManager.Instance.ActivePreset.GeneralSettings.Enabled)
            {
                return;
            }
            var validScenes = new List <GameScenes> {
                GameScenes.SPACECENTER, GameScenes.TRACKSTATION, GameScenes.EDITOR
            };

            if (validScenes.Contains(scene))
            {
                TechDisableEventFinal();
            }

            if (HighLogic.LoadedScene == scene && scene == GameScenes.EDITOR)    //Fix for null reference when using new or load buttons in editor
            {
                GamePersistence.SaveGame("persistent", HighLogic.SaveFolder, SaveMode.OVERWRITE);
            }

            if (HighLogic.LoadedSceneIsEditor)
            {
                EditorLogic.fetch.Unlock("KCTEditorMouseLock");
            }

            if (scene == GameScenes.EDITOR && !HighLogic.LoadedSceneIsEditor)
            {
                KCT_GUI.FirstOnGUIUpdate = true;
            }
        }
コード例 #2
0
ファイル: GUI_Editor.cs プロジェクト: Wallum/LRTR
        private static void RenderEditMode()
        {
            BuildListVessel ship = KCTGameStates.EditedVessel;

            if (_finishedShipBP < 0 && ship.IsFinished)
            {
                // If ship is finished, then both build and integration times can be refreshed with newly calculated values
                _finishedShipBP        = Utilities.GetBuildTime(ship.ExtractedPartNodes);
                ship.BuildPoints       = _finishedShipBP;
                ship.IntegrationPoints = MathParser.ParseIntegrationTimeFormula(ship);
            }

            Utilities.GetShipEditProgress(ship, out double newProgressBP, out double originalCompletionPercent, out double newCompletionPercent);
            GUILayout.Label($"Original: {Math.Max(0, Math.Round(100 * originalCompletionPercent, 2))}%");
            GUILayout.Label($"Edited: {Math.Round(100 * newCompletionPercent, 2)}%");

            BuildListVessel.ListType type = EditorLogic.fetch.launchSiteName == "LaunchPad" ? BuildListVessel.ListType.VAB : BuildListVessel.ListType.SPH;
            GUILayout.BeginHorizontal();
            GUILayout.Label("Build Time at ");
            if (BuildRateForDisplay == null)
            {
                BuildRateForDisplay = Utilities.GetBuildRate(0, type, null).ToString();
            }
            BuildRateForDisplay = GUILayout.TextField(BuildRateForDisplay, GUILayout.Width(75));
            GUILayout.Label(" BP/s:");
            List <double> rates = new List <double>();

            if (ship.Type == BuildListVessel.ListType.VAB)
            {
                rates = Utilities.GetVABBuildRates(null);
            }
            else
            {
                rates = Utilities.GetSPHBuildRates(null);
            }
            if (double.TryParse(BuildRateForDisplay, out double bR))
            {
                if (GUILayout.Button(new GUIContent("*", "Switch build line that is used for build time calculations"), GUILayout.ExpandWidth(false)))
                {
                    _rateIndexHolder = (_rateIndexHolder + 1) % rates.Count;
                    bR = rates[_rateIndexHolder];
                    BuildRateForDisplay = bR.ToString();
                }
                GUILayout.EndHorizontal();
                GUILayout.Label(MagiCore.Utilities.GetFormattedTime(Math.Abs(KCTGameStates.EditorBuildTime + KCTGameStates.EditorIntegrationTime - newProgressBP) / bR));
            }
            else
            {
                GUILayout.EndHorizontal();
                GUILayout.Label("Invalid Build Rate");
            }

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("Save Edits"))
            {
                _finishedShipBP = -1;
                Utilities.SaveShipEdits(ship);
            }
            if (GUILayout.Button("Cancel Edits"))
            {
                KCTDebug.Log("Edits cancelled.");
                _finishedShipBP = -1;
                ScrapYardWrapper.ProcessVessel(KCTGameStates.EditedVessel.ExtractedPartNodes);
                KCTGameStates.ClearVesselEditMode();

                HighLogic.LoadScene(GameScenes.SPACECENTER);
            }
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("Simulate"))
            {
                _finishedShipBP = -1;
                _simulationConfigPosition.height = 1;
                EditorLogic.fetch.Lock(true, true, true, "KCTGUILock");
                GUIStates.ShowSimConfig = true;

                double effCost = Utilities.GetEffectiveCost(EditorLogic.fetch.ship.Parts);
                double bp      = Utilities.GetBuildTime(effCost);
                KCTGameStates.LaunchedVessel = new BuildListVessel(EditorLogic.fetch.ship, EditorLogic.fetch.launchSiteName, effCost, bp, EditorLogic.FlagURL);
            }
            GUILayout.EndHorizontal();

            if (KCTGameStates.LaunchedVessel != null && !KCTGameStates.LaunchedVessel.AreTanksFull() &&
                GUILayout.Button("Fill Tanks"))
            {
                foreach (Part p in EditorLogic.fetch.ship.parts)
                {
                    //fill as part prefab would be filled?
                    if (Utilities.PartIsProcedural(p))
                    {
                        foreach (PartResource rsc in p.Resources)
                        {
                            if (GuiDataAndWhitelistItemsDatabase.ValidFuelRes.Contains(rsc.resourceName) && rsc.flowState)
                            {
                                rsc.amount = rsc.maxAmount;
                            }
                        }
                    }
                    else
                    {
                        foreach (PartResource rsc in p.Resources)
                        {
                            if (GuiDataAndWhitelistItemsDatabase.ValidFuelRes.Contains(rsc.resourceName) && rsc.flowState)
                            {
                                PartResource templateRsc = p.partInfo.partPrefab.Resources.FirstOrDefault(r => r.resourceName == rsc.resourceName);
                                if (templateRsc != null)
                                {
                                    rsc.amount = templateRsc.amount;
                                }
                            }
                        }
                    }
                }
            }

            RenderMergeSection(ship);
        }
コード例 #3
0
        public void Start()
        {
            KCTDebug.Log("Start called");
            if (Utilities.CurrentGameIsMission())
            {
                return;
            }

            // Subscribe to events from KSP and other mods
            if (!KCTEvents.Instance.SubscribedToEvents)
            {
                KCTEvents.Instance.SubscribeToEvents();
            }

            if (KCTGameStates.IsFirstStart)
            {
                PresetManager.Instance.SaveActiveToSaveData();
            }

            // Ghetto event queue
            if (HighLogic.LoadedScene == GameScenes.EDITOR)
            {
                InvokeRepeating("EditorRecalculation", 1, 1);

                KCT_GUI.BuildRateForDisplay = null;
                if (!KCT_GUI.IsPrimarilyDisabled)
                {
                    Utilities.RecalculateEditorBuildTime(EditorLogic.fetch.ship);
                }
            }

            if (KCT_GUI.IsPrimarilyDisabled &&
                InputLockManager.GetControlLock("KCTLaunchLock") == ControlTypes.EDITOR_LAUNCH)
            {
                InputLockManager.RemoveControlLock("KCTLaunchLock");
            }

            KACWrapper.InitKACWrapper();

            if (!PresetManager.Instance.ActivePreset.GeneralSettings.Enabled)
            {
                if (InputLockManager.GetControlLock("KCTKSCLock") == ControlTypes.KSC_FACILITIES)
                {
                    InputLockManager.RemoveControlLock("KCTKSCLock");
                }
                return;
            }

            //Begin primary mod functions

            KCTGameStates.UT = Utilities.GetUT();

            KCT_GUI.GuiDataSaver.Load();
            KCT_GUI.GUIStates.HideAllNonMainWindows();

            if (!HighLogic.LoadedSceneIsFlight)
            {
                bool b = KCTGameStates.SimulationParams.BuildSimulatedVessel;
                KCTGameStates.SimulationParams.Reset();
                if (b && KCTGameStates.LaunchedVessel != null)
                {
                    Utilities.AddVesselToBuildList(KCTGameStates.LaunchedVessel);
                }
            }

            switch (HighLogic.LoadedScene)
            {
            case GameScenes.EDITOR:
                KCT_GUI.HideAll();
                if (!KCT_GUI.IsPrimarilyDisabled)
                {
                    KCT_GUI.GUIStates.ShowEditorGUI = KCTGameStates.ShowWindows[1];
                    if (KCTGameStates.EditorShipEditingMode)
                    {
                        KCT_GUI.EnsureEditModeIsVisible();
                    }
                    else if (KCT_GUI.GUIStates.ShowEditorGUI)
                    {
                        KCT_GUI.ToggleVisibility(true);
                    }
                    else
                    {
                        KCT_GUI.ToggleVisibility(false);
                    }
                }
                break;

            case GameScenes.SPACECENTER:
                bool shouldStart = KCT_GUI.GUIStates.ShowFirstRun;
                KCT_GUI.HideAll();
                KCTGameStates.ClearVesselEditMode();
                if (!shouldStart)
                {
                    KCT_GUI.GUIStates.ShowBuildList = KCTGameStates.ShowWindows[0];
                    if (KCT_GUI.GUIStates.ShowBuildList)
                    {
                        KCT_GUI.ToggleVisibility(true);
                    }
                    else
                    {
                        KCT_GUI.ToggleVisibility(false);
                    }
                }
                KCT_GUI.GUIStates.ShowFirstRun = shouldStart;
                break;

            case GameScenes.TRACKSTATION:
                KCTGameStates.ClearVesselEditMode();
                break;

            case GameScenes.FLIGHT:
                if (!KCTGameStates.IsSimulatedFlight &&
                    FlightGlobals.ActiveVessel.situation == Vessel.Situations.PRELAUNCH &&
                    FlightGlobals.ActiveVessel.GetCrewCount() == 0 && KCTGameStates.LaunchedCrew.Count > 0)
                {
                    KerbalRoster roster = HighLogic.CurrentGame.CrewRoster;

                    for (int i = 0; i < FlightGlobals.ActiveVessel.parts.Count; i++)
                    {
                        Part p = FlightGlobals.ActiveVessel.parts[i];
                        KCTDebug.Log("Part being tested: " + p.partInfo.title);
                        {
                            CrewedPart cp = KCTGameStates.LaunchedCrew.Find(part => part.PartID == p.craftID);
                            if (cp == null)
                            {
                                continue;
                            }
                            List <ProtoCrewMember> crewList = cp.CrewList;
                            KCTDebug.Log("cP.crewList.Count: " + cp.CrewList.Count);
                            foreach (ProtoCrewMember crewMember in crewList)
                            {
                                if (crewMember != null)
                                {
                                    ProtoCrewMember finalCrewMember = crewMember;
                                    if (crewMember.type == ProtoCrewMember.KerbalType.Crew)
                                    {
                                        finalCrewMember = roster.Crew.FirstOrDefault(c => c.name == crewMember.name);
                                    }
                                    else if (crewMember.type == ProtoCrewMember.KerbalType.Tourist)
                                    {
                                        finalCrewMember = roster.Tourist.FirstOrDefault(c => c.name == crewMember.name);
                                    }
                                    if (finalCrewMember == null)
                                    {
                                        KCTDebug.LogError($"Error when assigning {crewMember.name} to {p.partInfo.name}. Cannot find Kerbal in list.");
                                        continue;
                                    }
                                    try
                                    {
                                        KCTDebug.Log($"Assigning {finalCrewMember.name } to {p.partInfo.name}");
                                        if (p.AddCrewmember(finalCrewMember))
                                        {
                                            finalCrewMember.rosterStatus = ProtoCrewMember.RosterStatus.Assigned;
                                            if (finalCrewMember.seat != null)
                                            {
                                                finalCrewMember.seat.SpawnCrew();
                                            }
                                        }
                                        else
                                        {
                                            KCTDebug.LogError($"Error when assigning {crewMember.name} to {p.partInfo.name}");
                                            finalCrewMember.rosterStatus = ProtoCrewMember.RosterStatus.Available;
                                            continue;
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        KCTDebug.LogError($"Error when assigning {crewMember.name} to {p.partInfo.name}: {ex}");
                                        finalCrewMember.rosterStatus = ProtoCrewMember.RosterStatus.Available;
                                        continue;
                                    }
                                }
                            }
                        }
                    }
                    KCTGameStates.LaunchedCrew.Clear();
                }

                KCT_GUI.HideAll();
                if (!KCTGameStates.IsSimulatedFlight && KCTGameStates.LaunchedVessel != null && FlightGlobals.ActiveVessel?.situation == Vessel.Situations.PRELAUNCH)
                {
                    KCTGameStates.LaunchedVessel.KSC = null;     //it's invalid now
                    KCTDebug.Log("Attempting to remove launched vessel from build list");
                    bool removed = KCTGameStates.LaunchedVessel.RemoveFromBuildList();
                    if (removed)     //Only do these when the vessel is first removed from the list
                    {
                        //Add the cost of the ship to the funds so it can be removed again by KSP
                        Utilities.AddFunds(KCTGameStates.LaunchedVessel.Cost, TransactionReasons.VesselRollout);
                        FlightGlobals.ActiveVessel.vesselName = KCTGameStates.LaunchedVessel.ShipName;
                    }

                    ReconRollout rollout = KCTGameStates.ActiveKSC.Recon_Rollout.FirstOrDefault(r => r.AssociatedID == KCTGameStates.LaunchedVessel.Id.ToString());
                    if (rollout != null)
                    {
                        KCTGameStates.ActiveKSC.Recon_Rollout.Remove(rollout);
                    }

                    AirlaunchPrep alPrep = KCTGameStates.ActiveKSC.AirlaunchPrep.FirstOrDefault(r => r.AssociatedID == KCTGameStates.LaunchedVessel.Id.ToString());
                    if (alPrep != null)
                    {
                        KCTGameStates.ActiveKSC.AirlaunchPrep.Remove(alPrep);
                    }

                    AirlaunchParams alParams = KCTGameStates.AirlaunchParams;
                    if (alParams != null && alParams.KCTVesselId == KCTGameStates.LaunchedVessel.Id &&
                        (!alParams.KSPVesselId.HasValue || alParams.KSPVesselId == FlightGlobals.ActiveVessel.id))
                    {
                        if (!alParams.KSPVesselId.HasValue)
                        {
                            alParams.KSPVesselId = FlightGlobals.ActiveVessel.id;
                        }
                        StartCoroutine(AirlaunchRoutine(alParams, FlightGlobals.ActiveVessel.id));
                    }
                }
                break;
            }

            _ratesUpdated = false;
            KCTDebug.Log("Start finished");

            _wfsOne  = new WaitForSeconds(1f);
            _wfsTwo  = new WaitForSeconds(2f);
            _wfsHalf = new WaitForSeconds(0.5f);

            DelayedStart();

            UpdateTechlistIconColor();
            StartCoroutine(HandleEditorButton_Coroutine());
        }
コード例 #4
0
        public void Start()
        {
            KCTDebug.Log("Start called");
            _wfsOne  = new WaitForSeconds(1f);
            _wfsTwo  = new WaitForSeconds(2f);
            _wfsHalf = new WaitForSeconds(0.5f);

            KCT_GUI.InitTooltips();

            if (Utilities.CurrentGameIsMission())
            {
                return;
            }

            // Subscribe to events from KSP and other mods
            if (!KCTEvents.Instance.SubscribedToEvents)
            {
                KCTEvents.Instance.SubscribeToEvents();
            }

            if (KCTGameStates.IsFirstStart)
            {
                PresetManager.Instance.SaveActiveToSaveData();
            }

            // Ghetto event queue
            if (HighLogic.LoadedScene == GameScenes.EDITOR)
            {
                InvokeRepeating("EditorRecalculation", 1, 1);

                KCT_GUI.BuildRateForDisplay = null;
                if (!KCT_GUI.IsPrimarilyDisabled)
                {
                    Utilities.RecalculateEditorBuildTime(EditorLogic.fetch.ship);
                }
            }

            if (KCT_GUI.IsPrimarilyDisabled &&
                InputLockManager.GetControlLock(KCTLaunchLock) == ControlTypes.EDITOR_LAUNCH)
            {
                InputLockManager.RemoveControlLock(KCTLaunchLock);
            }

            KACWrapper.InitKACWrapper();

            if (!PresetManager.Instance.ActivePreset.GeneralSettings.Enabled)
            {
                if (InputLockManager.GetControlLock(KCTKSCLock) == ControlTypes.KSC_FACILITIES)
                {
                    InputLockManager.RemoveControlLock(KCTKSCLock);
                }
                return;
            }

            //Begin primary mod functions

            KCT_GUI.GuiDataSaver.Load();
            KCT_GUI.GUIStates.HideAllNonMainWindows();

            if (!HighLogic.LoadedSceneIsFlight)
            {
                bool b = KCTGameStates.SimulationParams.BuildSimulatedVessel;
                KCTGameStates.SimulationParams.Reset();
                if (b && KCTGameStates.LaunchedVessel != null)
                {
                    Utilities.AddVesselToBuildList(KCTGameStates.LaunchedVessel);
                }
            }

            switch (HighLogic.LoadedScene)
            {
            case GameScenes.EDITOR:
                KCT_GUI.HideAll();
                if (!KCT_GUI.IsPrimarilyDisabled)
                {
                    KCT_GUI.GUIStates.ShowEditorGUI = KCTGameStates.ShowWindows[1];
                    if (KCTGameStates.EditorShipEditingMode)
                    {
                        KCT_GUI.EnsureEditModeIsVisible();
                    }
                    else
                    {
                        KCT_GUI.ToggleVisibility(KCT_GUI.GUIStates.ShowEditorGUI);
                    }
                }
                break;

            case GameScenes.SPACECENTER:
                bool shouldStart = KCT_GUI.GUIStates.ShowFirstRun;
                KCT_GUI.HideAll();
                KCTGameStates.ClearVesselEditMode();
                if (!shouldStart)
                {
                    KCT_GUI.GUIStates.ShowBuildList = KCTGameStates.ShowWindows[0];
                    KCT_GUI.ToggleVisibility(KCT_GUI.GUIStates.ShowBuildList);
                }
                KCT_GUI.GUIStates.ShowFirstRun = shouldStart;
                StartCoroutine(UpdateActiveLPLevel());
                StartCoroutine(UpdateBuildRates());
                break;

            case GameScenes.TRACKSTATION:
                KCTGameStates.ClearVesselEditMode();
                break;

            case GameScenes.FLIGHT:
                KCT_GUI.HideAll();
                ProcessFlightStart();
                break;
            }
            KCTDebug.Log("Start finished");

            DelayedStart();

            UpdateTechlistIconColor();
            StartCoroutine(HandleEditorButton_Coroutine());
        }
コード例 #5
0
        public override void OnLoad(ConfigNode node)
        {
            base.OnLoad(node);
            LoadTree();

            if (Utilities.CurrentGameIsMission())
            {
                return;
            }

            KCTDebug.Log("Reading from persistence.");
            KCTGameStates.KSCs.Clear();
            KCTGameStates.ActiveKSC = null;
            KCTGameStates.InitAndClearTechList();
            KCTGameStates.TechUpgradesTotal = 0;
            KCTGameStates.SciPointsTotal    = -1;
            KCT_GUI.ResetUpgradePointCounts();

            var        kctVS = new KCT_DataStorage();
            ConfigNode cn    = node.GetNode(kctVS.GetType().Name);

            if (cn != null)
            {
                ConfigNode.LoadObjectFromConfig(kctVS, cn);
            }

            bool foundStockKSC = false;

            foreach (ConfigNode ksc in node.GetNodes("KSC"))
            {
                string name       = ksc.GetValue("KSCName");
                var    loaded_KSC = new KSCItem(name);
                loaded_KSC.FromConfigNode(ksc);
                if (loaded_KSC != null && loaded_KSC.KSCName != null && loaded_KSC.KSCName.Length > 0)
                {
                    loaded_KSC.RDUpgrades[1] = KCTGameStates.TechUpgradesTotal;
                    if (KCTGameStates.KSCs.Find(k => k.KSCName == loaded_KSC.KSCName) == null)
                    {
                        KCTGameStates.KSCs.Add(loaded_KSC);
                    }
                    foundStockKSC |= string.Equals(loaded_KSC.KSCName, Utilities._legacyDefaultKscId, StringComparison.OrdinalIgnoreCase);
                }
            }

            Utilities.SetActiveKSCToRSS();
            if (foundStockKSC)
            {
                TryMigrateStockKSC();
            }

            var protoTechNodes      = new Dictionary <string, ProtoTechNode>(); // list of all the protoTechNodes that have been researched
            var inDevProtoTechNodes = new Dictionary <string, ProtoTechNode>(); // list of all the protoTechNodes that are being researched

            // get the TechList node containing the TechItems with the tech nodes currently being researched from KCT's ConfigNode
            if (node.GetNode("TechList") is ConfigNode tmp)
            {
                foreach (ConfigNode techNode in tmp.GetNodes("Tech"))
                {
                    var techStorageItem = new KCT_TechStorageItem();
                    ConfigNode.LoadObjectFromConfig(techStorageItem, techNode);
                    TechItem techItem = techStorageItem.ToTechItem();
                    techItem.ProtoNode = new ProtoTechNode(techNode.GetNode("ProtoNode"));
                    KCTGameStates.TechList.Add(techItem);

                    // save proto nodes that are in development
                    inDevProtoTechNodes.Add(techItem.ProtoNode.techID, techItem.ProtoNode);
                }
            }

            if (HighLogic.LoadedSceneIsEditor)
            {
                // get the nodes that have been researched from ResearchAndDevelopment
                protoTechNodes = Utilities.GetUnlockedProtoTechNodes();
                // iterate through all loaded parts to check if any of them should be experimental
                foreach (AvailablePart ap in PartLoader.LoadedPartsList)
                {
                    if (Utilities.PartIsUnlockedButNotPurchased(protoTechNodes, ap) || inDevProtoTechNodes.ContainsKey(ap.TechRequired))
                    {
                        Utilities.AddExperimentalPart(ap);
                    }
                }
            }

            KCTGameStates.ErroredDuringOnLoad.OnLoadFinish();
        }
コード例 #6
0
        public override void OnLoad(ConfigNode node)
        {
            try
            {
                base.OnLoad(node);
                LoadTree();

                if (Utilities.CurrentGameIsMission())
                {
                    return;
                }

                KCTDebug.Log("Reading from persistence.");
                KCTGameStates.KSCs.Clear();
                KCTGameStates.ActiveKSC = null;
                KCTGameStates.InitAndClearTechList();
                KCTGameStates.TechUpgradesTotal = 0;
                KCTGameStates.SciPointsTotal    = -1;
                KCT_GUI.ResetUpgradePointCounts();

                var kctVS = new KCT_DataStorage();
                if (node.GetNode(kctVS.GetType().Name) is ConfigNode cn)
                {
                    ConfigNode.LoadObjectFromConfig(kctVS, cn);
                }

                bool foundStockKSC = false;
                foreach (ConfigNode ksc in node.GetNodes("KSC"))
                {
                    string name       = ksc.GetValue("KSCName");
                    var    loaded_KSC = new KSCItem(name);
                    loaded_KSC.FromConfigNode(ksc);
                    if (loaded_KSC?.KSCName?.Length > 0)
                    {
                        loaded_KSC.RDUpgrades[1] = KCTGameStates.TechUpgradesTotal;
                        if (KCTGameStates.KSCs.Find(k => k.KSCName == loaded_KSC.KSCName) == null)
                        {
                            KCTGameStates.KSCs.Add(loaded_KSC);
                        }
                        foundStockKSC |= string.Equals(loaded_KSC.KSCName, Utilities._legacyDefaultKscId, StringComparison.OrdinalIgnoreCase);
                    }
                }

                Utilities.SetActiveKSCToRSS();
                if (foundStockKSC)
                {
                    TryMigrateStockKSC();
                }

                var protoTechNodes      = new Dictionary <string, ProtoTechNode>(); // list of all the protoTechNodes that have been researched
                var inDevProtoTechNodes = new Dictionary <string, ProtoTechNode>(); // list of all the protoTechNodes that are being researched

                // get the TechList node containing the TechItems with the tech nodes currently being researched from KCT's ConfigNode
                if (node.GetNode("TechList") is ConfigNode tmp)
                {
                    foreach (ConfigNode techNode in tmp.GetNodes("Tech"))
                    {
                        var techStorageItem = new KCT_TechStorageItem();
                        ConfigNode.LoadObjectFromConfig(techStorageItem, techNode);
                        TechItem techItem = techStorageItem.ToTechItem();
                        techItem.ProtoNode = new ProtoTechNode(techNode.GetNode("ProtoNode"));
                        KCTGameStates.TechList.Add(techItem);

                        // save proto nodes that are in development
                        inDevProtoTechNodes.Add(techItem.ProtoNode.techID, techItem.ProtoNode);
                    }
                }
                if (HighLogic.LoadedSceneIsEditor)
                {
                    // get the nodes that have been researched from ResearchAndDevelopment
                    protoTechNodes = Utilities.GetUnlockedProtoTechNodes();
                    // iterate through all loaded parts to check if any of them should be experimental
                    foreach (AvailablePart ap in PartLoader.LoadedPartsList)
                    {
                        if (Utilities.PartIsUnlockedButNotPurchased(protoTechNodes, ap) || inDevProtoTechNodes.ContainsKey(ap.TechRequired))
                        {
                            Utilities.AddExperimentalPart(ap);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                KCTGameStates.ErroredDuringOnLoad = true;
                Debug.LogError("[KCT] ERROR! An error while KCT loading data occurred. Things will be seriously broken!");
                PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "errorPopup", "Error Loading KCT Data", "ERROR! An error occurred while loading KCT data. Things will be seriously broken! Please report this error to LRTR GitHub and attach the log file. The game will be UNPLAYABLE in this state!", "Understood", false, HighLogic.UISkin);
            }
        }