using System; using System.Collections.Generic; 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 { /// /// Represents an prop owned by server. /// public class ServerProp { private Server Server; internal ServerProp(Server server) { Server= server; } /// /// Pass this as an argument in CustomEvent or NativeCall to convert this object to handle at client side. /// public Tuple Handle { get { return new(50, BitConverter.GetBytes(ID)); } } /// /// Delete this prop /// public void Delete() { Server.API.SendCustomEvent(CustomEvents.DeleteServerProp, new() { ID }); } /// /// Network ID of this object. /// public int ID { get; internal set; } /// /// The object's model /// public Model Model { get; internal set; } /// /// Gets or sets this object's position /// public Vector3 Position { get { return _pos; } set { _pos=value; Server.BaseScript.SendServerObjectsTo(new() { this }); } } private Vector3 _pos; /// /// Gets or sets this object's rotation /// public Vector3 Rotation { get { return _rot; } set { _rot=value; Server.BaseScript.SendServerObjectsTo(new() { this }); } } private Vector3 _rot; } /// /// Represents a ped from a client /// public class ServerPed { internal ServerPed() { } /// /// Pass this as an argument in CustomEvent or NativeCall to convert this object to handle at client side. /// public Tuple Handle { get { return new(51, BitConverter.GetBytes(ID)); } } /// /// The that is responsible synchronizing for this ped. /// public Client Owner { get; internal set; } /// /// The ped's network ID (not handle!). /// public int ID { get; internal set; } /// /// Whether this ped is a player. /// public bool IsPlayer { get { return Owner?.Player==this; } } /// /// The ped's last vehicle. /// public ServerVehicle LastVehicle { get; internal set; } /// /// Position of this ped /// public Vector3 Position { get; internal set; } /// /// Gets or sets this ped's rotation /// public Vector3 Rotation { get; internal set; } /// /// Health /// public int Health { get; internal set; } } /// /// Represents a vehicle from a client /// public class ServerVehicle { internal ServerVehicle() { } /// /// Pass this as an argument in CustomEvent or NativeCall to convert this object to handle at client side. /// public Tuple Handle { get{ return new(52, BitConverter.GetBytes(ID)); } } /// /// The that is responsible synchronizing for this vehicle. /// public Client Owner { get; internal set; } /// /// The vehicle's network ID (not handle!). /// public int ID { get; internal set; } /// /// Position of this vehicle /// public Vector3 Position { get; internal set; } /// /// Gets or sets this vehicle's quaternion /// public Quaternion Quaternion { get; internal set; } } /// /// Manipulate entities from the server /// public class ServerEntities { private readonly Server Server; internal ServerEntities(Server server) { Server = server; } internal Dictionary Peds { get; set; } = new(); internal Dictionary Vehicles { get; set; } = new(); internal Dictionary ServerProps { get; set; }=new(); /// /// Get a by it's id /// /// /// public ServerPed GetPedByID(int id) { if(Peds.TryGetValue(id,out var ped)) { return ped; } else { return null; } } /// /// Get a by it's id /// /// /// public ServerVehicle GetVehicleByID(int id) { if (Vehicles.TryGetValue(id, out var veh)) { return veh; } else { return null; } } /// /// Get a owned by server from it's ID. /// /// /// public ServerProp GetPropByID(int id) { if (ServerProps.TryGetValue(id, out var obj)) { return obj; } else { return null; } } /// /// Create a static prop owned by server. /// /// /// /// /// 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; } /// /// Get all peds on this server /// /// public ServerPed[] GetAllPeds() { return Peds.Values.ToArray(); } /// /// Get all vehicles on this server /// /// public ServerVehicle[] GetAllVehicle() { return Vehicles.Values.ToArray(); } /// /// Get all static objects owned by server /// /// public ServerProp[] GetAllProps() { return ServerProps.Values.ToArray(); } /// /// Not thread safe /// internal void Update(Packets.PedSync p,Client sender) { ServerPed ped; if(!Peds.TryGetValue(p.ID,out ped)) { Peds.Add(p.ID,ped=new ServerPed()); ped.ID=p.ID; } ped.Position = p.Position; ped.Owner=sender; ped.Health=p.Health; ped.Rotation=p.Rotation; ped.Owner=sender; } internal void Update(Packets.VehicleSync p, Client sender) { ServerVehicle veh; if (!Vehicles.TryGetValue(p.ID, out veh)) { Vehicles.Add(p.ID, veh=new ServerVehicle()); veh.ID=p.ID; } veh.Position = p.Position; veh.Owner=sender; veh.Quaternion=p.Quaternion; } internal void Update(Packets.VehicleStateSync p, Client sender) { ServerVehicle veh; if (!Vehicles.TryGetValue(p.ID, out veh)) { Vehicles.Add(p.ID, veh=new ServerVehicle()); veh.ID=p.ID; } foreach(var pair in p.Passengers) { if(Peds.TryGetValue(pair.Value,out var ped)) { ped.LastVehicle=veh; } } } internal void CleanUp(Client left) { Server.Logger?.Trace("Removing all entities from: "+left.Username); foreach (var pair in Peds) { if (pair.Value.Owner==left) { Server.QueueJob(()=>Peds.Remove(pair.Key)); } } foreach (var pair in Vehicles) { if (pair.Value.Owner==left) { Server.QueueJob(() => Vehicles.Remove(pair.Key)); } } Server.QueueJob(() => Server.Logger?.Trace("Remaining entities: "+(Peds.Count+Vehicles.Count+ServerProps.Count))); } internal void RemoveVehicle(int id) { // Server.Logger?.Trace($"Removing vehicle:{id}"); if (Vehicles.ContainsKey(id)) { Vehicles.Remove(id); } } internal void RemovePed(int id) { // Server.Logger?.Trace($"Removing ped:{id}"); if (Peds.ContainsKey(id)) { Peds.Remove(id); } } internal void Add(ServerPed ped) { if (Peds.ContainsKey(ped.ID)) { Peds[ped.ID]=ped; } else { 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; } } }