using System; using System.Collections.Generic; using System.Net.Sockets; using System.Text; using System.Threading; using Avalonia.Controls; using Avalonia.Threading; using DiscordRPC; using MafiaCommon.Packets; using MafiaCommon; namespace MafiaClient { public class ServerConnection { private readonly string _host = "localhost"; private readonly int _port = 25743; private readonly Socket _socket; private readonly Thread _thread; private bool _breakFlag; private bool _connected; public ServerConnection(string ip) { if (ip.Contains(':')) { _host = ip.Split(":")[0]; _port = Convert.ToInt32(ip.Split(":")[1]); } else if (_host.Length != 0) { _host = ip; } _thread = new Thread(ServerListener); _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { _socket.Connect(_host, _port); } catch (Exception e) { Dispatcher.UIThread.InvokeAsync(() => { MainWindow.Instance.ShowDisconnectScreen(e.Message); }); return; } _socket.Send(PacketConverter.ToBytes(new ConnectPacket(Settings.Config().Nick))); _thread.IsBackground = true; _thread.Start(); _connected = true; } public void AddMessageToChat(string chatName, ListBoxItem message) { ItemsRepeater listBoxes = MainWindow.Instance.Find(chatName); if (listBoxes.Items == null || listBoxes.Items.GetType() != typeof(List)) { List items = new(); items.Add(message); listBoxes.Items = items; } else { List items = (List) listBoxes.Items; List list = new(); list.AddRange(items); list.Add(message); listBoxes.Items = list; } MainWindow.Instance.FindControl(chatName).ScrollToEnd(); } public void SendMessage(ChatType chatType, string text) { _socket.Send(PacketConverter.ToBytes(new MessageSendPacket(chatType, text))); } public void ClearChats() { MainWindow.Instance.FindControl("QueueChat").Items = null; MainWindow.Instance.FindControl("GameVotingActiveChat").Items = null; MainWindow.Instance.FindControl("GameDayChat").Items = null; } public void Disconnect() { _connected = false; _socket.Send(PacketConverter.ToBytes(new DisconnectPlayerPacket())); _thread.Interrupt(); _socket.Close(); } public void Vote(int id) { _socket.Send(PacketConverter.ToBytes(new VotePacket(id))); } private void ServerListener() { while (!_breakFlag) { StringBuilder builder = new(); byte[] data = new byte[256]; try { do { var bytes = _socket.Receive(data); builder.Append(Encoding.UTF8.GetString(data, 0, bytes)); } while (_socket.Available > 0); } catch (Exception e) { _socket.Close(); if (_connected) { MainWindow.Instance.HideAll(); MainWindow.Instance.ShowDisconnectScreen(e.Message); _connected = false; } _breakFlag = true; } if (!_breakFlag) { Console.WriteLine(builder.ToString()); List packets = PacketConverter.ToPacket(builder.ToString()); foreach (Packet packet in packets) { WorkPacket(packet); } } } } private void WorkPacket(Packet packet) { Dispatcher.UIThread.InvokeAsync(() => { switch (packet.PacketType) { case PacketType.Welcome: MainWindow.Instance.Find("QueueOnline").Text = ((WelcomePacket) packet).Players + "/" + ((WelcomePacket) packet).MaxPlayers; MainWindow.Instance.ShowGameQueueScreen(); Party party = new() { ID = _host + ":" + _port, Size = ((WelcomePacket) packet).Players, Max = ((WelcomePacket) packet).MaxPlayers }; Secrets secrets = new() { JoinSecret = _host + ":" + _port + "/join", SpectateSecret = _host + ":" + _port + "/spectate" }; App.Instance.GetRpcClient().SetPresence(new RichPresence() { State = ((WelcomePacket) packet).ServerName, Party = party, Secrets = secrets, Timestamps = Timestamps.Now, Details = "Ожидание старта" }); break; case PacketType.Disconnect: MainWindow.Instance.ShowDisconnectScreen(((DisconnectPacket) packet).Reason); _breakFlag = true; break; case PacketType.PlayerConnected: MainWindow.Instance.Find("QueueOnline").Text = ((PlayerConnectedPacket) packet).Players + "/" + ((PlayerConnectedPacket) packet).MaxPlayers; try { App.Instance.GetRpcClient().UpdatePartySize(((PlayerConnectedPacket) packet).Players); } catch (Exception e) { Console.WriteLine(e.Message); } break; case PacketType.PlayerDisconnected: MainWindow.Instance.Find("QueueOnline").Text = ((PlayerDisconnectedPacket) packet).Players + "/" + ((PlayerDisconnectedPacket) packet).MaxPlayers; try { App.Instance.GetRpcClient().UpdatePartySize(((PlayerDisconnectedPacket) packet).Players); } catch (Exception e) { Console.WriteLine(e.Message); } break; case PacketType.ServerShutdown: MainWindow.Instance.ShowDisconnectScreen("Сервер выключен: " + ((ServerShutdownPacket) packet).Reason); _breakFlag = true; break; case PacketType.MessageReceivePacket: ListBoxItem message = new(); if (((MessageReceivePacket) packet).IsSystem) { message.Content = ((MessageReceivePacket) packet).Text; } else { message.Content = ((MessageReceivePacket) packet).Author + ": " + ((MessageReceivePacket) packet).Text; } switch (((MessageReceivePacket) packet).ChatType) { case ChatType.Queue: AddMessageToChat("QueueChat",message); break; case ChatType.Active: AddMessageToChat("GameVotingActiveChat",message); break; case ChatType.Day: AddMessageToChat("GameDayChat",message); break; } break; case PacketType.GameStartPacket: List players = ((GameStartPacket) packet).Players; ClearChats(); switch (((GameStartPacket) packet).Role) { case Role.Citizen: MainWindow.Instance.HideAll(); MainWindow.Instance.ShowVotingPassive("Ты Мирный Житель"); break; case Role.Don: MainWindow.Instance.HideAll(); List items = new(); MainWindow.Instance.ShowVotingActive("Ты Дон, выбери кого убить!"); foreach (Player player in players) { ListBoxItem item = new() { Content = player.Id + ") " + player.Name }; items.Add(item); } MainWindow.Instance.FindControl("GameVotingActiveSelect").Items = items; break; case Role.Mafia: MainWindow.Instance.HideAll(); items = new List(); MainWindow.Instance.ShowVotingActive("Ты Мафия, выбери кого убить!"); foreach (Player player in players) { ListBoxItem item = new() { Content = player.Id + ") " + player.Name }; items.Add(item); } MainWindow.Instance.FindControl("GameVotingActiveSelect").Items = items; break; } App.Instance.GetRpcClient().UpdateDetails("Ночь"); break; case PacketType.EndGame: MainWindow.Instance.ShowGameEnd(((EndGamePacket) packet).IsWon, ((EndGamePacket) packet).PlayerRoles); App.Instance.GetRpcClient().UpdateDetails("Ожидание старта"); break; case PacketType.GameStateChanged: MainWindow.Instance.HideAll(); players = ((GameStageChangedPacket) packet).Players; switch (((GameStageChangedPacket) packet).GameState) { case GameState.Day: MainWindow.Instance.ShowDay(false, ((GameStageChangedPacket) packet).Role, players); App.Instance.GetRpcClient().UpdateDetails("День"); break; case GameState.VotingDay: MainWindow.Instance.ShowDay(true, ((GameStageChangedPacket) packet).Role, players); App.Instance.GetRpcClient().UpdateDetails("Голосование!"); break; case GameState.VotingNight: switch (((GameStageChangedPacket) packet).Role) { case Role.Citizen: case Role.Died: string rol = ((GameStageChangedPacket) packet).Role == Role.Citizen ? "Мирный житель" : "Мёртв"; MainWindow.Instance.ShowVotingPassive("Ты " + rol + "!"); break; case Role.Mafia: case Role.Don: rol = ((GameStageChangedPacket) packet).Role == Role.Mafia ? "Мафия" : "Дон"; List items = new(); MainWindow.Instance.ShowVotingActive("Ты " + rol + ", выбери кого убить!"); MainWindow.Instance.FindControl("GameVotingActiveSelect").Items = null; foreach (Player player in players) { ListBoxItem item = new() { Content = player.Id + ") " + player.Name }; items.Add(item); } MainWindow.Instance.FindControl("GameVotingActiveSelect").Items = items; break; } break; } break; } }); } } }