using GameKit.Dependencies.Utilities.Types; using System.Collections.Generic; using UnityEngine; namespace GameKit.Dependencies.Utilities { public interface IWeighted { float GetWeight(); ByteRange GetQuantity(); } public static class WeightedRandom { /// /// Gets random entries by weight. /// /// Entries to pull from. /// Number of entries to get. /// Results of entries. Key is the entry, Value is the number of drops. /// True to allow the same entry to be included within results more than once. public static void GetEntries(List source, IntRange countRange, ref Dictionary results, bool allowRepeatingDrops = false) where T : IWeighted { if (source == null || source.Count == 0) { Debug.Log($"Source list of type {typeof(T).Name} cannot be null or empty."); return; } int count = Ints.RandomInclusiveRange(countRange.Minimum, countRange.Maximum); //If to not return any then exit early. if (count == 0) return; //Number of times each item has dropped. Dictionary dropCount = CollectionCaches.RetrieveDictionary(); //Get the total weight. float totalWeight = 0f; for (int i = 0; i < source.Count; i++) totalWeight += source[i].GetWeight(); //Make a copy of source to not modify source. List sourceCopy = CollectionCaches.RetrieveList(); foreach (T item in source) sourceCopy.Add(item); while (results.Count < count) { int startCount = results.Count; /* Reset copy to totalWeight. * totalWeight will be modified if * a non-repeatable item is pulled. */ float tWeightCopy = totalWeight; float rnd = UnityEngine.Random.Range(0f, totalWeight); for (int i = 0; i < sourceCopy.Count; i++) { T item = sourceCopy[i]; float weight = item.GetWeight(); if (rnd <= weight) { //Try to get current count. results.TryGetValueIL2CPP(item, out uint currentCount); //Set new vlaue. results[item] = (currentCount + 1); /* If cannot stay in collection then remove it * from copy and remove its weight * from total. */ if (!allowRepeatingDrops) { sourceCopy.RemoveAt(i); totalWeight -= weight; } break; } else { tWeightCopy -= weight; } } /* If nothing was added to results then * something went wrong. */ if (results.Count == startCount) break; } CollectionCaches.Store(dropCount); } } }