|
1 | 1 | using System; |
2 | 2 | using System.Collections.Generic; |
3 | 3 | using System.Linq; |
4 | | -using System.Text; |
5 | 4 |
|
6 | 5 | namespace ProgressiveColonizationSystem |
7 | 6 | { |
@@ -42,41 +41,56 @@ public double TransferPercent |
42 | 41 |
|
43 | 42 | public Vessel TargetVessel { get; set; } |
44 | 43 |
|
45 | | - public void StartTransfer() |
| 44 | + public void StartTransfer(IReadOnlyDictionary<string, TransferDirection> userOverrides) |
46 | 45 | { |
47 | 46 | if (IsTransferUnderway) |
48 | 47 | { |
49 | 48 | return; |
50 | 49 | } |
51 | 50 |
|
52 | | - if (!TryFindResourceToTransfer(FlightGlobals.ActiveVessel, this.TargetVessel, out Dictionary<string,double> toSend, out Dictionary<string,double> toReceive)) |
53 | | - { |
54 | | - return; |
55 | | - } |
| 51 | + var transfers = TryFindResourceToTransfer(FlightGlobals.ActiveVessel, this.TargetVessel); |
56 | 52 |
|
57 | | - this.sourceVessel = FlightGlobals.ActiveVessel; |
58 | | - this.resourceConverter = new ResourceConverter(); |
59 | | - this.thisVesselConversionRecipe = new ConversionRecipe(); |
60 | | - this.otherVesselConversionRecipe = new ConversionRecipe(); |
61 | | - this.lastTransferTime = transferStartTime = Planetarium.GetUniversalTime(); |
62 | | - this.expectedTransferCompleteTime = transferStartTime + transferTimeInSeconds; |
63 | | - this.IsTransferUnderway = true; |
64 | | - this.IsTransferComplete = false; |
65 | | - foreach (string resource in toSend.Keys.Union(toReceive.Keys)) |
| 53 | + var thisVesselConversionRecipe = new ConversionRecipe(); |
| 54 | + var otherVesselConversionRecipe = new ConversionRecipe(); |
| 55 | + |
| 56 | + bool anythingGoingOn = false; |
| 57 | + foreach (var item in transfers) |
66 | 58 | { |
67 | | - bool isSending; |
68 | | - double amount; |
69 | | - isSending = toSend.TryGetValue(resource, out amount); |
70 | | - if (!isSending) |
| 59 | + if (!userOverrides.TryGetValue(item.ResourceName, out var direction)) |
71 | 60 | { |
72 | | - amount = toReceive[resource]; |
| 61 | + direction = item.SuggestedDirection; |
73 | 62 | } |
74 | 63 |
|
75 | | - double amountPerSecond = amount / transferTimeInSeconds; |
76 | | - (isSending ? thisVesselConversionRecipe.Inputs : thisVesselConversionRecipe.Outputs) |
77 | | - .Add(new ResourceRatio(resource, amountPerSecond, dumpExcess: false)); |
78 | | - (isSending ? otherVesselConversionRecipe.Outputs : otherVesselConversionRecipe.Inputs) |
79 | | - .Add(new ResourceRatio(resource, amountPerSecond, dumpExcess: false)); |
| 64 | + if (direction == TransferDirection.Send) |
| 65 | + { |
| 66 | + anythingGoingOn = true; |
| 67 | + double amountPerSecond = item.MaxCanSend / transferTimeInSeconds; |
| 68 | + thisVesselConversionRecipe.Inputs |
| 69 | + .Add(new ResourceRatio(item.ResourceName, amountPerSecond, dumpExcess: false)); |
| 70 | + otherVesselConversionRecipe.Outputs |
| 71 | + .Add(new ResourceRatio(item.ResourceName, amountPerSecond, dumpExcess: false)); |
| 72 | + } |
| 73 | + else if (direction == TransferDirection.Receive) |
| 74 | + { |
| 75 | + anythingGoingOn = true; |
| 76 | + double amountPerSecond = item.MaxCanReceive / transferTimeInSeconds; |
| 77 | + thisVesselConversionRecipe.Outputs |
| 78 | + .Add(new ResourceRatio(item.ResourceName, amountPerSecond, dumpExcess: false)); |
| 79 | + otherVesselConversionRecipe.Inputs |
| 80 | + .Add(new ResourceRatio(item.ResourceName, amountPerSecond, dumpExcess: false)); |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + if (anythingGoingOn) |
| 85 | + { |
| 86 | + this.sourceVessel = FlightGlobals.ActiveVessel; |
| 87 | + this.resourceConverter = new ResourceConverter(); |
| 88 | + this.thisVesselConversionRecipe = thisVesselConversionRecipe; |
| 89 | + this.otherVesselConversionRecipe = otherVesselConversionRecipe; |
| 90 | + this.lastTransferTime = transferStartTime = Planetarium.GetUniversalTime(); |
| 91 | + this.expectedTransferCompleteTime = transferStartTime + transferTimeInSeconds; |
| 92 | + this.IsTransferUnderway = true; |
| 93 | + this.IsTransferComplete = false; |
80 | 94 | } |
81 | 95 | } |
82 | 96 |
|
@@ -196,130 +210,120 @@ private static HashSet<string> GetVesselsConsumers(Vessel vessel) |
196 | 210 | return consumers; |
197 | 211 | } |
198 | 212 |
|
199 | | - private enum SnacksDirection |
| 213 | + public class ResourceTransferPossibility |
200 | 214 | { |
201 | | - Send, |
202 | | - Receive, |
203 | | - Neither, |
| 215 | + public ResourceTransferPossibility(string resourceName, TransferDirection suggestedDirection, double maxCanSend, double maxCanRecieve) |
| 216 | + { |
| 217 | + this.ResourceName = resourceName; |
| 218 | + this.SuggestedDirection = suggestedDirection; |
| 219 | + this.MaxCanSend = maxCanSend; |
| 220 | + this.MaxCanReceive = maxCanRecieve; |
| 221 | + } |
| 222 | + |
| 223 | + public string ResourceName { get; } |
| 224 | + public TransferDirection SuggestedDirection { get; } |
| 225 | + public double MaxCanSend { get; } |
| 226 | + public double MaxCanReceive { get; } |
204 | 227 | } |
205 | 228 |
|
206 | | - public static bool TryFindResourceToTransfer(Vessel sourceVessel, Vessel otherVessel, out Dictionary<string, double> toSend, out Dictionary<string, double> toReceive) |
| 229 | + public static IReadOnlyList<ResourceTransferPossibility> TryFindResourceToTransfer(Vessel sourceVessel, Vessel otherVessel) |
207 | 230 | { |
208 | 231 | SnackConsumption.ResourceQuantities(sourceVessel, 1, out Dictionary<string, double> thisShipCanSupply, out Dictionary<string, double> thisShipCanStore); |
209 | 232 | SnackConsumption.ResourceQuantities(otherVessel, 1, out Dictionary<string, double> otherShipCanSupply, out Dictionary<string, double> otherShipCanStore); |
210 | 233 |
|
211 | | - List<string> couldSend = thisShipCanSupply.Keys.Intersect(otherShipCanStore.Keys).ToList(); |
212 | | - List<string> couldTake = otherShipCanSupply.Keys.Intersect(thisShipCanStore.Keys).ToList(); |
213 | | - |
214 | 234 | List<PksTieredResourceConverter> otherVesselProducers = otherVessel.FindPartModulesImplementing<PksTieredResourceConverter>(); |
| 235 | + HashSet<string> thisShipsProducts = GetVesselsProducers(sourceVessel); |
| 236 | + HashSet<string> otherShipsProducts = GetVesselsProducers(otherVessel); |
| 237 | + HashSet<string> thisShipsConsumption = GetVesselsConsumers(sourceVessel); |
| 238 | + HashSet<string> otherShipsConsumption = GetVesselsConsumers(otherVessel); |
215 | 239 |
|
216 | | - // Refactor me! Way too much "if other vessel has quality, then send, else if this vessel has that quality, receive." |
| 240 | + List<ResourceTransferPossibility> result = new List<ResourceTransferPossibility>(); |
217 | 241 |
|
218 | | - toSend = new Dictionary<string, double>(); |
219 | | - toReceive = new Dictionary<string, double>(); |
220 | | - if ((otherVessel.GetCrewCount() == 0 && otherVesselProducers.Count > 0) |
221 | | - || otherVessel.vesselType == VesselType.Debris) |
| 242 | + foreach (string resourceName in thisShipCanStore.Keys.Union(thisShipCanStore.Keys).Union(otherShipCanSupply.Keys).Union(otherShipCanStore.Keys)) |
222 | 243 | { |
223 | | - // The player's trying to abandon the base so we'll take everything and give nothing. |
224 | | - foreach (var otherShipPair in otherShipCanSupply) |
| 244 | + double maxCanReceive; |
225 | 245 | { |
226 | | - string resourceName = otherShipPair.Key; |
227 | | - if (thisShipCanStore.ContainsKey(resourceName)) |
228 | | - { |
229 | | - toReceive.Add(resourceName, Math.Min(thisShipCanStore[resourceName], otherShipPair.Value)); |
230 | | - } |
| 246 | + thisShipCanStore.TryGetValue(resourceName, out double maxCanStore); |
| 247 | + otherShipCanSupply.TryGetValue(resourceName, out double maxCanBeSent); |
| 248 | + maxCanReceive = Math.Min(maxCanStore, maxCanBeSent); |
231 | 249 | } |
232 | | - return toReceive.Count > 0; |
233 | | - } |
234 | 250 |
|
235 | | - // If other ship has a producer for a resource, take it |
236 | | - // and if this ship has a producer for a resource (and the other doesn't), give it |
237 | | - HashSet<string> thisShipsProducts = GetVesselsProducers(sourceVessel); |
238 | | - HashSet<string> otherShipsProducts = GetVesselsProducers(otherVessel); |
239 | | - foreach (string takeableStuff in otherShipCanSupply.Keys.Union(thisShipCanSupply.Keys)) |
240 | | - { |
241 | | - if (otherShipsProducts.Contains(takeableStuff) |
242 | | - && !thisShipsProducts.Contains(takeableStuff) |
243 | | - && thisShipCanStore.ContainsKey(takeableStuff) |
244 | | - && otherShipCanSupply.ContainsKey(takeableStuff)) |
| 251 | + double maxCanSend; |
245 | 252 | { |
246 | | - toReceive.Add(takeableStuff, Math.Min(thisShipCanStore[takeableStuff], otherShipCanSupply[takeableStuff])); |
| 253 | + otherShipCanStore.TryGetValue(resourceName, out double maxCanStore); |
| 254 | + thisShipCanSupply.TryGetValue(resourceName, out double maxCanBeSent); |
| 255 | + maxCanSend = Math.Min(maxCanBeSent, maxCanStore); |
247 | 256 | } |
248 | | - else if (!otherShipsProducts.Contains(takeableStuff) |
249 | | - && thisShipsProducts.Contains(takeableStuff) |
250 | | - && otherShipCanStore.ContainsKey(takeableStuff) |
251 | | - && thisShipCanSupply.ContainsKey(takeableStuff)) |
| 257 | + |
| 258 | + if (maxCanReceive == 0 && maxCanSend == 0) |
252 | 259 | { |
253 | | - toSend.Add(takeableStuff, Math.Min(otherShipCanStore[takeableStuff], thisShipCanSupply[takeableStuff])); |
| 260 | + continue; |
254 | 261 | } |
255 | | - } |
256 | 262 |
|
257 | | - // If one ship needs a resource to produce stuff and the other doesn't, but has some in storage, move it. |
258 | | - HashSet<string> thisShipsConsumption = GetVesselsConsumers(sourceVessel); |
259 | | - HashSet<string> otherShipsConsumption = GetVesselsConsumers(otherVessel); |
260 | | - foreach (string resourceName in thisShipsConsumption.Union(otherShipsConsumption)) |
261 | | - { |
262 | | - if (otherShipCanSupply.ContainsKey(resourceName) |
263 | | - && thisShipCanStore.ContainsKey(resourceName) |
264 | | - && thisShipsConsumption.Contains(resourceName) |
265 | | - && !otherShipsConsumption.Contains(resourceName)) |
| 263 | + TransferDirection transferDirection = TransferDirection.Neither; |
| 264 | + |
| 265 | + // if the player seems to have abandoned otherVessel |
| 266 | + if ((otherVessel.GetCrewCount() == 0 && otherVesselProducers.Count > 0) |
| 267 | + || otherVessel.vesselType == VesselType.Debris) |
| 268 | + { |
| 269 | + transferDirection = TransferDirection.Receive; |
| 270 | + } |
| 271 | + // If other ship has a producer for a resource and we don't |
| 272 | + else if (otherShipsProducts.Contains(resourceName) |
| 273 | + && !thisShipsProducts.Contains(resourceName)) |
266 | 274 | { |
267 | | - toReceive.Add(resourceName, Math.Min(thisShipCanStore[resourceName], otherShipCanSupply[resourceName])); |
| 275 | + transferDirection = TransferDirection.Receive; |
268 | 276 | } |
269 | | - else if (thisShipCanSupply.ContainsKey(resourceName) |
270 | | - && otherShipCanStore.ContainsKey(resourceName) |
271 | | - && otherShipsConsumption.Contains(resourceName) |
| 277 | + // else if the converse... |
| 278 | + else if (!otherShipsProducts.Contains(resourceName) |
| 279 | + && thisShipsProducts.Contains(resourceName)) |
| 280 | + { |
| 281 | + transferDirection = TransferDirection.Send; |
| 282 | + } |
| 283 | + else if (thisShipsConsumption.Contains(resourceName) |
| 284 | + && !otherShipsConsumption.Contains(resourceName)) |
| 285 | + { |
| 286 | + transferDirection = TransferDirection.Receive; |
| 287 | + } |
| 288 | + else if (otherShipsConsumption.Contains(resourceName) |
272 | 289 | && !thisShipsConsumption.Contains(resourceName)) |
273 | 290 | { |
274 | | - toSend.Add(resourceName, Math.Min(otherShipCanStore[resourceName], thisShipCanSupply[resourceName])); |
| 291 | + transferDirection = TransferDirection.Send; |
| 292 | + } |
| 293 | + else if (resourceName == "Snacks-Tier4") |
| 294 | + { |
| 295 | + if (sourceVessel.vesselType == VesselType.Ship && (otherVessel.vesselType == VesselType.Base || otherVessel.vesselType == VesselType.Rover || otherVessel.vesselType == VesselType.Lander) |
| 296 | + || sourceVessel.vesselType == VesselType.Base && (otherVessel.vesselType == VesselType.Rover || otherVessel.vesselType == VesselType.Lander)) |
| 297 | + { |
| 298 | + transferDirection = TransferDirection.Send; |
| 299 | + } |
| 300 | + else if (otherVessel.vesselType == VesselType.Ship && (sourceVessel.vesselType == VesselType.Base || sourceVessel.vesselType == VesselType.Rover || sourceVessel.vesselType == VesselType.Lander) |
| 301 | + || otherVessel.vesselType == VesselType.Base && (sourceVessel.vesselType == VesselType.Rover || sourceVessel.vesselType == VesselType.Lander)) |
| 302 | + { |
| 303 | + transferDirection = TransferDirection.Receive; |
| 304 | + } |
| 305 | + else if (otherVessel.GetCrewCount() > 0 && sourceVessel.GetCrewCount() == 0) |
| 306 | + { |
| 307 | + transferDirection = TransferDirection.Send; |
| 308 | + } |
| 309 | + else if (otherVessel.GetCrewCount() == 0 && sourceVessel.GetCrewCount() > 0) |
| 310 | + { |
| 311 | + transferDirection = TransferDirection.Receive; |
| 312 | + } |
275 | 313 | } |
276 | | - } |
277 | | - |
278 | | - SnacksDirection snackDirectionBasedOnVesselType; |
279 | | - if (sourceVessel.vesselType == VesselType.Ship && (otherVessel.vesselType == VesselType.Base || otherVessel.vesselType == VesselType.Rover || otherVessel.vesselType == VesselType.Lander) |
280 | | - || sourceVessel.vesselType == VesselType.Base && (otherVessel.vesselType == VesselType.Rover || otherVessel.vesselType == VesselType.Lander)) |
281 | | - { |
282 | | - snackDirectionBasedOnVesselType = SnacksDirection.Send; |
283 | | - } |
284 | | - else if (otherVessel.vesselType == VesselType.Ship && (sourceVessel.vesselType == VesselType.Base || sourceVessel.vesselType == VesselType.Rover || sourceVessel.vesselType == VesselType.Lander) |
285 | | - || otherVessel.vesselType == VesselType.Base && (sourceVessel.vesselType == VesselType.Rover || sourceVessel.vesselType == VesselType.Lander)) |
286 | | - { |
287 | | - snackDirectionBasedOnVesselType = SnacksDirection.Receive; |
288 | | - } |
289 | | - else if (otherVessel.GetCrewCount() > 0 && sourceVessel.GetCrewCount() == 0) |
290 | | - { |
291 | | - snackDirectionBasedOnVesselType = SnacksDirection.Send; |
292 | | - } |
293 | | - else if (otherVessel.GetCrewCount() == 0 && sourceVessel.GetCrewCount() > 0) |
294 | | - { |
295 | | - snackDirectionBasedOnVesselType = SnacksDirection.Receive; |
296 | | - } |
297 | | - else |
298 | | - { |
299 | | - snackDirectionBasedOnVesselType = SnacksDirection.Neither; |
300 | | - } |
301 | 314 |
|
302 | | - // Send snacks? |
303 | | - if (otherShipCanStore.ContainsKey("Snacks-Tier4") |
304 | | - && thisShipCanSupply.ContainsKey("Snacks-Tier4") |
305 | | - && (thisShipsProducts.Contains("Snacks-Tier4") // Always send if we produce it |
306 | | - || (!otherShipsProducts.Contains("Snacks-Tier4") // Don't send if the other guy produces |
307 | | - && snackDirectionBasedOnVesselType == SnacksDirection.Send))) |
308 | | - { |
309 | | - toReceive.Remove("Snacks-Tier4"); |
310 | | - toSend["Snacks-Tier4"] = Math.Min(thisShipCanSupply["Snacks-Tier4"], otherShipCanStore["Snacks-Tier4"]); |
311 | | - } |
312 | | - else if (thisShipCanStore.ContainsKey("Snacks-Tier4") |
313 | | - && otherShipCanSupply.ContainsKey("Snacks-Tier4") |
314 | | - && (otherShipsProducts.Contains("Snacks-Tier4") // Always take if the other guy produces |
315 | | - || (!thisShipsProducts.Contains("Snacks-Tier4") // Don't take if we produce it |
316 | | - && snackDirectionBasedOnVesselType == SnacksDirection.Receive))) |
317 | | - { |
318 | | - toSend.Remove("Snacks-Tier4"); |
319 | | - toReceive["Snacks-Tier4"] = Math.Min(thisShipCanStore["Snacks-Tier4"], otherShipCanSupply["Snacks-Tier4"]); |
| 315 | + if (transferDirection == TransferDirection.Send && maxCanSend == 0) |
| 316 | + { |
| 317 | + transferDirection = TransferDirection.Neither; |
| 318 | + } |
| 319 | + else if (transferDirection == TransferDirection.Receive && maxCanReceive == 0) |
| 320 | + { |
| 321 | + transferDirection = TransferDirection.Neither; |
| 322 | + } |
| 323 | + result.Add(new ResourceTransferPossibility(resourceName, transferDirection, maxCanSend, maxCanReceive)); |
320 | 324 | } |
321 | 325 |
|
322 | | - return toReceive.Any() || toSend.Any(); |
| 326 | + return result; |
323 | 327 | } |
324 | 328 | } |
325 | 329 | } |
0 commit comments