- PortalTestDestination practice range: Valorant-style hitscan rifle (recoil, spray/bloom, reload, controller support), debug HUD, practice-dummy targets with head/body hitboxes, hit/death/respawn animations, procedural SFX/FX - AK47 model (Quaternius, CC0) held via Animator IK, with fire/reload/equip anims - Intro cinematic (camera shots, title card, target beam-in, GO hand-off) - Scene dressing editor pass: CC0 textures, props, warehouse roof, lighting and post-processing; custom stylized skybox shader - CharacterMovement: camera recoil, shoulder offset, cinematic control lock - Unity CLI pipeline package; plus in-progress chat/Rive/player changes Asset credits: Assets/Models/Props/PROPS_CREDITS.txt (3 CC-BY 3.0 props), Assets/Textures/Range/TEXTURES_LICENSE.txt, Assets/Resources/*/..._LICENSE.txt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
110 lines
3.2 KiB
C#
110 lines
3.2 KiB
C#
using Mirror;
|
|
using Rive;
|
|
using Rive.Components;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
|
|
public class RiveLoginController : MonoBehaviour
|
|
{
|
|
[Header("Rive")]
|
|
[SerializeField] private RiveWidget riveWidget;
|
|
[SerializeField] private string startTriggerName = "startClicked";
|
|
|
|
[Header("Login")]
|
|
[Tooltip("Still needed username until Rive has a bound string property.")]
|
|
[SerializeField] private TMP_InputField usernameInput;
|
|
|
|
[SerializeField] private LoginUI loginUI;
|
|
|
|
private ViewModelInstanceTriggerProperty startTrigger;
|
|
|
|
private void Awake()
|
|
{
|
|
if (riveWidget == null)
|
|
riveWidget = GetComponent<RiveWidget>();
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
if (riveWidget == null) return;
|
|
|
|
riveWidget.OnWidgetStatusChanged += HandleWidgetStatusChanged;
|
|
HandleWidgetStatusChanged();
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
if (riveWidget != null)
|
|
riveWidget.OnWidgetStatusChanged -= HandleWidgetStatusChanged;
|
|
|
|
if (startTrigger != null)
|
|
startTrigger.OnTriggered -= OnStartClicked;
|
|
}
|
|
|
|
private void HandleWidgetStatusChanged()
|
|
{
|
|
if (riveWidget.Status != WidgetStatus.Loaded)
|
|
return;
|
|
|
|
ViewModelInstance vm = riveWidget.StateMachine?.ViewModelInstance;
|
|
if (vm == null)
|
|
{
|
|
Debug.LogError("RiveLoginController: ViewModelInstance is null. Set Data Binding Mode to Auto Bind Default.");
|
|
return;
|
|
}
|
|
|
|
if (startTrigger != null)
|
|
startTrigger.OnTriggered -= OnStartClicked;
|
|
|
|
startTrigger = vm.GetTriggerProperty(startTriggerName);
|
|
if (startTrigger == null)
|
|
{
|
|
Debug.LogError($"RiveLoginController: Trigger '{startTriggerName}' not found.");
|
|
return;
|
|
}
|
|
|
|
startTrigger.OnTriggered += OnStartClicked;
|
|
}
|
|
|
|
private void OnStartClicked()
|
|
{
|
|
StartMultiplayerSession();
|
|
}
|
|
|
|
public void StartMultiplayerSession()
|
|
{
|
|
string username = usernameInput != null
|
|
? usernameInput.text.Trim()
|
|
: string.Empty;
|
|
|
|
Debug.Log($"[RiveLoginController] StartMultiplayerSession called. Username length: {username.Length}");
|
|
|
|
if (string.IsNullOrWhiteSpace(username))
|
|
{
|
|
Debug.LogWarning("[RiveLoginController] Client start blocked because the username is empty.");
|
|
if (loginUI != null && loginUI.errorText != null)
|
|
{
|
|
loginUI.errorText.text = "Enter a username";
|
|
loginUI.errorText.gameObject.SetActive(true);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("RiveLoginController: Username is empty");
|
|
}
|
|
return;
|
|
}
|
|
|
|
ChatAuthenticator auth = NetworkManager.singleton.GetComponent<ChatAuthenticator>();
|
|
if (auth != null)
|
|
{
|
|
Debug.Log("[RiveLoginController] Assigning username to ChatAuthenticator.");
|
|
auth.SetPlayerName(username);
|
|
}
|
|
else
|
|
Debug.LogWarning("RiveLoginController: ChatAuthenticator not found on NetworkManager");
|
|
|
|
Debug.Log($"[RiveLoginController] Starting client. Network address: '{NetworkManager.singleton.networkAddress}'");
|
|
NetworkManager.singleton.StartClient();
|
|
}
|
|
}
|