Skip to content

fix(npc): restore behaviour lifecycle across runtimes - #258

Merged
ifBars merged 3 commits into
stablefrom
releases/3.1.14
Aug 11, 2026
Merged

fix(npc): restore behaviour lifecycle across runtimes#258
ifBars merged 3 commits into
stablefrom
releases/3.1.14

Conversation

@ifBars

@ifBars ifBars commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Summary

  • keep custom NPC behaviour-stack GameObjects active while NPCBehaviour manages their internal Enabled and Active states
  • repair dealer and customer deal-attendance setup and preserve the inactive lifecycle for schedule-owned NPCAction objects
  • normalize game-member access where Mono fields are exposed as IL2CPP wrapper properties
  • harden ReflectionUtils for inherited instance/static members and backing fields
  • bump the project and Melon metadata versions to 3.1.14

Root cause

Schedule I 0.4.6 moved customer deal attendance from the schedule-owned NPCSignal_WaitForDelivery path to the NPCBehaviour stack. S1API migrated the component types, but dealer, smoke-break, and graffiti behaviour objects were still created with the legacy schedule-action convention of activeSelf = false.

The behaviour manager can select and tick a registered behaviour independently of its GameObject activation state. When DealerAttendDealBehaviour.OnActiveTick() reached the handover, Unity rejected its coroutine because the component's GameObject was inactive.

The adjacent dual-runtime audit also confirmed that several raw reflection paths assumed the Mono assembly shape. In the IL2CPP interop assemblies, those native fields are generated as managed properties, and native arrays/delegates require their IL2CPP representations.

The audit compared the 3.1.0 migration, current Mono and IL2CPP assemblies, and the upstream 0.4.6f11 change:

k073l/s1-codearchiver@3973cfc

Closes #257.

Cross-runtime audit

All raw GetField call sites in the API project were reviewed. Applicable game-wrapper mismatches were corrected for:

  • dealer attend behaviour, overflow slots, recruitment callbacks, and message UI creation state
  • customer contract callbacks and nested contract data
  • NPC schedule-action npc and schedule references
  • customer affinity restoration
  • runtime item cleanup registrations
  • land-vehicle price updates
  • TV home-screen close state
  • internal law intensity

Remaining raw field access is Mono-only, explicitly paired with an IL2CPP property path, or targets S1API/managed Unity types rather than generated game wrappers.

Validation

Mono

  • build: 0 warnings, 0 errors
  • full contract suite: 560/560 passed

IL2CPP

  • build: 0 warnings, 0 errors
  • full contract suite: 549/549 passed

Additional checks

  • added regression coverage for instance/static field-to-property shapes and inherited non-public static members
  • git diff --check passed
  • project <Version> and MelonInfo both report 3.1.14
  • local DocFX was attempted but produced no output and exceeded the 120-second bounded run; the exact lingering DocFX process was stopped and no generated changes remained
  • no in-game dealer-contract smoke was run; runtime evidence is the issue stack trace plus current Mono/IL2CPP assembly inspection

Compatibility

  • public/protected API inventory: no public symbol changes
  • source and binary compatibility are unchanged
  • save formats, stable IDs, and network payloads are unchanged
  • existing schedule actions retain their prior inactive-GameObject lifecycle
  • behaviour changes are limited to components owned by the native NPCBehaviour stack and broken cross-runtime member access

Release policy

After this PR merges into stable, fast-forward releases/3.1.14 to the stable merge commit and tag that exact shared commit as v3.1.14.

Summary by CodeRabbit

  • Bug Fixes

    • Improved compatibility across supported runtime environments, including Mono and IL2CPP.
    • Fixed behavior-object lifecycle handling so related NPC activities remain active and function correctly.
    • Improved reliability for NPC schedules, dealer interactions, customer data, vehicle pricing, law intensity, item cleanup, and TV interface behavior.
    • Added safer handling for inherited and non-public game properties.
  • Chores

    • Updated the S1API version from 3.1.13 to 3.1.14.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ifBars, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 51 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b0a508ee-8a98-4d21-970b-9f626c57ce8e

📥 Commits

Reviewing files that changed from the base of the PR and between 6896831 and 97c3dfa.

📒 Files selected for processing (3)
  • S1API.Tests/Internal/Utils/ManagedEventRegistrationTrackerTests.cs
  • S1API/Entities/NPCDealer.cs
  • S1API/Internal/Utils/ManagedEventRegistrationTracker.cs
📝 Walkthrough

Walkthrough

Changes

Cross-runtime reflection and dealer lifecycle updates

Layer / File(s) Summary
Shared reflection access
S1API/Internal/Utils/ReflectionUtils.cs, S1API.Tests/Internal/Utils/ReflectionUtilsTests.cs
Reflection utilities now support instance and static fields and properties across type hierarchies and compiler-generated backing fields. Tests cover Mono-style fields, IL2CPP-style properties, and inherited static members.
Behavior activation and prefab wiring
S1API/Entities/NPCPrefabBuilder.cs, S1API/Entities/NPC.cs, S1API/Entities/NPCCustomer.cs, S1API.Tests/Entities/DealerLifecyclePolicyTests.cs
Prefab behavior objects remain active according to a shared setting. Schedule and contract wiring use shared reflection helpers.
IL2CPP dealer runtime handling
S1API/Entities/NPCDealer.cs
Dealer event subscription and removal now support Mono and IL2CPP delegates. Dealer behavior and overflow-slot initialization use runtime-compatible access.
Reflection consumer updates and release metadata
S1API/Internal/Patches/*, S1API/Items/ItemManager.cs, S1API/Law/LawController.cs, S1API/Vehicles/LandVehicle.cs, S1API/S1API.cs, S1API/S1API.csproj
Additional runtime integrations use shared reflection helpers. Assembly and package versions change from 3.1.13 to 3.1.14.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant NPCDealer
  participant NativeRecruitmentDelegate
  participant DealerStaticEvent
  NPCDealer->>NativeRecruitmentDelegate: convert callback when required
  NPCDealer->>DealerStaticEvent: subscribe platform-specific delegate
  DealerStaticEvent-->>NPCDealer: invoke recruitment callback
  NPCDealer->>DealerStaticEvent: remove platform-specific delegate
Loading

Possibly related PRs

Suggested labels: bug, npcs

Suggested reviewers: hazds

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes address issue [#257] by restoring dealer behavior lifecycle handling and fixing IL2CPP-compatible member access.
Out of Scope Changes check ✅ Passed The code changes support the stated lifecycle, cross-runtime compatibility, validation, and versioning objectives without unrelated scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title clearly summarizes the primary change: restoring NPC behavior lifecycle handling across Mono and IL2CPP runtimes.
Description check ✅ Passed The description covers the change, compatibility, Mono and IL2CPP validation, runtime evidence, and release impact, with only a minor documentation-section omission.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

@ifBars ifBars changed the title fix(npc): keep behaviour objects active fix(npc): restore behaviour lifecycle across runtimes Aug 11, 2026
@ifBars
ifBars marked this pull request as ready for review August 11, 2026 10:28
@ifBars ifBars self-assigned this Aug 11, 2026
@ifBars ifBars added this to the v3.1.14 milestone Aug 11, 2026
@ifBars ifBars added the bug Something isn't working label Aug 11, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@S1API/Entities/NPCDealer.cs`:
- Around line 846-848: Update the event subscription logic around
_dealerRecruitedHandlers so every add operation creates and stores a distinct
native wrapper, including duplicate Action values. Ensure remove deletes only
one matching registration while retaining any remaining duplicates, and add a
compatibility test covering duplicate add followed by a single remove.
- Around line 748-762: Update the fallback creation in the
DealerAttendDealBehaviour setup to create its GameObject inactive, assign the
behavior’s beh owner and npcBehaviour.Npc references consistently with
NPCPrefabBuilder.SetBehaviourRefs, then activate it only after both references
are initialized. Preserve the existing activation state and naming/priority
assignments for the prefab path.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0fdb5e36-b2b2-4c58-bc1c-79b1b689fcb6

📥 Commits

Reviewing files that changed from the base of the PR and between 95105b6 and 6896831.

📒 Files selected for processing (14)
  • S1API.Tests/Entities/DealerLifecyclePolicyTests.cs
  • S1API.Tests/Internal/Utils/ReflectionUtilsTests.cs
  • S1API/Entities/NPC.cs
  • S1API/Entities/NPCCustomer.cs
  • S1API/Entities/NPCDealer.cs
  • S1API/Entities/NPCPrefabBuilder.cs
  • S1API/Internal/Patches/NPCPatches.cs
  • S1API/Internal/Patches/TVPatches.cs
  • S1API/Internal/Utils/ReflectionUtils.cs
  • S1API/Items/ItemManager.cs
  • S1API/Law/LawController.cs
  • S1API/S1API.cs
  • S1API/S1API.csproj
  • S1API/Vehicles/LandVehicle.cs

Comment thread S1API/Entities/NPCDealer.cs
Comment thread S1API/Entities/NPCDealer.cs Outdated
@ifBars
ifBars merged commit 7b03732 into stable Aug 11, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Dealers from custom npc mods don't work

1 participant