diff --git a/S1API/Entities/NPC.cs b/S1API/Entities/NPC.cs index c00a364..3f29399 100644 --- a/S1API/Entities/NPC.cs +++ b/S1API/Entities/NPC.cs @@ -1719,8 +1719,13 @@ public void LerpScale(float scale, float lerpTime) => /// /// Causes the NPC to become panicked. /// - public void Panic() => - S1NPC.SetPanicked(); + public void Panic() + { + if (!SafeIsServer()) + return; + + S1NPC.SetPanicked_Server(); + } /// /// Causes the NPC to stop panicking, if they are currently. diff --git a/S1API/Growing/SeedCreator.cs b/S1API/Growing/SeedCreator.cs index 2dbe704..115af40 100644 --- a/S1API/Growing/SeedCreator.cs +++ b/S1API/Growing/SeedCreator.cs @@ -1,10 +1,12 @@ #if (IL2CPPMELON) using S1Growing = Il2CppScheduleOne.Growing; using S1ItemFramework = Il2CppScheduleOne.ItemFramework; +using S1CoreItemFramework = Il2CppScheduleOne.Core.Items.Framework; using S1Registry = Il2CppScheduleOne.Registry; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1Growing = ScheduleOne.Growing; using S1ItemFramework = ScheduleOne.ItemFramework; +using S1CoreItemFramework = ScheduleOne.Core.Items.Framework; using S1Registry = ScheduleOne.Registry; #endif @@ -32,7 +34,7 @@ public static SeedDefinition CreateSeed( seed.Name = name; seed.Description = description; seed.StackLimit = stackLimit; - seed.Category = S1ItemFramework.EItemCategory.Agriculture; + seed.Category = S1CoreItemFramework.EItemCategory.Agriculture; // if (icon != null) // { diff --git a/S1API/Internal/Patches/LoadingScreenPatches.cs b/S1API/Internal/Patches/LoadingScreenPatches.cs index c3e04ca..1ac7d15 100644 --- a/S1API/Internal/Patches/LoadingScreenPatches.cs +++ b/S1API/Internal/Patches/LoadingScreenPatches.cs @@ -211,7 +211,7 @@ private static void CloseLoadingScreenDirectly(S1UI.LoadingScreen loadingScreen) { ReflectionUtils.TrySetFieldOrProperty(loadingScreen, "IsOpen", false); - var musicPlayer = S1DevUtilities.Singleton.Instance; + var musicPlayer = S1DevUtilities.Singleton.Instance; if (musicPlayer != null) { musicPlayer.SetTrackEnabled("Loading Screen", enabled: false); diff --git a/S1API/Internal/Patches/NPCPatches.cs b/S1API/Internal/Patches/NPCPatches.cs index 61964d8..4f65e34 100644 --- a/S1API/Internal/Patches/NPCPatches.cs +++ b/S1API/Internal/Patches/NPCPatches.cs @@ -1579,8 +1579,36 @@ private static bool NPCHealth_Revive_Prefix(S1NPCs.NPCHealth __instance) if (apiNpc == null || !apiNpc.IsCustomNPC) return true; // use original for base NPCs - // Skip S1API NPCs for now - return false; + try + { + bool healthSet = Utils.ReflectionUtils.TrySetFieldOrProperty( + __instance, "k__BackingField", __instance.MaxHealth); + bool isDeadSet = Utils.ReflectionUtils.TrySetFieldOrProperty(__instance, "IsDead", false); + bool isKnockedOutSet = Utils.ReflectionUtils.TrySetFieldOrProperty(__instance, "IsKnockedOut", false); + + if (!healthSet || !isDeadSet || !isKnockedOutSet) + { + MelonLogger.Warning( + $"[S1API] Revive guard reflection failed for custom NPC '{baseNpc?.ID ?? ""}' " + + $"(Health={healthSet}, IsDead={isDeadSet}, IsKnockedOut={isKnockedOutSet}); falling back to original revive."); + return true; + } + + // Disable behaviours locally (non-networked equivalent of Disable_Server) + baseNpc.Behaviour.DeadBehaviour?.Disable(); + baseNpc.Behaviour.UnconsciousBehaviour?.Disable(); + + // Fire revive event so downstream listeners still react + __instance.onRevive?.Invoke(); + + return false; // skip original to avoid SyncVar/networking calls + } + catch (Exception ex) + { + MelonLogger.Warning( + $"[S1API] Revive guard failed for custom NPC '{baseNpc?.ID ?? ""}': {ex.Message}. Falling back to original revive."); + return true; + } } /// diff --git a/S1API/Items/AdditiveDefinitionBuilder.cs b/S1API/Items/AdditiveDefinitionBuilder.cs index 0f52ec4..d78cb39 100644 --- a/S1API/Items/AdditiveDefinitionBuilder.cs +++ b/S1API/Items/AdditiveDefinitionBuilder.cs @@ -1,9 +1,11 @@ #if (IL2CPPMELON) using S1ItemFramework = Il2CppScheduleOne.ItemFramework; +using S1CoreItemFramework = Il2CppScheduleOne.Core.Items.Framework; using S1Registry = Il2CppScheduleOne.Registry; using S1Storage = Il2CppScheduleOne.Storage; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1ItemFramework = ScheduleOne.ItemFramework; +using S1CoreItemFramework = ScheduleOne.Core.Items.Framework; using S1Registry = ScheduleOne.Registry; using S1Storage = ScheduleOne.Storage; #endif @@ -39,11 +41,10 @@ internal AdditiveDefinitionBuilder() _definition.StackLimit = 10; _definition.BasePurchasePrice = 10f; _definition.ResellMultiplier = 0.5f; - _definition.Category = S1ItemFramework.EItemCategory.Agriculture; - _definition.legalStatus = S1ItemFramework.ELegalStatus.Legal; + _definition.Category = S1CoreItemFramework.EItemCategory.Agriculture; + _definition.legalStatus = S1CoreItemFramework.ELegalStatus.Legal; _definition.AvailableInDemo = true; _definition.UsableInFilters = true; - _definition.LabelDisplayColor = Color.white; // Provide a minimal StoredItem placeholder so the field is never null in tooling/inspectors. _storedItemPlaceholder = new GameObject("S1API_DefaultStoredItem"); @@ -82,10 +83,8 @@ private void CopyPropertiesFrom(S1ItemFramework.AdditiveDefinition source) _definition.Description = source.Description; _definition.Category = source.Category; _definition.StackLimit = source.StackLimit; - _definition.Keywords = source.Keywords; _definition.AvailableInDemo = source.AvailableInDemo; _definition.UsableInFilters = source.UsableInFilters; - _definition.LabelDisplayColor = source.LabelDisplayColor; _definition.Icon = source.Icon; _definition.legalStatus = source.legalStatus; _definition.PickpocketDifficultyMultiplier = source.PickpocketDifficultyMultiplier; @@ -116,7 +115,7 @@ public AdditiveDefinitionBuilder WithBasicInfo(string id, string name, string de _definition.ID = id; _definition.Name = name; _definition.Description = description; - _definition.Category = (S1ItemFramework.EItemCategory)category; + _definition.Category = (S1CoreItemFramework.EItemCategory)category; var displayName = string.IsNullOrEmpty(name) ? id : name; if (!string.IsNullOrEmpty(displayName)) @@ -164,25 +163,7 @@ public AdditiveDefinitionBuilder WithPricing(float basePurchasePrice, float rese /// public AdditiveDefinitionBuilder WithLegalStatus(LegalStatus status) { - _definition.legalStatus = (S1ItemFramework.ELegalStatus)status; - return this; - } - - /// - /// Sets the color of the label displayed in UI. - /// - public AdditiveDefinitionBuilder WithLabelColor(Color color) - { - _definition.LabelDisplayColor = color; - return this; - } - - /// - /// Sets keywords used for filtering and searching this additive. - /// - public AdditiveDefinitionBuilder WithKeywords(params string[] keywords) - { - _definition.Keywords = keywords; + _definition.legalStatus = (S1CoreItemFramework.ELegalStatus)status; return this; } diff --git a/S1API/Items/BuildableItemDefinition.cs b/S1API/Items/BuildableItemDefinition.cs index 4ef3a29..65b0ca6 100644 --- a/S1API/Items/BuildableItemDefinition.cs +++ b/S1API/Items/BuildableItemDefinition.cs @@ -41,14 +41,6 @@ public BuildSoundType BuildSoundType set => S1BuildableItemDefinition.BuildSoundType = (S1ItemFramework.BuildableItemDefinition.EBuildSoundType)value; } - /// - /// The color displayed on the item's label in the UI. - /// - public new Color LabelDisplayColor - { - get => S1BuildableItemDefinition.LabelDisplayColor; - set => S1BuildableItemDefinition.LabelDisplayColor = value; - } } /// diff --git a/S1API/Items/BuildableItemDefinitionBuilder.cs b/S1API/Items/BuildableItemDefinitionBuilder.cs index ec2e9ae..3c4d1a8 100644 --- a/S1API/Items/BuildableItemDefinitionBuilder.cs +++ b/S1API/Items/BuildableItemDefinitionBuilder.cs @@ -1,8 +1,10 @@ #if (IL2CPPMELON) using S1ItemFramework = Il2CppScheduleOne.ItemFramework; +using S1CoreItemFramework = Il2CppScheduleOne.Core.Items.Framework; using S1Registry = Il2CppScheduleOne.Registry; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1ItemFramework = ScheduleOne.ItemFramework; +using S1CoreItemFramework = ScheduleOne.Core.Items.Framework; using S1Registry = ScheduleOne.Registry; #endif @@ -30,11 +32,10 @@ internal BuildableItemDefinitionBuilder() _definition.StackLimit = 10; _definition.BasePurchasePrice = 10f; _definition.ResellMultiplier = 0.5f; - _definition.Category = S1ItemFramework.EItemCategory.Furniture; - _definition.legalStatus = S1ItemFramework.ELegalStatus.Legal; + _definition.Category = S1CoreItemFramework.EItemCategory.Furniture; + _definition.legalStatus = S1CoreItemFramework.ELegalStatus.Legal; _definition.AvailableInDemo = true; _definition.UsableInFilters = true; - _definition.LabelDisplayColor = Color.white; _definition.BuildSoundType = S1ItemFramework.BuildableItemDefinition.EBuildSoundType.Wood; } @@ -57,10 +58,8 @@ private void CopyPropertiesFrom(S1ItemFramework.BuildableItemDefinition source) _definition.Description = source.Description; _definition.Category = source.Category; _definition.StackLimit = source.StackLimit; - _definition.Keywords = source.Keywords; _definition.AvailableInDemo = source.AvailableInDemo; _definition.UsableInFilters = source.UsableInFilters; - _definition.LabelDisplayColor = source.LabelDisplayColor; _definition.Icon = source.Icon; _definition.legalStatus = source.legalStatus; _definition.PickpocketDifficultyMultiplier = source.PickpocketDifficultyMultiplier; @@ -144,7 +143,7 @@ public BuildableItemDefinitionBuilder WithPricing(float basePurchasePrice, float /// The builder instance for fluent chaining. public BuildableItemDefinitionBuilder WithCategory(ItemCategory category) { - _definition.Category = (S1ItemFramework.EItemCategory)category; + _definition.Category = (S1CoreItemFramework.EItemCategory)category; return this; } @@ -159,28 +158,6 @@ public BuildableItemDefinitionBuilder WithStackLimit(int limit) return this; } - /// - /// Sets keywords used for filtering and searching this item. - /// - /// Array of keywords. - /// The builder instance for fluent chaining. - public BuildableItemDefinitionBuilder WithKeywords(params string[] keywords) - { - _definition.Keywords = keywords; - return this; - } - - /// - /// Sets the color of the label displayed in UI. - /// - /// The color to use for the item label. - /// The builder instance for fluent chaining. - public BuildableItemDefinitionBuilder WithLabelColor(Color color) - { - _definition.LabelDisplayColor = color; - return this; - } - /// /// Sets the legal status of the item. /// @@ -188,7 +165,7 @@ public BuildableItemDefinitionBuilder WithLabelColor(Color color) /// The builder instance for fluent chaining. public BuildableItemDefinitionBuilder WithLegalStatus(LegalStatus status) { - _definition.legalStatus = (S1ItemFramework.ELegalStatus)status; + _definition.legalStatus = (S1CoreItemFramework.ELegalStatus)status; return this; } diff --git a/S1API/Items/ClothingItemDefinitionBuilder.cs b/S1API/Items/ClothingItemDefinitionBuilder.cs index db47905..e6bb6f0 100644 --- a/S1API/Items/ClothingItemDefinitionBuilder.cs +++ b/S1API/Items/ClothingItemDefinitionBuilder.cs @@ -1,11 +1,13 @@ #if (IL2CPPMELON) using S1Clothing = Il2CppScheduleOne.Clothing; using S1ItemFramework = Il2CppScheduleOne.ItemFramework; +using S1CoreItemFramework = Il2CppScheduleOne.Core.Items.Framework; using S1Registry = Il2CppScheduleOne.Registry; using Il2CppCollections = Il2CppSystem.Collections.Generic; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1Clothing = ScheduleOne.Clothing; using S1ItemFramework = ScheduleOne.ItemFramework; +using S1CoreItemFramework = ScheduleOne.Core.Items.Framework; using S1Registry = ScheduleOne.Registry; using Il2CppCollections = System.Collections.Generic; #endif @@ -34,12 +36,11 @@ internal ClothingItemDefinitionBuilder() _definition.StackLimit = 10; _definition.BasePurchasePrice = 10f; _definition.ResellMultiplier = 0.5f; - _definition.Category = S1ItemFramework.EItemCategory.Clothing; - _definition.legalStatus = S1ItemFramework.ELegalStatus.Legal; + _definition.Category = S1CoreItemFramework.EItemCategory.Clothing; + _definition.legalStatus = S1CoreItemFramework.ELegalStatus.Legal; _definition.AvailableInDemo = true; _definition.UsableInFilters = true; - _definition.LabelDisplayColor = Color.white; - + // Clothing-specific defaults _definition.Slot = S1Clothing.EClothingSlot.Head; _definition.ApplicationType = S1Clothing.EClothingApplicationType.Accessory; @@ -72,8 +73,6 @@ internal ClothingItemDefinitionBuilder(S1Clothing.ClothingDefinition source) _definition.legalStatus = source.legalStatus; _definition.AvailableInDemo = source.AvailableInDemo; _definition.UsableInFilters = source.UsableInFilters; - _definition.LabelDisplayColor = source.LabelDisplayColor; - _definition.Keywords = source.Keywords; _definition.StoredItem = source.StoredItem; _definition.Equippable = source.Equippable; @@ -215,28 +214,6 @@ public ClothingItemDefinitionBuilder WithPricing(float basePurchasePrice, float return this; } - /// - /// Sets keywords used for filtering and searching this item. - /// - /// Array of keywords. - /// The builder instance for fluent chaining. - public ClothingItemDefinitionBuilder WithKeywords(params string[] keywords) - { - _definition.Keywords = keywords; - return this; - } - - /// - /// Sets the color of the label displayed in UI. - /// - /// The color to use for the item label. - /// The builder instance for fluent chaining. - public ClothingItemDefinitionBuilder WithLabelColor(Color color) - { - _definition.LabelDisplayColor = color; - return this; - } - /// /// Builds the clothing item definition, registers it with the game's registry, and returns a wrapper. /// diff --git a/S1API/Items/ItemDefinition.cs b/S1API/Items/ItemDefinition.cs index ab8a912..e5454af 100644 --- a/S1API/Items/ItemDefinition.cs +++ b/S1API/Items/ItemDefinition.cs @@ -1,7 +1,9 @@ #if (IL2CPPMELON) using S1ItemFramework = Il2CppScheduleOne.ItemFramework; +using S1CoreItemFramework = Il2CppScheduleOne.Core.Items.Framework; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1ItemFramework = ScheduleOne.ItemFramework; +using S1CoreItemFramework = ScheduleOne.Core.Items.Framework; #endif using UnityEngine; @@ -74,7 +76,7 @@ public int StackLimit public ItemCategory Category { get => (ItemCategory)S1ItemDefinition.Category; - set => S1ItemDefinition.Category = (S1ItemFramework.EItemCategory)value; + set => S1ItemDefinition.Category = (S1CoreItemFramework.EItemCategory)value; } /// @@ -101,28 +103,10 @@ public bool AvailableInDemo public LegalStatus LegalStatus { get => (LegalStatus)S1ItemDefinition.legalStatus; - set => S1ItemDefinition.legalStatus = (S1ItemFramework.ELegalStatus)value; + set => S1ItemDefinition.legalStatus = (S1CoreItemFramework.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[] Keywords - { - get => S1ItemDefinition.Keywords; - set => S1ItemDefinition.Keywords = value; - } - /// /// Creates a new item instance with the specified quantity. /// diff --git a/S1API/Items/StorableItemDefinitionBuilder.cs b/S1API/Items/StorableItemDefinitionBuilder.cs index 21e8131..4f36e79 100644 --- a/S1API/Items/StorableItemDefinitionBuilder.cs +++ b/S1API/Items/StorableItemDefinitionBuilder.cs @@ -1,10 +1,12 @@ #if (IL2CPPMELON) using S1ItemFramework = Il2CppScheduleOne.ItemFramework; +using S1CoreItemFramework = Il2CppScheduleOne.Core.Items.Framework; using S1Registry = Il2CppScheduleOne.Registry; using S1StationFramework = Il2CppScheduleOne.StationFramework; using S1Storage = Il2CppScheduleOne.Storage; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1ItemFramework = ScheduleOne.ItemFramework; +using S1CoreItemFramework = ScheduleOne.Core.Items.Framework; using S1Registry = ScheduleOne.Registry; using S1StationFramework = ScheduleOne.StationFramework; using S1Storage = ScheduleOne.Storage; @@ -50,11 +52,10 @@ internal StorableItemDefinitionBuilder() _definition.StackLimit = 10; _definition.BasePurchasePrice = 10f; _definition.ResellMultiplier = 0.5f; - _definition.Category = S1ItemFramework.EItemCategory.Tools; - _definition.legalStatus = S1ItemFramework.ELegalStatus.Legal; + _definition.Category = S1CoreItemFramework.EItemCategory.Tools; + _definition.legalStatus = S1CoreItemFramework.ELegalStatus.Legal; _definition.AvailableInDemo = true; _definition.UsableInFilters = true; - _definition.LabelDisplayColor = Color.white; // Provide a minimal StoredItem placeholder so the field is never null in tooling/inspectors. _storedItemPlaceholder = new GameObject("S1API_DefaultStoredItem"); @@ -78,7 +79,7 @@ public StorableItemDefinitionBuilder WithBasicInfo(string id, string name, strin _definition.ID = id; _definition.Name = name; _definition.Description = description; - _definition.Category = (S1ItemFramework.EItemCategory)category; + _definition.Category = (S1CoreItemFramework.EItemCategory)category; // Update the underlying ScriptableObject name for clarity in inspectors/debuggers. var displayName = string.IsNullOrEmpty(name) ? id : name; @@ -135,29 +136,7 @@ public StorableItemDefinitionBuilder WithPricing(float basePurchasePrice, float /// The builder instance for fluent chaining. public StorableItemDefinitionBuilder WithLegalStatus(LegalStatus status) { - _definition.legalStatus = (S1ItemFramework.ELegalStatus)status; - return this; - } - - /// - /// Sets the color of the label displayed in UI. - /// - /// The color to use for the item label. - /// The builder instance for fluent chaining. - public StorableItemDefinitionBuilder WithLabelColor(Color color) - { - _definition.LabelDisplayColor = color; - return this; - } - - /// - /// Sets keywords used for filtering and searching this item. - /// - /// Array of keywords. - /// The builder instance for fluent chaining. - public StorableItemDefinitionBuilder WithKeywords(params string[] keywords) - { - _definition.Keywords = keywords; + _definition.legalStatus = (S1CoreItemFramework.ELegalStatus)status; return this; } diff --git a/S1API/S1API.csproj b/S1API/S1API.csproj index f10716f..b875997 100644 --- a/S1API/S1API.csproj +++ b/S1API/S1API.csproj @@ -55,6 +55,9 @@ + + $(Il2CppAssembliesPath)\Il2CppScheduleOne.Core.dll + @@ -80,6 +83,9 @@ $(MonoAssembliesPath)/Assembly-CSharp.dll + + $(MonoAssembliesPath)/ScheduleOne.Core.dll + $(MonoAssembliesPath)/UnityEngine.dll diff --git a/S1API/Shops/Shop.cs b/S1API/Shops/Shop.cs index 4a52bf6..ac71f75 100644 --- a/S1API/Shops/Shop.cs +++ b/S1API/Shops/Shop.cs @@ -1,9 +1,11 @@ #if (IL2CPPMELON) using S1UIShop = Il2CppScheduleOne.UI.Shop; using S1ItemFramework = Il2CppScheduleOne.ItemFramework; +using S1CoreItemFramework = Il2CppScheduleOne.Core.Items.Framework; #elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) using S1UIShop = ScheduleOne.UI.Shop; using S1ItemFramework = ScheduleOne.ItemFramework; +using S1CoreItemFramework = ScheduleOne.Core.Items.Framework; #endif using System.Collections.Generic; @@ -63,7 +65,7 @@ public bool HasItem(string itemId) /// True if the shop sells at least one item in this category. public bool SellsCategory(ItemCategory category) { - var s1Category = (S1ItemFramework.EItemCategory)category; + var s1Category = (S1CoreItemFramework.EItemCategory)category; foreach (var listing in S1ShopInterface.Listings) {