- 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>
174 lines
5.1 KiB
C#
174 lines
5.1 KiB
C#
using Mirror;
|
|
using Mirror.Examples.Chat;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
public class ChatAuthenticator : NetworkAuthenticator
|
|
{
|
|
readonly HashSet<NetworkConnectionToClient> connectionsPendingDisconnect = new HashSet<NetworkConnectionToClient>();
|
|
internal static readonly HashSet<string> playerNames = new HashSet<string>();
|
|
|
|
[Header("Client Username")]
|
|
public string playerName;
|
|
|
|
#region Messages;
|
|
|
|
public struct AuthRequestMessage : NetworkMessage
|
|
{
|
|
public string authUsername;
|
|
}
|
|
|
|
public struct AuthResponseMessage : NetworkMessage
|
|
{
|
|
public byte code;
|
|
public string message;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Server
|
|
|
|
[UnityEngine.RuntimeInitializeOnLoadMethod]
|
|
static void ResetStatics()
|
|
{
|
|
playerNames.Clear();
|
|
}
|
|
|
|
public override void OnStartServer()
|
|
{
|
|
Debug.Log("[ChatAuthenticator] Server authentication started.");
|
|
NetworkServer.RegisterHandler<AuthRequestMessage>(OnAuthRequestMessage, false);
|
|
}
|
|
|
|
public override void OnStopServer()
|
|
{
|
|
Debug.Log("[ChatAuthenticator] Server authentication stopped.");
|
|
NetworkServer.UnregisterHandler<AuthRequestMessage>();
|
|
}
|
|
|
|
public override void OnServerAuthenticate(NetworkConnectionToClient conn)
|
|
{
|
|
Debug.LogWarning($"[ChatAuthenticator] OnServerAuthenticate called for connection {conn.connectionId}; waiting for AuthRequestMessage.");
|
|
}
|
|
|
|
public void OnAuthRequestMessage(NetworkConnectionToClient conn, AuthRequestMessage msg)
|
|
{
|
|
Debug.Log($"[ChatAuthenticator] Authentication request received from connection {conn.connectionId}. Username length: {msg.authUsername?.Length ?? 0}");
|
|
|
|
if (connectionsPendingDisconnect.Contains(conn)) return;
|
|
|
|
if (!playerNames.Contains(msg.authUsername))
|
|
{
|
|
playerNames.Add(msg.authUsername);
|
|
|
|
conn.authenticationData = msg.authUsername;
|
|
|
|
AuthResponseMessage authResponseMessage = new AuthResponseMessage
|
|
{
|
|
code = 100,
|
|
message = "Success"
|
|
};
|
|
|
|
conn.Send(authResponseMessage);
|
|
|
|
Debug.Log($"[ChatAuthenticator] Authentication accepted for connection {conn.connectionId}.");
|
|
ServerAccept(conn);
|
|
}
|
|
else
|
|
{
|
|
connectionsPendingDisconnect.Add(conn);
|
|
|
|
AuthResponseMessage authResponseMessage = new AuthResponseMessage
|
|
{
|
|
code = 200,
|
|
message = "Username already in use... try again"
|
|
};
|
|
|
|
conn.Send(authResponseMessage);
|
|
|
|
conn.isAuthenticated = false;
|
|
|
|
Debug.LogWarning($"[ChatAuthenticator] Authentication rejected for connection {conn.connectionId}: username already in use.");
|
|
StartCoroutine(DelayedDisconnect(conn, 1f));
|
|
}
|
|
}
|
|
|
|
IEnumerator DelayedDisconnect(NetworkConnectionToClient conn, float waitTime)
|
|
{
|
|
yield return new WaitForSeconds(waitTime);
|
|
|
|
ServerReject(conn);
|
|
|
|
yield return null;
|
|
|
|
connectionsPendingDisconnect.Remove(conn);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Client
|
|
|
|
public void SetPlayerName(string username)
|
|
{
|
|
playerName = username;
|
|
Debug.Log($"[ChatAuthenticator] Client username set. Length: {playerName?.Length ?? 0}");
|
|
if (LoginUI.instance != null && LoginUI.instance.errorText != null)
|
|
{
|
|
LoginUI.instance.errorText.text = string.Empty;
|
|
LoginUI.instance.errorText.gameObject.SetActive(false);
|
|
}
|
|
}
|
|
|
|
public override void OnStartClient()
|
|
{
|
|
Debug.Log("[ChatAuthenticator] Client authentication started.");
|
|
NetworkClient.RegisterHandler<AuthResponseMessage>(OnAuthResponseMessage, false);
|
|
}
|
|
|
|
public override void OnStopClient()
|
|
{
|
|
Debug.Log("[ChatAuthenticator] Client authentication stopped.");
|
|
NetworkClient.UnregisterHandler<AuthResponseMessage>();
|
|
}
|
|
|
|
public override void OnClientAuthenticate()
|
|
{
|
|
Debug.Log($"[ChatAuthenticator] Sending authentication request. Username length: {playerName?.Length ?? 0}");
|
|
NetworkClient.Send(new AuthRequestMessage { authUsername = playerName });
|
|
}
|
|
|
|
public void OnAuthResponseMessage(AuthResponseMessage msg)
|
|
{
|
|
Debug.Log($"[ChatAuthenticator] Authentication response received. Code: {msg.code}, Message: '{msg.message}'");
|
|
if (msg.code == 100)
|
|
{
|
|
ClientAccept();
|
|
Debug.Log("[ChatAuthenticator] Client accepted by server.");
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError($"[ChatAuthenticator] Client authentication rejected. Code: {msg.code}, Message: '{msg.message}'");
|
|
|
|
NetworkManager.singleton.StopHost();
|
|
|
|
LoginUI.instance.errorText.text = msg.message;
|
|
LoginUI.instance.errorText.gameObject.SetActive(true);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
|
void Start()
|
|
{
|
|
|
|
}
|
|
|
|
// Update is called once per frame
|
|
void Update()
|
|
{
|
|
|
|
}
|
|
}
|