using NightclubArcadia.Cinematics; using NightclubArcadia.Interaction; using NightclubArcadia.Player; using StarterAssets; using Unity.AI.Navigation; using Unity.Cinemachine; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.AI; /// /// Wires player control, navigation, and camera systems into Systems.unity. /// Run via Tools → Nightclub Arcadia → Set Up Player Control & Camera. /// public static class PlayerControlSetup { const string ScenePath = NightclubArcadia.EditorTools.ScenePaths.Systems; const string PlayerPrefabPath = "Assets/StarterAssets/ThirdPersonController/Prefabs/PlayerArmature.prefab"; const string SettingsFolder = "Assets/Settings"; [MenuItem("Tools/Nightclub Arcadia/Set Up Player Control & Camera")] public static void SetUp() { if (NightclubArcadia.EditorTools.LegacySceneSetup.Blocked("Set Up Player Control & Camera", "rebuild the player and camera rig and pull navigation into Systems.unity, " + "which turns that scene binary")) return; EnsurePlayerPrefab(); WireScene(); AssetDatabase.SaveAssets(); Debug.Log("[PlayerControlSetup] Player control and camera setup complete."); } static void EnsurePlayerPrefab() { var prefab = AssetDatabase.LoadAssetAtPath(PlayerPrefabPath); if (prefab == null) { Debug.LogError($"[PlayerControlSetup] Missing prefab at {PlayerPrefabPath}"); return; } var root = PrefabUtility.LoadPrefabContents(PlayerPrefabPath); EnsureComponent(root); EnsureComponent(root); EnsureComponent(root); EnsureComponent(root); EnsureComponent(root); var inputs = root.GetComponent(); if (inputs != null) { inputs.analogMovement = true; inputs.cursorLocked = false; } var controller = root.GetComponent(); if (controller != null) { controller.LockCameraPosition = true; } var clickToMove = root.GetComponent(); var pointerNav = root.GetComponent(); var pointerInput = root.GetComponent(); var arbiter = root.GetComponent(); WireSerializedReference(clickToMove, "brainCamera", null); WireSerializedReference(pointerNav, "pointerInput", pointerInput); WireSerializedReference(pointerNav, "clickToMove", clickToMove); WireSerializedReference(pointerNav, "motionArbiter", arbiter); PrefabUtility.SaveAsPrefabAsset(root, PlayerPrefabPath); PrefabUtility.UnloadPrefabContents(root); } static void WireScene() { var scene = EditorSceneManager.OpenScene(ScenePath, OpenSceneMode.Single); var player = GameObject.FindGameObjectWithTag("Player"); if (player == null) { Debug.LogError("[PlayerControlSetup] No Player-tagged object found in scene."); return; } EnsureComponent(player); EnsureComponent(player); EnsureComponent(player); EnsureComponent(player); EnsureComponent(player); var inputs = player.GetComponent(); if (inputs != null) { inputs.analogMovement = true; inputs.cursorLocked = false; } var controller = player.GetComponent(); if (controller != null) { controller.LockCameraPosition = true; } var brainCamera = Camera.main; var pointerInput = player.GetComponent(); var clickToMove = player.GetComponent(); var pointerNav = player.GetComponent(); var arbiter = player.GetComponent(); WireSerializedReference(clickToMove, "brainCamera", brainCamera); WireSerializedReference(pointerNav, "brainCamera", brainCamera); WireSerializedReference(pointerNav, "pointerInput", pointerInput); WireSerializedReference(pointerNav, "clickToMove", clickToMove); WireSerializedReference(pointerNav, "motionArbiter", arbiter); var groundLayer = LayerMask.NameToLayer("Ground"); var interactableLayer = LayerMask.NameToLayer("Interactable"); SetLayerIfExists("Floor", groundLayer); SetLayerIfExists("Room_101", groundLayer); SetLayerIfExists("Wall_Back", groundLayer); SetLayerIfExists("Wall_Front", groundLayer); SetLayerIfExists("Table", groundLayer); WireBartender("Bartender", interactableLayer); WireBartender("Bartender (1)", interactableLayer); EnsureNavigation(player.transform.position); EnsureCameraAnchor(player.transform, brainCamera); EditorSceneManager.MarkSceneDirty(scene); EditorSceneManager.SaveScene(scene); } static void WireBartender(string objectName, int interactableLayer) { var bartender = GameObject.Find(objectName); if (bartender == null) { return; } if (interactableLayer >= 0) { bartender.layer = interactableLayer; } EnsureComponent(bartender); EnsureComponent(bartender); } static void EnsureNavigation(Vector3 sampleOrigin) { var navigation = GameObject.Find("Navigation"); if (navigation == null) { navigation = new GameObject("Navigation"); } var surface = EnsureComponent(navigation); surface.agentTypeID = 0; surface.collectObjects = CollectObjects.All; surface.useGeometry = NavMeshCollectGeometry.RenderMeshes; var included = 0; var defaultLayer = LayerMask.NameToLayer("Default"); var groundLayer = LayerMask.NameToLayer("Ground"); if (defaultLayer >= 0) { included |= 1 << defaultLayer; } if (groundLayer >= 0) { included |= 1 << groundLayer; } surface.layerMask = included; var table = GameObject.Find("Table"); if (table != null) { var modifier = EnsureComponent(table); modifier.overrideArea = true; modifier.area = NavMesh.GetAreaFromName("Not Walkable"); } surface.BuildNavMesh(); if (!NavMesh.SamplePosition(sampleOrigin, out _, 2f, NavMesh.AllAreas)) { Debug.LogWarning("[PlayerControlSetup] NavMesh bake did not cover the player start position."); } } static void EnsureCameraAnchor(Transform followTarget, Camera brainCamera) { var vcamObject = GameObject.Find("CinemachineCamera"); if (vcamObject == null) { Debug.LogError("[PlayerControlSetup] CinemachineCamera not found."); return; } var vcam = vcamObject.GetComponent(); var composer = vcamObject.GetComponent(); var anchorObject = GameObject.Find("CameraAnchor"); if (anchorObject == null) { anchorObject = new GameObject("CameraAnchor"); } anchorObject.transform.position = followTarget.position; var anchor = EnsureComponent(anchorObject); EnsureComponent(anchorObject); EnsureComponent(anchorObject); EnsureComponent(anchorObject); WireSerializedReference(anchor, "followTarget", followTarget); WireSerializedReference(anchor, "composer", composer); if (vcam != null) { vcam.Target.TrackingTarget = anchorObject.transform; vcam.Priority.Value = 10; } var pan = anchorObject.GetComponent(); WireSerializedReference(pan, "brainCamera", brainCamera); WireSerializedReference(pan, "anchor", anchor); WireSerializedReference(pan, "stateDirector", anchorObject.GetComponent()); var poiDirector = anchorObject.GetComponent(); WireSerializedReference(poiDirector, "anchor", anchor); WireSerializedReference(poiDirector, "stateDirector", anchorObject.GetComponent()); var stateDirector = anchorObject.GetComponent(); WireSerializedReference(stateDirector, "anchor", anchor); EnsureRevealCamera(vcamObject, followTarget); } static void EnsureRevealCamera(GameObject followVcam, Transform followTarget) { var revealName = "CM_Reveal_Room101"; var revealObject = GameObject.Find(revealName); if (revealObject == null) { revealObject = new GameObject(revealName); revealObject.transform.SetPositionAndRotation( followVcam.transform.position + new Vector3(-4f, 2f, -2f), followVcam.transform.rotation); } var revealCam = EnsureComponent(revealObject); revealCam.Target.TrackingTarget = followTarget; revealCam.Priority.Value = 0; revealCam.Lens.FieldOfView = followVcam.GetComponent().Lens.FieldOfView; var volumeObject = GameObject.Find("RevealVolume_Room101"); if (volumeObject == null) { volumeObject = new GameObject("RevealVolume_Room101"); volumeObject.transform.position = followTarget.position + new Vector3(0f, 1f, 2f); } var box = EnsureComponent(volumeObject); box.isTrigger = true; box.size = new Vector3(6f, 3f, 4f); var volume = EnsureComponent(volumeObject); WireSerializedReference(volume, "revealCamera", revealCam); } static T EnsureComponent(GameObject target) where T : Component { var component = target.GetComponent(); if (component == null) { component = target.AddComponent(); } return component; } static void SetLayerIfExists(string objectName, int layer) { if (layer < 0) { return; } var obj = GameObject.Find(objectName); if (obj != null) { obj.layer = layer; } } static void WireSerializedReference(Object target, string propertyName, Object value) { if (target == null) { return; } var so = new SerializedObject(target); var property = so.FindProperty(propertyName); if (property != null) { property.objectReferenceValue = value; so.ApplyModifiedPropertiesWithoutUndo(); } } }