forked from RemoteTechnologiesGroup/RemoteTech
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRTSettings.cs
More file actions
333 lines (284 loc) · 15.1 KB
/
Copy pathRTSettings.cs
File metadata and controls
333 lines (284 loc) · 15.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
namespace RemoteTech
{
public class RTSettings
{
public static EventVoid OnSettingsChanged = new EventVoid("OnSettingsChanged");
public static EventVoid OnSettingsLoaded = new EventVoid("OnSettingsLoaded");
public static EventVoid OnSettingsSaved = new EventVoid("OnSettingsSaved");
private static Settings _instance;
public static Settings Instance
{
get
{
//check if there's an already loaded instance
if (_instance != null && _instance.SettingsLoaded)
return _instance;
// otherwise load settings to get the instance
return _instance = Settings.Load();
}
}
/// <summary>
/// Replace the given settings with a new Settings object of the given setting preset, and save it
/// </summary>
public static void ReloadSettings(Settings previousSettings, string presetCfgUrl)
{
_instance = Settings.LoadPreset(previousSettings, presetCfgUrl);
_instance.Save();
}
}
public class Settings
{
// Global settings of the RemoteTech add-on, whose default values are to be read from Default_Settings.cfg
// Note: do not rename any of those fields here except if you change the name in the configuration file; be careful though: this will render all previous saves incompatible!!!
[Persistent] public bool RemoteTechEnabled;
[Persistent] public bool CommNetEnabled;
[Persistent] public float ConsumptionMultiplier;
[Persistent] public float RangeMultiplier;
[Persistent] public float MissionControlRangeMultiplier;
[Persistent] public double OmniRangeClampFactor;
[Persistent] public double DishRangeClampFactor;
[Persistent] public string ActiveVesselGuid;
[Persistent] public string NoTargetGuid;
[Persistent] public float SpeedOfLight;
[Persistent] public MapFilter MapFilter;
[Persistent] public bool EnableSignalDelay;
[Persistent] public RangeModel.RangeModel RangeModelType;
[Persistent] public double MultipleAntennaMultiplier;
[Persistent] public bool ThrottleTimeWarp;
[Persistent] public bool ThrottleZeroOnNoConnection;
[Persistent] public bool HideGroundStationsBehindBody;
[Persistent] public bool ControlAntennaWithoutConnection;
[Persistent] public bool UpgradeableMissionControlAntennas;
[Persistent] public bool HideGroundStationsOnDistance;
[Persistent] public bool ShowMouseOverInfoGroundStations;
[Persistent] public bool AutoInsertKaCAlerts;
[Persistent] public int FCLeadTime;
[Persistent] public bool FCOffAfterExecute;
[Persistent] public float DistanceToHideGroundStations;
[Persistent] public Color DishConnectionColor;
[Persistent] public Color OmniConnectionColor;
[Persistent] public Color ActiveConnectionColor;
[Persistent] public Color RemoteStationColorDot;
[Persistent] public Color DirectConnectionColor = new Color(0, 0.749f, 0.952f, 1); //TODO: remove two new values after some significant time - 7 Nov 2017
[Persistent] public bool SignalRelayEnabled = false;
[Persistent] public bool IgnoreLineOfSight;
[Persistent(collectionIndex = "STATION")] public List<MissionControlSatellite> GroundStations;
[Persistent(collectionIndex = "PRESETS")] public List<string> PreSets;
public const string SaveFileName = "RemoteTech_Settings.cfg";
public static readonly string DefaultSettingCfgURL = AssemblyLoader.loadedAssemblies.FirstOrDefault(a => a.assembly.GetName().Name.Equals("RemoteTech")).url.Replace("/Plugins", "") + "/Default_Settings/RemoteTechSettings";
/// <summary>Trigger to force a reloading of the settings if a selected save is running.</summary>
public bool SettingsLoaded;
/// <summary>True if its the first start of RemoteTech for this save, false otherwise.</summary>
public bool FirstStart;
/// <summary>Temp Variable for all the Window Positions for each instance.</summary>
public Dictionary<string, Rect> SavedWindowPositions = new Dictionary<string, Rect>();
/// <summary>
/// Returns the current RemoteTech_Settings of an existing save full path. The path will be empty
/// if no save is loaded or the game is a training mission
/// </summary>
private static string SaveSettingFile
{
get
{
if (HighLogic.CurrentGame == null || RTUtil.IsGameScenario)
return string.Empty;
return KSPUtil.ApplicationRootPath + "/saves/" + HighLogic.SaveFolder + Path.DirectorySeparatorChar + SaveFileName;
}
}
/// <summary>
/// Saves the current RTSettings object to the RemoteTech_Settings.cfg
/// </summary>
public void Save()
{
try
{
// only save the settings if the file name is not empty (i.e. not on loading screen or in training)
if (string.IsNullOrEmpty(SaveSettingFile))
return;
var details = new ConfigNode("RemoteTechSettings");
ConfigNode.CreateConfigFromObject(this, 0, details);
var save = new ConfigNode();
save.AddNode(details);
save.Save(SaveSettingFile);
RTSettings.OnSettingsSaved.Fire();
}
catch (Exception e)
{
RTLog.Notify("An error occurred while attempting to save: {0}", RTLogLevel.LVL1, e.Message);
}
}
/// <summary>
/// Utilise KSP's GameDatabase to get a list of cfgs, included our Default_Settings.cfg, contained the 'RemoteTechSettings'
/// node and process each cfg accordingly
///
/// NOTE: Please do not use the static 'Default_Settings.cfg' file directly because we want third-party modders to apply
/// ModuleManager patches of their tweaks, like no signal delay, to our default-settings cfg that will be used when a
/// player starts a new game. (refer to our online manual for more details)
/// </summary>
public static Settings Load()
{
// Create a blank object of settings
var settings = new Settings();
var defaultSuccess = false;
// Exploit KSP's GameDatabase to find our MM-patched cfg of default settings (from GameData/RemoteTech/Default_Settings.cfg)
var cfgs = GameDatabase.Instance.GetConfigs("RemoteTechSettings");
for (var i = 0; i < cfgs.Length; i++)
{
if(cfgs[i].url.Equals(DefaultSettingCfgURL))
{
defaultSuccess = ConfigNode.LoadObjectFromConfig(settings, cfgs[i].config);
RTLog.Notify("Load default settings into object with {0}: LOADED {1}", cfgs[i].config, defaultSuccess ? "OK" : "FAIL");
break;
}
}
if (!defaultSuccess) // disable itself and write explanation to KSP's log
{
RTLog.Notify("RemoteTech is disabled because the default cfg '{0}' is not found", DefaultSettingCfgURL);
return null;
// the main impact of returning null is the endless loop of invoking Load() in the KSP's loading screen
}
settings.SettingsLoaded = true;
// Disable RemoteTech on Training missions
if (RTUtil.IsGameScenario)
{
settings.RemoteTechEnabled = false;
settings.CommNetEnabled = true;
}
// stop and return default settings if we are on the KSP loading screen OR in training scenarios
if (string.IsNullOrEmpty(SaveSettingFile))
{
return settings;
}
// try to load from the save-settings.cfg (MM-patches will not touch because it is outside GameData)
var load = ConfigNode.Load(SaveSettingFile);
if (load == null)
{
// write the RT settings to the player's save folder
settings.Save();
settings.FirstStart = true;
}
else
{
// old or new format?
if (load.HasNode("RemoteTechSettings"))
load = load.GetNode("RemoteTechSettings");
// replace the default settings with save-setting file
var success = ConfigNode.LoadObjectFromConfig(settings, load);
RTLog.Notify("Found and load save settings into object with {0}: LOADED {1}", load, success ? "OK" : "FAIL");
}
// find third-party mods' RemoteTech settings
SearchAndPreparePresets(settings);
// Detect if the celestial body, that Mission Control is on (default body index 1), is Kerbin
var KSCMC = settings.GroundStations.Find(x => x.GetName().Equals("Mission Control")); // leave extra ground stations to modders, who need to provide MM patches
if (KSCMC != null && !KSCMC.GetBody().name.Equals("Kerbin") && KSCMC.GetBody().flightGlobalsIndex == 1) // Kopernicus or similar map changes the planet
{
KSCMC.SetBodyIndex(FlightGlobals.GetHomeBodyIndex());
RTLog.Notify("KSC's Mission Control is on the wrong planet (not Kerbin/Earth) (Any Kopernicus/similar map would change). Relocated to the homeworld's body index {0}.", FlightGlobals.GetHomeBodyIndex());
}
RTSettings.OnSettingsLoaded.Fire();
return settings;
}
private static void SearchAndPreparePresets(Settings settings)
{
var presetsChanged = false;
// Exploit KSP's GameDatabase to find third-party mods' RemoteTechSetting node (from GameData/ExampleMod/RemoteTechSettings.cfg)
var cfgs = GameDatabase.Instance.GetConfigs("RemoteTechSettings");
var rtSettingCfGs = cfgs.Select(x => x.url).ToList();
//check for any invalid preset in the settings of a save
for (var i=0; i < settings.PreSets.Count(); i++)
{
if (rtSettingCfGs.Contains(settings.PreSets[i]))
continue;
RTLog.Notify("Remove an invalid setting preset {0}", settings.PreSets[i]);
settings.PreSets.RemoveAt(i);
presetsChanged = true;
}
//find and add new presets to the settings of a save
for (var i = 0; i < rtSettingCfGs.Count(); i++)
{
if (settings.PreSets.Contains(rtSettingCfGs[i]))
continue;
RTLog.Notify("Add a new setting preset {0}", rtSettingCfGs[i]);
settings.PreSets.Add(rtSettingCfGs[i]);
presetsChanged = true;
}
if (presetsChanged) // only if new RT settings are found and added to the save-setting's PreSets node
settings.Save();
}
/// <summary>
/// Load a preset configuration into the RemoteTech settings object.
/// </summary>
public static Settings LoadPreset(Settings previousSettings, string presetCfgUrl)
{
var newPreSetSettings = new Settings();
var successLoadPreSet = false;
// Exploit KSP's GameDatabase to find third-party mods' RemoteTechSetting node (from GameData/ExampleMod/RemoteTechSettings.cfg)
var rtSettingCfGs = GameDatabase.Instance.GetConfigs("RemoteTechSettings");
for(var i = 0; i < rtSettingCfGs.Length; i++)
{
var rtSettingCfg = rtSettingCfGs[i];
if (!rtSettingCfg.url.Equals(presetCfgUrl))
continue;
// Preserve important information of RT, such as the single ID
var importantInfoNode = new ConfigNode();
importantInfoNode.AddValue("MapFilter", previousSettings.MapFilter);
importantInfoNode.AddValue("ActiveVesselGuid", previousSettings.ActiveVesselGuid);
importantInfoNode.AddValue("NoTargetGuid", previousSettings.NoTargetGuid);
successLoadPreSet = ConfigNode.LoadObjectFromConfig(newPreSetSettings, rtSettingCfg.config);
RTLog.Notify("Load the preset cfg into object with {0}: LOADED {1}", newPreSetSettings, successLoadPreSet ? "OK" : "FAIL");
// Restore backups
ConfigNode.LoadObjectFromConfig(newPreSetSettings, importantInfoNode);
break;
}
return successLoadPreSet?newPreSetSettings: previousSettings;
}
/// <summary>
/// Adds a new ground station to the list.
/// </summary>
/// <param name="name">Name of the ground station</param>
/// <param name="latitude">Latitude position</param>
/// <param name="longitude">Longitude position</param>
/// <param name="height">Height above sea level</param>
/// <param name="body">Reference body 1=Kerbin etc...</param>
/// <returns>A new <see cref="Guid"/> if a new station was successfully added otherwise a Guid.Empty.</returns>
public Guid AddGroundStation(string name, double latitude, double longitude, double height, int body)
{
RTLog.Notify("Trying to add ground station({0})", RTLogLevel.LVL1, name);
var newGroundStation = new MissionControlSatellite();
newGroundStation.SetDetails(name, latitude, longitude, height, body);
// Already on the list?
var foundGroundStation = GroundStations.FirstOrDefault(ms => ms.GetDetails().Equals(newGroundStation.GetDetails()));
if (foundGroundStation != null)
{
RTLog.Notify("Ground station already exists!");
return Guid.Empty;
}
GroundStations.Add(newGroundStation);
Save();
return newGroundStation.mGuid;
}
/// <summary>Removes a ground station from the list by its unique <paramref name="stationid"/>.</summary>
/// <param name="stationid">Unique ground station id</param>
/// <returns>Returns true for a successful removed station, otherwise false.</returns>
public bool RemoveGroundStation(Guid stationid)
{
RTLog.Notify("Trying to remove ground station {0}", RTLogLevel.LVL1, stationid);
for (var i = 0; i < GroundStations.Count; i++)
{
if (!GroundStations[i].mGuid.Equals(stationid))
continue;
RTLog.Notify("Removing {0} ", RTLogLevel.LVL1, GroundStations[i].GetName());
GroundStations.RemoveAt(i);
Save();
return true;
}
RTLog.Notify("Cannot find station {0}", RTLogLevel.LVL1, stationid);
return false;
}
}
}