Multiple server instances in one process is now possible
This commit is contained in:
@ -128,7 +128,7 @@ namespace RageCoop.Client.Scripting
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="Core.Logging.Logger"/> that RAGECOOP is currently using.
|
||||
/// Get a <see cref="Core.Logger"/> that RAGECOOP is currently using.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Logger GetLogger()
|
||||
|
@ -21,7 +21,7 @@ namespace RageCoop.Client.Scripting
|
||||
public override void OnStop()
|
||||
{
|
||||
}
|
||||
void SetAutoRespawn(CustomEventReceivedArgs args)
|
||||
private void SetAutoRespawn(CustomEventReceivedArgs args)
|
||||
{
|
||||
API.Config.EnableAutoRespawn=(bool)args.Args[0];
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ namespace RageCoop.Core
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
Args= Args ?? new List<object>(0);
|
||||
message.Write((byte)PacketTypes.CustomEvent);
|
||||
|
||||
List<byte> result = new List<byte>();
|
||||
|
@ -48,7 +48,7 @@ namespace RageCoop.Core.Scripting
|
||||
var r = new Resource()
|
||||
{
|
||||
Scripts = new List<IScriptable>(),
|
||||
Name=Path.GetDirectoryName(path),
|
||||
Name=Path.GetFileName(path),
|
||||
Directory=path,
|
||||
};
|
||||
foreach (var f in Directory.GetFiles(path, "*.dll"))
|
||||
|
@ -42,6 +42,11 @@ namespace RageCoop.Server
|
||||
}
|
||||
public class Client
|
||||
{
|
||||
private readonly Server Server;
|
||||
internal Client(Server server)
|
||||
{
|
||||
Server=server;
|
||||
}
|
||||
internal long NetID = 0;
|
||||
public NetConnection Connection { get;internal set; }
|
||||
public ServerPed Player { get; internal set; }
|
||||
@ -111,7 +116,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
||||
Server.Logger?.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
||||
}
|
||||
}
|
||||
/*
|
||||
@ -127,13 +132,13 @@ namespace RageCoop.Server
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
|
||||
if (userConnection == null)
|
||||
{
|
||||
Program.Logger.Error($"[Client->SendNativeCall(ulong hash, params object[] args)]: Connection \"{NetID}\" not found!");
|
||||
Server.Logger?.Error($"[Client->SendNativeCall(ulong hash, params object[] args)]: Connection \"{NetID}\" not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args != null && args.Length == 0)
|
||||
{
|
||||
Program.Logger.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing arguments!");
|
||||
Server.Logger?.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing arguments!");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -149,7 +154,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
||||
Server.Logger?.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
@ -166,13 +171,13 @@ namespace RageCoop.Server
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
|
||||
if (userConnection == null)
|
||||
{
|
||||
Program.Logger.Error($"[Client->SendNativeResponse(Action<object> callback, ulong hash, Type type, params object[] args)]: Connection \"{NetID}\" not found!");
|
||||
Server.Logger?.Error($"[Client->SendNativeResponse(Action<object> callback, ulong hash, Type type, params object[] args)]: Connection \"{NetID}\" not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args != null && args.Length == 0)
|
||||
{
|
||||
Program.Logger.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing arguments!");
|
||||
Server.Logger?.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing arguments!");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -202,7 +207,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
else
|
||||
{
|
||||
Program.Logger.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing return type!");
|
||||
Server.Logger?.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing return type!");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -218,7 +223,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
||||
Server.Logger?.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
||||
}
|
||||
}
|
||||
*/
|
||||
@ -246,7 +251,7 @@ namespace RageCoop.Server
|
||||
{
|
||||
var argsList = new List<object>(args);
|
||||
argsList.InsertRange(0, new object[] { (byte)TypeCode.Empty,(ulong)hash});
|
||||
// Program.Logger.Debug(argsList.DumpWithType());
|
||||
// Server.Logger?.Debug(argsList.DumpWithType());
|
||||
SendCustomEvent(CustomEvents.NativeCall, argsList);
|
||||
}
|
||||
private int RequestNativeCallID<T>(Action<object> callback)
|
||||
@ -273,7 +278,7 @@ namespace RageCoop.Server
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
|
||||
if (userConnection == null)
|
||||
{
|
||||
Program.Logger.Error($"[Client->SendCleanUpWorld()]: Connection \"{NetID}\" not found!");
|
||||
Server.Logger?.Error($"[Client->SendCleanUpWorld()]: Connection \"{NetID}\" not found!");
|
||||
return;
|
||||
}
|
||||
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
||||
@ -285,7 +290,7 @@ namespace RageCoop.Server
|
||||
{
|
||||
if (!IsReady)
|
||||
{
|
||||
Program.Logger.Warning($"Player \"{Username}\" is not ready!");
|
||||
Server.Logger?.Warning($"Player \"{Username}\" is not ready!");
|
||||
}
|
||||
|
||||
try
|
||||
@ -302,7 +307,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Program.Logger.Error(ex);
|
||||
Server.Logger?.Error(ex);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
@ -9,10 +9,9 @@ namespace RageCoop.Server
|
||||
class Program
|
||||
{
|
||||
public static bool ReadyToStop = false;
|
||||
public static Core.Logger Logger;
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Logger=new Core.Logger()
|
||||
var mainLogger= new Core.Logger()
|
||||
{
|
||||
LogPath="RageCoop.Server.log",
|
||||
UseConsole=true,
|
||||
@ -49,13 +48,15 @@ namespace RageCoop.Server
|
||||
}
|
||||
};
|
||||
|
||||
_ = new Server();
|
||||
_ = new Server(mainLogger);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e);
|
||||
Logger.Error($"Fatal error occurred, server shutting down.");
|
||||
mainLogger.Error(e);
|
||||
mainLogger.Error($"Fatal error occurred, server shutting down.");
|
||||
Thread.Sleep(3000);
|
||||
}
|
||||
mainLogger.Dispose();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
@ -10,63 +10,60 @@ using System.Net;
|
||||
|
||||
namespace RageCoop.Server.Scripting
|
||||
{
|
||||
public static class API
|
||||
public class APIEvents
|
||||
{
|
||||
#region INTERNAL
|
||||
internal static Dictionary<int, List<Action<CustomEventReceivedArgs>>> CustomEventHandlers = new();
|
||||
internal Dictionary<int, List<Action<CustomEventReceivedArgs>>> CustomEventHandlers = new();
|
||||
#endregion
|
||||
public static class Events
|
||||
{
|
||||
#region DELEGATES
|
||||
public delegate void EmptyEvent();
|
||||
public delegate void PlayerConnect(Client client);
|
||||
public delegate void PlayerDisconnect(Client client);
|
||||
|
||||
#endregion
|
||||
public static event EventHandler<ChatEventArgs> OnChatMessage;
|
||||
public static event EventHandler<HandshakeEventArgs> OnPlayerHandshake;
|
||||
public static event PlayerConnect OnPlayerConnected;
|
||||
public static event PlayerDisconnect OnPlayerDisconnected;
|
||||
public event EventHandler<ChatEventArgs> OnChatMessage;
|
||||
public event EventHandler<HandshakeEventArgs> OnPlayerHandshake;
|
||||
/// <summary>
|
||||
/// Will be invoked when a player is connected, but this player might not be ready yet(client resources not loaded), using <see cref="OnPlayerReady"/> is recommended.
|
||||
/// </summary>
|
||||
public event EventHandler<Client> OnPlayerConnected;
|
||||
/// <summary>
|
||||
/// Will be invoked after the client connected and all resources(if any) have been loaded.
|
||||
/// </summary>
|
||||
public event EventHandler<Client> OnPlayerReady;
|
||||
public event EventHandler<Client> OnPlayerDisconnected;
|
||||
/// <summary>
|
||||
/// Will be invoked before registered handlers
|
||||
/// </summary>
|
||||
public static event EventHandler<OnCommandEventArgs> OnCommandReceived;
|
||||
public event EventHandler<OnCommandEventArgs> OnCommandReceived;
|
||||
/// <summary>
|
||||
/// Invoked everytime a player's main ped has been updated
|
||||
/// </summary>
|
||||
public static event EventHandler<Client> OnPlayerUpdate;
|
||||
/*
|
||||
/// <summary>
|
||||
/// This will be invoked when a CustomEvent is received from one client.
|
||||
/// </summary>
|
||||
public static event EventHandler<CustomEventReceivedArgs> OnCustomEventReceived;
|
||||
*/
|
||||
internal static void ClearHandlers()
|
||||
public event EventHandler<Client> OnPlayerUpdate;
|
||||
internal void ClearHandlers()
|
||||
{
|
||||
OnChatMessage=null;
|
||||
OnPlayerHandshake=null;
|
||||
OnPlayerConnected=null;
|
||||
OnPlayerReady=null;
|
||||
OnPlayerDisconnected=null;
|
||||
// OnCustomEventReceived=null;
|
||||
OnCommandReceived=null;
|
||||
OnPlayerUpdate=null;
|
||||
}
|
||||
#region INVOKE
|
||||
internal static void InvokeOnChatMessage(Packets.ChatMessage p,Client sender)
|
||||
internal void InvokeOnChatMessage(Packets.ChatMessage p, Client sender)
|
||||
{
|
||||
OnChatMessage?.Invoke(this, new ChatEventArgs()
|
||||
{
|
||||
OnChatMessage?.Invoke(null,new ChatEventArgs() {
|
||||
Sender=sender,
|
||||
Message=p.Message
|
||||
});
|
||||
}
|
||||
internal static void InvokePlayerConnected(Client client)
|
||||
{ OnPlayerConnected?.Invoke(client); }
|
||||
internal static void InvokePlayerDisconnected(Client client)
|
||||
{ OnPlayerDisconnected?.Invoke(client); }
|
||||
internal static void InvokePlayerHandshake(HandshakeEventArgs args)
|
||||
{ OnPlayerHandshake?.Invoke(null, args); }
|
||||
internal void InvokePlayerConnected(Client client)
|
||||
{ OnPlayerConnected?.Invoke(this,client); }
|
||||
internal void InvokePlayerReady(Client client)
|
||||
{ OnPlayerReady?.Invoke(this, client); }
|
||||
internal void InvokePlayerDisconnected(Client client)
|
||||
{ OnPlayerDisconnected?.Invoke(this,client); }
|
||||
internal void InvokePlayerHandshake(HandshakeEventArgs args)
|
||||
{ OnPlayerHandshake?.Invoke(this, args); }
|
||||
|
||||
internal static void InvokeCustomEventReceived(Packets.CustomEvent p,Client sender)
|
||||
internal void InvokeCustomEventReceived(Packets.CustomEvent p, Client sender)
|
||||
{
|
||||
var args = new CustomEventReceivedArgs() { Hash=p.Hash, Args=p.Args, Sender=sender };
|
||||
List<Action<CustomEventReceivedArgs>> handlers;
|
||||
@ -75,7 +72,7 @@ namespace RageCoop.Server.Scripting
|
||||
handlers.ForEach((x) => { x.Invoke(args); });
|
||||
}
|
||||
}
|
||||
internal static bool InvokeOnCommandReceived(string cname,string[] cargs,Client sender)
|
||||
internal bool InvokeOnCommandReceived(string cname, string[] cargs, Client sender)
|
||||
{
|
||||
var args = new OnCommandEventArgs()
|
||||
{
|
||||
@ -83,16 +80,23 @@ namespace RageCoop.Server.Scripting
|
||||
Args=cargs,
|
||||
Sender=sender
|
||||
};
|
||||
OnCommandReceived?.Invoke(null,args);
|
||||
OnCommandReceived?.Invoke(this, args);
|
||||
return args.Cancel;
|
||||
}
|
||||
internal static void InvokePlayerUpdate(Client client)
|
||||
internal void InvokePlayerUpdate(Client client)
|
||||
{
|
||||
OnPlayerUpdate?.Invoke(null,client);
|
||||
OnPlayerUpdate?.Invoke(this, client);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class API
|
||||
{
|
||||
private readonly Server Server;
|
||||
internal API(Server server)
|
||||
{
|
||||
Server=server;
|
||||
}
|
||||
public APIEvents Events { get; set; }=new APIEvents();
|
||||
#region FUNCTIONS
|
||||
/*
|
||||
/// <summary>
|
||||
@ -101,7 +105,7 @@ namespace RageCoop.Server.Scripting
|
||||
/// </summary>
|
||||
/// <param name="hash">The hash (Example: 0x25223CA6B4D20B7F = GET_CLOCK_HOURS)</param>
|
||||
/// <param name="args">The arguments (Example: string = int, object = 5)</param>
|
||||
public static void SendNativeCallToAll(GTA.Native.Hash hash, params object[] args)
|
||||
public void SendNativeCallToAll(GTA.Native.Hash hash, params object[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -112,7 +116,7 @@ namespace RageCoop.Server.Scripting
|
||||
|
||||
if (args != null && args.Length == 0)
|
||||
{
|
||||
Program.Logger.Error($"[ServerScript->SendNativeCallToAll(ulong hash, params object[] args)]: args is not null!");
|
||||
Server.Logger?.Error($"[ServerScript->SendNativeCallToAll(ulong hash, params object[] args)]: args is not null!");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -128,7 +132,7 @@ namespace RageCoop.Server.Scripting
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
||||
Server.Logger?.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
||||
}
|
||||
}
|
||||
*/
|
||||
@ -136,7 +140,7 @@ namespace RageCoop.Server.Scripting
|
||||
/// Get a list of all Clients
|
||||
/// </summary>
|
||||
/// <returns>All clients as a dictionary indexed by NetID</returns>
|
||||
public static Dictionary<long, Client> GetAllClients()
|
||||
public Dictionary<long, Client> GetAllClients()
|
||||
{
|
||||
return new(Server.Clients);
|
||||
}
|
||||
@ -146,7 +150,7 @@ namespace RageCoop.Server.Scripting
|
||||
/// </summary>
|
||||
/// <param name="username">The username to search for (non case-sensitive)</param>
|
||||
/// <returns>The Client from this user or null</returns>
|
||||
public static Client GetClientByUsername(string username)
|
||||
public Client GetClientByUsername(string username)
|
||||
{
|
||||
return Server.Clients.Values.FirstOrDefault(x => x.Username.ToLower() == username.ToLower());
|
||||
}
|
||||
@ -156,7 +160,7 @@ namespace RageCoop.Server.Scripting
|
||||
/// </summary>
|
||||
/// <param name="message">The chat message</param>
|
||||
/// <param name="username">The username which send this message (default = "Server")</param>
|
||||
public static void SendChatMessage(string message, List<Client> targets = null, string username = "Server")
|
||||
public void SendChatMessage(string message, List<Client> targets = null, string username = "Server")
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -172,10 +176,10 @@ namespace RageCoop.Server.Scripting
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
||||
Server.Logger?.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
||||
}
|
||||
}
|
||||
public static void SendChatMessage(string message, Client target, string username = "Server")
|
||||
public void SendChatMessage(string message, Client target, string username = "Server")
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -183,27 +187,29 @@ namespace RageCoop.Server.Scripting
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
||||
Server.Logger?.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send CleanUpWorld to all players to delete all objects created by the server
|
||||
/// </summary>
|
||||
public static void SendCleanUpWorldToAll(List<long> netHandleList = null)
|
||||
public void SendCleanUpWorldToAll(List<Client> clients = null)
|
||||
{
|
||||
if (Server.MainNetServer.ConnectionsCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<NetConnection> connections = netHandleList == null
|
||||
? Server.MainNetServer.Connections
|
||||
: Server.MainNetServer.Connections.FindAll(c => netHandleList.Contains(c.RemoteUniqueIdentifier));
|
||||
|
||||
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
||||
outgoingMessage.Write((byte)PacketTypes.CleanUpWorld);
|
||||
Server.MainNetServer.SendMessage(outgoingMessage, connections, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Default);
|
||||
if (clients == null)
|
||||
{
|
||||
Server.MainNetServer.SendToAll(outgoingMessage, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Default);
|
||||
}
|
||||
else
|
||||
{
|
||||
clients.ForEach(client => { Server.MainNetServer.SendMessage(outgoingMessage,client.Connection, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Default); });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -213,7 +219,7 @@ namespace RageCoop.Server.Scripting
|
||||
/// <param name="usage">How to use this message (argsLength required!)</param>
|
||||
/// <param name="argsLength">The length of args (Example: "/message USERNAME MESSAGE" = 2) (usage required!)</param>
|
||||
/// <param name="callback">Create a new function!</param>
|
||||
public static void RegisterCommand(string name, string usage, short argsLength, Action<CommandContext> callback)
|
||||
public void RegisterCommand(string name, string usage, short argsLength, Action<CommandContext> callback)
|
||||
{
|
||||
Server.RegisterCommand(name, usage, argsLength, callback);
|
||||
}
|
||||
@ -222,7 +228,7 @@ namespace RageCoop.Server.Scripting
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the command (Example: "test" for "/test")</param>
|
||||
/// <param name="callback">Create a new function!</param>
|
||||
public static void RegisterCommand(string name, Action<CommandContext> callback)
|
||||
public void RegisterCommand(string name, Action<CommandContext> callback)
|
||||
{
|
||||
Server.RegisterCommand(name, callback);
|
||||
}
|
||||
@ -231,18 +237,18 @@ namespace RageCoop.Server.Scripting
|
||||
/// Register a class of commands
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The name of your class with functions</typeparam>
|
||||
public static void RegisterCommands<T>()
|
||||
public void RegisterCommands<T>()
|
||||
{
|
||||
Server.RegisterCommands<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send an event and data to the specified clients.
|
||||
/// Send an event and data to the specified clients. Use <see cref="Client.SendCustomEvent(int, List{object})"/> if you want to send event to individual client.
|
||||
/// </summary>
|
||||
/// <param name="eventHash">An unique identifier of the event</param>
|
||||
/// <param name="args">The objects conataing your data, supported types: byte, short, ushort, int, uint, long, ulong, float, bool, string.</param>
|
||||
/// <param name="targets">The target clients to send.</param>
|
||||
public static void SendCustomEvent(int eventHash,List<object> args,List<Client> targets=null)
|
||||
/// <param name="targets">The target clients to send. Leave it null to send to all clients</param>
|
||||
public void SendCustomEvent(int eventHash,List<object> args,List<Client> targets=null)
|
||||
{
|
||||
targets ??= new(Server.Clients.Values);
|
||||
var p = new Packets.CustomEvent()
|
||||
@ -260,25 +266,25 @@ namespace RageCoop.Server.Scripting
|
||||
/// </summary>
|
||||
/// <param name="hash">An unique identifier of the event, you can hash your event name with <see cref="Core.Scripting.CustomEvents.Hash(string)"/></param>
|
||||
/// <param name="handler">An handler to be invoked when the event is received from the server. This will be invoked from main thread.
|
||||
public static void RegisterCustomEventHandler(int hash,Action<CustomEventReceivedArgs> handler)
|
||||
public void RegisterCustomEventHandler(int hash,Action<CustomEventReceivedArgs> handler)
|
||||
{
|
||||
List<Action<CustomEventReceivedArgs>> handlers;
|
||||
lock (CustomEventHandlers)
|
||||
lock (Events.CustomEventHandlers)
|
||||
{
|
||||
if (!CustomEventHandlers.TryGetValue(hash,out handlers))
|
||||
if (!Events.CustomEventHandlers.TryGetValue(hash,out handlers))
|
||||
{
|
||||
CustomEventHandlers.Add(hash, handlers = new List<Action<CustomEventReceivedArgs>>());
|
||||
Events.CustomEventHandlers.Add(hash, handlers = new List<Action<CustomEventReceivedArgs>>());
|
||||
}
|
||||
handlers.Add(handler);
|
||||
}
|
||||
}
|
||||
public static void RegisterCustomEventHandler(string name, Action<CustomEventReceivedArgs> handler)
|
||||
public void RegisterCustomEventHandler(string name, Action<CustomEventReceivedArgs> handler)
|
||||
{
|
||||
RegisterCustomEventHandler(CustomEvents.Hash(name), handler);
|
||||
}
|
||||
public static Logger GetLogger()
|
||||
public Logger GetLogger()
|
||||
{
|
||||
return Program.Logger;
|
||||
return Server.Logger;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@ -11,9 +11,13 @@ namespace RageCoop.Server.Scripting
|
||||
{
|
||||
internal class Resources : ResourceLoader
|
||||
{
|
||||
public Resources() : base("RageCoop.Server.Scripting.ServerScript", Program.Logger) { }
|
||||
private readonly Server Server;
|
||||
public Resources(Server server) : base("RageCoop.Server.Scripting.ServerScript", server.Logger)
|
||||
{
|
||||
Server = server;
|
||||
}
|
||||
|
||||
public static bool HasClientResources = false;
|
||||
public bool HasClientResources = false;
|
||||
public void LoadAll()
|
||||
{
|
||||
#region CLIENT
|
||||
@ -23,7 +27,7 @@ namespace RageCoop.Server.Scripting
|
||||
if (clientResources.Length!=0)
|
||||
{
|
||||
// Pack client side resources as a zip file
|
||||
Logger.Info("Packing client-side resources");
|
||||
Logger?.Info("Packing client-side resources");
|
||||
|
||||
try
|
||||
{
|
||||
@ -41,8 +45,8 @@ namespace RageCoop.Server.Scripting
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error("Failed to pack client resources");
|
||||
Logger.Error(ex);
|
||||
Logger?.Error("Failed to pack client resources");
|
||||
Logger?.Error(ex);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@ -52,7 +56,7 @@ namespace RageCoop.Server.Scripting
|
||||
Directory.CreateDirectory(path);
|
||||
foreach (var resource in Directory.GetDirectories(path))
|
||||
{
|
||||
Logger.Info($"Loading resource: {Path.GetFileName(resource)}");
|
||||
Logger?.Info($"Loading resource: {Path.GetFileName(resource)}");
|
||||
LoadResource(resource);
|
||||
}
|
||||
|
||||
@ -61,14 +65,15 @@ namespace RageCoop.Server.Scripting
|
||||
{
|
||||
foreach (var d in LoadedResources)
|
||||
{
|
||||
foreach (var s in d.Scripts)
|
||||
foreach (ServerScript s in d.Scripts)
|
||||
{
|
||||
(s as ServerScript).CurrentResource = d;
|
||||
s.CurrentResource = d;
|
||||
s.API=Server.API;
|
||||
try
|
||||
{
|
||||
s.OnStart();
|
||||
}
|
||||
catch(Exception ex) {Logger.Error($"Failed to start resource: {d.Name}"); Logger.Error(ex); }
|
||||
catch(Exception ex) {Logger?.Error($"Failed to start resource: {d.Name}"); Logger?.Error(ex); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -104,9 +109,9 @@ namespace RageCoop.Server.Scripting
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
Logger.Info($"Sending resources to client:{client.Username}");
|
||||
Logger?.Info($"Sending resources to client:{client.Username}");
|
||||
Server.SendFile(path, "Resources.zip", client);
|
||||
Logger.Info($"Resources sent to:{client.Username}");
|
||||
Logger?.Info($"Resources sent to:{client.Username}");
|
||||
|
||||
});
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace RageCoop.Server.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Inherit from this class, constructor will be called automatically, but other scripts might have yet been loaded, you should use <see cref="OnStart"/>. to initiate your script.
|
||||
/// Inherit from this class, constructor will be called automatically, but other scripts might have yet been loaded and <see cref="API"/> will be null, you should use <see cref="OnStart"/>. to initiate your script.
|
||||
/// </summary>
|
||||
public abstract class ServerScript :Core.Scripting.IScriptable
|
||||
{
|
||||
@ -20,6 +20,8 @@ namespace RageCoop.Server.Scripting
|
||||
/// Get the <see cref="Core.Scripting.Resource"/> object this script belongs to, this property will be initiated before <see cref="OnStart"/> (will be null if you access it in the constructor).
|
||||
/// </summary>
|
||||
public Core.Scripting.Resource CurrentResource { get;internal set; }
|
||||
|
||||
public API API { get; set; }
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
|
||||
|
@ -26,24 +26,29 @@ namespace RageCoop.Server
|
||||
|
||||
internal class Server
|
||||
{
|
||||
private static readonly string _compatibleVersion = "V0_5";
|
||||
public static BaseScript BaseScript { get; set; }=new BaseScript();
|
||||
public static readonly Settings MainSettings = Util.Read<Settings>("Settings.xml");
|
||||
public static NetServer MainNetServer;
|
||||
private readonly string _compatibleVersion = "V0_5";
|
||||
public BaseScript BaseScript { get; set; }=new BaseScript();
|
||||
public readonly Settings MainSettings = Util.Read<Settings>("Settings.xml");
|
||||
public NetServer MainNetServer;
|
||||
|
||||
public static readonly Dictionary<Command, Action<CommandContext>> Commands = new();
|
||||
public static readonly Dictionary<long,Client> Clients = new();
|
||||
private static System.Timers.Timer SendPlayerTimer = new System.Timers.Timer(5000);
|
||||
public readonly Dictionary<Command, Action<CommandContext>> Commands = new();
|
||||
public readonly Dictionary<long,Client> Clients = new();
|
||||
private System.Timers.Timer SendPlayerTimer = new System.Timers.Timer(5000);
|
||||
|
||||
private static Dictionary<int,FileTransfer> InProgressFileTransfers=new();
|
||||
private static Resources Resources = new Resources();
|
||||
public Server()
|
||||
private Dictionary<int,FileTransfer> InProgressFileTransfers=new();
|
||||
private Resources Resources;
|
||||
public API API;
|
||||
public Logger Logger;
|
||||
public Server(Logger logger=null)
|
||||
{
|
||||
Program.Logger.Info("================");
|
||||
Program.Logger.Info($"Server bound to: 0.0.0.0:{MainSettings.Port}");
|
||||
Program.Logger.Info($"Server version: {Assembly.GetCallingAssembly().GetName().Version}");
|
||||
Program.Logger.Info($"Compatible RAGECOOP versions: {_compatibleVersion.Replace('_', '.')}.x");
|
||||
Program.Logger.Info("================");
|
||||
Logger=logger;
|
||||
API=new API(this);
|
||||
Resources=new Resources(this);
|
||||
Logger?.Info("================");
|
||||
Logger?.Info($"Server bound to: 0.0.0.0:{MainSettings.Port}");
|
||||
Logger?.Info($"Server version: {Assembly.GetCallingAssembly().GetName().Version}");
|
||||
Logger?.Info($"Compatible RAGECOOP versions: {_compatibleVersion.Replace('_', '.')}.x");
|
||||
Logger?.Info("================");
|
||||
|
||||
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
|
||||
NetPeerConfiguration config = new("623c92c287cc392406e7aaaac1c0f3b0")
|
||||
@ -62,7 +67,7 @@ namespace RageCoop.Server
|
||||
SendPlayerTimer.Elapsed+=(s,e) => { SendPlayerInfos(); };
|
||||
SendPlayerTimer.AutoReset=true;
|
||||
SendPlayerTimer.Enabled=true;
|
||||
Program.Logger.Info(string.Format("Server listening on {0}:{1}", config.LocalAddress.ToString(), config.Port));
|
||||
Logger?.Info(string.Format("Server listening on {0}:{1}", config.LocalAddress.ToString(), config.Port));
|
||||
if (MainSettings.AnnounceSelf)
|
||||
{
|
||||
|
||||
@ -89,11 +94,11 @@ namespace RageCoop.Server
|
||||
|
||||
string content = await response.Content.ReadAsStringAsync();
|
||||
info = JsonConvert.DeserializeObject<IpInfo>(content);
|
||||
Program.Logger.Info($"Your public IP is {info.Address}, announcing to master server...");
|
||||
Logger?.Info($"Your public IP is {info.Address}, announcing to master server...");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Program.Logger.Error(ex.InnerException?.Message ?? ex.Message);
|
||||
Logger?.Error(ex.InnerException?.Message ?? ex.Message);
|
||||
return;
|
||||
}
|
||||
var realMaster = MainSettings.MasterServer=="[AUTO]" ? Util.DownloadString("https://ragecoop.online/stuff/masterserver") : MainSettings.MasterServer;
|
||||
@ -115,7 +120,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Program.Logger.Error($"MasterServer: {ex.Message}");
|
||||
Logger?.Error($"MasterServer: {ex.Message}");
|
||||
|
||||
// Sleep for 5s
|
||||
Thread.Sleep(5000);
|
||||
@ -124,19 +129,19 @@ namespace RageCoop.Server
|
||||
|
||||
if (response == null)
|
||||
{
|
||||
Program.Logger.Error("MasterServer: Something went wrong!");
|
||||
Logger?.Error("MasterServer: Something went wrong!");
|
||||
}
|
||||
else if (response.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
if (response.StatusCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
string requestContent = await response.Content.ReadAsStringAsync();
|
||||
Program.Logger.Error($"MasterServer: [{(int)response.StatusCode}], {requestContent}");
|
||||
Logger?.Error($"MasterServer: [{(int)response.StatusCode}], {requestContent}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Program.Logger.Error($"MasterServer: [{(int)response.StatusCode}]");
|
||||
Program.Logger.Error($"MasterServer: [{await response.Content.ReadAsStringAsync()}]");
|
||||
Logger?.Error($"MasterServer: [{(int)response.StatusCode}]");
|
||||
Logger?.Error($"MasterServer: [{await response.Content.ReadAsStringAsync()}]");
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,15 +151,16 @@ namespace RageCoop.Server
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
Program.Logger.Error($"MasterServer: {ex.InnerException.Message}");
|
||||
Logger?.Error($"MasterServer: {ex.InnerException.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Program.Logger.Error($"MasterServer: {ex.Message}");
|
||||
Logger?.Error($"MasterServer: {ex.Message}");
|
||||
}
|
||||
}).Start();
|
||||
#endregion
|
||||
}
|
||||
BaseScript.API=API;
|
||||
BaseScript.OnStart();
|
||||
Resources.LoadAll();
|
||||
Listen();
|
||||
@ -162,20 +168,27 @@ namespace RageCoop.Server
|
||||
|
||||
private void Listen()
|
||||
{
|
||||
Program.Logger.Info("Listening for clients");
|
||||
Program.Logger.Info("Please use CTRL + C if you want to stop the server!");
|
||||
Logger?.Info("Listening for clients");
|
||||
Logger?.Info("Please use CTRL + C if you want to stop the server!");
|
||||
|
||||
|
||||
while (!Program.ReadyToStop)
|
||||
{
|
||||
ProcessMessage(MainNetServer.WaitMessage(10));
|
||||
try
|
||||
{
|
||||
ProcessMessage(MainNetServer.WaitMessage(200));
|
||||
}
|
||||
Program.Logger.Warning("Server is shutting down!");
|
||||
catch(Exception ex)
|
||||
{
|
||||
Logger?.Error("Error processing message");
|
||||
Logger?.Error(ex);
|
||||
}
|
||||
}
|
||||
Logger?.Warning("Server is shutting down!");
|
||||
MainNetServer.Shutdown("Server is shutting down!");
|
||||
Program.Logger.Info("Waiting for resources to stop...Press Ctrl+C again to forcibly terminate the program.");
|
||||
Logger?.Info("Waiting for resources to stop...Press Ctrl+C again to forcibly terminate the program.");
|
||||
BaseScript.OnStop();
|
||||
Resources.StopAll();
|
||||
Program.Logger.Dispose();
|
||||
}
|
||||
|
||||
Client sender;
|
||||
@ -186,10 +199,10 @@ namespace RageCoop.Server
|
||||
{
|
||||
case NetIncomingMessageType.ConnectionApproval:
|
||||
{
|
||||
Program.Logger.Info($"New incoming connection from: [{message.SenderConnection.RemoteEndPoint}]");
|
||||
Logger?.Info($"New incoming connection from: [{message.SenderConnection.RemoteEndPoint}]");
|
||||
if (message.ReadByte() != (byte)PacketTypes.Handshake)
|
||||
{
|
||||
Program.Logger.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: Wrong packet!");
|
||||
Logger?.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: Wrong packet!");
|
||||
message.SenderConnection.Deny("Wrong packet!");
|
||||
}
|
||||
else
|
||||
@ -206,7 +219,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Program.Logger.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: {e.Message}");
|
||||
Logger?.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: {e.Message}");
|
||||
message.SenderConnection.Deny(e.Message);
|
||||
}
|
||||
}
|
||||
@ -214,19 +227,27 @@ namespace RageCoop.Server
|
||||
}
|
||||
case NetIncomingMessageType.StatusChanged:
|
||||
{
|
||||
// Get sender client
|
||||
if (!Clients.TryGetValue(message.SenderConnection.RemoteUniqueIdentifier, out sender))
|
||||
{
|
||||
break;
|
||||
}
|
||||
NetConnectionStatus status = (NetConnectionStatus)message.ReadByte();
|
||||
|
||||
if (status == NetConnectionStatus.Disconnected)
|
||||
{
|
||||
long nethandle = message.SenderConnection.RemoteUniqueIdentifier;
|
||||
|
||||
|
||||
SendPlayerDisconnectPacket(nethandle);
|
||||
SendPlayerDisconnectPacket(sender);
|
||||
}
|
||||
else if (status == NetConnectionStatus.Connected)
|
||||
{
|
||||
SendPlayerConnectPacket(message.SenderConnection);
|
||||
Resources.SendTo(Util.GetClientByNetID(message.SenderConnection.RemoteUniqueIdentifier));
|
||||
SendPlayerConnectPacket(sender);
|
||||
Resources.SendTo(sender);
|
||||
API.Events.InvokePlayerConnected(sender);
|
||||
if (sender.IsReady)
|
||||
{
|
||||
API.Events.InvokePlayerReady(sender);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -291,7 +312,7 @@ namespace RageCoop.Server
|
||||
|
||||
Packets.ProjectileSync packet = new();
|
||||
packet.Unpack(data);
|
||||
ProjectileSync(packet, message.SenderConnection.RemoteUniqueIdentifier);
|
||||
ProjectileSync(packet, sender);
|
||||
|
||||
}
|
||||
break;
|
||||
@ -329,7 +350,8 @@ namespace RageCoop.Server
|
||||
toRemove.Cancel=true;
|
||||
if (toRemove.Name=="Resources.zip")
|
||||
{
|
||||
Clients[message.SenderConnection.RemoteUniqueIdentifier].IsReady=true;
|
||||
sender.IsReady=true;
|
||||
API.Events.InvokePlayerReady(sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -339,14 +361,14 @@ namespace RageCoop.Server
|
||||
{
|
||||
// Sync Events
|
||||
try
|
||||
{
|
||||
var toSend = MainNetServer.Connections.Exclude(message.SenderConnection);
|
||||
if (toSend.Count!=0)
|
||||
{
|
||||
var outgoingMessage = MainNetServer.CreateMessage();
|
||||
outgoingMessage.Write(btype);
|
||||
outgoingMessage.Write(len);
|
||||
outgoingMessage.Write(data);
|
||||
var toSend = MainNetServer.Connections.Exclude(message.SenderConnection);
|
||||
if (toSend.Count!=0)
|
||||
{
|
||||
MainNetServer.SendMessage(outgoingMessage, toSend, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.SyncEvents);
|
||||
}
|
||||
}
|
||||
@ -357,7 +379,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
else
|
||||
{
|
||||
Program.Logger.Error("Unhandled Data / Packet type");
|
||||
Logger?.Error("Unhandled Data / Packet type");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -370,32 +392,36 @@ namespace RageCoop.Server
|
||||
}
|
||||
case NetIncomingMessageType.ConnectionLatencyUpdated:
|
||||
{
|
||||
Client client = Util.GetClientByNetID(message.SenderConnection.RemoteUniqueIdentifier);
|
||||
if (client != null)
|
||||
// Get sender client
|
||||
if (!Clients.TryGetValue(message.SenderConnection.RemoteUniqueIdentifier, out sender))
|
||||
{
|
||||
client.Latency = message.ReadFloat();
|
||||
break;
|
||||
}
|
||||
if (sender != null)
|
||||
{
|
||||
sender.Latency = message.ReadFloat();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetIncomingMessageType.ErrorMessage:
|
||||
Program.Logger.Error(message.ReadString());
|
||||
Logger?.Error(message.ReadString());
|
||||
break;
|
||||
case NetIncomingMessageType.WarningMessage:
|
||||
Program.Logger.Warning(message.ReadString());
|
||||
Logger?.Warning(message.ReadString());
|
||||
break;
|
||||
case NetIncomingMessageType.DebugMessage:
|
||||
case NetIncomingMessageType.VerboseDebugMessage:
|
||||
Program.Logger.Debug(message.ReadString());
|
||||
Logger?.Debug(message.ReadString());
|
||||
break;
|
||||
default:
|
||||
Program.Logger.Error(string.Format("Unhandled type: {0} {1} bytes {2} | {3}", message.MessageType, message.LengthBytes, message.DeliveryMethod, message.SequenceChannel));
|
||||
Logger?.Error(string.Format("Unhandled type: {0} {1} bytes {2} | {3}", message.MessageType, message.LengthBytes, message.DeliveryMethod, message.SequenceChannel));
|
||||
break;
|
||||
}
|
||||
|
||||
MainNetServer.Recycle(message);
|
||||
}
|
||||
static object _sendPlayersLock=new object();
|
||||
public static void SendPlayerInfos()
|
||||
object _sendPlayersLock=new object();
|
||||
public void SendPlayerInfos()
|
||||
{
|
||||
lock (_sendPlayersLock)
|
||||
{
|
||||
@ -422,9 +448,9 @@ namespace RageCoop.Server
|
||||
|
||||
private void DisconnectAndLog(NetConnection senderConnection,PacketTypes type, Exception e)
|
||||
{
|
||||
Program.Logger.Error($"Error receiving a packet of type {type}");
|
||||
Program.Logger.Error(e.Message);
|
||||
Program.Logger.Error(e.StackTrace);
|
||||
Logger?.Error($"Error receiving a packet of type {type}");
|
||||
Logger?.Error(e.Message);
|
||||
Logger?.Error(e.StackTrace);
|
||||
senderConnection.Disconnect(e.Message);
|
||||
}
|
||||
|
||||
@ -432,7 +458,7 @@ namespace RageCoop.Server
|
||||
// Before we approve the connection, we must shake hands
|
||||
private void GetHandshake(NetConnection connection, Packets.Handshake packet)
|
||||
{
|
||||
Program.Logger.Debug("New handshake from: [Name: " + packet.Username + " | Address: " + connection.RemoteEndPoint.Address.ToString() + "]");
|
||||
Logger?.Debug("New handshake from: [Name: " + packet.Username + " | Address: " + connection.RemoteEndPoint.Address.ToString() + "]");
|
||||
|
||||
if (!packet.ModVersion.StartsWith(_compatibleVersion))
|
||||
{
|
||||
@ -476,7 +502,7 @@ namespace RageCoop.Server
|
||||
lock (Clients)
|
||||
{
|
||||
Clients.Add(connection.RemoteUniqueIdentifier,
|
||||
tmpClient = new Client()
|
||||
tmpClient = new Client(this)
|
||||
{
|
||||
NetID = connection.RemoteUniqueIdentifier,
|
||||
Connection=connection,
|
||||
@ -489,7 +515,7 @@ namespace RageCoop.Server
|
||||
);;
|
||||
}
|
||||
|
||||
Program.Logger.Debug($"Handshake sucess, Player:{packet.Username} PedID:{packet.PedID}");
|
||||
Logger?.Debug($"Handshake sucess, Player:{packet.Username} PedID:{packet.PedID}");
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
|
||||
// Create a new handshake packet
|
||||
@ -504,93 +530,68 @@ namespace RageCoop.Server
|
||||
}
|
||||
|
||||
// The connection has been approved, now we need to send all other players to the new player and the new player to all players
|
||||
private static void SendPlayerConnectPacket(NetConnection local)
|
||||
private void SendPlayerConnectPacket(Client newClient)
|
||||
{
|
||||
Client localClient = Util.GetClientByNetID(local.RemoteUniqueIdentifier);
|
||||
if (localClient == null)
|
||||
{
|
||||
local.Disconnect("No data found!");
|
||||
return;
|
||||
}
|
||||
|
||||
List<NetConnection> clients=MainNetServer.Connections.Exclude(local);
|
||||
// Send all players to local
|
||||
|
||||
|
||||
if (clients.Count > 0)
|
||||
// Send other players to this client
|
||||
Clients.Values.ForEach(target =>
|
||||
{
|
||||
clients.ForEach(targetPlayer =>
|
||||
{
|
||||
long targetNetHandle = targetPlayer.RemoteUniqueIdentifier;
|
||||
if (target==newClient) { return; }
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
|
||||
Client targetClient = Util.GetClientByNetID(targetNetHandle);
|
||||
if (targetClient != null)
|
||||
{
|
||||
new Packets.PlayerConnect()
|
||||
{
|
||||
// NetHandle = targetNetHandle,
|
||||
Username = targetClient.Username,
|
||||
PedID=targetClient.ID,
|
||||
Username = target.Username,
|
||||
PedID=target.ID,
|
||||
|
||||
}.Pack(outgoingMessage);
|
||||
MainNetServer.SendMessage(outgoingMessage, local, NetDeliveryMethod.ReliableOrdered, 0);
|
||||
}
|
||||
MainNetServer.SendMessage(outgoingMessage, newClient.Connection, NetDeliveryMethod.ReliableOrdered, 0);
|
||||
});
|
||||
|
||||
// Send local to all players
|
||||
// Send new client to all players
|
||||
var cons = MainNetServer.Connections.Exclude(newClient.Connection);
|
||||
if (cons.Count!=0)
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
new Packets.PlayerConnect()
|
||||
{
|
||||
PedID=localClient.ID,
|
||||
Username = localClient.Username
|
||||
PedID=newClient.ID,
|
||||
Username = newClient.Username
|
||||
}.Pack(outgoingMessage);
|
||||
if(clients.Count > 0)
|
||||
{
|
||||
MainNetServer.SendMessage(outgoingMessage, clients, NetDeliveryMethod.ReliableOrdered, 0);
|
||||
}
|
||||
}
|
||||
API.Events.InvokePlayerConnected(localClient);
|
||||
|
||||
Program.Logger.Info($"Player {localClient.Username} connected!");
|
||||
MainNetServer.SendMessage(outgoingMessage,cons , NetDeliveryMethod.ReliableOrdered, 0);
|
||||
|
||||
}
|
||||
|
||||
Logger?.Info($"Player {newClient.Username} connected!");
|
||||
|
||||
if (!string.IsNullOrEmpty(MainSettings.WelcomeMessage))
|
||||
{
|
||||
SendChatMessage(new Packets.ChatMessage() { Username = "Server", Message = MainSettings.WelcomeMessage }, null,new List<NetConnection>() { local });
|
||||
SendChatMessage(new Packets.ChatMessage() { Username = "Server", Message = MainSettings.WelcomeMessage }, null,new List<NetConnection>() { newClient.Connection });
|
||||
}
|
||||
}
|
||||
|
||||
// Send all players a message that someone has left the server
|
||||
private static void SendPlayerDisconnectPacket(long nethandle)
|
||||
private void SendPlayerDisconnectPacket(Client localClient)
|
||||
{
|
||||
List<NetConnection> clients = MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != nethandle);
|
||||
int playerPedID = Clients[nethandle].ID;
|
||||
if (clients.Count > 0)
|
||||
var cons = MainNetServer.Connections.Exclude(localClient.Connection);
|
||||
if (cons.Count!=0)
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
new Packets.PlayerDisconnect()
|
||||
{
|
||||
PedID=playerPedID,
|
||||
PedID=localClient.ID,
|
||||
|
||||
}.Pack(outgoingMessage);
|
||||
MainNetServer.SendMessage(outgoingMessage, clients, NetDeliveryMethod.ReliableOrdered, 0);
|
||||
MainNetServer.SendMessage(outgoingMessage,cons , NetDeliveryMethod.ReliableOrdered, 0);
|
||||
}
|
||||
|
||||
Client localClient = Util.GetClientByNetID( nethandle);
|
||||
if (localClient == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Clients.Remove(localClient.NetID);
|
||||
|
||||
API.Events.InvokePlayerDisconnected(localClient);
|
||||
Program.Logger.Info($"Player {localClient.Username} disconnected! ID:{playerPedID}");
|
||||
Logger?.Info($"Player {localClient.Username} disconnected! ID:{localClient.ID}");
|
||||
Clients.Remove(localClient.NetID);
|
||||
|
||||
}
|
||||
|
||||
#region SyncEntities
|
||||
private static void PedStateSync(Packets.PedStateSync packet, Client client)
|
||||
private void PedStateSync(Packets.PedStateSync packet, Client client)
|
||||
{
|
||||
|
||||
|
||||
@ -604,7 +605,7 @@ namespace RageCoop.Server
|
||||
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
||||
}
|
||||
}
|
||||
private static void VehicleStateSync(Packets.VehicleStateSync packet, Client client)
|
||||
private void VehicleStateSync(Packets.VehicleStateSync packet, Client client)
|
||||
{
|
||||
// Save the new data
|
||||
if (packet.Passengers.ContainsValue(client.ID))
|
||||
@ -620,7 +621,7 @@ namespace RageCoop.Server
|
||||
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
||||
}
|
||||
}
|
||||
private static void PedSync(Packets.PedSync packet, Client client)
|
||||
private void PedSync(Packets.PedSync packet, Client client)
|
||||
{
|
||||
bool isPlayer = packet.ID==client.ID;
|
||||
if (isPlayer)
|
||||
@ -654,7 +655,7 @@ namespace RageCoop.Server
|
||||
MainNetServer.SendMessage(outgoingMessage,c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
||||
}
|
||||
}
|
||||
private static void VehicleSync(Packets.VehicleSync packet, Client client)
|
||||
private void VehicleSync(Packets.VehicleSync packet, Client client)
|
||||
{
|
||||
bool isPlayer = packet.ID==client.Player.VehicleID;
|
||||
foreach (var c in Clients.Values)
|
||||
@ -678,13 +679,8 @@ namespace RageCoop.Server
|
||||
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
||||
}
|
||||
}
|
||||
private static void ProjectileSync(Packets.ProjectileSync packet, long ClientID)
|
||||
private void ProjectileSync(Packets.ProjectileSync packet, Client client)
|
||||
{
|
||||
Client client = Util.GetClientByNetID(ClientID);
|
||||
if (client == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var c in Clients.Values)
|
||||
{
|
||||
@ -697,7 +693,7 @@ namespace RageCoop.Server
|
||||
|
||||
#endregion
|
||||
// Send a message to targets or all players
|
||||
private static void SendChatMessage(Packets.ChatMessage packet,Client sender=null, List<NetConnection> targets = null)
|
||||
private void SendChatMessage(Packets.ChatMessage packet,Client sender=null, List<NetConnection> targets = null)
|
||||
{
|
||||
if (packet.Message.StartsWith('/'))
|
||||
{
|
||||
@ -722,13 +718,8 @@ namespace RageCoop.Server
|
||||
|
||||
if (command.Key.Usage != null && command.Key.ArgsLength != argsWithoutCmd.Length)
|
||||
{
|
||||
NetConnection userConnection = Util.GetConnectionByUsername(packet.Username);
|
||||
if (userConnection == default)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendChatMessage("Server", command.Key.Usage, userConnection);
|
||||
SendChatMessage("Server", command.Key.Usage,sender.Connection);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -736,13 +727,8 @@ namespace RageCoop.Server
|
||||
}
|
||||
else
|
||||
{
|
||||
NetConnection userConnection = Util.GetConnectionByUsername(packet.Username);
|
||||
if (userConnection == default)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendChatMessage("Server", "Command not found!", userConnection);
|
||||
SendChatMessage("Server", "Command not found!", sender.Connection);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -750,25 +736,26 @@ namespace RageCoop.Server
|
||||
packet.Message = packet.Message.Replace("~", "");
|
||||
SendChatMessage(packet.Username, packet.Message, targets);
|
||||
|
||||
Program.Logger.Info(packet.Username + ": " + packet.Message);
|
||||
Logger?.Info(packet.Username + ": " + packet.Message);
|
||||
}
|
||||
|
||||
public static void SendChatMessage(string username, string message, List<NetConnection> targets = null)
|
||||
public void SendChatMessage(string username, string message, List<NetConnection> targets = null)
|
||||
{
|
||||
if (MainNetServer.Connections.Count==0) { return; }
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
|
||||
new Packets.ChatMessage() { Username = username, Message = message }.Pack(outgoingMessage);
|
||||
|
||||
MainNetServer.SendMessage(outgoingMessage, targets ?? MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Chat);
|
||||
}
|
||||
public static void SendChatMessage(string username, string message, NetConnection target)
|
||||
public void SendChatMessage(string username, string message, NetConnection target)
|
||||
{
|
||||
SendChatMessage(username, message, new List<NetConnection>() { target });
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public static void RegisterCommand(string name, string usage, short argsLength, Action<CommandContext> callback)
|
||||
public void RegisterCommand(string name, string usage, short argsLength, Action<CommandContext> callback)
|
||||
{
|
||||
Command command = new(name) { Usage = usage, ArgsLength = argsLength };
|
||||
|
||||
@ -779,7 +766,7 @@ namespace RageCoop.Server
|
||||
|
||||
Commands.Add(command, callback);
|
||||
}
|
||||
public static void RegisterCommand(string name, Action<CommandContext> callback)
|
||||
public void RegisterCommand(string name, Action<CommandContext> callback)
|
||||
{
|
||||
Command command = new(name);
|
||||
|
||||
@ -791,7 +778,7 @@ namespace RageCoop.Server
|
||||
Commands.Add(command, callback);
|
||||
}
|
||||
|
||||
public static void RegisterCommands<T>()
|
||||
public void RegisterCommands<T>()
|
||||
{
|
||||
IEnumerable<MethodInfo> commands = typeof(T).GetMethods().Where(method => method.GetCustomAttributes(typeof(Command), false).Any());
|
||||
|
||||
@ -803,13 +790,13 @@ namespace RageCoop.Server
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendFile(string path,string name,Client client,Action<float> updateCallback=null)
|
||||
public void SendFile(string path,string name,Client client,Action<float> updateCallback=null)
|
||||
{
|
||||
int id = RequestFileID();
|
||||
var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
fs.Seek(0, SeekOrigin.Begin);
|
||||
var total = fs.Length;
|
||||
Program.Logger.Debug($"Initiating file transfer:{name}, {total}");
|
||||
Logger?.Debug($"Initiating file transfer:{name}, {total}");
|
||||
FileTransfer transfer = new()
|
||||
{
|
||||
ID=id,
|
||||
@ -835,7 +822,7 @@ namespace RageCoop.Server
|
||||
if (thisRead!=chunk.Length)
|
||||
{
|
||||
if (thisRead==0) { break; }
|
||||
Program.Logger.Trace($"Purging chunk:{thisRead}");
|
||||
Logger?.Trace($"Purging chunk:{thisRead}");
|
||||
Array.Resize(ref chunk, thisRead);
|
||||
}
|
||||
Send(
|
||||
@ -858,10 +845,10 @@ namespace RageCoop.Server
|
||||
);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
Program.Logger.Debug($"All file chunks sent:{name}");
|
||||
Logger?.Debug($"All file chunks sent:{name}");
|
||||
InProgressFileTransfers.Remove(id);
|
||||
}
|
||||
private static int RequestFileID()
|
||||
private int RequestFileID()
|
||||
{
|
||||
int ID = 0;
|
||||
while ((ID==0)
|
||||
@ -883,7 +870,7 @@ namespace RageCoop.Server
|
||||
/// <param name="p"></param>
|
||||
/// <param name="channel"></param>
|
||||
/// <param name="method"></param>
|
||||
public static void Send(Packet p,Client client, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
|
||||
public void Send(Packet p,Client client, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
p.Pack(outgoingMessage);
|
||||
|
@ -47,7 +47,7 @@ namespace RageCoop.Server
|
||||
_ => (0x0, null),
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
public static Client GetClientByNetID(long id)
|
||||
{
|
||||
Client result = null;
|
||||
@ -75,17 +75,18 @@ namespace RageCoop.Server
|
||||
|
||||
return Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == client.NetID);
|
||||
}
|
||||
|
||||
*/
|
||||
// Return a list of all connections but not the local connection
|
||||
public static List<NetConnection> Exclude(this IEnumerable<NetConnection> connections,NetConnection toExclude)
|
||||
{
|
||||
return new(connections.Where(e => e != toExclude));
|
||||
}
|
||||
/*
|
||||
public static List<NetConnection> FilterAllLocal(long local)
|
||||
{
|
||||
return new(Server.MainNetServer.Connections.Where(e => e.RemoteUniqueIdentifier != local));
|
||||
}
|
||||
|
||||
*/
|
||||
public static T Read<T>(string file) where T : new()
|
||||
{
|
||||
XmlSerializer ser = new(typeof(T));
|
||||
|
Reference in New Issue
Block a user