mirror of
https://github.com/MilkBarModding/MilkBarLauncher.git
synced 2025-06-16 20:20:56 +00:00
273 lines
10 KiB
C#
273 lines
10 KiB
C#
using BOTWM.Server.DTO;
|
|
using BOTWM.Server.HelperTypes;
|
|
using BOTWM.Server.ServerClasses;
|
|
using Newtonsoft.Json;
|
|
using System.Net;
|
|
using System.Net.NetworkInformation;
|
|
using System.Net.Sockets;
|
|
using System.Text;
|
|
using BOTWM.Server.JSONBuilder;
|
|
using System.Diagnostics;
|
|
using BOTW.Logging;
|
|
|
|
namespace BOTWM.Server
|
|
{
|
|
public class Server
|
|
{
|
|
bool serverOpen = false;
|
|
|
|
public string Version = "0.20.0";
|
|
|
|
public short SerializationRate = 60;
|
|
public short TargetFPS = 60;
|
|
public short SleepMultiplier = 1;
|
|
public bool isLocalTest = false;
|
|
public bool ischaracterSpawn = true;
|
|
public bool DisplayNames = true;
|
|
public short GlyphDistance = 250;
|
|
public short GlyphTime = 60;
|
|
public bool isQuestSync = false;
|
|
public bool isEnemySync = false;
|
|
public string Gamemode = "";
|
|
|
|
public bool EnemyLog { get; set; }
|
|
|
|
public int ClientLog { get; set; }
|
|
public bool ServerLog { get; set; }
|
|
|
|
Socket listen;
|
|
Thread listenThread;
|
|
List<Thread> clientThreads = new List<Thread>();
|
|
|
|
public bool serverStart(string ip, int port, string password, string description, ServerSettings settings)
|
|
{
|
|
|
|
this.Gamemode = settings.SettingsName;
|
|
|
|
Dictionary<string, string> ipAddresses = new Dictionary<string, string>();
|
|
|
|
if (ip == "localhost")
|
|
{
|
|
var host = Dns.GetHostEntry(Dns.GetHostName());
|
|
|
|
foreach (NetworkInterface item in NetworkInterface.GetAllNetworkInterfaces())
|
|
{
|
|
if (item.OperationalStatus == OperationalStatus.Up)
|
|
{
|
|
foreach (UnicastIPAddressInformation uip in item.GetIPProperties().UnicastAddresses)
|
|
{
|
|
if (uip.Address.AddressFamily == AddressFamily.InterNetwork && host.AddressList.Contains(uip.Address))
|
|
{
|
|
ipAddresses.Add(item.Name.ToString(), uip.Address.ToString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ipAddresses.Add("custom IP", ip);
|
|
}
|
|
|
|
foreach (var key in ipAddresses.Keys)
|
|
{
|
|
try
|
|
{
|
|
listen = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
|
|
listen.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false);
|
|
string IP = ipAddresses[key].ToString();
|
|
|
|
IPEndPoint connect = new IPEndPoint(IPAddress.Parse(IP), port);
|
|
listen.Bind(connect);
|
|
|
|
Logger.LogInformation("Server opened on " + key + ".");
|
|
|
|
ServerData.Startup(ip, port, password, description, settings);
|
|
|
|
serverOpen = true;
|
|
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError(ex.ToString());
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void stopServer()
|
|
{
|
|
serverOpen = false;
|
|
listen.Close();
|
|
|
|
if (listenThread != null)
|
|
listenThread.Abort();
|
|
|
|
foreach (Thread clientThread in clientThreads)
|
|
clientThread.Abort();
|
|
}
|
|
|
|
public void startListen()
|
|
{
|
|
listenThread = new Thread(serverListen);
|
|
listenThread.IsBackground = true;
|
|
listenThread.Start();
|
|
}
|
|
|
|
public void serverListen()
|
|
{
|
|
while(true)
|
|
{
|
|
Socket connection;
|
|
|
|
listen.Listen(100);
|
|
|
|
connection = listen.Accept();
|
|
|
|
var clientThread = new Thread(() => handleClient(connection));
|
|
clientThread.Start();
|
|
clientThreads.Add(clientThread);
|
|
}
|
|
}
|
|
|
|
public void handleClient(Socket connection)
|
|
{
|
|
int SIZE = 10240;
|
|
|
|
byte[] info = new byte[SIZE];
|
|
List<byte> data = new List<byte>();
|
|
int totalLength = 0;
|
|
int retries = 0;
|
|
Stopwatch RetryWatch = new Stopwatch();
|
|
|
|
bool ClientConnected = true;
|
|
int PlayerNumber = -1;
|
|
string PlayerName = "";
|
|
|
|
while(serverOpen && ClientConnected)
|
|
{
|
|
try
|
|
{
|
|
if (retries == 0)
|
|
RetryWatch.Restart();
|
|
|
|
totalLength += connection.Receive(info, 0, info.Length, 0);
|
|
|
|
data.AddRange(info.ToList());
|
|
|
|
if (totalLength < 6144)
|
|
{
|
|
retries++;
|
|
|
|
if (retries > 10 && totalLength == 0)
|
|
throw new ApplicationException("Connection lost with player.");
|
|
|
|
continue;
|
|
}
|
|
|
|
Tuple<MessageType, object> ClientMessage = new JSONBuilder.JSONBuilder().BuildFromBytes(data.ToArray());
|
|
|
|
data.Clear();
|
|
totalLength = 0;
|
|
|
|
if(retries > 0)
|
|
{
|
|
Logger.LogInformation($"[{PlayerName}] Retried {retries} times and took {RetryWatch.ElapsedMilliseconds} milliseconds");
|
|
retries = 0;
|
|
}
|
|
|
|
if (ClientMessage.Item1 == MessageType.error)
|
|
{
|
|
throw new Exception($"[{PlayerName}] Error receiving message. Disconnecting player...");
|
|
}
|
|
else if(ClientMessage.Item1 == MessageType.ping)
|
|
{
|
|
var PingResult = new PingDTO();
|
|
|
|
if(ServerData.Configuration.PASSWORD != (string)ClientMessage.Item2)
|
|
PingResult = new PingDTO()
|
|
{
|
|
CorrectPassword = false,
|
|
Description = "",
|
|
PlayerList = new NamesDTO(),
|
|
GameMode = "",
|
|
PlayerLimit = 32
|
|
};
|
|
else
|
|
PingResult = new PingDTO()
|
|
{
|
|
CorrectPassword = true,
|
|
Description = ServerData.Configuration.DESCRIPTION,
|
|
PlayerList = ServerData.GetPlayers(),
|
|
GameMode = this.Gamemode,
|
|
PlayerLimit = 32
|
|
};
|
|
|
|
connection.Send(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(PingResult)));
|
|
|
|
connection.Close();
|
|
ClientConnected = false;
|
|
|
|
}
|
|
else if(ClientMessage.Item1 == MessageType.connect)
|
|
{
|
|
ConnectDTO UserConfiguration = (ConnectDTO)ClientMessage.Item2;
|
|
ConnectResponseDTO AssignationResult = ServerData.TryAssigning(UserConfiguration);
|
|
|
|
if(AssignationResult.Response != 1)
|
|
{
|
|
connection.Send(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(AssignationResult)));
|
|
connection.Close();
|
|
ClientConnected = false;
|
|
Logger.LogInformation($"Player {UserConfiguration.Name} tried to connect but failed with error {AssignationResult.Response}");
|
|
break;
|
|
}
|
|
|
|
PlayerNumber = AssignationResult.PlayerNumber;
|
|
PlayerName = ServerData.PlayerList[PlayerNumber].Name;
|
|
connection.Send(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(AssignationResult)));
|
|
|
|
Logger.LogInformation($"Player {UserConfiguration.Name} joined the server. Assigned to player {AssignationResult.PlayerNumber + 1}.");
|
|
}
|
|
else if(ClientMessage.Item1 == MessageType.update)
|
|
{
|
|
ServerData.SetConnection(PlayerNumber, true);
|
|
|
|
ClientDTO UserInformation = (ClientDTO)ClientMessage.Item2;
|
|
|
|
ServerData.UpdateWorldData(UserInformation.WorldData, PlayerNumber);
|
|
ServerData.UpdatePlayerData(UserInformation.PlayerData, PlayerNumber);
|
|
ServerData.UpdateEnemyData(UserInformation.EnemyData);
|
|
ServerData.UpdateQuestData(UserInformation.QuestData);
|
|
|
|
ServerDTO serverDTO = ServerData.GetData(PlayerNumber);
|
|
serverDTO.NetworkData.Map(this);
|
|
|
|
connection.Send(new JSONBuilder.JSONBuilder().BuildArrayOfBytes(serverDTO));
|
|
|
|
ServerData.ClearDeathSwap(PlayerNumber);
|
|
}
|
|
else if(ClientMessage.Item1 == MessageType.disconnect)
|
|
{
|
|
Logger.LogInformation($"Player {ServerData.GetPlayer(PlayerNumber).Name} disconnected. {(string)ClientMessage.Item2}");
|
|
connection.Close();
|
|
ClientConnected = false;
|
|
ServerData.SetConnection(PlayerNumber, false);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogInformation($"Player {ServerData.GetPlayer(PlayerNumber).Name} disconnected.", ex.Message);
|
|
Logger.LogDebug(ex.StackTrace);
|
|
ServerData.SetConnection(PlayerNumber, false);
|
|
connection.Close();
|
|
ClientConnected = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|