Skip to content

Move party vessel spawning to always-active PartyVesselSpawner#129

Open
Shombith03 wants to merge 371 commits into
claude/add-party-game-mode-Go0YHfrom
claude/fix-party-game-mode-aALL3
Open

Move party vessel spawning to always-active PartyVesselSpawner#129
Shombith03 wants to merge 371 commits into
claude/add-party-game-mode-Go0YHfrom
claude/fix-party-game-mode-aALL3

Conversation

@Shombith03

Copy link
Copy Markdown
Contributor

Summary

Refactored party mode vessel spawning to use a dedicated PartyVesselSpawner component on the always-active PartyGameManager, instead of calling spawn methods on ServerPlayerVesselInitializer (SPVI) which lives on disabled environment GameObjects. This ensures ClientRpcs are only invoked on NetworkBehaviours registered with Netcode at startup, preventing "RPC called on unregistered NetworkBehaviour" errors.

Key Changes

  • New PartyVesselSpawner class: Dedicated NetworkBehaviour that handles all vessel spawning and repositioning for party mode

    • SpawnVesselsForParty(): Spawns host player vessel and AI opponents on first round
    • RepositionForNewRound(): Repositions existing vessels for subsequent rounds
    • InitializeAllPlayersForParty_ClientRpc(): Safe ClientRpc on always-active GameObject
  • Removed party spawning from SPVI: Deleted SpawnVesselsForParty() and SpawnPlayerThenAIForParty() methods from ServerPlayerVesselInitializer that were unsafe to call via RPC

  • Updated PartyGameController:

    • Now references PartyVesselSpawner instead of calling SPVI spawn methods
    • Changed SPVI to always use InertMode (no longer switches between SpawnMode/InertMode)
    • Extracts spawn origins from SPVI via GetSpawnOriginsFromEnv() and passes to spawner
    • Delegates repositioning to PartyVesselSpawner.RepositionForNewRound()

Implementation Details

  • PartyVesselSpawner spawns player vessel first, waits 1 second, then spawns AI opponents with staggered spawn indices
  • AI vessel types are picked from game captain definitions when available, falling back to Sparrow
  • All player/vessel initialization happens via InitializePlayerAndVessel() which waits for network objects to be registered before calling initialization methods
  • SPVI now only provides spawn origin data; environment setup remains unchanged

https://claude.ai/code/session_01Piy2uQvUaeqfJhG3eaR4Dj

YsKhan61 and others added 30 commits February 26, 2026 02:45
…ors-LTKde

Add missing assembly definition dependencies
ProfileModal was routing through the disabled PlayFab PlayerDataController
instead of the active UGS PlayerDataService, so name changes were silently
dropped. ArcadeProfileWidget and ProfileIconSelectView lacked a singleton
fallback for PlayerDataService (whose Awake detaches from hierarchy via
DontDestroyOnLoad, breaking serialized Inspector refs) and gated saves on
IsInitialized when the service is usable as soon as CurrentProfile exists.

Default display name changed from static "Pilot" to "Pilot#XXXX" with a
random 4-digit suffix so new players get unique names out of the box.

https://claude.ai/code/session_018uU3m2F5XVUMoynp8jxdM4
In party mode, environment GameObjects are deactivated during network
spawn and reactivated per round via SetActive. This leaves
NetworkCrystalManager.IsSpawned potentially false after reactivation
(same root cause as RPCs being unregistered on mini-game controllers).

When IsSpawned is false:
- OnEnable skipped event subscription (gated on IsSpawned)
- OnTurnStarted returned early (IsServer false when !IsSpawned)
- No positions generated → no crystals spawned

Fix adds IsPartyMode flag to CrystalManager (set via
SetPartyModeOnEnvironment alongside controllers and cinematics) and
falls back to direct local spawning when IsSpawned is unreliable:

- OnEnable: subscribe when IsPartyMode even if !IsSpawned
- OnTurnStarted: use SpawnBatchIfMissing() fallback (like
  LocalCrystalManager) when IsPartyMode && !IsSpawned
- OnResetForReplay/OnTurnEnded: destroy crystals directly
- RespawnCrystal/ExplodeCrystal: bypass ServerRpc/ClientRpc

This mirrors the established party mode pattern where
MultiplayerDomainGamesController.OnReadyClicked_ already bypasses
RPCs with a direct local countdown for the same reason.

https://claude.ai/code/session_01Piy2uQvUaeqfJhG3eaR4Dj
Add NativeShare.Runtime, Reflex, Unity.Cinemachine, Unity.Services.Multiplayer,
and Unity.Entities.UI references to fix CS0246 compilation errors in
ShareByEmail, NetworkMonitor, WildlifeBlitzEndGameCinematicController,
PrismImplosionPoolManager, GameDataSO, and FloraConfigurationSO.

https://claude.ai/code/session_01UF2ffnmtP5fKPgDTEe2YhA
…s-FUUh6

Add missing assembly definition references for new features
Resolved 73 merge conflicts:
- 50+ files: kept using CosmicShore.Models.Enums from app-shell-polish
  (enum namespace reorganization)
- Kept Reflex DI [Inject] pattern over singleton Instance pattern
- Kept SOAP event-driven auth over AuthenticationController.Instance
- Removed deprecated MiniGame.cs and ProtectMissionGame.cs (deleted in app-shell-polish)
- Accepted WidescreenLayoutAdapter.cs in relocated path
- Kept HEAD's BoidSimulationController (development had garbled merge artifacts)
- Combined PlayFab disabled flag with SOAP-style network subscriptions
- Kept development's PrismScale property in SpawnableEllipsoid (needed for compilation)

https://claude.ai/code/session_01RGWp6PVjTsB34uTBcFZnEP
Root causes:
- IsPartyMode && !IsSpawned fallback never triggered because IsSpawned
  stays true after SetActive(false) — all party mode code paths fell
  through to the unreliable NetworkList/RPC mechanism
- Both HexRace and CrystalCapture use spawnOnClientReady=true, which
  fires OnClientReady at 0.5s (round 2+) before Cell.Initialize at 1s,
  causing null refs in SnowChangerManager

Fixes:
- NetworkCrystalManager: remove !IsSpawned from ALL party mode checks,
  always use direct local spawning via SpawnBatchIfMissing()
- In party mode, subscribe to OnMiniGameTurnStarted instead of
  OnClientReady to ensure Cell is initialized before crystal spawn
- Add unsubscribe-before-subscribe guard against double subscriptions
- SnowChangerManager: add null safety for cellData.Config and
  cellData.CellTransform, stay subscribed until cell is ready

https://claude.ai/code/session_01Piy2uQvUaeqfJhG3eaR4Dj
CosmicShore.Runtime: +Unity.Services.Analytics, Unity.Collections,
  Unity.TextMeshPro, Unity.Mathematics, Unity.Burst, Unity.Entities,
  Unity.Netcode.Components
CosmicShore.Utility: +Reflex, Unity.Cinemachine,
  Unity.Services.Multiplayer, Unity.Entities.UI
CosmicShore.Editor: +PlayFab
CosmicShore.DialogueSystem: +Unity.TextMeshPro

https://claude.ai/code/session_01RGWp6PVjTsB34uTBcFZnEP
…s-JfEWt

Optimize prism VFX and AOE damage with batched Jobs, add HyperSea skybox
Systematically updated namespace declarations across 1019 files to align
with their directory paths under Assets/_Scripts/ and Assets/FTUE/:

- Changed 651+ namespace declarations to match folder hierarchy
  (e.g., CosmicShore.Game -> CosmicShore.Game.Ship.ShipActions)
- Added namespaces to 200+ files that previously had none
- Updated using directives across the codebase to reference new namespaces
- Fixed FTUE scripts (split CosmicShore.FTUE into Data/Drivers/Handlers/etc.)
- Handled folder names with spaces (e.g., "Abstract Effect Types" -> AbstractEffectTypes)
- Skipped third-party packages and ~ChoppingBlock deprecated code

https://claude.ai/code/session_01QxKnfNHPy1woQ9chAkZGB5
…-1ZgoJ

Claude/add missing sounds 1 zgo j
…spaces-61yHn

Refactor namespace organization and update import statements
- PrismFactory.cs: CosmicShore.Utilities → CosmicShore.Utility.SOAP.ScriptableEventWithReturn
- ThemeManagerDataContainerSO.cs: CosmicShore.Utilities → CosmicShore.Models.ScriptableObjects
- Remove nonexistent CosmicShore.Soap using from 4 files (LifeFormsKilledScoring,
  SinglePlayerWildlifeBlitzController, SingleplayerWildlifeBlitzTurnMonitor,
  SparrowDebuffByRhinoDangerPrismEffectSO)

https://claude.ai/code/session_01GfuGtrE29i2FvfaY3o57Ea
…ors-YSMoK

Clean up unused imports and update namespace references
Remove unused using directives (CosmicShore.Game.Managers, CosmicShore.Game.Environment.FlowField, CosmicShore.Game.Ship) from RoundStats.cs and IRoundStats.cs. Fully qualify Editor base class as UnityEditor.Editor in SSUScripts editors to resolve namespace shadowing.

https://claude.ai/code/session_01MNcgikkBy86nmNR2uQpZey
…ors-7ybMl

Clean up unused imports and fully qualify Editor base class
The previous namespace update commit erroneously inserted the
`namespace CosmicShore.Utility.DataPersistence` declaration inside the
Load<T> method body instead of wrapping the class. This corrupted the
brace structure and broke compilation. Fix by properly wrapping the
class in the namespace and adding the using directive to all 6 callers.

https://claude.ai/code/session_01Pd8XCQjdTmbzhNjxu2bBvP
…o9Boc

Refactor DataAccessor into namespace and fix import statements
Qualify bare 'Editor' as 'UnityEditor.Editor' in three SSU Interactive
Editor files where the namespace segment 'Editor' shadowed the type.

Move NetworkMonitor.cs from CosmicShore.Utility assembly to
CosmicShore.Runtime assembly (Services folder) so it can access SOAP
types that live in Runtime via .asmref redirect.

https://claude.ai/code/session_01A1k4zWuunagSpsfG9yKoKK
Refactor: Move NetworkMonitor to Services namespace and fix Editor class references
DOFillAmount is an extension method from DOTweenModuleUI.cs which compiles
into the default assembly. BoostFillAnimator lives in the CosmicShore.Utility
asmdef, which cannot reference the default assembly. Using DOTween.To() from
the core DLL achieves the same result and is accessible from any assembly.

https://claude.ai/code/session_018XSMyynxCrPbEnWD4XFXLg
Refactor BoostFillAnimator to use DOTween.To for fill animation
Move misplaced namespace declarations to properly wrap class bodies in
VesselTransformer, DriftTrailAction, ScoutTrailPrismScaler,
FullAutoActionExecutor, and SpawnableWaypointTrack. Remove invalid
`using CosmicShore.DialogueSystem.Models` directives from
IDialogueService and IDialogueViewResolver (types already in scope
via containing namespace).

https://claude.ai/code/session_016mfEPyHGnW6yyWX5EoRs7J
…ors-iAjEt

Fix namespace declarations positioning in C# files
…nces

- Remove 'using CosmicShore.Core;' from 23 files (namespace doesn't exist,
  types are in CosmicShore.Models.Enums which is already imported)
- Remove 'using CosmicShore.Editor;' from 3 runtime files (editor-only
  assembly not accessible from runtime)
- Remove 'using CosmicShore.DialogueSystem.Editor;' from 4 runtime files
  (editor-only assembly not accessible from runtime)
- Fix 'using CosmicShore.App.UI;' → 'using CosmicShore.UI;' in 2 files
  (ScreenSwitcher lives in CosmicShore.UI)
- Remove unused 'using CosmicShore.App.UI.Controllers;' from OverviewPanelUI
- Remove invalid 'using Unity.Multiplayer.Samples.Utilities;' from
  NetworkVesselClientCache (types are local in CosmicShore.Game.Ship)
- Delete duplicate ShipSelectionSlot struct (defined in both
  ShipSelectionSlot.cs and inline in ShipSelectionView.cs)

https://claude.ai/code/session_017Bxu4xkBksyonCKup2TLvK
The ScriptablePartyData directory and its 7 scripts were committed without
.meta files, as was HostConnectionDataSO.cs. Unity requires .meta files for
proper asset tracking and GUID-based serialized references.

https://claude.ai/code/session_01VUuKBf6Rwadg5U9yMMhtdb
…ues-ihQXn

Remove unused imports and delete obsolete ShipSelectionSlot class
claude and others added 30 commits February 27, 2026 09:21
…b reference

The prefab was kept in the previous commit with its script swapped to
SceneLoader, but it is no longer needed — scenes already have their own
SceneLoader components from the GUID swap. Also removes the deleted
prefab's entry from the vestigial _gameplayManagerPrefabs list in
AppManager.prefab.

https://claude.ai/code/session_01FxqDVaymsgJiMjzwTUqvF9
Resolve conflict in AppManager.prefab: take incoming field names
(captainManager, iapManager, etc.) and rename gameManager → sceneLoader
to match our refactor. Drop vestigial _gameplayManagerPrefabs list and
orphaned component from HEAD.

https://claude.ai/code/session_01FxqDVaymsgJiMjzwTUqvF9
…agement-RkhkF

Consolidate GameManager into SceneLoader for unified scene management
The ReflexSettings.asset RootScopes field referenced fileID
5456740058571604360 on AppManager.prefab, but that fileID does not
exist in the prefab (likely stale after prefab re-import). The actual
ContainerScope component has fileID 4798048649644018183.

With the broken reference, Reflex created an empty root container.
AppManager.InstallBindings() populated a scene-scoped container
instead, so all subsequent scenes inherited nothing — causing
UnknownContractException for AuthenticationServiceFacade and null
[Inject] fields on SceneLoader, MultiplayerSetup, and CameraManager.

https://claude.ai/code/session_01WzSYJbtkyDkjSZAa5tma2w
…-reference-ivKQj

Update ReflexSettings root scope reference
Introduce a new ContainerScope prefab and metadata, and embed it as a prefab instance in Bootstrap and Authentication scenes (added scene root entries and prefab modifications). Remove the runtime SceneContainerScopeBridge script that auto-created scene scopes, switching to an explicit prefab-based scope so scenes have a persistent DI ContainerScope. Also add a few auth-related timeout fields (cachedAuthTimeout, playerDataTimeout, safetyTimeout) in the Authentication scene.
…enu_Main

The AppManager.prefab RootScope component used the wrong script GUID
(583638035e4a15c42b2fa9de5d6213fa) instead of the actual Reflex
ContainerScope GUID (5312032623c34414a54ea00e35a7eb8e). This caused
Reflex to ignore the RootScope, creating an empty root container with
no bindings from AppManager.InstallBindings(). All scene containers
inherited nothing, producing UnknownContractException for
AuthenticationServiceFacade and null [Inject] fields on SceneLoader,
MultiplayerSetup, and CameraManager.

Changes:
- Fix script GUID on AppManager.prefab ContainerScope component to
  match the actual Reflex ContainerScope class
- Add ContainerScope prefab instance to Menu_Main.unity so Reflex
  injects scene objects there (Bootstrap and Authentication already
  had it)
- Add null guard in CameraManager.InitializeSceneCamera() for
  _sceneNameList to produce a clear error instead of NullReferenceException

https://claude.ai/code/session_016SQwXR4SX8PWcrVuRJkZ1D
…R5jje

Add ContainerScope prefab to main menu and improve CameraManager initialization
- Bootstrap: BootstrapController merged into AppManager, IBootstrapService removed
- Scene management: GameManager/NetworkGameManager replaced by SceneLoader
- DI: document Reflex DI registration patterns, GameDataSO [Inject] migration
- New systems: SceneNameListSO for centralized scene names, ContainerScope per scene
- Multiplayer: MainMenuServerVesselInitializer removed, AI spawning deduplicated
- Update BOOTSTRAP_AUDIT.md file references and async bootstrap flow
- Update README.md application flow and project structure

https://claude.ai/code/session_015rxfje3tpa1tLP6GGeSgs3
…s-13mKg

Refactor bootstrap & scene loading: AppManager as DI root + SceneLoader
…n as networked scene

After successful authentication, the AuthenticationSceneController now:
1. Instantiates the NetworkManager prefab (if not already present)
2. Starts a local Netcode host with a temporary connection approval callback
3. Loads Menu_Main via NetworkManager.SceneManager.LoadScene (networked)
4. Falls back to direct scene load if NetworkManager prefab is unassigned

Also updates SceneLoader.ReturnToMainMenu() to use network scene loading
when a Netcode host is active, for consistency with the new flow.

MultiplayerSetup in Menu_Main already handles a pre-started host gracefully
(EnsureHostStarted is a no-op when host is already listening).

Inspector setup required: assign the NetworkManager prefab from
_Prefabs/CORE/NetworkManager.prefab to AuthenticationSceneController's
"Networking > Network Manager Prefab" field.

https://claude.ai/code/session_01PuRkcNmnRaNeg4zxjy3Hz1
…erSetup

MultiplayerSetup lives in Bootstrap (DontDestroyOnLoad), so it should own
the NetworkManager lifecycle instead of AuthenticationSceneController.

MultiplayerSetup changes:
- Remove Awake() that eagerly cached NetworkManager.Singleton (null in Bootstrap)
- Add [SerializeField] _networkManagerPrefab for lazy instantiation
- EnsureHostStarted → async EnsureHostStartedAsync: instantiates prefab if
  NetworkManager.Singleton is null, registers Netcode callbacks, starts host
- OnAuthenticationSignedIn wraps async flow properly

AuthenticationSceneController changes:
- Remove NetworkManager prefab field and host-start logic
- Remove connection approval callback (MultiplayerSetup owns it)
- NavigateToMainMenu now waits for NetworkManager.Singleton.IsListening
  (with configurable timeout) then does networked scene load
- Falls back to direct scene load if host not ready in time

Flow: OnSignedIn → MultiplayerSetup.EnsureHostStartedAsync (instantiate
NetworkManager, start host) → AuthScene.LoadMainMenuNetworkedAsync (wait
for host ready, nm.SceneManager.LoadScene)

Inspector setup: assign NetworkManager prefab to MultiplayerSetup's
"Networking > Network Manager Prefab" field in the Bootstrap scene.

https://claude.ai/code/session_01PuRkcNmnRaNeg4zxjy3Hz1
The AuthPanel was missing a TMP_Text for login error feedback. Added a
LoginStatusText GameObject (auto-sizing italic, gray, anchored to
bottom of AuthPanel) and wired it to the statusText serialized field
on AuthenticationSceneController.

Also serialized the new networkHostTimeout field (default 3s).

All AuthenticationSceneController serialized fields are now assigned:
- authPanel, usernameSetupPanel, loadingPanel
- guestLoginButton, statusText (was null, now wired)
- usernameInputField, confirmUsernameButton, usernameStatusText
- cachedAuthTimeout, playerDataTimeout, safetyTimeout, networkHostTimeout

https://claude.ai/code/session_01PuRkcNmnRaNeg4zxjy3Hz1
…l spawning

Extract Menu_Main vessel lifecycle into a dedicated ServerPlayerVesselInitializer
subclass that spawns the host's vessel (without AI opponents) and activates it
in autopilot mode after initialization.

- MenuServerPlayerVesselInitializer overrides OnClientConnected to skip AI
  opponent spawning, and subscribes to OnClientReady to activate the player,
  enable AI pilot, pause input, and fire menu lifecycle events.
- MainMenuPlayerSpawnerAdapter simplified to only configure game data (vessel
  class, spawn positions) — post-init logic moved to the new initializer.

https://claude.ai/code/session_019ouda61ZL9RKcDQUd2q3nV
Add CameraManager.FollowVesselInMainMenu() that switches back to the
Cinemachine main menu camera and sets its Follow/LookAt targets to the
vessel transform, cancelling the default crystal look-at.

Called from MenuServerPlayerVesselInitializer.OnClientReady() after
autopilot activation so the menu camera tracks the flying vessel.

https://claude.ai/code/session_019ouda61ZL9RKcDQUd2q3nV
…cation-setup-QdBXb

Implement networked scene loading for authentication flow
… MenuServerPlayerVesselInitializer

Transfer game data setup (force Squirrel vessel class, InitializeGame)
into MenuServerPlayerVesselInitializer.Start(). Spawn positions are
already handled by the base class OnNetworkSpawn via _playerOrigins.

Delete MainMenuPlayerSpawnerAdapter — MenuServerPlayerVesselInitializer
now owns the full menu vessel lifecycle end-to-end.

https://claude.ai/code/session_019ouda61ZL9RKcDQUd2q3nV
…st-kaG0p

Refactor menu vessel initialization into dedicated server class
Merges 348 commits from app-shell-polish. Key changes:
- Files moved from Game/Arcade/ to Controller/Arcade/ (namespace CosmicShore.Gameplay)
- Files moved from Game/UI/ to UI/ (namespace CosmicShore.UI)
- MultiplayerSetup moved to persistent Controller/Multiplayer/
- New party lobby system (HostConnectionService, PartyGameLauncher)
- AI backfill support (RequestedAIBackfillCount)

Conflict resolution:
- Scene files: took theirs (code-only changes on our side)
- Game controllers/turn monitors: took theirs (clean version, will re-apply party fixes)
- GameDataSO: kept IsPartyMode + added RequestedAIBackfillCount
- Party files: moved to new directory structure with namespace updates
- NetcodeExtensions: retained IsServerSafe() extension

https://claude.ai/code/session_01Piy2uQvUaeqfJhG3eaR4Dj
After merging app-shell-polish, game controllers moved from Game/Arcade/
to Controller/Arcade/ (namespace CosmicShore.Gameplay). This commit
re-applies the IsServerSafe() and party mode fixes to the new locations:

- MultiplayerMiniGameControllerBase: IsServerSafe, PartyMode_Activate/Deactivate,
  activeInHierarchy guard, party auto-start, local RPC fallbacks
- MultiplayerDomainGamesController: IsServerSafe in OnCountdownTimerEnded, SetupNewRound
- NetworkScoreTracker: IsServerSafe, OnEnable/OnDisable for SetActive toggling
- NetworkCrystalCollisionTurnMonitor: IsServerSafe, local crystal target fallback
- NetworkJoustCollisionTurnMonitor: IsServerSafe in OnCollisionChanged, CheckForEndOfTurn
- NetworkCrystalManager: OnEnable/OnDisable for party mode, party reset via ResetSpawnState
- ServerPlayerVesselInitializer: PartyModeState enum, InertMode/SpawnMode guards
- HexRaceController, MultiplayerJoustController: fix stale ClassExtensions using

https://claude.ai/code/session_01Piy2uQvUaeqfJhG3eaR4Dj
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants