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;
namespace RageCoop.Server.Scripting
{
///
/// 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);
}
}
}