From 085cfc52d26586f8a4c399e83916fc62b5973145 Mon Sep 17 00:00:00 2001 From: Aubrey Goodman Date: Mon, 22 Jun 2020 20:05:43 -0700 Subject: [PATCH 1/4] Initial draft of fuel steal on hit --- BDArmory/Bullets/PooledBullet.cs | 91 ++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/BDArmory/Bullets/PooledBullet.cs b/BDArmory/Bullets/PooledBullet.cs index b96b2026a..3862b5c2d 100644 --- a/BDArmory/Bullets/PooledBullet.cs +++ b/BDArmory/Bullets/PooledBullet.cs @@ -538,6 +538,14 @@ private void ApplyDamage(Part hitPart, RaycastHit hit, float multiplier, float p tData.lastPersonWhoHitMe = aName; tData.lastHitTime = Planetarium.GetUniversalTime(); tData.everyoneWhoHitMe.Add(aName); + + Vessel attacker = FlightGlobals.Vessels.Find(v => v.vesselName.Equals(aName)); + Vessel defender = FlightGlobals.Vessels.Find(v => v.vesselName.Equals(tName)); + if (attacker != null && defender != null) + { + StealResource(attacker, defender, "LiquidFuel", 0.5); + StealResource(attacker, defender, "Oxidizer", 0.5); + } } } @@ -559,6 +567,89 @@ private void ApplyDamage(Part hitPart, RaycastHit hit, float multiplier, float p } } + private void StealResource(Vessel src, Vessel dst, string resourceName, double ration) + { + // identify all parts on source vessel with resource + HashSet srcParts = new HashSet(); + foreach (Part p in src.Parts) + { + DeepFind(p, resourceName, srcParts); + } + + // identify all parts on destination vessel with resource + HashSet dstParts = new HashSet(); + foreach (Part p in dst.Parts) + { + DeepFind(p, resourceName, dstParts); + } + + if ( srcParts.Count == 0 || dstParts.Count == 0 ) + { + Debug.Log(string.Format("[BDArmoryCompetition] Steal resource {0} failed; no parts.", resourceName)); + return; + } + + double remainingAmount = srcParts.Sum(p => p.amount); + double amount = remainingAmount * ration; + + // transfer resource from src->dst parts, distributed evenly + List orderedSrcParts = new List(srcParts); + List orderedDstParts = new List(dstParts); + int srcIndex = 0; + double srcVal = 0; + for (int k=0;k srcVal ) + { + srcVal = orderedSrcParts[k].amount; + srcIndex = k; + } + } + int dstIndex = 0; + double val = 0; + for (int k=0;k val ) + { + val = diff; + dstIndex = k; + } + } + PartResource pr = orderedSrcParts[srcIndex]; + PartResource rcv = orderedDstParts[dstIndex]; + amount = Math.Min(Math.Min(amount, pr.amount), rcv.maxAmount - rcv.amount); + if (amount == 0) + { + return; + } + Debug.Log(string.Format("[BDArmoryCompetition] Attempting steal {0} of {1} from {2} (curr={3},max={4}) to {5} (curr={6},max={7})", amount, resourceName, pr.part.name, pr.amount, pr.maxAmount, rcv.part.name, rcv.amount, rcv.maxAmount)); + double confirmedAmount = pr.part.TransferResource(pr, amount, rcv.part); + if( confirmedAmount < 0 ) + { + Debug.Log(string.Format("[BDArmoryCompetition] Steal successful {0} from {2} to {1}", -confirmedAmount, src.vesselName, dst.vesselName)); + } + else + { + Debug.Log("[BDArmoryCompetition] Steal failed"); + } + } + + private void DeepFind(Part p, string resourceName, HashSet accumulator) + { + foreach (PartResource r in p.Resources) + { + if( r.resourceName.Equals(resourceName) ) + { + accumulator.Add(r); + } + } + foreach (Part child in p.children) + { + DeepFind(child, resourceName, accumulator); + } + } + private void CalculateDragNumericalIntegration() { Vector3 dragAcc = currentVelocity * currentVelocity.magnitude * From c184f6e7ca6949f1420f936a7a257145263babbc Mon Sep 17 00:00:00 2001 From: Aubrey Goodman Date: Tue, 23 Jun 2020 00:03:41 -0700 Subject: [PATCH 2/4] Respect resource priority when stealing fuel --- BDArmory/Bullets/PooledBullet.cs | 111 +++++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 29 deletions(-) diff --git a/BDArmory/Bullets/PooledBullet.cs b/BDArmory/Bullets/PooledBullet.cs index 3862b5c2d..d883ffccb 100644 --- a/BDArmory/Bullets/PooledBullet.cs +++ b/BDArmory/Bullets/PooledBullet.cs @@ -567,6 +567,53 @@ private void ApplyDamage(Part hitPart, RaycastHit hit, float multiplier, float p } } + private class PriorityQueue + { + private Dictionary> partResources = new Dictionary>(); + + public PriorityQueue(HashSet elements) + { + foreach (PartResource r in elements) + { + Add(r); + } + } + + public void Add(PartResource r) + { + int key = r.part.resourcePriorityOffset; + if( partResources.ContainsKey(key) ) + { + List existing = partResources[key]; + existing.Add(r); + partResources[key] = existing; + } + else + { + List newList = new List(); + newList.Add(r); + partResources.Add(key, newList); + } + } + + public List Pop() + { + if( partResources.Count == 0 ) + { + return new List(); + } + int key = partResources.Keys.Max(); + List result = partResources[key]; + partResources.Remove(key); + return result; + } + + public bool HasNext() + { + return partResources.Count != 0; + } + } + private void StealResource(Vessel src, Vessel dst, string resourceName, double ration) { // identify all parts on source vessel with resource @@ -592,46 +639,52 @@ private void StealResource(Vessel src, Vessel dst, string resourceName, double r double remainingAmount = srcParts.Sum(p => p.amount); double amount = remainingAmount * ration; - // transfer resource from src->dst parts, distributed evenly - List orderedSrcParts = new List(srcParts); - List orderedDstParts = new List(dstParts); - int srcIndex = 0; - double srcVal = 0; - for (int k=0;kdst parts, honoring their priorities + PriorityQueue sources = new PriorityQueue(srcParts); + PriorityQueue recipients = new PriorityQueue(dstParts); + + List allocations = new List(); + while( sources.HasNext() && recipients.HasNext() ) { - if( orderedSrcParts[k].amount > srcVal ) + List inputs = sources.Pop(); + List outputs = recipients.Pop(); + double availability = inputs.Sum(e => e.amount); + double opportunity = outputs.Sum(e => e.maxAmount - e.amount); + double perPartAmount = Math.Min(availability, amount) / (inputs.Count * outputs.Count); + foreach (PartResource n in inputs) { - srcVal = orderedSrcParts[k].amount; - srcIndex = k; + foreach (PartResource m in outputs) + { + ResourceAllocation ra = new ResourceAllocation(n, m.part, perPartAmount); + allocations.Add(ra); + } } } - int dstIndex = 0; - double val = 0; - for (int k=0;k val ) - { - val = diff; - dstIndex = k; - } + return; } - PartResource pr = orderedSrcParts[srcIndex]; - PartResource rcv = orderedDstParts[dstIndex]; - amount = Math.Min(Math.Min(amount, pr.amount), rcv.maxAmount - rcv.amount); - if (amount == 0) + double confirmed = 0; + foreach (ResourceAllocation ra in allocations) { - return; + confirmed += ra.sourceResource.part.TransferResource(ra.sourceResource, ra.amount, ra.destPart); } - Debug.Log(string.Format("[BDArmoryCompetition] Attempting steal {0} of {1} from {2} (curr={3},max={4}) to {5} (curr={6},max={7})", amount, resourceName, pr.part.name, pr.amount, pr.maxAmount, rcv.part.name, rcv.amount, rcv.maxAmount)); - double confirmedAmount = pr.part.TransferResource(pr, amount, rcv.part); - if( confirmedAmount < 0 ) + if (confirmed > 0) { - Debug.Log(string.Format("[BDArmoryCompetition] Steal successful {0} from {2} to {1}", -confirmedAmount, src.vesselName, dst.vesselName)); + Debug.Log(string.Format("[BDArmoryCompetition] Steal completed {0} from {2} to {1}", -confirmed, src.vesselName, dst.vesselName)); } - else + } + + private class ResourceAllocation + { + public PartResource sourceResource; + public Part destPart; + public double amount; + public ResourceAllocation(PartResource r, Part p, double a) { - Debug.Log("[BDArmoryCompetition] Steal failed"); + this.sourceResource = r; + this.destPart = p; + this.amount = a; } } From a9abbf6b1d73e2f21126d3ab1122e874e8ba1064 Mon Sep 17 00:00:00 2001 From: Aubrey Goodman Date: Tue, 23 Jun 2020 19:58:24 -0700 Subject: [PATCH 3/4] Improved resource priority allocations --- BDArmory/Bullets/PooledBullet.cs | 39 ++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/BDArmory/Bullets/PooledBullet.cs b/BDArmory/Bullets/PooledBullet.cs index d883ffccb..cdddcc9e4 100644 --- a/BDArmory/Bullets/PooledBullet.cs +++ b/BDArmory/Bullets/PooledBullet.cs @@ -545,6 +545,9 @@ private void ApplyDamage(Part hitPart, RaycastHit hit, float multiplier, float p { StealResource(attacker, defender, "LiquidFuel", 0.5); StealResource(attacker, defender, "Oxidizer", 0.5); + StealResource(attacker, defender, "20x102Ammo", 0.1); + StealResource(attacker, defender, "30x173Ammo", 0.1); + StealResource(attacker, defender, "50CalAmmo", 0.1); } } } @@ -632,7 +635,7 @@ private void StealResource(Vessel src, Vessel dst, string resourceName, double r if ( srcParts.Count == 0 || dstParts.Count == 0 ) { - Debug.Log(string.Format("[BDArmoryCompetition] Steal resource {0} failed; no parts.", resourceName)); + //Debug.Log(string.Format("[BDArmoryCompetition] Steal resource {0} failed; no parts.", resourceName)); return; } @@ -644,21 +647,43 @@ private void StealResource(Vessel src, Vessel dst, string resourceName, double r PriorityQueue recipients = new PriorityQueue(dstParts); List allocations = new List(); - while( sources.HasNext() && recipients.HasNext() ) + List inputs = null, outputs = null; + while ( amount > 0 ) { - List inputs = sources.Pop(); - List outputs = recipients.Pop(); + if (inputs == null) + { + inputs = sources.Pop(); + } + if (outputs == null) + { + outputs = recipients.Pop(); + } double availability = inputs.Sum(e => e.amount); double opportunity = outputs.Sum(e => e.maxAmount - e.amount); - double perPartAmount = Math.Min(availability, amount) / (inputs.Count * outputs.Count); + double tAmount = Math.Min(availability, Math.Min(opportunity, amount)); + double perPartAmount = tAmount / (inputs.Count * outputs.Count); foreach (PartResource n in inputs) { foreach (PartResource m in outputs) { + //Debug.Log(string.Format("[BDArmoryCompetition] Allocate {0} of {1} from {2} to {3}", perPartAmount, resourceName, n.part.name, m.part.name)); ResourceAllocation ra = new ResourceAllocation(n, m.part, perPartAmount); allocations.Add(ra); } } + if( availability < amount ) + { + inputs = null; + } + if( opportunity < amount ) + { + outputs = null; + } + if( tAmount == 0 ) + { + break; + } + amount -= tAmount; } if( allocations.Count == 0 ) { @@ -669,9 +694,9 @@ private void StealResource(Vessel src, Vessel dst, string resourceName, double r { confirmed += ra.sourceResource.part.TransferResource(ra.sourceResource, ra.amount, ra.destPart); } - if (confirmed > 0) + if (confirmed < 0) { - Debug.Log(string.Format("[BDArmoryCompetition] Steal completed {0} from {2} to {1}", -confirmed, src.vesselName, dst.vesselName)); + Debug.Log(string.Format("[BDArmoryCompetition] Steal completed {0} of {3} from {2} to {1}", -confirmed, src.vesselName, dst.vesselName, resourceName)); } } From 4ba0ce2090581f967f62111b971f4c47acae15af Mon Sep 17 00:00:00 2001 From: Aubrey Goodman Date: Tue, 23 Jun 2020 21:52:09 -0700 Subject: [PATCH 4/4] Added UI toggle and sliders for fuel/ammo ration --- BDArmory.Core/BDArmorySettings.cs | 3 +++ BDArmory/Bullets/PooledBullet.cs | 21 +++++++++++++-------- BDArmory/UI/BDArmorySetup.cs | 9 +++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/BDArmory.Core/BDArmorySettings.cs b/BDArmory.Core/BDArmorySettings.cs index 7f51e4035..cc52ebe49 100644 --- a/BDArmory.Core/BDArmorySettings.cs +++ b/BDArmory.Core/BDArmorySettings.cs @@ -58,5 +58,8 @@ public class BDArmorySettings [BDAPersistantSettingsField] public static bool PERFORMANCE_LOGGING = false; [BDAPersistantSettingsField] public static bool AUTOCATEGORIZE_PARTS = true; [BDAPersistantSettingsField] public static bool SHOW_CATEGORIES = false; + [BDAPersistantSettingsField] public static bool RESOURCE_STEAL_ENABLED = false; + [BDAPersistantSettingsField] public static float RESOURCE_STEAL_FUEL_RATION = 0.2f; + [BDAPersistantSettingsField] public static float RESOURCE_STEAL_AMMO_RATION = 0.2f; } } diff --git a/BDArmory/Bullets/PooledBullet.cs b/BDArmory/Bullets/PooledBullet.cs index cdddcc9e4..2f524d76b 100644 --- a/BDArmory/Bullets/PooledBullet.cs +++ b/BDArmory/Bullets/PooledBullet.cs @@ -539,15 +539,20 @@ private void ApplyDamage(Part hitPart, RaycastHit hit, float multiplier, float p tData.lastHitTime = Planetarium.GetUniversalTime(); tData.everyoneWhoHitMe.Add(aName); - Vessel attacker = FlightGlobals.Vessels.Find(v => v.vesselName.Equals(aName)); - Vessel defender = FlightGlobals.Vessels.Find(v => v.vesselName.Equals(tName)); - if (attacker != null && defender != null) + if (BDArmorySettings.RESOURCE_STEAL_ENABLED) { - StealResource(attacker, defender, "LiquidFuel", 0.5); - StealResource(attacker, defender, "Oxidizer", 0.5); - StealResource(attacker, defender, "20x102Ammo", 0.1); - StealResource(attacker, defender, "30x173Ammo", 0.1); - StealResource(attacker, defender, "50CalAmmo", 0.1); + float fuelRation = BDArmorySettings.RESOURCE_STEAL_FUEL_RATION; + float ammoRation = BDArmorySettings.RESOURCE_STEAL_AMMO_RATION; + Vessel attacker = FlightGlobals.Vessels.Find(v => v.vesselName.Equals(aName)); + Vessel defender = FlightGlobals.Vessels.Find(v => v.vesselName.Equals(tName)); + if (attacker != null && defender != null) + { + StealResource(attacker, defender, "LiquidFuel", fuelRation); + StealResource(attacker, defender, "Oxidizer", fuelRation); + StealResource(attacker, defender, "20x102Ammo", ammoRation); + StealResource(attacker, defender, "30x173Ammo", ammoRation); + StealResource(attacker, defender, "50CalAmmo", ammoRation); + } } } } diff --git a/BDArmory/UI/BDArmorySetup.cs b/BDArmory/UI/BDArmorySetup.cs index 7cfe83710..d6a4c1889 100644 --- a/BDArmory/UI/BDArmorySetup.cs +++ b/BDArmory/UI/BDArmorySetup.cs @@ -1413,6 +1413,15 @@ void WindowSettings(int windowID) BDArmorySettings.MAX_NUM_BULLET_DECALS = (int)GUI.HorizontalSlider(SRightRect(line), BDArmorySettings.MAX_NUM_BULLET_DECALS, 1f, 999); line++; line++; + BDArmorySettings.RESOURCE_STEAL_ENABLED = GUI.Toggle(SLeftRect(line), BDArmorySettings.RESOURCE_STEAL_ENABLED, Localizer.Format("#LOC_BDArmory_Settings_ResourceStealEnabled"));//"Resource Steal Enabled" + line++; + GUI.Label(SLeftRect(line), $"{Localizer.Format("#LOC_BDArmory_Settings_FuelStealRation")}: ({BDArmorySettings.RESOURCE_STEAL_FUEL_RATION})", leftLabel);//Fuel Steal Ration + BDArmorySettings.RESOURCE_STEAL_FUEL_RATION = GUI.HorizontalSlider(SRightRect(line), BDArmorySettings.RESOURCE_STEAL_FUEL_RATION, 0f, 1f); + line++; + GUI.Label(SLeftRect(line), $"{Localizer.Format("#LOC_BDArmory_Settings_AmmoStealRation")}: ({BDArmorySettings.RESOURCE_STEAL_AMMO_RATION})", leftLabel);//Ammo Steal Ration + BDArmorySettings.RESOURCE_STEAL_AMMO_RATION = GUI.HorizontalSlider(SRightRect(line), BDArmorySettings.RESOURCE_STEAL_AMMO_RATION, 0f, 1f); + line++; + line++; bool origPm = BDArmorySettings.PEACE_MODE; BDArmorySettings.PEACE_MODE = GUI.Toggle(SLeftRect(line), BDArmorySettings.PEACE_MODE, Localizer.Format("#LOC_BDArmory_Settings_PeaceMode"));//"Peace Mode"