From ca364bb51a8cef99ec4f17b94ff191ce546b261d Mon Sep 17 00:00:00 2001
From: k0 <21180271+k073l@users.noreply.github.com>
Date: Mon, 19 May 2025 21:05:47 +0200
Subject: [PATCH 1/5] feat: simple vehicle spawning
---
S1API/Vehicles/LandVehicle.cs | 177 +++++++++++++++++++++++++++++++++
S1API/Vehicles/VehicleColor.cs | 26 +++++
2 files changed, 203 insertions(+)
create mode 100644 S1API/Vehicles/LandVehicle.cs
create mode 100644 S1API/Vehicles/VehicleColor.cs
diff --git a/S1API/Vehicles/LandVehicle.cs b/S1API/Vehicles/LandVehicle.cs
new file mode 100644
index 00000000..941d4a3f
--- /dev/null
+++ b/S1API/Vehicles/LandVehicle.cs
@@ -0,0 +1,177 @@
+#if (IL2CPPMELON)
+using S1Vehicles = Il2CppScheduleOne.Vehicles;
+using Il2CppScheduleOne.DevUtilities;
+using Il2Cpp;
+using Il2CppFishNet;
+using Il2CppFishNet.Connection;
+#elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX)
+using S1Vehicles = ScheduleOne.Vehicles;
+using ScheduleOne.DevUtilities;
+using FishNet;
+using FishNet.Connection;
+#endif
+using System.Reflection;
+using UnityEngine;
+using S1API.Logging;
+
+namespace S1API.Vehicles
+{
+ ///
+ /// Represents a land vehicle in the game.
+ ///
+ public class LandVehicle
+ {
+ ///
+ /// Logger for the LandVehicle class.
+ ///
+ private static readonly Log Logger = new Log("S1API.LandVehicle");
+
+ ///
+ /// INTERNAL: The stored reference to the land vehicle in-game (see ).
+ ///
+ internal S1Vehicles.LandVehicle S1LandVehicle = null!;
+
+ ///
+ /// 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;
+
+ ///
+ /// Creates a new LandVehicle instance.
+ ///
+ public LandVehicle(string vehicleCode)
+ {
+ var vehiclePrefab = NetworkSingleton.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());
+ NetworkSingleton.Instance.AllVehicles.Add(component);
+
+ S1LandVehicle = component;
+ _setConnection();
+ }
+
+ ///
+ /// 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();
+ }
+
+ ///
+ /// 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;
+ }
+ }
+
+ ///
+ /// 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);
+ }
+
+ ///
+ /// 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)
+ NetworkSingleton.Instance.PlayerOwnedVehicles.Add(S1LandVehicle);
+ else
+ NetworkSingleton.Instance.PlayerOwnedVehicles.Remove(S1LandVehicle);
+ }
+
+ ///
+ /// Vehicle's color.
+ ///
+ public VehicleColor Color
+ {
+ get => (VehicleColor)S1LandVehicle.OwnedColor;
+ set => _setColor(value);
+ }
+
+ ///
+ /// 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]);
+ }
+
+ ///
+ /// Spawns the vehicle in the game world.
+ ///
+ /// Position in the world
+ /// Rotation of the vehicle
+ public void Spawn(Vector3 position, Quaternion rotation)
+ {
+ S1LandVehicle.transform.position = position;
+ S1LandVehicle.transform.rotation = rotation;
+ NetworkSingleton.Instance.Spawn(S1LandVehicle.gameObject);
+ }
+ }
+}
\ 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
From 000b93dc302ac00ab955e74d4e01df6fec64c627 Mon Sep 17 00:00:00 2001
From: k0 <21180271+k073l@users.noreply.github.com>
Date: Mon, 19 May 2025 21:15:53 +0200
Subject: [PATCH 2/5] fix: don't spawn if not host
---
S1API/Vehicles/LandVehicle.cs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/S1API/Vehicles/LandVehicle.cs b/S1API/Vehicles/LandVehicle.cs
index 941d4a3f..f46a2e12 100644
--- a/S1API/Vehicles/LandVehicle.cs
+++ b/S1API/Vehicles/LandVehicle.cs
@@ -169,6 +169,12 @@ private void _setColor(VehicleColor color)
/// 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;
+ }
+
S1LandVehicle.transform.position = position;
S1LandVehicle.transform.rotation = rotation;
NetworkSingleton.Instance.Spawn(S1LandVehicle.gameObject);
From d804cb3d51576b8f50811fceadc3dfff0f22d4f2 Mon Sep 17 00:00:00 2001
From: k0 <21180271+k073l@users.noreply.github.com>
Date: Tue, 20 May 2025 14:44:49 +0200
Subject: [PATCH 3/5] reorder fields and methods, rename private members
---
S1API/Vehicles/LandVehicle.cs | 175 ++++++++++++++++++----------------
1 file changed, 94 insertions(+), 81 deletions(-)
diff --git a/S1API/Vehicles/LandVehicle.cs b/S1API/Vehicles/LandVehicle.cs
index f46a2e12..e8447ba3 100644
--- a/S1API/Vehicles/LandVehicle.cs
+++ b/S1API/Vehicles/LandVehicle.cs
@@ -21,48 +21,93 @@ namespace S1API.Vehicles
///
public class LandVehicle
{
+ // Public members intended to be used by modders
+ #region Public Members
///
- /// Logger for the LandVehicle class.
+ /// Creates a new LandVehicle instance.
///
- private static readonly Log Logger = new Log("S1API.LandVehicle");
+ public LandVehicle(string vehicleCode)
+ {
+ var vehiclePrefab = NetworkSingleton.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());
+ NetworkSingleton.Instance.AllVehicles.Add(component);
+
+ S1LandVehicle = component;
+ SetConnection();
+ }
///
- /// INTERNAL: The stored reference to the land vehicle in-game (see ).
+ /// Vehicle price.
///
- internal S1Vehicles.LandVehicle S1LandVehicle = null!;
+ public float VehiclePrice
+ {
+ get => S1LandVehicle.VehiclePrice;
+ set => VehiclePriceField?.SetValue(S1LandVehicle, value);
+ }
///
- /// The stored reference to protected vehiclePrice field in the land vehicle in-game.
+ /// Vehicle's top speed.
///
- private static readonly FieldInfo? VehiclePriceField =
- typeof(S1Vehicles.LandVehicle).GetField("vehiclePrice", BindingFlags.NonPublic);
+ public float TopSpeed
+ {
+ get => S1LandVehicle.TopSpeed;
+ set => S1LandVehicle.TopSpeed = value;
+ }
///
- /// Connection to the player that owns the vehicle.
+ /// If the vehicle is owned by the player.
///
- private NetworkConnection? _conn;
+ public bool IsPlayerOwned
+ {
+ get => S1LandVehicle.IsPlayerOwned;
+ set => SetIsPlayerOwned(value);
+ }
///
- /// Creates a new LandVehicle instance.
+ /// Vehicle's color.
///
- public LandVehicle(string vehicleCode)
+ public VehicleColor Color
{
- var vehiclePrefab = NetworkSingleton.Instance.GetVehiclePrefab(vehicleCode);
- if (vehiclePrefab == null)
+ 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.Error($"SpawnVehicle: '{vehicleCode}' is not a valid vehicle code!");
+ _logger.Warning("Spawn can only be called on the server!");
return;
}
- var component = UnityEngine.Object.Instantiate(vehiclePrefab.gameObject)
- .GetComponent();
-
- component.SetGUID(GUIDManager.GenerateUniqueGUID());
- NetworkSingleton.Instance.AllVehicles.Add(component);
-
- S1LandVehicle = component;
- _setConnection();
+ S1LandVehicle.transform.position = position;
+ S1LandVehicle.transform.rotation = rotation;
+ NetworkSingleton.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.
@@ -71,13 +116,34 @@ public LandVehicle(string vehicleCode)
internal LandVehicle(S1Vehicles.LandVehicle landVehicle)
{
S1LandVehicle = landVehicle;
- _setConnection();
+ 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()
+ private void SetConnection()
{
var nm = InstanceFinder.NetworkManager;
if (nm.IsClientOnly)
@@ -94,38 +160,11 @@ private void _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);
- }
-
///
/// Helper method to set the vehicle as player owned.
///
/// If true, sets vehicle as player owned
- private void _setIsPlayerOwned(bool isPlayerOwned)
+ private void SetIsPlayerOwned(bool isPlayerOwned)
{
S1LandVehicle.SetIsPlayerOwned(_conn, isPlayerOwned);
// make sure to add/remove the vehicle from the player owned vehicles list
@@ -135,49 +174,23 @@ private void _setIsPlayerOwned(bool isPlayerOwned)
NetworkSingleton.Instance.PlayerOwnedVehicles.Remove(S1LandVehicle);
}
- ///
- /// Vehicle's color.
- ///
- public VehicleColor Color
- {
- get => (VehicleColor)S1LandVehicle.OwnedColor;
- set => _setColor(value);
- }
-
///
/// Helper method to set the vehicle color.
///
/// Vehicle's color
- private void _setColor(VehicleColor 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!");
+ _logger.Error("SetOwnedColor method not found!");
return;
}
setOwnedColorMethod.Invoke(S1LandVehicle, [_conn, (S1Vehicles.Modification.EVehicleColor)color]);
}
-
- ///
- /// 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;
- }
-
- S1LandVehicle.transform.position = position;
- S1LandVehicle.transform.rotation = rotation;
- NetworkSingleton.Instance.Spawn(S1LandVehicle.gameObject);
- }
+ #endregion
}
}
\ No newline at end of file
From a84dffbee797cbac54e067d94c050825284113b5 Mon Sep 17 00:00:00 2001
From: k0 <21180271+k073l@users.noreply.github.com>
Date: Tue, 20 May 2025 14:48:44 +0200
Subject: [PATCH 4/5] throw exception if user tries to spawn null vehicle
---
S1API/Vehicles/LandVehicle.cs | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/S1API/Vehicles/LandVehicle.cs b/S1API/Vehicles/LandVehicle.cs
index e8447ba3..55475536 100644
--- a/S1API/Vehicles/LandVehicle.cs
+++ b/S1API/Vehicles/LandVehicle.cs
@@ -10,6 +10,7 @@
using FishNet;
using FishNet.Connection;
#endif
+using System;
using System.Reflection;
using UnityEngine;
using S1API.Logging;
@@ -94,6 +95,9 @@ public void Spawn(Vector3 position, Quaternion rotation)
return;
}
+ if (S1LandVehicle == null)
+ throw new Exception("Unable to spawn vehicle, S1LandVehicle is null!");
+
S1LandVehicle.transform.position = position;
S1LandVehicle.transform.rotation = rotation;
NetworkSingleton.Instance.Spawn(S1LandVehicle.gameObject);
From 1c91ed9776f3726b1d284cb0b205db028174a350 Mon Sep 17 00:00:00 2001
From: k0 <21180271+k073l@users.noreply.github.com>
Date: Tue, 20 May 2025 18:57:33 +0200
Subject: [PATCH 5/5] removed NetworkSingleton generics
---
S1API/Vehicles/LandVehicle.cs | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/S1API/Vehicles/LandVehicle.cs b/S1API/Vehicles/LandVehicle.cs
index 55475536..3f91bdd7 100644
--- a/S1API/Vehicles/LandVehicle.cs
+++ b/S1API/Vehicles/LandVehicle.cs
@@ -1,12 +1,10 @@
#if (IL2CPPMELON)
using S1Vehicles = Il2CppScheduleOne.Vehicles;
-using Il2CppScheduleOne.DevUtilities;
using Il2Cpp;
using Il2CppFishNet;
using Il2CppFishNet.Connection;
#elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX)
using S1Vehicles = ScheduleOne.Vehicles;
-using ScheduleOne.DevUtilities;
using FishNet;
using FishNet.Connection;
#endif
@@ -29,7 +27,7 @@ public class LandVehicle
///
public LandVehicle(string vehicleCode)
{
- var vehiclePrefab = NetworkSingleton.Instance.GetVehiclePrefab(vehicleCode);
+ var vehiclePrefab = S1Vehicles.VehicleManager.Instance.GetVehiclePrefab(vehicleCode);
if (vehiclePrefab == null)
{
_logger.Error($"SpawnVehicle: '{vehicleCode}' is not a valid vehicle code!");
@@ -40,7 +38,7 @@ public LandVehicle(string vehicleCode)
.GetComponent();
component.SetGUID(GUIDManager.GenerateUniqueGUID());
- NetworkSingleton.Instance.AllVehicles.Add(component);
+ S1Vehicles.VehicleManager.Instance.AllVehicles.Add(component);
S1LandVehicle = component;
SetConnection();
@@ -100,7 +98,7 @@ public void Spawn(Vector3 position, Quaternion rotation)
S1LandVehicle.transform.position = position;
S1LandVehicle.transform.rotation = rotation;
- NetworkSingleton.Instance.Spawn(S1LandVehicle.gameObject);
+ S1Vehicles.VehicleManager.Instance.Spawn(S1LandVehicle.gameObject);
}
#endregion
@@ -173,9 +171,9 @@ private void SetIsPlayerOwned(bool isPlayerOwned)
S1LandVehicle.SetIsPlayerOwned(_conn, isPlayerOwned);
// make sure to add/remove the vehicle from the player owned vehicles list
if (isPlayerOwned)
- NetworkSingleton.Instance.PlayerOwnedVehicles.Add(S1LandVehicle);
+ S1Vehicles.VehicleManager.Instance.PlayerOwnedVehicles.Add(S1LandVehicle);
else
- NetworkSingleton.Instance.PlayerOwnedVehicles.Remove(S1LandVehicle);
+ S1Vehicles.VehicleManager.Instance.PlayerOwnedVehicles.Remove(S1LandVehicle);
}
///