Decompiled source of MegabonkMultiplayer v1.0.0
plugins\MegabonkMultiplayer.dll
Decompiled 11 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; 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("MegabonkMultiplayer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Multiplayer mod for Megabonk")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+ba547804f6d0d6662dd32230fb2a96b9f0759923")] [assembly: AssemblyProduct("MegabonkMultiplayer")] [assembly: AssemblyTitle("MegabonkMultiplayer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.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 MegabonkMultiplayer { public class ChestSyncManager : MonoBehaviour { [CompilerGenerated] private sealed class <AnimateItemText>d__22 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public float delay; public GameObject textObject; private Vector3 <startPos>5__2; private Vector3 <endPos>5__3; private float <duration>5__4; private float <t>5__5; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <AnimateItemText>d__22(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(delay); <>1__state = 1; return true; case 1: <>1__state = -1; <startPos>5__2 = textObject.transform.position; <endPos>5__3 = <startPos>5__2 + Vector3.up * 2f; <duration>5__4 = 2f; <t>5__5 = 0f; break; case 2: <>1__state = -1; <t>5__5 += Time.deltaTime; break; } if (<t>5__5 < <duration>5__4) { float num = <t>5__5 / <duration>5__4; textObject.transform.position = Vector3.Lerp(<startPos>5__2, <endPos>5__3, num); TextMesh component = textObject.GetComponent<TextMesh>(); if ((Object)(object)component != (Object)null) { Color color = component.color; color.a = 1f - num; component.color = color; } <>2__current = null; <>1__state = 2; return true; } Object.Destroy((Object)(object)textObject); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <AnimateOpenedByText>d__23 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public GameObject textObject; private float <duration>5__2; private float <t>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <AnimateOpenedByText>d__23(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <duration>5__2 = 3f; _ = textObject.transform.position; <t>5__3 = 0f; break; case 1: <>1__state = -1; <t>5__3 += Time.deltaTime; break; } if (<t>5__3 < <duration>5__2) { float num = <t>5__3 / <duration>5__2; TextMesh component = textObject.GetComponent<TextMesh>(); if ((Object)(object)component != (Object)null) { Color color = component.color; color.a = 1f - num; component.color = color; } <>2__current = null; <>1__state = 1; return true; } Object.Destroy((Object)(object)textObject); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static ChestSyncManager instance; private Dictionary<string, ChestData> chests = new Dictionary<string, ChestData>(); private float lastChestSync; private const float CHEST_SYNC_INTERVAL = 5f; public static ChestSyncManager Instance => instance; private void Awake() { if ((Object)(object)instance == (Object)null) { instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } else { Object.Destroy((Object)(object)((Component)this).gameObject); } } private void Start() { if ((Object)(object)NetworkManager.Instance != (Object)null) { NetworkManager.Instance.OnMessageReceived += HandleNetworkMessage; } } private void Update() { if (NetworkManager.Instance.IsHost && Time.time - lastChestSync >= 5f) { ScanForNewChests(); lastChestSync = Time.time; } } private void HandleNetworkMessage(NetworkMessage message) { string messageType = message.MessageType; if (!(messageType == "ChestSpawnMessage")) { if (messageType == "ChestOpenedMessage") { HandleChestOpenedMessage(message as ChestOpenedMessage); } } else { HandleChestSpawnMessage(message as ChestSpawnMessage); } } private void HandleChestSpawnMessage(ChestSpawnMessage message) { if (!NetworkManager.Instance.IsHost) { CreateRemoteChest(message); } } private void HandleChestOpenedMessage(ChestOpenedMessage message) { ProcessChestOpening(message); } public void RegisterChestSpawn(GameObject chest) { //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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Instance.IsHost) { string text = Guid.NewGuid().ToString(); Vector3 position = chest.transform.position; ChestType chestType = DetermineChestType(chest); int cost = CalculateChestCost(chestType); string[] items = GenerateChestItems(chestType); ChestData value = new ChestData { ChestId = text, GameObject = chest, Position = position, Type = chestType, Cost = cost, Items = items, IsOpened = false, OpenedByPlayerId = "" }; chests[text] = value; ChestSpawnMessage message = new ChestSpawnMessage { ChestId = text, Position = position, ChestType = chestType.ToString(), Cost = cost, Items = items }; NetworkManager.Instance.SendMessage(message); } } public bool TryOpenChest(GameObject chest, string playerId) { string text = FindChestId(chest); if (string.IsNullOrEmpty(text)) { return false; } ChestData chestData = chests[text]; if (chestData.IsOpened) { return false; } if (!CanPlayerAffordChest(playerId, chestData.Cost)) { ShowInsufficientFundsMessage(playerId); return false; } chestData.IsOpened = true; chestData.OpenedByPlayerId = playerId; DeductCostFromPlayer(playerId, chestData.Cost); GiveItemsToPlayer(playerId, chestData.Items); ChestOpenedMessage message = new ChestOpenedMessage { ChestId = text, OpenedByPlayerId = playerId, ItemsReceived = chestData.Items }; NetworkManager.Instance.SendMessage(message); UpdateChestVisual(chest, isOpened: true); return true; } private void CreateRemoteChest(ChestSpawnMessage message) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) GameObject gameObject = CreateRemoteChestVisual(message); ChestData value = new ChestData { ChestId = message.ChestId, GameObject = gameObject, Position = message.Position, Type = (ChestType)Enum.Parse(typeof(ChestType), message.ChestType), Cost = message.Cost, Items = message.Items, IsOpened = false, OpenedByPlayerId = "" }; chests[message.ChestId] = value; } private void ProcessChestOpening(ChestOpenedMessage message) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (chests.ContainsKey(message.ChestId)) { ChestData chestData = chests[message.ChestId]; chestData.IsOpened = true; chestData.OpenedByPlayerId = message.OpenedByPlayerId; if ((Object)(object)chestData.GameObject != (Object)null) { UpdateChestVisual(chestData.GameObject, isOpened: true); } ShowChestOpeningEffect(chestData.Position, message.ItemsReceived, message.OpenedByPlayerId); if (message.OpenedByPlayerId == GetLocalPlayerId()) { GiveItemsToPlayer(message.OpenedByPlayerId, message.ItemsReceived); } } } private void ScanForNewChests() { GameObject[] array = GameObject.FindGameObjectsWithTag("Chest"); foreach (GameObject chest in array) { if (string.IsNullOrEmpty(FindChestId(chest))) { RegisterChestSpawn(chest); } } } private GameObject CreateRemoteChestVisual(ChestSpawnMessage message) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val).name = "RemoteChest_" + message.ChestId; val.transform.position = message.Position; val.transform.localScale = new Vector3(1f, 0.5f, 1f); Renderer component = val.GetComponent<Renderer>(); if ((Object)(object)component != (Object)null) { Material val2 = new Material(Shader.Find("Standard")); val2.color = GetChestTypeColor(message.ChestType); component.material = val2; } CreateChestCostDisplay(val, message.Cost); ChestInteraction chestInteraction = val.AddComponent<ChestInteraction>(); chestInteraction.ChestId = message.ChestId; chestInteraction.Cost = message.Cost; chestInteraction.Items = message.Items; return val; } private void CreateChestCostDisplay(GameObject chest, int cost) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0021: 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_0059: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("CostDisplay"); val.transform.SetParent(chest.transform); val.transform.localPosition = Vector3.up * 1.5f; TextMesh obj = val.AddComponent<TextMesh>(); obj.text = $"{cost} Gold"; obj.fontSize = 16; obj.color = Color.yellow; obj.anchor = (TextAnchor)4; } private void UpdateChestVisual(GameObject chest, bool isOpened) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)chest == (Object)null) && isOpened) { Renderer component = chest.GetComponent<Renderer>(); if ((Object)(object)component != (Object)null) { component.material.color = Color.gray; } Transform val = chest.transform.Find("CostDisplay"); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(false); } ChestInteraction component2 = chest.GetComponent<ChestInteraction>(); if ((Object)(object)component2 != (Object)null) { ((Behaviour)component2).enabled = false; } } } private void ShowChestOpeningEffect(Vector3 position, string[] items, string playerId) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ChestOpenEffect"); val.transform.position = position + Vector3.up; for (int i = 0; i < items.Length; i++) { GameObject val2 = new GameObject($"ItemText_{i}"); val2.transform.position = position + Vector3.up * (2f + (float)i * 0.5f); TextMesh obj = val2.AddComponent<TextMesh>(); obj.text = items[i]; obj.color = GetItemRarityColor(items[i]); obj.fontSize = 12; obj.anchor = (TextAnchor)4; ((MonoBehaviour)this).StartCoroutine(AnimateItemText(val2, (float)i * 0.2f)); } ShowChestOpenedByText(position, playerId); Object.Destroy((Object)(object)val, 3f); } private void ShowChestOpenedByText(Vector3 position, string playerId) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("OpenedByText"); val.transform.position = position + Vector3.up * 3f; TextMesh obj = val.AddComponent<TextMesh>(); obj.text = "Opened by Player " + playerId.Substring(0, 8); obj.color = Color.cyan; obj.fontSize = 10; obj.anchor = (TextAnchor)4; ((MonoBehaviour)this).StartCoroutine(AnimateOpenedByText(val)); } [IteratorStateMachine(typeof(<AnimateItemText>d__22))] private IEnumerator AnimateItemText(GameObject textObject, float delay) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <AnimateItemText>d__22(0) { textObject = textObject, delay = delay }; } [IteratorStateMachine(typeof(<AnimateOpenedByText>d__23))] private IEnumerator AnimateOpenedByText(GameObject textObject) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <AnimateOpenedByText>d__23(0) { textObject = textObject }; } private ChestType DetermineChestType(GameObject chest) { string text = ((Object)chest).name.ToLower(); if (text.Contains("legendary")) { return ChestType.Legendary; } if (text.Contains("epic")) { return ChestType.Epic; } if (text.Contains("rare")) { return ChestType.Rare; } return ChestType.Common; } private int CalculateChestCost(ChestType chestType) { int connectedPlayerCount = NetworkManager.Instance.ConnectedPlayerCount; return Mathf.RoundToInt((float)(chestType switch { ChestType.Common => 10, ChestType.Rare => 25, ChestType.Epic => 50, ChestType.Legendary => 100, _ => 10, }) * (1f + (float)(connectedPlayerCount - 1) * 0.1f)); } private string[] GenerateChestItems(ChestType chestType) { List<string> list = new List<string>(); switch (chestType) { case ChestType.Common: list.Add("Health Potion"); list.Add("10 Gold"); break; case ChestType.Rare: list.Add("Mana Potion"); list.Add("Iron Sword"); list.Add("25 Gold"); break; case ChestType.Epic: list.Add("Magic Ring"); list.Add("Steel Armor"); list.Add("50 Gold"); break; case ChestType.Legendary: list.Add("Legendary Weapon"); list.Add("Ancient Artifact"); list.Add("100 Gold"); break; } return list.ToArray(); } private Color GetChestTypeColor(string chestType) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) return (Color)(chestType.ToLower() switch { "common" => new Color(0.6f, 0.3f, 0.1f), "rare" => Color.blue, "epic" => Color.magenta, "legendary" => Color.yellow, _ => Color.gray, }); } private Color GetItemRarityColor(string item) { //IL_000d: 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_004d: 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) if (item.Contains("Legendary")) { return Color.yellow; } if (item.Contains("Epic") || item.Contains("Ancient")) { return Color.magenta; } if (item.Contains("Magic") || item.Contains("Steel")) { return Color.blue; } return Color.white; } private bool CanPlayerAffordChest(string playerId, int cost) { return GetPlayerGold(playerId) >= cost; } private void DeductCostFromPlayer(string playerId, int cost) { int playerGold = GetPlayerGold(playerId); SetPlayerGold(playerId, playerGold - cost); } private void GiveItemsToPlayer(string playerId, string[] items) { foreach (string text in items) { Debug.Log((object)("Giving " + text + " to player " + playerId)); } } private void ShowInsufficientFundsMessage(string playerId) { if (playerId == GetLocalPlayerId()) { Debug.Log((object)"Insufficient gold to open this chest!"); } } private string FindChestId(GameObject chest) { return chests.FirstOrDefault((KeyValuePair<string, ChestData> kvp) => (Object)(object)kvp.Value.GameObject == (Object)(object)chest).Key; } private string GetLocalPlayerId() { return SystemInfo.deviceUniqueIdentifier; } private int GetPlayerGold(string playerId) { return 100; } private void SetPlayerGold(string playerId, int gold) { } public int GetTotalChestCount() { return chests.Count; } public int GetAvailableChestCount() { return chests.Values.Count((ChestData c) => !c.IsOpened); } public List<ChestData> GetAllChests() { return chests.Values.ToList(); } public ChestData GetChestData(string chestId) { if (!chests.ContainsKey(chestId)) { return null; } return chests[chestId]; } } public enum ChestType { Common, Rare, Epic, Legendary } [Serializable] public class ChestData { public string ChestId; public GameObject GameObject; public Vector3 Position; public ChestType Type; public int Cost; public string[] Items; public bool IsOpened; public string OpenedByPlayerId; } public class ChestInteraction : MonoBehaviour { public string ChestId; public int Cost; public string[] Items; private void OnMouseDown() { if ((Object)(object)ChestSyncManager.Instance != (Object)null) { string deviceUniqueIdentifier = SystemInfo.deviceUniqueIdentifier; ChestSyncManager.Instance.TryOpenChest(((Component)this).gameObject, deviceUniqueIdentifier); } } private void OnTriggerEnter(Collider other) { if (((Component)other).CompareTag("Player")) { ShowInteractionPrompt(show: true); } } private void OnTriggerExit(Collider other) { if (((Component)other).CompareTag("Player")) { ShowInteractionPrompt(show: false); } } private void ShowInteractionPrompt(bool show) { Debug.Log((object)(show ? $"Press E to open chest (Cost: {Cost} Gold)" : "")); } } public class EnemyScalingManager : MonoBehaviour { [CompilerGenerated] private sealed class <DeathAnimation>d__25 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public GameObject enemy; private float <duration>5__2; private Vector3 <originalScale>5__3; private float <t>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DeathAnimation>d__25(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <duration>5__2 = 1f; <originalScale>5__3 = enemy.transform.localScale; <t>5__4 = 0f; break; case 1: <>1__state = -1; <t>5__4 += Time.deltaTime; break; } if (<t>5__4 < <duration>5__2) { float num = <t>5__4 / <duration>5__2; enemy.transform.localScale = Vector3.Lerp(<originalScale>5__3, Vector3.zero, num); <>2__current = null; <>1__state = 1; return true; } Object.Destroy((Object)(object)enemy); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <RemoveEnemyDelayed>d__26 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public float delay; public EnemyScalingManager <>4__this; public string enemyId; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RemoveEnemyDelayed>d__26(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown int num = <>1__state; EnemyScalingManager enemyScalingManager = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(delay); <>1__state = 1; return true; case 1: <>1__state = -1; enemyScalingManager.RemoveEnemy(enemyId); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static EnemyScalingManager instance; private Dictionary<string, EnemyData> enemies = new Dictionary<string, EnemyData>(); private float lastEnemySync; private const float ENEMY_SYNC_INTERVAL = 2f; public static EnemyScalingManager Instance => instance; private void Awake() { if ((Object)(object)instance == (Object)null) { instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } else { Object.Destroy((Object)(object)((Component)this).gameObject); } } private void Start() { if ((Object)(object)NetworkManager.Instance != (Object)null) { NetworkManager.Instance.OnMessageReceived += HandleNetworkMessage; } } private void Update() { if (NetworkManager.Instance.IsHost && Time.time - lastEnemySync >= 2f) { SyncAllEnemies(); lastEnemySync = Time.time; } } private void HandleNetworkMessage(NetworkMessage message) { string messageType = message.MessageType; if (!(messageType == "EnemySpawnMessage")) { if (messageType == "EnemyUpdateMessage") { HandleEnemyUpdateMessage(message as EnemyUpdateMessage); } } else { HandleEnemySpawnMessage(message as EnemySpawnMessage); } } private void HandleEnemySpawnMessage(EnemySpawnMessage message) { if (!NetworkManager.Instance.IsHost) { SpawnRemoteEnemy(message); } } private void HandleEnemyUpdateMessage(EnemyUpdateMessage message) { UpdateRemoteEnemy(message); } public void RegisterEnemySpawn(GameObject enemy, string enemyType) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Instance.IsHost) { string text = Guid.NewGuid().ToString(); int connectedPlayerCount = NetworkManager.Instance.ConnectedPlayerCount; float value = MegabonkMultiplayerPlugin.EnemyScalingFactor.Value; EnemyStats originalEnemyStats = GetOriginalEnemyStats(enemy, enemyType); EnemyStats enemyStats = ScaleEnemyStats(originalEnemyStats, connectedPlayerCount, value); ApplyStatsToEnemy(enemy, enemyStats); EnemyData value2 = new EnemyData { EnemyId = text, GameObject = enemy, EnemyType = enemyType, Stats = enemyStats, LastPosition = enemy.transform.position, LastHealth = enemyStats.Health, State = "spawned" }; enemies[text] = value2; EnemySpawnMessage message = new EnemySpawnMessage { EnemyId = text, EnemyType = enemyType, SpawnPosition = enemy.transform.position, Health = enemyStats.Health, Damage = enemyStats.Damage, Level = enemyStats.Level }; NetworkManager.Instance.SendMessage(message); } } public void UpdateEnemyState(GameObject enemy, string state, string targetPlayerId = "") { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Instance.IsHost) { string text = FindEnemyId(enemy); if (!string.IsNullOrEmpty(text)) { EnemyData enemyData = enemies[text]; enemyData.State = state; enemyData.LastPosition = enemy.transform.position; enemyData.LastHealth = GetEnemyCurrentHealth(enemy); EnemyUpdateMessage message = new EnemyUpdateMessage { EnemyId = text, Position = enemy.transform.position, Health = enemyData.LastHealth, State = state, TargetPlayerId = targetPlayerId }; NetworkManager.Instance.SendMessage(message); } } } public void OnEnemyDeath(GameObject enemy) { if (NetworkManager.Instance.IsHost) { string text = FindEnemyId(enemy); if (!string.IsNullOrEmpty(text)) { UpdateEnemyState(enemy, "dead"); ((MonoBehaviour)this).StartCoroutine(RemoveEnemyDelayed(text, 5f)); } } } private void SpawnRemoteEnemy(EnemySpawnMessage message) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) GameObject gameObject = CreateRemoteEnemyVisual(message); EnemyData value = new EnemyData { EnemyId = message.EnemyId, GameObject = gameObject, EnemyType = message.EnemyType, Stats = new EnemyStats { Health = message.Health, Damage = message.Damage, Level = message.Level }, LastPosition = message.SpawnPosition, LastHealth = message.Health, State = "spawned" }; enemies[message.EnemyId] = value; } private void UpdateRemoteEnemy(EnemyUpdateMessage message) { //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) if (enemies.ContainsKey(message.EnemyId)) { EnemyData enemyData = enemies[message.EnemyId]; enemyData.LastPosition = message.Position; enemyData.LastHealth = message.Health; enemyData.State = message.State; if ((Object)(object)enemyData.GameObject != (Object)null) { UpdateRemoteEnemyVisual(enemyData.GameObject, message); } if (message.State == "dead") { HandleRemoteEnemyDeath(enemyData); } } } private EnemyStats GetOriginalEnemyStats(GameObject enemy, string enemyType) { EnemyStats enemyStats = new EnemyStats { Health = 100f, Damage = 10f, Speed = 5f, Level = 1, XPReward = 50 }; Health component = enemy.GetComponent<Health>(); if ((Object)(object)component != (Object)null) { enemyStats.Health = component.maxHealth; } Attack component2 = enemy.GetComponent<Attack>(); if ((Object)(object)component2 != (Object)null) { enemyStats.Damage = component2.damage; } return enemyStats; } private EnemyStats ScaleEnemyStats(EnemyStats originalStats, int playerCount, float scalingFactor) { float num = 1f + (float)(playerCount - 1) * scalingFactor; return new EnemyStats { Health = originalStats.Health * num, Damage = originalStats.Damage * num, Speed = originalStats.Speed, Level = originalStats.Level + (playerCount - 1), XPReward = Mathf.RoundToInt((float)originalStats.XPReward * num) }; } private void ApplyStatsToEnemy(GameObject enemy, EnemyStats stats) { Health component = enemy.GetComponent<Health>(); if ((Object)(object)component != (Object)null) { component.maxHealth = stats.Health; component.currentHealth = stats.Health; } Attack component2 = enemy.GetComponent<Attack>(); if ((Object)(object)component2 != (Object)null) { component2.damage = stats.Damage; } XPReward component3 = enemy.GetComponent<XPReward>(); if ((Object)(object)component3 != (Object)null) { component3.xpAmount = stats.XPReward; } } private GameObject CreateRemoteEnemyVisual(EnemySpawnMessage message) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val).name = "RemoteEnemy_" + message.EnemyId; val.transform.position = message.SpawnPosition; Renderer component = val.GetComponent<Renderer>(); if ((Object)(object)component != (Object)null) { Material val2 = new Material(Shader.Find("Standard")); val2.color = GetEnemyTypeColor(message.EnemyType); component.material = val2; } Collider component2 = val.GetComponent<Collider>(); if ((Object)(object)component2 != (Object)null) { Object.Destroy((Object)(object)component2); } CreateEnemyHealthBar(val, message.Health); return val; } private void UpdateRemoteEnemyVisual(GameObject remoteEnemy, EnemyUpdateMessage message) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)remoteEnemy == (Object)null)) { remoteEnemy.transform.position = Vector3.Lerp(remoteEnemy.transform.position, message.Position, Time.deltaTime * 5f); UpdateEnemyHealthBar(remoteEnemy, message.Health); string state = message.State; if (!(state == "chasing") && !(state == "attacking")) { _ = state == "dead"; } } } private void CreateEnemyHealthBar(GameObject enemy, float maxHealth) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("EnemyHealthBar"); val.transform.SetParent(enemy.transform); val.transform.localPosition = Vector3.up * 2f; GameObject val2 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val2).name = "Background"; val2.transform.SetParent(val.transform); val2.transform.localPosition = Vector3.zero; val2.transform.localScale = new Vector3(2f, 0.2f, 0.1f); Renderer component = val2.GetComponent<Renderer>(); if ((Object)(object)component != (Object)null) { component.material.color = Color.red; } Object.Destroy((Object)(object)val2.GetComponent<Collider>()); GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj).name = "Foreground"; obj.transform.SetParent(val2.transform); obj.transform.localPosition = Vector3.zero; obj.transform.localScale = Vector3.one; Renderer component2 = obj.GetComponent<Renderer>(); if ((Object)(object)component2 != (Object)null) { component2.material.color = Color.green; } Object.Destroy((Object)(object)obj.GetComponent<Collider>()); } private void UpdateEnemyHealthBar(GameObject enemy, float currentHealth) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) Transform val = enemy.transform.Find("EnemyHealthBar/Background/Foreground"); if ((Object)(object)val != (Object)null) { string text = FindEnemyId(enemy); if (!string.IsNullOrEmpty(text) && enemies.ContainsKey(text)) { float health = enemies[text].Stats.Health; float num = currentHealth / health; val.localScale = new Vector3(num, 1f, 1f); } } } private void HandleRemoteEnemyDeath(EnemyData enemyData) { if ((Object)(object)enemyData.GameObject != (Object)null) { ((MonoBehaviour)this).StartCoroutine(DeathAnimation(enemyData.GameObject)); } } [IteratorStateMachine(typeof(<DeathAnimation>d__25))] private IEnumerator DeathAnimation(GameObject enemy) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DeathAnimation>d__25(0) { enemy = enemy }; } [IteratorStateMachine(typeof(<RemoveEnemyDelayed>d__26))] private IEnumerator RemoveEnemyDelayed(string enemyId, float delay) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RemoveEnemyDelayed>d__26(0) { <>4__this = this, enemyId = enemyId, delay = delay }; } private void SyncAllEnemies() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) foreach (EnemyData value in enemies.Values) { if ((Object)(object)value.GameObject != (Object)null) { Vector3 position = value.GameObject.transform.position; float enemyCurrentHealth = GetEnemyCurrentHealth(value.GameObject); if (Vector3.Distance(position, value.LastPosition) > 1f || Mathf.Abs(enemyCurrentHealth - value.LastHealth) > 1f) { UpdateEnemyState(value.GameObject, value.State); } } } } private void RemoveEnemy(string enemyId) { if (enemies.ContainsKey(enemyId)) { if ((Object)(object)enemies[enemyId].GameObject != (Object)null) { Object.Destroy((Object)(object)enemies[enemyId].GameObject); } enemies.Remove(enemyId); } } private string FindEnemyId(GameObject enemy) { return enemies.FirstOrDefault((KeyValuePair<string, EnemyData> kvp) => (Object)(object)kvp.Value.GameObject == (Object)(object)enemy).Key; } private float GetEnemyCurrentHealth(GameObject enemy) { Health component = enemy.GetComponent<Health>(); if (!((Object)(object)component != (Object)null)) { return 100f; } return component.currentHealth; } private Color GetEnemyTypeColor(string enemyType) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) return (Color)(enemyType.ToLower() switch { "goblin" => Color.green, "orc" => Color.red, "skeleton" => Color.white, "boss" => Color.black, _ => Color.gray, }); } public int GetTotalEnemyCount() { return enemies.Count; } public List<EnemyData> GetAllEnemies() { return enemies.Values.ToList(); } public EnemyData GetEnemyData(string enemyId) { if (!enemies.ContainsKey(enemyId)) { return null; } return enemies[enemyId]; } } [Serializable] public class EnemyStats { public float Health; public float Damage; public float Speed; public int Level; public int XPReward; } [Serializable] public class EnemyData { public string EnemyId; public GameObject GameObject; public string EnemyType; public EnemyStats Stats; public Vector3 LastPosition; public float LastHealth; public string State; } public class Health : MonoBehaviour { public float maxHealth = 100f; public float currentHealth = 100f; } public class Attack : MonoBehaviour { public float damage = 10f; } public class XPReward : MonoBehaviour { public int xpAmount = 50; } [HarmonyPatch] public class GamePatches { [HarmonyPatch(typeof(PlayerController), "Update")] [HarmonyPostfix] public static void PlayerController_Update_Postfix(PlayerController __instance) { if ((Object)(object)PlayerSyncManager.Instance != (Object)null) { _ = NetworkManager.Instance.IsConnected; } } [HarmonyPatch(typeof(PlayerController), "Attack")] [HarmonyPostfix] public static void PlayerController_Attack_Postfix(PlayerController __instance, Vector3 targetPosition) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)PlayerSyncManager.Instance != (Object)null) { PlayerSyncManager.Instance.SendPlayerAction("attack", targetPosition); } } [HarmonyPatch(typeof(PlayerController), "UseSkill")] [HarmonyPostfix] public static void PlayerController_UseSkill_Postfix(PlayerController __instance, string skillId, Vector3 targetPosition) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)PlayerSyncManager.Instance != (Object)null) { PlayerSyncManager.Instance.SendPlayerAction("skill", targetPosition, skillId); } } [HarmonyPatch(typeof(ExperienceManager), "AddExperience")] [HarmonyPrefix] public static bool ExperienceManager_AddExperience_Prefix(ExperienceManager __instance, int amount, Vector3 source) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)XPManager.Instance != (Object)null && NetworkManager.Instance.IsConnected) { XPManager.Instance.AddXP(amount, "enemy", source); return false; } return true; } [HarmonyPatch(typeof(EnemySpawner), "SpawnEnemy")] [HarmonyPostfix] public static void EnemySpawner_SpawnEnemy_Postfix(EnemySpawner __instance, GameObject spawnedEnemy, string enemyType) { if ((Object)(object)EnemyScalingManager.Instance != (Object)null && NetworkManager.Instance.IsConnected) { EnemyScalingManager.Instance.RegisterEnemySpawn(spawnedEnemy, enemyType); } } [HarmonyPatch(typeof(Enemy), "Die")] [HarmonyPostfix] public static void Enemy_Die_Postfix(Enemy __instance) { if ((Object)(object)EnemyScalingManager.Instance != (Object)null && NetworkManager.Instance.IsConnected) { EnemyScalingManager.Instance.OnEnemyDeath(((Component)__instance).gameObject); } } [HarmonyPatch(typeof(ChestSpawner), "SpawnChest")] [HarmonyPostfix] public static void ChestSpawner_SpawnChest_Postfix(ChestSpawner __instance, GameObject spawnedChest) { if ((Object)(object)ChestSyncManager.Instance != (Object)null && NetworkManager.Instance.IsConnected) { ChestSyncManager.Instance.RegisterChestSpawn(spawnedChest); } } [HarmonyPatch(typeof(Chest), "Open")] [HarmonyPrefix] public static bool Chest_Open_Prefix(Chest __instance, Player player) { if ((Object)(object)ChestSyncManager.Instance != (Object)null && NetworkManager.Instance.IsConnected) { string playerNetworkId = GetPlayerNetworkId(player); ChestSyncManager.Instance.TryOpenChest(((Component)__instance).gameObject, playerNetworkId); return false; } return true; } [HarmonyPatch(typeof(GameManager), "StartWave")] [HarmonyPostfix] public static void GameManager_StartWave_Postfix(GameManager __instance, int waveNumber) { if (NetworkManager.Instance.IsHost) { GameStateMessage message = new GameStateMessage { GamePhase = "wave_started", Wave = waveNumber, GameTime = Time.time }; NetworkManager.Instance.SendMessage(message); } } [HarmonyPatch(typeof(GameManager), "EndWave")] [HarmonyPostfix] public static void GameManager_EndWave_Postfix(GameManager __instance, int waveNumber) { if (NetworkManager.Instance.IsHost) { GameStateMessage message = new GameStateMessage { GamePhase = "wave_ended", Wave = waveNumber, GameTime = Time.time }; NetworkManager.Instance.SendMessage(message); } } [HarmonyPatch(typeof(MainMenu), "Start")] [HarmonyPostfix] public static void MainMenu_Start_Postfix(MainMenu __instance) { MultiplayerUISimple.Instance?.CreateMainMenuUI(__instance); } private static string GetPlayerNetworkId(Player player) { return SystemInfo.deviceUniqueIdentifier; } } [HarmonyPatch] public class ConditionalPatches { [HarmonyPatch("PlayerMovement", "Move")] [HarmonyPostfix] public static void PlayerMovement_Move_Postfix() { } [HarmonyPatch("ItemManager", "GiveItem")] [HarmonyPostfix] public static void ItemManager_GiveItem_Postfix(string itemId, int quantity) { } } public class PlayerController : MonoBehaviour { public virtual void Update() { } public virtual void Attack(Vector3 targetPosition) { } public virtual void UseSkill(string skillId, Vector3 targetPosition) { } } public class ExperienceManager : MonoBehaviour { public virtual void AddExperience(int amount, Vector3 source) { } } public class EnemySpawner : MonoBehaviour { public virtual GameObject SpawnEnemy(string enemyType) { return null; } } public class Enemy : MonoBehaviour { public virtual void Die() { } } public class ChestSpawner : MonoBehaviour { public virtual GameObject SpawnChest() { return null; } } public class Chest : MonoBehaviour { public virtual void Open(Player player) { } } public class Player : MonoBehaviour { public string playerId; public int gold; public int experience; public int level; } public class GameManager : MonoBehaviour { public virtual void StartWave(int waveNumber) { } public virtual void EndWave(int waveNumber) { } } public class MainMenu : MonoBehaviour { public virtual void Start() { } } [BepInPlugin("com.multibonk.multiplayer", "Megabonk Multiplayer", "1.0.0")] public class MegabonkMultiplayerPlugin : BaseUnityPlugin { public const string PluginGUID = "com.multibonk.multiplayer"; public const string PluginName = "Megabonk Multiplayer"; public const string PluginVersion = "1.0.0"; public static ConfigEntry<int> MaxPlayers; public static ConfigEntry<float> XPShareRate; public static ConfigEntry<float> EnemyScalingFactor; public static ConfigEntry<float> ProximityRange; public static ConfigEntry<int> NetworkPort; public static NetworkManager NetworkManager; public static PlayerSyncManager PlayerSyncManager; public static XPManager XPManager; public static EnemyScalingManager EnemyScalingManager; public static ChestSyncManager ChestSyncManager; private Harmony harmony; private void Awake() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown ((BaseUnityPlugin)this).Logger.LogInfo((object)"Megabonk Multiplayer 1.0.0 is loading..."); InitializeConfig(); InitializeSystems(); harmony = new Harmony("com.multibonk.multiplayer"); harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Megabonk Multiplayer 1.0.0 loaded successfully!"); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } NetworkManager?.Shutdown(); } private void InitializeConfig() { MaxPlayers = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxPlayers", 4, "Maximum number of players (1-4)"); XPShareRate = ((BaseUnityPlugin)this).Config.Bind<float>("Gameplay", "XPShareRate", 1f, "Rate of XP sharing (0.0 = no sharing, 1.0 = full sharing)"); EnemyScalingFactor = ((BaseUnityPlugin)this).Config.Bind<float>("Gameplay", "EnemyScalingFactor", 0.75f, "Enemy scaling factor per additional player"); ProximityRange = ((BaseUnityPlugin)this).Config.Bind<float>("Gameplay", "ProximityRange", 50f, "Distance for player visibility on map"); NetworkPort = ((BaseUnityPlugin)this).Config.Bind<int>("Network", "Port", 25565, "Network port for hosting games"); } private void InitializeSystems() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown GameObject val = new GameObject("NetworkManager"); Object.DontDestroyOnLoad((Object)val); NetworkManager = val.AddComponent<NetworkManager>(); GameObject val2 = new GameObject("PlayerSyncManager"); Object.DontDestroyOnLoad((Object)val2); PlayerSyncManager = val2.AddComponent<PlayerSyncManager>(); GameObject val3 = new GameObject("XPManager"); Object.DontDestroyOnLoad((Object)val3); XPManager = val3.AddComponent<XPManager>(); GameObject val4 = new GameObject("EnemyScalingManager"); Object.DontDestroyOnLoad((Object)val4); EnemyScalingManager = val4.AddComponent<EnemyScalingManager>(); GameObject val5 = new GameObject("ChestSyncManager"); Object.DontDestroyOnLoad((Object)val5); ChestSyncManager = val5.AddComponent<ChestSyncManager>(); GameObject val6 = new GameObject("MultiplayerUI"); Object.DontDestroyOnLoad((Object)val6); val6.AddComponent<MultiplayerUISimple>(); } } public class MultiplayerUISimple : MonoBehaviour { private static MultiplayerUISimple instance; private bool showMultiplayerMenu; private bool showHostPanel; private bool showJoinPanel; private bool showLobbyPanel; private bool showSettings; private int maxPlayers = 4; private float xpShareRate = 1f; private float enemyScalingFactor = 0.75f; private float proximityRange = 50f; private string playerName = "Player"; private string roomCode = ""; private string chatMessage = ""; private Rect windowRect = new Rect((float)(Screen.width / 2 - 200), (float)(Screen.height / 2 - 150), 400f, 300f); private Vector2 scrollPosition = Vector2.zero; public static MultiplayerUISimple Instance => instance; private void Awake() { if ((Object)(object)instance == (Object)null) { instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } else { Object.Destroy((Object)(object)((Component)this).gameObject); } } private void Start() { if ((Object)(object)NetworkManager.Instance != (Object)null) { NetworkManager.Instance.OnMessageReceived += HandleNetworkMessage; NetworkManager.Instance.OnPlayerConnected += OnPlayerConnected; NetworkManager.Instance.OnPlayerDisconnected += OnPlayerDisconnected; } } private void Update() { if (Input.GetKeyDown((KeyCode)109)) { showMultiplayerMenu = !showMultiplayerMenu; } if (Input.GetKeyDown((KeyCode)116)) { _ = NetworkManager.Instance.IsConnected; } } private void OnGUI() { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_017c: 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) GUI.skin.label.fontSize = 14; GUI.skin.button.fontSize = 12; GUI.skin.textField.fontSize = 12; if (showMultiplayerMenu && !NetworkManager.Instance.IsConnected) { windowRect = GUI.Window(0, windowRect, new WindowFunction(MultiplayerMenuWindow), "Multiplayer"); } else if (showHostPanel) { windowRect = GUI.Window(1, windowRect, new WindowFunction(HostPanelWindow), "Host Game"); } else if (showJoinPanel) { windowRect = GUI.Window(2, windowRect, new WindowFunction(JoinPanelWindow), "Join Game"); } else if (showLobbyPanel) { windowRect = GUI.Window(3, windowRect, new WindowFunction(LobbyPanelWindow), "Multiplayer Lobby"); } if (NetworkManager.Instance.IsConnected) { string arg = (NetworkManager.Instance.IsHost ? "Hosting" : "Connected"); int connectedPlayerCount = NetworkManager.Instance.ConnectedPlayerCount; GUI.Label(new Rect(10f, 10f, 200f, 20f), $"{arg} - Players: {connectedPlayerCount}/{maxPlayers}"); DrawSimpleChat(); } GUI.Label(new Rect(10f, (float)(Screen.height - 30), 300f, 20f), "Press M to open Multiplayer menu"); } private void MultiplayerMenuWindow(int windowID) { GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); GUILayout.Label("Megabonk Multiplayer", GUI.skin.label, Array.Empty<GUILayoutOption>()); GUILayout.Space(10f); if (GUILayout.Button("Host Game", Array.Empty<GUILayoutOption>())) { showMultiplayerMenu = false; showHostPanel = true; } if (GUILayout.Button("Join Game", Array.Empty<GUILayoutOption>())) { showMultiplayerMenu = false; showJoinPanel = true; } GUILayout.Space(10f); if (GUILayout.Button("Close", Array.Empty<GUILayoutOption>())) { showMultiplayerMenu = false; } GUILayout.EndVertical(); GUI.DragWindow(); } private void HostPanelWindow(int windowID) { GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); GUILayout.Label("Host Game Settings", GUI.skin.label, Array.Empty<GUILayoutOption>()); GUILayout.Space(10f); GUILayout.Label("Player Name:", Array.Empty<GUILayoutOption>()); playerName = GUILayout.TextField(playerName, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Max Players: {maxPlayers}", Array.Empty<GUILayoutOption>()); maxPlayers = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)maxPlayers, 2f, 4f, Array.Empty<GUILayoutOption>())); GUILayout.Label($"XP Share Rate: {xpShareRate * 100f:F0}%", Array.Empty<GUILayoutOption>()); xpShareRate = GUILayout.HorizontalSlider(xpShareRate, 0f, 1f, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Enemy Scaling: {enemyScalingFactor * 100f:F0}%", Array.Empty<GUILayoutOption>()); enemyScalingFactor = GUILayout.HorizontalSlider(enemyScalingFactor, 0f, 1f, Array.Empty<GUILayoutOption>()); GUILayout.Space(10f); if (GUILayout.Button("Start Hosting", Array.Empty<GUILayoutOption>())) { StartHosting(); } if (GUILayout.Button("Back", Array.Empty<GUILayoutOption>())) { showHostPanel = false; showMultiplayerMenu = true; } GUILayout.EndVertical(); GUI.DragWindow(); } private void JoinPanelWindow(int windowID) { GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); GUILayout.Label("Join Game", GUI.skin.label, Array.Empty<GUILayoutOption>()); GUILayout.Space(10f); GUILayout.Label("Player Name:", Array.Empty<GUILayoutOption>()); playerName = GUILayout.TextField(playerName, Array.Empty<GUILayoutOption>()); GUILayout.Label("Host IP Address:", Array.Empty<GUILayoutOption>()); roomCode = GUILayout.TextField(roomCode, Array.Empty<GUILayoutOption>()); GUILayout.Space(10f); if (GUILayout.Button("Join Game", Array.Empty<GUILayoutOption>())) { JoinGame(); } if (GUILayout.Button("Back", Array.Empty<GUILayoutOption>())) { showJoinPanel = false; showMultiplayerMenu = true; } GUILayout.EndVertical(); GUI.DragWindow(); } private void LobbyPanelWindow(int windowID) { GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); GUILayout.Label("Multiplayer Lobby", GUI.skin.label, Array.Empty<GUILayoutOption>()); GUILayout.Space(10f); string text = (NetworkManager.Instance.IsHost ? "Hosting Game" : "Connected to Host"); GUILayout.Label("Status: " + text, Array.Empty<GUILayoutOption>()); int connectedPlayerCount = NetworkManager.Instance.ConnectedPlayerCount; GUILayout.Label($"Players: {connectedPlayerCount}/{maxPlayers}", Array.Empty<GUILayoutOption>()); GUILayout.Space(10f); if (NetworkManager.Instance.IsHost) { if (GUILayout.Button(showSettings ? "Hide Settings" : "Game Settings", Array.Empty<GUILayoutOption>())) { showSettings = !showSettings; } if (showSettings) { GUILayout.Label("--- Game Settings ---", Array.Empty<GUILayoutOption>()); GUILayout.Label($"Max Players: {maxPlayers}", Array.Empty<GUILayoutOption>()); int num = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)maxPlayers, 2f, 4f, Array.Empty<GUILayoutOption>())); GUILayout.Label($"XP Share Rate: {xpShareRate * 100f:F0}%", Array.Empty<GUILayoutOption>()); float num2 = GUILayout.HorizontalSlider(xpShareRate, 0f, 1f, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Enemy Scaling: {enemyScalingFactor * 100f:F0}%", Array.Empty<GUILayoutOption>()); float num3 = GUILayout.HorizontalSlider(enemyScalingFactor, 0f, 1f, Array.Empty<GUILayoutOption>()); if (num != maxPlayers || num2 != xpShareRate || num3 != enemyScalingFactor) { maxPlayers = num; xpShareRate = num2; enemyScalingFactor = num3; ApplySettings(); } } GUILayout.Space(10f); if (GUILayout.Button("Start Game", Array.Empty<GUILayoutOption>())) { StartGame(); } } GUILayout.Space(10f); if (GUILayout.Button("Leave Game", Array.Empty<GUILayoutOption>())) { LeaveGame(); } GUILayout.EndVertical(); GUI.DragWindow(); } private void DrawSimpleChat() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Invalid comparison between Unknown and I4 //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Invalid comparison between Unknown and I4 GUI.Box(new Rect(10f, (float)(Screen.height - 120), 300f, 80f), ""); Rect val = default(Rect); ((Rect)(ref val))..ctor(15f, (float)(Screen.height - 35), 200f, 20f); chatMessage = GUI.TextField(val, chatMessage); if (GUI.Button(new Rect(220f, (float)(Screen.height - 35), 50f, 20f), "Send") || ((int)Event.current.type == 4 && (int)Event.current.keyCode == 13 && GUI.GetNameOfFocusedControl() == "ChatInput")) { SendChatMessage(); } GUI.SetNextControlName("ChatInput"); } private void StartHosting() { MegabonkMultiplayerPlugin.MaxPlayers.Value = maxPlayers; MegabonkMultiplayerPlugin.XPShareRate.Value = xpShareRate; MegabonkMultiplayerPlugin.EnemyScalingFactor.Value = enemyScalingFactor; if (NetworkManager.Instance.StartHost()) { showHostPanel = false; showLobbyPanel = true; Debug.Log((object)"Started hosting multiplayer game"); } } private void JoinGame() { if (!string.IsNullOrEmpty(roomCode) && NetworkManager.Instance.ConnectToHost(roomCode)) { showJoinPanel = false; showLobbyPanel = true; Debug.Log((object)("Connecting to host: " + roomCode)); } } private void StartGame() { if (NetworkManager.Instance.IsHost) { GameStateMessage message = new GameStateMessage { GamePhase = "starting", GameTime = Time.time }; NetworkManager.Instance.SendMessage(message); showLobbyPanel = false; Debug.Log((object)"Starting multiplayer game"); } } private void LeaveGame() { NetworkManager.Instance.Shutdown(); showLobbyPanel = false; showMultiplayerMenu = true; Debug.Log((object)"Left multiplayer game"); } private void ApplySettings() { if (NetworkManager.Instance.IsHost) { MegabonkMultiplayerPlugin.MaxPlayers.Value = maxPlayers; MegabonkMultiplayerPlugin.XPShareRate.Value = xpShareRate; MegabonkMultiplayerPlugin.EnemyScalingFactor.Value = enemyScalingFactor; SettingsUpdateMessage message = new SettingsUpdateMessage { MaxPlayers = maxPlayers, XPShareRate = xpShareRate, EnemyScalingFactor = enemyScalingFactor, ProximityRange = proximityRange }; NetworkManager.Instance.SendMessage(message); Debug.Log((object)"Settings updated and synced to all players"); } } private void SendChatMessage() { if (!string.IsNullOrEmpty(chatMessage)) { ChatMessage message = new ChatMessage { PlayerName = playerName, Message = chatMessage, ChatType = "all" }; NetworkManager.Instance.SendMessage(message); chatMessage = ""; } } private void HandleNetworkMessage(NetworkMessage message) { switch (message.MessageType) { case "ChatMessage": HandleChatMessage(message as ChatMessage); break; case "GameStateMessage": HandleGameStateMessage(message as GameStateMessage); break; case "SettingsUpdateMessage": HandleSettingsUpdateMessage(message as SettingsUpdateMessage); break; } } private void HandleChatMessage(ChatMessage message) { Debug.Log((object)("[CHAT] " + message.PlayerName + ": " + message.Message)); } private void HandleGameStateMessage(GameStateMessage message) { if (message.GamePhase == "starting") { showLobbyPanel = false; Debug.Log((object)"Game starting!"); } } private void HandleSettingsUpdateMessage(SettingsUpdateMessage message) { if (!NetworkManager.Instance.IsHost) { maxPlayers = message.MaxPlayers; xpShareRate = message.XPShareRate; enemyScalingFactor = message.EnemyScalingFactor; proximityRange = message.ProximityRange; MegabonkMultiplayerPlugin.MaxPlayers.Value = maxPlayers; MegabonkMultiplayerPlugin.XPShareRate.Value = xpShareRate; MegabonkMultiplayerPlugin.EnemyScalingFactor.Value = enemyScalingFactor; MegabonkMultiplayerPlugin.ProximityRange.Value = proximityRange; Debug.Log((object)"Settings updated by host"); } } private void OnPlayerConnected(string playerId) { Debug.Log((object)("Player " + playerId.Substring(0, 8) + " connected")); } private void OnPlayerDisconnected(string playerId) { Debug.Log((object)("Player " + playerId.Substring(0, 8) + " disconnected")); } public void CreateMainMenuUI(object mainMenu) { Debug.Log((object)"Multiplayer UI initialized - Press M to open menu"); } } public class NetworkManager : MonoBehaviour { public enum NetworkRole { None, Host, Client } private NetworkRole currentRole; private TcpListener server; private TcpClient client; private List<ClientConnection> connectedClients = new List<ClientConnection>(); private Thread serverThread; private bool isRunning; private Queue<NetworkMessage> incomingMessages = new Queue<NetworkMessage>(); private Queue<NetworkMessage> outgoingMessages = new Queue<NetworkMessage>(); public static NetworkManager Instance { get; private set; } public bool IsHost => currentRole == NetworkRole.Host; public bool IsClient => currentRole == NetworkRole.Client; public bool IsConnected { get { if (isRunning) { if (!IsHost) { if (IsClient) { return client?.Connected ?? false; } return false; } return true; } return false; } } public int ConnectedPlayerCount { get { if (!IsHost) { if (!IsConnected) { return 1; } return 2; } return connectedClients.Count + 1; } } public event Action<NetworkMessage> OnMessageReceived; public event Action<string> OnPlayerConnected; public event Action<string> OnPlayerDisconnected; private void Awake() { if ((Object)(object)Instance == (Object)null) { Instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } else { Object.Destroy((Object)(object)((Component)this).gameObject); } } private void Update() { ProcessIncomingMessages(); ProcessOutgoingMessages(); } public bool StartHost(int port = 25565) { try { currentRole = NetworkRole.Host; server = new TcpListener(IPAddress.Any, port); server.Start(); isRunning = true; serverThread = new Thread(ServerLoop); serverThread.Start(); Debug.Log((object)$"Server started on port {port}"); return true; } catch (Exception ex) { Debug.LogError((object)("Failed to start server: " + ex.Message)); return false; } } public bool ConnectToHost(string ipAddress, int port = 25565) { try { currentRole = NetworkRole.Client; client = new TcpClient(); client.Connect(ipAddress, port); isRunning = true; new Thread(ClientLoop).Start(); Debug.Log((object)$"Connected to server at {ipAddress}:{port}"); return true; } catch (Exception ex) { Debug.LogError((object)("Failed to connect to server: " + ex.Message)); return false; } } private void ServerLoop() { while (isRunning) { try { if (server.Pending()) { TcpClient tcpClient = server.AcceptTcpClient(); if (connectedClients.Count < MegabonkMultiplayerPlugin.MaxPlayers.Value - 1) { string text = Guid.NewGuid().ToString(); ClientConnection connection = new ClientConnection(text, tcpClient); connectedClients.Add(connection); new Thread((ThreadStart)delegate { HandleClient(connection); }).Start(); this.OnPlayerConnected?.Invoke(text); BroadcastMessage(new PlayerConnectedMessage { PlayerId = text }); } else { tcpClient.Close(); } } Thread.Sleep(10); } catch (Exception ex) { Debug.LogError((object)("Server loop error: " + ex.Message)); } } } private void ClientLoop() { NetworkStream stream = client.GetStream(); byte[] array = new byte[4096]; while (isRunning && client.Connected) { try { if (stream.DataAvailable) { int count = stream.Read(array, 0, array.Length); NetworkMessage item = JsonConvert.DeserializeObject<NetworkMessage>(Encoding.UTF8.GetString(array, 0, count)); lock (incomingMessages) { incomingMessages.Enqueue(item); } } Thread.Sleep(10); } catch (Exception ex) { Debug.LogError((object)("Client loop error: " + ex.Message)); break; } } } private void HandleClient(ClientConnection connection) { NetworkStream stream = connection.TcpClient.GetStream(); byte[] array = new byte[4096]; while (isRunning && connection.TcpClient.Connected) { try { if (stream.DataAvailable) { int count = stream.Read(array, 0, array.Length); NetworkMessage networkMessage = JsonConvert.DeserializeObject<NetworkMessage>(Encoding.UTF8.GetString(array, 0, count)); networkMessage.SenderId = connection.ClientId; lock (incomingMessages) { incomingMessages.Enqueue(networkMessage); } BroadcastMessage(networkMessage, connection.ClientId); } Thread.Sleep(10); } catch (Exception ex) { Debug.LogError((object)("Client handler error: " + ex.Message)); break; } } connectedClients.Remove(connection); this.OnPlayerDisconnected?.Invoke(connection.ClientId); BroadcastMessage(new PlayerDisconnectedMessage { PlayerId = connection.ClientId }); } public void SendMessage(NetworkMessage message) { lock (outgoingMessages) { outgoingMessages.Enqueue(message); } } private void BroadcastMessage(NetworkMessage message, string excludeClientId = null) { string s = JsonConvert.SerializeObject((object)message); byte[] bytes = Encoding.UTF8.GetBytes(s); foreach (ClientConnection connectedClient in connectedClients) { if (connectedClient.ClientId != excludeClientId) { try { connectedClient.TcpClient.GetStream().Write(bytes, 0, bytes.Length); } catch (Exception ex) { Debug.LogError((object)("Failed to send message to client " + connectedClient.ClientId + ": " + ex.Message)); } } } } private void ProcessIncomingMessages() { lock (incomingMessages) { while (incomingMessages.Count > 0) { NetworkMessage obj = incomingMessages.Dequeue(); this.OnMessageReceived?.Invoke(obj); } } } private void ProcessOutgoingMessages() { lock (outgoingMessages) { while (outgoingMessages.Count > 0) { NetworkMessage networkMessage = outgoingMessages.Dequeue(); if (currentRole == NetworkRole.Host) { BroadcastMessage(networkMessage); } else if (currentRole == NetworkRole.Client && client != null && client.Connected) { try { string s = JsonConvert.SerializeObject((object)networkMessage); byte[] bytes = Encoding.UTF8.GetBytes(s); client.GetStream().Write(bytes, 0, bytes.Length); } catch (Exception ex) { Debug.LogError((object)("Failed to send message to server: " + ex.Message)); } } } } } public void Shutdown() { isRunning = false; if (server != null) { server.Stop(); } if (client != null) { client.Close(); } foreach (ClientConnection connectedClient in connectedClients) { connectedClient.TcpClient.Close(); } connectedClients.Clear(); currentRole = NetworkRole.None; } } public class ClientConnection { public string ClientId { get; } public TcpClient TcpClient { get; } public ClientConnection(string clientId, TcpClient tcpClient) { ClientId = clientId; TcpClient = tcpClient; } } [Serializable] public abstract class NetworkMessage { public string MessageType { get; set; } public string SenderId { get; set; } public float Timestamp { get; set; } protected NetworkMessage() { MessageType = GetType().Name; Timestamp = Time.time; } } [Serializable] public class PlayerPositionMessage : NetworkMessage { public Vector3 Position { get; set; } public Vector3 Velocity { get; set; } public float Rotation { get; set; } public string AnimationState { get; set; } } [Serializable] public class PlayerActionMessage : NetworkMessage { public string ActionType { get; set; } public Vector3 TargetPosition { get; set; } public string SkillId { get; set; } public float ActionData { get; set; } } [Serializable] public class XPGainedMessage : NetworkMessage { public int XPAmount { get; set; } public string Source { get; set; } public Vector3 SourcePosition { get; set; } } [Serializable] public class EnemySpawnMessage : NetworkMessage { public string EnemyId { get; set; } public string EnemyType { get; set; } public Vector3 SpawnPosition { get; set; } public float Health { get; set; } public float Damage { get; set; } public int Level { get; set; } } [Serializable] public class EnemyUpdateMessage : NetworkMessage { public string EnemyId { get; set; } public Vector3 Position { get; set; } public float Health { get; set; } public string State { get; set; } public string TargetPlayerId { get; set; } } [Serializable] public class ChestSpawnMessage : NetworkMessage { public string ChestId { get; set; } public Vector3 Position { get; set; } public string ChestType { get; set; } public int Cost { get; set; } public string[] Items { get; set; } } [Serializable] public class ChestOpenedMessage : NetworkMessage { public string ChestId { get; set; } public string OpenedByPlayerId { get; set; } public string[] ItemsReceived { get; set; } } [Serializable] public class PlayerConnectedMessage : NetworkMessage { public string PlayerId { get; set; } public string PlayerName { get; set; } public int PlayerLevel { get; set; } public Vector3 SpawnPosition { get; set; } } [Serializable] public class PlayerDisconnectedMessage : NetworkMessage { public string PlayerId { get; set; } } [Serializable] public class GameStateMessage : NetworkMessage { public string GamePhase { get; set; } public float GameTime { get; set; } public int Wave { get; set; } public int TotalPlayersAlive { get; set; } } [Serializable] public class PlayerStatsMessage : NetworkMessage { public int Level { get; set; } public int CurrentXP { get; set; } public int XPToNextLevel { get; set; } public float Health { get; set; } public float MaxHealth { get; set; } public float Mana { get; set; } public float MaxMana { get; set; } public int Gold { get; set; } } [Serializable] public class ChatMessage : NetworkMessage { public string PlayerName { get; set; } public string Message { get; set; } public string ChatType { get; set; } } [Serializable] public class PingMessage : NetworkMessage { public float ClientTime { get; set; } } [Serializable] public class PongMessage : NetworkMessage { public float ClientTime { get; set; } public float ServerTime { get; set; } } [Serializable] public class SettingsUpdateMessage : NetworkMessage { public int MaxPlayers { get; set; } public float XPShareRate { get; set; } public float EnemyScalingFactor { get; set; } public float ProximityRange { get; set; } } public class PlayerSyncManager : MonoBehaviour { private Dictionary<string, RemotePlayer> remotePlayers = new Dictionary<string, RemotePlayer>(); private float lastSyncTime; private const float SYNC_INTERVAL = 0.1f; private const float INTERPOLATION_RATE = 10f; public static PlayerSyncManager Instance { get; private set; } private void Awake() { Instance = this; } private void Start() { if ((Object)(object)NetworkManager.Instance != (Object)null) { NetworkManager.Instance.OnMessageReceived += HandleNetworkMessage; NetworkManager.Instance.OnPlayerConnected += OnPlayerConnected; NetworkManager.Instance.OnPlayerDisconnected += OnPlayerDisconnected; } } private void Update() { if (Time.time - lastSyncTime >= 0.1f && NetworkManager.Instance.IsConnected) { SendPlayerPosition(); lastSyncTime = Time.time; } InterpolateRemotePlayers(); } private void SendPlayerPosition() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) GameObject localPlayer = GetLocalPlayer(); if (!((Object)(object)localPlayer == (Object)null)) { PlayerPositionMessage obj = new PlayerPositionMessage { Position = localPlayer.transform.position, Velocity = GetPlayerVelocity(localPlayer) }; Quaternion rotation = localPlayer.transform.rotation; obj.Rotation = ((Quaternion)(ref rotation)).eulerAngles.y; obj.AnimationState = GetPlayerAnimationState(localPlayer); PlayerPositionMessage message = obj; NetworkManager.Instance.SendMessage(message); } } private void HandleNetworkMessage(NetworkMessage message) { switch (message.MessageType) { case "PlayerPositionMessage": HandlePlayerPositionMessage(message as PlayerPositionMessage); break; case "PlayerActionMessage": HandlePlayerActionMessage(message as PlayerActionMessage); break; case "PlayerStatsMessage": HandlePlayerStatsMessage(message as PlayerStatsMessage); break; } } private void HandlePlayerPositionMessage(PlayerPositionMessage message) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) if (!(message.SenderId == GetLocalPlayerId())) { if (!remotePlayers.ContainsKey(message.SenderId)) { CreateRemotePlayer(message.SenderId); } RemotePlayer remotePlayer = remotePlayers[message.SenderId]; remotePlayer.UpdatePosition(message.Position, message.Velocity, message.Rotation); remotePlayer.SetAnimationState(message.AnimationState); } } private void HandlePlayerActionMessage(PlayerActionMessage message) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!(message.SenderId == GetLocalPlayerId()) && remotePlayers.ContainsKey(message.SenderId)) { remotePlayers[message.SenderId].PerformAction(message.ActionType, message.TargetPosition, message.SkillId, message.ActionData); } } private void HandlePlayerStatsMessage(PlayerStatsMessage message) { if (!(message.SenderId == GetLocalPlayerId()) && remotePlayers.ContainsKey(message.SenderId)) { remotePlayers[message.SenderId].UpdateStats(message); } } private void OnPlayerConnected(string playerId) { Debug.Log((object)("Player connected: " + playerId)); CreateRemotePlayer(playerId); } private void OnPlayerDisconnected(string playerId) { Debug.Log((object)("Player disconnected: " + playerId)); if (remotePlayers.ContainsKey(playerId)) { Object.Destroy((Object)(object)((Component)remotePlayers[playerId]).gameObject); remotePlayers.Remove(playerId); } } private void CreateRemotePlayer(string playerId) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!remotePlayers.ContainsKey(playerId)) { RemotePlayer remotePlayer = new GameObject("RemotePlayer_" + playerId).AddComponent<RemotePlayer>(); remotePlayer.Initialize(playerId); remotePlayers[playerId] = remotePlayer; } } private void InterpolateRemotePlayers() { foreach (RemotePlayer value in remotePlayers.Values) { value.InterpolatePosition(10f); } } public void SendPlayerAction(string actionType, Vector3 targetPosition, string skillId = "", float actionData = 0f) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) PlayerActionMessage message = new PlayerActionMessage { ActionType = actionType, TargetPosition = targetPosition, SkillId = skillId, ActionData = actionData }; NetworkManager.Instance.SendMessage(message); } public void SendPlayerStats() { GameObject localPlayer = GetLocalPlayer(); if (!((Object)(object)localPlayer == (Object)null)) { PlayerStatsMessage message = new PlayerStatsMessage { Level = GetPlayerLevel(localPlayer), CurrentXP = GetPlayerCurrentXP(localPlayer), XPToNextLevel = GetPlayerXPToNextLevel(localPlayer), Health = GetPlayerHealth(localPlayer), MaxHealth = GetPlayerMaxHealth(localPlayer), Mana = GetPlayerMana(localPlayer), MaxMana = GetPlayerMaxMana(localPlayer), Gold = GetPlayerGold(localPlayer) }; NetworkManager.Instance.SendMessage(message); } } public List<RemotePlayer> GetRemotePlayersInRange(Vector3 position, float range) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return remotePlayers.Values.Where((RemotePlayer player) => Vector3.Distance(((Component)player).transform.position, position) <= range).ToList(); } public int GetTotalPlayerCount() { return remotePlayers.Count + 1; } private GameObject GetLocalPlayer() { return GameObject.FindWithTag("Player"); } private string GetLocalPlayerId() { return SystemInfo.deviceUniqueIdentifier; } private Vector3 GetPlayerVelocity(GameObject player) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) Rigidbody component = player.GetComponent<Rigidbody>(); if (!((Object)(object)component != (Object)null)) { return Vector3.zero; } return component.velocity; } private string GetPlayerAnimationState(GameObject player) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //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) Animator component = player.GetComponent<Animator>(); if ((Object)(object)component != (Object)null) { AnimatorStateInfo currentAnimatorStateInfo = component.GetCurrentAnimatorStateInfo(0); if (!((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("Walk")) { currentAnimatorStateInfo = component.GetCurrentAnimatorStateInfo(0); if (!((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("Attack")) { return "idle"; } return "attacking"; } return "walking"; } return "idle"; } private int GetPlayerLevel(GameObject player) { return 1; } private int GetPlayerCurrentXP(GameObject player) { return 0; } private int GetPlayerXPToNextLevel(GameObject player) { return 100; } private float GetPlayerHealth(GameObject player) { return 100f; } private float GetPlayerMaxHealth(GameObject player) { return 100f; } private float GetPlayerMana(GameObject player) { return 50f; } private float GetPlayerMaxMana(GameObject player) { return 50f; } private int GetPlayerGold(GameObject player) { return 0; } } public class RemotePlayer : MonoBehaviour { [CompilerGenerated] private sealed class <PlayAttackEffect>d__30 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public RemotePlayer <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PlayAttackEffect>d__30(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown int num = <>1__state; RemotePlayer remotePlayer = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; remotePlayer.SetAnimationState("attacking"); <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; case 1: <>1__state = -1; remotePlayer.SetAnimationState("idle"); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <PlayJumpEffect>d__32 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public RemotePlayer <>4__this; private Vector3 <originalPos>5__2; private float <jumpHeight>5__3; private float <jumpDuration>5__4; private float <t>5__5; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PlayJumpEffect>d__32(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; RemotePlayer remotePlayer = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <originalPos>5__2 = ((Component)remotePlayer).transform.position; <jumpHeight>5__3 = 2f; <jumpDuration>5__4 = 0.5f; <t>5__5 = 0f; break; case 1: <>1__state = -1; <t>5__5 += Time.deltaTime; break; } if (<t>5__5 < <jumpDuration>5__4) { float num2 = Mathf.Sin(<t>5__5 / <jumpDuration>5__4 * MathF.PI) * <jumpHeight>5__3; ((Component)remotePlayer).transform.position = <originalPos>5__2 + Vector3.up * num2; <>2__current = null; <>1__state = 1; return true; } ((Component)remotePlayer).transform.position = <originalPos>5__2; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <PlaySkillEffect>d__31 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PlaySkillEffect>d__31(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private Vector3 targetPosition; private Vector3 targetVelocity; private float targetRotation; private string currentAnimationState; private GameObject playerModel; private Animator animator; private int level = 1; private float health = 100f; private float maxHealth = 100f; private float mana = 50f; private float maxMana = 50f; private int gold; private bool isVisible = true; private float lastVisibilityCheck; private const float VISIBILITY_CHECK_INTERVAL = 0.5f; public string PlayerId { get; private set; } public void Initialize(string playerId) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) PlayerId = playerId; targetPosition = ((Component)this).transform.position; CreatePlayerModel(); CreateNameplate(); SetupComponents(); } private void Update() { CheckVisibility(); UpdateNameplate(); } private void CreatePlayerModel() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) playerModel = GameObject.CreatePrimitive((PrimitiveType)1); playerModel.transform.SetParent(((Component)this).transform); playerModel.transform.localPosition = Vector3.zero; Renderer component = playerModel.GetComponent<Renderer>(); if ((Object)(object)component != (Object)null) { Material val = new Material(Shader.Find("Standard")); val.color = GetPlayerColor(PlayerId); component.material = val; } Collider component2 = playerModel.GetComponent<Collider>(); if ((Object)(object)component2 != (Object)null) { Object.Destroy((Object)(object)component2); } animator = playerModel.AddComponent<Animator>(); } private void CreateNameplate() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Nameplate"); val.transform.SetParent(((Component)this).transform); val.transform.localPosition = Vector3.up * 2.5f; TextMesh obj = val.AddComponent<TextMesh>(); obj.text = "Player " + PlayerId.Substring(0, 8); obj.fontSize = 20; obj.color = Color.white; obj.anchor = (TextAnchor)4; val.transform.rotation = Quaternion.LookRotation(Vector3.forward); CreateSimpleHealthBar(val); } private void CreateSimpleHealthBar(GameObject parent) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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) GameObject val = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val).name = "HealthBarBG"; val.transform.SetParent(parent.transform); val.transform.localPosition = new Vector3(0f, -0.5f, 0f); val.transform.localScale = new Vector3(2f, 0.2f, 0.1f); Renderer component = val.GetComponent<Renderer>(); if ((Object)(object)component != (Object)null) { component.material.color = Color.red; } Object.Destroy((Object)(object)val.GetComponent<Collider>()); GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj).name = "HealthBarFG"; obj.transform.SetParent(val.transform); obj.transform.localPosition = Vector3.zero; obj.transform.localScale = Vector3.one; Renderer component2 = obj.GetComponent<Renderer>(); if ((Object)(object)component2 != (Object)null) { component2.material.color = Color.green; } Object.Destroy((Object)(object)obj.GetComponent<Collider>()); } private void SetupComponents() { ((Component)this).gameObject.layer = LayerMask.NameToLayer("UI"); } public void UpdatePosition(Vector3 position, Vector3 velocity, float rotation) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) targetPosition = position; targetVelocity = velocity; targetRotation = rotation; } public void InterpolatePosition(float interpolationRate) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0064: Unknown result type (might be due to invalid IL or missing references) ((Component)this).transform.position = Vector3.Lerp(((Component)this).transform.position, targetPosition, Time.deltaTime * interpolationRate); Quaternion rotation = ((Component)this).transform.rotation; float num = Mathf.LerpAngle(((Quaternion)(ref rotation)).eulerAngles.y, targetRotation, Time.deltaTime * interpolationRate); ((Component)this).transform.rotation = Quaternion.Euler(0f, num, 0f); } public void SetAnimationState(string animationState) { if (currentAnimationState != animationState) { currentAnimationState = animationState; UpdateAnimation(); } } private void UpdateAnimation() { if ((Object)(object)animator == (Object)null) { return; } string text = currentAnimationState; if (!(text == "walking")) { if (text == "attacking") { animator.SetBool("IsWalking", false); animator.SetBool("IsAttacking", true); } else { animator.SetBool("IsWalking", false); animator.SetBool("IsAttacking", false); } } else { animator.SetBool("IsWalking", true); animator.SetBool("IsAttacking", false); } } public void PerformAction(string actionType, Vector3 targetPos, string skillId, float actionData) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) switch (actionType) { case "attack": ((MonoBehaviour)this).StartCoroutine(PlayAttackEffect(targetPos)); break; case "skill": ((MonoBehaviour)this).StartCoroutine(PlaySkillEffect(skillId, targetPos)); break; case "jump": ((MonoBehaviour)this).StartCoroutine(PlayJumpEffect()); break; } } [IteratorStateMachine(typeof(<PlayAttackEffect>d__30))] private IEnumerator PlayAttackEffect(Vector3 targetPos) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PlayAttackEffect>d__30(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<PlaySkillEffect>d__31))] private IEnumerator PlaySkillEffect(string skillId, Vector3 targetPos) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PlaySkillEffect>d__31(0); } [IteratorStateMachine(typeof(<PlayJumpEffect>d__32))] private IEnumerator PlayJumpEffect() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PlayJumpEffect>d__32(0) { <>4__this = this }; } public void UpdateStats(PlayerStatsMessage stats) { level = stats.Level; health = stats.Health; maxHealth = stats.MaxHealth; mana = stats.Mana; maxMana = stats.MaxMana; gold = stats.Gold; UpdateHealthBar(); } private void UpdateHealthBar() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Component)this).transform.Find("Nameplate/HealthBarBG/HealthBarFG"); if ((Object)(object)val != (Object)null) { float num = health / maxHealth; val.localScale = new Vector3(num, 1f, 1f); } } private void CheckVisibility() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (Time.time - lastVisibilityCheck < 0.5f) { return; } lastVisibilityCheck = Time.time; GameObject val = GameObject.FindWithTag("Player"); if (!((Object)(object)val == (Object)null)) { bool flag = Vector3.Distance(((Component)this).transform.position, val.transform.position) <= MegabonkMultiplayerPlugi