Resources are now multithreaded. GameMode renamed to Resource

This commit is contained in:
EntenKoeniq
2021-11-20 05:38:00 +01:00
parent 814c2c76e7
commit f0d1fee2bd
4 changed files with 104 additions and 19 deletions

View File

@ -18,9 +18,9 @@
LastPosition = CurrentPosition;
CurrentPosition = value;
if (Server.GameMode != null && !LVector3.Equals(CurrentPosition, LastPosition))
if (Server.MainResource != null && !LVector3.Equals(CurrentPosition, LastPosition))
{
Server.GameMode.API.InvokePlayerPositionUpdate(this);
Server.MainResource.InvokePlayerPositionUpdate(this);
}
}
}

View File

@ -19,7 +19,7 @@ namespace CoopServer
public static NetServer MainNetServer;
public static ServerScript GameMode;
public static Resource MainResource;
public static Dictionary<Command, Action<CommandContext>> Commands;
public static readonly List<Client> Clients = new();
@ -62,13 +62,13 @@ namespace CoopServer
}
}
if (!string.IsNullOrEmpty(MainSettings.GameMode))
if (!string.IsNullOrEmpty(MainSettings.Resource))
{
try
{
Logging.Info("Loading gamemode...");
Logging.Info("Loading resource...");
Assembly asm = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + "gamemodes" + Path.DirectorySeparatorChar + MainSettings.GameMode + ".dll");
Assembly asm = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + "resources" + Path.DirectorySeparatorChar + MainSettings.Resource + ".dll");
Type[] types = asm.GetExportedTypes();
IEnumerable<Type> validTypes = types.Where(t => !t.IsInterface && !t.IsAbstract).Where(t => typeof(ServerScript).IsAssignableFrom(t));
Type[] enumerable = validTypes as Type[] ?? validTypes.ToArray();
@ -81,14 +81,13 @@ namespace CoopServer
{
Commands = new();
GameMode = Activator.CreateInstance(enumerable.ToArray()[0]) as ServerScript;
if (GameMode == null)
if (Activator.CreateInstance(enumerable.ToArray()[0]) is ServerScript script)
{
Logging.Warning("Could not create gamemode: it is null.");
MainResource = new(script);
}
else
{
GameMode.API.InvokeStart();
Logging.Warning("Could not create resource: it is null.");
}
}
}
@ -289,9 +288,10 @@ namespace CoopServer
packet.NetIncomingMessageToPacket(message);
ModPacket modPacket = (ModPacket)packet;
if (GameMode != null)
if (MainResource != null)
{
if (GameMode.API.InvokeModPacketReceived(modPacket.ID, modPacket.Target, modPacket.Mod, modPacket.CustomPacketID, modPacket.Bytes))
// TODO: We need the true/false result
if (MainResource.InvokeModPacketReceived(modPacket.ID, modPacket.Target, modPacket.Mod, modPacket.CustomPacketID, modPacket.Bytes))
{
break;
}
@ -458,9 +458,9 @@ namespace CoopServer
SendChatMessage(new ChatMessagePacket() { Username = "Server", Message = MainSettings.WelcomeMessage }, new List<NetConnection>() { local });
}
if (GameMode != null)
if (MainResource != null)
{
GameMode.API.InvokePlayerConnected(Clients.Find(x => x.ID == packet.ID));
MainResource.InvokePlayerConnected(Clients.Find(x => x.ID == packet.ID));
}
List<NetConnection> clients;
@ -502,9 +502,9 @@ namespace CoopServer
// Send all players a message that someone has left the server
private static void SendPlayerDisconnectPacket(PlayerDisconnectPacket packet)
{
if (GameMode != null)
if (MainResource != null)
{
GameMode.API.InvokePlayerDisconnected(Clients.Find(x => x.ID == packet.ID));
MainResource.InvokePlayerDisconnected(Clients.Find(x => x.ID == packet.ID));
}
List<NetConnection> clients;
@ -643,7 +643,7 @@ namespace CoopServer
{
NetOutgoingMessage outgoingMessage;
if (GameMode != null)
if (MainResource != null)
{
if (packet.Message.StartsWith("/"))
{
@ -679,7 +679,7 @@ namespace CoopServer
return;
}
else if (GameMode.API.InvokeChatMessage(packet.Username, packet.Message))
else if (MainResource.InvokeChatMessage(packet.Username, packet.Message)) // TODO: We need the true/false result
{
return;
}

View File

@ -2,11 +2,96 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Lidgren.Network;
namespace CoopServer
{
internal class Resource
{
private static Thread _mainThread;
private static bool _hasToStop = false;
private static Queue<Action> _actionQueue;
private static TaskFactory _factory;
private static ServerScript _script;
public Resource(ServerScript script)
{
_factory = new();
_actionQueue = new();
_mainThread = new(ThreadLoop) { IsBackground = true };
_mainThread.Start();
lock (_actionQueue)
{
_actionQueue.Enqueue(() => _script = script);
}
}
private void ThreadLoop()
{
do
{
// 16 milliseconds to sleep to reduce CPU usage
Thread.Sleep(1000 / 60);
if (_actionQueue.Count == 0)
{
continue;
}
lock (_actionQueue)
{
_factory.StartNew(() => _actionQueue.Dequeue()?.Invoke());
}
} 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);
return shutdownTask.Result;
}
public void InvokePlayerConnected(Client client)
{
lock (_actionQueue)
{
_actionQueue.Enqueue(() => _script.API.InvokePlayerConnected(client));
}
}
public void InvokePlayerDisconnected(Client client)
{
lock (_actionQueue)
{
_actionQueue.Enqueue(() => _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;
}
public void InvokePlayerPositionUpdate(PlayerData playerData)
{
lock (_actionQueue)
{
_actionQueue.Enqueue(() => _script.API.InvokePlayerPositionUpdate(playerData));
}
}
}
public abstract class ServerScript
{
public API API { get; } = new();

View File

@ -6,7 +6,7 @@
public int MaxPlayers { get; set; } = 16;
public string ServerName { get; set; } = "GTACoop:R server";
public string WelcomeMessage { get; set; } = "Welcome on this server :)";
public string GameMode { get; set; } = "";
public string Resource { get; set; } = "";
public bool Allowlist { get; set; } = false;
public bool NpcsAllowed { get; set; } = true;
public bool ModsAllowed { get; set; } = false;