using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using HarmonyLib; using Mirror; using Mirror.RemoteCalls; using MoreMountains.Feedbacks; using MoreMountains.Tools; using Newtonsoft.Json; using UnityEngine; using UnityEngine.Events; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("GambleMod")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("GambleMod")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("183b4327-b9f3-422a-b49c-e07adfd24cfb")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace MoreGamesBase; [Serializable] public class GameManifest { [JsonProperty("name")] public string name; [JsonProperty("directions")] public List directions; [JsonProperty("floorWeights")] public Dictionary floorWeights; [JsonProperty("buttons")] public List buttons; [JsonProperty("fields")] public List fields; [JsonProperty("baseMinBet")] public long? baseMinBet; [JsonProperty("baseMaxBet")] public long? baseMaxBet; public Dictionary BuildFloorWeights() { return (floorWeights == null) ? new Dictionary() : new Dictionary(floorWeights); } } [Serializable] public class GameFieldDef { [JsonProperty("fieldName")] public string FieldName { get; set; } [JsonProperty("source")] public string Source { get; set; } = "bundle"; [JsonProperty("targetName")] public string TargetName { get; set; } [JsonProperty("targetNames")] public List TargetNames { get; set; } } [Serializable] public class GameButtonDef { [JsonProperty("objectName")] public string ObjectName { get; set; } [JsonProperty("functionName")] public string FunctionName { get; set; } } public class MoreGamesButtonTracker : MonoBehaviour { public bool isWired = false; } [BepInPlugin("com.moregames.base", "MoreGames Base Loader", "1.0.0")] public class MoreGamesBaseLoader : BaseUnityPlugin { private class LoadedGame { public string name; public GameObject gamePrefab; public Type gameType; public HashSet directions = new HashSet(); public Dictionary floorWeights = new Dictionary(); public List buttons = new List(); } [HarmonyPatch(typeof(StampManager), "GetLootTableForFloor")] private class LootInjectPatch { private static void Postfix(CasinoFloor floor, MMLootTableGameObjectSO __result) { MoreGamesBaseLoader instance = Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)__result == (Object)null) && __result.LootTable != null) { int num = (((Object)(object)floor != (Object)null) ? floor.floorIndex : (-1)); MMLootTableGameObject lootTable = __result.LootTable; if (!((MMLootTable)(object)lootTable).ObjectsToLoot.Any((MMLootGameObject x) => (Object)(object)((MMLoot)(object)x)?.Loot != (Object)null && ((Object)((MMLoot)(object)x).Loot).name.Contains("[Injected]"))) { instance.injectedFloors.Add(num); instance.InjectIntoLootTable(num, __result.LootTable); } } } } [HarmonyPatch(typeof(NetworkServer), "Spawn", new Type[] { typeof(GameObject), typeof(NetworkConnectionToClient) })] public static class Patch_NetworkSpawn { private static void Postfix(GameObject obj) { if ((Object)(object)obj == (Object)null) { return; } GameBase gameBase = obj.GetComponentInChildren(); if ((Object)(object)gameBase == (Object)null) { return; } MoreGamesButtonTracker moreGamesButtonTracker = obj.GetComponent(); if ((Object)(object)moreGamesButtonTracker != (Object)null && moreGamesButtonTracker.isWired) { return; } if ((Object)(object)moreGamesButtonTracker == (Object)null) { moreGamesButtonTracker = obj.AddComponent(); } MoreGamesBaseLoader instance = Instance; LoadedGame loadedGame = instance.loadedGames.FirstOrDefault((LoadedGame g) => g.gameType == ((object)gameBase).GetType()); if (loadedGame != null && loadedGame.buttons != null) { foreach (GameButtonDef button in loadedGame.buttons) { Transform val = FindDeepChild(obj.transform, button.ObjectName); if ((Object)(object)val == (Object)null) { continue; } InteractableEventTrigger component = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null) { continue; } if (component.serverOnInteractEvent == null) { component.serverOnInteractEvent = new UnityEvent(); } ((UnityEventBase)component.serverOnInteractEvent).RemoveAllListeners(); MethodInfo targetMethod = ((object)gameBase).GetType().GetMethod(button.FunctionName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(targetMethod != null)) { continue; } ParameterInfo[] parameters = targetMethod.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType.Name == "PlayerInteract") { UnityAction val2 = (UnityAction)(object)Delegate.CreateDelegate(typeof(UnityAction), gameBase, targetMethod); component.serverOnInteractEvent.AddListener(val2); continue; } if (parameters.Length == 0) { component.serverOnInteractEvent.AddListener((UnityAction)delegate { targetMethod.Invoke(gameBase, null); }); continue; } Debug.LogError((object)("[MoreGames] Method '" + button.FunctionName + "' in '" + ((object)gameBase).GetType().Name + "' must take either zero arguments or one argument of type 'PlayerInteract'.")); } } CasinoGameFeedbacks componentInChildren = obj.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { AccessTools.Field(typeof(GameBase), "gameFeedbacks")?.SetValue(gameBase, componentInChildren); } moreGamesButtonTracker.isWired = true; } } public static MoreGamesBaseLoader Instance; private readonly List loadedGames = new List(); private readonly HashSet injectedFloors = new HashSet(); private void Awake() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown Instance = this; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[MoreGames] Base loader starting..."); ScanAllPlugins(); Harmony val = new Harmony("com.moregames.base"); val.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[MoreGames] Loaded {loadedGames.Count} games."); } private void ScanAllPlugins() { string pluginPath = Paths.PluginPath; if (!Directory.Exists(pluginPath)) { ((BaseUnityPlugin)this).Logger.LogError((object)"[MoreGames] Plugins folder not found"); return; } string[] directories = Directory.GetDirectories(pluginPath); foreach (string path in directories) { string text = Path.Combine(path, "Games"); if (!Directory.Exists(text)) { continue; } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[MoreGames] Found Games folder: " + text)); string[] directories2 = Directory.GetDirectories(text); foreach (string text2 in directories2) { try { LoadGame(text2); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"[MoreGames] Failed loading {text2}\n{arg}"); } } } } private void LoadGame(string gameDir) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[MoreGames] Loading: " + gameDir)); string path2 = Path.Combine(gameDir, "gamemanifest.json"); if (!File.Exists(path2)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[MoreGames] Missing gamemanifest.json"); return; } GameManifest manifest = JsonConvert.DeserializeObject(File.ReadAllText(path2)); if (manifest == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[MoreGames] Invalid gamemanifest.json"); return; } Type type = null; string path3 = Path.Combine(gameDir, manifest.name + ".dll"); if (File.Exists(path3)) { Assembly assembly = Assembly.LoadFile(path3); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[MoreGames] Loaded DLL: " + manifest.name)); type = assembly.GetTypes().FirstOrDefault((Type t) => typeof(GameBase).IsAssignableFrom(t) && !t.IsAbstract && typeof(MonoBehaviour).IsAssignableFrom(t)); if (type == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[MoreGames] No valid GameBase found in " + manifest.name)); } } string text = Path.Combine(gameDir, manifest.name); if (!File.Exists(text)) { ((BaseUnityPlugin)this).Logger.LogError((object)("[MoreGames] Missing bundle: " + text)); return; } AssetBundle val = AssetBundle.LoadFromFile(text); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[MoreGames] Failed to load AssetBundle"); return; } string text2 = val.GetAllAssetNames().FirstOrDefault((string path) => path.EndsWith(".prefab") && path.Contains(manifest.name.ToLower())); if (string.IsNullOrEmpty(text2)) { ((BaseUnityPlugin)this).Logger.LogError((object)("[MoreGames] Could not find a .prefab matching '" + manifest.name + "' in the bundle.")); return; } GameObject val2 = val.LoadAsset(text2); if ((Object)(object)val2 == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[MoreGames] No GameObject found at prefab path"); return; } GameBase val3 = null; if (type != null) { Component val4 = val2.GetComponent(type); if ((Object)(object)val4 == (Object)null) { val4 = val2.AddComponent(type); } val3 = (GameBase)(object)((val4 is GameBase) ? val4 : null); if ((Object)(object)val3 == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[MoreGames] Failed to cast GameBase"); return; } InjectGameFields(val3, val, manifest.fields); if (manifest.baseMinBet.HasValue) { AccessTools.Field(typeof(GameBase), "baseMinBet")?.SetValue(val3, manifest.baseMinBet.Value * 10 / 6); } if (manifest.baseMaxBet.HasValue) { AccessTools.Field(typeof(GameBase), "baseMaxBet")?.SetValue(val3, manifest.baseMaxBet.Value * 3 / 2 + 30); } } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[MoreGames] No GameBase type found, continuing without logic script"); } List buttons = manifest.buttons ?? new List(); RegisterAllNetworkRPCs(type); FixGamePrefab(val2); PreparePrefab(val2, val3, buttons); FixCasinoGameFeedbacks(val2); loadedGames.Add(new LoadedGame { name = manifest.name, gamePrefab = val2, gameType = type, directions = ((manifest.directions != null) ? new HashSet(manifest.directions) : new HashSet()), floorWeights = manifest.BuildFloorWeights(), buttons = buttons }); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[MoreGames] Loaded game: " + manifest.name)); } private void InjectGameFields(GameBase gameBase, AssetBundle bundle, List fields) { if (fields == null || fields.Count == 0) { return; } foreach (GameFieldDef field in fields) { FieldInfo fieldInfo = AccessTools.Field(((object)gameBase).GetType(), field.FieldName); if (fieldInfo == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[MoreGames] Field '" + field.FieldName + "' not found on " + ((object)gameBase).GetType().Name + ".")); } else if (field.TargetNames != null && field.TargetNames.Count > 0) { if (fieldInfo.FieldType.IsArray) { Type elementType = fieldInfo.FieldType.GetElementType(); Array array = Array.CreateInstance(elementType, field.TargetNames.Count); for (int i = 0; i < field.TargetNames.Count; i++) { GameObject targetObject = GetTargetObject(((Component)gameBase).gameObject, bundle, field.Source, field.TargetNames[i]); array.SetValue(ConvertObjectToType(targetObject, elementType), i); } fieldInfo.SetValue(gameBase, array); } } else if (!string.IsNullOrEmpty(field.TargetName)) { GameObject targetObject2 = GetTargetObject(((Component)gameBase).gameObject, bundle, field.Source, field.TargetName); fieldInfo.SetValue(gameBase, ConvertObjectToType(targetObject2, fieldInfo.FieldType)); } } } private GameObject GetTargetObject(GameObject rootPrefab, AssetBundle bundle, string source, string targetName) { if (source.ToLower() == "child") { Transform val = FindDeepChild(rootPrefab.transform, targetName); return ((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null; } return bundle.LoadAsset(targetName); } private object ConvertObjectToType(GameObject obj, Type targetType) { if ((Object)(object)obj == (Object)null) { return null; } if (targetType == typeof(GameObject)) { return obj; } if (targetType == typeof(Transform)) { return obj.transform; } if (typeof(Component).IsAssignableFrom(targetType)) { return obj.GetComponent(targetType); } return null; } private void RegisterAllNetworkRPCs(Type gameType) { //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown if (gameType == null) { return; } MethodInfo[] methods = gameType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); MethodInfo[] array = methods; foreach (MethodInfo method in array) { if (!method.Name.StartsWith("UserRpc")) { continue; } if (method.GetCustomAttributes(typeof(ClientRpcAttribute), inherit: true).Length != 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[MoreGames] " + method.Name + " is already Weaved. Skipping manual registration.")); continue; } string text = method.ReturnType.FullName ?? "System.Void"; ParameterInfo[] parameters = method.GetParameters(); string text2 = string.Join(",", parameters.Select((ParameterInfo p) => p.ParameterType.FullName)); string text3 = text + " " + gameType.FullName + "::" + method.Name + "(" + text2 + ")"; RemoteCallDelegate val = (RemoteCallDelegate)delegate(NetworkBehaviour obj, NetworkReader reader, NetworkConnectionToClient senderConnection) { if (NetworkClient.active) { if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string)) { string text4 = NetworkReaderExtensions.ReadString(reader); method.Invoke(obj, new object[1] { text4 }); } else if (parameters.Length == 0) { method.Invoke(obj, null); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[MoreGames] Unhandled parameter configuration for RPC " + method.Name)); } } }; try { RemoteProcedureCalls.RegisterRpc(gameType, text3, val); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[MoreGames] Successfully auto-registered RPC: " + method.Name)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[MoreGames] Failed to register RPC " + method.Name + ": " + ex.Message)); } } } private static void PreparePrefab(GameObject root, GameBase gameBase, List buttons) { AddGameName(root, gameBase); SetupButtons(root, gameBase, buttons); SetupFeedbacks(root, gameBase); SetupKeypad(root, gameBase); } private static Transform FindDeepChild(Transform parent, string name) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown foreach (Transform item in parent) { Transform val = item; if (((Object)val).name == name) { return val; } Transform val2 = FindDeepChild(val, name); if ((Object)(object)val2 != (Object)null) { return val2; } } return null; } private static void AddGameName(GameObject root, GameBase gameBase) { } private static void SetupButtons(GameObject root, GameBase gameBase, List buttons) { if (buttons == null || buttons.Count == 0) { return; } foreach (GameButtonDef button in buttons) { Transform val = FindDeepChild(root.transform, button.ObjectName); if (!((Object)(object)val == (Object)null)) { InteractableEventTrigger component = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null) { component = ((Component)val).gameObject.AddComponent(); } } } } private static void SetupFeedbacks(GameObject root, GameBase gameBase) { Transform val = FindDeepChild(root.transform, "Feedbacks"); if (!((Object)(object)val == (Object)null)) { EnsureMMF(val, "GameResultFB"); EnsureMMF(val, "GameWinFB"); EnsureMMF(val, "GameLoseFB"); EnsureMMF(val, "GameTieFB"); Transform val2 = FindDeepChild(val, "FloatingText Spawner"); if ((Object)(object)val2 != (Object)null && !Object.op_Implicit((Object)(object)((Component)val2).GetComponent())) { ((Component)val2).gameObject.AddComponent(); } } } private static void SetupKeypad(GameObject root, GameBase gameBase) { Transform val = FindDeepChild(root.transform, "KeypadPoint"); if ((Object)(object)val == (Object)null) { return; } Transform val2 = FindDeepChild(val, "Keypad"); if (!((Object)(object)val2 == (Object)null)) { if (!Object.op_Implicit((Object)(object)((Component)val2).GetComponent())) { ((Component)val2).gameObject.AddComponent(); } AccessTools.Field(typeof(GameBase), "keypadSpawnPoint")?.SetValue(gameBase, val); Keypad componentInChildren = ((Component)val2).GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { AccessTools.Field(typeof(GameBase), "keypad")?.SetValue(gameBase, componentInChildren); } } } private static void EnsureMMF(Transform root, string name) { Transform val = FindDeepChild(root, name); if (!((Object)(object)val == (Object)null) && !Object.op_Implicit((Object)(object)((Component)val).GetComponent())) { ((Component)val).gameObject.AddComponent(); } } private void FixGamePrefab(GameObject prefab) { if (!Object.op_Implicit((Object)(object)prefab.GetComponent())) { prefab.AddComponent(); } if (!Object.op_Implicit((Object)(object)prefab.GetComponent())) { prefab.AddComponent(); } if (!Object.op_Implicit((Object)(object)prefab.GetComponent())) { prefab.AddComponent(); } } private static void SetField(object obj, string fieldName, object value) { FieldInfo fieldInfo = AccessTools.Field(obj.GetType(), fieldName); if (!(fieldInfo == null)) { fieldInfo.SetValue(obj, value); } } private void FixCasinoGameFeedbacks(GameObject prefab) { CasinoGameFeedbacks val = prefab.GetComponent(); if ((Object)(object)val == (Object)null) { val = prefab.AddComponent(); } Renderer[] value = (Renderer[])(object)new Renderer[0]; SetField(val, "lightRenderers", value); SetField(val, "lights", prefab.GetComponentsInChildren(true)); SetField(val, "lightFeedbacks", BuildLightFeedbacks(prefab)); SetField(val, "resultParticles", prefab.GetComponentsInChildren(true)); SetField(val, "onGameResultFeedback", FindMMF(prefab, "GameResultFB")); SetField(val, "onGameWinFeedback", FindMMF(prefab, "GameWinFB")); SetField(val, "onGameLoseFeedback", FindMMF(prefab, "GameLoseFB")); SetField(val, "onGameTieFeedback", FindMMF(prefab, "GameTieFB")); SetField(val, "lightTweenDuration", 0.3f); } private MMF_Player FindMMF(GameObject root, string name) { Transform val = FindDeepChild(root.transform, name); if ((Object)(object)val == (Object)null) { return null; } MMF_Player val2 = ((Component)val).GetComponent(); if ((Object)(object)val2 == (Object)null) { val2 = ((Component)val).gameObject.AddComponent(); } return val2; } private List BuildLightFeedbacks(GameObject prefab) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) return new List { new LightFeedbackData { threshold = 0f, color = new Color(1f, 0.16509432f, 0.25624812f, 1f), intensity = 3f, duration = 1f }, new LightFeedbackData { threshold = 0.01f, color = new Color(1f, 0.549705f, 0.1462264f, 1f), intensity = 1.5f, duration = 1f }, new LightFeedbackData { threshold = 1f, color = new Color(1f, 0.96215194f, 0.2216981f, 1f), intensity = 1.5f, duration = 1f }, new LightFeedbackData { threshold = 2f, color = new Color(0.528569f, 1f, 0.23113209f, 1f), intensity = 2f, duration = 1f }, new LightFeedbackData { threshold = 5f, color = new Color(0.1273585f, 1f, 0.96583235f, 1f), intensity = 3f, duration = 1.5f }, new LightFeedbackData { threshold = 10f, color = new Color(0.49349895f, 0.17647058f, 1f, 1f), intensity = 4f, duration = 2f } }; } private void InjectIntoLootTable(int floorIndex, MMLootTableGameObject table) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_00b8: Expected O, but got Unknown foreach (LoadedGame game in loadedGames) { float value = 0f; if (game.floorWeights != null) { game.floorWeights.TryGetValue(floorIndex, out value); } if (!(value <= 0f) && !((MMLootTable)(object)table).ObjectsToLoot.Any((MMLootGameObject x) => x != null && (Object)(object)((MMLoot)(object)x).Loot == (Object)(object)game.gamePrefab)) { List objectsToLoot = ((MMLootTable)(object)table).ObjectsToLoot; MMLootGameObject val = new MMLootGameObject(); ((MMLoot)val).Loot = game.gamePrefab; ((MMLoot)val).Weight = value; ((MMLoot)val).ChancePercentage = 0f; objectsToLoot.Add(val); } } } }