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)
{