diff --git a/LobbyServer/ChatManager.cs b/LobbyServer/ChatManager.cs new file mode 100644 index 0000000..452deaa --- /dev/null +++ b/LobbyServer/ChatManager.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +namespace LobbyServer +{ + class ChatManager + { + private List _messages; + public IReadOnlyList Messages => _messages.AsReadOnly(); + + public ChatManager() + { + _messages = new List(); + } + + public void Add(Message message) + { + _messages.Add(message); + } + } +} \ No newline at end of file diff --git a/LobbyServer/Command.cs b/LobbyServer/Command.cs new file mode 100644 index 0000000..b8df6fc --- /dev/null +++ b/LobbyServer/Command.cs @@ -0,0 +1,11 @@ +namespace LobbyServer +{ + enum Command + { + ChatAdd, + ChatRequest, + ScoreAdd, + ScoreRequest, + Invalid + } +} \ No newline at end of file diff --git a/LobbyServer/CommandPacket.cs b/LobbyServer/CommandPacket.cs new file mode 100644 index 0000000..3b3b5a4 --- /dev/null +++ b/LobbyServer/CommandPacket.cs @@ -0,0 +1,19 @@ +namespace LobbyServer +{ + class CommandPacket + { + public Command Command { get; } + public string Content { get; } + + public CommandPacket(Command command, string content) + { + Command = command; + Content = content; + } + + public override string ToString() + { + return $"{Command.ToString()}\n{Content}"; + } + } +} \ No newline at end of file diff --git a/LobbyServer/CommandStream.cs b/LobbyServer/CommandStream.cs new file mode 100644 index 0000000..f22a4bb --- /dev/null +++ b/LobbyServer/CommandStream.cs @@ -0,0 +1,47 @@ +using System; +using System.Net.Sockets; +using System.Text; + +namespace LobbyServer +{ + class CommandStream + { + private NetworkStream _stream; + + public CommandStream(NetworkStream stream) + { + _stream = stream; + } + + public CommandPacket Receive() + { + // Length + byte[] buffer = new byte[4]; + _stream.Read(buffer, 0, buffer.Length); + + uint length = BitConverter.ToUInt32(buffer, 0); + + // Data + buffer = new byte[length]; + _stream.Read(buffer, 0, buffer.Length); + + string[] packet = Encoding.UTF8.GetString(buffer).Split('\n'); + + if (!Enum.TryParse(packet[0], true, out Command command)) + { + command = Command.Invalid; + } + + return new CommandPacket(command, packet[1]); + } + + public void Send(CommandPacket command) + { + string packet = command.ToString(); + byte[] data = Encoding.UTF8.GetBytes(packet); + + _stream.Write(BitConverter.GetBytes((uint)data.Length), 0, 4); + _stream.Write(data, 0, data.Length); + } + } +} \ No newline at end of file diff --git a/LobbyServer/LobbyServer.cs b/LobbyServer/LobbyServer.cs new file mode 100644 index 0000000..4ecbd1e --- /dev/null +++ b/LobbyServer/LobbyServer.cs @@ -0,0 +1,108 @@ +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System; +namespace LobbyServer +{ + class LobbyServer + { + public static LobbyServer Instance { get; private set; } + + public ChatManager ChatManager { get; } + public ScoresManager ScoresManager { get; } + + public LobbyServer() + { + Instance = this; + + Console.WriteLine("Starting LobbyServer..."); + + ChatManager = new ChatManager(); + ScoresManager = new ScoresManager(); + + Console.WriteLine("LobbyServer started"); + } + + public void Start() + { + var listener = new TcpListener(IPAddress.Any, 1409); + listener.Start(); + + while (true) + { + Console.WriteLine("Waiting client..."); + using (var client = listener.AcceptTcpClient()) + { + ClientLoop(client); + } + } + } + + public void ClientLoop(TcpClient client) + { + Console.WriteLine($"Client connected: {client.Client.RemoteEndPoint}"); + + var stream = new CommandStream(client.GetStream()); + + while (true) + { + try + { + var packet = stream.Receive(); + + switch (packet.Command) + { + case Command.ChatAdd: + ChatAdd(packet); + break; + case Command.ChatRequest: + ChatRequest(stream, packet); + break; + case Command.ScoreAdd: + ScoreAdd(packet); + break; + case Command.ScoreRequest: + ScoreRequest(stream, packet); + break; + case Command.Invalid: + throw new InvalidOperationException("Received invalid command"); + } + } + catch (Exception e) + { + Console.WriteLine($"Client disconnected: {e.Message}"); + } + } + } + + private void ChatAdd(CommandPacket packet) + { + var message = new Message(packet.Content); + + ChatManager.Add(message); + } + + private void ChatRequest(CommandStream stream, CommandPacket packet) + { + var messages = ChatManager.Messages.Reverse().Take(10).Reverse().Select(x => x.ToString()); + string data = string.Join('@', messages); + + stream.Send(new CommandPacket(Command.ChatRequest, data)); + } + + private void ScoreAdd(CommandPacket packet) + { + var score = new ScoreEntry(packet.Content); + + ScoresManager.Add(score); + } + + private void ScoreRequest(CommandStream stream, CommandPacket packet) + { + var scores = ScoresManager.Scores.Take(10).Select(x => x.ToString()); + string data = string.Join('@', scores); + + stream.Send(new CommandPacket(Command.ScoreRequest, data)); + } + } +} \ No newline at end of file diff --git a/LobbyServer/LobbyServer.csproj b/LobbyServer/LobbyServer.csproj index 23df604..aa02741 100644 --- a/LobbyServer/LobbyServer.csproj +++ b/LobbyServer/LobbyServer.csproj @@ -5,4 +5,8 @@ netcoreapp2.1 + + + + diff --git a/LobbyServer/Message.cs b/LobbyServer/Message.cs new file mode 100644 index 0000000..53bf097 --- /dev/null +++ b/LobbyServer/Message.cs @@ -0,0 +1,31 @@ +using System.Linq; +using System; +namespace LobbyServer +{ + class Message + { + public string SendDate { get; } + public string Sender { get; } + public string Content { get; } + + public Message(string sendDate, string sender, string content) + { + SendDate = sendDate; + Sender = sender; + Content = content; + } + + public Message(string serialized) + { + var split = serialized.Split(';'); + SendDate = split[0]; + Sender = split[1]; + Content = string.Join(';', split.Skip(2)); + } + + public override string ToString() + { + return $"{SendDate};{Sender};{Content}"; + } + } +} \ No newline at end of file diff --git a/LobbyServer/Program.cs b/LobbyServer/Program.cs index 5a2b7e9..133ce7a 100644 --- a/LobbyServer/Program.cs +++ b/LobbyServer/Program.cs @@ -6,7 +6,7 @@ namespace LobbyServer { static void Main(string[] args) { - Console.WriteLine("Hello World!"); + new LobbyServer().Start(); } } } diff --git a/LobbyServer/ScoreEntry.cs b/LobbyServer/ScoreEntry.cs new file mode 100644 index 0000000..2e4f9a5 --- /dev/null +++ b/LobbyServer/ScoreEntry.cs @@ -0,0 +1,26 @@ +namespace LobbyServer +{ + public class ScoreEntry + { + public string Pseudo { get; } + public int Score { get; } + + public ScoreEntry(string pseudo, int score) + { + Pseudo = pseudo; + Score = score; + } + + public ScoreEntry(string serialized) + { + var split = serialized.Split(';'); + Pseudo = split[0]; + Score = int.Parse(split[1]); + } + + public override string ToString() + { + return $"{Pseudo};{Score}"; + } + } +} \ No newline at end of file diff --git a/LobbyServer/ScoresManager.cs b/LobbyServer/ScoresManager.cs new file mode 100644 index 0000000..0902741 --- /dev/null +++ b/LobbyServer/ScoresManager.cs @@ -0,0 +1,40 @@ +using System.Linq; +using System; +using System.IO; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace LobbyServer +{ + class ScoresManager + { + public const string FileName = "scores.json"; + public string FilePath => Path.Combine(Environment.CurrentDirectory, FileName); + + private List _scores; + public IReadOnlyList Scores => _scores.AsReadOnly(); + + public ScoresManager() + { + if (File.Exists("scores.json")) + { + _scores = JsonConvert.DeserializeObject>(File.ReadAllText(FilePath)); + } + else + { + _scores = new List(); + } + } + + public void Add(ScoreEntry entry) + { + _scores.Add(entry); + _scores.OrderByDescending(x => x.Score); + } + + public void Save() + { + File.WriteAllText(FilePath, JsonConvert.SerializeObject(_scores)); + } + } +} \ No newline at end of file