using System; using Unity.BossRoom.Gameplay.Messages; using Unity.BossRoom.Infrastructure; using Unity.Netcode; using UnityEngine; using VContainer; namespace Unity.BossRoom.Gameplay.GameplayObjects { /// /// This class contains both client and server logic for a door that is opened when a player stands on a floor switch. /// (Assign the floor switches for this door in the editor.) /// Represents a door in the client. The visuals of the door animate as /// "opening" and "closing", but for physics purposes this is an illusion: /// whenever the door is open on the server, the door's physics are disabled, /// and vice versa. /// public class SwitchedDoor : NetworkBehaviour { [SerializeField] FloorSwitch[] m_SwitchesThatOpenThisDoor; [SerializeField] Animator m_Animator; public NetworkVariable IsOpen { get; } = new NetworkVariable(); const string k_AnimatorDoorOpenBoolVarName = "IsOpen"; [SerializeField, HideInInspector] int m_AnimatorDoorOpenBoolID; #if UNITY_EDITOR || DEVELOPMENT_BUILD public bool ForceOpen; #endif [SerializeField] [Tooltip("This physics and navmesh obstacle is enabled when the door is closed.")] GameObject m_PhysicsObject; [Inject] IPublisher m_Publisher; void Awake() { if (m_SwitchesThatOpenThisDoor.Length == 0) Debug.LogError("Door has no switches and can never be opened!", gameObject); } public override void OnNetworkSpawn() { IsOpen.OnValueChanged += OnDoorStateChanged; if (IsClient) { // initialize visuals based on current server state (or else we default to "closed") m_PhysicsObject.SetActive(!IsOpen.Value); } if (IsServer) { OnDoorStateChanged(false, IsOpen.Value); } } public override void OnNetworkDespawn() { IsOpen.OnValueChanged -= OnDoorStateChanged; } void Update() { if (IsServer && IsSpawned) { var isAnySwitchOn = false; foreach (var floorSwitch in m_SwitchesThatOpenThisDoor) { if (floorSwitch && floorSwitch.IsSwitchedOn.Value) { isAnySwitchOn = true; break; } } #if UNITY_EDITOR || DEVELOPMENT_BUILD isAnySwitchOn |= ForceOpen; #endif IsOpen.Value = isAnySwitchOn; } } void OnDoorStateChanged(bool wasDoorOpen, bool isDoorOpen) { if (IsServer) { m_Animator.SetBool(m_AnimatorDoorOpenBoolID, isDoorOpen); } if (IsClient) { m_PhysicsObject.SetActive(!isDoorOpen); if (m_Publisher != null) { m_Publisher.Publish(new DoorStateChangedEventMessage() { IsDoorOpen = isDoorOpen }); } } } void OnValidate() { m_AnimatorDoorOpenBoolID = Animator.StringToHash(k_AnimatorDoorOpenBoolVarName); } } }