using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using GTA; using GTA.Native; using GTA.Math; using RageCoop.Core; using RageCoop.Core.Scripting; using RageCoop.Server.Scripting; namespace RageCoop.Server { /// /// Server-side object controller /// public abstract class ServerObject { /// /// Server that this object belongs to /// internal readonly Server Server; internal ServerObject(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(GetTypeByte(), BitConverter.GetBytes(ID)); } } private byte GetTypeByte() { switch (this) { case ServerProp _: return 50; case ServerPed _: return 51; case ServerVehicle _: return 52; default: throw new NotImplementedException(); } } /// /// The client that owns this object, null if it's owned by server. /// public Client Owner { get; internal set; } /// /// 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 virtual Vector3 Position { get { return _pos; } set { _pos=value; Owner.SendNativeCall(Hash.SET_ENTITY_COORDS_NO_OFFSET, Handle, value.X, value.Y, value.Z,1, 1,1 ); } } internal Vector3 _pos; /// /// Gets or sets this object's rotation /// public virtual Vector3 Rotation { get { return _rot; } set { _rot=value; Owner.SendNativeCall(Hash.SET_ENTITY_ROTATION, Handle, value.X, value.Y, value.Z ,2,1); } } internal Vector3 _rot; /// /// Send updated information to clients, would be called automatically. /// /// /// Delete this object /// public virtual void Delete() { Owner?.SendCustomEventQueued(CustomEvents.DeleteEntity, Handle); } /// /// Freeze this object, will throw an exception if it's a ServerProp. /// /// /// public virtual void Freeze(bool toggle) { if (GetTypeByte()==50) { throw new InvalidOperationException("Can't freeze or unfreeze static server object"); } else { Owner.SendNativeCall(Hash.FREEZE_ENTITY_POSITION, Handle, toggle); } } } /// /// Represents an prop owned by server. /// public class ServerProp : ServerObject { internal ServerProp(Server server) : base(server) { } /// /// Delete this prop /// public override void Delete() { Server.API.SendCustomEventQueued(null,CustomEvents.DeleteServerProp,ID); Server.API.Entities.RemoveProp(ID); } /// /// Gets or sets this object's position /// public override Vector3 Position { get { return _pos; } set { _pos=value; Server.API.SendNativeCall(null, Hash.SET_ENTITY_COORDS_NO_OFFSET, Handle, value.X, value.Y, value.Z, 1, 1, 1); } } /// /// Gets or sets this object's rotation /// public override Vector3 Rotation { get { return _rot; } set { _rot=value; Server.API.SendNativeCall(null, Hash.SET_ENTITY_ROTATION, Handle, value.X, value.Y, value.Z, 2, 1); } } /// /// Send updated information to clients, would be called automatically. /// internal void Update() { Server.API.Server.BaseScript.SendServerPropsTo(new() { this }); } } /// /// Represents a ped from a client /// public class ServerPed : ServerObject { internal ServerPed(Server server) : base(server) { } /// /// Get the ped's last vehicle /// public ServerVehicle LastVehicle { get; internal set; } /// /// Get the attached to this ped. /// public PedBlip AttachedBlip { get; internal set; } /// /// Attach a blip to this ped. /// /// public PedBlip AddBlip() { AttachedBlip = new PedBlip(this); AttachedBlip.Update(); return AttachedBlip; } /// /// Health /// public int Health { get; internal set; } } /// /// Represents a vehicle from a client /// public class ServerVehicle : ServerObject { internal ServerVehicle(Server server) : base(server) { } /// /// Gets or sets vehicle rotation /// public override Vector3 Rotation { get { return _quat.ToEulerAngles().ToDegree(); } set { Owner.SendNativeCall(Hash.SET_ENTITY_ROTATION, Handle ,value.X, value.Y ,value.Z); } } internal Quaternion _quat; /// /// Get this vehicle's quaternion /// public Quaternion Quaternion { get { return _quat; } set { _quat = value ;Owner.SendNativeCall(Hash.SET_ENTITY_QUATERNION, Handle, value.X, value.Y, value.Z, value.W); } } } /// /// A static blip owned by server. /// public class ServerBlip { private readonly Server Server; internal ServerBlip(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(60, BitConverter.GetBytes(ID)); } } /// /// Network ID (not handle!) /// public int ID { get; internal set; } internal BlipColor _color; /// /// Color of this blip /// public BlipColor Color { get { return _color; } set { _color=value; Update(); } } internal BlipSprite _sprite=BlipSprite.Standard; /// /// Sprite of this blip /// public BlipSprite Sprite { get { return _sprite; } set { _sprite=value; Update();} } internal float _scale =1; /// /// Scale of this blip /// public float Scale { get { return _scale; } set { _scale=value;Update(); } } internal Vector3 _pos = new(); /// /// Position of this blip /// public Vector3 Position { get { return _pos; } set { _pos=value; Update(); } } internal int _rot; /// /// Rotation of this blip /// public int Rotation { get { return _rot; } set { _rot=value; Update(); } } internal string _name="Beeeeeee"; /// /// Name of this blip /// public string Name { get { return _name;} set { _name=value; Update(); } } /// /// Delete this blip /// public void Delete() { Server.API.SendCustomEventQueued(null, CustomEvents.DeleteServerBlip,ID); Server.Entities.RemoveServerBlip(ID); } private bool _bouncing=false; internal void Update() { // 5ms debounce if (!_bouncing) { _bouncing=true; Task.Run(() => { Thread.Sleep(5); DoUpdate(); _bouncing=false; }); } } private void DoUpdate() { // Server.Logger?.Debug("bee"); // Serve-side blip Server.BaseScript.SendServerBlipsTo(new() { this }); } } /// /// Represent a blip attached to ped. /// public class PedBlip { /// /// Get the that this blip attached to. /// public ServerPed Ped { get;internal set; } internal PedBlip(ServerPed ped) { Ped = ped; } internal BlipColor _color; /// /// Color of this blip /// public BlipColor Color { get { return _color; } set { _color=value; Update(); } } internal BlipSprite _sprite=BlipSprite.Standard; /// /// Sprite of this blip /// public BlipSprite Sprite { get { return _sprite; } set { _sprite=value; Update(); } } internal float _scale = 1; /// /// Scale of this blip /// public float Scale { get { return _scale; } set { _scale=value; Update(); } } private bool _bouncing = false; internal void Update() { // 5ms debounce if (!_bouncing) { _bouncing=true; Task.Run(() => { Thread.Sleep(5); DoUpdate(); _bouncing=false; }); } } private void DoUpdate() { Ped.Owner.SendCustomEventQueued(CustomEvents.UpdatePedBlip,Ped.Handle,(byte)Color,(ushort)Sprite,Scale); } } }