RMafia/MafiaClient/ServerConnection.cs
2021-04-28 23:50:55 +03:00

332 lines
14 KiB
C#

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<ItemsRepeater>(chatName);
if (listBoxes.Items == null || listBoxes.Items.GetType() != typeof(List<ListBoxItem>))
{
List<ListBoxItem> items = new();
items.Add(message);
listBoxes.Items = items;
}
else
{
List<ListBoxItem> items = (List<ListBoxItem>) listBoxes.Items;
List<ListBoxItem> list = new();
list.AddRange(items);
list.Add(message);
listBoxes.Items = list;
}
MainWindow.Instance.FindControl<ScrollViewer>(chatName).ScrollToEnd();
}
public void SendMessage(ChatType chatType, string text)
{
_socket.Send(PacketConverter.ToBytes(new MessageSendPacket(chatType, text)));
}
public void ClearChats()
{
MainWindow.Instance.FindControl<ItemsRepeater>("QueueChat").Items = null;
MainWindow.Instance.FindControl<ItemsRepeater>("GameVotingActiveChat").Items = null;
MainWindow.Instance.FindControl<ItemsRepeater>("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<Packet> 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<TextBlock>("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<TextBlock>("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<TextBlock>("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<Player> 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<ListBoxItem> items = new();
MainWindow.Instance.ShowVotingActive("Ты Дон, выбери кого убить!");
foreach (Player player in players)
{
ListBoxItem item = new()
{
Content = player.Id + ") " + player.Name
};
items.Add(item);
}
MainWindow.Instance.FindControl<ListBox>("GameVotingActiveSelect").Items = items;
break;
case Role.Mafia:
MainWindow.Instance.HideAll();
items = new List<ListBoxItem>();
MainWindow.Instance.ShowVotingActive("Ты Мафия, выбери кого убить!");
foreach (Player player in players)
{
ListBoxItem item = new()
{
Content = player.Id + ") " + player.Name
};
items.Add(item);
}
MainWindow.Instance.FindControl<ListBox>("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<ListBoxItem> items = new();
MainWindow.Instance.ShowVotingActive("Ты " + rol + ", выбери кого убить!");
MainWindow.Instance.FindControl<ListBox>("GameVotingActiveSelect").Items = null;
foreach (Player player in players)
{
ListBoxItem item = new()
{
Content = player.Id + ") " + player.Name
};
items.Add(item);
}
MainWindow.Instance.FindControl<ListBox>("GameVotingActiveSelect").Items = items;
break;
}
break;
}
break;
}
});
}
}
}