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

@ -442,7 +442,7 @@ namespace CoopClient
if (VehicleSteeringAngle != MainVehicle.SteeringAngle) if (VehicleSteeringAngle != MainVehicle.SteeringAngle)
{ {
MainVehicle.Handle.CustomSteeringAngle((float)(Math.PI / 180) * VehicleSteeringAngle); MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * VehicleSteeringAngle);
} }
// Good enough for now, but we need to create a better sync // Good enough for now, but we need to create a better sync

View File

@ -25,8 +25,11 @@ namespace FirstGameMode
RunningSinceTimer.Start(); RunningSinceTimer.Start();
RunningSinceTimer.Elapsed += new ElapsedEventHandler((sender, e) => RunningSince += 1); RunningSinceTimer.Elapsed += new ElapsedEventHandler((sender, e) => RunningSince += 1);
API.OnStart += OnResourceStarted;
API.OnPlayerConnected += OnPlayerConnected; API.OnPlayerConnected += OnPlayerConnected;
API.OnPlayerDisconnected += OnPlayerDisconnected; API.OnPlayerDisconnected += OnPlayerDisconnected;
API.OnPlayerHealthUpdate += OnPlayerHealthUpdate;
API.OnPlayerPositionUpdate += OnPlayerPositionUpdate;
API.OnChatMessage += OnChatMessage; API.OnChatMessage += OnChatMessage;
API.OnModPacketReceived += OnModPacketReceived; API.OnModPacketReceived += OnModPacketReceived;
@ -34,7 +37,25 @@ namespace FirstGameMode
API.RegisterCommands<Commands>(); API.RegisterCommands<Commands>();
} }
private void OnModPacketReceived(long from, long target, string mod, byte customID, byte[] bytes, CancelEventArgs args) public void OnResourceStarted()
{
Logging.Info("Resource started successfully!");
}
public void OnPlayerHealthUpdate(Client client)
{
if (client.Player.Health == 0)
{
Logging.Warning($"Player {client.Player.Username} has died!");
}
}
public void OnPlayerPositionUpdate(Client client)
{
// Code...
}
public void OnModPacketReceived(long from, long target, string mod, byte customID, byte[] bytes, CancelEventArgs args)
{ {
if (mod != "FirstScript" || customID != 1) if (mod != "FirstScript" || customID != 1)
{ {
@ -56,22 +77,22 @@ namespace FirstGameMode
targetClient.SendNativeCall(0x47C3B5848C3E45D8, setPlayerTime.Hours, setPlayerTime.Minutes, setPlayerTime.Seconds); targetClient.SendNativeCall(0x47C3B5848C3E45D8, setPlayerTime.Hours, setPlayerTime.Minutes, setPlayerTime.Seconds);
} }
public static void RunningCommand(CommandContext ctx) public void RunningCommand(CommandContext ctx)
{ {
ctx.Client.SendChatMessage("Server has been running for: " + RunningSince + " seconds!"); ctx.Client.SendChatMessage($"Server has been running for: {RunningSince} seconds!");
} }
public static void OnPlayerConnected(Client client) public void OnPlayerConnected(Client client)
{ {
API.SendChatMessageToAll("Player " + client.Player.Username + " connected!"); client.SendChatMessage($"Welcome {client.Player.Username}!");
} }
public static void OnPlayerDisconnected(Client client) public void OnPlayerDisconnected(Client client)
{ {
API.SendChatMessageToAll("Player " + client.Player.Username + " disconnected!"); API.SendChatMessageToAll($"Player {client.Player.Username} disconnected!");
} }
public static void OnChatMessage(string username, string message, CancelEventArgs e) public void OnChatMessage(string username, string message, CancelEventArgs e)
{ {
e.Cancel = true; e.Cancel = true;

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using Lidgren.Network; using Lidgren.Network;
@ -43,14 +44,21 @@ namespace CoopServer
} }
#endregion #endregion
#region FUNCTIONS
public void Kick(string[] reason) public void Kick(string[] reason)
{ {
Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ID).Disconnect(string.Join(" ", reason)); Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ID)?.Disconnect(string.Join(" ", reason));
} }
public void SendChatMessage(string message, string from = "Server") public void SendChatMessage(string message, string from = "Server")
{
try
{ {
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ID); NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ID);
if (userConnection == null)
{
return;
}
ChatMessagePacket packet = new() ChatMessagePacket packet = new()
{ {
@ -62,10 +70,21 @@ namespace CoopServer
packet.PacketToNetOutGoingMessage(outgoingMessage); packet.PacketToNetOutGoingMessage(outgoingMessage);
Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, 0); Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, 0);
} }
catch (Exception e)
{
Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
}
}
public void SendNativeCall(ulong hash, params object[] args) public void SendNativeCall(ulong hash, params object[] args)
{
try
{ {
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ID); NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ID);
if (userConnection == null)
{
return;
}
List<NativeArgument> arguments = Util.ParseNativeArguments(args); List<NativeArgument> arguments = Util.ParseNativeArguments(args);
if (arguments == null) if (arguments == null)
@ -83,15 +102,26 @@ namespace CoopServer
packet.PacketToNetOutGoingMessage(outgoingMessage); packet.PacketToNetOutGoingMessage(outgoingMessage);
Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, 0); Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, 0);
} }
catch (Exception e)
{
Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
}
}
public void SendModPacket(string mod, byte customID, byte[] bytes) public void SendModPacket(string mod, byte customID, byte[] bytes)
{
try
{ {
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ID); NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ID);
if (userConnection == null)
{
return;
}
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage(); NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
new ModPacket() new ModPacket()
{ {
ID = -1, ID = 0,
Target = 0, Target = 0,
Mod = mod, Mod = mod,
CustomPacketID = customID, CustomPacketID = customID,
@ -100,5 +130,11 @@ namespace CoopServer
Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, 0); Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, 0);
Server.MainNetServer.FlushSendQueue(); Server.MainNetServer.FlushSendQueue();
} }
catch (Exception e)
{
Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
}
}
#endregion
} }
} }

View File

@ -8,11 +8,7 @@
private LVector3 CurrentPosition { get; set; } private LVector3 CurrentPosition { get; set; }
public LVector3 Position public LVector3 Position
{ {
get get => CurrentPosition;
{
return CurrentPosition;
}
set set
{ {
LastPosition = CurrentPosition; LastPosition = CurrentPosition;
@ -24,6 +20,20 @@
} }
} }
} }
private int CurrentHealth { get; set; }
public int Health
{
get => CurrentHealth;
set
{
if (CurrentHealth != value && Server.MainResource != null)
{
Server.MainResource.InvokePlayerHealthUpdate(this);
}
CurrentHealth = value;
}
}
public bool IsInRangeOf(LVector3 position, float distance) public bool IsInRangeOf(LVector3 position, float distance)
{ {

View File

@ -299,15 +299,16 @@ namespace CoopServer
if (modPacket.Target != 0) if (modPacket.Target != 0)
{ {
NetConnection target = MainNetServer.Connections.FirstOrDefault(x => x.RemoteUniqueIdentifier == modPacket.Target); NetConnection target = MainNetServer.Connections.FirstOrDefault(x => x.RemoteUniqueIdentifier == modPacket.Target);
if (target == null) if (target.Equals(default(Client)))
{ {
Logging.Error($"[ModPacket] target \"{modPacket.Target}\" not found!"); Logging.Error($"[ModPacket] target \"{modPacket.Target}\" not found!");
return;
} }
else
{
// Send back to target // Send back to target
MainNetServer.SendMessage(outgoingMessage, target, NetDeliveryMethod.ReliableOrdered, 0); MainNetServer.SendMessage(outgoingMessage, target, NetDeliveryMethod.ReliableOrdered, 0);
} }
}
else else
{ {
// Send back to all players // Send back to all players
@ -331,7 +332,7 @@ namespace CoopServer
break; break;
case NetIncomingMessageType.ConnectionLatencyUpdated: case NetIncomingMessageType.ConnectionLatencyUpdated:
Client client = Clients.FirstOrDefault(x => x.ID == message.SenderConnection.RemoteUniqueIdentifier); Client client = Clients.FirstOrDefault(x => x.ID == message.SenderConnection.RemoteUniqueIdentifier);
if (client != default) if (!client.Equals(default(Client)))
{ {
client.Latency = message.ReadFloat(); client.Latency = message.ReadFloat();
} }
@ -420,9 +421,13 @@ namespace CoopServer
long localID = local.RemoteUniqueIdentifier; long localID = local.RemoteUniqueIdentifier;
Client tmpClient;
// Add the player to Players // Add the player to Players
lock (Clients)
{
Clients.Add( Clients.Add(
new Client() tmpClient = new Client()
{ {
ID = localID, ID = localID,
Player = new() Player = new()
@ -432,6 +437,7 @@ namespace CoopServer
} }
} }
); );
}
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
@ -447,47 +453,51 @@ namespace CoopServer
// Accept the connection and send back a new handshake packet with the connection ID // Accept the connection and send back a new handshake packet with the connection ID
local.Approve(outgoingMessage); local.Approve(outgoingMessage);
if (MainResource != null)
{
MainResource.InvokePlayerHandshake(tmpClient);
}
} }
// The connection has been approved, now we need to send all other players to the new player and the new player to all players // 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, PlayerConnectPacket packet) private static void SendPlayerConnectPacket(NetConnection local, PlayerConnectPacket packet)
{ {
Client localClient = Clients.FirstOrDefault(x => x.ID == packet.ID);
if (localClient.Equals(default(Client)))
{
local.Disconnect("No data found!");
return;
}
if (!string.IsNullOrEmpty(MainSettings.WelcomeMessage)) if (!string.IsNullOrEmpty(MainSettings.WelcomeMessage))
{ {
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 (MainResource != null)
{
MainResource.InvokePlayerConnected(Clients.Find(x => x.ID == packet.ID));
}
List<NetConnection> clients; List<NetConnection> clients;
if ((clients = Util.FilterAllLocal(local)).Count == 0) if ((clients = Util.FilterAllLocal(local)).Count > 0)
{ {
return;
}
// Send all players to local // Send all players to local
clients.ForEach(targetPlayer => clients.ForEach(targetPlayer =>
{ {
long targetPlayerID = targetPlayer.RemoteUniqueIdentifier; long targetPlayerID = targetPlayer.RemoteUniqueIdentifier;
Client targetEntity = Clients.First(x => x.ID == targetPlayerID); Client targetClient = Clients.FirstOrDefault(x => x.ID == targetPlayerID);
if (!targetClient.Equals(default(Client)))
{
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
new PlayerConnectPacket() new PlayerConnectPacket()
{ {
ID = targetPlayerID, ID = targetPlayerID,
SocialClubName = targetEntity.Player.SocialClubName, SocialClubName = targetClient.Player.SocialClubName,
Username = targetEntity.Player.Username Username = targetClient.Player.Username
}.PacketToNetOutGoingMessage(outgoingMessage); }.PacketToNetOutGoingMessage(outgoingMessage);
MainNetServer.SendMessage(outgoingMessage, local, NetDeliveryMethod.ReliableOrdered, 0); MainNetServer.SendMessage(outgoingMessage, local, NetDeliveryMethod.ReliableOrdered, 0);
}
}); });
// Send local to all players // Send local to all players
Client localClient = Clients.First(x => x.ID == packet.ID);
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
new PlayerConnectPacket() new PlayerConnectPacket()
{ {
@ -498,14 +508,15 @@ namespace CoopServer
MainNetServer.SendMessage(outgoingMessage, clients, NetDeliveryMethod.ReliableOrdered, 0); MainNetServer.SendMessage(outgoingMessage, clients, NetDeliveryMethod.ReliableOrdered, 0);
} }
if (MainResource != null)
{
MainResource.InvokePlayerConnected(localClient);
}
}
// 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 (MainResource != null)
{
MainResource.InvokePlayerDisconnected(Clients.Find(x => x.ID == packet.ID));
}
List<NetConnection> clients; List<NetConnection> clients;
if ((clients = Util.FilterAllLocal(packet.ID)).Count > 0) if ((clients = Util.FilterAllLocal(packet.ID)).Count > 0)
{ {
@ -514,16 +525,40 @@ namespace CoopServer
MainNetServer.SendMessage(outgoingMessage, clients, NetDeliveryMethod.ReliableOrdered, 0); MainNetServer.SendMessage(outgoingMessage, clients, NetDeliveryMethod.ReliableOrdered, 0);
} }
Clients.Remove(Clients.Find(x => x.ID == packet.ID)); Client localClient = Clients.FirstOrDefault(x => x.ID == packet.ID);
if (localClient.Equals(default(Client)))
{
return;
}
if (MainResource != null)
{
MainResource.InvokePlayerDisconnected(localClient);
}
lock (Clients)
{
Clients.Remove(localClient);
}
} }
private static void FullSyncPlayer(FullSyncPlayerPacket packet) private static void FullSyncPlayer(FullSyncPlayerPacket packet)
{ {
Client client = Clients.First(x => x.ID == packet.Extra.ID); Client tmpClient = Clients.FirstOrDefault(x => x.ID == packet.Extra.ID);
client.Player.Position = packet.Extra.Position; if (tmpClient.Equals(default(Client)))
{
NetConnection localConn = MainNetServer.Connections.Find(x => packet.Extra.ID == x.RemoteUniqueIdentifier);
if (localConn != null)
{
localConn.Disconnect("No data found!");
}
return;
}
tmpClient.Player.Position = packet.Extra.Position;
tmpClient.Player.Health = packet.Extra.Health;
PlayerPacket playerPacket = packet.Extra; PlayerPacket playerPacket = packet.Extra;
playerPacket.Latency = client.Latency; playerPacket.Latency = tmpClient.Latency;
packet.Extra = playerPacket; packet.Extra = playerPacket;
@ -545,15 +580,30 @@ namespace CoopServer
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, 0); MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, 0);
}); });
if (MainResource != null)
{
MainResource.InvokePlayerUpdate(tmpClient);
}
} }
private static void FullSyncPlayerVeh(FullSyncPlayerVehPacket packet) private static void FullSyncPlayerVeh(FullSyncPlayerVehPacket packet)
{ {
Client client = Clients.First(x => x.ID == packet.Extra.ID); Client tmpClient = Clients.FirstOrDefault(x => x.ID == packet.Extra.ID);
client.Player.Position = packet.Extra.Position; if (tmpClient.Equals(default(Client)))
{
NetConnection localConn = MainNetServer.Connections.Find(x => packet.Extra.ID == x.RemoteUniqueIdentifier);
if (localConn != null)
{
localConn.Disconnect("No data found!");
}
return;
}
tmpClient.Player.Position = packet.Extra.Position;
tmpClient.Player.Health = packet.Extra.Health;
PlayerPacket playerPacket = packet.Extra; PlayerPacket playerPacket = packet.Extra;
playerPacket.Latency = client.Latency; playerPacket.Latency = tmpClient.Latency;
packet.Extra = playerPacket; packet.Extra = playerPacket;
@ -575,15 +625,30 @@ namespace CoopServer
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, 0); MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, 0);
}); });
if (MainResource != null)
{
MainResource.InvokePlayerUpdate(tmpClient);
}
} }
private static void LightSyncPlayer(LightSyncPlayerPacket packet) private static void LightSyncPlayer(LightSyncPlayerPacket packet)
{ {
Client client = Clients.First(x => x.ID == packet.Extra.ID); Client tmpClient = Clients.FirstOrDefault(x => x.ID == packet.Extra.ID);
client.Player.Position = packet.Extra.Position; if (tmpClient.Equals(default(Client)))
{
NetConnection localConn = MainNetServer.Connections.Find(x => packet.Extra.ID == x.RemoteUniqueIdentifier);
if (localConn != null)
{
localConn.Disconnect("No data found!");
}
return;
}
tmpClient.Player.Position = packet.Extra.Position;
tmpClient.Player.Health = packet.Extra.Health;
PlayerPacket playerPacket = packet.Extra; PlayerPacket playerPacket = packet.Extra;
playerPacket.Latency = client.Latency; playerPacket.Latency = tmpClient.Latency;
packet.Extra = playerPacket; packet.Extra = playerPacket;
@ -605,15 +670,30 @@ namespace CoopServer
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, 0); MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, 0);
}); });
if (MainResource != null)
{
MainResource.InvokePlayerUpdate(tmpClient);
}
} }
private static void LightSyncPlayerVeh(LightSyncPlayerVehPacket packet) private static void LightSyncPlayerVeh(LightSyncPlayerVehPacket packet)
{ {
Client client = Clients.First(x => x.ID == packet.Extra.ID); Client tmpClient = Clients.FirstOrDefault(x => x.ID == packet.Extra.ID);
client.Player.Position = packet.Extra.Position; if (tmpClient.Equals(default(Client)))
{
NetConnection localConn = MainNetServer.Connections.Find(x => packet.Extra.ID == x.RemoteUniqueIdentifier);
if (localConn != null)
{
localConn.Disconnect("No data found!");
}
return;
}
tmpClient.Player.Position = packet.Extra.Position;
tmpClient.Player.Health = packet.Extra.Health;
PlayerPacket playerPacket = packet.Extra; PlayerPacket playerPacket = packet.Extra;
playerPacket.Latency = client.Latency; playerPacket.Latency = tmpClient.Latency;
packet.Extra = playerPacket; packet.Extra = playerPacket;
@ -635,6 +715,11 @@ namespace CoopServer
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, 0); MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, 0);
}); });
if (MainResource != null)
{
MainResource.InvokePlayerUpdate(tmpClient);
}
} }
// Send a message to targets or all players // Send a message to targets or all players

View File

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

View File

@ -50,13 +50,13 @@ namespace CoopServer
public static NetConnection GetConnectionByUsername(string username) public static NetConnection GetConnectionByUsername(string username)
{ {
long clientID; Client client = Server.Clients.FirstOrDefault(x => x.Player.Username == username);
if ((clientID = Server.Clients.FirstOrDefault(x => x.Player.Username == username).ID) == default) if (client.Equals(default(Client)))
{ {
return null; return null;
} }
return Server.MainNetServer.Connections.FirstOrDefault(x => x.RemoteUniqueIdentifier == clientID); return Server.MainNetServer.Connections.FirstOrDefault(x => x.RemoteUniqueIdentifier == client.ID);
} }
// Return a list of all connections but not the local connection // Return a list of all connections but not the local connection
@ -72,12 +72,20 @@ namespace CoopServer
// Return a list of players within range of ... // Return a list of players within range of ...
public static List<NetConnection> GetAllInRange(LVector3 position, float range) public static List<NetConnection> GetAllInRange(LVector3 position, float range)
{ {
return new(Server.MainNetServer.Connections.FindAll(e => Server.Clients.First(x => x.ID == e.RemoteUniqueIdentifier).Player.IsInRangeOf(position, range))); return new(Server.MainNetServer.Connections.FindAll(e =>
{
Client client = Server.Clients.First(x => x.ID == e.RemoteUniqueIdentifier);
return !client.Equals(default(Client)) && client.Player.IsInRangeOf(position, range);
}));
} }
// Return a list of players within range of ... but not the local one // Return a list of players within range of ... but not the local one
public static List<NetConnection> GetAllInRange(LVector3 position, float range, NetConnection local) public static List<NetConnection> GetAllInRange(LVector3 position, float range, NetConnection local)
{ {
return new(Server.MainNetServer.Connections.Where(e => e != local && Server.Clients.First(x => x.ID == e.RemoteUniqueIdentifier).Player.IsInRangeOf(position, range))); return new(Server.MainNetServer.Connections.Where(e =>
{
Client client = Server.Clients.First(x => x.ID == e.RemoteUniqueIdentifier);
return e != local && !client.Equals(default(Client)) && client.Player.IsInRangeOf(position, range);
}));
} }
public static T Read<T>(string file) where T : new() public static T Read<T>(string file) where T : new()