using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")] [assembly: AssemblyCompany("MuseumGambling")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.2.0")] [assembly: AssemblyInformationalVersion("0.1.2")] [assembly: AssemblyProduct("MuseumGambling")] [assembly: AssemblyTitle("MuseumGambling")] [assembly: InternalsVisibleTo("MuseumGambling.Tests")] [assembly: AssemblyVersion("0.1.2.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace MuseumGambling { internal static class GrabSpot { private static readonly Dictionary _spots = new Dictionary(); internal static void Record(int viewId, Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) _spots[viewId] = position; } internal static Vector3? Consume(int viewId) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (_spots.TryGetValue(viewId, out var value)) { _spots.Remove(viewId); return value; } return null; } } internal static class Outcome { internal static bool ShouldWin(int roll, int winChancePercent) { if (winChancePercent > 0) { return roll <= winChancePercent; } return false; } } internal static class Payout { private static readonly FieldInfo? s_dollarValueOverride = typeof(ValuableObject).GetField("dollarValueOverride", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal static void Spawn(Vector3 position, int value) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) try { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } GameObject surplusValuableSmall = AssetManager.instance.surplusValuableSmall; if ((Object)(object)surplusValuableSmall == (Object)null) { Plugin.Log.LogError((object)"[MuseumGambling] surplusValuableSmall prefab missing — cannot spawn payout."); return; } GameObject val = (SemiFunc.IsMultiplayer() ? PhotonNetwork.InstantiateRoomObject("Valuables/" + ((Object)surplusValuableSmall).name, position, Quaternion.identity, (byte)0, (object[])null) : Object.Instantiate(surplusValuableSmall, position, Quaternion.identity)); if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)"[MuseumGambling] Spawn returned null."); return; } ValuableObject component = val.GetComponent(); if ((Object)(object)component == (Object)null) { Plugin.Log.LogError((object)"[MuseumGambling] Spawned object has no ValuableObject component."); return; } if (s_dollarValueOverride == null) { Plugin.Log.LogError((object)"[MuseumGambling] dollarValueOverride field not found via reflection — value not stamped."); } else { s_dollarValueOverride.SetValue(component, value); } Plugin.Log.LogInfo((object)$"[MuseumGambling] Spawned money bag worth {value} at {position}."); } catch (Exception arg) { Plugin.Log.LogError((object)$"Payout.Spawn failed: {arg}"); } } } [BepInPlugin("darkharasho.MuseumGambling", "MuseumGambling", "0.1.2")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; internal static ConfigEntry Enabled; internal static ConfigEntry WinChancePercent; internal static ConfigEntry PayoutValue; private void Awake() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Global kill-switch. When false, the Museum Head behaves vanilla (no gambling)."); WinChancePercent = ((BaseUnityPlugin)this).Config.Bind("General", "WinChancePercent", 5, new ConfigDescription("Percent chance (whole number, 0–100) that a click pays out instead of dealing damage.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); PayoutValue = ((BaseUnityPlugin)this).Config.Bind("General", "PayoutValue", 50000, new ConfigDescription("Dollar value stamped on the spawned money-bag valuable on a win.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 1000000), Array.Empty())); new Harmony("darkharasho.MuseumGambling").PatchAll(); Log.LogInfo((object)"MuseumGambling v0.1.2 loaded."); } } internal static class WinBroadcast { internal const byte EventCode = 199; private static readonly Dictionary _pendingDamage = new Dictionary(); private static readonly HashSet _pendingEffects = new HashSet(); private static bool _registered; internal static void Register() { if (!_registered) { PhotonNetwork.NetworkingClient.EventReceived += OnEventReceived; _registered = true; } } internal static void Send(int viewId, bool win) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_003c: Unknown result type (might be due to invalid IL or missing references) Apply(viewId, win); if (PhotonNetwork.InRoom) { object[] array = new object[2] { viewId, win }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)0 }; PhotonNetwork.RaiseEvent((byte)199, (object)array, val, SendOptions.SendReliable); } } internal static bool ConsumePendingResult(int viewId) { if (_pendingDamage.TryGetValue(viewId, out var value)) { _pendingDamage.Remove(viewId); return value; } return false; } internal static bool ConsumePendingEffect(int viewId) { return _pendingEffects.Remove(viewId); } private static void OnEventReceived(EventData ev) { if (ev.Code == 199 && ev.CustomData is object[] array && array.Length >= 2) { int viewId = (int)array[0]; bool win = (bool)array[1]; Apply(viewId, win); } } private static void Apply(int viewId, bool win) { _pendingDamage[viewId] = win; if (win) { _pendingEffects.Add(viewId); } } } internal static class WinSound { private static Sound? _sound; internal static void Play(Vector3 position) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) try { Sound val = ResolveSound(); if (val == null) { Plugin.Log.LogWarning((object)"[MuseumGambling] Could not initialize win jingle."); } else { val.Play(position, 1f, 1f, 1f, 1f); } } catch (Exception arg) { Plugin.Log.LogError((object)$"WinSound.Play failed: {arg}"); } } private static Sound? ResolveSound() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (_sound != null) { return _sound; } AudioClip val = LoadEmbeddedClip(); if ((Object)(object)val == (Object)null) { return null; } Sound val2 = new Sound(); val2.Sounds = (AudioClip[])(object)new AudioClip[1] { val }; val2.Type = (AudioType)1; val2.Volume = 0.7f; val2.VolumeRandom = 0f; val2.Pitch = 1f; val2.PitchRandom = 0f; val2.SpatialBlend = 0.7f; val2.Doppler = 0f; val2.ReverbMix = 1f; val2.FalloffMultiplier = 2f; val2.OffscreenVolume = 1f; val2.OffscreenFalloff = 1f; _sound = val2; return _sound; } private static AudioClip? LoadEmbeddedClip() { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MuseumGambling.assets.winjingle.wav"); if (stream == null) { Plugin.Log.LogError((object)"[MuseumGambling] Embedded winjingle.wav resource not found."); return null; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); return WavLoader.Load(memoryStream.ToArray(), "MuseumGambling.WinJingle"); } } internal static class WavLoader { internal static AudioClip? Load(byte[] data, string name) { if (data.Length < 44) { return null; } if (data[0] != 82 || data[1] != 73 || data[2] != 70 || data[3] != 70) { return null; } if (data[8] != 87 || data[9] != 65 || data[10] != 86 || data[11] != 69) { return null; } int num = BitConverter.ToInt16(data, 22); int num2 = BitConverter.ToInt32(data, 24); if (BitConverter.ToInt16(data, 34) != 16) { return null; } int i = 12; int num3 = -1; int num4 = 0; int num5; for (; i < data.Length - 8; i += 8 + num5) { string @string = Encoding.ASCII.GetString(data, i, 4); num5 = BitConverter.ToInt32(data, i + 4); if (@string == "data") { num3 = i + 8; num4 = num5; break; } } if (num3 < 0) { return null; } int num6 = num4 / 2; int num7 = num6 / num; float[] array = new float[num6]; for (int j = 0; j < num6; j++) { short num8 = BitConverter.ToInt16(data, num3 + j * 2); array[j] = (float)num8 / 32768f; } AudioClip obj = AudioClip.Create(name, num7, num, num2, false); obj.SetData(array, 0); return obj; } } public static class PluginInfo { public const string PLUGIN_GUID = "darkharasho.MuseumGambling"; public const string PLUGIN_NAME = "MuseumGambling"; public const string PLUGIN_VERSION = "0.1.2"; } } namespace MuseumGambling.Patches { [HarmonyPatch(typeof(HurtCollider), "PlayerHurt")] internal static class HurtCollider_PlayerHurt_Prefix { private static bool Prefix(HurtCollider __instance) { try { MuseumPropMoneyHead componentInParent = ((Component)__instance).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null) { return true; } PhotonView component = ((Component)componentInParent).GetComponent(); int num = ((component != null) ? component.ViewID : 0); if (WinBroadcast.ConsumePendingResult(num)) { Plugin.Log.LogInfo((object)$"[MuseumGambling] Damage suppressed for view {num}."); return false; } return true; } catch (Exception arg) { Plugin.Log.LogError((object)$"HurtCollider.PlayerHurt prefix failed: {arg}"); return true; } } } [HarmonyPatch(typeof(MuseumPropMoneyHead), "DragInPlayerStart")] internal static class MuseumPropMoneyHead_DragInPlayerStart_Postfix { private static readonly FieldInfo? PlayerToDragInField = AccessTools.Field(typeof(MuseumPropMoneyHead), "playerToDragIn"); private static void Postfix(MuseumPropMoneyHead __instance) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) try { WinBroadcast.Register(); if (!(PlayerToDragInField == null)) { object? value = PlayerToDragInField.GetValue(__instance); PlayerAvatar val = (PlayerAvatar)((value is PlayerAvatar) ? value : null); if (val != null) { PhotonView component = ((Component)__instance).GetComponent(); GrabSpot.Record((component != null) ? component.ViewID : 0, ((Component)val).transform.position); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"DragInPlayerStart postfix failed: {arg}"); } } } [HarmonyPatch(typeof(MuseumPropMoneyHead), "StateSetRPC")] internal static class MuseumPropMoneyHead_StateSetRPC_Postfix { private static void Postfix(MuseumPropMoneyHead __instance, int _newState) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Invalid comparison between Unknown and I4 //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) try { WinBroadcast.Register(); State val = (State)_newState; PhotonView component = ((Component)__instance).GetComponent(); int num = ((component != null) ? component.ViewID : 0); if ((int)val == 2) { if (Plugin.Enabled.Value && (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient)) { int num2 = Random.Range(1, 101); int value = Plugin.WinChancePercent.Value; bool flag = Outcome.ShouldWin(num2, value); Plugin.Log.LogInfo((object)$"[MuseumGambling] viewId={num} roll={num2} chance={value} win={flag}"); WinBroadcast.Send(num, flag); } } else if ((int)val == 3 && WinBroadcast.ConsumePendingEffect(num)) { Plugin.Log.LogInfo((object)$"[MuseumGambling] Effects firing for view {num}."); if (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient) { Payout.Spawn((Vector3)(((??)GrabSpot.Consume(num)) ?? ((Component)__instance).transform.position) + Vector3.up * 0.5f, Plugin.PayoutValue.Value); } WinSound.Play(((Component)__instance).transform.position); FlashEyesGreen(__instance); } } catch (Exception arg) { Plugin.Log.LogError((object)$"MuseumPropMoneyHead.StateSetRPC postfix failed: {arg}"); } } private static void FlashEyesGreen(MuseumPropMoneyHead head) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)head.eye1Light != (Object)null) { head.eye1Light.color = Color.green; } if ((Object)(object)head.eye2Light != (Object)null) { head.eye2Light.color = Color.green; } } } }