Пример #1
0
        /// <summary>
        /// Condenses the pickups.
        /// </summary>
        /// <param name="pickups">The pickups to condense down.</param>
        private void CondensePickups(List <Pickup> pickups)
        {
            int    n          = pickups.Count;
            Pickup prevPickup = pickups[0];
            var    tagBits    = new TagBits(ref FetchManager.disallowedTagMask);

            prevPickup.pickupable.KPrefabID.AndTagBits(ref tagBits);
            int hash = prevPickup.tagBitsHash, last = n, next = 0;

            for (int i = 1; i < n; i++)
            {
                bool del        = false;
                var  pickup     = pickups[i];
                var  newTagBits = default(TagBits);
                if (prevPickup.masterPriority == pickup.masterPriority)
                {
                    newTagBits = new TagBits(ref FetchManager.disallowedTagMask);
                    pickup.pickupable.KPrefabID.AndTagBits(ref newTagBits);
                    if (pickup.tagBitsHash == hash && newTagBits.AreEqual(ref tagBits))
                    {
                        // Identical to the previous item
                        del = true;
                    }
                }
                if (del)
                {
                    // Skip
                    last--;
                }
                else
                {
                    // Keep and move down
                    next++;
                    prevPickup = pickup;
                    tagBits    = newTagBits;
                    hash       = pickup.tagBitsHash;
                    if (i > next)
                    {
                        pickups[next] = pickup;
                    }
                }
            }
            pickups.RemoveRange(last, n - last);
        }
        /// <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();
        }
Пример #3
0
        /// <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);
        }