forked from RemoteTechnologiesGroup/RemoteTech
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSatelliteManager.cs
More file actions
264 lines (224 loc) · 9.43 KB
/
Copy pathSatelliteManager.cs
File metadata and controls
264 lines (224 loc) · 9.43 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
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using RemoteTech.Modules;
namespace RemoteTech
{
/// <summary>
/// Class keeping track of RemoteTech satellites.
/// Acts as a list of vessels managed by RemoteTech.
/// </summary>
public class SatelliteManager : IEnumerable<VesselSatellite>, IDisposable
{
public event Action<VesselSatellite> OnRegister = delegate { };
public event Action<VesselSatellite> OnUnregister = delegate { };
public int Count => _satelliteCache.Count;
public VesselSatellite this[Guid g] => GetSatelliteById(g);
public VesselSatellite this[Vessel v] => v == null ? null : GetSatelliteById(v.id);
private readonly Dictionary<Guid, List<ISignalProcessor>> _loadedSpuCache =
new Dictionary<Guid, List<ISignalProcessor>>();
private readonly Dictionary<Guid, VesselSatellite> _satelliteCache =
new Dictionary<Guid, VesselSatellite>();
public SatelliteManager()
{
GameEvents.onVesselCreate.Add(OnVesselCreate);
GameEvents.onVesselDestroy.Add(OnVesselDestroy);
GameEvents.onVesselGoOnRails.Add(OnVesselOnRails);
OnRegister += vs => RTLog.Notify("SatelliteManager: OnRegister({0})", vs);
OnUnregister += vs => RTLog.Notify("SatelliteManager: OnUnregister({0})", vs);
}
/// <summary>
/// Registers a signal processor for the vessel.
/// </summary>
/// <param name="vessel">The vessel.</param>
/// <param name="spu">The signal processor.</param>
/// <returns>Guid key under which the signal processor was registered.</returns>
public Guid Register(Vessel vessel, ISignalProcessor spu)
{
RTLog.Notify("SatelliteManager: Register({0})", spu);
var key = vessel.id;
if (!_loadedSpuCache.ContainsKey(key))
{
UnregisterProto(vessel.id);
_loadedSpuCache[key] = new List<ISignalProcessor>();
}
// Add if non duplicate
var signalProcessor = _loadedSpuCache[key].Find(x => x == spu);
if (signalProcessor != null)
return key;
_loadedSpuCache[key].Add(spu);
// Create a new satellite if it's the only loaded signal processor.
if (_loadedSpuCache[key].Count != 1)
return key;
_satelliteCache[key] = new VesselSatellite(_loadedSpuCache[key]);
OnRegister(_satelliteCache[key]);
return key;
}
/// <summary>
/// Unregisters the specified signal processor.
/// </summary>
/// <param name="key">The key the signal processor was registered under.</param>
/// <param name="spu">The signal processor.</param>
public void Unregister(Guid key, ISignalProcessor spu)
{
RTLog.Notify("SatelliteManager: Unregister({0})", spu);
// Return if nothing to unregister.
if (!_loadedSpuCache.ContainsKey(key)) return;
// Find instance of the signal processor.
var instanceId = _loadedSpuCache[key].FindIndex(x => x == spu);
if (instanceId == -1)
return;
// Remove satellite if no signal processors remain.
if (_loadedSpuCache[key].Count == 1)
{
if (_satelliteCache.ContainsKey(key))
{
VesselSatellite sat = _satelliteCache[key];
OnUnregister(sat);
_satelliteCache.Remove(key);
}
_loadedSpuCache[key].RemoveAt(instanceId);
_loadedSpuCache.Remove(key);
// search vessel by id
var vessel = RTUtil.GetVesselById(key);
if (vessel != null)
{
// trigger the onRails on more time
// to re-register the satellite as a protoSat
OnVesselOnRails(vessel);
}
}
else
{
_loadedSpuCache[key].RemoveAt(instanceId);
}
}
/// <summary>
/// Registers a protosatellite compiled from the unloaded vessel data.
/// </summary>
/// <param name="vessel">The vessel.</param>
public void RegisterProto(Vessel vessel)
{
Guid key = vessel.protoVessel.vesselID;
RTLog.Notify("SatelliteManager: RegisterProto({0}, {1})", vessel.vesselName, key);
// Return if there are still signal processors loaded.
if (_loadedSpuCache.ContainsKey(vessel.id)) {
_loadedSpuCache.Remove(vessel.id);
}
var spu = vessel.GetSignalProcessor();
if (spu == null)
return;
var protos = new List<ISignalProcessor> {spu};
_satelliteCache[key] = new VesselSatellite(protos);
OnRegister(_satelliteCache[key]);
}
/// <summary>
/// Unregisters the protosatellite which was compiled from the unloaded vessel data.
/// </summary>
public void UnregisterProto(Guid key)
{
RTLog.Notify("SatelliteManager: UnregisterProto({0})", key);
// Return if there are still signal processors loaded.
if (_loadedSpuCache.ContainsKey(key))
return;
// Unregister satellite if it exists.
if (!_satelliteCache.ContainsKey(key))
return;
OnUnregister(_satelliteCache[key]);
_satelliteCache.Remove(key);
}
private VesselSatellite GetSatelliteById(Guid key)
{
VesselSatellite result;
return _satelliteCache.TryGetValue(key, out result) ? result : null;
}
public IEnumerable<ISatellite> FindCommandStations()
{
return _satelliteCache.Values.Where(vs => vs.IsCommandStation).Cast<ISatellite>();
}
private void OnVesselOnRails(Vessel v)
{
if (v.parts.Count == 0)
{
RegisterProto(v);
}
}
private void OnVesselCreate(Vessel v)
{
RTLog.Notify("SatelliteManager: OnVesselCreate({0}, {1})", v.id, v.vesselName);
}
private void OnVesselDestroy(Vessel v)
{
RTLog.Notify("SatelliteManager: OnVesselDestroy({0}, {1})", v.id, v.vesselName);
UnregisterProto(v.id);
}
public void Dispose()
{
GameEvents.onVesselCreate.Remove(OnVesselCreate);
GameEvents.onVesselDestroy.Remove(OnVesselDestroy);
GameEvents.onVesselGoOnRails.Remove(OnVesselOnRails);
}
public IEnumerator<VesselSatellite> GetEnumerator()
{
return _satelliteCache.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public static partial class RTUtil
{
public static bool IsSignalProcessor(this ProtoPartModuleSnapshot ppms)
{
return ppms.GetBool("IsRTSignalProcessor");
}
public static bool IsSignalProcessor(this PartModule pm)
{
return pm.Fields.GetValue<bool>("IsRTSignalProcessor");
}
public static ISignalProcessor GetSignalProcessor(this Vessel v)
{
RTLog.Notify("GetSignalProcessor({0}): Check", v.vesselName);
ISignalProcessor result = null;
if (v.loaded && v.parts.Count > 0)
{
var partModuleList = v.Parts.SelectMany(p => p.Modules.Cast<PartModule>()).Where(pm => pm.IsSignalProcessor()).ToList();
// try to look for a moduleSPU
result = partModuleList.FirstOrDefault(pm => pm.moduleName == "ModuleSPU") as ISignalProcessor ??
partModuleList.FirstOrDefault() as ISignalProcessor;
}
else
{
var protoPartList = v.protoVessel.protoPartSnapshots.SelectMany(x => x.modules).Where(ppms => ppms.IsSignalProcessor()).ToList();
// try to look for a moduleSPU on a unloaded vessel
var protoPartProcessor = protoPartList.FirstOrDefault(ppms => ppms.moduleName == "ModuleSPU") ??
protoPartList.FirstOrDefault();
// convert the found protoPartSnapshots to a ProtoSignalProcessor
if (protoPartProcessor != null)
{
result = new ProtoSignalProcessor(protoPartProcessor, v);
}
}
return result;
}
public static bool IsCommandStation(this ProtoPartModuleSnapshot ppms)
{
return ppms.GetBool("IsRTCommandStation");
}
public static bool IsCommandStation(this PartModule pm)
{
return pm.Fields.GetValue<bool>("IsRTCommandStation");
}
public static bool HasCommandStation(this Vessel v)
{
RTLog.Notify("HasCommandStation({0})", v.vesselName);
if (v.loaded && v.parts.Count > 0)
{
return v.Parts.SelectMany(p => p.Modules.Cast<PartModule>()).Any(pm => pm.IsCommandStation());
}
return v.protoVessel.protoPartSnapshots.SelectMany(x => x.modules).Any(pm => pm.IsCommandStation());
}
}
}