Esempio n. 1
0
        /// <summary>
        /// Updates the available pickups.
        /// </summary>
        /// <param name="fetch">The fetchables to update.</param>
        /// <param name="fetcher">The Duplicant gathering the items.</param>
        /// <param name="navigator">The navigator for that Duplicant.</param>
        /// <param name="cellCosts">A location to store the cell costs.</param>
        internal void UpdatePickups(FetchablesByPrefabId fetch, Navigator navigator,
                                    GameObject fetcher, IDictionary <int, int> cellCosts)
        {
            var pickups = fetch.finalPickups;

            if (pickups != null)
            {
                if (!outstanding.TryGetValue(fetch.prefabId, out FetchData data))
                {
                    data = null;
                }
                pickups.Clear();
                GetFetchList(fetch, navigator, fetcher, cellCosts);
                if (pickups.Count > 1)
                {
                    if (data != null)
                    {
                        pickups.Sort(data);
                    }
                    else
                    {
                        pickups.Sort(FetchData.Default);
                    }
                    // Condense down using the stock game logic
                    CondensePickups(pickups);
                }
                if (data != null)
                {
                    data.NeedsScan = false;
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Gets the list of fetchable pickups.
        /// </summary>
        /// <param name="fetch">The fetchables to update.</param>
        /// <param name="fetcher">The Duplicant gathering the items.</param>
        /// <param name="navigator">The navigator for that Duplicant.</param>
        /// <param name="cellCosts">A location to store the cell costs.</param>
        private void GetFetchList(FetchablesByPrefabId fetch, Navigator navigator,
                                  GameObject fetcher, IDictionary <int, int> cellCosts)
        {
            cellCosts.Clear();
            var pickups = fetch.finalPickups;

            foreach (var fetchable in fetch.fetchables.GetDataList())
            {
                var pickupable = fetchable.pickupable;
                if (pickupable.CouldBePickedUpByMinion(fetcher))
                {
                    // Optimize if many pickupables are in the same cell
                    int cell = pickupable.cachedCell;
                    if (!cellCosts.TryGetValue(cell, out int cost))
                    {
                        cost = pickupable.GetNavigationCost(navigator, cell);
                        cellCosts.Add(cell, cost);
                    }
                    if (cost >= 0)
                    {
                        // This pickup is reachable
                        pickups.Add(new Pickup {
                            pickupable     = pickupable,
                            tagBitsHash    = fetchable.tagBitsHash,
                            PathCost       = (ushort)Math.Min(cost, ushort.MaxValue),
                            masterPriority = fetchable.masterPriority,
                            freshness      = fetchable.freshness,
                            foodQuality    = fetchable.foodQuality
                        });
                    }
                }
            }
        }
 /// <summary>
 /// Applied before UpdatePickups runs.
 /// </summary>
 internal static bool Prefix(FetchManager.FetchablesByPrefabId __instance,
                             Navigator worker_navigator, GameObject worker_go)
 {
     UpdatePickups(__instance, worker_navigator, worker_go);
     // Prevent the original method from running
     return(false);
 }
Esempio n. 4
0
            /// <summary>
            /// Applied before UpdatePickups runs.
            /// </summary>
            internal static bool Prefix(FetchManager.FetchablesByPrefabId __instance,
                                        Navigator worker_navigator, GameObject worker_go,
                                        Dictionary <int, int> ___cellCosts)
            {
                var  inst = EfficientFetchManager.Instance;
                bool cont = true;

                if (inst != null && options.MinimumAmountPercent > 0)
                {
                    try {
                        inst.UpdatePickups(__instance, worker_navigator, worker_go,
                                           ___cellCosts);
                        cont = false;
                    } catch (Exception e) {
                        // Crashing will bring down simdll with no stack trace
                        PUtil.LogException(e);
                    }
                }
                return(cont);
            }
        /// <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);
        }