/// <summary> /// The better and more optimized UpdatePickups. Aggregate runtime on a test world /// dropped from ~60 ms/1000 ms to ~45 ms/1000 ms. /// </summary> private static void UpdatePickups(FetchManager.FetchablesByPrefabId targets, Navigator navigator, GameObject worker) { var canBePickedUp = DictionaryPool <PickupTagKey, FetchManager.Pickup, FetchManager> .Allocate(); var pathCosts = DictionaryPool <int, int, FetchManager> .Allocate(); var finalPickups = targets.finalPickups; // Will reflect the changes from Waste Not, Want Not and No Manual Delivery var comparer = PICKUP_COMPARER.Get(null); foreach (var fetchable in targets.fetchables.GetDataList()) { var target = fetchable.pickupable; int cell = target.cachedCell; if (target.CouldBePickedUpByMinion(worker)) { // Look for cell cost, share costs across multiple queries to a cell if (!pathCosts.TryGetValue(cell, out int cost)) { pathCosts.Add(cell, cost = target.GetNavigationCost(navigator, cell)); } // Exclude unreachable items if (cost >= 0) { int hash = fetchable.tagBitsHash; var key = new PickupTagKey(hash, target.KPrefabID); var candidate = new FetchManager.Pickup { pickupable = target, tagBitsHash = hash, PathCost = (ushort)cost, masterPriority = fetchable.masterPriority, freshness = fetchable. freshness, foodQuality = fetchable.foodQuality }; if (canBePickedUp.TryGetValue(key, out FetchManager.Pickup current)) { // Is the new one better? int result = comparer.Compare(current, candidate); if (result > 0 || (result == 0 && candidate.pickupable. UnreservedAmount > current.pickupable.UnreservedAmount)) { canBePickedUp[key] = candidate; } } else { canBePickedUp.Add(key, candidate); } } } } // Copy the remaining pickups to the list, there are now way fewer because only // one was kept per possible tag bits (with the highest priority, best path cost, // etc) finalPickups.Clear(); foreach (var pair in canBePickedUp) { finalPickups.Add(pair.Value); } pathCosts.Recycle(); canBePickedUp.Recycle(); }
/// <summary> /// Applied before UpdatePickups runs. A more optimized UpdatePickups whose aggregate /// runtime on a test world dropped from ~60 ms/1000 ms to ~45 ms/1000 ms. /// </summary> internal static bool BeforeUpdatePickups(FetchManager.FetchablesByPrefabId __instance, Navigator worker_navigator, GameObject worker_go) { var canBePickedUp = Allocate(); var pathCosts = DictionaryPool <int, int, FetchManager> .Allocate(); var finalPickups = __instance.finalPickups; // Will reflect the changes from Waste Not, Want Not and No Manual Delivery var comparer = FetchManager.ComparerIncludingPriority; bool needThreadSafe = FastTrackOptions.Instance.PickupOpts; var fetchables = __instance.fetchables.GetDataList(); int n = fetchables.Count; for (int i = 0; i < n; i++) { var fetchable = fetchables[i]; var target = fetchable.pickupable; int cell = target.cachedCell; if (target.CouldBePickedUpByMinion(worker_go)) { // Look for cell cost, share costs across multiple queries to a cell // If this is being run synchronous, no issue, otherwise the GSP patch will // avoid races on the scene partitioner if (!pathCosts.TryGetValue(cell, out int cost)) { if (needThreadSafe) { worker_navigator.GetNavigationCostNU(target, cell, out cost); } else { cost = worker_navigator.GetNavigationCost(target); } pathCosts.Add(cell, cost); } // Exclude unreachable items if (cost >= 0) { int hash = fetchable.tagBitsHash; var key = new PickupTagKey(hash, target.KPrefabID); var candidate = new FetchManager.Pickup { pickupable = target, tagBitsHash = hash, PathCost = (ushort)cost, masterPriority = fetchable.masterPriority, freshness = fetchable. freshness, foodQuality = fetchable.foodQuality }; if (canBePickedUp.TryGetValue(key, out FetchManager.Pickup current)) { // Is the new one better? int result = comparer.Compare(candidate, current); if (result < 0 || (result == 0 && candidate.pickupable. UnreservedAmount > current.pickupable.UnreservedAmount)) { canBePickedUp[key] = candidate; } } else { canBePickedUp.Add(key, candidate); } } } } // Copy the remaining pickups to the list, there are now way fewer because only // one was kept per possible tag bits (with the highest priority, best path cost, // etc) finalPickups.Clear(); foreach (var pickup in canBePickedUp.Values) { finalPickups.Add(pickup); } pathCosts.Recycle(); Recycle(canBePickedUp); // Prevent the original method from running return(false); }