Skip to content

v0.4.4f6 compatibility#57

Merged
ifBars merged 3 commits intoifBars:betafrom
HazDS:haz/v0.4.4f6-compat
Mar 15, 2026
Merged

v0.4.4f6 compatibility#57
ifBars merged 3 commits intoifBars:betafrom
HazDS:haz/v0.4.4f6-compat

Conversation

@HazDS
Copy link
Collaborator

@HazDS HazDS commented Mar 14, 2026

Update S1API for Schedule 1 v0.4.4f6

Summary

Schedule 1 v0.4.4f6 introduced a new ScheduleOne.Core assembly, splitting base item/entity types out of Assembly-CSharp. This PR updates S1API to compile against the new game version for both Il2CppMelon and MonoMelon configurations.

Changes

Assembly References

  • Added ScheduleOne.Core.dll (Mono) and Il2CppScheduleOne.Core.dll (IL2CPP) references to the project file. Base types like BaseItemDefinition, BaseItemInstance, and core enums now live in this assembly.

Namespace Migrations

  • EItemCategory and ELegalStatus moved from ScheduleOne.ItemFramework to ScheduleOne.Core.Items.Framework. Added S1CoreItemFramework using alias across all 7 affected files.

API Renames

  • MusicPlayerMusicManager in LoadingScreenPatches.cs (singleton class renamed in game).
  • NPC.SetPanicked()NPC.SetPanicked_Server() in NPC.cs (method now uses FishNet [ServerRpc] pattern).

Removed Properties

  • Keywords and LabelDisplayColor were removed from item definitions in v0.4.4f6. Stripped all references from ItemDefinition, BuildableItemDefinition, and the Storable/Additive/Buildable/Clothing builder classes.

Files Changed (12)

File Change
S1API.csproj Added ScheduleOne.Core assembly references
Items/ItemDefinition.cs Core namespace alias, removed Keywords/LabelDisplayColor
Items/BuildableItemDefinition.cs Removed LabelDisplayColor property
Items/StorableItemDefinitionBuilder.cs Core namespace alias, removed Keywords/LabelDisplayColor
Items/AdditiveDefinitionBuilder.cs Core namespace alias, removed Keywords/LabelDisplayColor
Items/BuildableItemDefinitionBuilder.cs Core namespace alias, removed Keywords/LabelDisplayColor
Items/ClothingItemDefinitionBuilder.cs Core namespace alias, removed Keywords/LabelDisplayColor
Shops/Shop.cs Core namespace alias for EItemCategory
Growing/SeedCreator.cs Core namespace alias for EItemCategory
Entities/NPC.cs SetPanicked → SetPanicked_Server
Internal/Patches/LoadingScreenPatches.cs MusicPlayer → MusicManager
Internal/Patches/NPCPatches.cs Already modified (pre-existing)

Release Notes

  • Updated S1API to compile against Schedule 1 v0.4.4f6 for both Il2CppMelon and MonoMelon
  • Added references to new ScheduleOne.Core assemblies (ScheduleOne.Core.dll for Mono and Il2CppScheduleOne.Core.dll for IL2CPP)
  • Migrated namespace usage: EItemCategory and ELegalStatus now sourced from ScheduleOne.Core.Items.Framework instead of ScheduleOne.ItemFramework, with S1CoreItemFramework alias introduced across 7 files
  • Renamed MusicPlayer to MusicManager in loading screen patch handling
  • Updated NPC panic state handling: SetPanicked() replaced with SetPanicked_Server() for server-side consistency
  • Removed deprecated item properties: Keywords and LabelDisplayColor from ItemDefinition and all builder classes (StorableItemDefinitionBuilder, AdditiveDefinitionBuilder, BuildableItemDefinitionBuilder, ClothingItemDefinitionBuilder)
  • Refactored NPC revival logic to use local, non-networked state updates via reflection while bypassing networked SyncVar calls

Changes by Author

Author Lines Added Lines Removed
HazDS 62 143

Schedule 1 v0.4.4f6 introduced a new `ScheduleOne.Core` assembly, splitting base item/entity types out of `Assembly-CSharp`.
@HazDS HazDS requested a review from ifBars March 14, 2026 14:01
@coderabbitai
Copy link

coderabbitai bot commented Mar 14, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8a7dde87-cf98-4475-a8cb-14c28fcbd9ec

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The pull request migrates the S1API codebase from S1ItemFramework to S1CoreItemFramework for item category and legal status enums, removes public API methods for label color and keyword customization, updates NPC revival mechanics to use local reflection-based state changes instead of networked calls, adds ScheduleOne.Core dependencies, and updates audio management to use MusicManager instead of MusicPlayer.

Changes

Cohort / File(s) Summary
Framework Migration
S1API/Items/AdditiveDefinitionBuilder.cs, S1API/Items/BuildableItemDefinitionBuilder.cs, S1API/Items/ClothingItemDefinitionBuilder.cs, S1API/Items/ItemDefinition.cs, S1API/Items/StorableItemDefinitionBuilder.cs, S1API/Growing/SeedCreator.cs, S1API/Shops/Shop.cs
Consistent migration from S1ItemFramework to S1CoreItemFramework for category and legal status enum references across item definition builders and related classes.
Public API Surface Reduction
S1API/Items/BuildableItemDefinition.cs, S1API/Items/BuildableItemDefinitionBuilder.cs, S1API/Items/ClothingItemDefinitionBuilder.cs, S1API/Items/ItemDefinition.cs, S1API/Items/StorableItemDefinitionBuilder.cs
Removal of public properties LabelDisplayColor and Keywords, and fluent builder methods WithLabelColor() and WithKeywords() across item definition classes and builders.
NPC Entity Logic
S1API/Entities/NPC.cs, S1API/Internal/Patches/NPCPatches.cs
Panic state now invokes SetPanicked_Server() instead of SetPanicked(); custom NPC revival changed from skipping S1API NPCs to implementing local reflection-based state restoration (IsDead, IsKnockedOut, Health) with event emission, avoiding networked SyncVar calls.
Core Dependencies & Audio
S1API/S1API.csproj, S1API/Internal/Patches/LoadingScreenPatches.cs
Addition of ScheduleOne.Core project references for Il2Cpp and Mono build configurations; replacement of MusicPlayer dependency with MusicManager in loading screen close flow.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Bug fixes #50: Modifies NPCPatches.cs to add ResetState for clearing static collections, directly related to the NPC revival logic changes in this PR.

Suggested reviewers

  • ifBars

Poem

🐰 A rabbit hops through frameworks old,
Switching Core where items fold,
Reflection whispers, networks rest,
Revival happens, bugs are blessed!
APIs pruned, dependencies grown—
The warren's stronger, fully known! 🌱

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'v0.4.4f6 compatibility' is concise (22 characters), clearly related to the main objective of updating S1API for v0.4.4f6 compatibility, and accurately describes the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 88.89% which is sufficient. The required threshold is 70.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@S1API/Entities/NPC.cs`:
- Around line 1722-1723: The public Panic() should check the server context
before calling the server-only method: modify NPC.Panic() to call SafeIsServer()
and only invoke S1NPC.SetPanicked_Server() when SafeIsServer() returns true
(otherwise no-op or early return); locate the Panic() method and replace the
direct call to S1NPC.SetPanicked_Server() with this guard to prevent client-side
invocation from reaching server-only code.

In `@S1API/Internal/Patches/NPCPatches.cs`:
- Around line 1582-1605: The patch currently always returns false (skipping
original revive) even when the local revive operations fail; change the method
so it only returns false when all local operations succeed. Capture the boolean
results from Utils.ReflectionUtils.TrySetFieldOrProperty calls for
"<Health>k__BackingField", "IsDead", and "IsKnockedOut", and check that
baseNpc.Behaviour.DeadBehaviour?.Disable(),
baseNpc.Behaviour.UnconsciousBehaviour?.Disable(), and
__instance.onRevive?.Invoke() execute without error; if any reflection call
returns false or an exception is thrown, log the failure and return true to
allow the original revive path to run, otherwise return false to skip the
original. Use the existing symbols (__instance,
Utils.ReflectionUtils.TrySetFieldOrProperty, baseNpc.Behaviour,
__instance.onRevive) when implementing the checks.

In `@S1API/S1API.csproj`:
- Around line 58-59: The Il2Cpp reference for Il2CppScheduleOne.Core.dll
currently uses a bare Reference Include ("Il2CppScheduleOne.Core.dll") and needs
an explicit HintPath like the Mono entries; update the Reference element that
uses $(Il2CppAssembliesPath)\Il2CppScheduleOne.Core.dll (the Reference Include
for Il2CppScheduleOne.Core) to the same pattern used by the Mono references by
adding a nested HintPath that points to
$(Il2CppAssembliesPath)\Il2CppScheduleOne.Core.dll so MSBuild can reliably
resolve the assembly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 07660fae-102a-433f-81fc-f30181430b6a

📥 Commits

Reviewing files that changed from the base of the PR and between c2f34a4 and 2a6b7ab.

📒 Files selected for processing (12)
  • S1API/Entities/NPC.cs
  • S1API/Growing/SeedCreator.cs
  • S1API/Internal/Patches/LoadingScreenPatches.cs
  • S1API/Internal/Patches/NPCPatches.cs
  • S1API/Items/AdditiveDefinitionBuilder.cs
  • S1API/Items/BuildableItemDefinition.cs
  • S1API/Items/BuildableItemDefinitionBuilder.cs
  • S1API/Items/ClothingItemDefinitionBuilder.cs
  • S1API/Items/ItemDefinition.cs
  • S1API/Items/StorableItemDefinitionBuilder.cs
  • S1API/S1API.csproj
  • S1API/Shops/Shop.cs
💤 Files with no reviewable changes (1)
  • S1API/Items/BuildableItemDefinition.cs

Comment on lines +1722 to +1723
public void Panic() =>
S1NPC.SetPanicked();
S1NPC.SetPanicked_Server();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Call sites of NPC.Panic() =="
rg -n --type=cs -C3 '\.Panic\s*\('

echo
echo "== Direct uses of SetPanicked_Server() =="
rg -n --type=cs -C4 '\bSetPanicked_Server\s*\('

echo
echo "== Legacy SetPanicked() usages (if any remain) =="
rg -n --type=cs -C2 '\bSetPanicked\s*\('

Repository: ifBars/S1API

Length of output: 87


🏁 Script executed:

find . -name "NPC.cs" -type f

Repository: ifBars/S1API

Length of output: 79


🏁 Script executed:

wc -l ./S1API/Entities/NPC.cs

Repository: ifBars/S1API

Length of output: 84


🏁 Script executed:

sed -n '1720,1730p' ./S1API/Entities/NPC.cs

Repository: ifBars/S1API

Length of output: 415


🏁 Script executed:

rg -n --type=cs 'SafeIsServer' -A2 -B2

Repository: ifBars/S1API

Length of output: 270


🏁 Script executed:

sed -n '1535,1545p' ./S1API/Entities/NPC.cs

Repository: ifBars/S1API

Length of output: 334


🏁 Script executed:

rg -n 'Panic()' ./S1API/Entities/NPC.cs

Repository: ifBars/S1API

Length of output: 787


🏁 Script executed:

rg -n --type=cs '\.Panic\(\)' --glob='!NPC.cs'

Repository: ifBars/S1API

Length of output: 38


🏁 Script executed:

rg -n 'Panic\(' --type=cs --glob='!NPC.cs'

Repository: ifBars/S1API

Length of output: 38


🏁 Script executed:

rg -n 'SetPanicked_Server' --type=cs

Repository: ifBars/S1API

Length of output: 122


🏁 Script executed:

rg -n 'SetPanicked_Server' --type=cs -A2 -B2

Repository: ifBars/S1API

Length of output: 307


🏁 Script executed:

grep -n 'SafeIsServer()' ./S1API/Entities/NPC.cs

Repository: ifBars/S1API

Length of output: 103


🏁 Script executed:

rg -n '_Server\(\)' --type=cs ./S1API/Entities/NPC.cs | head -20

Repository: ifBars/S1API

Length of output: 100


🏁 Script executed:

sed -n '1700,1750p' ./S1API/Entities/NPC.cs

Repository: ifBars/S1API

Length of output: 2103


🏁 Script executed:

sed -n '1700,1780p' ./S1API/Entities/NPC.cs

Repository: ifBars/S1API

Length of output: 3363


🏁 Script executed:

rg -n 'SafeIsServer\(\)' --type=cs -B5 -A5

Repository: ifBars/S1API

Length of output: 722


🏁 Script executed:

rg -n 'SafeIsServer()' --type=cs -v 'private static bool'

Repository: ifBars/S1API

Length of output: 115


Add server-context guard to Panic() method to prevent client-side breakage.

The Panic() method is a public API that directly calls SetPanicked_Server(), a server-only method. This creates a mismatch: the public method can be invoked from client contexts, but the underlying implementation will fail outside server execution. The codebase already provides SafeIsServer() for exactly this purpose.

Suggested safeguard
-        public void Panic() =>
-            S1NPC.SetPanicked_Server();
+        public void Panic()
+        {
+            if (!SafeIsServer())
+                return;
+
+            S1NPC.SetPanicked_Server();
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void Panic() =>
S1NPC.SetPanicked();
S1NPC.SetPanicked_Server();
public void Panic()
{
if (!SafeIsServer())
return;
S1NPC.SetPanicked_Server();
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@S1API/Entities/NPC.cs` around lines 1722 - 1723, The public Panic() should
check the server context before calling the server-only method: modify
NPC.Panic() to call SafeIsServer() and only invoke S1NPC.SetPanicked_Server()
when SafeIsServer() returns true (otherwise no-op or early return); locate the
Panic() method and replace the direct call to S1NPC.SetPanicked_Server() with
this guard to prevent client-side invocation from reaching server-only code.

Comment on lines +1582 to 1605
try
{
// Local-only revive: set state flags via reflection (read-only properties)
Utils.ReflectionUtils.TrySetFieldOrProperty(__instance, "IsDead", false);
Utils.ReflectionUtils.TrySetFieldOrProperty(__instance, "IsKnockedOut", false);

// Set health backing field directly to bypass SyncVar setter
Utils.ReflectionUtils.TrySetFieldOrProperty(
__instance, "<Health>k__BackingField", __instance.MaxHealth);

// 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();
}
catch (Exception ex)
{
MelonLogger.Warning($"[S1API] Revive guard failed for custom NPC: {ex.Message}");
}

return false; // skip original to avoid SyncVar/networking calls
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t skip original revive when the guard path fails.

On Line 1604 the patch always returns false, even if local mutations fail (exception or unsuccessful reflection set). That can leave the NPC unrecovered while still bypassing the original revive path.

💡 Suggested fail-safe patch
-            try
+            bool localReviveApplied = false;
+            try
             {
                 // Local-only revive: set state flags via reflection (read-only properties)
-                Utils.ReflectionUtils.TrySetFieldOrProperty(__instance, "IsDead", false);
-                Utils.ReflectionUtils.TrySetFieldOrProperty(__instance, "IsKnockedOut", false);
+                bool isDeadSet = Utils.ReflectionUtils.TrySetFieldOrProperty(__instance, "IsDead", false);
+                bool isKoSet = Utils.ReflectionUtils.TrySetFieldOrProperty(__instance, "IsKnockedOut", false);

                 // Set health backing field directly to bypass SyncVar setter
-                Utils.ReflectionUtils.TrySetFieldOrProperty(
+                bool healthSet = Utils.ReflectionUtils.TrySetFieldOrProperty(
                     __instance, "<Health>k__BackingField", __instance.MaxHealth);

+                if (!(isDeadSet && isKoSet && healthSet))
+                {
+                    MelonLogger.Warning("[S1API] Revive guard could not apply all local state updates; falling back to original Revive().");
+                    return true;
+                }
+
                 // Disable behaviours locally (non-networked equivalent of Disable_Server)
-                baseNpc.Behaviour.DeadBehaviour?.Disable();
-                baseNpc.Behaviour.UnconsciousBehaviour?.Disable();
+                baseNpc?.Behaviour?.DeadBehaviour?.Disable();
+                baseNpc?.Behaviour?.UnconsciousBehaviour?.Disable();

                 // Fire revive event so downstream listeners still react
                 __instance.onRevive?.Invoke();
+                localReviveApplied = true;
             }
             catch (Exception ex)
             {
                 MelonLogger.Warning($"[S1API] Revive guard failed for custom NPC: {ex.Message}");
+                return true;
             }

-            return false; // skip original to avoid SyncVar/networking calls
+            return !localReviveApplied ? true : false; // skip original only on successful local revive
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@S1API/Internal/Patches/NPCPatches.cs` around lines 1582 - 1605, The patch
currently always returns false (skipping original revive) even when the local
revive operations fail; change the method so it only returns false when all
local operations succeed. Capture the boolean results from
Utils.ReflectionUtils.TrySetFieldOrProperty calls for "<Health>k__BackingField",
"IsDead", and "IsKnockedOut", and check that
baseNpc.Behaviour.DeadBehaviour?.Disable(),
baseNpc.Behaviour.UnconsciousBehaviour?.Disable(), and
__instance.onRevive?.Invoke() execute without error; if any reflection call
returns false or an exception is thrown, log the failure and return true to
allow the original revive path to run, otherwise return false to skip the
original. Use the existing symbols (__instance,
Utils.ReflectionUtils.TrySetFieldOrProperty, baseNpc.Behaviour,
__instance.onRevive) when implementing the checks.

Comment on lines 58 to 59
<Reference Include="$(Il2CppAssembliesPath)\Il2CppScheduleOne.Core.dll" />
<Reference Include="$(Il2CppAssembliesPath)\Il2Cppmscorlib.dll" />
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Core-related references in S1API.csproj =="
rg -n "ScheduleOne\\.Core|Il2CppScheduleOne\\.Core|MonoAssembliesPath|Il2CppAssembliesPath" S1API/S1API.csproj

echo
echo "== Build props that define assembly paths =="
fd -HI '.*build\.props$' -x rg -n "MonoAssembliesPath|Il2CppAssembliesPath|ScheduleOne\\.Core|0\\.4\\.4f6" {}

echo
echo "== Workflow references to assembly bundle/version wiring =="
fd -HI '.*\.(yml|yaml)$' .github -x rg -n "ScheduleOne|assemblies|MonoAssembliesPath|Il2CppAssembliesPath|0\\.4\\.4f6" {}

Repository: ifBars/S1API

Length of output: 26202


Add HintPath for IL2CPP Il2CppScheduleOne.Core reference to match Mono reference pattern.

Line 58 uses a simple Include with a property path, which lacks explicit hint path resolution. The Mono configuration (lines 84–85) already demonstrates the correct pattern using HintPath. Update line 58 to follow the same structure for consistency and stable assembly resolution:

Suggested csproj adjustment
-        <Reference Include="$(Il2CppAssembliesPath)\Il2CppScheduleOne.Core.dll" />
+        <Reference Include="Il2CppScheduleOne.Core">
+            <HintPath>$(Il2CppAssembliesPath)\Il2CppScheduleOne.Core.dll</HintPath>
+        </Reference>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Reference Include="$(Il2CppAssembliesPath)\Il2CppScheduleOne.Core.dll" />
<Reference Include="$(Il2CppAssembliesPath)\Il2Cppmscorlib.dll" />
<Reference Include="Il2CppScheduleOne.Core">
<HintPath>$(Il2CppAssembliesPath)\Il2CppScheduleOne.Core.dll</HintPath>
</Reference>
<Reference Include="$(Il2CppAssembliesPath)\Il2Cppmscorlib.dll" />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@S1API/S1API.csproj` around lines 58 - 59, The Il2Cpp reference for
Il2CppScheduleOne.Core.dll currently uses a bare Reference Include
("Il2CppScheduleOne.Core.dll") and needs an explicit HintPath like the Mono
entries; update the Reference element that uses
$(Il2CppAssembliesPath)\Il2CppScheduleOne.Core.dll (the Reference Include for
Il2CppScheduleOne.Core) to the same pattern used by the Mono references by
adding a nested HintPath that points to
$(Il2CppAssembliesPath)\Il2CppScheduleOne.Core.dll so MSBuild can reliably
resolve the assembly.

@ifBars ifBars self-assigned this Mar 15, 2026
@ifBars ifBars added game update Fixes the API for a Schedule 1 game update beta A game update on the beta & alternate-beta steam branches labels Mar 15, 2026
@ifBars ifBars changed the base branch from stable to beta March 15, 2026 08:38
@ifBars ifBars deleted the branch ifBars:beta March 15, 2026 09:06
@ifBars ifBars closed this Mar 15, 2026
@ifBars ifBars reopened this Mar 15, 2026
@ifBars
Copy link
Owner

ifBars commented Mar 15, 2026

I did not mean to close the PR, had to re-make the beta branch and it auto-closed the pr 😆

@ifBars ifBars merged commit 5179859 into ifBars:beta Mar 15, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

beta A game update on the beta & alternate-beta steam branches game update Fixes the API for a Schedule 1 game update

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants