@@ -1,459 +1,81 @@
using System ;
using GTANetworkAPI ;
using Newtonsoft.Json.Linq ;
using ReallifeGamemode.Server.Types ;
using ReallifeGamemode.Server.Common ;
namespace ReallifeGamemode.Server.Util
{
//Enums for ease of use
public enum WindowID
{
WindowFrontRight ,
WindowFrontLeft ,
WindowRearRight ,
WindowRearLeft
}
public enum WindowState
{
WindowFixed ,
WindowDown ,
WindowBroken
}
public enum DoorID
{
DoorFrontLeft ,
DoorFrontRight ,
DoorRearLeft ,
DoorRearRight ,
DoorHood ,
DoorTrunk
}
public enum DoorState
{
DoorClosed ,
DoorOpen ,
DoorBroken ,
}
public enum WheelID
{
Wheel0 ,
Wheel1 ,
Wheel2 ,
Wheel3 ,
Wheel4 ,
Wheel5 ,
Wheel6 ,
Wheel7 ,
Wheel8 ,
Wheel9
}
public enum WheelState
{
WheelFixed ,
WheelBurst ,
WheelOnRim ,
}
public class VehicleStreaming : Script
{
//This is the data object which will be synced to vehicles
public class VehicleSyncData
private const string DataKey = "VehicleData" ;
public static void SetEngineState ( Vehicle veh , bool state )
{
//Used to bypass some streaming bugs
public Vector3 Position { get ; set ; } = new Vector3 ( ) ;
public Vector3 Rotation { get ; set ; } = new Vector3 ( ) ;
//Basics
public float Dirt { get ; set ; } = 0.0f ;
public bool Locked { get ; set ; } = true ;
public bool Engine { get ; set ; } = false ;
//(Not synced)
//public float BodyHealth { get; set; } = 1000.0f;
//public float EngineHealth { get; set; } = 1000.0f;
//Doors 0-7 (0 = closed, 1 = open, 2 = broken) (This uses enums so don't worry about it)
public int [ ] Door { get ; set ; } = new int [ 8 ] { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
//Windows (0 = up, 1 = down, 2 = smashed) (This uses enums so don't worry about it)
public int [ ] Window { get ; set ; } = new int [ 4 ] { 0 , 0 , 0 , 0 } ;
//Wheels 0-7, 45/47 (0 = fixed, 1 = flat, 2 = missing) (This uses enums so don't worry about it)
public int [ ] Wheel { get ; set ; } = new int [ 10 ] { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
}
//API functions for people to use
public static void SetVehicleWindowState ( Vehicle veh , WindowID window , WindowState state )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) ) //If data doesn't exist create a new one. This is the process for all API functions
data = new VehicleSyncData ( ) ;
data . Window [ ( int ) window ] = ( int ) state ;
UpdateVehicleSyncData ( veh , data ) ;
NAPI . ClientEvent . TriggerClientEventInDimension ( veh . Dimension , "VehStream_SetVehicleWindowStatus_Single" , veh . Handle , ( int ) window , ( int ) state ) ;
}
public static WindowState GetVehicleWindowState ( Vehicle veh , WindowID window )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
{
data = new VehicleSyncData ( ) ;
UpdateVehicleSyncData ( veh , data ) ;
}
return ( WindowState ) data . Window [ ( int ) window ] ;
}
public static void SetVehicleWheelState ( Vehicle veh , WheelID wheel , WheelState state )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
data = new VehicleSyncData ( ) ;
data . Wheel [ ( int ) wheel ] = ( int ) state ;
UpdateVehicleSyncData ( veh , data ) ;
NAPI . ClientEvent . TriggerClientEventInDimension ( veh . Dimension , "VehStream_SetVehicleWheelStatus_Single" , veh . Handle , ( int ) wheel , ( int ) state ) ;
}
public static WheelState GetVehicleWheelState ( Vehicle veh , WheelID wheel )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
{
data = new VehicleSyncData ( ) ;
UpdateVehicleSyncData ( veh , data ) ;
}
return ( WheelState ) data . Wheel [ ( int ) wheel ] ;
}
public static void SetVehicleDirt ( Vehicle veh , float dirt )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
data = new VehicleSyncData ( ) ;
data . Dirt = dirt ;
UpdateVehicleSyncData ( veh , data ) ;
NAPI . ClientEvent . TriggerClientEventInDimension ( veh . Dimension , "VehStream_SetVehicleDirtLevel" , veh . Handle , dirt ) ;
}
public static float GetVehicleDirt ( Vehicle veh )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
{
data = new VehicleSyncData ( ) ;
UpdateVehicleSyncData ( veh , data ) ;
}
return data . Dirt ;
}
public static void SetDoorState ( Vehicle veh , DoorID door , DoorState state )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
data = new VehicleSyncData ( ) ;
data . Door [ ( int ) door ] = ( int ) state ;
UpdateVehicleSyncData ( veh , data ) ;
NAPI . ClientEvent . TriggerClientEventInDimension ( veh . Dimension , "VehStream_SetVehicleDoorStatus_Single" , veh , ( int ) door , ( int ) state ) ;
}
public static DoorState GetDoorState ( Vehicle veh , DoorID door )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
{
data = new VehicleSyncData ( ) ;
UpdateVehicleSyncData ( veh , data ) ;
}
return ( DoorState ) data . Door [ ( int ) door ] ;
}
public static void SetEngineState ( Vehicle veh , bool status )
{
veh . EngineStatus = status ;
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
data = new VehicleSyncData ( ) ;
data . Engine = status ;
UpdateVehicleSyncData ( veh , data ) ;
NAPI . ClientEvent . TriggerClientEventInDimension ( veh . Dimension , "VehStream_SetEngineStatus" , veh , status ) ;
var data = GetData ( veh ) ;
data . EngineState = state ;
SetData ( veh , data ) ;
}
public static bool GetEngineState ( Vehicle veh )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
{
data = new VehicleSyncData ( ) ;
UpdateVehicleSyncData ( veh , data ) ;
}
return veh . EngineStatus ;
return GetData ( veh ) . EngineState ;
}
public static void SetLockStatus ( Vehicle veh , bool status )
public static void SetLockStatus ( Vehicle veh , bool state )
{
VehicleSyncData data = GetVehicleSync Data ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
data = new VehicleSyncData ( ) ;
data . Locked = status ;
UpdateVehicleSyncData ( veh , data ) ;
NAPI . ClientEvent . TriggerClientEventInDimension ( veh . Dimension , "VehStream_SetLockStatus" , veh , status ) ;
NAPI . Pools . GetAllPlayers ( ) . ForEach ( p = >
{
if ( p . IsInVehicle & & p . Vehicle . Handle = = veh . Handle )
{
p . TriggerEvent ( "Vehicle_setLockStatus" , status ) ;
}
} ) ;
var data = GetData ( veh ) ;
data . Locked = state ;
SetData ( veh , data ) ;
}
public static bool GetLockState ( Vehicle veh )
{
VehicleSyncData data = GetVehicleSync Data( veh ) ;
if ( data = = default ( VehicleSyncData ) )
{
data = new VehicleSyncData ( ) ;
UpdateVehicleSyncData ( veh , data ) ;
}
return data . Locked ;
return Get Data( veh ) . Locked ;
}
//Used internally only but publicly available in case any of you need it
public static VehicleSyncData GetVehicleSyncData ( Vehicle veh )
public static void SetDoorState ( Vehicle veh , DoorID door , DoorState state )
{
if ( veh ! = null )
VehicleData data = GetData ( veh ) ;
data . Doors [ ( int ) door ] = ( int ) state ;
SetData ( veh , data ) ;
}
public static DoorState GetDoorState ( Vehicle veh , DoorID door )
{
VehicleData data = GetData ( veh ) ;
if ( ! data . Doors . ContainsKey ( ( int ) door ) )
{
if ( NAPI . Entity . DoesEntityExist ( veh ) )
{
if ( NAPI . Data . HasEntitySharedData ( veh , "VehicleSyncData" ) )
{
try
{
//API converts class objects to JObject so we have to change it back
JObject obj = ( JObject ) NAPI . Data . GetEntitySharedData ( veh , "VehicleSyncData" ) ;
return obj . ToObject < VehicleSyncData > ( ) ;
}
catch ( Exception ) { return null ; }
}
}
return DoorState . DoorClosed ;
}
return default ; //null
return ( DoorState ) data . Doors [ ( int ) door ] ;
}
//Used internally only but publicly available in case any of you need it
public static bool UpdateVehicleSyncData ( Vehicle veh , VehicleSyncData data )
public static VehicleData GetData ( Vehicle veh )
{
if ( veh ! = null )
if ( ! veh . HasSharedData ( DataKey ) )
{
if ( NAPI . Entity . DoesEntityExist ( veh ) )
{
if ( data ! = null )
{
data . Position = veh . Position ;
data . Rotation = veh . Rotation ;
NAPI . Data . SetEntitySharedData ( veh , "VehicleSyncData" , data ) ;
return true ;
}
}
return new VehicleData ( ) ;
}
return false ;
return veh . GetSharedData < string > ( DataKey ) . DeserializeJson < VehicleData > ( ) ;
}
public static void SetVehicleRotation ( Vehicle veh , VehicleSync Data data , Vector3 rot )
public static void SetData ( Vehicle veh , VehicleData data )
{
if ( veh ! = null )
if ( data is null )
{
if ( NAPI . Entity . DoesEntityExist ( veh ) )
{
if ( data ! = null )
{
data . Rotation = rot ;
NAPI . Data . SetEntitySharedData ( veh , "VehicleSyncData" , data ) ;
}
}
throw new ArgumentNullException ( nameof ( data ) ) ;
}
}
//Called from the client to sync dirt level
[RemoteEvent("VehStream_SetDirtLevel")]
public void VehStreamSetDirtLevel ( Player player , Vehicle veh , float dirt )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
data = new VehicleSyncData ( ) ;
var dataStr = data . SerializeJson ( ) ;
d ata. Dirt = dirt ;
UpdateVehicleSyncData ( veh , data ) ;
//Re-distribute the goods
NAPI . ClientEvent . TriggerClientEventInDimension ( veh . Dimension , "VehStream_SetVehicleDirtLevel" , veh . Handle , dirt ) ;
}
//Called from the client to sync door data
[RemoteEvent("VehStream_SetDoorData")]
public void VehStreamSetDoorData ( Player player , Vehicle veh , int door1state , int door2state , int door3state , int door4state , int door5state , int door6state , int door7state , int door8state )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
data = new VehicleSyncData ( ) ;
data . Door [ 0 ] = door1state ;
data . Door [ 1 ] = door2state ;
data . Door [ 2 ] = door3state ;
data . Door [ 3 ] = door4state ;
data . Door [ 4 ] = door5state ;
data . Door [ 5 ] = door6state ;
data . Door [ 6 ] = door7state ;
data . Door [ 7 ] = door8state ;
UpdateVehicleSyncData ( veh , data ) ;
//Re-distribute the goods
NAPI . ClientEvent . TriggerClientEventInDimension ( veh . Dimension , "VehStream_SetVehicleDoorStatus" , veh . Handle , door1state , door2state , door3state , door4state , door5state , door6state , door7state , door8state ) ;
}
//Called from the client to sync window data
[RemoteEvent("VehStream_SetWindowData")]
public void VehStreamSetWindowData ( Player player , Vehicle veh , int window1state , int window2state , int window3state , int window4state )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
data = new VehicleSyncData ( ) ;
data . Window [ 0 ] = window1state ;
data . Window [ 1 ] = window2state ;
data . Window [ 2 ] = window3state ;
data . Window [ 3 ] = window4state ;
UpdateVehicleSyncData ( veh , data ) ;
//Re-distribute the goods
NAPI . ClientEvent . TriggerClientEventInDimension ( veh . Dimension , "VehStream_SetVehicleWindowStatus" , veh . Handle , window1state , window2state , window3state , window4state ) ;
}
//Called from the client to sync wheel data
[RemoteEvent("VehStream_SetWheelData")]
public void VehStreamSetWheelData ( Player player , Vehicle veh , int wheel1state , int wheel2state , int wheel3state , int wheel4state , int wheel5state , int wheel6state , int wheel7state , int wheel8state , int wheel9state , int wheel10state )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
data = new VehicleSyncData ( ) ;
data . Wheel [ 0 ] = wheel1state ;
data . Wheel [ 1 ] = wheel2state ;
data . Wheel [ 2 ] = wheel3state ;
data . Wheel [ 3 ] = wheel4state ;
data . Wheel [ 4 ] = wheel5state ;
data . Wheel [ 5 ] = wheel6state ;
data . Wheel [ 6 ] = wheel7state ;
data . Wheel [ 7 ] = wheel8state ;
data . Wheel [ 8 ] = wheel9state ;
data . Wheel [ 9 ] = wheel10state ;
UpdateVehicleSyncData ( veh , data ) ;
//Re-distribute the goods
NAPI . ClientEvent . TriggerClientEventInDimension ( veh . Dimension , "VehStream_SetVehicleWheelStatus" , veh . Handle , wheel1state , wheel2state , wheel3state , wheel4state , wheel5state , wheel6state , wheel7state , wheel8state , wheel9state , wheel10state ) ;
}
//Other events
[ServerEvent(Event.PlayerEnterVehicleAttempt)]
public void VehStreamEnterAttempt ( Player player , Vehicle veh , sbyte seat )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
data = new VehicleSyncData ( ) ;
UpdateVehicleSyncData ( veh , data ) ;
NAPI . ClientEvent . TriggerClientEvent ( player , "VehStream_PlayerEnterVehicleAttempt" , veh . Handle . Value , seat ) ;
}
[ServerEvent(Event.PlayerExitVehicleAttempt)]
public void VehStreamExitAttempt ( Player player , Vehicle veh )
{
if ( player . HasData ( "isDead" ) & & player . GetData < bool > ( "isDead" ) )
return ;
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
data = new VehicleSyncData ( ) ;
data . Position = veh . Position ;
data . Rotation = veh . Rotation ;
UpdateVehicleSyncData ( veh , data ) ;
NAPI . ClientEvent . TriggerClientEvent ( player , "VehStream_PlayerExitVehicleAttempt" , veh ) ;
}
[ServerEvent(Event.PlayerExitVehicle)]
public void VehStreamExit ( Player player , Vehicle veh )
{
if ( player . HasData ( "isDead" ) & & player . GetData < bool > ( "isDead" ) )
return ;
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
data = new VehicleSyncData ( ) ;
data . Position = veh . Position ;
data . Rotation = veh . Rotation ;
UpdateVehicleSyncData ( veh , data ) ;
NAPI . ClientEvent . TriggerClientEvent ( player , "VehStream_PlayerExitVehicle" , veh . Handle . Value ) ;
}
[ServerEvent(Event.PlayerEnterVehicle)]
public void VehStreamEnter ( Player player , Vehicle veh , sbyte seat )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
data = new VehicleSyncData ( ) ;
UpdateVehicleSyncData ( veh , data ) ;
NAPI . ClientEvent . TriggerClientEvent ( player , "VehStream_PlayerEnterVehicle" , veh , seat ) ;
player . TriggerEvent ( "Vehicle_setLockStatus" , data . Locked ) ;
}
//[ServerEvent(Event.VehicleDamage)]
//public void VehDamage(Vehicle veh, float bodyHealthLoss, float engineHealthLoss)
//{
// VehicleSyncData data = GetVehicleSyncData(veh);
// if (data == default(VehicleSyncData))
// data = new VehicleSyncData();
// data.BodyHealth -= bodyHealthLoss;
// data.EngineHealth -= engineHealthLoss;
// UpdateVehicleSyncData(veh, data);
// if (NAPI.Vehicle.GetVehicleDriver(veh) != default(Player)) //Doesn't work?
// NAPI.ClientEvent.TriggerClientEvent(NAPI.Vehicle.GetVehicleDriver(veh), "VehStream_PlayerExitVehicleAttempt", veh);
//}
[ServerEvent(Event.VehicleDoorBreak)]
public void VehDoorBreak ( Vehicle veh , int index )
{
VehicleSyncData data = GetVehicleSyncData ( veh ) ;
if ( data = = default ( VehicleSyncData ) )
data = new VehicleSyncData ( ) ;
data . Door [ index ] = 2 ;
UpdateVehicleSyncData ( veh , data ) ;
NAPI . ClientEvent . TriggerClientEventInDimension ( veh . Dimension , "VehStream_SetVehicleDoorStatus" , veh . Handle , data . Door [ 0 ] , data . Door [ 1 ] , data . Door [ 2 ] , data . Door [ 3 ] , data . Door [ 4 ] , data . Door [ 5 ] , data . Door [ 6 ] , data . Door [ 7 ] ) ;
veh . SetSharedD ata( DataKey , dataStr ) ;
NAPI . ClientEvent . TriggerClientEventForAll ( "SERVER:Vehicle:UpdateData" , veh . Handle . Value , dataStr ) ;
}
// INDICATORS