Merge pull request #31 from EntenKoeniq/main
Added multithreading and SendModPacket from the server
This commit is contained in:
commit
490ec02a3c
@ -83,5 +83,22 @@ namespace CoopServer
|
|||||||
packet.PacketToNetOutGoingMessage(outgoingMessage);
|
packet.PacketToNetOutGoingMessage(outgoingMessage);
|
||||||
Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, 0);
|
Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SendModPacket(string mod, byte customID, byte[] bytes)
|
||||||
|
{
|
||||||
|
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ID);
|
||||||
|
|
||||||
|
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
||||||
|
new ModPacket()
|
||||||
|
{
|
||||||
|
ID = -1,
|
||||||
|
Target = 0,
|
||||||
|
Mod = mod,
|
||||||
|
CustomPacketID = customID,
|
||||||
|
Bytes = bytes
|
||||||
|
}.PacketToNetOutGoingMessage(outgoingMessage);
|
||||||
|
Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, 0);
|
||||||
|
Server.MainNetServer.FlushSendQueue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
LastPosition = CurrentPosition;
|
LastPosition = CurrentPosition;
|
||||||
CurrentPosition = value;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ namespace CoopServer
|
|||||||
|
|
||||||
public static NetServer MainNetServer;
|
public static NetServer MainNetServer;
|
||||||
|
|
||||||
public static ServerScript GameMode;
|
public static Resource MainResource;
|
||||||
public static Dictionary<Command, Action<CommandContext>> Commands;
|
public static Dictionary<Command, Action<CommandContext>> Commands;
|
||||||
|
|
||||||
public static readonly List<Client> Clients = new();
|
public static readonly List<Client> Clients = new();
|
||||||
@ -62,13 +62,13 @@ namespace CoopServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(MainSettings.GameMode))
|
if (!string.IsNullOrEmpty(MainSettings.Resource))
|
||||||
{
|
{
|
||||||
try
|
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();
|
Type[] types = asm.GetExportedTypes();
|
||||||
IEnumerable<Type> validTypes = types.Where(t => !t.IsInterface && !t.IsAbstract).Where(t => typeof(ServerScript).IsAssignableFrom(t));
|
IEnumerable<Type> validTypes = types.Where(t => !t.IsInterface && !t.IsAbstract).Where(t => typeof(ServerScript).IsAssignableFrom(t));
|
||||||
Type[] enumerable = validTypes as Type[] ?? validTypes.ToArray();
|
Type[] enumerable = validTypes as Type[] ?? validTypes.ToArray();
|
||||||
@ -81,14 +81,13 @@ namespace CoopServer
|
|||||||
{
|
{
|
||||||
Commands = new();
|
Commands = new();
|
||||||
|
|
||||||
GameMode = Activator.CreateInstance(enumerable.ToArray()[0]) as ServerScript;
|
if (Activator.CreateInstance(enumerable.ToArray()[0]) is ServerScript script)
|
||||||
if (GameMode == null)
|
|
||||||
{
|
{
|
||||||
Logging.Warning("Could not create gamemode: it is null.");
|
MainResource = new(script);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GameMode.API.InvokeStart();
|
Logging.Warning("Could not create resource: it is null.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,9 +106,6 @@ namespace CoopServer
|
|||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// 16 milliseconds to sleep to reduce CPU usage
|
|
||||||
Thread.Sleep(1000 / 60);
|
|
||||||
|
|
||||||
NetIncomingMessage message;
|
NetIncomingMessage message;
|
||||||
|
|
||||||
while ((message = MainNetServer.ReadMessage()) != null)
|
while ((message = MainNetServer.ReadMessage()) != null)
|
||||||
@ -289,9 +285,9 @@ namespace CoopServer
|
|||||||
packet.NetIncomingMessageToPacket(message);
|
packet.NetIncomingMessageToPacket(message);
|
||||||
|
|
||||||
ModPacket modPacket = (ModPacket)packet;
|
ModPacket modPacket = (ModPacket)packet;
|
||||||
if (GameMode != null)
|
if (MainResource != null)
|
||||||
{
|
{
|
||||||
if (GameMode.API.InvokeModPacketReceived(modPacket.ID, modPacket.Target, modPacket.Mod, modPacket.CustomPacketID, modPacket.Bytes))
|
if (MainResource.InvokeModPacketReceived(modPacket.ID, modPacket.Target, modPacket.Mod, modPacket.CustomPacketID, modPacket.Bytes))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -357,6 +353,9 @@ namespace CoopServer
|
|||||||
|
|
||||||
MainNetServer.Recycle(message);
|
MainNetServer.Recycle(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 16 milliseconds to sleep to reduce CPU usage
|
||||||
|
Thread.Sleep(1000 / 60);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,9 +457,9 @@ namespace CoopServer
|
|||||||
SendChatMessage(new ChatMessagePacket() { Username = "Server", Message = MainSettings.WelcomeMessage }, new List<NetConnection>() { local });
|
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;
|
List<NetConnection> clients;
|
||||||
@ -502,9 +501,9 @@ namespace CoopServer
|
|||||||
// Send all players a message that someone has left the server
|
// Send all players a message that someone has left the server
|
||||||
private static void SendPlayerDisconnectPacket(PlayerDisconnectPacket packet)
|
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;
|
List<NetConnection> clients;
|
||||||
@ -643,7 +642,7 @@ namespace CoopServer
|
|||||||
{
|
{
|
||||||
NetOutgoingMessage outgoingMessage;
|
NetOutgoingMessage outgoingMessage;
|
||||||
|
|
||||||
if (GameMode != null)
|
if (MainResource != null)
|
||||||
{
|
{
|
||||||
if (packet.Message.StartsWith("/"))
|
if (packet.Message.StartsWith("/"))
|
||||||
{
|
{
|
||||||
@ -679,7 +678,8 @@ namespace CoopServer
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (GameMode.API.InvokeChatMessage(packet.Username, packet.Message))
|
|
||||||
|
if (MainResource.InvokeChatMessage(packet.Username, packet.Message))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,98 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Lidgren.Network;
|
using Lidgren.Network;
|
||||||
|
|
||||||
namespace CoopServer
|
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;
|
||||||
|
_script.API.InvokeStart();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThreadLoop()
|
||||||
|
{
|
||||||
|
while (_hasToStop)
|
||||||
|
{
|
||||||
|
if (_actionQueue.Count != 0)
|
||||||
|
{
|
||||||
|
lock (_actionQueue)
|
||||||
|
{
|
||||||
|
_factory.StartNew(() => _actionQueue.Dequeue()?.Invoke());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 16 milliseconds to sleep to reduce CPU usage
|
||||||
|
Thread.Sleep(1000 / 60);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 abstract class ServerScript
|
||||||
{
|
{
|
||||||
public API API { get; } = new();
|
public API API { get; } = new();
|
||||||
@ -64,6 +151,21 @@ namespace CoopServer
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region FUNCTIONS
|
#region FUNCTIONS
|
||||||
|
public static void SendModPacketToAll(string mod, byte customID, byte[] bytes)
|
||||||
|
{
|
||||||
|
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
||||||
|
new ModPacket()
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
public static void SendNativeCallToAll(ulong hash, params object[] args)
|
public static void SendNativeCallToAll(ulong hash, params object[] args)
|
||||||
{
|
{
|
||||||
if (Server.MainNetServer.ConnectionsCount == 0)
|
if (Server.MainNetServer.ConnectionsCount == 0)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
public int MaxPlayers { get; set; } = 16;
|
public int MaxPlayers { get; set; } = 16;
|
||||||
public string ServerName { get; set; } = "GTACoop:R server";
|
public string ServerName { get; set; } = "GTACoop:R server";
|
||||||
public string WelcomeMessage { get; set; } = "Welcome on this 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 Allowlist { get; set; } = false;
|
||||||
public bool NpcsAllowed { get; set; } = true;
|
public bool NpcsAllowed { get; set; } = true;
|
||||||
public bool ModsAllowed { get; set; } = false;
|
public bool ModsAllowed { get; set; } = false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user