private void UpdateInventoryMargin(IEnumerable <ThingGroupSelector> groupSelectors) { ValidateArg.NotNull(groupSelectors, nameof(groupSelectors)); foreach (ThingGroupSelector groupSelector in groupSelectors) { this.InventoryMargins[groupSelector] = groupSelector.AllowedStackCount * -1; } ConcurrentBag <ThingGroupSelectorPool> pools = new ConcurrentBag <ThingGroupSelectorPool>(); Parallel.ForEach( Partitioner.Create(MakeListForPawnGearAndInventory(_pawn)), (Thing thing) => { ThingGroupSelectorPool pool = this.FindPotentialThingGroupSelectors(thing, groupSelectors); if (pool.OrderedSelectorTuples.Any()) { pools.Add(pool); } }); foreach (ThingGroupSelectorPool pool in pools) { this.Restock(pool); } }
/// <summary> /// Find <see cref="ThingGroupSelector"/> that allows <paramref name="thing"/>. /// </summary> /// <param name="thing"> Thing to check if there is any selector fits. </param> /// <param name="stackCount"> Stack count of <paramref name="thing"/>. </param> /// <param name="groupSelectors"> A list of fiiting selectors. </param> /// <returns> A data packet that contains all information needed to find the best suited selector for <paramref name="thing"/>. </returns> protected virtual ThingGroupSelectorPool FindPotentialThingGroupSelectors(Thing thing, int stackCount, IEnumerable <ThingGroupSelector> groupSelectors) { ValidateArg.NotNull(groupSelectors, nameof(groupSelectors)); ThingGroupSelectorPool pool = new ThingGroupSelectorPool() { Thing = thing, StackCount = stackCount, OrderedSelectorTuples = new List <Tuple <ThingSelector, ThingGroupSelector> >(), }; foreach (ThingGroupSelector groupSelector in groupSelectors) { if (groupSelector.Allows(thing, out ThingSelector thingSelector)) { pool.OrderedSelectorTuples.Add(Tuple.Create(thingSelector, groupSelector)); } } if (pool.OrderedSelectorTuples.Count > 1) { pool.OrderedSelectorTuples = pool.OrderedSelectorTuples.OrderBy(t => t.Item1, ThingSelectorComparer.Instance).ToList(); } return(pool); }
/// <summary> /// Remove thing from <see cref="CompAwesomeInventoryLoadout.InventoryMargins"/>. /// </summary> /// <param name="thing"> Thing to remove. </param> /// <param name="stackCountToDelete"> Stack count to remove. </param> protected virtual void DeleteStock(Thing thing, int stackCountToDelete) { ThingGroupSelectorPool pool = this.FindPotentialThingGroupSelectors(thing, stackCountToDelete, this.InventoryMargins.Keys); foreach (var tuple in pool.OrderedSelectorTuples) { int maxNegativeMargin = tuple.Item2.AllowedStackCount * -1; if (this.InventoryMargins[tuple.Item2] - pool.StackCount < maxNegativeMargin) { pool.StackCount -= this.InventoryMargins[tuple.Item2] - maxNegativeMargin; this.InventoryMargins[tuple.Item2] = maxNegativeMargin; this.UpdateThreshold(new[] { tuple.Item2 }); } else { this.InventoryMargins[tuple.Item2] -= pool.StackCount; this.UpdateThreshold(new[] { tuple.Item2 }); break; } } // Rebalance inventory margin for cases where bottom threshold in ThingGroupSelectors are set to CanRestock in the code above. if (pool.OrderedSelectorTuples.Any(t => t.Item2.UseBottomThreshold && _bottomThresholdLookup[t.Item2].CanRestock)) { this.UpdateInventoryMargin(pool.OrderedSelectorTuples.Select(t => t.Item2)); } }
/// <summary> /// Keep <see cref="CompAwesomeInventoryLoadout.InventoryMargins" /> in sync with pawn's inventory. /// </summary> /// <param name="pool"> A data packet contains all necessary information. </param> protected virtual void Restock(ThingGroupSelectorPool pool) { int restockCount = pool.StackCount; foreach (var tuple in pool.OrderedSelectorTuples) { if (!tuple.Item2.UseBottomThreshold || _bottomThresholdLookup[tuple.Item2].CanRestock) { if (this.InventoryMargins[tuple.Item2] + restockCount <= 0) { this.InventoryMargins[tuple.Item2] += restockCount; if (this.InventoryMargins[tuple.Item2] == 0) { this.UpdateThreshold(new[] { tuple.Item2 }); } restockCount = 0; break; } else { restockCount += this.InventoryMargins[tuple.Item2]; this.InventoryMargins[tuple.Item2] = 0; this.UpdateThreshold(new[] { tuple.Item2 }); } } } if (pool.OrderedSelectorTuples.Any() && restockCount != 0) { this.InventoryMargins[pool.OrderedSelectorTuples.First().Item2] += restockCount; } }
/// <summary> /// Remove thing from <see cref="CompAwesomeInventoryLoadout.InventoryMargins"/>. /// </summary> /// <param name="thing"> Thing to remove. </param> /// <param name="stackCountToDelete"> Stack count to remove. </param> protected virtual void DeleteStock(Thing thing, int stackCountToDelete) { ThingGroupSelectorPool pool = this.FindPotentialThingGroupSelectors(thing, stackCountToDelete, this.InventoryMargins.Keys); foreach (var tuple in pool.OrderedSelectorTuples) { int maxNegativeMargin = tuple.Item2.AllowedStackCount * -1; if (this.InventoryMargins[tuple.Item2] - pool.StackCount < maxNegativeMargin) { pool.StackCount -= this.InventoryMargins[tuple.Item2] - maxNegativeMargin; this.InventoryMargins[tuple.Item2] = maxNegativeMargin; } else { this.InventoryMargins[tuple.Item2] -= pool.StackCount; break; } } }
/// <summary> /// Keep <see cref="CompAwesomeInventoryLoadout.InventoryMargins" /> in sync with pawn's inventory. /// </summary> /// <param name="pool"> A data packet contains all necessary information. </param> protected virtual void Restock(ThingGroupSelectorPool pool) { int restockCount = pool.StackCount; foreach (var tuple in pool.OrderedSelectorTuples) { if (this.InventoryMargins[tuple.Item2] + restockCount <= 0) { this.InventoryMargins[tuple.Item2] += restockCount; restockCount = 0; break; } else { restockCount += this.InventoryMargins[tuple.Item2]; this.InventoryMargins[tuple.Item2] = 0; } } if (pool.OrderedSelectorTuples.Any() && restockCount != 0) { this.InventoryMargins[pool.OrderedSelectorTuples.First().Item2] += restockCount; } }