From c9a70d7e63ad0165ff8cdffc5ba7b63fc926b858 Mon Sep 17 00:00:00 2001 From: Stepan Goremykin Date: Sun, 29 Jan 2023 14:49:27 +0100 Subject: [PATCH] Introduce PickRandom and TryPickRandom extensions --- .../Core/Extensions/EnumerableExtensions.cs | 113 ++++++++++-------- .../Core/Helpers/Math/RandomHelper.cs | 39 ++++-- src/DiIiS-NA/Core/MPQ/FileFormats/AnimSet.cs | 3 +- .../GSSystem/AISystem/Brains/MinionBrain.cs | 9 +- .../GSSystem/AISystem/Brains/MonsterBrain.cs | 10 +- .../GeneratorsSystem/MonsterAffixGenerator.cs | 9 +- .../GeneratorsSystem/WorldGenerator.cs | 11 +- .../Implementations/HeroSkills/Necromancer.cs | 7 +- 8 files changed, 111 insertions(+), 90 deletions(-) diff --git a/src/DiIiS-NA/Core/Extensions/EnumerableExtensions.cs b/src/DiIiS-NA/Core/Extensions/EnumerableExtensions.cs index e2d1a56..db22845 100644 --- a/src/DiIiS-NA/Core/Extensions/EnumerableExtensions.cs +++ b/src/DiIiS-NA/Core/Extensions/EnumerableExtensions.cs @@ -1,61 +1,70 @@ -//Blizzless Project 2022 -using System; +using System; using System.Collections.Generic; using System.Text; using System.Linq; +using DiIiS_NA.Core.Helpers.Math; -namespace DiIiS_NA.Core.Extensions +namespace DiIiS_NA.Core.Extensions; + +public static class EnumerableExtensions { - public static class EnumerableExtensions + public static string HexDump(this IEnumerable collection) { - public static string HexDump(this IEnumerable collection) + var sb = new StringBuilder(); + foreach (byte value in collection) { - var sb = new StringBuilder(); - foreach (byte value in collection) - { - sb.Append(value.ToString("X2")); - sb.Append(' '); - } - if (sb.Length > 0) - sb.Remove(sb.Length - 1, 1); - return sb.ToString(); - } - - public static string ToEncodedString(this IEnumerable collection, Encoding encoding) - { - return encoding.GetString(collection.ToArray()); - } - - public static string Dump(this IEnumerable collection) - { - var output = new StringBuilder(); - var hex = new StringBuilder(); - var text = new StringBuilder(); - int i = 0; - foreach (byte value in collection) - { - if (i > 0 && ((i % 16) == 0)) - { - output.Append(hex); - output.Append(' '); - output.Append(text); - output.Append(Environment.NewLine); - hex.Clear(); text.Clear(); - } - hex.Append(value.ToString("X2")); - hex.Append(' '); - text.Append(string.Format("{0}", (char.IsWhiteSpace((char)value) && (char)value != ' ') ? '.' : (char)value)); // prettify text - ++i; - } - var hexstring = hex.ToString(); - if (text.Length < 16) - { - hexstring = hexstring.PadRight(48); // pad the hex representation in-case it's smaller than a regular 16 value line. - } - output.Append(hexstring); - output.Append(' '); - output.Append(text); - return output.ToString(); + sb.Append(value.ToString("X2")); + sb.Append(' '); } + if (sb.Length > 0) + sb.Remove(sb.Length - 1, 1); + return sb.ToString(); } -} + + public static string ToEncodedString(this IEnumerable collection, Encoding encoding) + { + return encoding.GetString(collection.ToArray()); + } + + public static string Dump(this IEnumerable collection) + { + var output = new StringBuilder(); + var hex = new StringBuilder(); + var text = new StringBuilder(); + int i = 0; + foreach (byte value in collection) + { + if (i > 0 && ((i % 16) == 0)) + { + output.Append(hex); + output.Append(' '); + output.Append(text); + output.Append(Environment.NewLine); + hex.Clear(); text.Clear(); + } + hex.Append(value.ToString("X2")); + hex.Append(' '); + text.Append($"{((char.IsWhiteSpace((char)value) && (char)value != ' ') ? '.' : (char)value)}"); // prettify text + ++i; + } + var hexstring = hex.ToString(); + if (text.Length < 16) + { + hexstring = hexstring.PadRight(48); // pad the hex representation in-case it's smaller than a regular 16 value line. + } + output.Append(hexstring); + output.Append(' '); + output.Append(text); + return output.ToString(); + } + + public static TItem PickRandom(this IEnumerable source) + { + return RandomHelper.RandomItem(source); + } + + public static bool TryPickRandom(this IEnumerable source, out TItem randomItem) + { + return RandomHelper.TryGetRandomItem(source, out randomItem); + } +} \ No newline at end of file diff --git a/src/DiIiS-NA/Core/Helpers/Math/RandomHelper.cs b/src/DiIiS-NA/Core/Helpers/Math/RandomHelper.cs index 64a20a7..657c971 100644 --- a/src/DiIiS-NA/Core/Helpers/Math/RandomHelper.cs +++ b/src/DiIiS-NA/Core/Helpers/Math/RandomHelper.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using System.Collections.Generic; -using DiIiS_NA.Core.Logging; namespace DiIiS_NA.Core.Helpers.Math; @@ -45,6 +44,26 @@ public static class RandomHelper var randomIndex = Next(collection.Count); return collection.ElementAt(randomIndex); } + + public static bool TryGetRandomItem(IEnumerable source, out T randomItem) + { + var collection = source as IReadOnlyCollection ?? source?.ToArray(); + if (collection == null) + { + throw new ArgumentException("Cannot be null", nameof(source)); + } + + if (collection.Count == 0) + { + randomItem = default; + return false; + } + + var randomIndex = Next(collection.Count); + randomItem = collection.ElementAt(randomIndex); + + return true; + } /// /// Picks a random item from a list @@ -74,26 +93,26 @@ public static class RandomHelper public class ItemRandomHelper { - uint a; - uint b; + uint _a; + uint _b; public ItemRandomHelper(int seed) { - a = (uint)seed; - b = 666; + _a = (uint)seed; + _b = 666; } public void ReinitSeed() { - b = 666; + _b = 666; } public uint Next() { - ulong temp = 1791398085UL * a + b; - a = (uint)temp; - b = (uint)(temp >> 32); + ulong temp = 1791398085UL * _a + _b; + _a = (uint)temp; + _b = (uint)(temp >> 32); - return a; + return _a; } public float Next(float min, float max) diff --git a/src/DiIiS-NA/Core/MPQ/FileFormats/AnimSet.cs b/src/DiIiS-NA/Core/MPQ/FileFormats/AnimSet.cs index a068ef4..1927476 100644 --- a/src/DiIiS-NA/Core/MPQ/FileFormats/AnimSet.cs +++ b/src/DiIiS-NA/Core/MPQ/FileFormats/AnimSet.cs @@ -7,6 +7,7 @@ using DiIiS_NA.Core.MPQ.FileFormats.Types; using DiIiS_NA.GameServer.Core.Types.TagMap; using System.Linq; using System; +using DiIiS_NA.Core.Extensions; using DiIiS_NA.Core.Helpers.Math; using DiIiS_NA.D3_GameServer.Core.Types.SNO; @@ -104,7 +105,7 @@ namespace DiIiS_NA.Core.MPQ.FileFormats } var possibleDeaths = deathTags.Select(GetAniSNO).Where(x => x != AnimationSno._NONE); - return RandomHelper.RandomItem(possibleDeaths); + return possibleDeaths.PickRandom(); } } public enum AnimationTags diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brains/MinionBrain.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brains/MinionBrain.cs index 64748a4..b474f2e 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brains/MinionBrain.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brains/MinionBrain.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using DiIiS_NA.Core.Extensions; using DiIiS_NA.Core.Helpers.Math; using DiIiS_NA.Core.MPQ; using DiIiS_NA.D3_GameServer.Core.Types.SNO; @@ -196,12 +197,12 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains // randomly used an implemented power if (PresetPowers.Count > 0) { - //int power = this.PresetPowers[RandomHelper.Next(this.PresetPowers.Count)].Key; + // int power = this.PresetPowers[RandomHelper.Next(this.PresetPowers.Count)].Key; List availablePowers = PresetPowers.Where(p => (p.Value.CooldownTimer == null || p.Value.CooldownTimer.TimedOut) && PowerLoader.HasImplementationForPowerSNO(p.Key)).Select(p => p.Key).ToList(); - if (availablePowers.Any(p => p != 30592)) - return availablePowers.Where(p => p != 30592).ToList()[RandomHelper.Next(availablePowers.Count(p => p != 30592))]; + if (availablePowers.Where(p => p != 30592).TryPickRandom(out var randomItem)) + return randomItem; if (availablePowers.Contains(30592)) - return 30592; //melee attack + return 30592; // melee attack } // no usable power diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brains/MonsterBrain.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brains/MonsterBrain.cs index 11c521a..0821a3f 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brains/MonsterBrain.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brains/MonsterBrain.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using DiIiS_NA.Core.Extensions; using DiIiS_NA.Core.Helpers.Math; using DiIiS_NA.Core.Logging; using DiIiS_NA.Core.MPQ; @@ -435,16 +436,13 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains //int power = this.PresetPowers[RandomHelper.Next(this.PresetPowers.Count)].Key; var availablePowers = PresetPowers.Where(p => (p.Value.CooldownTimer == null || p.Value.CooldownTimer.TimedOut) && PowerLoader.HasImplementationForPowerSNO(p.Key)).Select(p => p.Key).ToList(); - if (availablePowers.Count(p => p != 30592) > 0) + if (availablePowers.Where(p => p != 30592).TryPickRandom(out var selectedPower)) { - int SelectedPower = availablePowers.Where(p => p != 30592).ToList()[RandomHelper.Next(availablePowers.Count(p => p != 30592))]; - //if(SelectedPower == 73824) - //if(SkeletonKingWhirlwind) - return SelectedPower; + return selectedPower; } if (availablePowers.Contains(30592)) - return 30592; //melee attack + return 30592; // melee attack // no usable power return -1; diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/GeneratorsSystem/MonsterAffixGenerator.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/GeneratorsSystem/MonsterAffixGenerator.cs index cc56144..f0791b1 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/GeneratorsSystem/MonsterAffixGenerator.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/GeneratorsSystem/MonsterAffixGenerator.cs @@ -1,6 +1,7 @@ using DiIiS_NA.Core.Logging; using System.Collections.Generic; using System.Linq; +using DiIiS_NA.Core.Extensions; using DiIiS_NA.GameServer.GSSystem.AISystem.Brains; using static DiIiS_NA.Core.MPQ.FileFormats.GameBalance; using Actor = DiIiS_NA.GameServer.GSSystem.ActorSystem.Actor; @@ -250,17 +251,13 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem public static int GeneratePrefixName() { - var prefixes = NamesList.Where(n => n.AffixType == AffixType.Prefix); - var randomPrefix = RandomHelper.RandomItem(prefixes); - + var randomPrefix = NamesList.Where(n => n.AffixType == AffixType.Prefix).PickRandom(); return randomPrefix.Hash; } public static int GenerateSuffixName() { - var prefixes = NamesList.Where(n => n.AffixType == AffixType.Suffix); - var randomPrefix = RandomHelper.RandomItem(prefixes); - + var randomPrefix = NamesList.Where(n => n.AffixType == AffixType.Suffix).PickRandom(); return randomPrefix.Hash; } } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/GeneratorsSystem/WorldGenerator.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/GeneratorsSystem/WorldGenerator.cs index 2718523..be017f9 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/GeneratorsSystem/WorldGenerator.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/GeneratorsSystem/WorldGenerator.cs @@ -302,11 +302,8 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem else { var entries = clusterSelected[sceneChunk.SceneSpecification.ClusterID]; - SubSceneEntry subSceneEntry = null; - - if (entries.Count > 0) + if (entries.TryPickRandom(out var subSceneEntry)) { - subSceneEntry = RandomHelper.RandomItem(entries); entries.Remove(subSceneEntry); } else @@ -1975,7 +1972,7 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem for (int i = 0; i < count; i++) { //Chose a random exit to test - Vector3D chosenExitPosition = RandomHelper.RandomItem(exitTypes).Value; + Vector3D chosenExitPosition = exitTypes.PickRandom().Value; var chosenExitDirection = (from pair in exitTypes where pair.Value == chosenExitPosition select pair.Key).FirstOrDefault(); @@ -2087,7 +2084,7 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem return null; } - return RandomHelper.RandomItem(tilesWithRightDirection); + return tilesWithRightDirection.PickRandom(); } private TileInfo GetTile(Dictionary tiles, int snoId) @@ -2105,7 +2102,7 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem private TileInfo GetTileInfo(Dictionary tiles, TileTypes tileType) { var tilesWithRightType = tiles.Values.Where(tile => tile.TileType == (int)tileType); - return RandomHelper.RandomItem(tilesWithRightType); + return tilesWithRightType.PickRandom(); } private TileInfo GetTileInfo(Dictionary tiles, TileTypes tileType, int exitDirectionBits) diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/HeroSkills/Necromancer.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/HeroSkills/Necromancer.cs index 3f203e1..f370d57 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/HeroSkills/Necromancer.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/HeroSkills/Necromancer.cs @@ -17,6 +17,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using DiIiS_NA.Core.Extensions; namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations { @@ -3300,10 +3301,8 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations Remove(); var newms = payload.Target.GetMonstersInRange(40f); - - if (newms.Count > 0) + if (newms.TryPickRandom(out var target)) { - var target = RandomHelper.RandomItem(newms); AddBuff(target, new Rune_B_Buff()); } } @@ -4497,7 +4496,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations { Founded = true; var possibleTargets = projectile.GetMonstersInRange(25f); - var target = RandomHelper.RandomItem(possibleTargets); + var target = possibleTargets.PickRandom(); projectile.Launch(target.Position, 1f); } };