using Harmony; using KCM.Enums; using KCM.Packets; using KCM.Packets.Handlers; using KCM.Packets.Lobby; using KCM.Packets.Network; using Riptide; using Steamworks; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using UnityEngine; using static KCM.KCServer; namespace KCM { public class KCClient : MonoBehaviour { public static Client client; public string Name { get; set; } public static KCClient inst { get; set; } static KCClient() { InitializeClient(); } private static void InitializeClient() { // Clean up old client if exists if (client != null) { if (client.IsConnected || client.IsConnecting) { client.Disconnect(); } // Unsubscribe from old events client.Connected -= Client_Connected; client.ConnectionFailed -= Client_ConnectionFailed; client.Disconnected -= Client_Disconnected; client.MessageReceived -= PacketHandler.HandlePacket; } // Create new client instance client = new Client(Main.steamClient); // Set a higher timeout to prevent frequent disconnections client.TimeoutTime = 15000; // 15 seconds instead of default 5 seconds // Subscribe to events client.Connected += Client_Connected; client.ConnectionFailed += Client_ConnectionFailed; client.Disconnected += Client_Disconnected; client.MessageReceived += PacketHandler.HandlePacket; } private static void Client_Disconnected(object sender, DisconnectedEventArgs e) { Main.helper.Log($"Client disconnected event start - Reason: {e.Reason}"); try { // Clean up client state Main.clientSteamIds.Clear(); // Only show modal if disconnect was unexpected (not voluntary) bool wasVoluntary = e.Reason == DisconnectReason.Disconnected; if (e.Message != null) { Main.helper.Log("Processing disconnect message..."); MessageReceivedEventArgs eargs = new MessageReceivedEventArgs(null, (ushort)Enums.Packets.ShowModal, e.Message); if (eargs.MessageId == (ushort)Enums.Packets.ShowModal) { ShowModal modalPacket = (ShowModal)PacketHandler.DeserialisePacket(eargs); modalPacket.HandlePacketClient(); } } else if (!wasVoluntary) { // Only show error modal for unexpected disconnections Main.helper.Log("Showing disconnect modal to user"); GameState.inst.SetNewMode(GameState.inst.mainMenuMode); ModalManager.ShowModal("Disconnected from Server", ErrorCodeMessages.GetMessage(e.Reason), "Okay", true, () => { Main.TransitionTo(MenuState.ServerBrowser); }); } else { Main.helper.Log("Voluntary disconnect - no modal shown"); } } catch (Exception ex) { Main.helper.Log("Error handling disconnection message:"); Main.helper.Log(ex.Message); Main.helper.Log(ex.StackTrace); } Main.helper.Log("Client disconnected event end"); } private static void Client_ConnectionFailed(object sender, ConnectionFailedEventArgs e) { Main.helper.Log($"Connection failed: {e.Reason}"); ModalManager.ShowModal("Failed to connect", ErrorCodeMessages.GetMessage(e.Reason)); } private static void Client_Connected(object sender, EventArgs e) { } public KCClient(string name) { Name = name; } public static void Connect(string ip) { Main.helper.Log("Trying to connect to: " + ip); // Reinitialize client to ensure clean state before connecting InitializeClient(); client.Connect(ip, maxConnectionAttempts: 10, useMessageHandlers: false); } private void Update() { client.Update(); } private void Preload(KCModHelper helper) { helper.Log("Preload run in client"); } private void SceneLoaded(KCModHelper helper) { } } }