Files
Test-Multiplayer/Assets/Scripts/Chat/ChatUI.cs
T
pelpanagiotisandClaude Opus 5.5 5fc9ebf1e6 Add practice range: shooting, AK47, intro cinematic, dressed warehouse scene
- 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>
2026-09-25 08:56:35 +03:00

134 lines
3.6 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using TMPro;
// Client-only UI. DO NOT add a NetworkIdentity to this prefab.
public class ChatUI : MonoBehaviour
{
[Header("UI Elements")]
[SerializeField] private TextMeshProUGUI chatHistory;
[SerializeField] private Scrollbar scrollbar;
[SerializeField] private TMP_InputField chatMessage;
[SerializeField] private Button sendButton;
internal static string localPlayerName;
// Instance reference so static callers can check focus state safely
internal static ChatUI Instance;
private readonly List<string> lines = new();
private Player localPlayer;
void Awake()
{
Instance = this;
if (chatMessage != null)
{
chatMessage.onValueChanged.AddListener(ToggleButton);
chatMessage.onSubmit.AddListener(OnInputSubmit);
}
}
// Expose whether the chat input is focused so other systems can disable input/movement
public static bool IsInputFieldFocused => Instance != null && Instance.chatMessage != null && Instance.chatMessage.isFocused;
// Called by PlayerScript when Escape is pressed while chat is focused, so mouse-look/
// cursor lock can resume immediately instead of waiting for a manual click-away.
public void ExitChatFocus()
{
if (chatMessage != null)
chatMessage.DeactivateInputField();
if (EventSystem.current != null)
EventSystem.current.SetSelectedGameObject(null);
}
// Called by Player.OnStartLocalPlayer to connect the UI to the player's network methods.
public void Initialize(Player player)
{
localPlayer = player;
}
public void SetHistory(string[] history)
{
lines.Clear();
if (history != null && history.Length > 0)
lines.AddRange(history);
RefreshVisual();
}
// Called by Player.RpcReceiveChat / Player.TargetReceiveHistory
public void AddMessage(string message)
{
lines.Add(message);
if (chatHistory != null)
chatHistory.text += message + "\n";
StartCoroutine(ScrollNextFrame());
}
IEnumerator ScrollNextFrame()
{
yield return null;
yield return null;
if (scrollbar != null)
scrollbar.value = 0;
}
void RefreshVisual()
{
if (chatHistory == null) return;
chatHistory.text = string.Empty;
foreach (var l in lines)
chatHistory.text += l + "\n";
StartCoroutine(ScrollNextFrame());
}
public void ToggleButton(string input)
{
if (sendButton != null)
sendButton.interactable = !string.IsNullOrWhiteSpace(input);
}
private void OnInputSubmit(string input)
{
if (!string.IsNullOrWhiteSpace(input))
SendMessage();
}
public void SendMessage()
{
if (localPlayer == null)
{
Debug.LogWarning("ChatUI: local player not set; cannot send chat.");
return;
}
if (string.IsNullOrWhiteSpace(chatMessage?.text)) return;
localPlayer.SendChatToServer(chatMessage.text.Trim());
chatMessage.text = string.Empty;
chatMessage.ActivateInputField();
}
void OnDestroy()
{
if (chatMessage != null)
{
chatMessage.onValueChanged.RemoveListener(ToggleButton);
chatMessage.onSubmit.RemoveListener(OnInputSubmit);
}
// Clear static instance reference
if (Instance == this) Instance = null;
}
}