P2P connectivity
This commit is contained in:
parent
09bb121ffe
commit
c3d7c2b335
@ -41,11 +41,13 @@ namespace RageCoop.Client
|
||||
internal static Vector3 PlayerPosition;
|
||||
internal static Scripting.Resources Resources = null;
|
||||
private static List<Func<bool>> QueuedActions = new List<Func<bool>>();
|
||||
public static Worker Worker;
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public Main()
|
||||
{
|
||||
Worker = new Worker("RageCoop.Client.Main.Worker", Logger);
|
||||
try
|
||||
{
|
||||
Settings = Util.ReadSettings();
|
||||
|
@ -11,7 +11,7 @@ namespace RageCoop.Client
|
||||
internal static partial class Networking
|
||||
{
|
||||
public static NetPeer Peer;
|
||||
public static float Latency = 0;
|
||||
public static float Latency => ServerConnection.AverageRoundtripTime/2;
|
||||
public static bool ShowNetworkInfo = false;
|
||||
public static Security Security;
|
||||
public static NetConnection ServerConnection;
|
||||
@ -22,17 +22,21 @@ namespace RageCoop.Client
|
||||
static Networking()
|
||||
{
|
||||
Security=new Security(Main.Logger);
|
||||
RequestHandlers.Add(PacketType.PingPong, (b) =>
|
||||
{
|
||||
return new Packets.PingPong();
|
||||
});
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (Peer!=null)
|
||||
{
|
||||
ProcessMessage(Peer.WaitMessage(200));
|
||||
try
|
||||
{
|
||||
|
||||
ProcessMessage(Peer.WaitMessage(200));
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Main.Logger.Error(ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -64,7 +68,9 @@ namespace RageCoop.Client
|
||||
{
|
||||
AutoFlushSendQueue = false,
|
||||
SimulatedMinimumLatency =SimulatedLatency,
|
||||
AcceptIncomingConnections = true
|
||||
AcceptIncomingConnections = true,
|
||||
MaximumConnections = 32,
|
||||
PingInterval = 5
|
||||
};
|
||||
|
||||
config.EnableMessageType(NetIncomingMessageType.UnconnectedData);
|
||||
@ -110,7 +116,7 @@ namespace RageCoop.Client
|
||||
Username =username,
|
||||
ModVersion = Main.CurrentVersion,
|
||||
PasswordEncrypted=Security.Encrypt(password.GetBytes()),
|
||||
InternalEndPoint = (System.Net.IPEndPoint)Peer.Socket.LocalEndPoint
|
||||
InternalEndPoint = new System.Net.IPEndPoint(CoreUtils.GetLocalAddress(ip[0]),Peer.Port)
|
||||
};
|
||||
|
||||
Security.GetSymmetricKeysCrypted(out handshake.AesKeyCrypted, out handshake.AesIVCrypted);
|
||||
@ -135,7 +141,7 @@ namespace RageCoop.Client
|
||||
#region -- PLAYER --
|
||||
private static void PlayerConnect(Packets.PlayerConnect packet)
|
||||
{
|
||||
var p = new PlayerData
|
||||
var p = new Player
|
||||
{
|
||||
PedID = packet.PedID,
|
||||
Username= packet.Username,
|
||||
|
@ -36,26 +36,51 @@ namespace RageCoop.Client
|
||||
{
|
||||
case NetIncomingMessageType.StatusChanged:
|
||||
NetConnectionStatus status = (NetConnectionStatus)message.ReadByte();
|
||||
|
||||
string reason = message.ReadString();
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case NetConnectionStatus.InitiatedConnect:
|
||||
#if !NON_INTERACTIVE
|
||||
CoopMenu.InitiateConnectionMenuSetting();
|
||||
#endif
|
||||
if (message.SenderConnection==ServerConnection)
|
||||
{
|
||||
|
||||
CoopMenu.InitiateConnectionMenuSetting();
|
||||
}
|
||||
break;
|
||||
case NetConnectionStatus.Connected:
|
||||
Memory.ApplyPatches();
|
||||
Main.QueueAction(() =>
|
||||
if (message.SenderConnection==ServerConnection)
|
||||
{
|
||||
CoopMenu.ConnectedMenuSetting();
|
||||
Main.MainChat.Init();
|
||||
GTA.UI.Notification.Show("~g~Connected!");
|
||||
});
|
||||
Memory.ApplyPatches();
|
||||
var response = message.SenderConnection.RemoteHailMessage;
|
||||
if ((PacketType)response.ReadByte()!=PacketType.HandshakeSuccess)
|
||||
{
|
||||
throw new Exception("Invalid handshake response!");
|
||||
}
|
||||
var p = new Packets.HandshakeSuccess();
|
||||
p.Deserialize(response.ReadBytes(response.ReadInt32()));
|
||||
foreach(var player in p.Players)
|
||||
{
|
||||
PlayerList.SetPlayer(player.ID,player.Username);
|
||||
}
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
CoopMenu.ConnectedMenuSetting();
|
||||
Main.MainChat.Init();
|
||||
GTA.UI.Notification.Show("~g~Connected!");
|
||||
});
|
||||
|
||||
Main.Logger.Info(">> Connected <<");
|
||||
Main.Logger.Info(">> Connected <<");
|
||||
}
|
||||
else if (PlayerList.PendingConnections.TryGetValue(message.SenderEndPoint.ToString(),out var player))
|
||||
{
|
||||
PlayerList.PendingConnections.Remove(message.SenderEndPoint.ToString());
|
||||
Main.Logger.Debug($"Connection to {player.Username},{player.PedID},{player.Connection.Status} established, sending ID...");
|
||||
// Inform target our ID
|
||||
SendTo(new Packets.ConnectionEstablished()
|
||||
{
|
||||
ID=Main.LocalPlayerID
|
||||
}, player.Connection, ConnectionChannel.Default, NetDeliveryMethod.ReliableOrdered);
|
||||
Peer.FlushSendQueue();
|
||||
}
|
||||
break;
|
||||
case NetConnectionStatus.Disconnected:
|
||||
if (message.SenderConnection==ServerConnection)
|
||||
@ -75,12 +100,25 @@ namespace RageCoop.Client
|
||||
GTA.UI.Notification.Show("~r~Disconnected: " + reason));
|
||||
Main.Resources.Unload();
|
||||
}
|
||||
|
||||
|
||||
|
||||
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:
|
||||
{
|
||||
|
||||
@ -123,7 +161,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
byte[] data = message.ReadBytes(message.ReadInt32());
|
||||
|
||||
HandlePacket(packetType, data);
|
||||
HandlePacket(packetType, data,message.SenderConnection);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -160,6 +198,7 @@ namespace RageCoop.Client
|
||||
case NetIncomingMessageType.ErrorMessage:
|
||||
case NetIncomingMessageType.WarningMessage:
|
||||
case NetIncomingMessageType.VerboseDebugMessage:
|
||||
Main.Logger.Trace(message.ReadString());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -167,11 +206,22 @@ namespace RageCoop.Client
|
||||
|
||||
Peer.Recycle(message);
|
||||
}
|
||||
private static void HandlePacket(PacketType packetType, byte[] data)
|
||||
private static void HandlePacket(PacketType packetType, byte[] data, NetConnection senderConnection)
|
||||
{
|
||||
|
||||
switch (packetType)
|
||||
{
|
||||
case PacketType.ConnectionEstablished:
|
||||
{
|
||||
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;
|
||||
}
|
||||
case PacketType.PlayerConnect:
|
||||
{
|
||||
|
||||
|
@ -4,6 +4,7 @@ using GTA.Native;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -11,18 +12,18 @@ namespace RageCoop.Client
|
||||
{
|
||||
|
||||
public static int SyncInterval = 30;
|
||||
#region -- SEND --
|
||||
/// <summary>
|
||||
/// Pack the packet then send to server.
|
||||
/// </summary>
|
||||
/// <param name="p"></param>
|
||||
/// <param name="channel"></param>
|
||||
/// <param name="method"></param>
|
||||
public static List<NetConnection> Targets = new List<NetConnection>();
|
||||
public static void Send(Packet p, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = Peer.CreateMessage();
|
||||
p.Pack(outgoingMessage);
|
||||
Peer.SendMessage(outgoingMessage,ServerConnection, method, (int)channel);
|
||||
Peer.SendMessage(outgoingMessage,Targets, method, (int)channel);
|
||||
}
|
||||
public static void SendTo(Packet p,NetConnection connection, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = Peer.CreateMessage();
|
||||
p.Pack(outgoingMessage);
|
||||
Peer.SendMessage(outgoingMessage, connection, method, (int)channel);
|
||||
}
|
||||
|
||||
public static void SendPed(SyncedPed c, bool full)
|
||||
@ -101,16 +102,16 @@ namespace RageCoop.Client
|
||||
Flags = veh.GetVehicleFlags(),
|
||||
SteeringAngle = veh.SteeringAngle,
|
||||
Position = veh.PredictPosition(),
|
||||
Velocity=veh.Velocity,
|
||||
Quaternion=veh.ReadQuaternion(),
|
||||
RotationVelocity=veh.RotationVelocity,
|
||||
ThrottlePower = veh.ThrottlePower,
|
||||
BrakePower = veh.BrakePower,
|
||||
};
|
||||
var velo = veh.Velocity;
|
||||
if (v.LastVelocity==default) {v.LastVelocity=velo; }
|
||||
packet.Acceleration = (velo-v.LastVelocity)*1000/v.LastSentStopWatch.ElapsedMilliseconds;
|
||||
packet.Velocity=(v.LastVelocity = velo) + packet.Acceleration*Latency;
|
||||
if (v.LastVelocity==default) {v.LastVelocity=packet.Velocity; }
|
||||
packet.Acceleration = (packet.Velocity-v.LastVelocity)*1000/v.LastSentStopWatch.ElapsedMilliseconds;
|
||||
v.LastSentStopWatch.Restart();
|
||||
v.LastVelocity= packet.Velocity;
|
||||
if (packet.Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering)) { packet.DeluxoWingRatio=v.MainVehicle.GetDeluxoWingRatio(); }
|
||||
if (full)
|
||||
{
|
||||
@ -185,10 +186,6 @@ namespace RageCoop.Client
|
||||
|
||||
Peer.SendMessage(outgoingMessage,ServerConnection, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Chat);
|
||||
Peer.FlushSendQueue();
|
||||
|
||||
#if DEBUG
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using RageCoop.Core;
|
||||
using System.Collections.Generic;
|
||||
using Lidgren.Network;
|
||||
using System.Net;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -14,7 +17,8 @@ namespace RageCoop.Client
|
||||
public static ulong Pressed { get; set; }
|
||||
|
||||
public static bool LeftAlign = true;
|
||||
public static Dictionary<int, PlayerData> Players = new Dictionary<int, PlayerData> { };
|
||||
public static Dictionary<int, Player> Players = new Dictionary<int, Player> { };
|
||||
public static Dictionary<string, Player> PendingConnections = new Dictionary<string, Player>();
|
||||
public static void Tick()
|
||||
{
|
||||
if (!Networking.IsOnServer)
|
||||
@ -24,7 +28,7 @@ namespace RageCoop.Client
|
||||
|
||||
if ((Util.GetTickCount64() - _lastUpdate) >= 1000)
|
||||
{
|
||||
Update(Main.Settings.Username);
|
||||
Update();
|
||||
}
|
||||
|
||||
if ((Util.GetTickCount64() - Pressed) < 5000 && !Main.MainChat.Focused
|
||||
@ -40,7 +44,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
}
|
||||
|
||||
private static void Update(string localUsername)
|
||||
private static void Update()
|
||||
{
|
||||
_lastUpdate = Util.GetTickCount64();
|
||||
|
||||
@ -48,9 +52,9 @@ namespace RageCoop.Client
|
||||
|
||||
int i=0;
|
||||
|
||||
foreach (var player in Players)
|
||||
foreach (var player in Players.Values)
|
||||
{
|
||||
_mainScaleform.CallFunction("SET_DATA_SLOT", i++, $"{player.Value.Latency * 1000:N0}ms", player.Value.Username, 116, 0, i - 1, "", "", 2, "", "", ' ');
|
||||
_mainScaleform.CallFunction("SET_DATA_SLOT", i++, $"{(player.PedID==Main.LocalPlayerID ? Networking.Latency : player.Latency) * 1000:N0}ms", player.Username, 116, 0, i - 1, "", "", 2, "", "", ' ');
|
||||
}
|
||||
|
||||
_mainScaleform.CallFunction("SET_TITLE", "Player list", $"{Players.Count} players");
|
||||
@ -58,37 +62,36 @@ namespace RageCoop.Client
|
||||
}
|
||||
public static void SetPlayer(int id, string username, float latency = 0)
|
||||
{
|
||||
if(id == Main.LocalPlayerID) { Networking.Latency=latency; }
|
||||
Main.Logger.Debug($"{id},{username},{latency}");
|
||||
PlayerData p;
|
||||
Player p;
|
||||
if (Players.TryGetValue(id, out p))
|
||||
{
|
||||
p.Username=username;
|
||||
p.PedID=id;
|
||||
p.Latency=latency;
|
||||
p._latencyToServer=latency;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = new PlayerData { PedID=id, Username=username, Latency=latency };
|
||||
p = new Player { PedID=id, Username=username, _latencyToServer=latency };
|
||||
Players.Add(id, p);
|
||||
}
|
||||
}
|
||||
public static void UpdatePlayer(Packets.PlayerInfoUpdate packet)
|
||||
{
|
||||
if (packet.PedID == Main.LocalPlayerID) {Main.Logger.Debug("Latency updated"); Networking.Latency=packet.Latency; }
|
||||
var p = GetPlayer(packet.PedID);
|
||||
if (p!=null)
|
||||
{
|
||||
p.Latency= packet.Latency;
|
||||
p._latencyToServer = packet.Latency;
|
||||
p.Position = packet.Position;
|
||||
}
|
||||
}
|
||||
public static PlayerData GetPlayer(int id)
|
||||
public static Player GetPlayer(int id)
|
||||
{
|
||||
PlayerData p;
|
||||
Player p;
|
||||
Players.TryGetValue(id, out p);
|
||||
return p;
|
||||
}
|
||||
public static PlayerData GetPlayer(SyncedPed p)
|
||||
public static Player GetPlayer(SyncedPed p)
|
||||
{
|
||||
var player = GetPlayer(p.ID);
|
||||
if (player!=null)
|
||||
@ -106,13 +109,13 @@ namespace RageCoop.Client
|
||||
}
|
||||
public static void Cleanup()
|
||||
{
|
||||
Players=new Dictionary<int, PlayerData> { };
|
||||
Players=new Dictionary<int, Player> { };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
internal class PlayerData
|
||||
internal class Player
|
||||
{
|
||||
public string Username { get; internal set; }
|
||||
/// <summary>
|
||||
@ -122,12 +125,16 @@ namespace RageCoop.Client
|
||||
{
|
||||
get; internal set;
|
||||
}
|
||||
public Vector3 Position { get; set; }
|
||||
public SyncedPed Character { get; set; }
|
||||
/// <summary>
|
||||
/// Player Latency in second.
|
||||
/// Player Latency in seconds, will be the latency to server if not using P2P connection.
|
||||
/// </summary>
|
||||
public float Latency { get; set; }
|
||||
|
||||
public float Latency => HasDirectConnection ? Connection.AverageRoundtripTime/2 : _latencyToServer;
|
||||
public float PacketTravelTime => HasDirectConnection ? Connection.AverageRoundtripTime/2 : Networking.Latency+_latencyToServer;
|
||||
public float _latencyToServer = 0;
|
||||
public bool DisplayNameTag { get; set; } = true;
|
||||
public NetConnection Connection { get; set; }
|
||||
public bool HasDirectConnection => Connection?.Status==NetConnectionStatus.Connected;
|
||||
}
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ namespace RageCoop.Client.Scripting
|
||||
Args=args,
|
||||
Hash=eventHash
|
||||
};
|
||||
Networking.Send(p, ConnectionChannel.Event, Lidgren.Network.NetDeliveryMethod.ReliableOrdered);
|
||||
Networking.SendTo(p,Networking.ServerConnection, ConnectionChannel.Event, Lidgren.Network.NetDeliveryMethod.ReliableOrdered);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -25,10 +25,27 @@ namespace RageCoop.Client
|
||||
/// Network ID for this entity
|
||||
/// </summary>
|
||||
public int ID { get; internal set; }
|
||||
|
||||
|
||||
private int _ownerID;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public int OwnerID { get; internal set; }
|
||||
public int OwnerID
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ownerID;
|
||||
}
|
||||
internal set
|
||||
{
|
||||
if (value==_ownerID) { return; }
|
||||
_ownerID = value;
|
||||
Owner=PlayerList.GetPlayer(value);
|
||||
}
|
||||
}
|
||||
|
||||
internal Player Owner { get; private set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
@ -49,7 +49,7 @@ namespace RageCoop.Client
|
||||
internal BlipColor BlipColor = (BlipColor)255;
|
||||
internal BlipSprite BlipSprite = (BlipSprite)0;
|
||||
internal float BlipScale = 1;
|
||||
internal PlayerData Player;
|
||||
internal Player Player;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
@ -142,7 +142,7 @@ namespace RageCoop.Client
|
||||
|
||||
if (IsPlayer)
|
||||
{
|
||||
Main.Logger.Debug("blip:"+Player.Username);
|
||||
// Main.Logger.Debug("blip:"+Player.Username);
|
||||
Main.QueueAction(() => { PedBlip.Name=Player.Username; });
|
||||
}
|
||||
PedBlip.Color=BlipColor;
|
||||
@ -236,7 +236,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
if (MainPed.Exists())
|
||||
{
|
||||
Main.Logger.Debug($"Removing ped {ID}. Reason:CreateCharacter");
|
||||
// Main.Logger.Debug($"Removing ped {ID}. Reason:CreateCharacter");
|
||||
MainPed.Kill();
|
||||
MainPed.MarkAsNoLongerNeeded();
|
||||
MainPed.Delete();
|
||||
|
@ -358,14 +358,14 @@ namespace RageCoop.Client
|
||||
void DisplayVehicle(bool touching)
|
||||
{
|
||||
// predict velocity/position
|
||||
_elapsed = Networking.Latency+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();
|
||||
_predictedVel = Velocity+Acceleration*_elapsed;
|
||||
_predictedPos = Position+_elapsed*(LastVelocity+_predictedVel)/2;
|
||||
LastVelocity=_predictedVel;
|
||||
var current = MainVehicle.ReadPosition();
|
||||
var dist = current.DistanceTo(Position);
|
||||
var cali = ((Velocity.Length()<0.1 && !touching)?dist*4:dist)*(_predictedPos - current);
|
||||
// new LemonUI.Elements.ScaledText(new System.Drawing.PointF(50, 50), dist.ToString()).Draw();
|
||||
|
||||
if (dist<8)
|
||||
{
|
||||
|
@ -1,12 +1,11 @@
|
||||
|
||||
using GTA;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using RageCoop.Client.Scripting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -291,7 +290,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
Handle_Projectiles.Remove(p.Handle);
|
||||
}
|
||||
Main.Logger.Debug($"Removing projectile {sp.ID}. Reason:{reason}");
|
||||
// Main.Logger.Debug($"Removing projectile {sp.ID}. Reason:{reason}");
|
||||
p.Explode();
|
||||
}
|
||||
ID_Projectiles.Remove(id);
|
||||
@ -322,6 +321,7 @@ namespace RageCoop.Client
|
||||
|
||||
public static void DoSync()
|
||||
{
|
||||
UpdateTargets();
|
||||
#if BENCHMARK
|
||||
PerfCounter.Restart();
|
||||
Debug.TimeStamps[TimeStamp.CheckProjectiles]=PerfCounter.ElapsedTicks;
|
||||
@ -560,11 +560,19 @@ namespace RageCoop.Client
|
||||
Debug.TimeStamps[TimeStamp.VehicleTotal]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
}
|
||||
|
||||
ThreadPool.QueueUserWorkItem((o) => { Networking.Peer.FlushSendQueue(); });
|
||||
|
||||
Networking.Peer.FlushSendQueue();
|
||||
}
|
||||
static void UpdateTargets()
|
||||
{
|
||||
Networking.Targets=new List<NetConnection>(PlayerList.Players.Count) { Networking.ServerConnection };
|
||||
foreach (var p in PlayerList.Players.Values.ToArray())
|
||||
{
|
||||
if (p.HasDirectConnection && p.Position.DistanceTo(Main.PlayerPosition)<500)
|
||||
{
|
||||
Networking.Targets.Add(p.Connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void RemoveAllFromPlayer(int playerPedId)
|
||||
{
|
||||
|
@ -113,7 +113,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
if (ped.Handle==Game.Player.Character.Handle) { continue; }
|
||||
|
||||
Main.Logger.Trace($"Removing ped {ped.Handle}. Reason:RemoveTraffic");
|
||||
// Main.Logger.Trace($"Removing ped {ped.Handle}. Reason:RemoveTraffic");
|
||||
ped.CurrentVehicle?.Delete();
|
||||
ped.Kill();
|
||||
ped.Delete();
|
||||
@ -131,7 +131,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
if ((v== null) || (v.IsLocal&&veh.PopulationType!=EntityPopulationType.Mission))
|
||||
{
|
||||
Main.Logger.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic");
|
||||
// Main.Logger.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic");
|
||||
|
||||
veh.Delete();
|
||||
}
|
||||
|
@ -25,8 +25,7 @@ namespace RageCoop.Core
|
||||
}
|
||||
public override string ReadString()
|
||||
{
|
||||
string value = Encoding.UTF8.GetString(ReadBytes(ReadInt32()));
|
||||
return value;
|
||||
return Encoding.UTF8.GetString(ReadBytes(ReadInt32()));
|
||||
}
|
||||
|
||||
public Vector3 ReadVector3()
|
||||
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
using GTA.Math;
|
||||
using System.Security.Cryptography;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
@ -100,7 +101,7 @@ namespace RageCoop.Core
|
||||
|
||||
//try to use the address as IPv4, otherwise get hostname
|
||||
if (!IPAddress.TryParse(values[0], out ipaddy))
|
||||
ipaddy = getIPfromHost(values[0]);
|
||||
ipaddy = GetIPfromHost(values[0]);
|
||||
}
|
||||
else if (values.Length > 2) //ipv6
|
||||
{
|
||||
@ -141,8 +142,16 @@ namespace RageCoop.Core
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
private static IPAddress getIPfromHost(string p)
|
||||
public static IPAddress GetLocalAddress(string target= "8.8.8.8")
|
||||
{
|
||||
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
|
||||
{
|
||||
socket.Connect(target, 65530);
|
||||
IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint;
|
||||
return endPoint.Address;
|
||||
}
|
||||
}
|
||||
private static IPAddress GetIPfromHost(string p)
|
||||
{
|
||||
var hosts = Dns.GetHostAddresses(p);
|
||||
|
||||
|
@ -5,15 +5,6 @@ namespace RageCoop.Core
|
||||
{
|
||||
internal partial class Packets
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Used to measure the connection latency
|
||||
/// </summary>
|
||||
internal class PingPong : Packet
|
||||
{
|
||||
public override PacketType Type => PacketType.PingPong;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request direct connection to another client
|
||||
/// </summary>
|
||||
@ -33,5 +24,26 @@ namespace RageCoop.Core
|
||||
TargetID = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sent to the host when a direct connection has been established
|
||||
/// </summary>
|
||||
internal class ConnectionEstablished : Packet
|
||||
{
|
||||
public int ID { get; set; }
|
||||
public override PacketType Type => PacketType.ConnectionEstablished;
|
||||
public override byte[] Serialize()
|
||||
{
|
||||
var data = new List<byte>(10);
|
||||
data.AddInt(ID);
|
||||
return data.ToArray();
|
||||
}
|
||||
public override void Deserialize(byte[] array)
|
||||
{
|
||||
var reader = new BitReader(array);
|
||||
ID = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ namespace RageCoop.Core
|
||||
Request=6,
|
||||
Response=7,
|
||||
PingPong = 8,
|
||||
HandshakeSuccess = 9,
|
||||
ChatMessage =10,
|
||||
|
||||
FileTransferChunk=11,
|
||||
@ -30,6 +31,7 @@ namespace RageCoop.Core
|
||||
CustomEventQueued = 17,
|
||||
|
||||
ConnectionRequest=18,
|
||||
ConnectionEstablished = 19,
|
||||
#region Sync
|
||||
|
||||
#region INTERVAL
|
||||
|
@ -1,14 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using GTA.Math;
|
||||
using System.Net;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
internal partial class Packets
|
||||
{
|
||||
internal class Handshake : Packet
|
||||
internal struct PlayerData
|
||||
{
|
||||
public int ID;
|
||||
public string Username;
|
||||
}
|
||||
public class Handshake : Packet
|
||||
{
|
||||
public override PacketType Type => PacketType.Handshake;
|
||||
public int PedID { get; set; }
|
||||
@ -92,7 +97,35 @@ namespace RageCoop.Core
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
public class HandshakeSuccess : Packet
|
||||
{
|
||||
public PlayerData[] Players { get; set; }
|
||||
public override PacketType Type => PacketType.HandshakeSuccess;
|
||||
public override byte[] Serialize()
|
||||
{
|
||||
var data = new List<byte>();
|
||||
data.AddInt(Players.Length);
|
||||
foreach(var p in Players)
|
||||
{
|
||||
data.AddInt(p.ID);
|
||||
data.AddString(p.Username);
|
||||
}
|
||||
return data.ToArray();
|
||||
}
|
||||
public override void Deserialize(byte[] array)
|
||||
{
|
||||
var reader = new BitReader(array);
|
||||
Players=new PlayerData[reader.ReadInt32()];
|
||||
for(int i = 0; i<Players.Length; i++)
|
||||
{
|
||||
Players[i]=new PlayerData()
|
||||
{
|
||||
ID=reader.ReadInt32(),
|
||||
Username=reader.ReadString(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
public class PlayerConnect : Packet
|
||||
{
|
||||
public override PacketType Type => PacketType.PlayerConnect;
|
||||
@ -168,6 +201,7 @@ namespace RageCoop.Core
|
||||
public int PedID { get; set; }
|
||||
public string Username { get; set; }
|
||||
public float Latency { get; set; }
|
||||
public Vector3 Position { get; set; }
|
||||
public override byte[] Serialize()
|
||||
{
|
||||
|
||||
@ -176,19 +210,14 @@ namespace RageCoop.Core
|
||||
// Write ID
|
||||
byteArray.AddRange(BitConverter.GetBytes(PedID));
|
||||
|
||||
// Get Username bytes
|
||||
byte[] usernameBytes = Encoding.UTF8.GetBytes(Username);
|
||||
|
||||
|
||||
// Write UsernameLength
|
||||
byteArray.AddRange(BitConverter.GetBytes(usernameBytes.Length));
|
||||
|
||||
// Write Username
|
||||
byteArray.AddRange(usernameBytes);
|
||||
byteArray.AddString(Username);
|
||||
|
||||
// Write Latency
|
||||
byteArray.AddFloat(Latency);
|
||||
|
||||
byteArray.AddVector3(Position);
|
||||
|
||||
return byteArray.ToArray();
|
||||
}
|
||||
|
||||
@ -203,6 +232,8 @@ namespace RageCoop.Core
|
||||
Username = reader.ReadString();
|
||||
|
||||
Latency=reader.ReadSingle();
|
||||
|
||||
Position=reader.ReadVector3();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ namespace RageCoop.Server
|
||||
/// <summary>
|
||||
/// The client's latency in seconds.
|
||||
/// </summary>
|
||||
public float Latency { get; internal set; }
|
||||
public float Latency => Connection.AverageRoundtripTime/2;
|
||||
internal readonly Dictionary<int, Action<object>> Callbacks = new();
|
||||
internal byte[] PublicKey { get; set; }
|
||||
/// <summary>
|
||||
@ -80,21 +80,6 @@ namespace RageCoop.Server
|
||||
_displayNameTag=value;
|
||||
}
|
||||
}
|
||||
internal void UpdateLatency()
|
||||
{
|
||||
_latencyWatch.Restart();
|
||||
Server.GetResponse<Packets.PingPong>(this, new Packets.PingPong(), ConnectionChannel.PingPong);
|
||||
_latencyWatch.Stop();
|
||||
Latency = (float)_latencyWatch.ElapsedMilliseconds/2000;
|
||||
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
||||
new Packets.PlayerInfoUpdate()
|
||||
{
|
||||
PedID=Player.ID,
|
||||
Username=Username,
|
||||
Latency=Latency,
|
||||
}.Pack(outgoingMessage);
|
||||
Server.MainNetServer.SendToAll(outgoingMessage, NetDeliveryMethod.ReliableSequenced, (byte)ConnectionChannel.Default);
|
||||
}
|
||||
#region FUNCTIONS
|
||||
/// <summary>
|
||||
/// Kick this client
|
||||
|
@ -91,9 +91,24 @@ namespace RageCoop.Server
|
||||
{
|
||||
foreach(var c in ClientsByNetHandle.Values.ToArray())
|
||||
{
|
||||
c.UpdateLatency();
|
||||
try
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
new Packets.PlayerInfoUpdate()
|
||||
{
|
||||
PedID=c.Player.ID,
|
||||
Username=c.Username,
|
||||
Latency=c.Latency,
|
||||
Position=c.Player.Position
|
||||
}.Pack(outgoingMessage);
|
||||
MainNetServer.SendToAll(outgoingMessage, NetDeliveryMethod.ReliableSequenced, (byte)ConnectionChannel.Default);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Logger?.Error(ex);
|
||||
}
|
||||
}
|
||||
Thread.Sleep(3000);
|
||||
Thread.Sleep(5000);
|
||||
}
|
||||
});
|
||||
_announceThread=new Thread(async () =>
|
||||
@ -217,7 +232,8 @@ namespace RageCoop.Server
|
||||
Port = Settings.Port,
|
||||
MaximumConnections = Settings.MaxPlayers,
|
||||
EnableUPnP = false,
|
||||
AutoFlushSendQueue = true
|
||||
AutoFlushSendQueue = true,
|
||||
PingInterval=5
|
||||
};
|
||||
|
||||
config.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
|
||||
@ -375,6 +391,8 @@ namespace RageCoop.Server
|
||||
if (type.IsSyncEvent())
|
||||
{
|
||||
// Sync Events
|
||||
|
||||
if (Settings.UseP2P) { break; }
|
||||
try
|
||||
{
|
||||
var toSend = MainNetServer.Connections.Exclude(message.SenderConnection);
|
||||
@ -563,8 +581,22 @@ namespace RageCoop.Server
|
||||
connection.Deny("Malformed handshak packet!");
|
||||
return;
|
||||
}
|
||||
|
||||
connection.Approve();
|
||||
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
|
||||
@ -604,27 +636,6 @@ namespace RageCoop.Server
|
||||
API.SendCustomEvent(new() { newClient },CustomEvents.IsHost, true);
|
||||
}
|
||||
|
||||
// Send other players to this client
|
||||
ClientsByNetHandle.Values.ForEach(target =>
|
||||
{
|
||||
if (target==newClient) { return; }
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
new Packets.PlayerConnect()
|
||||
{
|
||||
// NetHandle = targetNetHandle,
|
||||
Username = target.Username,
|
||||
PedID=target.Player.ID,
|
||||
|
||||
}.Pack(outgoingMessage);
|
||||
MainNetServer.SendMessage(outgoingMessage, newClient.Connection, 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});
|
||||
|
||||
// Send new client to all players
|
||||
var cons = MainNetServer.Connections.Exclude(newClient.Connection);
|
||||
if (cons.Count!=0)
|
||||
@ -636,10 +647,28 @@ namespace RageCoop.Server
|
||||
Username = newClient.Username
|
||||
}.Pack(outgoingMessage);
|
||||
|
||||
MainNetServer.SendMessage(outgoingMessage,cons , NetDeliveryMethod.ReliableOrdered, 0);
|
||||
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))
|
||||
@ -690,6 +719,7 @@ namespace RageCoop.Server
|
||||
_worker.QueueJob(() => API.Events.InvokePlayerUpdate(client));
|
||||
}
|
||||
|
||||
if (Settings.UseP2P) { return; }
|
||||
foreach (var c in ClientsByNetHandle.Values)
|
||||
{
|
||||
|
||||
@ -718,6 +748,9 @@ namespace RageCoop.Server
|
||||
{
|
||||
_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; }
|
||||
@ -742,6 +775,7 @@ namespace RageCoop.Server
|
||||
private void ProjectileSync(Packets.ProjectileSync packet, Client client)
|
||||
{
|
||||
|
||||
if (Settings.UseP2P) { return; }
|
||||
foreach (var c in ClientsByNetHandle.Values)
|
||||
{
|
||||
if (c.NetHandle==client.NetHandle) { continue; }
|
||||
|
@ -84,5 +84,10 @@
|
||||
/// List of all allowed username characters
|
||||
/// </summary>
|
||||
public string AllowedUsernameChars { get; set; } = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-_";
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use direct connection between players to send entity information
|
||||
/// </summary>
|
||||
public bool UseP2P { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user