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();
}
}
}