From d8180a0f91e0422bd4cedbb8bdd88bc997c53c95 Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Tue, 29 Apr 2025 03:42:18 +0200 Subject: [PATCH 01/28] feat: product quality --- S1API/Products/ProductInstance.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/S1API/Products/ProductInstance.cs b/S1API/Products/ProductInstance.cs index 00e61924..bb8f38ce 100644 --- a/S1API/Products/ProductInstance.cs +++ b/S1API/Products/ProductInstance.cs @@ -4,8 +4,9 @@ using S1Product = ScheduleOne.Product; #endif +using Il2CppScheduleOne.ItemFramework; using S1API.Internal.Utils; -using S1API.Items; +using ItemInstance = S1API.Items.ItemInstance; namespace S1API.Products { @@ -37,5 +38,11 @@ internal ProductInstance(S1Product.ProductItemInstance productInstance) : base(p /// public PackagingDefinition AppliedPackaging => new PackagingDefinition(S1ProductInstance.AppliedPackaging); + /// + /// The quality of this product instance. + /// + public EQuality Quality => S1ProductInstance.Quality; + } + } From adf3cca240d4be5d3177073c81526648d1a2acbb Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Tue, 29 Apr 2025 03:43:28 +0200 Subject: [PATCH 02/28] fix: usings --- S1API/Products/ProductInstance.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/S1API/Products/ProductInstance.cs b/S1API/Products/ProductInstance.cs index bb8f38ce..b4b4f0f8 100644 --- a/S1API/Products/ProductInstance.cs +++ b/S1API/Products/ProductInstance.cs @@ -1,10 +1,12 @@ #if (IL2CPPMELON || IL2CPPBEPINEX) using S1Product = Il2CppScheduleOne.Product; +using Il2CppScheduleOne.ItemFramework; + #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1Product = ScheduleOne.Product; +using ScheduleOne.ItemFramework; #endif -using Il2CppScheduleOne.ItemFramework; using S1API.Internal.Utils; using ItemInstance = S1API.Items.ItemInstance; From 2051d7f8610b96955fec268bd08279ef16ee8bb0 Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Tue, 29 Apr 2025 14:04:16 +0200 Subject: [PATCH 03/28] fix: abstract quality --- S1API/Products/ProductInstance.cs | 3 +- S1API/Products/Quality.cs | 86 +++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 S1API/Products/Quality.cs diff --git a/S1API/Products/ProductInstance.cs b/S1API/Products/ProductInstance.cs index b4b4f0f8..25043ba1 100644 --- a/S1API/Products/ProductInstance.cs +++ b/S1API/Products/ProductInstance.cs @@ -43,7 +43,8 @@ internal ProductInstance(S1Product.ProductItemInstance productInstance) : base(p /// /// The quality of this product instance. /// - public EQuality Quality => S1ProductInstance.Quality; + public Quality Quality => S1ProductInstance.Quality.ToAPI(); + } diff --git a/S1API/Products/Quality.cs b/S1API/Products/Quality.cs new file mode 100644 index 00000000..702923e1 --- /dev/null +++ b/S1API/Products/Quality.cs @@ -0,0 +1,86 @@ +#if IL2CPPBEPINEX || IL2CPPMELON +using InternalQuality = Il2CppScheduleOne.ItemFramework.EQuality; +#else +using InternalQuality = ScheduleOne.ItemFramework.EQuality; +#endif +namespace S1API.Products +{ + /// + /// Represents the quality levels for items. + /// + /// + /// This enumeration defines various quality tiers that items can belong to. Each tier represents a specific + /// standard or grade, ranging from the lowest to the highest. + /// + public enum Quality + { + /// + /// Represents the lowest quality level, indicating an item of no value or unusable condition. + /// + Trash = 0, + + /// + /// Represents a quality level that is below standard but better than trash-quality. + /// + Poor = 1, + + /// + /// Represents a standard level of quality in the predefined quality enumeration. + /// Typically used to indicate an average or commonly acceptable quality level. + /// + Standard = 2, + + /// + /// Represents a higher-tier quality level compared to lower + Premium = 3, + + /// + /// Represents the highest level of quality, denoted as "Heavenly". + Heavenly = 4 + } + + /// + /// Provides extension methods for converting between and + /// enumerations. + /// + internal static class QualityExtensions + { + /// + /// Converts an instance of to its corresponding + /// representation. + /// + /// The instance to convert. + /// A value that represents the converted quality. + internal static Quality ToAPI(this InternalQuality quality) + { + return quality switch + { + InternalQuality.Trash => Quality.Trash, + InternalQuality.Poor => Quality.Poor, + InternalQuality.Standard => Quality.Standard, + InternalQuality.Premium => Quality.Premium, + InternalQuality.Heavenly => Quality.Heavenly, + _ => Quality.Trash, + }; + } + + /// + /// Converts an instance of the enum to its corresponding + /// enum representation. + /// + /// The enum value to convert. + /// The corresponding enum value. + internal static InternalQuality ToInternal(this Quality quality) + { + return quality switch + { + Quality.Trash => InternalQuality.Trash, + Quality.Poor => InternalQuality.Poor, + Quality.Standard => InternalQuality.Standard, + Quality.Premium => InternalQuality.Premium, + Quality.Heavenly => InternalQuality.Heavenly, + _ => InternalQuality.Trash, + }; + } + } +} From f134b624e2f7e34b72fe223c22cac775aa3e449e Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Wed, 30 Apr 2025 00:16:57 +0200 Subject: [PATCH 04/28] feat: get product properties --- S1API/Products/CocaineDefinition.cs | 35 ++++++++++++--- S1API/Products/MethDefinition.cs | 38 +++++++++++++--- S1API/Products/ProductDefinition.cs | 9 +++- S1API/Products/ProductDefinitionWrapper.cs | 15 +++++-- S1API/Products/ProductInstance.cs | 11 ++++- S1API/Products/WeedDefinition.cs | 50 +++++++++++++++++++--- 6 files changed, 132 insertions(+), 26 deletions(-) diff --git a/S1API/Products/CocaineDefinition.cs b/S1API/Products/CocaineDefinition.cs index 04b3b346..a27a2098 100644 --- a/S1API/Products/CocaineDefinition.cs +++ b/S1API/Products/CocaineDefinition.cs @@ -6,34 +6,57 @@ using S1CocaineDefinition = ScheduleOne.Product.CocaineDefinition; #endif +using System.Collections.Generic; using S1API.Internal.Utils; using S1API.Items; namespace S1API.Products { /// - /// Represents the definition of a Cocaine product. + /// Represents the definition of a cocaine product within the system. /// public class CocaineDefinition : ProductDefinition { /// - /// INTERNAL: Strongly typed access to the CocaineDefinition. + /// INTERNAL: Strongly typed access to the CocaineDefinition within the Schedule One framework. /// internal S1CocaineDefinition S1CocaineDefinition => CrossType.As(S1ItemDefinition); /// - /// Creates a new cocaine product definition. + /// Represents the definition of a Cocaine product. /// - /// The original in-game cocaine definition. internal CocaineDefinition(S1CocaineDefinition definition) - : base(definition) { } + : base(definition) + { + } /// - /// Creates an instance of this cocaine product. + /// Creates an instance of this cocaine product with the specified quantity. /// + /// The quantity of the product to create. Defaults to 1. + /// An instance of the cocaine product with the specified quantity. public override ItemInstance CreateInstance(int quantity = 1) => new ProductInstance(CrossType.As( S1CocaineDefinition.GetDefaultInstance(quantity))); + + /// + /// Retrieves a list of properties associated with the current cocaine product definition. + /// + /// A list of properties specific to the cocaine product definition. + public List GetProperties() + { + var result = new List(); + var list = S1CocaineDefinition?.Properties; + if (list != null) + { + for (int i = 0; i < list.Count; i++) + { + result.Add(list[i]); + } + } + return result; + } } + } diff --git a/S1API/Products/MethDefinition.cs b/S1API/Products/MethDefinition.cs index 4d11a0c1..ddd335ea 100644 --- a/S1API/Products/MethDefinition.cs +++ b/S1API/Products/MethDefinition.cs @@ -6,34 +6,60 @@ using S1MethDefinition = ScheduleOne.Product.MethDefinition; #endif +using System.Collections.Generic; using S1API.Internal.Utils; using S1API.Items; namespace S1API.Products { /// - /// Represents the definition of a Meth product. + /// Represents the definition of a Meth product in the product framework. /// + /// + /// Provides methods for retrieving properties and creating instances of meth products. This class extends the base functionality provided by . + /// public class MethDefinition : ProductDefinition { /// - /// INTERNAL: Strongly typed access to the MethDefinition. + /// INTERNAL: Strongly typed access to S1MethDefinition, representing the Il2CppScheduleOne.Product.MethDefinition entity. /// internal S1MethDefinition S1MethDefinition => CrossType.As(S1ItemDefinition); /// - /// Creates a new meth product definition. + /// Represents the definition of a Meth product. /// - /// The original in-game meth definition. internal MethDefinition(S1MethDefinition definition) - : base(definition) { } + : base(definition) + { + } /// - /// Creates an instance of this meth product. + /// Creates an instance of this meth product with a specified quantity. /// + /// The quantity of the meth product to instantiate. Defaults to 1 if not provided. + /// An instance of the meth product as a . public override ItemInstance CreateInstance(int quantity = 1) => new ProductInstance(CrossType.As( S1MethDefinition.GetDefaultInstance(quantity))); + + /// + /// Retrieves the list of properties associated with the meth product definition. + /// + /// A list of properties that belong to the meth product definition. + public List GetProperties() + { + var result = new List(); + var list = S1MethDefinition?.Properties; + if (list != null) + { + for (int i = 0; i < list.Count; i++) + { + result.Add(list[i]); + } + } + + return result; + } } } diff --git a/S1API/Products/ProductDefinition.cs b/S1API/Products/ProductDefinition.cs index 91ea8591..fbda17e1 100644 --- a/S1API/Products/ProductDefinition.cs +++ b/S1API/Products/ProductDefinition.cs @@ -5,6 +5,7 @@ using S1Product = ScheduleOne.Product; #endif +using System.Collections.Generic; using S1API.Internal.Utils; using S1API.Items; using UnityEngine; @@ -26,7 +27,7 @@ public class ProductDefinition : ItemDefinition /// INTERNAL: Creates a product definition from the in-game product definition. /// /// - internal ProductDefinition(S1Product.ProductDefinition productDefinition) : base(productDefinition) { } + internal ProductDefinition(Il2CppScheduleOne.ItemFramework.ItemDefinition productDefinition) : base(productDefinition) { } /// /// The price associated with this product. @@ -50,5 +51,9 @@ public Sprite Icon get { return S1ProductDefinition.Icon; } } - } + private List properties; // or however properties are stored + + // Add this public property if it doesn't exist yet + public IReadOnlyList Properties => properties.AsReadOnly(); +} } diff --git a/S1API/Products/ProductDefinitionWrapper.cs b/S1API/Products/ProductDefinitionWrapper.cs index e6bb70ad..b3078fbd 100644 --- a/S1API/Products/ProductDefinitionWrapper.cs +++ b/S1API/Products/ProductDefinitionWrapper.cs @@ -2,6 +2,7 @@ #if (IL2CPPMELON || IL2CPPBEPINEX) using S1Product = Il2CppScheduleOne.Product; + #else using S1Product = ScheduleOne.Product; #endif @@ -9,19 +10,27 @@ namespace S1API.Products { /// - /// INTERNAL: A wrapper class for converting a product definition to its proper dedicated class. + /// Provides functionality to wrap and convert generic product definitions into their specific type-derived definitions. /// - internal static class ProductDefinitionWrapper + public static class ProductDefinitionWrapper { - internal static ProductDefinition Wrap(ProductDefinition def) + /// + /// Converts a generic into its corresponding typed wrapper. + /// + /// The raw product definition to be processed and converted. + /// A wrapped instance of with type-specific methods and properties, or the input definition if no specific wrapper applies. + public static ProductDefinition Wrap(ProductDefinition def) { var item = def.S1ItemDefinition; if (CrossType.Is(item, out var weed)) return new WeedDefinition(weed); + if (CrossType.Is(item, out var meth)) return new MethDefinition(meth); + if (CrossType.Is(item, out var coke)) return new CocaineDefinition(coke); + return def; } } diff --git a/S1API/Products/ProductInstance.cs b/S1API/Products/ProductInstance.cs index 25043ba1..7b1aa868 100644 --- a/S1API/Products/ProductInstance.cs +++ b/S1API/Products/ProductInstance.cs @@ -7,6 +7,7 @@ using ScheduleOne.ItemFramework; #endif +using System.Collections.Generic; using S1API.Internal.Utils; using ItemInstance = S1API.Items.ItemInstance; @@ -27,7 +28,9 @@ public class ProductInstance : ItemInstance /// INTERNAL: Creates a product instance from the in-game product instance. /// /// - internal ProductInstance(S1Product.ProductItemInstance productInstance) : base(productInstance) { } + internal ProductInstance(S1Product.ProductItemInstance productInstance) : base(productInstance) + { + } /// /// Whether this product is currently packaged or not. @@ -40,12 +43,16 @@ internal ProductInstance(S1Product.ProductItemInstance productInstance) : base(p /// public PackagingDefinition AppliedPackaging => new PackagingDefinition(S1ProductInstance.AppliedPackaging); + /// /// The quality of this product instance. /// public Quality Quality => S1ProductInstance.Quality.ToAPI(); + // Expose the underlying definition's properties (if S1ProductInstance.Definition is available) + public IReadOnlyList Properties => Definition.Properties; + // Add Definition property if you don't have one yet + public ProductDefinition Definition => new ProductDefinition(S1ProductInstance.Definition); } - } diff --git a/S1API/Products/WeedDefinition.cs b/S1API/Products/WeedDefinition.cs index a57f6dfe..0ef7c2d7 100644 --- a/S1API/Products/WeedDefinition.cs +++ b/S1API/Products/WeedDefinition.cs @@ -8,33 +8,69 @@ using S1API.Internal.Utils; using S1API.Items; +using System.Collections.Generic; namespace S1API.Products { /// - /// Represents the definition of a Weed product. + /// Represents a specific type of weed product definition. This class extends the functionality of + /// to include details specific to weed products. /// + /// + /// This class provides methods and properties to work with weed-related product definitions, + /// including creating product instances and accessing weed-specific properties. + /// public class WeedDefinition : ProductDefinition { /// - /// INTERNAL: Strongly typed access to the WeedDefinition. + /// Represents the definition of a weed product in the ScheduleOne API. + /// Provides access to underlying data and functionalities specific to weed products. /// internal S1WeedDefinition S1WeedDefinition => CrossType.As(S1ItemDefinition); - /// - /// Creates a new weed product definition. + /// Represents a specific type of product definition for weed products in the API. /// - /// The original in-game weed definition. + /// + /// This class acts as a wrapper for `Il2CppScheduleOne.Product.WeedDefinition`, + /// providing additional functionality and a specific type for handling weed items. + /// internal WeedDefinition(S1WeedDefinition definition) - : base(definition) { } + : base(definition) + { + } /// - /// Creates an instance of this weed product. + /// Creates an instance of the product with the specified quantity. /// + /// The quantity of the product to create. Defaults to 1 if not specified. + /// An instance of representing the created product. public override ItemInstance CreateInstance(int quantity = 1) => new ProductInstance(CrossType.As( S1WeedDefinition.GetDefaultInstance(quantity))); + + /// + /// Gets a list of properties associated with the current weed definition. + /// + /// + /// A list of properties of type Il2CppScheduleOne.Properties.Property + /// associated with the weed definition. If no properties are found, + /// an empty list is returned. + /// + public List GetProperties() + { + var result = new List(); + var list = S1WeedDefinition?.Properties; + if (list != null) + { + for (int i = 0; i < list.Count; i++) + { + result.Add(list[i]); + } + } + + return result; + } } } From 492a4baeaa8fdd640e6c1b21b9890afb1f3b6b39 Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Wed, 30 Apr 2025 00:24:12 +0200 Subject: [PATCH 05/28] fix: references --- S1API/Products/CocaineDefinition.cs | 8 ++++++++ S1API/Products/MethDefinition.cs | 8 ++++++++ S1API/Products/ProductDefinition.cs | 5 ++++- S1API/Products/WeedDefinition.cs | 8 ++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/S1API/Products/CocaineDefinition.cs b/S1API/Products/CocaineDefinition.cs index a27a2098..43c0543d 100644 --- a/S1API/Products/CocaineDefinition.cs +++ b/S1API/Products/CocaineDefinition.cs @@ -44,9 +44,17 @@ public override ItemInstance CreateInstance(int quantity = 1) => /// Retrieves a list of properties associated with the current cocaine product definition. /// /// A list of properties specific to the cocaine product definition. +#if IL2CPPBEPINEX || IL2CPPMELON public List GetProperties() +#else + public List GetProperties() +#endif { +#if IL2CPPBEPINEX || IL2CPPMELON var result = new List(); +#else + var result = new List(); +#endif var list = S1CocaineDefinition?.Properties; if (list != null) { diff --git a/S1API/Products/MethDefinition.cs b/S1API/Products/MethDefinition.cs index ddd335ea..4635b0c9 100644 --- a/S1API/Products/MethDefinition.cs +++ b/S1API/Products/MethDefinition.cs @@ -47,9 +47,17 @@ public override ItemInstance CreateInstance(int quantity = 1) => /// Retrieves the list of properties associated with the meth product definition. /// /// A list of properties that belong to the meth product definition. +#if IL2CPPBEPINEX || IL2CPPMELON public List GetProperties() +#else + public List GetProperties() +#endif { +#if IL2CPPBEPINEX || IL2CPPMELON var result = new List(); +#else + var result = new List(); +#endif var list = S1MethDefinition?.Properties; if (list != null) { diff --git a/S1API/Products/ProductDefinition.cs b/S1API/Products/ProductDefinition.cs index fbda17e1..78f02545 100644 --- a/S1API/Products/ProductDefinition.cs +++ b/S1API/Products/ProductDefinition.cs @@ -27,8 +27,11 @@ public class ProductDefinition : ItemDefinition /// INTERNAL: Creates a product definition from the in-game product definition. /// /// + #if IL2CPPBEPINEX || IL2CPPMELON internal ProductDefinition(Il2CppScheduleOne.ItemFramework.ItemDefinition productDefinition) : base(productDefinition) { } - +#else + internal ProductDefinition(ScheduleOne.ItemFramework.ItemDefinition productDefinition) : base(productDefinition) { } + #endif /// /// The price associated with this product. /// diff --git a/S1API/Products/WeedDefinition.cs b/S1API/Products/WeedDefinition.cs index 0ef7c2d7..956999e5 100644 --- a/S1API/Products/WeedDefinition.cs +++ b/S1API/Products/WeedDefinition.cs @@ -58,9 +58,17 @@ public override ItemInstance CreateInstance(int quantity = 1) => /// associated with the weed definition. If no properties are found, /// an empty list is returned. /// +#if IL2CPPBEPINEX || IL2CPPMELON public List GetProperties() +#else +public List GetProperties() +#endif { +#if IL2CPPBEPINEX || IL2CPPMELON var result = new List(); +#else + var result = new List(); + #endif var list = S1WeedDefinition?.Properties; if (list != null) { From 0a3c70c0bedc72e74f2a60ae7ee1e0a5ca8f9ccd Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Wed, 30 Apr 2025 00:30:06 +0200 Subject: [PATCH 06/28] more fixes --- S1API/Products/ProductDefinition.cs | 10 +++++++--- S1API/Products/ProductInstance.cs | 10 +++++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/S1API/Products/ProductDefinition.cs b/S1API/Products/ProductDefinition.cs index 78f02545..69ff9b61 100644 --- a/S1API/Products/ProductDefinition.cs +++ b/S1API/Products/ProductDefinition.cs @@ -53,10 +53,14 @@ public Sprite Icon { get { return S1ProductDefinition.Icon; } } +#if IL2CPPBEPINEX || IL2CPPMELON + private List properties; // or however properties are stored + public List Properties; // or however properties are stored +#else + private List properties; // or however properties are stored + public IReadOnlyList Properties => properties.AsReadOnly(); +#endif - private List properties; // or however properties are stored - // Add this public property if it doesn't exist yet - public IReadOnlyList Properties => properties.AsReadOnly(); } } diff --git a/S1API/Products/ProductInstance.cs b/S1API/Products/ProductInstance.cs index 7b1aa868..9a479e34 100644 --- a/S1API/Products/ProductInstance.cs +++ b/S1API/Products/ProductInstance.cs @@ -50,9 +50,17 @@ internal ProductInstance(S1Product.ProductItemInstance productInstance) : base(p public Quality Quality => S1ProductInstance.Quality.ToAPI(); // Expose the underlying definition's properties (if S1ProductInstance.Definition is available) - public IReadOnlyList Properties => Definition.Properties; // Add Definition property if you don't have one yet + +#if IL2CPPBEPINEX || IL2CPPMELON + public IReadOnlyList Properties => Definition.Properties; + public ProductDefinition Definition => new ProductDefinition(S1ProductInstance.Definition); +#else + public IReadOnlyList Properties => Definition.Properties; public ProductDefinition Definition => new ProductDefinition(S1ProductInstance.Definition); + +#endif + } } From 36e845cceca587017a97885389dbd90ae23f8956 Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Sat, 10 May 2025 13:14:21 +0200 Subject: [PATCH 07/28] changes for max --- S1API/Products/ProductDefinition.cs | 4 ++-- S1API/Products/ProductDefinitionWrapper.cs | 6 ++---- S1API/Products/ProductInstance.cs | 1 - S1API/Products/Quality.cs | 15 ++++++++------- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/S1API/Products/ProductDefinition.cs b/S1API/Products/ProductDefinition.cs index 69ff9b61..3abd4efe 100644 --- a/S1API/Products/ProductDefinition.cs +++ b/S1API/Products/ProductDefinition.cs @@ -27,11 +27,11 @@ public class ProductDefinition : ItemDefinition /// INTERNAL: Creates a product definition from the in-game product definition. /// /// - #if IL2CPPBEPINEX || IL2CPPMELON +#if IL2CPPBEPINEX || IL2CPPMELON internal ProductDefinition(Il2CppScheduleOne.ItemFramework.ItemDefinition productDefinition) : base(productDefinition) { } #else internal ProductDefinition(ScheduleOne.ItemFramework.ItemDefinition productDefinition) : base(productDefinition) { } - #endif +#endif /// /// The price associated with this product. /// diff --git a/S1API/Products/ProductDefinitionWrapper.cs b/S1API/Products/ProductDefinitionWrapper.cs index b3078fbd..923744cc 100644 --- a/S1API/Products/ProductDefinitionWrapper.cs +++ b/S1API/Products/ProductDefinitionWrapper.cs @@ -1,9 +1,7 @@ using S1API.Internal.Utils; - -#if (IL2CPPMELON || IL2CPPBEPINEX) +#if (IL2CPPMELON) using S1Product = Il2CppScheduleOne.Product; - -#else +#elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1Product = ScheduleOne.Product; #endif diff --git a/S1API/Products/ProductInstance.cs b/S1API/Products/ProductInstance.cs index 9a479e34..610096c1 100644 --- a/S1API/Products/ProductInstance.cs +++ b/S1API/Products/ProductInstance.cs @@ -1,7 +1,6 @@ #if (IL2CPPMELON || IL2CPPBEPINEX) using S1Product = Il2CppScheduleOne.Product; using Il2CppScheduleOne.ItemFramework; - #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1Product = ScheduleOne.Product; using ScheduleOne.ItemFramework; diff --git a/S1API/Products/Quality.cs b/S1API/Products/Quality.cs index 702923e1..2f21bd24 100644 --- a/S1API/Products/Quality.cs +++ b/S1API/Products/Quality.cs @@ -1,6 +1,6 @@ #if IL2CPPBEPINEX || IL2CPPMELON using InternalQuality = Il2CppScheduleOne.ItemFramework.EQuality; -#else +#elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using InternalQuality = ScheduleOne.ItemFramework.EQuality; #endif namespace S1API.Products @@ -15,27 +15,28 @@ namespace S1API.Products public enum Quality { /// - /// Represents the lowest quality level, indicating an item of no value or unusable condition. + /// Represents "Trash" Quality /// Trash = 0, /// - /// Represents a quality level that is below standard but better than trash-quality. + /// Represents "Poor" Quality /// Poor = 1, /// - /// Represents a standard level of quality in the predefined quality enumeration. - /// Typically used to indicate an average or commonly acceptable quality level. + /// Represents "Standard" Quality /// Standard = 2, /// - /// Represents a higher-tier quality level compared to lower + /// Represents "Premium" quality + /// Premium = 3, /// - /// Represents the highest level of quality, denoted as "Heavenly". + /// Represents "Heavenly" quality + /// Heavenly = 4 } From f0cbcd7b11277bdff1097c8dcc00d86e7c61c540 Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Sat, 10 May 2025 13:37:04 +0200 Subject: [PATCH 08/28] fixes --- S1API/Products/CocaineDefinition.cs | 2 +- S1API/Products/MethDefinition.cs | 2 +- S1API/Products/PackagingDefinition.cs | 2 +- S1API/Products/ProductDefinition.cs | 2 +- S1API/Products/ProductInstance.cs | 2 +- S1API/Products/ProductManager.cs | 2 +- S1API/Products/Quality.cs | 2 +- S1API/Products/WeedDefinition.cs | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/S1API/Products/CocaineDefinition.cs b/S1API/Products/CocaineDefinition.cs index 43c0543d..6475d23b 100644 --- a/S1API/Products/CocaineDefinition.cs +++ b/S1API/Products/CocaineDefinition.cs @@ -1,4 +1,4 @@ -#if (IL2CPPMELON || IL2CPPBEPINEX) +#if (IL2CPPMELON) using Il2CppScheduleOne.Product; using S1CocaineDefinition = Il2CppScheduleOne.Product.CocaineDefinition; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) diff --git a/S1API/Products/MethDefinition.cs b/S1API/Products/MethDefinition.cs index 4635b0c9..1f0248c0 100644 --- a/S1API/Products/MethDefinition.cs +++ b/S1API/Products/MethDefinition.cs @@ -1,4 +1,4 @@ -#if (IL2CPPMELON || IL2CPPBEPINEX) +#if (IL2CPPMELON) using Il2CppScheduleOne.Product; using S1MethDefinition = Il2CppScheduleOne.Product.MethDefinition; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) diff --git a/S1API/Products/PackagingDefinition.cs b/S1API/Products/PackagingDefinition.cs index 8c1bb9d1..81d6aa84 100644 --- a/S1API/Products/PackagingDefinition.cs +++ b/S1API/Products/PackagingDefinition.cs @@ -1,4 +1,4 @@ -#if (IL2CPPMELON || IL2CPPBEPINEX) +#if (IL2CPPMELON) using S1Packaging = Il2CppScheduleOne.Product.Packaging; using S1ItemFramework = Il2CppScheduleOne.ItemFramework; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) diff --git a/S1API/Products/ProductDefinition.cs b/S1API/Products/ProductDefinition.cs index 3abd4efe..778f9ac9 100644 --- a/S1API/Products/ProductDefinition.cs +++ b/S1API/Products/ProductDefinition.cs @@ -1,4 +1,4 @@ -#if (IL2CPPMELON || IL2CPPBEPINEX) +#if (IL2CPPMELON) using Il2CppInterop.Runtime.InteropTypes; using S1Product = Il2CppScheduleOne.Product; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) diff --git a/S1API/Products/ProductInstance.cs b/S1API/Products/ProductInstance.cs index 610096c1..f19f43c5 100644 --- a/S1API/Products/ProductInstance.cs +++ b/S1API/Products/ProductInstance.cs @@ -1,4 +1,4 @@ -#if (IL2CPPMELON || IL2CPPBEPINEX) +#if (IL2CPPMELON ) using S1Product = Il2CppScheduleOne.Product; using Il2CppScheduleOne.ItemFramework; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) diff --git a/S1API/Products/ProductManager.cs b/S1API/Products/ProductManager.cs index 811a28a3..c317d8f4 100644 --- a/S1API/Products/ProductManager.cs +++ b/S1API/Products/ProductManager.cs @@ -1,4 +1,4 @@ -#if (IL2CPPMELON || IL2CPPBEPINEX) +#if (IL2CPPMELON) using S1Product = Il2CppScheduleOne.Product; using Il2CppSystem.Collections.Generic; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) diff --git a/S1API/Products/Quality.cs b/S1API/Products/Quality.cs index 2f21bd24..d95d2313 100644 --- a/S1API/Products/Quality.cs +++ b/S1API/Products/Quality.cs @@ -1,4 +1,4 @@ -#if IL2CPPBEPINEX || IL2CPPMELON +#if IL2CPPMELON using InternalQuality = Il2CppScheduleOne.ItemFramework.EQuality; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using InternalQuality = ScheduleOne.ItemFramework.EQuality; diff --git a/S1API/Products/WeedDefinition.cs b/S1API/Products/WeedDefinition.cs index 956999e5..be86ced9 100644 --- a/S1API/Products/WeedDefinition.cs +++ b/S1API/Products/WeedDefinition.cs @@ -1,4 +1,4 @@ -#if (IL2CPPMELON || IL2CPPBEPINEX) +#if (IL2CPPMELON) using Il2CppScheduleOne.Product; using S1WeedDefinition = Il2CppScheduleOne.Product.WeedDefinition; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) From 373744da1b7d0c414a47ad1474854e17085c4198 Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Mon, 12 May 2025 00:04:26 +0200 Subject: [PATCH 09/28] should work --- S1API/Products/CocaineDefinition.cs | 4 ++-- S1API/Products/MethDefinition.cs | 4 ++-- S1API/Products/ProductDefinition.cs | 4 ++-- S1API/Products/ProductInstance.cs | 2 +- S1API/Products/WeedDefinition.cs | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/S1API/Products/CocaineDefinition.cs b/S1API/Products/CocaineDefinition.cs index 6475d23b..6b66dd5e 100644 --- a/S1API/Products/CocaineDefinition.cs +++ b/S1API/Products/CocaineDefinition.cs @@ -44,13 +44,13 @@ public override ItemInstance CreateInstance(int quantity = 1) => /// Retrieves a list of properties associated with the current cocaine product definition. /// /// A list of properties specific to the cocaine product definition. -#if IL2CPPBEPINEX || IL2CPPMELON +#if IL2CPPMELON public List GetProperties() #else public List GetProperties() #endif { -#if IL2CPPBEPINEX || IL2CPPMELON +#if IL2CPPMELON var result = new List(); #else var result = new List(); diff --git a/S1API/Products/MethDefinition.cs b/S1API/Products/MethDefinition.cs index 1f0248c0..4faa7823 100644 --- a/S1API/Products/MethDefinition.cs +++ b/S1API/Products/MethDefinition.cs @@ -47,13 +47,13 @@ public override ItemInstance CreateInstance(int quantity = 1) => /// Retrieves the list of properties associated with the meth product definition. /// /// A list of properties that belong to the meth product definition. -#if IL2CPPBEPINEX || IL2CPPMELON +#if IL2CPPMELON public List GetProperties() #else public List GetProperties() #endif { -#if IL2CPPBEPINEX || IL2CPPMELON +#if IL2CPPMELON var result = new List(); #else var result = new List(); diff --git a/S1API/Products/ProductDefinition.cs b/S1API/Products/ProductDefinition.cs index 778f9ac9..11b9d551 100644 --- a/S1API/Products/ProductDefinition.cs +++ b/S1API/Products/ProductDefinition.cs @@ -27,7 +27,7 @@ public class ProductDefinition : ItemDefinition /// INTERNAL: Creates a product definition from the in-game product definition. /// /// -#if IL2CPPBEPINEX || IL2CPPMELON +#if IL2CPPMELON internal ProductDefinition(Il2CppScheduleOne.ItemFramework.ItemDefinition productDefinition) : base(productDefinition) { } #else internal ProductDefinition(ScheduleOne.ItemFramework.ItemDefinition productDefinition) : base(productDefinition) { } @@ -53,7 +53,7 @@ public Sprite Icon { get { return S1ProductDefinition.Icon; } } -#if IL2CPPBEPINEX || IL2CPPMELON +#if IL2CPPMELON private List properties; // or however properties are stored public List Properties; // or however properties are stored #else diff --git a/S1API/Products/ProductInstance.cs b/S1API/Products/ProductInstance.cs index 3593a5bd..0ef67164 100644 --- a/S1API/Products/ProductInstance.cs +++ b/S1API/Products/ProductInstance.cs @@ -52,7 +52,7 @@ internal ProductInstance(S1Product.ProductItemInstance productInstance) : base(p // Add Definition property if you don't have one yet -#if IL2CPPBEPINEX || IL2CPPMELON +#if IL2CPPMELON public IReadOnlyList Properties => Definition.Properties; public ProductDefinition Definition => new ProductDefinition(S1ProductInstance.Definition); #else diff --git a/S1API/Products/WeedDefinition.cs b/S1API/Products/WeedDefinition.cs index be86ced9..cb7ca0e0 100644 --- a/S1API/Products/WeedDefinition.cs +++ b/S1API/Products/WeedDefinition.cs @@ -58,13 +58,13 @@ public override ItemInstance CreateInstance(int quantity = 1) => /// associated with the weed definition. If no properties are found, /// an empty list is returned. /// -#if IL2CPPBEPINEX || IL2CPPMELON +#if IL2CPPMELON public List GetProperties() #else public List GetProperties() #endif { -#if IL2CPPBEPINEX || IL2CPPMELON +#if IL2CPPMELON var result = new List(); #else var result = new List(); From fcee074f217fd68256fa612503a3529e7d3a8f8a Mon Sep 17 00:00:00 2001 From: MaxtorCoder Date: Mon, 12 May 2025 22:18:43 +0200 Subject: [PATCH 10/28] fix: Fix NPC constraint for NPC.Get and fix csproj for latest rider --- S1API/Entities/NPC.cs | 2 +- S1API/S1API.csproj | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/S1API/Entities/NPC.cs b/S1API/Entities/NPC.cs index a758395f..6c24deac 100644 --- a/S1API/Entities/NPC.cs +++ b/S1API/Entities/NPC.cs @@ -592,7 +592,7 @@ public bool ConversationCanBeHidden /// /// The NPC class to get the instance of. /// - public static NPC? Get() => + public static NPC? Get() where T : NPC => All.FirstOrDefault(npc => npc.GetType() == typeof(T)); #endregion diff --git a/S1API/S1API.csproj b/S1API/S1API.csproj index 85a23c63..418bcc38 100644 --- a/S1API/S1API.csproj +++ b/S1API/S1API.csproj @@ -17,6 +17,7 @@ AnyCPU S1API true + latest From e68f0a8dcf6ee9f56e41179b38da95e6c3380558 Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Wed, 14 May 2025 22:56:17 +0200 Subject: [PATCH 11/28] quest patches fix --- S1API/Internal/Patches/QuestPatches.cs | 81 ++++++----- S1API/Items/ItemDefinition.cs | 190 +++++++++++++++++-------- 2 files changed, 171 insertions(+), 100 deletions(-) diff --git a/S1API/Internal/Patches/QuestPatches.cs b/S1API/Internal/Patches/QuestPatches.cs index bb964b04..cf44676e 100644 --- a/S1API/Internal/Patches/QuestPatches.cs +++ b/S1API/Internal/Patches/QuestPatches.cs @@ -1,13 +1,13 @@ -#if (IL2CPPMELON || IL2CPPBEPINEX) +#if (IL2CPPMELON) using S1Loaders = Il2CppScheduleOne.Persistence.Loaders; using S1Datas = Il2CppScheduleOne.Persistence.Datas; using S1Quests = Il2CppScheduleOne.Quests; +using S1Persistence = Il2CppScheduleOne.Persistence; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1Loaders = ScheduleOne.Persistence.Loaders; using S1Datas = ScheduleOne.Persistence.Datas; using S1Quests = ScheduleOne.Quests; #endif - #if (IL2CPPMELON || IL2CPPBEPINEX) using Il2CppSystem.Collections.Generic; #elif (MONOMELON || MONOBEPINEX) @@ -18,64 +18,78 @@ using System.IO; using System.Linq; using HarmonyLib; +using MelonLoader; using Newtonsoft.Json; -using S1API.Internal.Abstraction; using S1API.Internal.Utils; using S1API.Quests; using UnityEngine; +using ISaveable = S1API.Internal.Abstraction.ISaveable; namespace S1API.Internal.Patches { /// - /// INTERNAL: All patches related to quests. + /// INTERNAL: Contains patches specific to quest handling and modification. /// [HarmonyPatch] internal class QuestPatches { /// - /// Patching performed when all quests are saved. + /// Invoked after all quests are saved. + /// Ensures that modded quest data is correctly saved to a designated folder. /// - /// Instance of the quest manager. - /// Path to the base Quest folder. - /// List of extra saveable data. The game uses this for cleanup later. - [HarmonyPatch(typeof(S1Quests.QuestManager), "WriteData")] + /// The path to the primary save folder where quest data will be stored. + [HarmonyPatch(typeof(S1Persistence.SaveManager), nameof(S1Persistence.SaveManager.Save), typeof(string))] [HarmonyPostfix] - private static void QuestManagerWriteData(S1Quests.QuestManager __instance, string parentFolderPath, ref List __result) + private static void SaveManager_Save_Postfix(string saveFolderPath) { - string questsPath = Path.Combine(parentFolderPath, "Quests"); + try + { + string moddedQuestsPath = Path.Combine(saveFolderPath, "..\\Players\\ModdedQuests"); + + if (!Directory.Exists(moddedQuestsPath)) + Directory.CreateDirectory(moddedQuestsPath); + + foreach (Quest quest in QuestManager.Quests) + { + + List dummy = new(); + quest.SaveInternal(moddedQuestsPath, ref dummy); - foreach (Quest quest in QuestManager.Quests) - quest.SaveInternal(questsPath, ref __result); + } + + } + catch (Exception ex) + { + return; + } } + /// - /// Patching performed for when all quests are loaded. + /// Patching performed for when all quests are loaded from the modded quests directory. /// - /// Instance of the quest loader. - /// Path to the base Quest folder. + /// Instance of the quest loader responsible for loading quests. + /// Path to the base Quest folder where quests are located. [HarmonyPatch(typeof(S1Loaders.QuestsLoader), "Load")] [HarmonyPostfix] private static void QuestsLoaderLoad(S1Loaders.QuestsLoader __instance, string mainPath) { - // Make sure we have a quests directory (fresh saves don't at this point in runtime) - if (!Directory.Exists(mainPath)) - return; + string moddedQuestsPath = Path.Combine(mainPath, "..\\Players\\ModdedQuests"); - string[] questDirectories = Directory.GetDirectories(mainPath) + string[] questDirectories = Directory.GetDirectories(moddedQuestsPath) .Select(Path.GetFileName) .Where(directory => directory != null && directory.StartsWith("Quest_")) .ToArray()!; - foreach (string questDirectory in questDirectories) { - string baseQuestPath = Path.Combine(mainPath, questDirectory); + string baseQuestPath = Path.Combine(moddedQuestsPath, questDirectory); __instance.TryLoadFile(baseQuestPath, out string questDataText); if (questDataText == null) continue; S1Datas.QuestData baseQuestData = JsonUtility.FromJson(questDataText); - string questDirectoryPath = Path.Combine(mainPath, questDirectory); + string questDirectoryPath = Path.Combine(moddedQuestsPath, questDirectory); string questDataPath = Path.Combine(questDirectoryPath, "QuestData"); if (!__instance.TryLoadFile(questDataPath, out string questText)) continue; @@ -93,26 +107,11 @@ private static void QuestsLoaderLoad(S1Loaders.QuestsLoader __instance, string m } } + /// - /// Patching performed for when stale files are deleted. + /// Executes custom initialization logic whenever a quest starts. /// - /// Instance of the quest manager. - /// Path to the base Quest folder. - [HarmonyPatch(typeof(S1Quests.QuestManager), "DeleteUnapprovedFiles")] - [HarmonyPostfix] - private static void QuestManagerDeleteUnapprovedFiles(S1Quests.QuestManager __instance, string parentFolderPath) - { - string questFolder = Path.Combine(parentFolderPath, "Quests"); - string?[] existingQuests = QuestManager.Quests.Select(quest => quest.SaveFolder).ToArray(); - - string[] unapprovedQuestDirectories = Directory.GetDirectories(questFolder) - .Where(directory => directory.StartsWith("Quest_") && !existingQuests.Contains(directory)) - .ToArray(); - - foreach (string unapprovedQuestDirectory in unapprovedQuestDirectories) - Directory.Delete(unapprovedQuestDirectory, true); - } - + /// The instance of the quest that is starting. [HarmonyPatch(typeof(S1Quests.Quest), "Start")] [HarmonyPrefix] private static void QuestStart(S1Quests.Quest __instance) => diff --git a/S1API/Items/ItemDefinition.cs b/S1API/Items/ItemDefinition.cs index 2ac08b66..a35b0062 100644 --- a/S1API/Items/ItemDefinition.cs +++ b/S1API/Items/ItemDefinition.cs @@ -1,118 +1,190 @@ -#if (IL2CPPMELON || IL2CPPBEPINEX) +#if (IL2CPPMELON) using S1ItemFramework = Il2CppScheduleOne.ItemFramework; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1ItemFramework = ScheduleOne.ItemFramework; #endif +using UnityEngine; using S1API.Internal.Abstraction; namespace S1API.Items { /// /// Represents an item definition in-game. - /// NOTE: A definition is "what" the item is. For example, "This is a `Soda`". - /// Any instanced items in the game will be a instead. + /// Use this class to read and create new item definitions dynamically. /// public class ItemDefinition : IGUIDReference { /// - /// INTERNAL: A reference to the item definition in the game. + /// INTERNAL: A reference to the native game item definition. /// - internal readonly S1ItemFramework.ItemDefinition S1ItemDefinition; + internal S1ItemFramework.ItemDefinition S1ItemDefinition { get; } /// - /// Creates a new item definition from the game item definition instance. + /// INTERNAL: Wraps an existing native item definition. /// - /// - internal ItemDefinition(S1ItemFramework.ItemDefinition s1ItemDefinition) => - S1ItemDefinition = s1ItemDefinition; + internal ItemDefinition(S1ItemFramework.ItemDefinition definition) + { + S1ItemDefinition = definition; + } /// - /// INTERNAL: Gets an item definition from a GUID. + /// The unique ID of this item. /// - /// The GUID to look for - /// The applicable item definition, if found. - internal static ItemDefinition GetFromGUID(string guid) => - ItemManager.GetItemDefinition(guid); + public string ID + { + get => S1ItemDefinition.ID; + set => S1ItemDefinition.ID = value; + } /// - /// Performs an equals check on the game item definition instance. + /// The display name for this item. /// - /// The item definition you want to compare against. - /// Whether the item definitions are the same or not. - public override bool Equals(object? obj) => - obj is ItemDefinition other && S1ItemDefinition == other.S1ItemDefinition; + public string Name + { + get => S1ItemDefinition.Name; + set => S1ItemDefinition.Name = value; + } /// - /// Snags the hash code from the game instance versus this instance. + /// A short description for this item. /// - /// The game intance hash code - public override int GetHashCode() => - S1ItemDefinition?.GetHashCode() ?? 0; + public string Description + { + get => S1ItemDefinition.Description; + set => S1ItemDefinition.Description = value; + } /// - /// Performs an == check on the game item definition instance. + /// Stack limit for this item (max quantity per slot). /// - /// The first item definition to compare. - /// The second item definition to compare. - /// Whether the item definitions are the same or not. - public static bool operator ==(ItemDefinition? left, ItemDefinition? right) + public int StackLimit { - if (ReferenceEquals(left, right)) return true; - return left?.S1ItemDefinition == right?.S1ItemDefinition; + get => S1ItemDefinition.StackLimit; + set => S1ItemDefinition.StackLimit = value; } /// - /// Performs an != check on the game item definition instance. + /// The category for inventory sorting. /// - /// The first item definition to compare. - /// The second item definition to compare. - /// Whether the item definitions are different or not. - public static bool operator !=(ItemDefinition left, ItemDefinition right) => - !(left == right); + public ItemCategory Category + { + get => (ItemCategory)S1ItemDefinition.Category; + set => S1ItemDefinition.Category = (S1ItemFramework.EItemCategory)value; + } /// - /// The unique identifier assigned to this item definition. + /// The icon for this item. /// - public virtual string GUID => - S1ItemDefinition.ID; + public Sprite Icon + { + get => S1ItemDefinition.Icon; + set => S1ItemDefinition.Icon = value; + } /// - /// The unique identifier assigned to this item definition. + /// Whether this item is available in the demo version of the game. /// - public string ID => - S1ItemDefinition.ID; + public bool AvailableInDemo + { + get => S1ItemDefinition.AvailableInDemo; + set => S1ItemDefinition.AvailableInDemo = value; + } /// - /// The display name for this item. + /// Legal status of the item (e.g., illegal drugs). + /// + public LegalStatus LegalStatus + { + get => (LegalStatus)S1ItemDefinition.legalStatus; + set => S1ItemDefinition.legalStatus = (S1ItemFramework.ELegalStatus)value; + } + + + /// + /// The color of the label shown in UI. + /// + public Color LabelDisplayColor + { + get => S1ItemDefinition.LabelDisplayColor; + set => S1ItemDefinition.LabelDisplayColor = value; + } + + /// + /// Any keywords used to filter/search this item. /// - public string Name => - S1ItemDefinition.Name; + public string[] Keywords + { + get => S1ItemDefinition.Keywords; + set => S1ItemDefinition.Keywords = value; + } /// - /// The description used for this item. + /// Creates a new item instance with the specified quantity. /// - public string Description => - S1ItemDefinition.Description; + public virtual ItemInstance CreateInstance(int quantity = 1) + { + var inst = S1ItemDefinition.GetDefaultInstance(quantity); + return new ItemInstance(inst); + } + + /// + /// Gets the globally unique identifier (GUID) of the item, which is equivalent to the ID. + /// + public string GUID => ID; /// - /// The category this item is assigned to. + /// Determines whether the specified object is equal to the current object. /// - public ItemCategory Category => - (ItemCategory)S1ItemDefinition.Category; + /// The object to compare with the current object. + /// true if the specified object is an and has the same S1ItemDefinition; otherwise, false. + public override bool Equals(object? obj) => + obj is ItemDefinition other && S1ItemDefinition == other.S1ItemDefinition; /// - /// The stack limit for this item. + /// Serves as the default hash function. /// - public int StackLimit => - S1ItemDefinition.StackLimit; + /// A hash code for the current object based on S1ItemDefinition. + public override int GetHashCode() => S1ItemDefinition.GetHashCode(); /// - /// Creates an instance of this item from the definition. + /// Determines whether two instances are equal. /// - /// How many of the item the instance will have. - /// A new item instance within the game. - public virtual ItemInstance CreateInstance(int quantity = 1) => - new ItemInstance(S1ItemDefinition.GetDefaultInstance(quantity)); + /// The first to compare. + /// The second to compare. + /// true if both instances are equal or have the same S1ItemDefinition; otherwise, false. + public static bool operator ==(ItemDefinition? a, ItemDefinition? b) + { + if (ReferenceEquals(a, b)) + return true; + if (a is null || b is null) + return false; + return ReferenceEquals(a.S1ItemDefinition, b.S1ItemDefinition); + } + /// + /// Determines whether two instances are not equal. + /// + /// The first to compare. + /// The second to compare. + /// true if the instances are not equal; otherwise, false. + public static bool operator !=(ItemDefinition? a, ItemDefinition? b) + { + if (ReferenceEquals(a, b)) + return false; + if (a is null || b is null) + return true; + return !ReferenceEquals(a.S1ItemDefinition, b.S1ItemDefinition); + } + + } + + /// + /// Represents the legal status of an item (e.g., legal or illegal). + /// + public enum LegalStatus + { + Legal, + Illegal, + // More if needed } } From 78bec8b55204724f8d0060d78228d2b1f1a1ff5c Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Wed, 14 May 2025 22:59:34 +0200 Subject: [PATCH 12/28] fix for mono --- S1API/Internal/Patches/QuestPatches.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/S1API/Internal/Patches/QuestPatches.cs b/S1API/Internal/Patches/QuestPatches.cs index cf44676e..4d0b633f 100644 --- a/S1API/Internal/Patches/QuestPatches.cs +++ b/S1API/Internal/Patches/QuestPatches.cs @@ -7,6 +7,8 @@ using S1Loaders = ScheduleOne.Persistence.Loaders; using S1Datas = ScheduleOne.Persistence.Datas; using S1Quests = ScheduleOne.Quests; +using S1Persistence = ScheduleOne.Persistence; + #endif #if (IL2CPPMELON || IL2CPPBEPINEX) using Il2CppSystem.Collections.Generic; @@ -18,7 +20,6 @@ using System.IO; using System.Linq; using HarmonyLib; -using MelonLoader; using Newtonsoft.Json; using S1API.Internal.Utils; using S1API.Quests; @@ -51,8 +52,11 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) foreach (Quest quest in QuestManager.Quests) { - +#if (IL2CPPMELON) List dummy = new(); +#else + List dummy = new List(); +#endif quest.SaveInternal(moddedQuestsPath, ref dummy); } From 41d3b057def140539ab5e4e22da37e32cd85340a Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Thu, 15 May 2025 00:20:21 +0200 Subject: [PATCH 13/28] changes for max --- S1API/Internal/Patches/QuestPatches.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/S1API/Internal/Patches/QuestPatches.cs b/S1API/Internal/Patches/QuestPatches.cs index 4d0b633f..9c865667 100644 --- a/S1API/Internal/Patches/QuestPatches.cs +++ b/S1API/Internal/Patches/QuestPatches.cs @@ -52,11 +52,9 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) foreach (Quest quest in QuestManager.Quests) { -#if (IL2CPPMELON) - List dummy = new(); -#else + List dummy = new List(); -#endif + quest.SaveInternal(moddedQuestsPath, ref dummy); } @@ -64,7 +62,7 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) } catch (Exception ex) { - return; + throw new Exception("Failed during SaveManager_Save_Postfix execution.", ex); } } From fd280c411962737fa2669d32bd0af3c0e5516472 Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Thu, 15 May 2025 11:54:16 +0200 Subject: [PATCH 14/28] fix: using logger --- S1API/Internal/Patches/QuestPatches.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/S1API/Internal/Patches/QuestPatches.cs b/S1API/Internal/Patches/QuestPatches.cs index 9c865667..8d4fee8b 100644 --- a/S1API/Internal/Patches/QuestPatches.cs +++ b/S1API/Internal/Patches/QuestPatches.cs @@ -34,6 +34,8 @@ namespace S1API.Internal.Patches [HarmonyPatch] internal class QuestPatches { + protected static readonly Logging.Log Logger = new Logging.Log("QuestPatches"); + /// /// Invoked after all quests are saved. /// Ensures that modded quest data is correctly saved to a designated folder. @@ -62,7 +64,7 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) } catch (Exception ex) { - throw new Exception("Failed during SaveManager_Save_Postfix execution.", ex); + Logger.Error("Failed during SaveManager_Save_Postfix execution."); } } From e7df9c06dcf8ba6661de09a9f8e615707096019c Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Thu, 15 May 2025 12:35:19 +0200 Subject: [PATCH 15/28] change exception handling --- S1API/Internal/Patches/QuestPatches.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/S1API/Internal/Patches/QuestPatches.cs b/S1API/Internal/Patches/QuestPatches.cs index 8d4fee8b..51147a2a 100644 --- a/S1API/Internal/Patches/QuestPatches.cs +++ b/S1API/Internal/Patches/QuestPatches.cs @@ -64,7 +64,8 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) } catch (Exception ex) { - Logger.Error("Failed during SaveManager_Save_Postfix execution."); + Logger.Error("Failed during SaveManager_Save_Postfix execution.\n" + ex); + throw; } } From f115cdd33e3cb1625333b656e90ab7fb0dbad1b8 Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Fri, 16 May 2025 14:31:41 +0200 Subject: [PATCH 16/28] fix: save under Modded/Quests --- S1API/Internal/Patches/QuestPatches.cs | 44 +++++++++++++++++++------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/S1API/Internal/Patches/QuestPatches.cs b/S1API/Internal/Patches/QuestPatches.cs index 51147a2a..5d98854e 100644 --- a/S1API/Internal/Patches/QuestPatches.cs +++ b/S1API/Internal/Patches/QuestPatches.cs @@ -3,6 +3,7 @@ using S1Datas = Il2CppScheduleOne.Persistence.Datas; using S1Quests = Il2CppScheduleOne.Quests; using S1Persistence = Il2CppScheduleOne.Persistence; +using Il2CppScheduleOne.DevUtilities; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1Loaders = ScheduleOne.Persistence.Loaders; using S1Datas = ScheduleOne.Persistence.Datas; @@ -47,25 +48,38 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) { try { - string moddedQuestsPath = Path.Combine(saveFolderPath, "..\\Players\\ModdedQuests"); + var saveManager = Singleton.Instance; - if (!Directory.Exists(moddedQuestsPath)) - Directory.CreateDirectory(moddedQuestsPath); + string[] approved = { + "Modded", + Path.Combine("Modded", "Quests") + }; - foreach (Quest quest in QuestManager.Quests) + foreach (var path in approved) { + if (!saveManager.ApprovedBaseLevelPaths.Contains(path)) + saveManager.ApprovedBaseLevelPaths.Add(path); + } - List dummy = new List(); - - quest.SaveInternal(moddedQuestsPath, ref dummy); + // ✅ Create the directory structure + string questsPath = Path.Combine(saveFolderPath, "Modded", "Quests"); + Directory.CreateDirectory(questsPath); + // ✅ Save only non-vanilla modded quests + foreach (Quest quest in QuestManager.Quests) + { + if (!quest.GetType().Namespace.StartsWith("ScheduleOne")) + { + List dummy = new(); + quest.SaveInternal(questsPath, ref dummy); + } } + Logger.Msg($"[S1API] ✅ Saved modded quests to: {questsPath}"); } catch (Exception ex) { - Logger.Error("Failed during SaveManager_Save_Postfix execution.\n" + ex); - throw; + Logger.Error("[S1API] ❌ Failed to save modded quests:\n" + ex); } } @@ -79,12 +93,20 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) [HarmonyPostfix] private static void QuestsLoaderLoad(S1Loaders.QuestsLoader __instance, string mainPath) { - string moddedQuestsPath = Path.Combine(mainPath, "..\\Players\\ModdedQuests"); + string moddedQuestsPath = Path.Combine(mainPath, "..//Modded", "Quests"); + + if (!Directory.Exists(moddedQuestsPath)) + { + Logger.Warning("[S1API] No Modded/Quests folder found: " + moddedQuestsPath); + return; + } + + Logger.Msg("[S1API] ✅ Loading modded quests from: " + moddedQuestsPath); string[] questDirectories = Directory.GetDirectories(moddedQuestsPath) .Select(Path.GetFileName) .Where(directory => directory != null && directory.StartsWith("Quest_")) - .ToArray()!; + .ToArray(); foreach (string questDirectory in questDirectories) { string baseQuestPath = Path.Combine(moddedQuestsPath, questDirectory); From 25daf9400c03dc6fc86b8a609b5e2ab70c14575f Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Fri, 16 May 2025 14:51:41 +0200 Subject: [PATCH 17/28] fix: load path --- S1API/Internal/Patches/QuestPatches.cs | 35 +++++++++++++++++--------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/S1API/Internal/Patches/QuestPatches.cs b/S1API/Internal/Patches/QuestPatches.cs index 5d98854e..ca14985b 100644 --- a/S1API/Internal/Patches/QuestPatches.cs +++ b/S1API/Internal/Patches/QuestPatches.cs @@ -9,7 +9,7 @@ using S1Datas = ScheduleOne.Persistence.Datas; using S1Quests = ScheduleOne.Quests; using S1Persistence = ScheduleOne.Persistence; - +using ScheduleOne.DevUtilities; #endif #if (IL2CPPMELON || IL2CPPBEPINEX) using Il2CppSystem.Collections.Generic; @@ -30,18 +30,23 @@ namespace S1API.Internal.Patches { /// - /// INTERNAL: Contains patches specific to quest handling and modification. + /// INTERNAL: Contains patches related to quest processing and custom modifications. /// [HarmonyPatch] internal class QuestPatches { + /// + /// Provides a centralized logging mechanism to capture and output messages, warnings, + /// and errors during runtime, using underlying logging frameworks like BepInEx or MelonLoader. + /// protected static readonly Logging.Log Logger = new Logging.Log("QuestPatches"); /// - /// Invoked after all quests are saved. - /// Ensures that modded quest data is correctly saved to a designated folder. + /// Executes additional logic after quests are saved by the SaveManager. + /// Ensures that directories for modded quests are properly created and that + /// only non-vanilla modded quests are saved into the specified folder. /// - /// The path to the primary save folder where quest data will be stored. + /// The path to the save folder where quests are being stored. [HarmonyPatch(typeof(S1Persistence.SaveManager), nameof(S1Persistence.SaveManager.Save), typeof(string))] [HarmonyPostfix] private static void SaveManager_Save_Postfix(string saveFolderPath) @@ -70,7 +75,7 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) { if (!quest.GetType().Namespace.StartsWith("ScheduleOne")) { - List dummy = new(); + List dummy = new List(); quest.SaveInternal(questsPath, ref dummy); } } @@ -85,15 +90,19 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) /// - /// Patching performed for when all quests are loaded from the modded quests directory. + /// Invoked after all base quests are loaded to handle modded quest loading. + /// Loads modded quests from a specific "Modded/Quests" directory and integrates them into the game. /// - /// Instance of the quest loader responsible for loading quests. - /// Path to the base Quest folder where quests are located. + /// The quest loader instance responsible for managing quest load operations. + /// The path to the primary quest directory in the base game. [HarmonyPatch(typeof(S1Loaders.QuestsLoader), "Load")] [HarmonyPostfix] private static void QuestsLoaderLoad(S1Loaders.QuestsLoader __instance, string mainPath) { - string moddedQuestsPath = Path.Combine(mainPath, "..//Modded", "Quests"); + string moddedQuestsPath = Path.Combine( + Singleton.Instance.LoadedGameFolderPath, + "Modded", "Quests" + ); if (!Directory.Exists(moddedQuestsPath)) { @@ -107,6 +116,7 @@ private static void QuestsLoaderLoad(S1Loaders.QuestsLoader __instance, string m .Select(Path.GetFileName) .Where(directory => directory != null && directory.StartsWith("Quest_")) .ToArray(); + foreach (string questDirectory in questDirectories) { string baseQuestPath = Path.Combine(moddedQuestsPath, questDirectory); @@ -136,9 +146,10 @@ private static void QuestsLoaderLoad(S1Loaders.QuestsLoader __instance, string m /// - /// Executes custom initialization logic whenever a quest starts. + /// Executes logic prior to the start of a quest. + /// Ensures that linked modded quest data is properly initialized. /// - /// The instance of the quest that is starting. + /// The instance of the quest that is being started. [HarmonyPatch(typeof(S1Quests.Quest), "Start")] [HarmonyPrefix] private static void QuestStart(S1Quests.Quest __instance) => From eaeb3390f6cfe33b7341f7004f25967dd0878ffd Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Fri, 16 May 2025 14:53:54 +0200 Subject: [PATCH 18/28] fix: no singleton usage savemanager.instance --- S1API/Internal/Patches/QuestPatches.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/S1API/Internal/Patches/QuestPatches.cs b/S1API/Internal/Patches/QuestPatches.cs index ca14985b..af5fb96d 100644 --- a/S1API/Internal/Patches/QuestPatches.cs +++ b/S1API/Internal/Patches/QuestPatches.cs @@ -53,7 +53,7 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) { try { - var saveManager = Singleton.Instance; + var saveManager = S1Persistence.SaveManager.Instance; string[] approved = { "Modded", @@ -80,7 +80,6 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) } } - Logger.Msg($"[S1API] ✅ Saved modded quests to: {questsPath}"); } catch (Exception ex) { @@ -110,8 +109,6 @@ private static void QuestsLoaderLoad(S1Loaders.QuestsLoader __instance, string m return; } - Logger.Msg("[S1API] ✅ Loading modded quests from: " + moddedQuestsPath); - string[] questDirectories = Directory.GetDirectories(moddedQuestsPath) .Select(Path.GetFileName) .Where(directory => directory != null && directory.StartsWith("Quest_")) From e84c6581d55d5c238960d5bb1df1385d205e15e4 Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Fri, 16 May 2025 14:55:42 +0200 Subject: [PATCH 19/28] fix: singelton in load --- S1API/Internal/Patches/QuestPatches.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/S1API/Internal/Patches/QuestPatches.cs b/S1API/Internal/Patches/QuestPatches.cs index af5fb96d..eb985cfb 100644 --- a/S1API/Internal/Patches/QuestPatches.cs +++ b/S1API/Internal/Patches/QuestPatches.cs @@ -99,7 +99,7 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) private static void QuestsLoaderLoad(S1Loaders.QuestsLoader __instance, string mainPath) { string moddedQuestsPath = Path.Combine( - Singleton.Instance.LoadedGameFolderPath, + S1Persistence.LoadManager.Instance.LoadedGameFolderPath, "Modded", "Quests" ); From 7a2328ec29098028e13ef638b11815c7675abad8 Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Sat, 17 May 2025 01:03:00 +0200 Subject: [PATCH 20/28] fix: codestyling --- S1API/Internal/Patches/QuestPatches.cs | 20 ----------------- S1API/Products/CocaineDefinition.cs | 10 +++++---- S1API/Products/MethDefinition.cs | 10 +++++---- S1API/Products/ProductDefinition.cs | 16 ++++++++------ S1API/Products/ProductInstance.cs | 30 ++++++++++++++++---------- S1API/Products/WeedDefinition.cs | 10 +++++---- 6 files changed, 47 insertions(+), 49 deletions(-) diff --git a/S1API/Internal/Patches/QuestPatches.cs b/S1API/Internal/Patches/QuestPatches.cs index b5e062dc..dc0dd12a 100644 --- a/S1API/Internal/Patches/QuestPatches.cs +++ b/S1API/Internal/Patches/QuestPatches.cs @@ -93,26 +93,6 @@ private static void QuestsLoaderLoad(S1Loaders.QuestsLoader __instance, string m } } - /// - /// Patching performed for when stale files are deleted. - /// - /// Instance of the quest manager. - /// Path to the base Quest folder. - [HarmonyPatch(typeof(S1Quests.QuestManager), "DeleteUnapprovedFiles")] - [HarmonyPostfix] - private static void QuestManagerDeleteUnapprovedFiles(S1Quests.QuestManager __instance, string parentFolderPath) - { - string questFolder = Path.Combine(parentFolderPath, "Quests"); - string?[] existingQuests = QuestManager.Quests.Select(quest => quest.SaveFolder).ToArray(); - - string[] unapprovedQuestDirectories = Directory.GetDirectories(questFolder) - .Where(directory => directory.StartsWith("Quest_") && !existingQuests.Contains(directory)) - .ToArray(); - - foreach (string unapprovedQuestDirectory in unapprovedQuestDirectories) - Directory.Delete(unapprovedQuestDirectory, true); - } - [HarmonyPatch(typeof(S1Quests.Quest), "Start")] [HarmonyPrefix] private static void QuestStart(S1Quests.Quest __instance) => diff --git a/S1API/Products/CocaineDefinition.cs b/S1API/Products/CocaineDefinition.cs index 6b66dd5e..31fd27ef 100644 --- a/S1API/Products/CocaineDefinition.cs +++ b/S1API/Products/CocaineDefinition.cs @@ -1,9 +1,11 @@ #if (IL2CPPMELON) using Il2CppScheduleOne.Product; using S1CocaineDefinition = Il2CppScheduleOne.Product.CocaineDefinition; +using Properties = Il2CppScheduleOne.Properties; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using ScheduleOne.Product; using S1CocaineDefinition = ScheduleOne.Product.CocaineDefinition; +using Properties = ScheduleOne.Properties; #endif using System.Collections.Generic; @@ -45,15 +47,15 @@ public override ItemInstance CreateInstance(int quantity = 1) => /// /// A list of properties specific to the cocaine product definition. #if IL2CPPMELON - public List GetProperties() + public List GetProperties() #else - public List GetProperties() + public List GetProperties() #endif { #if IL2CPPMELON - var result = new List(); + var result = new List(); #else - var result = new List(); + var result = new List(); #endif var list = S1CocaineDefinition?.Properties; if (list != null) diff --git a/S1API/Products/MethDefinition.cs b/S1API/Products/MethDefinition.cs index 4faa7823..b1de7c00 100644 --- a/S1API/Products/MethDefinition.cs +++ b/S1API/Products/MethDefinition.cs @@ -1,9 +1,11 @@ #if (IL2CPPMELON) using Il2CppScheduleOne.Product; using S1MethDefinition = Il2CppScheduleOne.Product.MethDefinition; + using Properties = Il2CppScheduleOne.Properties; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using ScheduleOne.Product; using S1MethDefinition = ScheduleOne.Product.MethDefinition; +using Properties = ScheduleOne.Properties; #endif using System.Collections.Generic; @@ -48,15 +50,15 @@ public override ItemInstance CreateInstance(int quantity = 1) => /// /// A list of properties that belong to the meth product definition. #if IL2CPPMELON - public List GetProperties() + public List GetProperties() #else - public List GetProperties() + public List GetProperties() #endif { #if IL2CPPMELON - var result = new List(); + var result = new List(); #else - var result = new List(); + var result = new List(); #endif var list = S1MethDefinition?.Properties; if (list != null) diff --git a/S1API/Products/ProductDefinition.cs b/S1API/Products/ProductDefinition.cs index 11b9d551..7ba72fb6 100644 --- a/S1API/Products/ProductDefinition.cs +++ b/S1API/Products/ProductDefinition.cs @@ -1,8 +1,12 @@ #if (IL2CPPMELON) using Il2CppInterop.Runtime.InteropTypes; using S1Product = Il2CppScheduleOne.Product; +using ItemFramework = Il2CppScheduleOne.ItemFramework; +using Properties = Il2CppScheduleOne.Properties; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1Product = ScheduleOne.Product; +using ItemFramework = ScheduleOne.ItemFramework; +using Properties = ScheduleOne.Properties; #endif using System.Collections.Generic; @@ -28,9 +32,9 @@ public class ProductDefinition : ItemDefinition /// /// #if IL2CPPMELON - internal ProductDefinition(Il2CppScheduleOne.ItemFramework.ItemDefinition productDefinition) : base(productDefinition) { } + internal ProductDefinition(ItemFramework.ItemDefinition productDefinition) : base(productDefinition) { } #else - internal ProductDefinition(ScheduleOne.ItemFramework.ItemDefinition productDefinition) : base(productDefinition) { } + internal ProductDefinition(ItemFramework.ItemDefinition productDefinition) : base(productDefinition) { } #endif /// /// The price associated with this product. @@ -54,11 +58,11 @@ public Sprite Icon get { return S1ProductDefinition.Icon; } } #if IL2CPPMELON - private List properties; // or however properties are stored - public List Properties; // or however properties are stored + private List properties; // or however properties are stored + public List Properties; // or however properties are stored #else - private List properties; // or however properties are stored - public IReadOnlyList Properties => properties.AsReadOnly(); + private List properties; // or however properties are stored + public IReadOnlyList Properties => properties.AsReadOnly(); #endif diff --git a/S1API/Products/ProductInstance.cs b/S1API/Products/ProductInstance.cs index 0ef67164..bd15181f 100644 --- a/S1API/Products/ProductInstance.cs +++ b/S1API/Products/ProductInstance.cs @@ -1,11 +1,10 @@ #if (IL2CPPMELON ) using S1Product = Il2CppScheduleOne.Product; -using Il2CppScheduleOne.ItemFramework; +using Properties = Il2CppScheduleOne.Properties; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1Product = ScheduleOne.Product; -using ScheduleOne.ItemFramework; +using Properties = ScheduleOne.Properties; #endif - using System.Collections.Generic; using S1API.Internal.Utils; using ItemInstance = S1API.Items.ItemInstance; @@ -18,34 +17,36 @@ namespace S1API.Products public class ProductInstance : ItemInstance { /// - /// INTERNAL: The stored reference to the in-game product instance. + /// INTERNAL: Reference to the in-game product item instance. /// internal S1Product.ProductItemInstance S1ProductInstance => CrossType.As(S1ItemInstance); /// - /// INTERNAL: Creates a product instance from the in-game product instance. + /// Represents an instance of a product derived from an in-game product item instance. /// - /// internal ProductInstance(S1Product.ProductItemInstance productInstance) : base(productInstance) { } /// - /// Whether this product is currently packaged or not. + /// Indicates whether the product instance has applied packaging. /// public bool IsPackaged => S1ProductInstance.AppliedPackaging; /// - /// The type of packaging applied to this product. + /// Represents the packaging details currently applied to the product instance, if any. /// public PackagingDefinition AppliedPackaging => new PackagingDefinition(S1ProductInstance.AppliedPackaging); /// - /// The quality of this product instance. + /// Represents the quality tier of the product instance. /// + /// + /// The quality indicates the standard or grade of the product, ranging through predefined levels such as Trash, Poor, Standard, Premium, and Heavenly. + /// public Quality Quality => S1ProductInstance.Quality.ToAPI(); // Expose the underlying definition's properties (if S1ProductInstance.Definition is available) @@ -53,10 +54,17 @@ internal ProductInstance(S1Product.ProductItemInstance productInstance) : base(p // Add Definition property if you don't have one yet #if IL2CPPMELON - public IReadOnlyList Properties => Definition.Properties; + public IReadOnlyList Properties => Definition.Properties; public ProductDefinition Definition => new ProductDefinition(S1ProductInstance.Definition); #else - public IReadOnlyList Properties => Definition.Properties; + /// + /// Represents the collection of properties associated with the product. + /// + public IReadOnlyList Properties => Definition.Properties; + + /// + /// Represents the definition of a product in the game, including its core properties. + /// public ProductDefinition Definition => new ProductDefinition(S1ProductInstance.Definition); #endif diff --git a/S1API/Products/WeedDefinition.cs b/S1API/Products/WeedDefinition.cs index cb7ca0e0..395d82cf 100644 --- a/S1API/Products/WeedDefinition.cs +++ b/S1API/Products/WeedDefinition.cs @@ -1,9 +1,11 @@ #if (IL2CPPMELON) using Il2CppScheduleOne.Product; using S1WeedDefinition = Il2CppScheduleOne.Product.WeedDefinition; +using Properties = Il2CppScheduleOne.Properties; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using ScheduleOne.Product; using S1WeedDefinition = ScheduleOne.Product.WeedDefinition; +using Properties = ScheduleOne.Properties; #endif using S1API.Internal.Utils; @@ -59,15 +61,15 @@ public override ItemInstance CreateInstance(int quantity = 1) => /// an empty list is returned. /// #if IL2CPPMELON - public List GetProperties() + public List GetProperties() #else -public List GetProperties() + public List GetProperties() #endif { #if IL2CPPMELON - var result = new List(); + var result = new List(); #else - var result = new List(); + var result = new List(); #endif var list = S1WeedDefinition?.Properties; if (list != null) From d0f02d9c7320fa756babc86884b53750f3d7aa55 Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Sat, 17 May 2025 01:16:46 +0200 Subject: [PATCH 21/28] Get rid of the preprocessord, prefix s1 namespaces with S1 --- S1API/Products/CocaineDefinition.cs | 35 +++++++------------ S1API/Products/MethDefinition.cs | 37 ++++++-------------- S1API/Products/ProductInstance.cs | 53 ++++++++++++++--------------- S1API/Products/WeedDefinition.cs | 45 ++++++------------------ 4 files changed, 60 insertions(+), 110 deletions(-) diff --git a/S1API/Products/CocaineDefinition.cs b/S1API/Products/CocaineDefinition.cs index 31fd27ef..0ee5e2f5 100644 --- a/S1API/Products/CocaineDefinition.cs +++ b/S1API/Products/CocaineDefinition.cs @@ -1,11 +1,11 @@ #if (IL2CPPMELON) using Il2CppScheduleOne.Product; using S1CocaineDefinition = Il2CppScheduleOne.Product.CocaineDefinition; -using Properties = Il2CppScheduleOne.Properties; +using S1Properties = Il2CppScheduleOne.Properties; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using ScheduleOne.Product; using S1CocaineDefinition = ScheduleOne.Product.CocaineDefinition; -using Properties = ScheduleOne.Properties; +using S1Properties = ScheduleOne.Properties; #endif using System.Collections.Generic; @@ -15,18 +15,18 @@ namespace S1API.Products { /// - /// Represents the definition of a cocaine product within the system. + /// Defines the characteristics and behaviors of a cocaine product within the system. /// public class CocaineDefinition : ProductDefinition { /// - /// INTERNAL: Strongly typed access to the CocaineDefinition within the Schedule One framework. + /// Provides internal access to the CocaineDefinition type within the Schedule One system. /// internal S1CocaineDefinition S1CocaineDefinition => CrossType.As(S1ItemDefinition); /// - /// Represents the definition of a Cocaine product. + /// Represents the definition of a cocaine product within the system. /// internal CocaineDefinition(S1CocaineDefinition definition) : base(definition) @@ -34,39 +34,28 @@ internal CocaineDefinition(S1CocaineDefinition definition) } /// - /// Creates an instance of this cocaine product with the specified quantity. + /// Creates an instance of this product definition with the specified quantity. /// - /// The quantity of the product to create. Defaults to 1. - /// An instance of the cocaine product with the specified quantity. + /// The quantity of the product to instantiate. Defaults to 1 if not specified. + /// An representing the instantiated product with the specified quantity. public override ItemInstance CreateInstance(int quantity = 1) => new ProductInstance(CrossType.As( S1CocaineDefinition.GetDefaultInstance(quantity))); /// - /// Retrieves a list of properties associated with the current cocaine product definition. + /// Retrieves a list of properties associated with this product definition. /// - /// A list of properties specific to the cocaine product definition. -#if IL2CPPMELON - public List GetProperties() -#else - public List GetProperties() -#endif + /// A list of properties for the product. + public List GetProperties() { -#if IL2CPPMELON - var result = new List(); -#else - var result = new List(); -#endif + var result = new List(); var list = S1CocaineDefinition?.Properties; if (list != null) { for (int i = 0; i < list.Count; i++) - { result.Add(list[i]); - } } return result; } } - } diff --git a/S1API/Products/MethDefinition.cs b/S1API/Products/MethDefinition.cs index b1de7c00..87689244 100644 --- a/S1API/Products/MethDefinition.cs +++ b/S1API/Products/MethDefinition.cs @@ -1,35 +1,31 @@ #if (IL2CPPMELON) using Il2CppScheduleOne.Product; using S1MethDefinition = Il2CppScheduleOne.Product.MethDefinition; - using Properties = Il2CppScheduleOne.Properties; +using S1Properties = Il2CppScheduleOne.Properties; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using ScheduleOne.Product; using S1MethDefinition = ScheduleOne.Product.MethDefinition; -using Properties = ScheduleOne.Properties; +using S1Properties = ScheduleOne.Properties; #endif using System.Collections.Generic; using S1API.Internal.Utils; using S1API.Items; - namespace S1API.Products { /// - /// Represents the definition of a Meth product in the product framework. + /// Represents the definition of a meth product within the ScheduleOne product framework. /// - /// - /// Provides methods for retrieving properties and creating instances of meth products. This class extends the base functionality provided by . - /// public class MethDefinition : ProductDefinition { /// - /// INTERNAL: Strongly typed access to S1MethDefinition, representing the Il2CppScheduleOne.Product.MethDefinition entity. + /// INTERNAL: Strongly typed access to S1MethDefinition. /// internal S1MethDefinition S1MethDefinition => CrossType.As(S1ItemDefinition); /// - /// Represents the definition of a Meth product. + /// Represents the definition of a Meth product in the product framework. /// internal MethDefinition(S1MethDefinition definition) : base(definition) @@ -37,10 +33,10 @@ internal MethDefinition(S1MethDefinition definition) } /// - /// Creates an instance of this meth product with a specified quantity. + /// Creates an instance of this meth product with the specified quantity. /// - /// The quantity of the meth product to instantiate. Defaults to 1 if not provided. - /// An instance of the meth product as a . + /// The quantity of the product instance to create. Defaults to 1 if not specified. + /// An instance of representing the created meth product. public override ItemInstance CreateInstance(int quantity = 1) => new ProductInstance(CrossType.As( S1MethDefinition.GetDefaultInstance(quantity))); @@ -48,27 +44,16 @@ public override ItemInstance CreateInstance(int quantity = 1) => /// /// Retrieves the list of properties associated with the meth product definition. /// - /// A list of properties that belong to the meth product definition. -#if IL2CPPMELON - public List GetProperties() -#else - public List GetProperties() -#endif + /// A list of properties defined for the meth product. + public List GetProperties() { -#if IL2CPPMELON - var result = new List(); -#else - var result = new List(); -#endif + var result = new List(); var list = S1MethDefinition?.Properties; if (list != null) { for (int i = 0; i < list.Count; i++) - { result.Add(list[i]); - } } - return result; } } diff --git a/S1API/Products/ProductInstance.cs b/S1API/Products/ProductInstance.cs index bd15181f..ee3a45bf 100644 --- a/S1API/Products/ProductInstance.cs +++ b/S1API/Products/ProductInstance.cs @@ -1,73 +1,72 @@ #if (IL2CPPMELON ) using S1Product = Il2CppScheduleOne.Product; -using Properties = Il2CppScheduleOne.Properties; +using S1Properties = Il2CppScheduleOne.Properties; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1Product = ScheduleOne.Product; using Properties = ScheduleOne.Properties; #endif using System.Collections.Generic; using S1API.Internal.Utils; -using ItemInstance = S1API.Items.ItemInstance; - +using S1ItemInstance = S1API.Items.ItemInstance; namespace S1API.Products { /// /// Represents an instance of a product in the game. /// - public class ProductInstance : ItemInstance + /// + /// This class defines specific properties and behaviors for a product instance, + /// such as quality, packaging, and definition, derived from the S1API's item instance structure. + /// + public class ProductInstance : S1ItemInstance { /// - /// INTERNAL: Reference to the in-game product item instance. + /// INTERNAL: Provides access to the underlying in-game product item instance. /// internal S1Product.ProductItemInstance S1ProductInstance => CrossType.As(S1ItemInstance); /// - /// Represents an instance of a product derived from an in-game product item instance. + /// Represents an instance of a product, derived from a specific in-game product item instance, + /// with additional properties for packaging, quality, and product definition. /// - internal ProductInstance(S1Product.ProductItemInstance productInstance) : base(productInstance) + internal ProductInstance(S1Product.ProductItemInstance productInstance) + : base(productInstance) { } /// /// Indicates whether the product instance has applied packaging. /// - public bool IsPackaged => - S1ProductInstance.AppliedPackaging; + public bool IsPackaged => S1ProductInstance.AppliedPackaging; /// - /// Represents the packaging details currently applied to the product instance, if any. + /// Provides access to the packaging information applied to the product, + /// represented as a specific packaging definition instance. /// public PackagingDefinition AppliedPackaging => new PackagingDefinition(S1ProductInstance.AppliedPackaging); /// - /// Represents the quality tier of the product instance. + /// Represents the quality level of the product instance. /// /// - /// The quality indicates the standard or grade of the product, ranging through predefined levels such as Trash, Poor, Standard, Premium, and Heavenly. + /// Quality levels provide a measure of the product's grading, ranging from "Trash" to "Heavenly". /// public Quality Quality => S1ProductInstance.Quality.ToAPI(); - // Expose the underlying definition's properties (if S1ProductInstance.Definition is available) - - // Add Definition property if you don't have one yet - -#if IL2CPPMELON - public IReadOnlyList Properties => Definition.Properties; - public ProductDefinition Definition => new ProductDefinition(S1ProductInstance.Definition); -#else /// - /// Represents the collection of properties associated with the product. + /// Gets the definition of the product associated with this instance. /// - public IReadOnlyList Properties => Definition.Properties; + public ProductDefinition Definition => new ProductDefinition(S1ProductInstance.Definition); /// - /// Represents the definition of a product in the game, including its core properties. + /// Gets the list of properties associated with the product definition. /// - public ProductDefinition Definition => new ProductDefinition(S1ProductInstance.Definition); - -#endif - + /// + /// This property provides an unmodifiable list of properties associated + /// with the underlying product definition. Each property represents + /// a specific characteristic or behavior of the corresponding product. + /// + public IReadOnlyList Properties => Definition.Properties; } } diff --git a/S1API/Products/WeedDefinition.cs b/S1API/Products/WeedDefinition.cs index 395d82cf..fb4c0164 100644 --- a/S1API/Products/WeedDefinition.cs +++ b/S1API/Products/WeedDefinition.cs @@ -1,11 +1,11 @@ #if (IL2CPPMELON) using Il2CppScheduleOne.Product; using S1WeedDefinition = Il2CppScheduleOne.Product.WeedDefinition; -using Properties = Il2CppScheduleOne.Properties; +using S1Properties = Il2CppScheduleOne.Properties; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using ScheduleOne.Product; using S1WeedDefinition = ScheduleOne.Product.WeedDefinition; -using Properties = ScheduleOne.Properties; +using S1Properties = ScheduleOne.Properties; #endif using S1API.Internal.Utils; @@ -15,29 +15,19 @@ namespace S1API.Products { /// - /// Represents a specific type of weed product definition. This class extends the functionality of - /// to include details specific to weed products. + /// Represents a specific type of weed product definition. /// - /// - /// This class provides methods and properties to work with weed-related product definitions, - /// including creating product instances and accessing weed-specific properties. - /// public class WeedDefinition : ProductDefinition { /// - /// Represents the definition of a weed product in the ScheduleOne API. - /// Provides access to underlying data and functionalities specific to weed products. + /// INTERNAL: Strongly typed reference to Schedule One's WeedDefinition. /// internal S1WeedDefinition S1WeedDefinition => CrossType.As(S1ItemDefinition); /// - /// Represents a specific type of product definition for weed products in the API. + /// Represents a specific type of weed product definition. /// - /// - /// This class acts as a wrapper for `Il2CppScheduleOne.Product.WeedDefinition`, - /// providing additional functionality and a specific type for handling weed items. - /// internal WeedDefinition(S1WeedDefinition definition) : base(definition) { @@ -47,37 +37,24 @@ internal WeedDefinition(S1WeedDefinition definition) /// Creates an instance of the product with the specified quantity. /// /// The quantity of the product to create. Defaults to 1 if not specified. - /// An instance of representing the created product. + /// An representing the created product instance with the specified quantity. public override ItemInstance CreateInstance(int quantity = 1) => new ProductInstance(CrossType.As( S1WeedDefinition.GetDefaultInstance(quantity))); /// - /// Gets a list of properties associated with the current weed definition. + /// Retrieves a list of properties associated with this weed definition. /// - /// - /// A list of properties of type Il2CppScheduleOne.Properties.Property - /// associated with the weed definition. If no properties are found, - /// an empty list is returned. - /// -#if IL2CPPMELON - public List GetProperties() -#else - public List GetProperties() -#endif + /// A list of properties of type S1Properties.Property that are linked with the current weed definition, or an empty list if none are found. + public List GetProperties() { -#if IL2CPPMELON - var result = new List(); -#else - var result = new List(); - #endif + var result = new List(); var list = S1WeedDefinition?.Properties; + if (list != null) { for (int i = 0; i < list.Count; i++) - { result.Add(list[i]); - } } return result; From 641f48fa8b0d4f675011d39ecd6ab5eaf25a379f Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Sat, 17 May 2025 01:18:55 +0200 Subject: [PATCH 22/28] fix: build for melon --- S1API/Products/ProductInstance.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/S1API/Products/ProductInstance.cs b/S1API/Products/ProductInstance.cs index ee3a45bf..150c6e72 100644 --- a/S1API/Products/ProductInstance.cs +++ b/S1API/Products/ProductInstance.cs @@ -3,7 +3,7 @@ using S1Properties = Il2CppScheduleOne.Properties; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1Product = ScheduleOne.Product; -using Properties = ScheduleOne.Properties; +using S1Properties = ScheduleOne.Properties; #endif using System.Collections.Generic; using S1API.Internal.Utils; From 84bd747058617b963ac34bbc8d75dee21f7c413a Mon Sep 17 00:00:00 2001 From: Omar Akermi Date: Sat, 17 May 2025 11:09:10 +0200 Subject: [PATCH 23/28] fix: directory creation instead of log --- S1API/Internal/Patches/QuestPatches.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/S1API/Internal/Patches/QuestPatches.cs b/S1API/Internal/Patches/QuestPatches.cs index eb985cfb..189019f5 100644 --- a/S1API/Internal/Patches/QuestPatches.cs +++ b/S1API/Internal/Patches/QuestPatches.cs @@ -3,13 +3,11 @@ using S1Datas = Il2CppScheduleOne.Persistence.Datas; using S1Quests = Il2CppScheduleOne.Quests; using S1Persistence = Il2CppScheduleOne.Persistence; -using Il2CppScheduleOne.DevUtilities; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1Loaders = ScheduleOne.Persistence.Loaders; using S1Datas = ScheduleOne.Persistence.Datas; using S1Quests = ScheduleOne.Quests; using S1Persistence = ScheduleOne.Persistence; -using ScheduleOne.DevUtilities; #endif #if (IL2CPPMELON || IL2CPPBEPINEX) using Il2CppSystem.Collections.Generic; @@ -105,7 +103,7 @@ private static void QuestsLoaderLoad(S1Loaders.QuestsLoader __instance, string m if (!Directory.Exists(moddedQuestsPath)) { - Logger.Warning("[S1API] No Modded/Quests folder found: " + moddedQuestsPath); + Directory.CreateDirectory(moddedQuestsPath); return; } 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 24/28] 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 25/28] 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 26/28] 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 27/28] 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 28/28] 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); } ///