162 lines
3.6 KiB
C#

using UdonSharp;
using UnityEngine;
using VRC.SDK3.UdonNetworkCalling;
using VRC.SDKBase;
using VRC.Udon.Common.Interfaces;
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class Modem : UdonSharpBehaviour
{
[UdonSynced, FieldChangeCallback(nameof(ActivateModem))] private bool _ActivateModem = false;
[UdonSynced, FieldChangeCallback(nameof(BeginTeleport))] private bool _BeginTeleport = false;
[SerializeField] private GameObject _ModemActivationObject;
[SerializeField] private Modem _ModemDestination;
[Space]
[SerializeField] private AudioManager _AudioManager;
[SerializeField] private Animator _ModemAnimator;
[SerializeField] private Animator _ModemDestinationAnimator;
[UdonSynced] private string[] _EnteredPlayers = new string[MAX_PLAYERS_IN_MODEM];
private const int MAX_PLAYERS_IN_MODEM = 10;
public override void OnPlayerTriggerEnter(VRCPlayerApi Player)
{
for (int i = 0; i < MAX_PLAYERS_IN_MODEM; i++)
{
if (_EnteredPlayers[i] == null)
{
_EnteredPlayers[i] = Player.displayName;
break;
}
}
RequestSerialization();
base.OnPlayerTriggerEnter(Player);
}
public override void OnPlayerTriggerExit(VRCPlayerApi Player)
{
for (int i = 0; i < MAX_PLAYERS_IN_MODEM; i++)
{
if (_EnteredPlayers[i] == Player.displayName)
{
_EnteredPlayers[i] = null;
break;
}
}
RequestSerialization();
base.OnPlayerTriggerExit(Player);
}
public void Activate(bool Active)
{
ActivateModem = Active;
RequestSerialization();
}
public void Teleport()
{
Networking.SetOwner(Networking.LocalPlayer, gameObject);
BeginTeleport = true;
RequestSerialization();
}
private void ExecuteTeleportProcess()
{
// This is a synced function, so only play the sound effect locally.
_AudioManager.PlaySFX(SFXEventType.ModemOperation);
_ModemAnimator.SetBool("Teleport", true);
_ModemDestinationAnimator.SetBool("Teleport", true);
SendCustomEventDelayedSeconds(nameof(TeleportAllPlayers), 2.5f);
SendCustomEventDelayedSeconds(nameof(EndTeleport), 6.0f);
}
public void TeleportAllPlayers()
{
// Only the Modem owner should execute teleportations.
if (Networking.LocalPlayer.IsOwner(gameObject))
{
SendCustomNetworkEvent(NetworkEventTarget.All, nameof(TeleportLocalPlayerIfInModem));
}
}
public void ResetTeleportProcess()
{
_ModemAnimator.SetBool("Teleport", false);
_ModemDestinationAnimator.SetBool("Teleport", false);
}
public void EndTeleport()
{
BeginTeleport = false;
RequestSerialization();
}
[NetworkCallable]
public void TeleportLocalPlayerIfInModem()
{
for (int j = 0; j < _EnteredPlayers.Length; j++)
{
if (_EnteredPlayers[j] == Networking.LocalPlayer.displayName)
{
TeleportToModemDestination();
break;
}
}
}
private void TeleportToModemDestination()
{
Vector3 DeltaVector = Networking.LocalPlayer.GetPosition() - transform.position;
Quaternion DeltaRotation = _ModemDestination.transform.rotation * Quaternion.Inverse(transform.rotation);
Vector3 DestinationVectorRotated = DeltaRotation * DeltaVector.normalized;
Vector3 DestinationPositionDelta = DestinationVectorRotated * DeltaVector.magnitude;
Networking.LocalPlayer.TeleportTo(
_ModemDestination.transform.position + DestinationPositionDelta,
DeltaRotation * Networking.LocalPlayer.GetRotation());
}
private bool ActivateModem
{
set
{
_ActivateModem = value;
_ModemActivationObject.SetActive(_ActivateModem);
}
get => _ActivateModem;
}
private bool BeginTeleport
{
set
{
_BeginTeleport = value;
if (_BeginTeleport)
{
ExecuteTeleportProcess();
}
else
{
ResetTeleportProcess();
}
}
get => _BeginTeleport;
}
}