using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using Battle; using Battle.Attacks; using Battle.Attacks.AttackBehaviours; using Battle.Pachinko.BallBehaviours; using Battle.PegBehaviour; using Battle.StatusEffects; using BepInEx; using HarmonyLib; using IL.Battle; using IL.Battle.Attacks; using IL.Battle.Attacks.AttackBehaviours; using IL.Battle.Pachinko.BallBehaviours; using IL.Battle.StatusEffects; using IL.Relics; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using Mono.Cecil.Cil; using MonoMod.Cil; using On; using On.Battle; using On.Battle.PegBehaviour; using PeglinUtils; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("PeglinRNGSeeding")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Seeds some of the game RNG")] [assembly: AssemblyFileVersion("0.0.11.0")] [assembly: AssemblyInformationalVersion("0.0.11+1cb2ad99f58908793c1ee1858a852063483b30b2")] [assembly: AssemblyProduct("PeglinRNGSeeding")] [assembly: AssemblyTitle("PeglinRNGSeeding")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.11.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace PeglinRNGSeeding { public enum LogLevel { Off, On, Debug, Trace } [BepInPlugin("PeglinRNGSeeding", "PeglinRNGSeeding", "0.0.11")] public class Plugin : BaseUnityPlugin { private void Awake() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin PeglinRNGSeeding is loaded!"); try { ((Component)this).gameObject.AddComponent(); RngSeeding.LogLevel = ((BaseUnityPlugin)this).Config.Bind("General", "Log Level", LogLevel.On, "Controls the amount of info that should be printed to the console").Value; RngSeeding.SeedAllShuffles = ((BaseUnityPlugin)this).Config.Bind("General", "Seed Random Shuffles", true, "Seed all randomized shuffling. Slightly experimental").Value; } catch (Exception arg) { Debug.LogWarning((object)$"Couldn't read config file: {arg}"); } } } public class RngSeeding : MonoBehaviour { [HarmonyPatch] private class PatchShuffle { [HarmonyTargetMethod] [UsedImplicitly] private static MethodBase TargetMethod() { return typeof(ListExtensions).GetMethod("Shuffle")?.MakeGenericMethod(typeof(object)); } [UsedImplicitly] private static bool Prefix(IList list) { if (!SeedAllShuffles) { Log(LogLevel.Debug, "Shuffle seeding disabled"); return true; } Log(LogLevel.Trace, "Shuffling List Before: " + string.Join(", ", list)); Log($"Shuffling list of type: {list.GetType()}"); int num = list.Count; while (num > 1) { num--; int index = _shuffleRng?.Next(0, num + 1) ?? Random.Range(0, num + 1); int index2 = num; object value = list[num]; object value2 = list[index]; list[index] = value; list[index2] = value2; } Log(LogLevel.Trace, "Shuffling List After: " + string.Join(", ", list)); return false; } } private Random _specialPegRng; private Dictionary _specialPegRngs = new Dictionary(); private Random _deckOrderRng; private Random _roundrelStatusRng; private Random _roundrelStatusDebug; private Random _critStatusRng; private Random _primeSlimeRng; private Random _potionBalltRng; private Random _refresherCourseRng; private Random _specialSlotRng; private Random _dungeonDieRng; private Random _randomPegFieldRng; private static Random _shuffleRng; private Harmony _harmony; public static LogLevel LogLevel { get; set; } public static bool SeedAllShuffles { get; set; } public void Awake() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown _harmony = new Harmony("PeglinRNGSeeding"); _harmony.PatchAll(); BattleController.Start += new hook_Start(BattleControllerOnStart); DeckManager.ShuffleCompleteDeck += new hook_ShuffleCompleteDeck(DeckManagerOnShuffleCompleteDeck); PegManager.CreateSpecialPeg += new Manipulator(PegManagerOnCreateSpecialPeg); AddRandomStatusEffectOnHit.AffectEnemy += new Manipulator(AddRandomStatusEffectOnHitOnAffectEnemy); TargetingManager.OnCritActivated += new Manipulator(TargetingManagerOnOnCritActivated); RelicManager.GetRandomPrimeSlimeType += new Manipulator(RelicManagerOnGetRandomPrimeSlimeType); MultiballPrefabOverridePool.GetMultiballGameobject += new Manipulator(MultiballPrefabOverridePoolOnGetMultiballGameobject); PlayerStatusEffectController.CheckRefreshEffects += new Manipulator(PlayerStatusEffectControllerOnCheckRefreshEffects); SpecialSlotController.TurnComplete += new hook_TurnComplete(SpecialSlotControllerTurnComplete); Attack.SetRandomRolledDamage += new Manipulator(AttackOnSetRandomRolledDamage); RandomPegField.CreatePegs += new hook_CreatePegs(RandomPegFieldOnCreatePegs); } private void PegManagerOnCreateSpecialPeg(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_00e1: Unknown result type (might be due to invalid IL or missing references) ILCursor val = new ILCursor(il); if (!val.TryGotoNext((MoveType)0, new Func[5] { (Instruction i) => ILPatternMatchingExt.MatchLdarg(i, 2), (Instruction i) => ILPatternMatchingExt.MatchLdcI4(i, 0), (Instruction i) => ILPatternMatchingExt.MatchLdarg(i, 2), (Instruction i) => ILPatternMatchingExt.MatchCallvirt(i, (MethodBase)(typeof(List).GetProperty("Count")?.GetMethod)), (Instruction i) => ILPatternMatchingExt.MatchCall(i, (MethodBase)typeof(Random).GetMethod("Range", new Type[2] { typeof(int), typeof(int) })) })) { Debug.LogWarning((object)"Failed to match special peg IL"); return; } val.Index += 4; val.Remove(); val.Emit(OpCodes.Ldarg_1); val.EmitDelegate>((Func)delegate(int a, int b, PegType pegType) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) Log($"Creating special peg of type: {pegType}"); if (!_specialPegRngs.TryGetValue(pegType, out var value)) { Log(LogLevel.Debug, $"Instantiating RNG for type: {pegType} in this battle"); value = new Random(_specialPegRng.Next()); _specialPegRngs[pegType] = value; } else { Log(LogLevel.Debug, $"Found existing RNG for type: {pegType}"); } int num = value.Next(a, b); Log(LogLevel.Debug, $"Next {pegType} peg index: {num}"); return num; }); } public void OnDestroy() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown BattleController.Start -= new hook_Start(BattleControllerOnStart); DeckManager.ShuffleCompleteDeck -= new hook_ShuffleCompleteDeck(DeckManagerOnShuffleCompleteDeck); PegManager.CreateSpecialPeg -= new Manipulator(PegManagerOnCreateSpecialPeg); AddRandomStatusEffectOnHit.AffectEnemy -= new Manipulator(AddRandomStatusEffectOnHitOnAffectEnemy); TargetingManager.OnCritActivated -= new Manipulator(TargetingManagerOnOnCritActivated); RelicManager.GetRandomPrimeSlimeType -= new Manipulator(RelicManagerOnGetRandomPrimeSlimeType); MultiballPrefabOverridePool.GetMultiballGameobject -= new Manipulator(MultiballPrefabOverridePoolOnGetMultiballGameobject); PlayerStatusEffectController.CheckRefreshEffects -= new Manipulator(PlayerStatusEffectControllerOnCheckRefreshEffects); SpecialSlotController.TurnComplete -= new hook_TurnComplete(SpecialSlotControllerTurnComplete); Attack.SetRandomRolledDamage -= new Manipulator(AttackOnSetRandomRolledDamage); RandomPegField.CreatePegs -= new hook_CreatePegs(RandomPegFieldOnCreatePegs); } private void RandomPegFieldOnCreatePegs(orig_CreatePegs orig, RandomPegField self) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (_randomPegFieldRng == null) { orig.Invoke(self); return; } State state = Random.state; Random.InitState(_randomPegFieldRng.Next()); orig.Invoke(self); Random.state = state; } private void AddRandomStatusEffectOnHitOnAffectEnemy(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ILCursor val = new ILCursor(il); if (!val.TryGotoNext((MoveType)0, new Func[5] { (Instruction i) => ILPatternMatchingExt.MatchLdcI4(i, 0), (Instruction i) => ILPatternMatchingExt.MatchLdsfld(i, "RoundreloquencePotentialEffects"), (Instruction i) => ILPatternMatchingExt.MatchLdlen(i), (Instruction i) => ILPatternMatchingExt.MatchConvI4(i), (Instruction i) => ILPatternMatchingExt.MatchCall(i, (MethodBase)typeof(Random).GetMethod("Range", new Type[2] { typeof(int), typeof(int) })) })) { Debug.LogWarning((object)"Failed to match call for status on hit"); return; } val.Index += 4; val.Remove(); val.EmitDelegate>((Func)delegate(int a, int b) { _roundrelStatusDebug.Next(a, b); int num = _roundrelStatusDebug.Next(a, b); int num2 = _roundrelStatusRng.Next(a, b); StatusEffectType[] roundreloquencePotentialEffects = AddRandomStatusEffectOnHit.RoundreloquencePotentialEffects; Log($"Applying status effect: {roundreloquencePotentialEffects[num2]}"); Log(LogLevel.Trace, $"Upcoming status effect is: {roundreloquencePotentialEffects[num]}"); return num2; }); } private IEnumerator BattleControllerOnStart(orig_Start orig, BattleController self) { int num = SeedUtils.ConvertSeedFromSymbolsToInt(StaticGameData.currentSeed) - StaticGameData.totalFloorCount; Random random = new Random(num); Log($"Setting up battle RNG with seed: {num}"); _deckOrderRng = new Random(random.Next()); _specialPegRng = new Random(random.Next()); int seed = random.Next(); _roundrelStatusRng = new Random(seed); _roundrelStatusDebug = new Random(seed); _critStatusRng = new Random(random.Next()); _primeSlimeRng = new Random(random.Next()); _potionBalltRng = new Random(random.Next()); _refresherCourseRng = new Random(random.Next()); _specialSlotRng = new Random(random.Next()); _dungeonDieRng = new Random(random.Next()); _randomPegFieldRng = new Random(random.Next()); _shuffleRng = new Random(random.Next()); _specialPegRngs = new Dictionary(); return orig.Invoke(self); } private void DeckManagerOnShuffleCompleteDeck(orig_ShuffleCompleteDeck orig, DeckManager self, bool fromcomplete) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) State state = Random.state; int num = _deckOrderRng.Next(); Log($"Shuffling deck with random state seed: {num}"); Random.InitState(num); orig.Invoke(self, fromcomplete); Random.state = state; } private void TargetingManagerOnOnCritActivated(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ILCursor val = new ILCursor(il); if (!val.TryGotoNext((MoveType)0, new Func[5] { (Instruction i) => ILPatternMatchingExt.MatchLdcI4(i, 0), (Instruction i) => ILPatternMatchingExt.MatchLdsfld(i, "RoundreloquencePotentialEffects"), (Instruction i) => ILPatternMatchingExt.MatchLdlen(i), (Instruction i) => ILPatternMatchingExt.MatchConvI4(i), (Instruction i) => ILPatternMatchingExt.MatchCall(i, (MethodBase)typeof(Random).GetMethod("Range", new Type[2] { typeof(int), typeof(int) })) })) { Debug.LogWarning((object)"Failed to match call for status on crit"); return; } val.Index += 4; val.Remove(); val.EmitDelegate>((Func)delegate(int a, int b) { int num = _critStatusRng.Next(a, b); Log($"Applying crit status effect: {AddRandomStatusEffectOnHit.RoundreloquencePotentialEffects[num]}"); return num; }); } private void RelicManagerOnGetRandomPrimeSlimeType(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_00e1: Unknown result type (might be due to invalid IL or missing references) ILCursor val = new ILCursor(il); if (!val.TryGotoNext((MoveType)0, new Func[5] { (Instruction i) => ILPatternMatchingExt.MatchLdloc(i, 0), (Instruction i) => ILPatternMatchingExt.MatchLdcI4(i, 0), (Instruction i) => ILPatternMatchingExt.MatchLdloc(i, 0), (Instruction i) => ILPatternMatchingExt.MatchCallvirt(i, (MethodBase)(typeof(List).GetProperty("Count")?.GetMethod)), (Instruction i) => ILPatternMatchingExt.MatchCall(i, (MethodBase)typeof(Random).GetMethod("Range", new Type[2] { typeof(int), typeof(int) })) })) { Debug.LogWarning((object)"Failed to match call for prime slime"); return; } val.Index += 4; val.Remove(); val.Emit(OpCodes.Ldloc_0); val.EmitDelegate, int>>((Func, int>)delegate(int a, int b, List slimeTypes) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) int num = _primeSlimeRng.Next(a, b); Log($"Applying prime slime: {slimeTypes[num]}"); return num; }); } private void MultiballPrefabOverridePoolOnGetMultiballGameobject(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) ILCursor val = new ILCursor(il); if (!val.TryGotoNext((MoveType)0, new Func[8] { (Instruction i) => ILPatternMatchingExt.MatchLdarg(i, 0), (Instruction i) => ILPatternMatchingExt.MatchLdfld(i, "multiballOverridePool"), (Instruction i) => ILPatternMatchingExt.MatchLdcI4(i, 0), (Instruction i) => ILPatternMatchingExt.MatchLdarg(i, 0), (Instruction i) => ILPatternMatchingExt.MatchLdfld(i, "multiballOverridePool"), (Instruction i) => ILPatternMatchingExt.MatchLdlen(i), (Instruction i) => ILPatternMatchingExt.MatchConvI4(i), (Instruction i) => ILPatternMatchingExt.MatchCall(i, (MethodBase)typeof(Random).GetMethod("Range", new Type[2] { typeof(int), typeof(int) })) })) { Debug.LogWarning((object)"Failed to match call for potion ballt"); return; } val.Index += 7; val.Remove(); FieldInfo field = typeof(MultiballPrefabOverridePool).GetField("multiballOverridePool", BindingFlags.Instance | BindingFlags.NonPublic); val.Emit(OpCodes.Ldarg_0); val.Emit(OpCodes.Ldfld, field); val.EmitDelegate>((Func)delegate(int a, int b, GameObject[] slimeTypes) { if (_potionBalltRng == null) { return Random.Range(a, b); } int num = _potionBalltRng.Next(a, b); Log($"Next slime ball is: {slimeTypes[num]}"); return num; }); } private void PlayerStatusEffectControllerOnCheckRefreshEffects(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ILCursor val = new ILCursor(il); if (!val.TryGotoNext((MoveType)0, new Func[2] { (Instruction i) => ILPatternMatchingExt.MatchCall(i, (MethodBase)(typeof(Random).GetProperty("value")?.GetMethod)), (Instruction i) => ILPatternMatchingExt.MatchLdcR4(i, 0.5f) })) { Debug.LogWarning((object)"Failed to match call for player status effect"); return; } val.Remove(); val.EmitDelegate>((Func)delegate { float num = (float)_refresherCourseRng.NextDouble(); Log(((double)num < 0.5) ? "refresher course adding muscircle" : "refresher course adding spinesse"); return num; }); } private void SpecialSlotControllerTurnComplete(orig_TurnComplete orig, SpecialSlotController self) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) State state = Random.state; Random.InitState(_specialSlotRng.Next()); orig.Invoke(self); Random.state = state; } private void AttackOnSetRandomRolledDamage(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ILCursor val = new ILCursor(il); if (!val.TryGotoNext((MoveType)0, new Func[2] { (Instruction i) => ILPatternMatchingExt.MatchCall(i, (MethodBase)typeof(Random).GetMethod("Range", new Type[2] { typeof(int), typeof(int) })), (Instruction i) => ILPatternMatchingExt.MatchStfld(i, "_randomDmgMod") })) { Debug.LogWarning((object)"Failed to match call for dungeon die base damage"); return; } val.Remove(); val.EmitDelegate>((Func)delegate(int a, int b) { int result2 = _dungeonDieRng.Next(a, b); Log(LogLevel.Debug, $"Rolling dungeon die base damage between [{a}, {b}]"); return result2; }); if (!val.TryGotoNext((MoveType)0, new Func[2] { (Instruction i) => ILPatternMatchingExt.MatchCall(i, (MethodBase)typeof(Random).GetMethod("Range", new Type[2] { typeof(int), typeof(int) })), (Instruction i) => ILPatternMatchingExt.MatchStfld(i, "_randomCritMod") })) { Debug.LogWarning((object)"Failed to match call for dungeon die crit damage"); return; } val.Remove(); val.EmitDelegate>((Func)delegate(int a, int b) { int result = _dungeonDieRng.Next(a, b); Log(LogLevel.Debug, $"Rolling dungeon die crit damage between [{a}, {b}]"); return result; }); } private static void Log(object message) { Log(LogLevel.On, message); } private static void Log(LogLevel level, object message) { if (LogLevel != 0 && LogLevel >= level) { Debug.Log(message); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "PeglinRNGSeeding"; public const string PLUGIN_NAME = "PeglinRNGSeeding"; public const string PLUGIN_VERSION = "0.0.11"; } }