You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
3.3 KiB
C#

using System;
using Unity.BossRoom.Gameplay.Messages;
using Unity.BossRoom.Infrastructure;
using Unity.Netcode;
using UnityEngine;
using VContainer;
namespace Unity.BossRoom.Gameplay.GameplayObjects
{
/// <summary>
/// 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.
/// </summary>
public class SwitchedDoor : NetworkBehaviour
{
[SerializeField]
FloorSwitch[] m_SwitchesThatOpenThisDoor;
[SerializeField]
Animator m_Animator;
public NetworkVariable<bool> IsOpen { get; } = new NetworkVariable<bool>();
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<DoorStateChangedEventMessage> 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);
}
}
}