Server side prop control
This commit is contained in:
@ -65,7 +65,6 @@ namespace RageCoop.Client
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_gameLoaded)
|
||||
{
|
||||
GTA.UI.Notification.Show("~r~Please update your GTA5 to v1.0.1290 or newer!", true);
|
||||
|
@ -10,7 +10,6 @@ namespace RageCoop.Client
|
||||
{
|
||||
static DownloadManager()
|
||||
{
|
||||
|
||||
Networking.RequestHandlers.Add(PacketType.FileTransferRequest, (data) =>
|
||||
{
|
||||
var fr = new Packets.FileTransferRequest();
|
||||
@ -40,7 +39,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
try
|
||||
{
|
||||
Main.Resources.Load(DownloadFolder);
|
||||
Main.Resources.Load(ResourceFolder);
|
||||
return new Packets.FileTransferResponse() { ID=0, Response=FileResponse.Loaded };
|
||||
}
|
||||
catch(Exception ex)
|
||||
@ -52,7 +51,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
});
|
||||
}
|
||||
public static string DownloadFolder {
|
||||
public static string ResourceFolder {
|
||||
get {
|
||||
return Path.Combine(Main.Settings.DataDirectory,"Resources", Main.Settings.LastServerAddress.Replace(":", "."));
|
||||
}
|
||||
@ -60,13 +59,13 @@ namespace RageCoop.Client
|
||||
private static readonly Dictionary<int, DownloadFile> InProgressDownloads = new Dictionary<int, DownloadFile>();
|
||||
public static bool AddFile(int id, string name, long length)
|
||||
{
|
||||
Main.Logger.Debug($"Downloading file to {DownloadFolder}\\{name} , id:{id}");
|
||||
if (!Directory.Exists(DownloadFolder))
|
||||
Main.Logger.Debug($"Downloading file to {ResourceFolder}\\{name} , id:{id}");
|
||||
if (!Directory.Exists(ResourceFolder))
|
||||
{
|
||||
Directory.CreateDirectory(DownloadFolder);
|
||||
Directory.CreateDirectory(ResourceFolder);
|
||||
}
|
||||
|
||||
if (FileAlreadyExists(DownloadFolder, name, length))
|
||||
if (FileAlreadyExists(ResourceFolder, name, length))
|
||||
{
|
||||
Main.Logger.Debug($"File already exists! canceling download:{name}");
|
||||
return false;
|
||||
@ -84,7 +83,7 @@ namespace RageCoop.Client
|
||||
FileID = id,
|
||||
FileName = name,
|
||||
FileLength = length,
|
||||
Stream = new FileStream($"{DownloadFolder}\\{name}", FileMode.CreateNew, FileAccess.Write, FileShare.ReadWrite)
|
||||
Stream = new FileStream($"{ResourceFolder}\\{name}", FileMode.CreateNew, FileAccess.Write, FileShare.ReadWrite)
|
||||
});
|
||||
}
|
||||
return true;
|
||||
@ -159,6 +158,10 @@ namespace RageCoop.Client
|
||||
}
|
||||
InProgressDownloads.Clear();
|
||||
}
|
||||
foreach (var zip in Directory.GetDirectories(ResourceFolder, "*.zip"))
|
||||
{
|
||||
File.Delete(zip);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ namespace RageCoop.Client
|
||||
|
||||
public static void LoadAll()
|
||||
{
|
||||
string downloadFolder = DownloadManager.DownloadFolder;
|
||||
string downloadFolder = DownloadManager.ResourceFolder;
|
||||
|
||||
if (!Directory.Exists(downloadFolder))
|
||||
{
|
||||
|
@ -3,6 +3,7 @@ using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -69,10 +70,12 @@ namespace RageCoop.Client
|
||||
EntityPool.AddPlayer();
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
DownloadManager.Cleanup();
|
||||
Client = new NetClient(config);
|
||||
Client.Start();
|
||||
Main.QueueAction(() => { GTA.UI.Notification.Show($"~y~Trying to connect..."); });
|
||||
DownloadManager.Cleanup();
|
||||
Security.Regen();
|
||||
GetServerPublicKey(address);
|
||||
|
||||
@ -90,6 +93,11 @@ namespace RageCoop.Client
|
||||
handshake.Pack(outgoingMessage);
|
||||
Client.Connect(ip[0], short.Parse(ip[1]), outgoingMessage);
|
||||
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Main.Logger.Error("Cannot connect to server", ex);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
@ -328,7 +328,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
EntityPool.ThreadSafe.Add(v=new SyncedVehicle(packet.ID));
|
||||
}
|
||||
if (v.IsMine) { return; }
|
||||
if (v.IsLocal) { return; }
|
||||
v.ID= packet.ID;
|
||||
v.Position=packet.Position;
|
||||
v.Quaternion=packet.Quaternion;
|
||||
@ -343,7 +343,7 @@ namespace RageCoop.Client
|
||||
private static void VehicleStateSync(Packets.VehicleStateSync packet)
|
||||
{
|
||||
SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID);
|
||||
if (v==null||v.IsMine) { return; }
|
||||
if (v==null||v.IsLocal) { return; }
|
||||
v.ID= packet.ID;
|
||||
v.OwnerID= packet.OwnerID;
|
||||
v.DamageModel=packet.DamageModel;
|
||||
|
@ -1,7 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GTA.Native;
|
||||
using GTA.Math;
|
||||
using GTA;
|
||||
using RageCoop.Core;
|
||||
using RageCoop.Core.Scripting;
|
||||
using System.Linq;
|
||||
|
||||
namespace RageCoop.Client.Scripting
|
||||
{
|
||||
@ -11,6 +15,8 @@ namespace RageCoop.Client.Scripting
|
||||
{
|
||||
API.RegisterCustomEventHandler(CustomEvents.SetAutoRespawn,SetAutoRespawn);
|
||||
API.RegisterCustomEventHandler(CustomEvents.NativeCall,NativeCall);
|
||||
API.RegisterCustomEventHandler(CustomEvents.ServerPropSync, ServerObjectSync);
|
||||
API.RegisterCustomEventHandler(CustomEvents.DeleteServerProp, DeleteServerProp);
|
||||
API.Events.OnPedDeleted+=(s,p) => { API.SendCustomEvent(CustomEvents.OnPedDeleted,p.ID); };
|
||||
API.Events.OnVehicleDeleted+=(s, p) => { API.SendCustomEvent(CustomEvents.OnVehicleDeleted, p.ID); };
|
||||
|
||||
@ -23,6 +29,29 @@ namespace RageCoop.Client.Scripting
|
||||
{
|
||||
API.Config.EnableAutoRespawn=(bool)args.Args[0];
|
||||
}
|
||||
private void DeleteServerProp(CustomEventReceivedArgs e)
|
||||
{
|
||||
var id = (int)e.Args[0];
|
||||
if (EntityPool.ServerProps.TryGetValue(id, out var prop))
|
||||
{
|
||||
EntityPool.ServerProps.Remove(id);
|
||||
API.QueueAction(() => { prop?.MainProp?.Delete(); });
|
||||
}
|
||||
}
|
||||
private void ServerObjectSync(CustomEventReceivedArgs e)
|
||||
{
|
||||
SyncedProp prop;
|
||||
var id = (int)e.Args[0];
|
||||
if (!EntityPool.ServerProps.TryGetValue(id,out prop))
|
||||
{
|
||||
EntityPool.ServerProps.Add(id,prop=new SyncedProp(id));
|
||||
}
|
||||
prop.LastSynced=Main.Ticked+1;
|
||||
prop.ModelHash= (Model)e.Args[1];
|
||||
prop.Position=(Vector3)e.Args[2];
|
||||
prop.Rotation=(Vector3)e.Args[3];
|
||||
Main.Logger.Trace($"{Main.Ticked},{(VehicleHash)prop.ModelHash},{prop.Position},{prop.Rotation}");
|
||||
}
|
||||
private void NativeCall(CustomEventReceivedArgs e)
|
||||
{
|
||||
List<InputArgument> arguments = new List<InputArgument>();
|
||||
|
@ -149,6 +149,7 @@ namespace RageCoop.Client.Scripting
|
||||
}
|
||||
}
|
||||
LoadedResources.Add(r);
|
||||
file.Close();
|
||||
}
|
||||
private bool LoadScriptsFromAssembly(ResourceFile file, string path, ClientResource resource, bool shadowCopy = true)
|
||||
{
|
||||
|
@ -17,13 +17,14 @@ namespace RageCoop.Client
|
||||
/// <summary>
|
||||
/// Indicates whether the current player is responsible for syncing this entity.
|
||||
/// </summary>
|
||||
public bool IsMine
|
||||
public bool IsLocal
|
||||
{
|
||||
get
|
||||
{
|
||||
return OwnerID==Main.LocalPlayerID;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Network ID for this entity
|
||||
/// </summary>
|
||||
@ -39,13 +40,14 @@ namespace RageCoop.Client
|
||||
{
|
||||
get
|
||||
{
|
||||
return Main.Ticked-LastSynced>200;
|
||||
return Main.Ticked-LastSynced>200 && ID!=0;
|
||||
}
|
||||
}
|
||||
internal bool IsReady
|
||||
{
|
||||
get {return !(LastSynced==0||LastStateSynced==0);}
|
||||
get {return (LastSynced>0||LastStateSynced==0);}
|
||||
}
|
||||
internal bool IsInvincible { get; set; } = false;
|
||||
internal bool NeedUpdate
|
||||
{
|
||||
get { return LastSynced>LastUpdated; }
|
||||
@ -65,6 +67,12 @@ namespace RageCoop.Client
|
||||
public ulong LastUpdated { get; set; } = 0;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal protected bool _lastFrozen=false;
|
||||
internal bool IsFrozen { get; set; } = false;
|
||||
internal int ModelHash { get; set; }
|
||||
internal Vector3 Position { get; set; }
|
||||
internal Vector3 Rotation { get; set; }
|
||||
internal Quaternion Quaternion { get; set; }
|
||||
|
@ -68,10 +68,6 @@ namespace RageCoop.Client
|
||||
private bool _lastRagdoll=false;
|
||||
private ulong _lastRagdollTime=0;
|
||||
private bool _lastInCover = false;
|
||||
internal int ModelHash
|
||||
{
|
||||
get;set;
|
||||
}
|
||||
private byte[] _lastClothes = null;
|
||||
internal byte[] Clothes { get; set; }
|
||||
|
||||
@ -284,6 +280,7 @@ namespace RageCoop.Client
|
||||
|
||||
MainPed.IsInvincible=true;
|
||||
}
|
||||
if (IsInvincible) { MainPed.IsInvincible=true; }
|
||||
|
||||
// Add to EntityPool so this Character can be accessed by handle.
|
||||
EntityPool.Add(this);
|
||||
@ -325,6 +322,11 @@ namespace RageCoop.Client
|
||||
|
||||
private void DisplayOnFoot()
|
||||
{
|
||||
if (IsFrozen != _lastFrozen)
|
||||
{
|
||||
MainPed.SetFrozen(IsFrozen);
|
||||
_lastFrozen=IsFrozen;
|
||||
}
|
||||
if (IsInParachuteFreeFall)
|
||||
{
|
||||
MainPed.PositionNoOffset = Vector3.Lerp(MainPed.Position, Position + Velocity, 0.5f);
|
||||
|
@ -37,7 +37,7 @@ namespace RageCoop.Client
|
||||
IsValid=false;
|
||||
}
|
||||
ShooterID=shooter.ID;
|
||||
IsMine=shooter.IsMine;
|
||||
IsMine=shooter.IsLocal;
|
||||
}
|
||||
|
||||
}
|
||||
|
44
RageCoop.Client/Sync/Entities/SyncedProp.cs
Normal file
44
RageCoop.Client/Sync/Entities/SyncedProp.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA.Native;
|
||||
using GTA;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Synchronized prop, mostly owned by server
|
||||
/// </summary>
|
||||
public class SyncedProp : SyncedEntity
|
||||
{
|
||||
internal SyncedProp(int id)
|
||||
{
|
||||
ID= id;
|
||||
}
|
||||
/// <summary>
|
||||
/// The real entity
|
||||
/// </summary>
|
||||
public Prop MainProp { get; set; }
|
||||
internal new int OwnerID { get
|
||||
{
|
||||
// alwayse owned by server
|
||||
return 0;
|
||||
} }
|
||||
internal override void Update()
|
||||
{
|
||||
|
||||
if (!NeedUpdate) { return; }
|
||||
if (MainProp== null || !MainProp.Exists())
|
||||
{
|
||||
MainProp=World.CreateProp(ModelHash,Position,Rotation,false,false);
|
||||
MainProp.IsInvincible=true;
|
||||
}
|
||||
MainProp.Position=Position;
|
||||
MainProp.Rotation=Rotation;
|
||||
MainProp.SetFrozen(true);
|
||||
LastUpdated=Main.Ticked;
|
||||
}
|
||||
}
|
||||
}
|
@ -89,7 +89,6 @@ namespace RageCoop.Client
|
||||
internal VehicleRoofState RoofState { get; set; }
|
||||
internal bool SireneActive { get; set; }
|
||||
internal VehicleDamageModel DamageModel { get; set; }
|
||||
internal int ModelHash { get; set; }
|
||||
internal byte[] Colors { get; set; }
|
||||
internal Dictionary<int, int> Mods { get; set; }
|
||||
internal bool IsDead { get; set; }
|
||||
@ -133,7 +132,12 @@ namespace RageCoop.Client
|
||||
{
|
||||
MainVehicle.BrakePower=BrakePower;
|
||||
}
|
||||
if (MainVehicle.Position.DistanceTo(Position)<5)
|
||||
if (IsFrozen != _lastFrozen)
|
||||
{
|
||||
MainVehicle.SetFrozen(IsFrozen);
|
||||
_lastFrozen=IsFrozen;
|
||||
}
|
||||
else if (MainVehicle.Position.DistanceTo(Position)<5)
|
||||
{
|
||||
MainVehicle.Velocity = Velocity+5*(Position+Velocity*SyncParameters.PositioinPredictionDefault - MainVehicle.Position);
|
||||
if (IsFlipped)
|
||||
@ -378,6 +382,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
MainVehicle.RoofState=RoofState;
|
||||
}
|
||||
if (IsInvincible) { MainVehicle.IsInvincible=true; }
|
||||
vehicleModel.MarkAsNoLongerNeeded();
|
||||
}
|
||||
#region -- PEDALING --
|
||||
|
@ -37,6 +37,8 @@ namespace RageCoop.Client
|
||||
private static Dictionary<int, SyncedProjectile> ID_Projectiles = new Dictionary<int, SyncedProjectile>();
|
||||
private static Dictionary<int, SyncedProjectile> Handle_Projectiles = new Dictionary<int, SyncedProjectile>();
|
||||
|
||||
public static object PropsLock=new object();
|
||||
public static Dictionary<int,SyncedProp> ServerProps=new Dictionary<int,SyncedProp>();
|
||||
|
||||
public static void Cleanup(bool keepPlayer=true,bool keepMine=true)
|
||||
{
|
||||
@ -66,6 +68,12 @@ namespace RageCoop.Client
|
||||
}
|
||||
ID_Projectiles.Clear();
|
||||
Handle_Projectiles.Clear();
|
||||
|
||||
foreach(var p in ServerProps.Values)
|
||||
{
|
||||
p?.MainProp?.Delete();
|
||||
}
|
||||
ServerProps.Clear();
|
||||
}
|
||||
|
||||
#region PEDS
|
||||
@ -139,7 +147,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
Handle_Peds.Add(c.MainPed.Handle, c);
|
||||
}
|
||||
if (c.IsMine)
|
||||
if (c.IsLocal)
|
||||
{
|
||||
API.Events.InvokePedSpawned(c);
|
||||
}
|
||||
@ -165,7 +173,7 @@ namespace RageCoop.Client
|
||||
c.PedBlip?.Delete();
|
||||
c.ParachuteProp?.Delete();
|
||||
ID_Peds.Remove(id);
|
||||
if (c.IsMine)
|
||||
if (c.IsLocal)
|
||||
{
|
||||
API.Events.InvokePedDeleted(c);
|
||||
}
|
||||
@ -205,7 +213,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
Handle_Vehicles.Add(v.MainVehicle.Handle, v);
|
||||
}
|
||||
if (v.IsMine)
|
||||
if (v.IsLocal)
|
||||
{
|
||||
API.Events.InvokeVehicleSpawned(v);
|
||||
}
|
||||
@ -228,7 +236,7 @@ namespace RageCoop.Client
|
||||
veh.Delete();
|
||||
}
|
||||
ID_Vehicles.Remove(id);
|
||||
if (v.IsMine) { API.Events.InvokeVehicleDeleted(v); }
|
||||
if (v.IsLocal) { API.Events.InvokeVehicleDeleted(v); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -417,7 +425,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
|
||||
// Outgoing sync
|
||||
if (c.IsMine)
|
||||
if (c.IsLocal)
|
||||
{
|
||||
#if BENCHMARK
|
||||
var start = PerfCounter2.ElapsedTicks;
|
||||
@ -495,7 +503,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
|
||||
// Outgoing sync
|
||||
if (v.IsMine)
|
||||
if (v.IsLocal)
|
||||
{
|
||||
SyncEvents.Check(v);
|
||||
|
||||
@ -521,6 +529,14 @@ namespace RageCoop.Client
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
lock (PropsLock)
|
||||
{
|
||||
foreach (var p in ServerProps.Values)
|
||||
{
|
||||
p.Update();
|
||||
}
|
||||
}
|
||||
#if BENCHMARK
|
||||
Debug.TimeStamps[TimeStamp.VehicleTotal]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
|
@ -174,6 +174,10 @@ namespace RageCoop.Client
|
||||
Function.Call(Hash.STOP_ENTITY_FIRE, e.Handle);
|
||||
}
|
||||
}
|
||||
public static void SetFrozen(this Entity e,bool toggle)
|
||||
{
|
||||
Function.Call(Hash.FREEZE_ENTITY_POSITION, e, toggle);
|
||||
}
|
||||
|
||||
public static SyncedPed GetSyncEntity(this Ped p)
|
||||
{
|
||||
|
@ -111,7 +111,7 @@ namespace RageCoop.Client
|
||||
foreach (Ped ped in World.GetAllPeds())
|
||||
{
|
||||
SyncedPed c = EntityPool.GetPedByHandle(ped.Handle);
|
||||
if ((c==null) || (c.IsMine && (ped.Handle!=Game.Player.Character.Handle)&&ped.PopulationType!=EntityPopulationType.Mission))
|
||||
if ((c==null) || (c.IsLocal && (ped.Handle!=Game.Player.Character.Handle)&&ped.PopulationType!=EntityPopulationType.Mission))
|
||||
{
|
||||
if (ped.Handle==Game.Player.Character.Handle) { continue; }
|
||||
|
||||
@ -131,7 +131,7 @@ namespace RageCoop.Client
|
||||
// Don't delete player's vehicle
|
||||
continue;
|
||||
}
|
||||
if((v== null) || (v.IsMine&&veh.PopulationType!=EntityPopulationType.Mission))
|
||||
if((v== null) || (v.IsLocal&&veh.PopulationType!=EntityPopulationType.Mission))
|
||||
{
|
||||
Main.Logger.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic");
|
||||
|
||||
|
@ -39,7 +39,16 @@ namespace RageCoop.Core
|
||||
case bool _:
|
||||
return (0x09, BitConverter.GetBytes((bool)obj));
|
||||
case string _:
|
||||
return (0x10, (obj as string).GetBytesWithLength());
|
||||
return (0x10, ((string)obj).GetBytesWithLength());
|
||||
case Vector3 _:
|
||||
return (0x11,((Vector3)obj).GetBytes());
|
||||
case Quaternion _:
|
||||
return (0x12, ((Quaternion)obj).GetBytes());
|
||||
case GTA.Model _:
|
||||
return (0x13, BitConverter.GetBytes((GTA.Model)obj));
|
||||
case Tuple<byte, byte[]> _:
|
||||
var tup = (Tuple<byte, byte[]>)obj;
|
||||
return (tup.Item1, tup.Item2);
|
||||
default:
|
||||
return (0x0, null);
|
||||
}
|
||||
@ -115,7 +124,21 @@ namespace RageCoop.Core
|
||||
{
|
||||
return Encoding.UTF8.GetString(data);
|
||||
}
|
||||
|
||||
public static byte[] GetBytes(this Vector3 vec)
|
||||
{
|
||||
// 12 bytes
|
||||
return new List<byte[]>() { BitConverter.GetBytes(vec.X), BitConverter.GetBytes(vec.Y), BitConverter.GetBytes(vec.Z) }.Join(4);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="qua"></param>
|
||||
/// <returns>An array of bytes with length 16</returns>
|
||||
public static byte[] GetBytes(this Quaternion qua)
|
||||
{
|
||||
// 16 bytes
|
||||
return new List<byte[]>() { BitConverter.GetBytes(qua.X), BitConverter.GetBytes(qua.Y), BitConverter.GetBytes(qua.Z), BitConverter.GetBytes(qua.W) }.Join(4);
|
||||
}
|
||||
|
||||
public static bool HasPedFlag(this PedDataFlags flagToCheck, PedDataFlags flag)
|
||||
{
|
||||
@ -223,10 +246,10 @@ namespace RageCoop.Core
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
public static byte[] Join(this List<byte[]> arrays)
|
||||
public static byte[] Join(this List<byte[]> arrays,int lengthPerArray=-1)
|
||||
{
|
||||
if (arrays.Count==1) { return arrays[0]; }
|
||||
var output = new byte[arrays.Sum(arr => arr.Length)];
|
||||
var output = lengthPerArray== -1 ? new byte[arrays.Sum(arr => arr.Length)] : new byte[arrays.Count*lengthPerArray];
|
||||
int writeIdx = 0;
|
||||
foreach (var byteArr in arrays)
|
||||
{
|
||||
|
@ -121,16 +121,35 @@ namespace RageCoop.Core
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="error"></param>
|
||||
public void Error(string message, Exception error)
|
||||
{
|
||||
if (LogLevel>4) { return; }
|
||||
lock (Buffer)
|
||||
{
|
||||
string msg = string.Format("[{0}][{2}] [ERR] {1}:{3}", Date(), message, Name,error.Message);
|
||||
Buffer+=msg+"\r\n";
|
||||
Trace(error.ToString());
|
||||
|
||||
}
|
||||
if (FlushImmediately)
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="ex"></param>
|
||||
public void Error(Exception ex)
|
||||
{
|
||||
if (LogLevel>4) { return; }
|
||||
lock (Buffer)
|
||||
{
|
||||
string msg = string.Format("[{0}][{2}] [ERR] {1}", Date(), "\r\n"+ex.ToString(), Name);
|
||||
// msg += string.Format("\r\n[{0}][{2}] [ERR] {1}", Date(), "\r\n"+ex.StackTrace, Process.GetCurrentProcess().Id);
|
||||
|
||||
string msg = string.Format("[{0}][{2}] [ERR] {1}", Date(), "\r\n"+ex.Message, Name);
|
||||
Buffer+=msg+"\r\n";
|
||||
Trace(ex.ToString());
|
||||
}
|
||||
if (FlushImmediately)
|
||||
{
|
||||
|
@ -49,35 +49,31 @@ namespace RageCoop.Core
|
||||
switch (type)
|
||||
{
|
||||
case 0x01:
|
||||
Args.Add(reader.ReadByte());
|
||||
break;
|
||||
Args.Add(reader.ReadByte()); break;
|
||||
case 0x02:
|
||||
Args.Add(reader.ReadShort());
|
||||
break;
|
||||
Args.Add(reader.ReadShort()); break;
|
||||
case 0x03:
|
||||
Args.Add(reader.ReadUShort());
|
||||
break;
|
||||
Args.Add(reader.ReadUShort()); break;
|
||||
case 0x04:
|
||||
Args.Add(reader.ReadInt());
|
||||
break;
|
||||
Args.Add(reader.ReadInt()); break;
|
||||
case 0x05:
|
||||
Args.Add(reader.ReadUInt());
|
||||
break;
|
||||
Args.Add(reader.ReadUInt()); break;
|
||||
case 0x06:
|
||||
Args.Add(reader.ReadLong());
|
||||
break;
|
||||
Args.Add(reader.ReadLong()); break;
|
||||
case 0x07:
|
||||
Args.Add(reader.ReadULong());
|
||||
break;
|
||||
Args.Add(reader.ReadULong()); break;
|
||||
case 0x08:
|
||||
Args.Add(reader.ReadFloat());
|
||||
break;
|
||||
Args.Add(reader.ReadFloat()); break;
|
||||
case 0x09:
|
||||
Args.Add(reader.ReadBool());
|
||||
break;
|
||||
Args.Add(reader.ReadBool()); break;
|
||||
case 0x10:
|
||||
Args.Add(reader.ReadString());
|
||||
break;
|
||||
Args.Add(reader.ReadString()); break;
|
||||
case 0x11:
|
||||
Args.Add(reader.ReadVector3()); break;
|
||||
case 0x12:
|
||||
Args.Add(reader.ReadQuaternion()); break;
|
||||
case 0x13:
|
||||
Args.Add((GTA.Model)reader.ReadInt()); break;
|
||||
default:
|
||||
throw new InvalidOperationException($"Unexpected type:{type}\r\n{array.Dump()}");
|
||||
|
||||
|
@ -19,6 +19,9 @@ namespace RageCoop.Core.Scripting
|
||||
internal static readonly int NativeCall = Hash("RageCoop.NativeCall");
|
||||
internal static readonly int NativeResponse = Hash("RageCoop.NativeResponse");
|
||||
internal static readonly int AllResourcesSent = Hash("RageCoop.AllResourcesSent");
|
||||
internal static readonly int ServerPropSync = Hash("RageCoop.ServerPropSync");
|
||||
internal static readonly int DeleteServerProp = Hash("RageCoop.DeleteServerProp");
|
||||
|
||||
/// <summary>
|
||||
/// Get a Int32 hash of a string.
|
||||
/// </summary>
|
||||
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using RageCoop.Core.Scripting;
|
||||
using RageCoop.Core;
|
||||
|
||||
namespace RageCoop.Server.Scripting
|
||||
{
|
||||
@ -28,6 +29,13 @@ namespace RageCoop.Server.Scripting
|
||||
{
|
||||
c.SendCustomEvent(CustomEvents.SetAutoRespawn, toggle );
|
||||
}
|
||||
public void SendServerObjectsTo(List<ServerProp> objects,List<Client> clients=null)
|
||||
{
|
||||
foreach(var obj in objects)
|
||||
{
|
||||
API.SendCustomEvent(CustomEvents.ServerPropSync, new() { obj.ID, obj.Model ,obj.Position,obj.Rotation },clients);
|
||||
}
|
||||
}
|
||||
void NativeResponse(CustomEventReceivedArgs e)
|
||||
{
|
||||
try
|
||||
|
@ -637,6 +637,10 @@ namespace RageCoop.Server
|
||||
}.Pack(outgoingMessage);
|
||||
MainNetServer.SendMessage(outgoingMessage, newClient.Connection, NetDeliveryMethod.ReliableOrdered, 0);
|
||||
});
|
||||
|
||||
// Send all props to this player
|
||||
BaseScript.SendServerObjectsTo( new(Entities.ServerProps.Values), new() { newClient});
|
||||
|
||||
// Send new client to all players
|
||||
var cons = MainNetServer.Connections.Exclude(newClient.Connection);
|
||||
if (cons.Count!=0)
|
||||
|
@ -4,12 +4,62 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using RageCoop.Core;
|
||||
using RageCoop.Core.Scripting;
|
||||
using System.Security.Cryptography;
|
||||
using GTA.Math;
|
||||
using GTA;
|
||||
|
||||
namespace RageCoop.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an prop owned by server.
|
||||
/// </summary>
|
||||
public class ServerProp
|
||||
{
|
||||
private Server Server;
|
||||
internal ServerProp(Server server)
|
||||
{
|
||||
Server= server;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete this prop
|
||||
/// </summary>
|
||||
public void Delete()
|
||||
{
|
||||
Server.API.SendCustomEvent(CustomEvents.DeleteServerProp, new() { ID });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Network ID of this object.
|
||||
/// </summary>
|
||||
public int ID { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The object's model
|
||||
/// </summary>
|
||||
public Model Model { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets this object's position
|
||||
/// </summary>
|
||||
public Vector3 Position
|
||||
{
|
||||
get { return _pos; }
|
||||
set { _pos=value; Server.BaseScript.SendServerObjectsTo(new() { this }); }
|
||||
}
|
||||
private Vector3 _pos;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets this object's rotation
|
||||
/// </summary>
|
||||
public Vector3 Rotation
|
||||
{
|
||||
get { return _rot; }
|
||||
set { _rot=value; Server.BaseScript.SendServerObjectsTo(new() { this }); }
|
||||
}
|
||||
private Vector3 _rot;
|
||||
}
|
||||
/// <summary>
|
||||
/// Represents a ped from a client
|
||||
/// </summary>
|
||||
@ -77,36 +127,6 @@ namespace RageCoop.Server
|
||||
public Quaternion Quaternion { get; internal set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an object owned by server.
|
||||
/// </summary>
|
||||
public class ServerObject
|
||||
{
|
||||
internal ServerObject()
|
||||
{
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// The object's model
|
||||
/// </summary>
|
||||
public Model Model { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets this object's position
|
||||
/// </summary>
|
||||
public Vector3 Position { get;set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets this object's quaternion
|
||||
/// </summary>
|
||||
public Quaternion Quaternion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this object is invincible
|
||||
/// </summary>
|
||||
public bool IsInvincible { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manipulate entities from the server
|
||||
/// </summary>
|
||||
@ -119,7 +139,78 @@ namespace RageCoop.Server
|
||||
}
|
||||
internal Dictionary<int, ServerPed> Peds { get; set; } = new();
|
||||
internal Dictionary<int, ServerVehicle> Vehicles { get; set; } = new();
|
||||
internal Dictionary<int,ServerObject> ServerObjects { get; set; }=new();
|
||||
internal Dictionary<int,ServerProp> ServerProps { get; set; }=new();
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="ServerPed"/> by it's id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public ServerPed GetPedByID(int id)
|
||||
{
|
||||
if(Peds.TryGetValue(id,out var ped))
|
||||
{
|
||||
return ped;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="ServerVehicle"/> by it's id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public ServerVehicle GetVehicleByID(int id)
|
||||
{
|
||||
if (Vehicles.TryGetValue(id, out var veh))
|
||||
{
|
||||
return veh;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="ServerProp"/> owned by server from it's ID.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public ServerProp GetPropByID(int id)
|
||||
{
|
||||
if (ServerProps.TryGetValue(id, out var obj))
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Create a static prop owned by server.
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <param name="pos"></param>
|
||||
/// <param name="rot"></param>
|
||||
/// <returns></returns>
|
||||
public ServerProp CreateProp(Model model,Vector3 pos,Vector3 rot)
|
||||
{
|
||||
int id = RequestID();
|
||||
ServerProp prop;
|
||||
ServerProps.Add(id,prop=new ServerProp(Server)
|
||||
{
|
||||
ID=id,
|
||||
Model=model,
|
||||
Position=pos,
|
||||
Rotation=rot
|
||||
});
|
||||
return prop;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all peds on this server
|
||||
@ -143,9 +234,9 @@ namespace RageCoop.Server
|
||||
/// Get all static objects owned by server
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ServerObject[] GetAllObjects()
|
||||
public ServerProp[] GetAllObjects()
|
||||
{
|
||||
return ServerObjects.Values.ToArray();
|
||||
return ServerProps.Values.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -212,7 +303,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
}
|
||||
Server.QueueJob(() =>
|
||||
Server.Logger?.Trace("Remaining entities: "+(Peds.Count+Vehicles.Count)));
|
||||
Server.Logger?.Trace("Remaining entities: "+(Peds.Count+Vehicles.Count+ServerProps.Count)));
|
||||
}
|
||||
internal void RemoveVehicle(int id)
|
||||
{
|
||||
@ -236,5 +327,22 @@ namespace RageCoop.Server
|
||||
Peds.Add(ped.ID, ped);
|
||||
}
|
||||
}
|
||||
internal int RequestID()
|
||||
{
|
||||
int ID = 0;
|
||||
while ((ID==0)
|
||||
|| ServerProps.ContainsKey(ID)
|
||||
|| Peds.ContainsKey(ID)
|
||||
|| Vehicles.ContainsKey(ID))
|
||||
{
|
||||
byte[] rngBytes = new byte[4];
|
||||
|
||||
RandomNumberGenerator.Create().GetBytes(rngBytes);
|
||||
|
||||
// Convert the bytes into an integer
|
||||
ID = BitConverter.ToInt32(rngBytes, 0);
|
||||
}
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user