Error handling, bug fixes, new API functions and more added!

This commit is contained in:
EntenKoeniq
2021-11-25 16:32:04 +01:00
parent ed46155138
commit 5c7e7f45a0
7 changed files with 411 additions and 185 deletions

View File

@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
@ -13,18 +14,16 @@ namespace CoopServer
{
private static Thread _mainThread;
private static bool _hasToStop = false;
private static Queue<Action> _actionQueue;
private static TaskFactory _factory;
private static Queue _actionQueue;
private static ServerScript _script;
public Resource(ServerScript script)
{
_factory = new();
_actionQueue = new();
_actionQueue = Queue.Synchronized(new Queue());
_mainThread = new(ThreadLoop) { IsBackground = true };
_mainThread.Start();
lock (_actionQueue)
lock (_actionQueue.SyncRoot)
{
_actionQueue.Enqueue(() =>
{
@ -36,60 +35,88 @@ namespace CoopServer
private void ThreadLoop()
{
do
while (!_hasToStop)
{
if (_actionQueue.Count != 0)
Queue localQueue;
lock (_actionQueue.SyncRoot)
{
lock (_actionQueue)
{
_factory.StartNew(() => _actionQueue.Dequeue()?.Invoke());
}
localQueue = new(_actionQueue);
_actionQueue.Clear();
}
while (localQueue.Count > 0)
{
(localQueue.Dequeue() as Action)?.Invoke();
}
// 16 milliseconds to sleep to reduce CPU usage
Thread.Sleep(1000 / 60);
} while (_hasToStop);
}
}
public bool InvokeModPacketReceived(long from, long target, string mod, byte customID, byte[] bytes)
{
Task<bool> shutdownTask = new(() => _script.API.InvokeModPacketReceived(from, target, mod, customID, bytes));
shutdownTask.Start();
shutdownTask.Wait(5000);
Task<bool> task = new(() => _script.API.InvokeModPacketReceived(from, target, mod, customID, bytes));
task.Start();
task.Wait(5000);
return task.Result;
}
return shutdownTask.Result;
public void InvokePlayerHandshake(Client client)
{
lock (_actionQueue.SyncRoot)
{
_actionQueue.Enqueue(new Action(() => _script.API.InvokePlayerConnected(client)));
}
}
public void InvokePlayerConnected(Client client)
{
lock (_actionQueue)
lock (_actionQueue.SyncRoot)
{
_actionQueue.Enqueue(() => _script.API.InvokePlayerConnected(client));
_actionQueue.Enqueue(new Action(() => _script.API.InvokePlayerConnected(client)));
}
}
public void InvokePlayerDisconnected(Client client)
{
lock (_actionQueue)
lock (_actionQueue.SyncRoot)
{
_actionQueue.Enqueue(() => _script.API.InvokePlayerDisconnected(client));
_actionQueue.Enqueue(new Action(() => _script.API.InvokePlayerDisconnected(client)));
}
}
public bool InvokeChatMessage(string username, string message)
{
Task<bool> shutdownTask = new(() => _script.API.InvokeChatMessage(username, message));
shutdownTask.Start();
shutdownTask.Wait(5000);
return shutdownTask.Result;
Task<bool> task = new(() => _script.API.InvokeChatMessage(username, message));
task.Start();
task.Wait(5000);
return task.Result;
}
public void InvokePlayerPositionUpdate(PlayerData playerData)
{
lock (_actionQueue)
lock (_actionQueue.SyncRoot)
{
_actionQueue.Enqueue(() => _script.API.InvokePlayerPositionUpdate(playerData));
_actionQueue.Enqueue(new Action(() => _script.API.InvokePlayerPositionUpdate(playerData)));
}
}
public void InvokePlayerUpdate(Client client)
{
lock (_actionQueue.SyncRoot)
{
_actionQueue.Enqueue(new Action(() => _script.API.InvokePlayerUpdate(client)));
}
}
public void InvokePlayerHealthUpdate(PlayerData playerData)
{
lock (_actionQueue.SyncRoot)
{
_actionQueue.Enqueue(new Action(() => _script.API.InvokePlayerHealthUpdate(playerData)));
}
}
}
@ -102,22 +129,31 @@ namespace CoopServer
public class API
{
#region DELEGATES
public delegate void EmptyEvent();
public delegate void ChatEvent(string username, string message, CancelEventArgs cancel);
public delegate void PlayerEvent(Client client);
public delegate void ModEvent(long from, long target, string mod, byte customID, byte[] bytes, CancelEventArgs args);
#endregion
#region EVENTS
public event EventHandler OnStart;
public event EmptyEvent OnStart;
public event ChatEvent OnChatMessage;
public event PlayerEvent OnPlayerHandshake;
public event PlayerEvent OnPlayerConnected;
public event PlayerEvent OnPlayerDisconnected;
public event PlayerEvent OnPlayerUpdate;
public event PlayerEvent OnPlayerHealthUpdate;
public event PlayerEvent OnPlayerPositionUpdate;
public event ModEvent OnModPacketReceived;
internal void InvokeStart()
{
OnStart?.Invoke(this, EventArgs.Empty);
OnStart?.Invoke();
}
internal void InvokePlayerHandshake(Client client)
{
OnPlayerHandshake?.Invoke(client);
}
internal void InvokePlayerConnected(Client client)
@ -130,6 +166,16 @@ namespace CoopServer
OnPlayerDisconnected?.Invoke(client);
}
internal void InvokePlayerUpdate(Client client)
{
OnPlayerUpdate?.Invoke(client);
}
internal void InvokePlayerHealthUpdate(PlayerData playerData)
{
OnPlayerHealthUpdate?.Invoke(Server.Clients.First(x => x.Player.Username == playerData.Username));
}
internal bool InvokeChatMessage(string username, string message)
{
CancelEventArgs args = new(false);
@ -153,41 +199,55 @@ namespace CoopServer
#region FUNCTIONS
public static void SendModPacketToAll(string mod, byte customID, byte[] bytes)
{
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
new ModPacket()
try
{
ID = -1,
Target = 0,
Mod = mod,
CustomPacketID = customID,
Bytes = bytes
}.PacketToNetOutGoingMessage(outgoingMessage);
Server.MainNetServer.SendMessage(outgoingMessage, Server.MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, 0);
Server.MainNetServer.FlushSendQueue();
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
new ModPacket()
{
ID = 0,
Target = 0,
Mod = mod,
CustomPacketID = customID,
Bytes = bytes
}.PacketToNetOutGoingMessage(outgoingMessage);
Server.MainNetServer.SendMessage(outgoingMessage, Server.MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, 0);
Server.MainNetServer.FlushSendQueue();
}
catch (Exception e)
{
Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
}
}
public static void SendNativeCallToAll(ulong hash, params object[] args)
{
if (Server.MainNetServer.ConnectionsCount == 0)
try
{
return;
if (Server.MainNetServer.ConnectionsCount == 0)
{
return;
}
List<NativeArgument> arguments;
if ((arguments = Util.ParseNativeArguments(args)) == null)
{
return;
}
NativeCallPacket packet = new()
{
Hash = hash,
Args = arguments
};
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
packet.PacketToNetOutGoingMessage(outgoingMessage);
Server.MainNetServer.SendMessage(outgoingMessage, Server.MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, 0);
}
List<NativeArgument> arguments;
if ((arguments = Util.ParseNativeArguments(args)) == null)
catch (Exception e)
{
return;
Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
}
NativeCallPacket packet = new()
{
Hash = hash,
Args = arguments
};
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
packet.PacketToNetOutGoingMessage(outgoingMessage);
Server.MainNetServer.SendMessage(outgoingMessage, Server.MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, 0);
}
public static List<long> GetAllConnections()
@ -211,25 +271,31 @@ namespace CoopServer
public static Client GetClientByUsername(string username)
{
return Server.Clients.FirstOrDefault(x => x.Player.Username == username);
Client client = Server.Clients.FirstOrDefault(x => x.Player.Username == username);
return client.Equals(default(Client)) ? null : client;
}
public static void SendChatMessageToAll(string message, string username = "Server")
{
if (Server.MainNetServer.ConnectionsCount == 0)
try
{
return;
if (Server.MainNetServer.ConnectionsCount == 0)
{
return;
}
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
new ChatMessagePacket()
{
Username = username,
Message = message
}.PacketToNetOutGoingMessage(outgoingMessage);
Server.MainNetServer.SendMessage(outgoingMessage, Server.MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, 0);
}
ChatMessagePacket packet = new()
catch (Exception e)
{
Username = username,
Message = message
};
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
packet.PacketToNetOutGoingMessage(outgoingMessage);
Server.MainNetServer.SendMessage(outgoingMessage, Server.MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, 0);
Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
}
}
public static void RegisterCommand(string name, Action<CommandContext> callback)