Repository navigation
[BUG] IL2CPP joining client throws in Customer.Awake and duplicates a custom dealer #357
Description
Summary
An IL2CPP multiplayer client joining a host with four automatic custom NPC roles throws NullReferenceException in native Customer.Awake and ends up with a duplicate custom dealer ID. The strict four-NPC validation gate fails. This was reproduced with PR #353 alone, without either optimization PR (#354 or #355).
Environment
- Schedule I beta 0.4.7f11, Steam build 25770926, updated and validated with SteamCMD.
- S1API PR fix: keep packaging-content patches working on game 0.4.7f11 #353 exact head:
8c22c42e2a3703320fc6af58424d0109957cbb84(beta.8 lineage plus the packaging compatibility change). - IL2CPP, MelonLoader 0.7.3, fresh f11 interop wrappers.
- Two isolated installations with S1API and the same disposable minimal probe registering plain, customer, dealer, and supplier NPC roles.
- LAN test used GSE Steam emulation with distinct peer identities and the native lobby/FishNet path. Real Steam transport was not tested.
- Copied save fixture originally created on 0.4.6f8 Alternate. An unrelated custom product descriptor with no installed provider was removed only from the disposable save copy before co-op testing. A newly created f11 save was not tested.
Steps to reproduce
- Register one automatic custom NPC for each of the four roles on both peers.
- Start the IL2CPP host and load the copied save. Confirm four custom NPCs are present.
- Start a second IL2CPP process with a distinct Steam identity and join the host through the native lobby path.
- Allow the joining client to follow the host's save load into Main.
- Check the client's exception output and the custom NPC registry for all four expected IDs and duplicate entries.
Expected behavior
The client reaches normal gameplay with one instance of each custom NPC and no Customer.Awake exception.
Observed behavior
The host completes its four-role validation. The joining client reaches Main but reports NullReferenceException in native Customer.Awake. Its custom NPC registry contains five entries instead of four, including a duplicate s1api_pr_dealernpc. The client's strict gate times out:
FAIL|Role=sender|Phase=Gameplay1|Reason=Timed out; Scene=Main|NPCs=5
The exception and duplicate entry were observed together; their causal relationship has not been established.
Controls and investigation limits
The #353-only control and the #353+#354+#355 integration reproduce the same exception, duplicate dealer ID, and terminal client failure. Mono two-peer validation passes with distinct identities, shared two-member lobby membership, correct host/client network state, and four expected NPCs on both peers.
This establishes reproduction without the optimization PRs. It does not identify the responsible game/S1API lifecycle path or the first affected version. The latest published prerelease was not separately exercised for this scenario. Complete raw logs and the disposable probe were removed after validation; the exception method, duplicate ID, and terminal marker above were retained.
Acceptance criteria
Isolate the client spawn/initialization failure, explain the duplicate dealer entry, and verify one instance of each role on an IL2CPP joining client without Customer.Awake exceptions. Include a fresh-save control and preserve passing Mono multiplayer behavior.
Activity
ifBars commentedon Oct 8, 2026
@Diffuin Investigate please
diffuin commentedon Oct 8, 2026
Issue investigation
Confidence: Medium
The leading hypothesis is incomplete Customer preparation before client Awake. Dealer conversion can also retain two NPC components, explaining an extra client wrapper while the host wraps only one. An unguarded consolidated loader provides a competing explanation if the duplicates are separate objects. The smallest likely fix is to prepare missing Customer data on the inactive prefab and remove a replaced dealer donor after rewiring. The exact native dereference and duplicate object identities still require runtime evidence.
Recommended next steps
Open questions
Evidence and validation
Evidence inspected
Validation performed
Runtime validation remaining
Diffuin run details
codexgpt-6.1-solxhigh(Luna advisor: complexity (high); baseline coupled source-backed request)01a119c0-90da-7573-a53c-28c2ebfcfcb4AI notice: Generated with AI assistance and not guaranteed accurate. Verify findings and plans against the current source and runtime.
ifBars commentedon Oct 8, 2026
The baseline f11 client reproduction now identifies both paths. Customer.Awake enters with customerData and DefaultAffinityData missing on S1API_CustomerNpc, then throws in Awake_UserLogic. The dealer appears twice in NPC.All on the client, with the same GameObject (-413470) and two different native component IDs (-413474 and -413498). Host count is four; client count is five. Both peers report a two-member lobby and the expected host/client network state.
I will seed missing customer data on the inactive custom prefab using the existing runtime fallback defaults, preserving donor data and explicit WithCustomerDefaults configuration. Dealer conversion will remove the replaced donor component after rewiring, matching the existing supplier conversion. No registry deduplication or client-authority changes are needed for this reproduction. Validation will cover both runtimes and then combine this fix with the portrait fix and the two optimization PRs.
ifBars commentedon Oct 9, 2026
Fixed by #359 and shipped in 3.2.1-beta.9.
Inactive customer prefabs now receive missing fallback CustomerData before the joining client's native Awake. Existing data and explicit configuration are preserved. Dealer conversion removes the replaced donor NPC component after references are rewired.
Final beta.9 validation passes on Mono and IL2CPP game beta 0.4.7f11 with MelonLoader 0.7.3: two local peers with separate identities, first load and same-process reload/rejoin, normal gameplay on both peers, four custom NPC roles, and one native NPC component per object. Customer data and affinity exist before Awake, with omitted spending defaults still 100/400; the original customer Awake exception and duplicate dealer registration are absent. Closing as completed. Real Steam transport remains untested, and existing native Contacts warnings remain.