Implement LobbyServer
This commit is contained in:
19
LobbyServer/ChatManager.cs
Normal file
19
LobbyServer/ChatManager.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
namespace LobbyServer
|
||||
{
|
||||
class ChatManager
|
||||
{
|
||||
private List<Message> _messages;
|
||||
public IReadOnlyList<Message> Messages => _messages.AsReadOnly();
|
||||
|
||||
public ChatManager()
|
||||
{
|
||||
_messages = new List<Message>();
|
||||
}
|
||||
|
||||
public void Add(Message message)
|
||||
{
|
||||
_messages.Add(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
LobbyServer/Command.cs
Normal file
11
LobbyServer/Command.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace LobbyServer
|
||||
{
|
||||
enum Command
|
||||
{
|
||||
ChatAdd,
|
||||
ChatRequest,
|
||||
ScoreAdd,
|
||||
ScoreRequest,
|
||||
Invalid
|
||||
}
|
||||
}
|
||||
19
LobbyServer/CommandPacket.cs
Normal file
19
LobbyServer/CommandPacket.cs
Normal file
@@ -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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
47
LobbyServer/CommandStream.cs
Normal file
47
LobbyServer/CommandStream.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
108
LobbyServer/LobbyServer.cs
Normal file
108
LobbyServer/LobbyServer.cs
Normal file
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,4 +5,8 @@
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
31
LobbyServer/Message.cs
Normal file
31
LobbyServer/Message.cs
Normal file
@@ -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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace LobbyServer
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
new LobbyServer().Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
26
LobbyServer/ScoreEntry.cs
Normal file
26
LobbyServer/ScoreEntry.cs
Normal file
@@ -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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
40
LobbyServer/ScoresManager.cs
Normal file
40
LobbyServer/ScoresManager.cs
Normal file
@@ -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<ScoreEntry> _scores;
|
||||
public IReadOnlyList<ScoreEntry> Scores => _scores.AsReadOnly();
|
||||
|
||||
public ScoresManager()
|
||||
{
|
||||
if (File.Exists("scores.json"))
|
||||
{
|
||||
_scores = JsonConvert.DeserializeObject<List<ScoreEntry>>(File.ReadAllText(FilePath));
|
||||
}
|
||||
else
|
||||
{
|
||||
_scores = new List<ScoreEntry>();
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(ScoreEntry entry)
|
||||
{
|
||||
_scores.Add(entry);
|
||||
_scores.OrderByDescending(x => x.Score);
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
File.WriteAllText(FilePath, JsonConvert.SerializeObject(_scores));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user