first commit
This commit is contained in:
147
NitroxClient/MonoBehaviours/Gui/Chat/PlayerChat.cs
Normal file
147
NitroxClient/MonoBehaviours/Gui/Chat/PlayerChat.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NitroxClient.GameLogic.ChatUI;
|
||||
using NitroxClient.GameLogic.Settings;
|
||||
using NitroxModel.Core;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NitroxClient.MonoBehaviours.Gui.Chat
|
||||
{
|
||||
public class PlayerChat : uGUI_InputGroup
|
||||
{
|
||||
private const int LINE_CHAR_LIMIT = 255;
|
||||
private const int MESSAGES_LIMIT = 64;
|
||||
private const float TOGGLED_TRANSPARENCY = 0.4f;
|
||||
public const float CHAT_VISIBILITY_TIME_LENGTH = 6f;
|
||||
|
||||
private static readonly Queue<ChatLogEntry> entries = new Queue<ChatLogEntry>();
|
||||
private Image[] backgroundImages;
|
||||
private CanvasGroup canvasGroup;
|
||||
private InputField inputField;
|
||||
private GameObject logEntryPrefab;
|
||||
|
||||
private PlayerChatManager playerChatManager;
|
||||
private bool transparent;
|
||||
|
||||
public static bool IsReady { get; private set; }
|
||||
|
||||
public string InputText
|
||||
{
|
||||
get => inputField.text;
|
||||
set => inputField.text = value;
|
||||
}
|
||||
|
||||
public IEnumerator SetupChatComponents()
|
||||
{
|
||||
playerChatManager = NitroxServiceLocator.LocateService<PlayerChatManager>();
|
||||
|
||||
canvasGroup = GetComponent<CanvasGroup>();
|
||||
|
||||
logEntryPrefab = GameObject.Find("ChatLogEntryPrefab");
|
||||
logEntryPrefab.AddComponent<PlayerChatLogItem>();
|
||||
logEntryPrefab.SetActive(false);
|
||||
|
||||
GetComponentsInChildren<Button>()[0].onClick.AddListener(ToggleBackgroundTransparency);
|
||||
GetComponentsInChildren<Button>()[1].gameObject.AddComponent<PlayerChatPinButton>();
|
||||
|
||||
inputField = GetComponentInChildren<InputField>();
|
||||
inputField.gameObject.AddComponent<PlayerChatInputField>().InputField = inputField;
|
||||
inputField.GetComponentInChildren<Button>().onClick.AddListener(playerChatManager.SendMessage);
|
||||
|
||||
// We pick any image that's inside the chat component to have all of their opacity lowered
|
||||
backgroundImages = transform.GetComponentsInChildren<Image>();
|
||||
|
||||
yield return new WaitForEndOfFrame(); //Needed so Select() works on initialization
|
||||
IsReady = true;
|
||||
if (NitroxPrefs.SilenceChat.Value)
|
||||
{
|
||||
Log.InGame(Language.main.Get("Nitrox_SilencedChatNotif"));
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteLogEntry(string playerName, string message, Color color)
|
||||
{
|
||||
if (entries.Count == MESSAGES_LIMIT)
|
||||
{
|
||||
Destroy(entries.Dequeue().EntryObject);
|
||||
}
|
||||
|
||||
ChatLogEntry chatLogEntry;
|
||||
GameObject chatLogEntryObject;
|
||||
if (entries.Count != 0 && entries.Last().PlayerName == playerName)
|
||||
{
|
||||
chatLogEntry = entries.Last();
|
||||
chatLogEntry.MessageText += $"{Environment.NewLine}{message}";
|
||||
chatLogEntry.UpdateTime();
|
||||
chatLogEntryObject = chatLogEntry.EntryObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
chatLogEntry = new ChatLogEntry(playerName, SanitizeMessage(message), color);
|
||||
chatLogEntryObject = Instantiate(logEntryPrefab, logEntryPrefab.transform.parent, false);
|
||||
chatLogEntry.EntryObject = chatLogEntryObject;
|
||||
entries.Enqueue(chatLogEntry);
|
||||
}
|
||||
|
||||
chatLogEntryObject.GetComponent<PlayerChatLogItem>().ApplyOnPrefab(chatLogEntry);
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
PlayerChatInputField.ResetTimer();
|
||||
StartCoroutine(ToggleChatFade(true));
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
StartCoroutine(ToggleChatFade(false));
|
||||
}
|
||||
|
||||
public void Select()
|
||||
{
|
||||
base.Select(true);
|
||||
inputField.Select();
|
||||
inputField.ActivateInputField();
|
||||
}
|
||||
|
||||
private static string SanitizeMessage(string message)
|
||||
{
|
||||
message = message.Trim().TrimEnd('\n').Trim();
|
||||
return message.Length < LINE_CHAR_LIMIT ? message : message.Substring(0, LINE_CHAR_LIMIT);
|
||||
}
|
||||
|
||||
private void ToggleBackgroundTransparency()
|
||||
{
|
||||
float alpha = transparent ? 1f : TOGGLED_TRANSPARENCY;
|
||||
transparent = !transparent;
|
||||
|
||||
foreach (Image backgroundImage in backgroundImages)
|
||||
{
|
||||
backgroundImage.CrossFadeAlpha(alpha, 0.5f, false);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator ToggleChatFade(bool fadeIn)
|
||||
{
|
||||
if (fadeIn)
|
||||
{
|
||||
while (canvasGroup.alpha < 1f)
|
||||
{
|
||||
canvasGroup.alpha += 0.01f;
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (canvasGroup.alpha > 0f)
|
||||
{
|
||||
canvasGroup.alpha -= 0.01f;
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
172
NitroxClient/MonoBehaviours/Gui/Chat/PlayerChatInputField.cs
Normal file
172
NitroxClient/MonoBehaviours/Gui/Chat/PlayerChatInputField.cs
Normal file
@@ -0,0 +1,172 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NitroxClient.GameLogic.ChatUI;
|
||||
using NitroxModel.Core;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NitroxClient.MonoBehaviours.Gui.Chat
|
||||
{
|
||||
public class PlayerChatInputField : MonoBehaviour, ISelectHandler, IDeselectHandler
|
||||
{
|
||||
private PlayerChatManager playerChatManager;
|
||||
private bool selected;
|
||||
private static float timeLeftUntilAutoClose;
|
||||
public static bool FreezeTime;
|
||||
public InputField InputField;
|
||||
|
||||
// Chat history
|
||||
private const int historyLength = 32; // 2^5 messages availables :D
|
||||
|
||||
private List<string> sentMessages;
|
||||
private int _sentMessagesIndex;
|
||||
private int sentMessagesIndex
|
||||
{
|
||||
get { return _sentMessagesIndex; }
|
||||
set
|
||||
{
|
||||
if (sentMessages.Count == 0)
|
||||
{
|
||||
// -1 is the state when there's no message sent
|
||||
_sentMessagesIndex = -1;
|
||||
}
|
||||
else if (value < 1)
|
||||
{
|
||||
sentMessagesIndex = 1;
|
||||
}
|
||||
else if (value > sentMessages.Count)
|
||||
{
|
||||
_sentMessagesIndex = sentMessages.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal functionning
|
||||
InputField.text = sentMessages[value - 1];
|
||||
_sentMessagesIndex = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
playerChatManager = NitroxServiceLocator.LocateService<PlayerChatManager>();
|
||||
sentMessages = new();
|
||||
sentMessagesIndex = -1;
|
||||
}
|
||||
|
||||
public void OnSelect(BaseEventData eventData)
|
||||
{
|
||||
playerChatManager.SelectChat();
|
||||
selected = true;
|
||||
ResetTimer();
|
||||
}
|
||||
|
||||
public void OnDeselect(BaseEventData eventData)
|
||||
{
|
||||
selected = false;
|
||||
}
|
||||
|
||||
public static void ResetTimer()
|
||||
{
|
||||
timeLeftUntilAutoClose = PlayerChat.CHAT_VISIBILITY_TIME_LENGTH;
|
||||
FreezeTime = false;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (FreezeTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(InputField.text))
|
||||
{
|
||||
if (UnityEngine.Input.GetKey(KeyCode.Return))
|
||||
{
|
||||
if (UnityEngine.Input.GetKey(KeyCode.LeftShift))
|
||||
{
|
||||
if (!InputField.text.EndsWith("\n"))
|
||||
{
|
||||
InputField.ActivateInputField();
|
||||
InputField.text += "\n";
|
||||
StartCoroutine(MoveToEndOfText());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Detect if there's a ghost message on top of the list (one that wasn't sent but still saved)
|
||||
if (sentMessagesIndex != sentMessages.Count && sentMessages.Count > 0)
|
||||
{
|
||||
sentMessages.RemoveAt(sentMessages.Count - 1);
|
||||
}
|
||||
|
||||
// If the list is too long, we'll just remove the first message of the list
|
||||
if (sentMessages.Count > historyLength)
|
||||
{
|
||||
sentMessages.RemoveAt(0);
|
||||
}
|
||||
|
||||
sentMessages.Add(InputField.text);
|
||||
_sentMessagesIndex = sentMessages.Count;
|
||||
playerChatManager.SendMessage();
|
||||
playerChatManager.DeselectChat(); // return to game after message sent
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (UnityEngine.Input.GetKey(KeyCode.Return))
|
||||
{
|
||||
ResetTimer();
|
||||
playerChatManager.DeselectChat();
|
||||
}
|
||||
}
|
||||
|
||||
// Chat history stuff
|
||||
// GetKeyDown means it's only getting executed once per press
|
||||
if (UnityEngine.Input.GetKeyDown(KeyCode.UpArrow))
|
||||
{
|
||||
// If we're currently on the newest message, we want to save it to be able to come back to it (a ghost message)
|
||||
if (sentMessagesIndex == sentMessages.Count && sentMessages.Count > 0)
|
||||
{
|
||||
sentMessages.Add(InputField.text);
|
||||
_sentMessagesIndex = sentMessages.Count;
|
||||
}
|
||||
sentMessagesIndex--;
|
||||
}
|
||||
else if(UnityEngine.Input.GetKeyDown(KeyCode.DownArrow))
|
||||
{
|
||||
// We shouldn't execute this check if we're already on top of the list
|
||||
if (sentMessagesIndex < sentMessages.Count)
|
||||
{
|
||||
sentMessagesIndex++;
|
||||
// If we're back to the newest message, we can delete it from the list because it has not been sent yet
|
||||
if (sentMessagesIndex == sentMessages.Count && sentMessages.Count > 0)
|
||||
{
|
||||
sentMessages.RemoveAt(sentMessages.Count - 1);
|
||||
_sentMessagesIndex = sentMessages.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
timeLeftUntilAutoClose -= Time.unscaledDeltaTime;
|
||||
if (timeLeftUntilAutoClose <= 0)
|
||||
{
|
||||
playerChatManager.HideChat();
|
||||
FreezeTime = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator MoveToEndOfText()
|
||||
{
|
||||
yield return null;
|
||||
InputField.MoveTextEnd(false);
|
||||
}
|
||||
}
|
||||
}
|
35
NitroxClient/MonoBehaviours/Gui/Chat/PlayerChatLogItem.cs
Normal file
35
NitroxClient/MonoBehaviours/Gui/Chat/PlayerChatLogItem.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using NitroxClient.GameLogic.ChatUI;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NitroxClient.MonoBehaviours.Gui.Chat
|
||||
{
|
||||
public class PlayerChatLogItem : MonoBehaviour
|
||||
{
|
||||
private Text playerName;
|
||||
private Text time;
|
||||
private Text message;
|
||||
|
||||
private void SetupComponents()
|
||||
{
|
||||
Text[] textFields = gameObject.GetComponentsInChildren<Text>();
|
||||
playerName = textFields[0];
|
||||
time = textFields[1];
|
||||
message = textFields[2];
|
||||
}
|
||||
|
||||
public void ApplyOnPrefab(ChatLogEntry chatLogEntry)
|
||||
{
|
||||
if (playerName == null)
|
||||
{
|
||||
SetupComponents();
|
||||
}
|
||||
|
||||
playerName.text = chatLogEntry.PlayerName;
|
||||
playerName.color = chatLogEntry.PlayerColor;
|
||||
time.text = chatLogEntry.Time;
|
||||
message.text = chatLogEntry.MessageText;
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
}
|
66
NitroxClient/MonoBehaviours/Gui/Chat/PlayerChatPinButton.cs
Normal file
66
NitroxClient/MonoBehaviours/Gui/Chat/PlayerChatPinButton.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using NitroxClient.GameLogic.ChatUI;
|
||||
using NitroxModel.Core;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace NitroxClient.MonoBehaviours.Gui.Chat
|
||||
{
|
||||
public class PlayerChatPinButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
|
||||
{
|
||||
private static PlayerChatManager playerChatManager;
|
||||
|
||||
private readonly Camera mainCamera = Camera.main;
|
||||
private Vector2 screenRes = new Vector2(1920f, 1200f);
|
||||
private Vector2 chatSize;
|
||||
private Vector4 screenBorder;
|
||||
private Vector2 offset;
|
||||
private bool drag;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
playerChatManager = NitroxServiceLocator.LocateService<PlayerChatManager>();
|
||||
chatSize = transform.parent.parent.GetComponent<RectTransform>().sizeDelta;
|
||||
}
|
||||
|
||||
public void OnPointerDown(PointerEventData eventData)
|
||||
{
|
||||
screenRes.y = (screenRes.x / Screen.width) * Screen.height;
|
||||
offset = GetMouseWorldPosition() - (Vector2)playerChatManager.PlayerChaTransform.localPosition;
|
||||
screenBorder = new Vector4(-(screenRes.x - chatSize.x) / 2f, (screenRes.x - chatSize.x) / 2f, -(screenRes.y - chatSize.y) / 2f, (screenRes.y - chatSize.y) / 2f);
|
||||
|
||||
drag = true;
|
||||
PlayerChatInputField.FreezeTime = true;
|
||||
}
|
||||
|
||||
public void OnPointerUp(PointerEventData eventData)
|
||||
{
|
||||
drag = false;
|
||||
PlayerChatInputField.FreezeTime = false;
|
||||
PlayerChatInputField.ResetTimer();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (drag)
|
||||
{
|
||||
playerChatManager.PlayerChaTransform.localPosition = GetChatPosition();
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 GetMouseWorldPosition()
|
||||
{
|
||||
Vector3 position = mainCamera.ScreenToViewportPoint(UnityEngine.Input.mousePosition);
|
||||
position.x = (position.x - 0.5f) * screenRes.x;
|
||||
position.y = (position.y - 0.5f) * screenRes.y;
|
||||
return position;
|
||||
}
|
||||
|
||||
private Vector2 GetChatPosition()
|
||||
{
|
||||
Vector2 position = GetMouseWorldPosition() - offset;
|
||||
position.x = Mathf.Clamp(position.x, screenBorder.x, screenBorder.y);
|
||||
position.y = Mathf.Clamp(position.y, screenBorder.z, screenBorder.w);
|
||||
return position;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user