From 61b5ad11449df046e2f696883f4a42cd71367295 Mon Sep 17 00:00:00 2001 From: fingerboxes Date: Wed, 29 Apr 2015 20:06:32 -0700 Subject: [PATCH] Revert "Revert "Some speculative work."" This reverts commit d0a29918998626eca9d8076c85cc9daeba08319c. --- Source/CrewQ.csproj | 3 +- Source/Data.cs | 253 ----------------------------- Source/Interface/AppLauncher.cs | 4 +- Source/Interface/SceneModule.cs | 6 +- Source/Interface/SettingsWindow.cs | 32 ++-- Source/Main.cs | 40 +---- Source/Roster.cs | 191 ++++++++++++++++++++++ Source/Settings.cs | 131 +++++++++++++++ 8 files changed, 353 insertions(+), 307 deletions(-) delete mode 100644 Source/Data.cs create mode 100644 Source/Roster.cs create mode 100644 Source/Settings.cs diff --git a/Source/CrewQ.csproj b/Source/CrewQ.csproj index 9407c8a..098404e 100644 --- a/Source/CrewQ.csproj +++ b/Source/CrewQ.csproj @@ -50,7 +50,8 @@ - + + diff --git a/Source/Data.cs b/Source/Data.cs deleted file mode 100644 index fd7a735..0000000 --- a/Source/Data.cs +++ /dev/null @@ -1,253 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 Alexander Taylor - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using UnityEngine; -using KSPPluginFramework; -using FingerboxLib; - -namespace CrewQueue -{ - [KSPScenario(ScenarioCreationOptions.AddToAllGames, new GameScenes[] { GameScenes.EDITOR, GameScenes.FLIGHT, GameScenes.SPACECENTER, GameScenes.TRACKSTATION })] - class Data : ScenarioModule - { - // Singleton boilerplate - private static Data _Instance; - internal static Data Instance - { - get - { - if (_Instance == null) - { - throw new Exception("ERROR: Attempted to query CrewQData before it was loaded."); - } - - return _Instance; - } - } - - [KSPField(isPersistant = true)] - public bool settingHideSettingsIcon = false; - - [KSPField(isPersistant = true)] - public bool settingUseCrewCompositions = true; - - [KSPField(isPersistant = true)] - public bool settingDoCustomAssignment = true; - - [KSPField(isPersistant = true)] - public bool settingVacationHardlock = false; - - [KSPField(isPersistant = true)] - public bool settingRemoveDefaultCrews = true; - - [KSPField(isPersistant = true)] - public double settingVacationScalar = 0.1; - - [KSPField(isPersistant = true)] - public int settingMinimumVacationDays = 7; - - [KSPField(isPersistant = true)] - public int settingMaximumVacationDays = 28; - - private List _CrewList; - - public override void OnAwake() - { - _Instance = this; - _CrewList = new List(); - - GameEvents.onKerbalAdded.Add(onKerbalAdded); - GameEvents.onKerbalRemoved.Add(onKerbalRemoved); - } - - void Start() - { - // This should only ever run once, when the game is first created or the mod is installed. - if (_CrewList.Count < HighLogic.CurrentGame.CrewRoster.Count) - { - foreach (ProtoCrewMember kerbal in HighLogic.CurrentGame.CrewRoster.Crew) - { - if (!_CrewList.Select(x => x.ProtoCrewReference).Contains(kerbal)) - { - _CrewList.Add(new CrewNode(kerbal.name)); - } - } - } - - Main.Instance.ShowVacationingCrew(); - } - - void Destroy() - { - _Instance = null; - - GameEvents.onKerbalAdded.Remove(onKerbalAdded); - GameEvents.onKerbalRemoved.Remove(onKerbalRemoved); - } - - // KSP Events - - // If a Kerbal gets added to the roster, add it to ours - private void onKerbalAdded(ProtoCrewMember kerbal) - { - if (!_CrewList.Select(x => x.ProtoCrewReference).Contains(kerbal)) - { - _CrewList.Add(new CrewNode(kerbal.name)); - } - } - - // Likewise, if a Kerbal is removed from the roster, remove it from ours - private void onKerbalRemoved(ProtoCrewMember kerbal) - { - if (_CrewList.Select(x => x.ProtoCrewReference).Contains(kerbal)) - { - _CrewList.Remove(_CrewList.FirstOrDefault(x => x.ProtoCrewReference == kerbal)); - } - } - - // ScenarioModule methods - public override void OnLoad(ConfigNode rootNode) - { - if (rootNode.HasNode("CrewList")) - { - rootNode = rootNode.GetNode("CrewList"); - IEnumerable crewNodes = rootNode.GetNodes(); - - foreach (ConfigNode crewNode in crewNodes) - { - _CrewList.Add(new CrewNode(crewNode)); - } - } - } - - public override void OnSave(ConfigNode rootNode) - { - rootNode.RemoveNode("CrewList"); - ConfigNode crewNodes = new ConfigNode("CrewList"); - - foreach (CrewNode crewNode in _CrewList) - { - crewNodes.AddNode(crewNode.AsConfigNode()); - } - - rootNode.AddNode(crewNodes); - } - - // Accessor methods. - public double GetVacationTimer(ProtoCrewMember kerbal) - { - return _CrewList.FirstOrDefault(x => x.ProtoCrewReference == kerbal).Expiration; - } - - public bool OnVacation(ProtoCrewMember kerbal) - { - return ((GetVacationTimer(kerbal) - Planetarium.GetUniversalTime()) > 0); - } - - public void SetVacationTimer(ProtoCrewMember kerbal, double timeout) - { - _CrewList.FirstOrDefault(x => x.ProtoCrewReference == kerbal).Expiration = timeout; - } - } - - // Our storage node type. - class CrewNode - { - private string name; - private double expiration; - - public ProtoCrewMember ProtoCrewReference - { - get - { - return HighLogic.CurrentGame.CrewRoster.Crew.FirstOrDefault(x => x.name == name); - } - } - - public double Expiration - { - get - { - return expiration; - } - - set - { - expiration = value; - - Logging.Debug("expiration is now: " + expiration); - } - } - - public CrewNode(ConfigNode sourceNode) - { - name = sourceNode.GetValue("Name"); - expiration = Convert.ToDouble(sourceNode.GetValue("Expiration")); - } - - public CrewNode(string crewName) - { - name = crewName; - } - - public ConfigNode AsConfigNode() - { - ConfigNode _thisNode = new ConfigNode("KERBAL"); - - _thisNode.AddValue("Name", name); - _thisNode.AddValue("Expiration", expiration); - - Logging.Debug("Building ConfigNode: expiration: " + expiration); - - return _thisNode; - } - - public override bool Equals(object obj) - { - if (obj == null || obj.GetType() != typeof(CrewNode)) - { - return false; - } - - if ((obj as CrewNode).ProtoCrewReference == this.ProtoCrewReference) - { - return true; - } - else - { - return false; - } - } - - public override int GetHashCode() - { - return ProtoCrewReference.GetHashCode(); - } - } -} diff --git a/Source/Interface/AppLauncher.cs b/Source/Interface/AppLauncher.cs index df45d4e..51cbe42 100644 --- a/Source/Interface/AppLauncher.cs +++ b/Source/Interface/AppLauncher.cs @@ -39,7 +39,7 @@ class AppLauncher : ProtoAppLauncher { public override Texture AppLauncherIcon { - get { return GameDatabase.Instance.GetTexture("Fingerboxes/CrewQ/Icons/appLauncher", false); } + get { return GameDatabase.Instance.GetTexture("Fingerboxes/CrewQueue/Icons/appLauncher", false); } } public override ApplicationLauncher.AppScenes Visibility @@ -49,7 +49,7 @@ public override ApplicationLauncher.AppScenes Visibility try { bool coalescedCondition = (settingsWindow != null) && - (Data.Instance.settingHideSettingsIcon == false || settingsWindow.Visible == true); + (Settings.Instance.HideSettingsIcon == false || settingsWindow.Visible == true); return coalescedCondition ? ApplicationLauncher.AppScenes.SPACECENTER : ApplicationLauncher.AppScenes.NEVER; } diff --git a/Source/Interface/SceneModule.cs b/Source/Interface/SceneModule.cs index 95e344c..d06b2ad 100644 --- a/Source/Interface/SceneModule.cs +++ b/Source/Interface/SceneModule.cs @@ -39,7 +39,7 @@ public abstract class SceneModule : MonoBehaviourExtended { public void CleanManifest() { - if (CMAssignmentDialog.Instance != null && (Data.Instance.settingRemoveDefaultCrews || Data.Instance.settingDoCustomAssignment)) + if (CMAssignmentDialog.Instance != null && Settings.Instance.AssignCrews) { VesselCrewManifest originalVesselManifest = CMAssignmentDialog.Instance.GetManifest(); IList partCrewManifests = originalVesselManifest.GetCrewableParts(); @@ -55,7 +55,7 @@ public void CleanManifest() partManifest.RemoveCrewFromSeat(partManifest.GetCrewSeat(crewMember)); } } - if (Data.Instance.settingDoCustomAssignment) + if (Settings.Instance.AssignCrews) { partManifest.AddCrewToOpenSeats(Main.Instance.GetCrewForPart(partManifest.PartInfo.partPrefab, true)); } @@ -77,7 +77,7 @@ public void OnFillButton(ref POINTER_INFO eventPointer) if (eventPointer.evt == POINTER_INFO.INPUT_EVENT.TAP) { Logging.Debug("Fill Button Pressed"); - if (Data.Instance.settingDoCustomAssignment) + if (Settings.Instance.AssignCrews) { // TODO - make this work. } diff --git a/Source/Interface/SettingsWindow.cs b/Source/Interface/SettingsWindow.cs index f80b4e9..05282b7 100644 --- a/Source/Interface/SettingsWindow.cs +++ b/Source/Interface/SettingsWindow.cs @@ -119,34 +119,34 @@ protected override void Update() public void PreSync() { - Data settings = Data.Instance; + Settings settings = Settings.Instance; if (settings != null) { - toggleDoCustomAssignment = settings.settingDoCustomAssignment; - toggleUseCrewCompositions = settings.settingUseCrewCompositions; - toggleVacationHardlock = settings.settingVacationHardlock; - localMinimumVacationDays = settings.settingMinimumVacationDays.ToString(); - localMaximumVacationDays = settings.settingMaximumVacationDays.ToString(); - localVacationScalar = (settings.settingVacationScalar * 100).ToString(); + toggleDoCustomAssignment = settings.AssignCrews; + toggleUseCrewCompositions = settings.StrictCrewCompositions; + toggleVacationHardlock = settings.VacationHardLock; + localMinimumVacationDays = settings.MinimumVacationDays.ToString(); + localMaximumVacationDays = settings.MaximumVacationDays.ToString(); + localVacationScalar = (settings.VacationScalar * 100).ToString(); } } public void Sync() { - Data settings = Data.Instance; + Settings settings = Settings.Instance; if (settings != null) { - settings.settingHideSettingsIcon = toggleRemoveDefaultCrews; - settings.settingDoCustomAssignment = toggleDoCustomAssignment; - settings.settingUseCrewCompositions = toggleUseCrewCompositions; - settings.settingVacationHardlock = toggleVacationHardlock; - settings.settingHideSettingsIcon = toggleHideSettingsIcon; + settings.HideSettingsIcon = toggleRemoveDefaultCrews; + settings.AssignCrews = toggleDoCustomAssignment; + settings.StrictCrewCompositions = toggleUseCrewCompositions; + settings.VacationHardLock = toggleVacationHardlock; + settings.HideSettingsIcon = toggleHideSettingsIcon; try { - settings.settingMinimumVacationDays = Int32.Parse(localMinimumVacationDays); + settings.MinimumVacationDays = Int32.Parse(localMinimumVacationDays); } catch (Exception) { @@ -155,7 +155,7 @@ public void Sync() try { - settings.settingMaximumVacationDays = Int32.Parse(localMaximumVacationDays); + settings.MaximumVacationDays = Int32.Parse(localMaximumVacationDays); } catch (Exception) { @@ -164,7 +164,7 @@ public void Sync() try { - settings.settingVacationScalar = (Double.Parse(localVacationScalar) / 100); + settings.VacationScalar = (Double.Parse(localVacationScalar) / 100); } catch (Exception) { diff --git a/Source/Main.cs b/Source/Main.cs index acd5e56..42584bb 100644 --- a/Source/Main.cs +++ b/Source/Main.cs @@ -48,7 +48,7 @@ public static Main Instance { if (_Instance == null) { - throw new Exception("ERROR: Attempted to access CrewQ before it was loaded"); + throw new Exception("ERROR: Attempted to access CrewQueue.Main before it was loaded"); } return _Instance; } @@ -73,8 +73,8 @@ void OnVesselRecoveryRequested(Vessel vessel) { double adjustedTime = vessel.missionTime + Planetarium.GetUniversalTime(); - adjustedTime = adjustedTime.Clamp(Planetarium.GetUniversalTime() + Data.Instance.settingMinimumVacationDays * Utilities.GetDayLength, - Planetarium.GetUniversalTime() + Data.Instance.settingMaximumVacationDays * Utilities.GetDayLength); + adjustedTime = adjustedTime.Clamp(Planetarium.GetUniversalTime() + Settings.Instance.MinimumVacationDays * Utilities.GetDayLength, + Planetarium.GetUniversalTime() + Settings.Instance.MaximumVacationDays * Utilities.GetDayLength); foreach (ProtoCrewMember kerbal in vessel.GetVesselCrew()) { @@ -91,7 +91,7 @@ internal IEnumerable AvailableCrew { IEnumerable _AvailableCrew; - if (Data.Instance.settingVacationHardlock) + if (Settings.Instance.VacationHardLock) { _AvailableCrew = HighLogic.CurrentGame.CrewRoster.Crew.Where(x => x.OnVacation() == false && x.rosterStatus == ProtoCrewMember.RosterStatus.Available); } @@ -113,33 +113,9 @@ internal IEnumerable AvailableCrew } } - internal IEnumerable UnavailableCrew - { - get - { - return HighLogic.CurrentGame.CrewRoster.Crew.Except(AvailableCrew); - } - } - - internal IOrderedEnumerable NewbieCrew - { - get - { - return AvailableCrew.OrderBy(x => x.experienceLevel).ThenBy(x => x.GetVacationTimer()); - } - } - - internal IOrderedEnumerable VeteranCrew - { - get - { - return AvailableCrew.OrderByDescending(x => x.experienceLevel).ThenBy(x => x.GetVacationTimer()); - } - } - internal void HideVacationingCrew() { - if (Data.Instance.settingVacationHardlock) + if (Settings.Instance.VacationHardLock) { foreach (ProtoCrewMember kerbal in UnavailableCrew) { @@ -205,18 +181,18 @@ public static class CrewQExtensions { internal static double GetVacationTimer(this ProtoCrewMember kerbal) { - return Data.Instance.GetVacationTimer(kerbal); + return Settings.Instance.GetVacationTimer(kerbal); } internal static bool OnVacation(this ProtoCrewMember kerbal) { - return Data.Instance.OnVacation(kerbal); + return Settings.Instance.OnVacation(kerbal); } internal static void SetVacationTimer(this ProtoCrewMember kerbal, double timeout) { Logging.Debug("Attempting to set vacation timer: " + timeout); - Data.Instance.SetVacationTimer(kerbal, timeout); + Settings.Instance.SetVacationTimer(kerbal, timeout); } } diff --git a/Source/Roster.cs b/Source/Roster.cs new file mode 100644 index 0000000..420589f --- /dev/null +++ b/Source/Roster.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using FingerboxLib; + +namespace CrewQueue +{ + internal class Roster + { + // Singleton boilerplate + private static Roster _Instance; + internal static Roster Instance + { + get + { + if (_Instance == null) + { + _Instance = new Roster(); + } + + return _Instance; + } + } + + private HashSet _ExtDataSet = new HashSet(); + + public IEnumerable ExtDataSet + { + get + { + return _ExtDataSet.Where(x => x.ProtoReference != null); + } + } + + public IEnumerable CrewOnVacation + { + get + { + return ExtDataSet.Where(x => x.OnVacation).Select(x => x.ProtoReference); + } + } + + public IEnumerable CrewAvailable + { + get + { + return HighLogic.CurrentGame.CrewRoster.Crew.Except(CrewOnVacation); + } + } + + // Returns the ExtData node for the specified Kerbal name + internal KerbalExtData GetExtForKerbal(ProtoCrewMember kerbal) + { + return GetExtForKerbal(kerbal.name); + } + + internal KerbalExtData GetExtForKerbal(string kerbal) + { + // Set only allows non-unique elements, so just try to add it anyway + _ExtDataSet.Add(new KerbalExtData(kerbal)); + + // Now find the element + foreach (KerbalExtData data in _ExtDataSet) + { + if (data.Name == kerbal) + { + return data; + } + } + + // This will never happen + Logging.Error("Something dun broke, unsuccessful KerbalExtData lookup"); + return null; + } + + internal bool UpdateExtName(string oldName, string newName) + { + //make sure that the new name is available + if (HighLogic.CurrentGame.CrewRoster.Crew.Where(x => x.name == newName).ToList().Count == 0) + { + GetExtForKerbal(oldName).Name = newName; + return true; + } + else + { + return false; + } + } + + // Our storage node type. + internal class KerbalExtData + { + // This is the Kerbal which this ExtData is attached to. + // Any mods which change the name of a Kerbal will need to update this value + // TODO - add method to update values to API + internal string Name; + + // This is the time value at which this Kerbal's last mission started. + // When a mission is started, the LastMissionEndTime must also be reset + internal double LastMissionStartTime = 0; + internal double LastMissionEndTime = 0; + + // Returns the duration of the last mission + internal double LastMissionDuration + { + get + { + return (LastMissionEndTime - LastMissionStartTime).Clamp(0, LastMissionEndTime); + } + } + + internal double LastMissionVacationExpiry + { + get + { + Settings settings = Settings.Instance; + return (settings.VacationScalar * LastMissionDuration).Clamp(settings.MinimumVacationDays, settings.MaximumVacationDays); + } + } + + internal bool OnVacation + { + get + { + return LastMissionVacationExpiry > Planetarium.GetUniversalTime() ? true : false; + } + } + + // Should return null if this is an unattached element + internal ProtoCrewMember ProtoReference + { + get + { + return HighLogic.CurrentGame.CrewRoster.Crew.Where(k => k.name == Name).FirstOrDefault(); + } + } + + internal KerbalExtData(string newName) + { + Name = newName; + } + + public override bool Equals(object obj) + { + if (obj != null && (obj as KerbalExtData) != null && (obj as KerbalExtData).Name == Name) + { + return true; + } + else + { + return false; + } + } + + public override int GetHashCode() + { + return Name.GetHashCode(); + } + + public override string ToString() + { + return Name; + } + } + } + + internal static class RosterExtensions + { + public static double GetLastMissionStartTime(this ProtoCrewMember kerbal) + { + return Roster.Instance.GetExtForKerbal(kerbal).LastMissionStartTime; + } + + public static double GetLastMissionEndTime(this ProtoCrewMember kerbal) + { + return Roster.Instance.GetExtForKerbal(kerbal).LastMissionEndTime; + } + + public static double LastMissionDuration(this ProtoCrewMember kerbal) + { + return Roster.Instance.GetExtForKerbal(kerbal).LastMissionDuration; + } + + public static double LastMissionVacationExpiry(this ProtoCrewMember kerbal) + { + return Roster.Instance.GetExtForKerbal(kerbal).LastMissionVacationExpiry; + } + } +} diff --git a/Source/Settings.cs b/Source/Settings.cs new file mode 100644 index 0000000..39c4d9b --- /dev/null +++ b/Source/Settings.cs @@ -0,0 +1,131 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Alexander Taylor + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using UnityEngine; +using KSPPluginFramework; +using FingerboxLib; + +namespace CrewQueue +{ + [KSPScenario(ScenarioCreationOptions.AddToAllGames, new GameScenes[] { GameScenes.EDITOR, GameScenes.FLIGHT, GameScenes.SPACECENTER, GameScenes.TRACKSTATION })] + class Settings : ScenarioModule + { + // Singleton boilerplate + private static Settings _Instance; + internal static Settings Instance + { + get + { + if (_Instance == null) + { + throw new Exception("ERROR: Attempted to query CrewQueue.Data before it was loaded."); + } + + return _Instance; + } + } + + [KSPField(isPersistant = true)] + public bool HideSettingsIcon = false; + + [KSPField(isPersistant = true)] + public bool StrictCrewCompositions = true; + + [KSPField(isPersistant = true)] + public bool AssignCrews = true; + + [KSPField(isPersistant = true)] + public bool VacationHardLock = true; + + [KSPField(isPersistant = true)] + public double VacationScalar = 0.1; + + [KSPField(isPersistant = true)] + public int MinimumVacationDays = 7; + + [KSPField(isPersistant = true)] + public int MaximumVacationDays = 28; + + public override void OnAwake() + { + _Instance = this; + } + + void Destroy() + { + _Instance = null; + } + + // ScenarioModule methods + public override void OnLoad(ConfigNode rootNode) + { + if (rootNode.HasNode("CrewList")) + { + rootNode = rootNode.GetNode("CrewList"); + IEnumerable crewNodes = rootNode.GetNodes(); + + foreach (ConfigNode crewNode in crewNodes) + { + _CrewList.Add(new CrewNode(crewNode)); + } + } + } + + public override void OnSave(ConfigNode rootNode) + { + rootNode.RemoveNode("CrewList"); + ConfigNode crewNodes = new ConfigNode("CrewList"); + + foreach (CrewNode crewNode in _CrewList) + { + crewNodes.AddNode(crewNode.AsConfigNode()); + } + + rootNode.AddNode(crewNodes); + } + + // Accessor methods. + public double GetVacationTimer(ProtoCrewMember kerbal) + { + return _CrewList.FirstOrDefault(x => x.ProtoCrewReference == kerbal).Expiration; + } + + public bool OnVacation(ProtoCrewMember kerbal) + { + return ((GetVacationTimer(kerbal) - Planetarium.GetUniversalTime()) > 0); + } + + public void SetVacationTimer(ProtoCrewMember kerbal, double timeout) + { + _CrewList.FirstOrDefault(x => x.ProtoCrewReference == kerbal).Expiration = timeout; + } + } + + +}