/
ModuleRTDataTransmitter.cs
214 lines (181 loc) · 10 KB
/
ModuleRTDataTransmitter.cs
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
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using KSP.Localization;
namespace RemoteTech.Modules
{
/// <summary>Used to transmit science from a vessel with an antenna.</summary>
public sealed class ModuleRTDataTransmitter : PartModule, IScienceDataTransmitter
{
//Default parameters unless loaded from antenna configuration
[KSPField]
public float
PacketInterval = 0.5f,
PacketSize = 1.0f,
PacketResourceCost = 10f;
[KSPField]
public String
RequiredResource = "ElectricCharge";
[KSPField(guiName = "#RT_ModuleUI_Comms", guiActive = true)]//Comms
public String GUIStatus = "";
private bool isBusy;
private readonly List<ScienceData> scienceDataQueue = new List<ScienceData>();
private double timeElapsed = 0;
// Compatible with ModuleDataTransmitter
public override void OnLoad(ConfigNode node)
{
RTLog.Notify("ModuleRTDataTransmitter::OnLoad");
foreach (ConfigNode data in node.GetNodes("CommsData"))
{
scienceDataQueue.Add(new ScienceData(data));
}
GUIStatus = Localizer.Format("#RT_ModuleUI_Comms_Status");//"Idle"
}
// Compatible with ModuleDataTransmitter
public override void OnSave(ConfigNode node)
{
RTLog.Notify("ModuleRTDataTransmitter::OnSave");
scienceDataQueue.ForEach(d => d.Save(node.AddNode("CommsData")));
}
bool IScienceDataTransmitter.CanTransmit()
{
RTLog.Notify("ModuleRTDataTransmitter::CanTransmit");
return true;
}
void IScienceDataTransmitter.TransmitData(List<ScienceData> dataQueue)
{
RTLog.Notify("ModuleRTDataTransmitter::TransmitData(2p)");
scienceDataQueue.AddRange(dataQueue);
if (!isBusy)
{
StartCoroutine(Transmit());
}
}
float IScienceDataTransmitter.DataRate { get { return PacketSize / PacketInterval; } }
double IScienceDataTransmitter.DataResourceCost { get { return PacketResourceCost / PacketSize; } }
bool IScienceDataTransmitter.IsBusy() { return isBusy; }
public void FixedUpdate()
{
if (isBusy)
{
timeElapsed += TimeWarp.fixedDeltaTime;
}
}
private IEnumerator Transmit(Callback callback = null)
{
RTLog.Notify("ModuleRTDataTransmitter::Transmit");
var msg = new ScreenMessage(Localizer.Format("#RT_ModuleUI_TransmitMsg", part.partInfo.title), 4f, ScreenMessageStyle.UPPER_LEFT);//String.Format("[{0}]: Starting Transmission...", )
var msgStatus = new ScreenMessage(String.Empty, 4.0f, ScreenMessageStyle.UPPER_LEFT);
ScreenMessages.PostScreenMessage(msg);
isBusy = true;
while (scienceDataQueue.Any())
{
var scienceData = scienceDataQueue[0];
var dataAmount = scienceData.dataAmount;
scienceDataQueue.RemoveAt(0);
bool aborted = false;
var subject = ResearchAndDevelopment.GetSubjectByID(scienceData.subjectID);
if (subject == null)
subject = new ScienceSubject("", "", 1, 0, 0);
int packets = Mathf.CeilToInt(scienceData.dataAmount / PacketSize);
RnDCommsStream commStream = null;
if (ResearchAndDevelopment.Instance != null && !scienceData.triggered)
{
// pre-calculate the time interval - fix for x64 systems
// workaround for issue #136
//float time1 = Time.time;
//yield return new WaitForSeconds(PacketInterval);
// get the delta time
//float x64PacketInterval = (Time.time - time1);
//RTLog.Notify("Changing RnDCommsStream timeout from {0} to {1}", PacketInterval, x64PacketInterval);
//(porting to 1.2): check if scienceData.baseTransmitValue alone or with scienceData.transmitBonus
//commStream = new RnDCommsStream(subject, scienceData.dataAmount, x64PacketInterval,
commStream = new RnDCommsStream(subject, scienceData.dataAmount, PacketInterval,
scienceData.baseTransmitValue, false, ResearchAndDevelopment.Instance);
}
//StartCoroutine(SetFXModules_Coroutine(modules_progress, 0.0f));
float power = 0;
timeElapsed = 0;
while (packets > 0)
{
if (timeElapsed >= PacketInterval)
{
timeElapsed -= PacketInterval;
power += part.RequestResource("ElectricCharge", PacketResourceCost - power);
if (power >= PacketResourceCost * 0.95)
{
GUIStatus = Localizer.Format("#RT_ModuleUI_Comms_Status2");//"Uploading Data..."
// remove some power due to transmission
power -= PacketResourceCost;
// transmitted size
float frame = Math.Min(PacketSize, dataAmount);
// subtract current packet size from data left to transmit
// and clamp it to 1 digit precision to avoid large float precision error (#667)
dataAmount -= frame;
dataAmount = (float)Math.Round(dataAmount, 1);
packets--;
float progress = (scienceData.dataAmount - dataAmount) / scienceData.dataAmount;
msgStatus.message = Localizer.Format("#RT_ModuleUI_TransmitMsg2",part.partInfo.title, String.Format("{0:P0}", progress));//String.Format("[{0}]: Uploading Data... {1:P0}",,part.partInfo.title ,progress )
ScreenMessages.PostScreenMessage(msgStatus);
RTLog.Notify("[Transmitter]: Uploading Data... ({0}) - {1} Mits/sec. Packets to go: {2} - Other experiments waiting to transfer: {3}",
scienceData.title, (PacketSize / PacketInterval).ToString("0.00"), packets, scienceDataQueue.Count);
// if we've a defined callback parameter so skip to stream each packet
if (commStream != null)
{
RTLog.Notify(
"[Transmitter]: PacketSize: {0}; Transmitted size (frame): {1}; Data left to transmit (dataAmount): {2}; Packets left (packets): {3}",
PacketSize, frame, dataAmount, packets);
// use try / catch to prevent NRE spamming in KSP code when RT is used with other mods.
try
{
// check if it's the last packet to send
if (packets == 0)
{
// issue #667, issue #714 ; floating point error in RnDCommsStream.StreamData method when adding to dataIn private field
// e.g scienceData.dataAmount is 10 but in the end RnDCommsStream.dataIn will be 9.999999, so the science never
// gets registered to the ResearchAndDevelopment center.
// Let's just go ahead and send the full amount so there's no question if we sent it all
// KSP will clamp the final size to PacketSize anyway.
frame = scienceData.dataAmount;
}
commStream.StreamData(frame, vessel.protoVessel);
}
catch (NullReferenceException nre)
{
RTLog.Notify("[Transmitter] A problem occurred during science transmission: {0}", RTLogLevel.LVL2, nre);
}
}
else
{
RTLog.Notify("[Transmitter]: [DEBUG] commstream is null and no callback");
}
}
else
{
// not enough power
msg.message = "<b><color=orange>" + Localizer.Format("#RT_ModuleUI_TransmitMsg3", part.partInfo.title,RequiredResource)+ "</color></b>";//String.Format("<b><color=orange>[{0}]: Warning! Not Enough {1}!</color></b>", , )
ScreenMessages.PostScreenMessage(msg);
aborted = true;
GUIStatus = String.Format("{0}/{1} {2}", power, PacketResourceCost, RequiredResource);
}
}
yield return new WaitForFixedUpdate();
}
// effectively inform the game that science has been transmitted
if (scienceData.triggered)
{
GameEvents.OnTriggeredDataTransmission.Fire(scienceData, vessel, aborted);
}
yield return new WaitForSeconds(PacketInterval * 2);
}
isBusy = false;
msg.message = Localizer.Format("#RT_ModuleUI_TransmitMsg4", part.partInfo.title);//String.Format("[{0}]: Done!", )
ScreenMessages.PostScreenMessage(msg);
if (callback != null)
callback.Invoke();
GUIStatus = Localizer.Format("#RT_ModuleUI_Comms_Status");//"Idle"
}
}
}