diff --git a/S1API/Vehicles/LandVehicle.cs b/S1API/Vehicles/LandVehicle.cs new file mode 100644 index 00000000..3f91bdd7 --- /dev/null +++ b/S1API/Vehicles/LandVehicle.cs @@ -0,0 +1,198 @@ +#if (IL2CPPMELON) +using S1Vehicles = Il2CppScheduleOne.Vehicles; +using Il2Cpp; +using Il2CppFishNet; +using Il2CppFishNet.Connection; +#elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) +using S1Vehicles = ScheduleOne.Vehicles; +using FishNet; +using FishNet.Connection; +#endif +using System; +using System.Reflection; +using UnityEngine; +using S1API.Logging; + +namespace S1API.Vehicles +{ + /// + /// Represents a land vehicle in the game. + /// + public class LandVehicle + { + // Public members intended to be used by modders + #region Public Members + /// + /// Creates a new LandVehicle instance. + /// + public LandVehicle(string vehicleCode) + { + var vehiclePrefab = S1Vehicles.VehicleManager.Instance.GetVehiclePrefab(vehicleCode); + if (vehiclePrefab == null) + { + _logger.Error($"SpawnVehicle: '{vehicleCode}' is not a valid vehicle code!"); + return; + } + + var component = UnityEngine.Object.Instantiate(vehiclePrefab.gameObject) + .GetComponent(); + + component.SetGUID(GUIDManager.GenerateUniqueGUID()); + S1Vehicles.VehicleManager.Instance.AllVehicles.Add(component); + + S1LandVehicle = component; + SetConnection(); + } + + /// + /// Vehicle price. + /// + public float VehiclePrice + { + get => S1LandVehicle.VehiclePrice; + set => VehiclePriceField?.SetValue(S1LandVehicle, value); + } + + /// + /// Vehicle's top speed. + /// + public float TopSpeed + { + get => S1LandVehicle.TopSpeed; + set => S1LandVehicle.TopSpeed = value; + } + + /// + /// If the vehicle is owned by the player. + /// + public bool IsPlayerOwned + { + get => S1LandVehicle.IsPlayerOwned; + set => SetIsPlayerOwned(value); + } + + /// + /// Vehicle's color. + /// + public VehicleColor Color + { + get => (VehicleColor)S1LandVehicle.OwnedColor; + set => SetColor(value); + } + + /// + /// Spawns the vehicle in the game world. + /// + /// Position in the world + /// Rotation of the vehicle + public void Spawn(Vector3 position, Quaternion rotation) + { + if (!InstanceFinder.IsServer) + { + _logger.Warning("Spawn can only be called on the server!"); + return; + } + + if (S1LandVehicle == null) + throw new Exception("Unable to spawn vehicle, S1LandVehicle is null!"); + + S1LandVehicle.transform.position = position; + S1LandVehicle.transform.rotation = rotation; + S1Vehicles.VehicleManager.Instance.Spawn(S1LandVehicle.gameObject); + } + + #endregion + + // Internal members used by S1API + #region Internal Members + + /// + /// INTERNAL: The stored reference to the land vehicle in-game (see ). + /// + internal S1Vehicles.LandVehicle S1LandVehicle = null!; + + /// + /// INTERNAL: Creates a LandVehicle instance from an in-game land vehicle instance. + /// + /// The in-game land vehicle instance. + internal LandVehicle(S1Vehicles.LandVehicle landVehicle) + { + S1LandVehicle = landVehicle; + SetConnection(); + } + + #endregion + + // Private members used by LandVehicle class + #region Private Members + + /// + /// Logger for the LandVehicle class. + /// + private static readonly Log _logger = new Log("S1API.LandVehicle"); + + /// + /// The stored reference to protected vehiclePrice field in the land vehicle in-game. + /// + private static readonly FieldInfo? VehiclePriceField = + typeof(S1Vehicles.LandVehicle).GetField("vehiclePrice", BindingFlags.NonPublic); + + /// + /// Connection to the player that owns the vehicle. + /// + private NetworkConnection? _conn; + + /// + /// Sets the connection to the player that owns the vehicle. + /// + private void SetConnection() + { + var nm = InstanceFinder.NetworkManager; + if (nm.IsClientOnly) + { + var tempConn = InstanceFinder.ClientManager.Connection; + if (tempConn != null && tempConn.IsValid) + _conn = tempConn; + } + else if (nm.IsServerOnly || (nm.IsServer && !nm.IsClient)) + { + var owner = S1LandVehicle.Owner; + if (owner != null && owner.IsValid) + _conn = owner; + } + } + + /// + /// Helper method to set the vehicle as player owned. + /// + /// If true, sets vehicle as player owned + private void SetIsPlayerOwned(bool isPlayerOwned) + { + S1LandVehicle.SetIsPlayerOwned(_conn, isPlayerOwned); + // make sure to add/remove the vehicle from the player owned vehicles list + if (isPlayerOwned) + S1Vehicles.VehicleManager.Instance.PlayerOwnedVehicles.Add(S1LandVehicle); + else + S1Vehicles.VehicleManager.Instance.PlayerOwnedVehicles.Remove(S1LandVehicle); + } + + /// + /// Helper method to set the vehicle color. + /// + /// Vehicle's color + private void SetColor(VehicleColor color) + { + var setOwnedColorMethod = + typeof(S1Vehicles.LandVehicle).GetMethod("SetOwnedColor", + BindingFlags.Instance | BindingFlags.NonPublic); + if (setOwnedColorMethod == null) + { + _logger.Error("SetOwnedColor method not found!"); + return; + } + + setOwnedColorMethod.Invoke(S1LandVehicle, [_conn, (S1Vehicles.Modification.EVehicleColor)color]); + } + #endregion + } +} \ No newline at end of file diff --git a/S1API/Vehicles/VehicleColor.cs b/S1API/Vehicles/VehicleColor.cs new file mode 100644 index 00000000..4694d3a5 --- /dev/null +++ b/S1API/Vehicles/VehicleColor.cs @@ -0,0 +1,26 @@ +namespace S1API.Vehicles +{ + /// + /// Represents available colors for vehicles. + /// + public enum VehicleColor + { + Black, + DarkGrey, + LightGrey, + White, + Yellow, + Orange, + Red, + DullRed, + Pink, + Purple, + Navy, + DarkBlue, + LightBlue, + Cyan, + LightGreen, + DarkGreen, + Custom + } +} \ No newline at end of file