Restore
This commit is contained in:
13
.github/FUNDING.yml
vendored
Normal file
13
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: [RAGECOOP] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
#patreon: # Replace with a single Patreon username
|
||||||
|
#open_collective: # Replace with a single Open Collective username
|
||||||
|
#ko_fi: # Replace with a single Ko-fi username
|
||||||
|
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
#liberapay: # Replace with a single Liberapay username
|
||||||
|
#issuehunt: # Replace with a single IssueHunt username
|
||||||
|
#otechie: # Replace with a single Otechie username
|
||||||
|
#lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||||
|
custom: ['https://www.buymeacoffee.com/xEntenKoeniqx', 'https://patreon.com/Sardelka']
|
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
# 🌐 RAGECOOP
|
# 🌐 RAGECOOP
|
||||||
|
[![Downloads][downloads-shield]][downloads-url]
|
||||||
[![Contributors][contributors-shield]][contributors-url]
|
[![Contributors][contributors-shield]][contributors-url]
|
||||||
[![Forks][forks-shield]][forks-url]
|
[![Forks][forks-shield]][forks-url]
|
||||||
[![Stargazers][stars-shield]][stars-url]
|
[![Stargazers][stars-shield]][stars-url]
|
||||||
@ -55,9 +56,6 @@ You can also download nightly builds [here](https://github.com/RAGECOOP/RAGECOOP
|
|||||||
Please note that this is incompatible with all previous versions of ragecoop, remove old files before installing.
|
Please note that this is incompatible with all previous versions of ragecoop, remove old files before installing.
|
||||||
|
|
||||||
|
|
||||||
# Support us
|
|
||||||
|
|
||||||
<a href="https://patreon.com/Sardelka"><img src="https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3DSardelka%26type%3Dpatrons&style=for-the-badge" /></a>
|
|
||||||
|
|
||||||
# 🦆 Special thanks to
|
# 🦆 Special thanks to
|
||||||
- [Makinolo](https://github.com/Makinolo), [oldnapalm](https://github.com/oldnapalm)
|
- [Makinolo](https://github.com/Makinolo), [oldnapalm](https://github.com/oldnapalm)
|
||||||
@ -70,6 +68,8 @@ Please note that this is incompatible with all previous versions of ragecoop, re
|
|||||||
# 📝 License
|
# 📝 License
|
||||||
This project is licensed under [MIT license](https://github.com/RAGECOOP/RAGECOOP-V/blob/main/LICENSE)
|
This project is licensed under [MIT license](https://github.com/RAGECOOP/RAGECOOP-V/blob/main/LICENSE)
|
||||||
|
|
||||||
|
[downloads-shield]: https://img.shields.io/github/downloads/RAGECOOP/RAGECOOP-V/total?style=for-the-badge
|
||||||
|
[downloads-url]: https://github.com/RAGECOOP/RAGECOOP-V/releases
|
||||||
[contributors-shield]: https://img.shields.io/github/contributors/RAGECOOP/RAGECOOP-V.svg?style=for-the-badge
|
[contributors-shield]: https://img.shields.io/github/contributors/RAGECOOP/RAGECOOP-V.svg?style=for-the-badge
|
||||||
[contributors-url]: https://github.com/RAGECOOP/RAGECOOP-V/graphs/contributors
|
[contributors-url]: https://github.com/RAGECOOP/RAGECOOP-V/graphs/contributors
|
||||||
[forks-shield]: https://img.shields.io/github/forks/RAGECOOP/RAGECOOP-V.svg?style=for-the-badge
|
[forks-shield]: https://img.shields.io/github/forks/RAGECOOP/RAGECOOP-V.svg?style=for-the-badge
|
||||||
|
85
RageCoop.Client/Networking/HolePunch.cs
Normal file
85
RageCoop.Client/Networking/HolePunch.cs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Timers;
|
||||||
|
using RageCoop.Core;
|
||||||
|
using Lidgren.Network;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace RageCoop.Client
|
||||||
|
{
|
||||||
|
internal static partial class HolePunch
|
||||||
|
{
|
||||||
|
static HolePunch()
|
||||||
|
{
|
||||||
|
// Periodically send hole punch message as needed
|
||||||
|
var timer=new Timer(1000);
|
||||||
|
timer.Elapsed+=DoPunch;
|
||||||
|
timer.Enabled=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DoPunch(object sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!Networking.IsOnServer) { return; }
|
||||||
|
foreach (var p in PlayerList.Players.Values.ToArray())
|
||||||
|
{
|
||||||
|
if (p.InternalEndPoint!=null && p.ExternalEndPoint!=null && (p.Connection==null || p.Connection.Status==NetConnectionStatus.Disconnected))
|
||||||
|
{
|
||||||
|
Main.Logger.Trace($"Sending HolePunch message to {p.InternalEndPoint},{p.ExternalEndPoint}. {p.Username}:{p.PedID}");
|
||||||
|
var msg = Networking.Peer.CreateMessage();
|
||||||
|
new Packets.HolePunch
|
||||||
|
{
|
||||||
|
Puncher=Main.LocalPlayerID,
|
||||||
|
Status=p.HolePunchStatus
|
||||||
|
}.Pack(msg);
|
||||||
|
Networking.Peer.SendUnconnectedMessage(msg, new List<IPEndPoint> { p.InternalEndPoint, p.ExternalEndPoint });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Main.Logger.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Add(Packets.HolePunchInit p)
|
||||||
|
{
|
||||||
|
if(PlayerList.Players.TryGetValue(p.TargetID,out var player))
|
||||||
|
{
|
||||||
|
Main.Logger.Debug($"{p.TargetID},{player.Username} added to HolePunch target");
|
||||||
|
player.InternalEndPoint = CoreUtils.StringToEndPoint(p.TargetInternal);
|
||||||
|
player.ExternalEndPoint = CoreUtils.StringToEndPoint(p.TargetExternal);
|
||||||
|
player.ConnectWhenPunched=p.Connect;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Main.Logger.Warning("No player with specified TargetID found for hole punching:"+p.TargetID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void Punched(Packets.HolePunch p,IPEndPoint from)
|
||||||
|
{
|
||||||
|
Main.Logger.Debug($"HolePunch message received from:{from}, status:{p.Status}");
|
||||||
|
if(PlayerList.Players.TryGetValue(p.Puncher,out var puncher))
|
||||||
|
{
|
||||||
|
Main.Logger.Debug("Puncher identified as: "+puncher.Username);
|
||||||
|
puncher.HolePunchStatus=(byte)(p.Status+1);
|
||||||
|
if (p.Status>=3)
|
||||||
|
{
|
||||||
|
Main.Logger.Debug("HolePunch sucess: "+from+", "+puncher.PedID);
|
||||||
|
if (puncher.ConnectWhenPunched && (puncher.Connection==null || puncher.Connection.Status==NetConnectionStatus.Disconnected))
|
||||||
|
{
|
||||||
|
Main.Logger.Debug("Connecting to peer: "+from);
|
||||||
|
var msg = Networking.Peer.CreateMessage();
|
||||||
|
new Packets.P2PConnect { ID=Main.LocalPlayerID }.Pack(msg);
|
||||||
|
puncher.Connection=Networking.Peer.Connect(from,msg);
|
||||||
|
Networking.Peer.FlushSendQueue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -146,19 +146,20 @@ namespace RageCoop.Client
|
|||||||
PedID = packet.PedID,
|
PedID = packet.PedID,
|
||||||
Username= packet.Username,
|
Username= packet.Username,
|
||||||
};
|
};
|
||||||
GTA.UI.Notification.Show($"~h~{p.Username}~h~ connected.");
|
|
||||||
PlayerList.SetPlayer(packet.PedID, packet.Username);
|
PlayerList.SetPlayer(packet.PedID, packet.Username);
|
||||||
|
|
||||||
Main.Logger.Debug($"player connected:{p.Username}");
|
Main.Logger.Debug($"player connected:{p.Username}");
|
||||||
|
Main.QueueAction(() =>
|
||||||
|
GTA.UI.Notification.Show($"~h~{p.Username}~h~ connected."));
|
||||||
}
|
}
|
||||||
private static void PlayerDisconnect(Packets.PlayerDisconnect packet)
|
private static void PlayerDisconnect(Packets.PlayerDisconnect packet)
|
||||||
{
|
{
|
||||||
var name = PlayerList.GetPlayer(packet.PedID).Username;
|
var name = PlayerList.GetPlayer(packet.PedID).Username;
|
||||||
GTA.UI.Notification.Show($"~h~{name}~h~ left.");
|
|
||||||
PlayerList.RemovePlayer(packet.PedID);
|
PlayerList.RemovePlayer(packet.PedID);
|
||||||
EntityPool.RemoveAllFromPlayer(packet.PedID);
|
EntityPool.RemoveAllFromPlayer(packet.PedID);
|
||||||
|
|
||||||
|
Main.QueueAction(() =>
|
||||||
|
GTA.UI.Notification.Show($"~h~{name}~h~ left."));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion // -- PLAYER --
|
#endregion // -- PLAYER --
|
||||||
|
@ -70,16 +70,22 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
Main.Logger.Info(">> Connected <<");
|
Main.Logger.Info(">> Connected <<");
|
||||||
}
|
}
|
||||||
else if (PlayerList.PendingConnections.TryGetValue(message.SenderEndPoint.ToString(),out var player))
|
else
|
||||||
{
|
{
|
||||||
PlayerList.PendingConnections.Remove(message.SenderEndPoint.ToString());
|
// Self-initiated connection
|
||||||
Main.Logger.Debug($"Connection to {player.Username},{player.PedID},{player.Connection.Status} established, sending ID...");
|
if (message.SenderConnection.RemoteHailMessage==null) { return; }
|
||||||
// Inform target our ID
|
|
||||||
SendTo(new Packets.ConnectionEstablished()
|
var p = message.SenderConnection.RemoteHailMessage.GetPacket<Packets.P2PConnect>();
|
||||||
|
if (PlayerList.Players.TryGetValue(p.ID,out var player))
|
||||||
{
|
{
|
||||||
ID=Main.LocalPlayerID
|
player.Connection=message.SenderConnection;
|
||||||
}, player.Connection, ConnectionChannel.Default, NetDeliveryMethod.ReliableOrdered);
|
Main.Logger.Debug($"Direct connectionn to {player.Username} established");
|
||||||
Peer.FlushSendQueue();
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Main.Logger.Info($"Unidentified peer connection from {message.SenderEndPoint} was rejected.");
|
||||||
|
message.SenderConnection.Disconnect("eat poop");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NetConnectionStatus.Disconnected:
|
case NetConnectionStatus.Disconnected:
|
||||||
@ -103,22 +109,6 @@ namespace RageCoop.Client
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NetIncomingMessageType.NatIntroductionSuccess:
|
|
||||||
{
|
|
||||||
var playerID = int.Parse(message.ReadString());
|
|
||||||
// Main.Logger.Debug("NatIntroductionSuccess received from "+message.SenderEndPoint+" "+playerID);
|
|
||||||
if (PlayerList.Players.TryGetValue(playerID, out var player) && (player.Connection==null || player.Connection.Status==NetConnectionStatus.Disconnected))
|
|
||||||
{
|
|
||||||
Main.Logger.Debug($"Establishing direct connection to {player.Username},{player.PedID}");
|
|
||||||
player.Connection=Peer.Connect(message.SenderEndPoint);
|
|
||||||
var ep = message.SenderEndPoint.ToString();
|
|
||||||
if (!PlayerList.PendingConnections.ContainsKey(ep))
|
|
||||||
{
|
|
||||||
PlayerList.PendingConnections.Add(ep, player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NetIncomingMessageType.Data:
|
case NetIncomingMessageType.Data:
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -184,14 +174,23 @@ namespace RageCoop.Client
|
|||||||
var packetType = (PacketType)message.ReadByte();
|
var packetType = (PacketType)message.ReadByte();
|
||||||
int len = message.ReadInt32();
|
int len = message.ReadInt32();
|
||||||
byte[] data = message.ReadBytes(len);
|
byte[] data = message.ReadBytes(len);
|
||||||
if (packetType==PacketType.PublicKeyResponse)
|
switch (packetType)
|
||||||
{
|
{
|
||||||
var packet = new Packets.PublicKeyResponse();
|
|
||||||
packet.Deserialize(data);
|
case PacketType.HolePunch:
|
||||||
|
{
|
||||||
|
HolePunch.Punched(data.GetPacket<Packets.HolePunch>(), message.SenderEndPoint);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PacketType.PublicKeyResponse:
|
||||||
|
{
|
||||||
|
|
||||||
|
var packet = data.GetPacket<Packets.PublicKeyResponse>();
|
||||||
Security.SetServerPublicKey(packet.Modulus, packet.Exponent);
|
Security.SetServerPublicKey(packet.Modulus, packet.Exponent);
|
||||||
_publicKeyReceived.Set();
|
_publicKeyReceived.Set();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NetIncomingMessageType.DebugMessage:
|
case NetIncomingMessageType.DebugMessage:
|
||||||
@ -211,69 +210,33 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
switch (packetType)
|
switch (packetType)
|
||||||
{
|
{
|
||||||
case PacketType.ConnectionEstablished:
|
case PacketType.HolePunchInit:
|
||||||
{
|
HolePunch.Add(data.GetPacket<Packets.HolePunchInit>());
|
||||||
var p=new Packets.ConnectionEstablished();
|
|
||||||
p.Deserialize(data);
|
|
||||||
Main.Logger.Debug("Connection message received from "+senderConnection.RemoteEndPoint+","+p.ID);
|
|
||||||
if(PlayerList.Players.TryGetValue(p.ID,out var player)){
|
|
||||||
Main.Logger.Debug($"Direct connection to {player.Username},{player.PedID} has been established");
|
|
||||||
player.Connection=senderConnection;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case PacketType.PlayerConnect:
|
case PacketType.PlayerConnect:
|
||||||
{
|
PlayerConnect(data.GetPacket<Packets.PlayerConnect>());
|
||||||
|
|
||||||
Packets.PlayerConnect packet = new Packets.PlayerConnect();
|
|
||||||
packet.Deserialize(data);
|
|
||||||
|
|
||||||
Main.QueueAction(() => PlayerConnect(packet));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.PlayerDisconnect:
|
case PacketType.PlayerDisconnect:
|
||||||
{
|
PlayerDisconnect(data.GetPacket<Packets.PlayerDisconnect>());
|
||||||
|
|
||||||
Packets.PlayerDisconnect packet = new Packets.PlayerDisconnect();
|
|
||||||
packet.Deserialize(data);
|
|
||||||
Main.QueueAction(() => PlayerDisconnect(packet));
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.PlayerInfoUpdate:
|
case PacketType.PlayerInfoUpdate:
|
||||||
{
|
PlayerList.UpdatePlayer(data.GetPacket<Packets.PlayerInfoUpdate>());
|
||||||
var packet = new Packets.PlayerInfoUpdate();
|
|
||||||
packet.Deserialize(data);
|
|
||||||
PlayerList.UpdatePlayer(packet);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
#region ENTITY SYNC
|
|
||||||
case PacketType.VehicleSync:
|
case PacketType.VehicleSync:
|
||||||
{
|
VehicleSync(data.GetPacket<Packets.VehicleSync>());
|
||||||
|
|
||||||
Packets.VehicleSync packet = new Packets.VehicleSync();
|
|
||||||
packet.Deserialize(data);
|
|
||||||
VehicleSync(packet);
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.PedSync:
|
case PacketType.PedSync:
|
||||||
{
|
PedSync(data.GetPacket<Packets.PedSync>());
|
||||||
|
|
||||||
Packets.PedSync packet = new Packets.PedSync();
|
|
||||||
packet.Deserialize(data);
|
|
||||||
PedSync(packet);
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case PacketType.ProjectileSync:
|
case PacketType.ProjectileSync:
|
||||||
{
|
ProjectileSync(data.GetPacket<Packets.ProjectileSync>());
|
||||||
Packets.ProjectileSync packet = new Packets.ProjectileSync();
|
|
||||||
packet.Deserialize(data);
|
|
||||||
ProjectileSync(packet);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
case PacketType.ChatMessage:
|
case PacketType.ChatMessage:
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -284,10 +247,9 @@ namespace RageCoop.Client
|
|||||||
packet.Deserialize(data);
|
packet.Deserialize(data);
|
||||||
|
|
||||||
Main.QueueAction(() => { Main.MainChat.AddMessage(packet.Username, packet.Message); return true; });
|
Main.QueueAction(() => { Main.MainChat.AddMessage(packet.Username, packet.Message); return true; });
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.CustomEvent:
|
case PacketType.CustomEvent:
|
||||||
{
|
{
|
||||||
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
|
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
|
||||||
@ -295,6 +257,7 @@ namespace RageCoop.Client
|
|||||||
Scripting.API.Events.InvokeCustomEventReceived(packet);
|
Scripting.API.Events.InvokeCustomEventReceived(packet);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.CustomEventQueued:
|
case PacketType.CustomEventQueued:
|
||||||
{
|
{
|
||||||
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
|
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
|
||||||
@ -305,6 +268,7 @@ namespace RageCoop.Client
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.FileTransferChunk:
|
case PacketType.FileTransferChunk:
|
||||||
{
|
{
|
||||||
Packets.FileTransferChunk packet = new Packets.FileTransferChunk();
|
Packets.FileTransferChunk packet = new Packets.FileTransferChunk();
|
||||||
@ -312,10 +276,11 @@ namespace RageCoop.Client
|
|||||||
DownloadManager.Write(packet.ID, packet.FileChunk);
|
DownloadManager.Write(packet.ID, packet.FileChunk);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (packetType.IsSyncEvent())
|
if (packetType.IsSyncEvent())
|
||||||
{
|
{
|
||||||
// Dispatch to main thread
|
// Dispatch to script thread
|
||||||
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, data); return true; });
|
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, data); return true; });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -108,7 +108,7 @@ namespace RageCoop.Client
|
|||||||
OwnerID=v.OwnerID,
|
OwnerID=v.OwnerID,
|
||||||
Flags = veh.GetVehicleFlags(),
|
Flags = veh.GetVehicleFlags(),
|
||||||
SteeringAngle = veh.SteeringAngle,
|
SteeringAngle = veh.SteeringAngle,
|
||||||
Position = veh.PredictPosition(),
|
Position = veh.Position,
|
||||||
Velocity=veh.Velocity,
|
Velocity=veh.Velocity,
|
||||||
Quaternion=veh.ReadQuaternion(),
|
Quaternion=veh.ReadQuaternion(),
|
||||||
RotationVelocity=veh.RotationVelocity,
|
RotationVelocity=veh.RotationVelocity,
|
||||||
@ -160,11 +160,11 @@ namespace RageCoop.Client
|
|||||||
ID =sp.ID,
|
ID =sp.ID,
|
||||||
ShooterID=sp.ShooterID,
|
ShooterID=sp.ShooterID,
|
||||||
Rotation=p.Rotation,
|
Rotation=p.Rotation,
|
||||||
|
Position=p.Position,
|
||||||
Velocity=p.Velocity,
|
Velocity=p.Velocity,
|
||||||
WeaponHash=(uint)p.WeaponHash,
|
WeaponHash=(uint)p.WeaponHash,
|
||||||
Exploded=p.IsDead
|
Exploded=p.IsDead
|
||||||
};
|
};
|
||||||
packet.Position=p.Position+packet.Velocity*Latency;
|
|
||||||
if (p.IsDead) { EntityPool.RemoveProjectile(sp.ID, "Dead"); }
|
if (p.IsDead) { EntityPool.RemoveProjectile(sp.ID, "Dead"); }
|
||||||
Send(packet, ConnectionChannel.ProjectileSync);
|
Send(packet, ConnectionChannel.ProjectileSync);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
public static bool LeftAlign = true;
|
public static bool LeftAlign = true;
|
||||||
public static Dictionary<int, Player> Players = new Dictionary<int, Player> { };
|
public static Dictionary<int, Player> Players = new Dictionary<int, Player> { };
|
||||||
public static Dictionary<string, Player> PendingConnections = new Dictionary<string, Player>();
|
|
||||||
public static void Tick()
|
public static void Tick()
|
||||||
{
|
{
|
||||||
if (!Networking.IsOnServer)
|
if (!Networking.IsOnServer)
|
||||||
@ -138,6 +137,7 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
internal class Player
|
internal class Player
|
||||||
{
|
{
|
||||||
|
public byte HolePunchStatus { get; set; } = 1;
|
||||||
public string Username { get; internal set; }
|
public string Username { get; internal set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Universal character ID.
|
/// Universal character ID.
|
||||||
@ -146,6 +146,9 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
get; internal set;
|
get; internal set;
|
||||||
}
|
}
|
||||||
|
public IPEndPoint InternalEndPoint { get; set; }
|
||||||
|
public IPEndPoint ExternalEndPoint { get; set; }
|
||||||
|
public bool ConnectWhenPunched { get; set; }
|
||||||
public Blip FakeBlip { get; set; }
|
public Blip FakeBlip { get; set; }
|
||||||
public Vector3 Position { get; set; }
|
public Vector3 Position { get; set; }
|
||||||
public SyncedPed Character { get; set; }
|
public SyncedPed Character { get; set; }
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
<Compile Include="Menus\Sub\UpdateMenu.cs" />
|
<Compile Include="Menus\Sub\UpdateMenu.cs" />
|
||||||
<Compile Include="Networking\Chat.cs" />
|
<Compile Include="Networking\Chat.cs" />
|
||||||
<Compile Include="Networking\DownloadManager.cs" />
|
<Compile Include="Networking\DownloadManager.cs" />
|
||||||
|
<Compile Include="Networking\HolePunch.cs" />
|
||||||
<Compile Include="Networking\Networking.cs" />
|
<Compile Include="Networking\Networking.cs" />
|
||||||
<Compile Include="Networking\Receive.cs" />
|
<Compile Include="Networking\Receive.cs" />
|
||||||
<Compile Include="Networking\Send.cs" />
|
<Compile Include="Networking\Send.cs" />
|
||||||
|
@ -221,7 +221,8 @@ namespace RageCoop.Client
|
|||||||
new ScaledText(toDraw, Player.Username, 0.4f, GTA.UI.Font.ChaletLondon)
|
new ScaledText(toDraw, Player.Username, 0.4f, GTA.UI.Font.ChaletLondon)
|
||||||
{
|
{
|
||||||
Outline = true,
|
Outline = true,
|
||||||
Alignment = GTA.UI.Alignment.Center
|
Alignment = GTA.UI.Alignment.Center,
|
||||||
|
Color=Owner.HasDirectConnection? Color.FromArgb(179, 229, 252) : Color.White,
|
||||||
}.Draw();
|
}.Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ namespace RageCoop.Client
|
|||||||
CreateProjectile();
|
CreateProjectile();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MainProjectile.Velocity=Velocity+(Position+Networking.Latency*Velocity-MainProjectile.Position);
|
MainProjectile.Velocity=Velocity+(Position+Shooter.Owner.PacketTravelTime*Velocity-MainProjectile.Position);
|
||||||
MainProjectile.Rotation=Rotation;
|
MainProjectile.Rotation=Rotation;
|
||||||
LastUpdated=Main.Ticked;
|
LastUpdated=Main.Ticked;
|
||||||
}
|
}
|
||||||
|
@ -353,23 +353,22 @@ namespace RageCoop.Client
|
|||||||
LastUpdated=Main.Ticked;
|
LastUpdated=Main.Ticked;
|
||||||
}
|
}
|
||||||
float _elapsed;
|
float _elapsed;
|
||||||
Vector3 _predictedVel;
|
|
||||||
Vector3 _predictedPos;
|
Vector3 _predictedPos;
|
||||||
void DisplayVehicle(bool touching)
|
void DisplayVehicle(bool touching)
|
||||||
{
|
{
|
||||||
// predict velocity/position
|
// predict velocity/position
|
||||||
_elapsed = Owner.PacketTravelTime+0.001f*LastSyncedStopWatch.ElapsedMilliseconds;
|
_elapsed = Owner.PacketTravelTime+0.001f*LastSyncedStopWatch.ElapsedMilliseconds;
|
||||||
// new LemonUI.Elements.ScaledText(new System.Drawing.PointF(50, 50), Owner.HasDirectConnection+" "+LastSyncedStopWatch.ElapsedMilliseconds).Draw();
|
// new LemonUI.Elements.ScaledText(new System.Drawing.PointF(50, 50), Owner.HasDirectConnection+" "+LastSyncedStopWatch.ElapsedMilliseconds).Draw();
|
||||||
_predictedVel = Velocity+Acceleration*_elapsed;
|
// _predictedVel = Velocity+Acceleration*_elapsed;
|
||||||
_predictedPos = Position+_elapsed*(LastVelocity+_predictedVel)/2;
|
_predictedPos = Position+_elapsed*Velocity;
|
||||||
LastVelocity=_predictedVel;
|
// LastVelocity=_predictedVel;
|
||||||
var current = MainVehicle.ReadPosition();
|
var current = MainVehicle.ReadPosition();
|
||||||
var dist = current.DistanceTo(Position);
|
var dist = current.DistanceTo(Position);
|
||||||
var cali = ((Velocity.Length()<0.1 && !touching)?dist*4:dist)*(_predictedPos - current);
|
var cali = ((Velocity.Length()<0.1 && !touching)?dist*4:dist)*(_predictedPos - current);
|
||||||
|
|
||||||
if (dist<8)
|
if (dist<8)
|
||||||
{
|
{
|
||||||
MainVehicle.Velocity = _predictedVel;
|
MainVehicle.Velocity = Velocity;
|
||||||
MainVehicle.ApplyForce(cali);
|
MainVehicle.ApplyForce(cali);
|
||||||
if (IsFlipped)
|
if (IsFlipped)
|
||||||
{
|
{
|
||||||
@ -393,7 +392,7 @@ namespace RageCoop.Client
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
MainVehicle.Position=_predictedPos;
|
MainVehicle.Position=_predictedPos;
|
||||||
MainVehicle.Velocity=_predictedVel;
|
MainVehicle.Velocity=Velocity;
|
||||||
MainVehicle.Quaternion=Quaternion;
|
MainVehicle.Quaternion=Quaternion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,10 +161,6 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vector3 PredictPosition(this Entity e)
|
|
||||||
{
|
|
||||||
return e.ReadPosition()+e.Velocity*(Networking.Latency);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vehicle CreateVehicle(Model model, Vector3 position, float heading = 0f)
|
public static Vehicle CreateVehicle(Model model, Vector3 position, float heading = 0f)
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,7 @@ using System.Net;
|
|||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("RageCoop.Server")]
|
[assembly: InternalsVisibleTo("RageCoop.Server")]
|
||||||
[assembly: InternalsVisibleTo("RageCoop.Client")]
|
[assembly: InternalsVisibleTo("RageCoop.Client")]
|
||||||
@ -259,6 +260,18 @@ namespace RageCoop.Core
|
|||||||
return new List<byte[]>() { BitConverter.GetBytes(qua.X), BitConverter.GetBytes(qua.Y), BitConverter.GetBytes(qua.Z), BitConverter.GetBytes(qua.W) }.Join(4);
|
return new List<byte[]>() { BitConverter.GetBytes(qua.X), BitConverter.GetBytes(qua.Y), BitConverter.GetBytes(qua.Z), BitConverter.GetBytes(qua.W) }.Join(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static T GetPacket<T>(this NetIncomingMessage msg) where T : Packet, new()
|
||||||
|
{
|
||||||
|
msg.ReadByte();
|
||||||
|
return GetPacket<T>(msg.ReadBytes(msg.ReadInt32()));
|
||||||
|
}
|
||||||
|
public static T GetPacket<T>(this byte[] data) where T : Packet, new()
|
||||||
|
{
|
||||||
|
T p = new T();
|
||||||
|
p.Deserialize(data);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
public static bool HasPedFlag(this PedDataFlags flagToCheck, PedDataFlags flag)
|
public static bool HasPedFlag(this PedDataFlags flagToCheck, PedDataFlags flag)
|
||||||
{
|
{
|
||||||
return (flagToCheck & flag)!=0;
|
return (flagToCheck & flag)!=0;
|
||||||
|
69
RageCoop.Core/Packets/HolePunch.cs
Normal file
69
RageCoop.Core/Packets/HolePunch.cs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
internal partial class Packets
|
||||||
|
{
|
||||||
|
|
||||||
|
internal class HolePunchInit : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.HolePunchInit;
|
||||||
|
public int TargetID { get; set; }
|
||||||
|
public string TargetInternal { get; set; }
|
||||||
|
public string TargetExternal { get; set; }
|
||||||
|
public bool Connect { get; set; }
|
||||||
|
public override byte[] Serialize()
|
||||||
|
{
|
||||||
|
|
||||||
|
List<byte> byteArray = new List<byte>();
|
||||||
|
byteArray.AddInt(TargetID);
|
||||||
|
byteArray.AddString(TargetInternal);
|
||||||
|
byteArray.AddString(TargetExternal);
|
||||||
|
byteArray.AddBool(Connect);
|
||||||
|
return byteArray.ToArray();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(byte[] array)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
BitReader reader = new BitReader(array);
|
||||||
|
TargetID = reader.ReadInt32();
|
||||||
|
TargetInternal = reader.ReadString();
|
||||||
|
TargetExternal = reader.ReadString();
|
||||||
|
Connect=reader.ReadBoolean();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal class HolePunch : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.HolePunch;
|
||||||
|
public int Puncher { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 1:initial, 2:acknowledged, 3:confirmed
|
||||||
|
/// </summary>
|
||||||
|
public byte Status { get;set;}
|
||||||
|
public override byte[] Serialize()
|
||||||
|
{
|
||||||
|
|
||||||
|
List<byte> byteArray = new List<byte>();
|
||||||
|
byteArray.AddInt(Puncher);
|
||||||
|
byteArray.Add(Status);
|
||||||
|
return byteArray.ToArray();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(byte[] array)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
BitReader reader = new BitReader(array);
|
||||||
|
Puncher = reader.ReadInt32();
|
||||||
|
Status = reader.ReadByte();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -29,10 +29,10 @@ namespace RageCoop.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sent to the host when a direct connection has been established
|
/// Sent to the host when a direct connection has been established
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class ConnectionEstablished : Packet
|
internal class P2PConnect : Packet
|
||||||
{
|
{
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
public override PacketType Type => PacketType.ConnectionEstablished;
|
public override PacketType Type => PacketType.P2PConnect;
|
||||||
public override byte[] Serialize()
|
public override byte[] Serialize()
|
||||||
{
|
{
|
||||||
var data = new List<byte>(10);
|
var data = new List<byte>(10);
|
||||||
|
@ -31,12 +31,12 @@ namespace RageCoop.Core
|
|||||||
CustomEventQueued = 17,
|
CustomEventQueued = 17,
|
||||||
|
|
||||||
ConnectionRequest=18,
|
ConnectionRequest=18,
|
||||||
ConnectionEstablished = 19,
|
P2PConnect = 19,
|
||||||
|
HolePunchInit=20,
|
||||||
|
HolePunch=21,
|
||||||
#region Sync
|
#region Sync
|
||||||
|
|
||||||
#region INTERVAL
|
|
||||||
VehicleSync = 20,
|
|
||||||
PedSync = 22,
|
PedSync = 22,
|
||||||
|
VehicleSync = 23,
|
||||||
ProjectileSync =24,
|
ProjectileSync =24,
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -53,7 +53,6 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#endregion
|
|
||||||
Unknown=255
|
Unknown=255
|
||||||
}
|
}
|
||||||
internal static class PacketExtensions
|
internal static class PacketExtensions
|
||||||
|
198
RageCoop.Server/Networking/Server.Connections.cs
Normal file
198
RageCoop.Server/Networking/Server.Connections.cs
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Lidgren.Network;
|
||||||
|
using RageCoop.Core;
|
||||||
|
using RageCoop.Core.Scripting;
|
||||||
|
using RageCoop.Server.Scripting;
|
||||||
|
|
||||||
|
namespace RageCoop.Server
|
||||||
|
{
|
||||||
|
public partial class Server
|
||||||
|
{
|
||||||
|
private void DisconnectAndLog(NetConnection senderConnection, PacketType type, Exception e)
|
||||||
|
{
|
||||||
|
Logger?.Error($"Error receiving a packet of type {type}");
|
||||||
|
Logger?.Error(e.Message);
|
||||||
|
Logger?.Error(e.StackTrace);
|
||||||
|
senderConnection.Disconnect(e.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetHandshake(NetConnection connection, Packets.Handshake packet)
|
||||||
|
{
|
||||||
|
Logger?.Debug("New handshake from: [Name: " + packet.Username + " | Address: " + connection.RemoteEndPoint.Address.ToString() + "]");
|
||||||
|
|
||||||
|
if (!packet.ModVersion.StartsWith(_compatibleVersion))
|
||||||
|
{
|
||||||
|
connection.Deny($"RAGECOOP version {_compatibleVersion.Replace('_', '.')}.x required!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(packet.Username))
|
||||||
|
{
|
||||||
|
connection.Deny("Username is empty or contains spaces!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (packet.Username.Any(p => !_allowedCharacterSet.Contains(p)))
|
||||||
|
{
|
||||||
|
connection.Deny("Username contains special chars!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ClientsByNetHandle.Values.Any(x => x.Username.ToLower() == packet.Username.ToLower()))
|
||||||
|
{
|
||||||
|
connection.Deny("Username is already taken!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Security.AddConnection(connection.RemoteEndPoint, packet.AesKeyCrypted, packet.AesIVCrypted);
|
||||||
|
|
||||||
|
var args = new HandshakeEventArgs()
|
||||||
|
{
|
||||||
|
EndPoint=connection.RemoteEndPoint,
|
||||||
|
ID=packet.PedID,
|
||||||
|
Username=packet.Username,
|
||||||
|
PasswordHash=Security.Decrypt(packet.PasswordEncrypted, connection.RemoteEndPoint).GetString().GetSHA256Hash().ToHexString(),
|
||||||
|
};
|
||||||
|
API.Events.InvokePlayerHandshake(args);
|
||||||
|
if (args.Cancel)
|
||||||
|
{
|
||||||
|
connection.Deny(args.DenyReason);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger?.Error($"Cannot process handshake packet from {connection.RemoteEndPoint}");
|
||||||
|
Logger?.Error(ex);
|
||||||
|
connection.Deny("Malformed handshak packet!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var handshakeSuccess = MainNetServer.CreateMessage();
|
||||||
|
var currentClients = ClientsByID.Values.ToArray();
|
||||||
|
var players = new Packets.PlayerData[currentClients.Length];
|
||||||
|
for (int i = 0; i<players.Length; i++)
|
||||||
|
{
|
||||||
|
players[i]=new Packets.PlayerData()
|
||||||
|
{
|
||||||
|
ID=currentClients[i].Player.ID,
|
||||||
|
Username=currentClients[i].Username,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
new Packets.HandshakeSuccess()
|
||||||
|
{
|
||||||
|
Players=players
|
||||||
|
}.Pack(handshakeSuccess);
|
||||||
|
connection.Approve(handshakeSuccess);
|
||||||
|
Client tmpClient;
|
||||||
|
|
||||||
|
// Add the player to Players
|
||||||
|
lock (ClientsByNetHandle)
|
||||||
|
{
|
||||||
|
var player = new ServerPed(this)
|
||||||
|
{
|
||||||
|
ID= packet.PedID,
|
||||||
|
};
|
||||||
|
Entities.Add(player);
|
||||||
|
ClientsByNetHandle.Add(connection.RemoteUniqueIdentifier,
|
||||||
|
tmpClient = new Client(this)
|
||||||
|
{
|
||||||
|
NetHandle = connection.RemoteUniqueIdentifier,
|
||||||
|
Connection=connection,
|
||||||
|
Username=packet.Username,
|
||||||
|
Player = player,
|
||||||
|
InternalEndPoint=packet.InternalEndPoint,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
ClientsByName.Add(packet.Username.ToLower(), tmpClient);
|
||||||
|
ClientsByID.Add(player.ID, tmpClient);
|
||||||
|
if (ClientsByNetHandle.Count==1)
|
||||||
|
{
|
||||||
|
_hostClient=tmpClient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger?.Debug($"Handshake sucess, Player:{packet.Username} PedID:{packet.PedID}");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 void PlayerConnected(Client newClient)
|
||||||
|
{
|
||||||
|
if (newClient==_hostClient)
|
||||||
|
{
|
||||||
|
API.SendCustomEvent(new() { newClient }, CustomEvents.IsHost, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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=newClient.Player.ID,
|
||||||
|
Username = newClient.Username
|
||||||
|
}.Pack(outgoingMessage);
|
||||||
|
|
||||||
|
MainNetServer.SendMessage(outgoingMessage, cons, NetDeliveryMethod.ReliableOrdered, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send all props to this player
|
||||||
|
BaseScript.SendServerPropsTo(new(Entities.ServerProps.Values), new() { newClient });
|
||||||
|
|
||||||
|
// Send all blips to this player
|
||||||
|
BaseScript.SendServerBlipsTo(new(Entities.Blips.Values), new() { newClient });
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Create P2P connection
|
||||||
|
if (Settings.UseP2P)
|
||||||
|
{
|
||||||
|
ClientsByNetHandle.Values.ForEach(target =>
|
||||||
|
{
|
||||||
|
if (target==newClient) { return; }
|
||||||
|
HolePunch(target,newClient);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger?.Info($"Player {newClient.Username} connected!");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(Settings.WelcomeMessage))
|
||||||
|
{
|
||||||
|
SendChatMessage("Server", Settings.WelcomeMessage, newClient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send all players a message that someone has left the server
|
||||||
|
private void PlayerDisconnected(Client localClient)
|
||||||
|
{
|
||||||
|
var cons = MainNetServer.Connections.Exclude(localClient.Connection);
|
||||||
|
if (cons.Count!=0)
|
||||||
|
{
|
||||||
|
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||||
|
new Packets.PlayerDisconnect()
|
||||||
|
{
|
||||||
|
PedID=localClient.Player.ID,
|
||||||
|
|
||||||
|
}.Pack(outgoingMessage);
|
||||||
|
MainNetServer.SendMessage(outgoingMessage, cons, NetDeliveryMethod.ReliableOrdered, 0);
|
||||||
|
}
|
||||||
|
Entities.CleanUp(localClient);
|
||||||
|
_worker.QueueJob(() => API.Events.InvokePlayerDisconnected(localClient));
|
||||||
|
Logger?.Info($"Player {localClient.Username} disconnected! ID:{localClient.Player.ID}");
|
||||||
|
if (ClientsByNetHandle.ContainsKey(localClient.NetHandle)) { ClientsByNetHandle.Remove(localClient.NetHandle); }
|
||||||
|
if (ClientsByName.ContainsKey(localClient.Username.ToLower())) { ClientsByName.Remove(localClient.Username.ToLower()); }
|
||||||
|
if (ClientsByID.ContainsKey(localClient.Player.ID)) { ClientsByID.Remove(localClient.Player.ID); }
|
||||||
|
if (localClient==_hostClient)
|
||||||
|
{
|
||||||
|
|
||||||
|
_hostClient = ClientsByNetHandle.Values.FirstOrDefault();
|
||||||
|
_hostClient?.SendCustomEvent(CustomEvents.IsHost, true);
|
||||||
|
}
|
||||||
|
Security.RemoveConnection(localClient.Connection.RemoteEndPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
92
RageCoop.Server/Networking/Server.EntitySync.cs
Normal file
92
RageCoop.Server/Networking/Server.EntitySync.cs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Lidgren.Network;
|
||||||
|
using RageCoop.Core;
|
||||||
|
using RageCoop.Core.Scripting;
|
||||||
|
using RageCoop.Server.Scripting;
|
||||||
|
|
||||||
|
namespace RageCoop.Server
|
||||||
|
{
|
||||||
|
public partial class Server
|
||||||
|
{
|
||||||
|
private void PedSync(Packets.PedSync packet, Client client)
|
||||||
|
{
|
||||||
|
_worker.QueueJob(() => Entities.Update(packet, client));
|
||||||
|
|
||||||
|
bool isPlayer = packet.ID==client.Player.ID;
|
||||||
|
if (isPlayer)
|
||||||
|
{
|
||||||
|
_worker.QueueJob(() => API.Events.InvokePlayerUpdate(client));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Settings.UseP2P) { return; }
|
||||||
|
foreach (var c in ClientsByNetHandle.Values)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Don't send data back
|
||||||
|
if (c.NetHandle==client.NetHandle) { continue; }
|
||||||
|
|
||||||
|
// Check streaming distance
|
||||||
|
if (isPlayer)
|
||||||
|
{
|
||||||
|
if ((Settings.PlayerStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.PlayerStreamingDistance))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((Settings.NpcStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.NpcStreamingDistance))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||||
|
packet.Pack(outgoingMessage);
|
||||||
|
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void VehicleSync(Packets.VehicleSync packet, Client client)
|
||||||
|
{
|
||||||
|
_worker.QueueJob(() => Entities.Update(packet, client));
|
||||||
|
bool isPlayer = packet.ID==client.Player?.LastVehicle?.ID;
|
||||||
|
|
||||||
|
|
||||||
|
if (Settings.UseP2P) { return; }
|
||||||
|
foreach (var c in ClientsByNetHandle.Values)
|
||||||
|
{
|
||||||
|
if (c.NetHandle==client.NetHandle) { continue; }
|
||||||
|
if (isPlayer)
|
||||||
|
{
|
||||||
|
// Player's vehicle
|
||||||
|
if ((Settings.PlayerStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.PlayerStreamingDistance))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if ((Settings.NpcStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.NpcStreamingDistance))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||||
|
packet.Pack(outgoingMessage);
|
||||||
|
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void ProjectileSync(Packets.ProjectileSync packet, Client client)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (Settings.UseP2P) { return; }
|
||||||
|
foreach (var c in ClientsByNetHandle.Values)
|
||||||
|
{
|
||||||
|
if (c.NetHandle==client.NetHandle) { continue; }
|
||||||
|
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||||
|
packet.Pack(outgoingMessage);
|
||||||
|
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
36
RageCoop.Server/Networking/Server.HolePunch.cs
Normal file
36
RageCoop.Server/Networking/Server.HolePunch.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Lidgren.Network;
|
||||||
|
using RageCoop.Core;
|
||||||
|
using RageCoop.Core.Scripting;
|
||||||
|
using RageCoop.Server.Scripting;
|
||||||
|
|
||||||
|
namespace RageCoop.Server
|
||||||
|
{
|
||||||
|
public partial class Server
|
||||||
|
{
|
||||||
|
private void HolePunch(Client host, Client client)
|
||||||
|
{
|
||||||
|
// Send to host
|
||||||
|
Send(new Packets.HolePunchInit
|
||||||
|
{
|
||||||
|
Connect=false,
|
||||||
|
TargetID=client.Player.ID,
|
||||||
|
TargetInternal=client.InternalEndPoint.ToString(),
|
||||||
|
TargetExternal=client.EndPoint.ToString()
|
||||||
|
}, host, ConnectionChannel.Default, NetDeliveryMethod.ReliableOrdered);
|
||||||
|
|
||||||
|
// Send to client
|
||||||
|
Send(new Packets.HolePunchInit
|
||||||
|
{
|
||||||
|
Connect=true,
|
||||||
|
TargetID=host.Player.ID,
|
||||||
|
TargetInternal=host.InternalEndPoint.ToString(),
|
||||||
|
TargetExternal=host.EndPoint.ToString()
|
||||||
|
}, client, ConnectionChannel.Default, NetDeliveryMethod.ReliableOrdered);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -32,7 +32,7 @@ namespace RageCoop.Server
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The instantiable RageCoop server class
|
/// The instantiable RageCoop server class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Server
|
public partial class Server
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The API for controlling server and hooking events.
|
/// The API for controlling server and hooking events.
|
||||||
@ -108,7 +108,7 @@ namespace RageCoop.Server
|
|||||||
Logger?.Error(ex);
|
Logger?.Error(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Thread.Sleep(5000);
|
Thread.Sleep(1000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
_announceThread=new Thread(async () =>
|
_announceThread=new Thread(async () =>
|
||||||
@ -316,10 +316,7 @@ namespace RageCoop.Server
|
|||||||
{
|
{
|
||||||
int len = message.ReadInt32();
|
int len = message.ReadInt32();
|
||||||
byte[] data = message.ReadBytes(len);
|
byte[] data = message.ReadBytes(len);
|
||||||
|
GetHandshake(message.SenderConnection, data.GetPacket<Packets.Handshake>());
|
||||||
Packets.Handshake packet = new();
|
|
||||||
packet.Deserialize(data);
|
|
||||||
GetHandshake(message.SenderConnection, packet);
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -457,33 +454,20 @@ namespace RageCoop.Server
|
|||||||
}
|
}
|
||||||
private void HandlePacket(PacketType type,byte[] data,Client sender)
|
private void HandlePacket(PacketType type,byte[] data,Client sender)
|
||||||
{
|
{
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case PacketType.PedSync:
|
case PacketType.PedSync:
|
||||||
{
|
PedSync(data.GetPacket<Packets.PedSync>(), sender);
|
||||||
|
break;
|
||||||
|
|
||||||
Packets.PedSync packet = new();
|
|
||||||
packet.Deserialize(data);
|
|
||||||
PedSync(packet, sender);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PacketType.VehicleSync:
|
case PacketType.VehicleSync:
|
||||||
{
|
VehicleSync(data.GetPacket<Packets.VehicleSync>(), sender);
|
||||||
Packets.VehicleSync packet = new();
|
|
||||||
packet.Deserialize(data);
|
|
||||||
VehicleSync(packet, sender);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.ProjectileSync:
|
case PacketType.ProjectileSync:
|
||||||
{
|
ProjectileSync(data.GetPacket<Packets.ProjectileSync>(), sender);
|
||||||
Packets.ProjectileSync packet = new();
|
|
||||||
packet.Deserialize(data);
|
|
||||||
ProjectileSync(packet, sender);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.ChatMessage:
|
case PacketType.ChatMessage:
|
||||||
@ -496,6 +480,7 @@ namespace RageCoop.Server
|
|||||||
ChatMessageReceived(packet.Username,packet.Message, sender);
|
ChatMessageReceived(packet.Username,packet.Message, sender);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.CustomEvent:
|
case PacketType.CustomEvent:
|
||||||
{
|
{
|
||||||
Packets.CustomEvent packet = new Packets.CustomEvent();
|
Packets.CustomEvent packet = new Packets.CustomEvent();
|
||||||
@ -503,19 +488,10 @@ namespace RageCoop.Server
|
|||||||
_worker.QueueJob(() => API.Events.InvokeCustomEventReceived(packet, sender));
|
_worker.QueueJob(() => API.Events.InvokeCustomEventReceived(packet, sender));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PacketType.ConnectionRequest:
|
|
||||||
{
|
|
||||||
var p=new Packets.ConnectionRequest();
|
|
||||||
p.Deserialize(data);
|
|
||||||
if (ClientsByID.TryGetValue(p.TargetID,out var target))
|
|
||||||
{
|
|
||||||
MainNetServer.Introduce(target.InternalEndPoint,target.EndPoint,sender.InternalEndPoint,sender.EndPoint,Guid.NewGuid().ToString());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
Logger?.Error("Unhandled Data / Packet type");
|
Logger?.Error("Unhandled Data / Packet type");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -524,268 +500,6 @@ namespace RageCoop.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisconnectAndLog(NetConnection senderConnection,PacketType type, Exception e)
|
|
||||||
{
|
|
||||||
Logger?.Error($"Error receiving a packet of type {type}");
|
|
||||||
Logger?.Error(e.Message);
|
|
||||||
Logger?.Error(e.StackTrace);
|
|
||||||
senderConnection.Disconnect(e.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GetHandshake(NetConnection connection, Packets.Handshake packet)
|
|
||||||
{
|
|
||||||
Logger?.Debug("New handshake from: [Name: " + packet.Username + " | Address: " + connection.RemoteEndPoint.Address.ToString() + "]");
|
|
||||||
|
|
||||||
if (!packet.ModVersion.StartsWith(_compatibleVersion))
|
|
||||||
{
|
|
||||||
connection.Deny($"RAGECOOP version {_compatibleVersion.Replace('_', '.')}.x required!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (string.IsNullOrWhiteSpace(packet.Username))
|
|
||||||
{
|
|
||||||
connection.Deny("Username is empty or contains spaces!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (packet.Username.Any(p => !_allowedCharacterSet.Contains(p)))
|
|
||||||
{
|
|
||||||
connection.Deny("Username contains special chars!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (ClientsByNetHandle.Values.Any(x => x.Username.ToLower() == packet.Username.ToLower()))
|
|
||||||
{
|
|
||||||
connection.Deny("Username is already taken!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Security.AddConnection(connection.RemoteEndPoint, packet.AesKeyCrypted,packet.AesIVCrypted);
|
|
||||||
|
|
||||||
var args = new HandshakeEventArgs()
|
|
||||||
{
|
|
||||||
EndPoint=connection.RemoteEndPoint,
|
|
||||||
ID=packet.PedID,
|
|
||||||
Username=packet.Username,
|
|
||||||
PasswordHash=Security.Decrypt(packet.PasswordEncrypted, connection.RemoteEndPoint).GetString().GetSHA256Hash().ToHexString(),
|
|
||||||
};
|
|
||||||
API.Events.InvokePlayerHandshake(args);
|
|
||||||
if (args.Cancel)
|
|
||||||
{
|
|
||||||
connection.Deny(args.DenyReason);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger?.Error($"Cannot process handshake packet from {connection.RemoteEndPoint}");
|
|
||||||
Logger?.Error(ex);
|
|
||||||
connection.Deny("Malformed handshak packet!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var handshakeSuccess = MainNetServer.CreateMessage();
|
|
||||||
var currentClients = ClientsByID.Values.ToArray();
|
|
||||||
var players = new Packets.PlayerData[currentClients.Length];
|
|
||||||
for(int i= 0; i<players.Length; i++)
|
|
||||||
{
|
|
||||||
players[i]=new Packets.PlayerData()
|
|
||||||
{
|
|
||||||
ID=currentClients[i].Player.ID,
|
|
||||||
Username=currentClients[i].Username,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
new Packets.HandshakeSuccess()
|
|
||||||
{
|
|
||||||
Players=players
|
|
||||||
}.Pack(handshakeSuccess);
|
|
||||||
connection.Approve(handshakeSuccess);
|
|
||||||
Client tmpClient;
|
|
||||||
|
|
||||||
// Add the player to Players
|
|
||||||
lock (ClientsByNetHandle)
|
|
||||||
{
|
|
||||||
var player = new ServerPed(this)
|
|
||||||
{
|
|
||||||
ID= packet.PedID,
|
|
||||||
};
|
|
||||||
Entities.Add(player);
|
|
||||||
ClientsByNetHandle.Add(connection.RemoteUniqueIdentifier,
|
|
||||||
tmpClient = new Client(this)
|
|
||||||
{
|
|
||||||
NetHandle = connection.RemoteUniqueIdentifier,
|
|
||||||
Connection=connection,
|
|
||||||
Username=packet.Username,
|
|
||||||
Player = player,
|
|
||||||
InternalEndPoint=packet.InternalEndPoint,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
ClientsByName.Add(packet.Username.ToLower(), tmpClient);
|
|
||||||
ClientsByID.Add(player.ID, tmpClient);
|
|
||||||
if (ClientsByNetHandle.Count==1) {
|
|
||||||
_hostClient=tmpClient;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger?.Debug($"Handshake sucess, Player:{packet.Username} PedID:{packet.PedID}");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 void PlayerConnected(Client newClient)
|
|
||||||
{
|
|
||||||
if (newClient==_hostClient)
|
|
||||||
{
|
|
||||||
API.SendCustomEvent(new() { newClient },CustomEvents.IsHost, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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=newClient.Player.ID,
|
|
||||||
Username = newClient.Username
|
|
||||||
}.Pack(outgoingMessage);
|
|
||||||
|
|
||||||
MainNetServer.SendMessage(outgoingMessage, cons, NetDeliveryMethod.ReliableOrdered, 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send all props to this player
|
|
||||||
BaseScript.SendServerPropsTo( new(Entities.ServerProps.Values), new() { newClient});
|
|
||||||
|
|
||||||
// Send all blips to this player
|
|
||||||
BaseScript.SendServerBlipsTo(new(Entities.Blips.Values), new() { newClient});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Create P2P connection
|
|
||||||
if (Settings.UseP2P)
|
|
||||||
{
|
|
||||||
ClientsByNetHandle.Values.ForEach(target =>
|
|
||||||
{
|
|
||||||
if (target==newClient) { return; }
|
|
||||||
MainNetServer.Introduce(target.InternalEndPoint, target.EndPoint, newClient.InternalEndPoint, newClient.EndPoint, target.Player.ID.ToString());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger?.Info($"Player {newClient.Username} connected!");
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Settings.WelcomeMessage))
|
|
||||||
{
|
|
||||||
SendChatMessage("Server",Settings.WelcomeMessage , newClient);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send all players a message that someone has left the server
|
|
||||||
private void PlayerDisconnected(Client localClient)
|
|
||||||
{
|
|
||||||
var cons = MainNetServer.Connections.Exclude(localClient.Connection);
|
|
||||||
if (cons.Count!=0)
|
|
||||||
{
|
|
||||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
|
||||||
new Packets.PlayerDisconnect()
|
|
||||||
{
|
|
||||||
PedID=localClient.Player.ID,
|
|
||||||
|
|
||||||
}.Pack(outgoingMessage);
|
|
||||||
MainNetServer.SendMessage(outgoingMessage,cons , NetDeliveryMethod.ReliableOrdered, 0);
|
|
||||||
}
|
|
||||||
Entities.CleanUp(localClient);
|
|
||||||
_worker.QueueJob(() => API.Events.InvokePlayerDisconnected(localClient));
|
|
||||||
Logger?.Info($"Player {localClient.Username} disconnected! ID:{localClient.Player.ID}");
|
|
||||||
if (ClientsByNetHandle.ContainsKey(localClient.NetHandle)) { ClientsByNetHandle.Remove(localClient.NetHandle); }
|
|
||||||
if (ClientsByName.ContainsKey(localClient.Username.ToLower())) { ClientsByName.Remove(localClient.Username.ToLower()); }
|
|
||||||
if (ClientsByID.ContainsKey(localClient.Player.ID)) { ClientsByID.Remove(localClient.Player.ID); }
|
|
||||||
if (localClient==_hostClient)
|
|
||||||
{
|
|
||||||
|
|
||||||
_hostClient = ClientsByNetHandle.Values.FirstOrDefault();
|
|
||||||
_hostClient?.SendCustomEvent(CustomEvents.IsHost, true);
|
|
||||||
}
|
|
||||||
Security.RemoveConnection(localClient.Connection.RemoteEndPoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region -- SYNC --
|
|
||||||
#region SyncEntities
|
|
||||||
|
|
||||||
private void PedSync(Packets.PedSync packet, Client client)
|
|
||||||
{
|
|
||||||
_worker.QueueJob(() => Entities.Update(packet, client));
|
|
||||||
|
|
||||||
bool isPlayer = packet.ID==client.Player.ID;
|
|
||||||
if (isPlayer)
|
|
||||||
{
|
|
||||||
_worker.QueueJob(() => API.Events.InvokePlayerUpdate(client));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Settings.UseP2P) { return; }
|
|
||||||
foreach (var c in ClientsByNetHandle.Values)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Don't send data back
|
|
||||||
if (c.NetHandle==client.NetHandle) { continue; }
|
|
||||||
|
|
||||||
// Check streaming distance
|
|
||||||
if (isPlayer)
|
|
||||||
{
|
|
||||||
if ((Settings.PlayerStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.PlayerStreamingDistance))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((Settings.NpcStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.NpcStreamingDistance))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
|
||||||
packet.Pack(outgoingMessage);
|
|
||||||
MainNetServer.SendMessage(outgoingMessage,c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void VehicleSync(Packets.VehicleSync packet, Client client)
|
|
||||||
{
|
|
||||||
_worker.QueueJob(() => Entities.Update(packet, client));
|
|
||||||
bool isPlayer = packet.ID==client.Player?.LastVehicle?.ID;
|
|
||||||
|
|
||||||
|
|
||||||
if (Settings.UseP2P) { return; }
|
|
||||||
foreach (var c in ClientsByNetHandle.Values)
|
|
||||||
{
|
|
||||||
if (c.NetHandle==client.NetHandle) { continue; }
|
|
||||||
if (isPlayer)
|
|
||||||
{
|
|
||||||
// Player's vehicle
|
|
||||||
if ((Settings.PlayerStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.PlayerStreamingDistance))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else if((Settings.NpcStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.NpcStreamingDistance))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
|
||||||
packet.Pack(outgoingMessage);
|
|
||||||
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void ProjectileSync(Packets.ProjectileSync packet, Client client)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (Settings.UseP2P) { return; }
|
|
||||||
foreach (var c in ClientsByNetHandle.Values)
|
|
||||||
{
|
|
||||||
if (c.NetHandle==client.NetHandle) { continue; }
|
|
||||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
|
||||||
packet.Pack(outgoingMessage);
|
|
||||||
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
// Send a message to targets or all players
|
// Send a message to targets or all players
|
||||||
internal void ChatMessageReceived(string name, string message,Client sender=null)
|
internal void ChatMessageReceived(string name, string message,Client sender=null)
|
||||||
{
|
{
|
||||||
@ -831,8 +545,6 @@ namespace RageCoop.Server
|
|||||||
}.Pack(msg);
|
}.Pack(msg);
|
||||||
MainNetServer.SendMessage(msg, target.Connection, NetDeliveryMethod.ReliableOrdered, (int)ConnectionChannel.Chat);
|
MainNetServer.SendMessage(msg, target.Connection, NetDeliveryMethod.ReliableOrdered, (int)ConnectionChannel.Chat);
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
internal void RegisterCommand(string name, string usage, short argsLength, Action<CommandContext> callback)
|
internal void RegisterCommand(string name, string usage, short argsLength, Action<CommandContext> callback)
|
||||||
{
|
{
|
@ -88,6 +88,6 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to use direct connection between players to send entity information
|
/// Whether to use direct connection between players to send entity information
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UseP2P { get; set; } = true;
|
public bool UseP2P { get; set; } = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user