Files
source/Assets/Scripts/ChatroomMenu.cs

573 lines
27 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class ChatroomMenu : MonoBehaviour
{
private readonly static WaitForSeconds _waitForSeconds2 = new(2f);
private readonly static WaitForSeconds _waitForSeconds3 = new(3f);
[SerializeField] private TMP_Text statusText;
[SerializeField] private Button backButton;
[SerializeField] private Button sendButton;
[SerializeField] private TMP_InputField messageInputField;
[SerializeField] private GameObject content;
[SerializeField] private GameObject sampleObject;
private string statusMessage;
private Coroutine statusRoutine;
private Coroutine refreshLoopRoutine;
private bool shouldScrollToBottom = true;
[SerializeField] private Button downButton;
[SerializeField] private ProfileMenu profilePrefab;
[SerializeField] private GameObject optionsPanel;
[SerializeField] private Button optionsPanelExitButton;
[SerializeField] private Button optionsPanelDeleteButton;
[SerializeField] private Button optionsPanelEditButton;
[SerializeField] private Button optionsPanelReportButton;
[SerializeField] private Button optionsPanelCopyButton;
private ChatroomMessage selectedMessageForOptions;
[SerializeField] private GameObject editMessagePanelSample;
private GameObject editMessagePanelCurrent;
[SerializeField] private GameObject reportMessagePanel;
[SerializeField] private Button reportMessagePanelExitButton;
[SerializeField] private Button reportMessagePanelSubmitButton;
[SerializeField] private TMP_InputField reportMessagePanelReportReason;
[SerializeField] private Dictionary<string, string> customIcons;
void Start()
{
reportMessagePanelReportReason.transform.GetChild(0).GetChild(1).GetComponent<TMP_Text>().textWrappingMode = TextWrappingModes.Normal;
if (BazookaManager.Instance.GetAccountID() == null || BazookaManager.Instance.GetAccountName() == null || BazookaManager.Instance.GetAccountSession() == null)
{
sendButton.interactable = false;
messageInputField.interactable = false;
ShowStatus("Warning: You are not logged in. Please log in to send messages.");
}
sendButton.onClick.AddListener(async () => await HandleMessageSubmit());
downButton.onClick.AddListener(() => StartCoroutine(ScrollToBottom()));
messageInputField.textComponent.textWrappingMode = TextWrappingModes.Normal;
messageInputField.onSubmit.AddListener(async (_) => await HandleMessageSubmit());
refreshLoopRoutine = StartCoroutine(Loop());
optionsPanelExitButton.onClick.AddListener(() =>
{
optionsPanel.SetActive(false);
selectedMessageForOptions = null;
});
optionsPanelDeleteButton.onClick.AddListener(async () =>
{
if (selectedMessageForOptions != null) await HandleDelete();
});
optionsPanelDeleteButton.onClick.AddListener(optionsPanelExitButton.onClick.Invoke);
optionsPanelEditButton.onClick.AddListener(() =>
{
var editMessage = Instantiate(editMessagePanelSample, editMessagePanelSample.transform.parent);
editMessagePanelCurrent = editMessage;
var editMessageChild = editMessage.transform.GetChild(0);
var editMessageChildExitButton = editMessageChild.GetChild(0).GetComponent<Button>();
var editMessageChildSubmitButton = editMessageChild.GetChild(1).GetComponent<Button>();
var editMessageChildOriginalPreview = editMessageChild.GetChild(2).gameObject;
var editMessageChildEditedPreview = editMessageChild.GetChild(3).gameObject;
var editMessageChildNewContentInputBox = editMessageChild.GetChild(4).GetComponent<TMP_InputField>();
editMessageChildNewContentInputBox.text = Encoding.UTF8.GetString(Convert.FromBase64String(selectedMessageForOptions.Content));
editMessageChildExitButton.onClick.AddListener(() =>
{
editMessagePanelCurrent = null;
Destroy(editMessage);
optionsPanel.SetActive(true);
});
editMessageChildSubmitButton.onClick.AddListener(async () =>
{
await HandleEdit();
editMessagePanelCurrent = null;
Destroy(editMessage);
selectedMessageForOptions = null;
});
var rowInfo = editMessageChild.GetChild(2);
var usernameText = rowInfo.transform.GetChild(2).GetComponent<TMP_Text>();
var playerIcon = rowInfo.transform.GetChild(3).GetComponent<Image>();
var playerOverlayIcon = playerIcon.transform.GetChild(0).GetComponent<Image>();
var messageText = rowInfo.transform.GetChild(4).GetComponent<TMP_Text>();
var optionsButton = rowInfo.transform.GetChild(5).GetComponent<Button>();
usernameText.text = selectedMessageForOptions.Username;
messageText.text = Encoding.UTF8.GetString(Convert.FromBase64String(selectedMessageForOptions.Content));
if (selectedMessageForOptions.CustomIcon == null)
{
playerIcon.sprite = Resources.Load<Sprite>("Icons/Icons/bird_" + selectedMessageForOptions.Icon);
if (selectedMessageForOptions.Icon == 1)
{
playerIcon.sprite = Tools.GetIconForUser(selectedMessageForOptions.UserID);
}
playerOverlayIcon.sprite = Resources.Load<Sprite>("Icons/Overlays/overlay_" + selectedMessageForOptions.Overlay);
if (selectedMessageForOptions.Overlay == 0)
{
playerOverlayIcon.gameObject.SetActive(false);
}
else if (selectedMessageForOptions.Overlay == 8)
{
playerOverlayIcon.transform.localPosition = new UnityEngine.Vector2(-16.56f, 14.81f);
}
else if (selectedMessageForOptions.Overlay == 11)
{
playerOverlayIcon.transform.localPosition = new UnityEngine.Vector2(-14.74451f, 20.39122f);
}
else if (selectedMessageForOptions.Overlay == 13)
{
playerOverlayIcon.transform.localPosition = new UnityEngine.Vector2(-16.54019f, 14.70365f);
}
try
{
playerIcon.color = new Color(selectedMessageForOptions.BirdColor[0] / 255f, selectedMessageForOptions.BirdColor[1] / 255f, selectedMessageForOptions.BirdColor[2] / 255f);
playerOverlayIcon.color = new Color(selectedMessageForOptions.OverlayColor[0] / 255f, selectedMessageForOptions.OverlayColor[1] / 255f, selectedMessageForOptions.OverlayColor[2] / 255f);
}
catch (Exception)
{
playerIcon.color = Color.white;
playerOverlayIcon.color = Color.white;
}
}
else
{
Tools.RenderFromBase64(customIcons[selectedMessageForOptions.CustomIcon], playerIcon);
playerOverlayIcon.gameObject.SetActive(false);
}
rowInfo = editMessageChild.GetChild(3);
usernameText = rowInfo.transform.GetChild(2).GetComponent<TMP_Text>();
playerIcon = rowInfo.transform.GetChild(3).GetComponent<Image>();
playerOverlayIcon = playerIcon.transform.GetChild(0).GetComponent<Image>();
messageText = rowInfo.transform.GetChild(4).GetComponent<TMP_Text>();
optionsButton = rowInfo.transform.GetChild(5).GetComponent<Button>();
usernameText.text = selectedMessageForOptions.Username;
messageText.text = Encoding.UTF8.GetString(Convert.FromBase64String(selectedMessageForOptions.Content));
editMessageChildNewContentInputBox.onValueChanged.AddListener((value) => messageText.text = value);
if (selectedMessageForOptions.CustomIcon == null)
{
playerIcon.sprite = Resources.Load<Sprite>("Icons/Icons/bird_" + selectedMessageForOptions.Icon);
if (selectedMessageForOptions.Icon == 1)
{
playerIcon.sprite = Tools.GetIconForUser(selectedMessageForOptions.UserID);
}
playerOverlayIcon.sprite = Resources.Load<Sprite>("Icons/Overlays/overlay_" + selectedMessageForOptions.Overlay);
if (selectedMessageForOptions.Overlay == 0)
{
playerOverlayIcon.gameObject.SetActive(false);
}
else if (selectedMessageForOptions.Overlay == 8)
{
playerOverlayIcon.transform.localPosition = new UnityEngine.Vector2(-16.56f, 14.81f);
}
else if (selectedMessageForOptions.Overlay == 11)
{
playerOverlayIcon.transform.localPosition = new UnityEngine.Vector2(-14.74451f, 20.39122f);
}
else if (selectedMessageForOptions.Overlay == 13)
{
playerOverlayIcon.transform.localPosition = new UnityEngine.Vector2(-16.54019f, 14.70365f);
}
try
{
playerIcon.color = new Color(selectedMessageForOptions.BirdColor[0] / 255f, selectedMessageForOptions.BirdColor[1] / 255f, selectedMessageForOptions.BirdColor[2] / 255f);
playerOverlayIcon.color = new Color(selectedMessageForOptions.OverlayColor[0] / 255f, selectedMessageForOptions.OverlayColor[1] / 255f, selectedMessageForOptions.OverlayColor[2] / 255f);
}
catch (Exception)
{
playerIcon.color = Color.white;
playerOverlayIcon.color = Color.white;
}
}
else
{
Tools.RenderFromBase64(customIcons[selectedMessageForOptions.CustomIcon], playerIcon);
playerOverlayIcon.gameObject.SetActive(false);
}
optionsPanel.SetActive(false);
editMessage.SetActive(true);
});
optionsPanelReportButton.onClick.AddListener(() =>
{
reportMessagePanelReportReason.text = "";
optionsPanel.SetActive(false);
reportMessagePanel.SetActive(true);
});
reportMessagePanelExitButton.onClick.AddListener(() =>
{
editMessagePanelCurrent = null;
reportMessagePanel.SetActive(false);
optionsPanel.SetActive(true);
});
reportMessagePanelSubmitButton.onClick.AddListener(async () =>
{
reportMessagePanel.SetActive(false);
await HandleReport();
editMessagePanelCurrent = null;
selectedMessageForOptions = null;
});
optionsPanelCopyButton.onClick.AddListener(() =>
{
if (selectedMessageForOptions != null) GUIUtility.systemCopyBuffer = Encoding.UTF8.GetString(Convert.FromBase64String(selectedMessageForOptions.Content));
});
optionsPanelCopyButton.onClick.AddListener(optionsPanelExitButton.onClick.Invoke);
}
IEnumerator Loop()
{
while (true)
{
Refresh();
yield return _waitForSeconds3;
}
}
async Task HandleMessageSubmit()
{
if (!sendButton.interactable || messageInputField.text.Trim().Length == 0) return;
backButton.interactable = false;
var text = messageInputField.text.Clone() as string;
messageInputField.text = string.Empty;
if (string.IsNullOrEmpty(text))
{
return;
}
WWWForm dataForm = new();
dataForm.AddField("content", text);
dataForm.AddField("token", BazookaManager.Instance.GetAccountSession());
dataForm.AddField("username", BazookaManager.Instance.GetAccountName());
using UnityWebRequest request = UnityWebRequest.Post(SensitiveInfo.SERVER_DATABASE_PREFIX + "berrydash/sendChatroomMessage.php", dataForm);
request.SetRequestHeader("Requester", "BerryDashClient");
request.SetRequestHeader("ClientVersion", Application.version);
request.SetRequestHeader("ClientPlatform", Application.platform.ToString());
await request.SendWebRequest();
if (request.downloadHandler.text == null)
{
backButton.interactable = true;
return;
}
string response = request.downloadHandler.text;
if (response == "-999")
{
ShowStatus("Server error while fetching data");
}
else if (response == "-998")
{
ShowStatus("Client version too outdated to access servers");
}
else if (response == "-997")
{
ShowStatus("Encryption/decryption issues");
}
else if (response == "-996")
{
ShowStatus("Can't send requests on self-built instance");
}
else
{
var jsonResponse = JObject.Parse(response);
if ((bool)jsonResponse["success"])
{
shouldScrollToBottom = true;
StopCoroutine(refreshLoopRoutine);
refreshLoopRoutine = StartCoroutine(Loop());
}
else
{
ShowStatus((string)jsonResponse["message"]);
}
}
backButton.interactable = true;
}
void ShowStatus(string content)
{
statusMessage = content;
if (statusRoutine != null) StopCoroutine(statusRoutine);
statusRoutine = StartCoroutine(StatusRoutine());
}
async void Update()
{
var max = content.GetComponent<RectTransform>().sizeDelta.y;
var current = content.transform.localPosition.y;
downButton.gameObject.SetActive(Mathf.Abs(max - current) > 0.1f * max);
if (Keyboard.current.escapeKey.wasPressedThisFrame && FindFirstObjectByType<ProfileMenu>() == null)
{
if (optionsPanel.activeSelf) optionsPanelExitButton.onClick.Invoke();
else if (reportMessagePanel.activeSelf) reportMessagePanelExitButton.onClick.Invoke();
else if (editMessagePanelCurrent != null) editMessagePanelCurrent.transform.GetChild(0).GetChild(0).GetComponent<Button>().onClick.Invoke();
else await SceneManager.LoadSceneAsync("MainMenu");
}
}
IEnumerator StatusRoutine()
{
statusText.gameObject.SetActive(true);
statusText.text = statusMessage;
statusText.color = new Color(statusText.color.r, statusText.color.g, statusText.color.b, 0f);
float t = 0f;
while (t < 0.5f)
{
t += Time.deltaTime;
float a = t / 0.5f;
statusText.color = new Color(statusText.color.r, statusText.color.g, statusText.color.b, a);
yield return null;
}
yield return _waitForSeconds2;
t = 0f;
while (t < 0.5f)
{
t += Time.deltaTime;
float a = 1f - (t / 0.5f);
statusText.color = new Color(statusText.color.r, statusText.color.g, statusText.color.b, a);
yield return null;
}
statusText.gameObject.SetActive(false);
statusText.text = "";
statusRoutine = null;
}
async void Refresh()
{
if (isPaused) return;
using UnityWebRequest request = UnityWebRequest.Get(SensitiveInfo.SERVER_DATABASE_PREFIX + "berrydash/getChatroomMessages.php");
request.SetRequestHeader("Requester", "BerryDashClient");
request.SetRequestHeader("ClientVersion", Application.version);
request.SetRequestHeader("ClientPlatform", Application.platform.ToString());
await request.SendWebRequest();
if (request.downloadHandler.text == null)
{
Debug.LogError("Failed to fetch chatroom messages: " + request.error);
return;
}
string response = request.downloadHandler.text;
var shouldClear = true;
switch (response)
{
case "-999":
ShowStatus("Server error while fetching data");
break;
case "-998":
ShowStatus("Client version too outdated to access servers");
break;
case "-997":
ShowStatus("Encryption/decryption issues");
break;
case "-996":
ShowStatus("Can't send requests on self-built instance");
break;
default:
shouldClear = false;
var jsonResponse = JObject.Parse(response);
var messages = jsonResponse["messages"].ToObject<ChatroomMessage[]>();
customIcons = jsonResponse["customIcons"].ToObject<Dictionary<string, string>>();
var localUserId = BazookaManager.Instance.GetAccountID();
var sortedMessages = messages.OrderBy(m => m.ID).ToArray();
for (int i = 0; i < sortedMessages.Length; i++)
{
var message = sortedMessages[i];
var obj = content.transform.Find("ChatroomRow_" + message.ID);
if (message.Deleted)
{
if (obj != null) Destroy(obj.gameObject);
continue;
}
if (obj != null)
{
var txt = obj.GetChild(3).GetComponent<TMP_Text>();
var decoded = Encoding.UTF8.GetString(Convert.FromBase64String(message.Content));
if (txt.text != decoded) txt.text = decoded;
var btn = obj.GetChild(4).GetComponent<Button>();
if (!btn.interactable)
{
btn.interactable = true;
btn.onClick.AddListener(() => OptionsButtonClick(message, localUserId ?? 0));
}
obj.SetSiblingIndex(i);
}
int activeCount = content.transform.Cast<Transform>().Count(t => t.gameObject.activeSelf);
if (activeCount > 50)
{
int toRemove = activeCount - 50;
foreach (Transform item in content.transform)
{
if (!item.gameObject.activeSelf) continue;
Destroy(item.gameObject);
toRemove--;
if (toRemove <= 0) break;
}
}
var rowInfo = Instantiate(sampleObject, content.transform);
rowInfo.transform.SetSiblingIndex(content.transform.childCount - 1);
var bgImg = rowInfo.transform.GetChild(0).GetComponent<Image>();
var usernameText = rowInfo.transform.GetChild(1).GetComponent<TMP_Text>();
var playerIcon = rowInfo.transform.GetChild(2).GetComponent<Image>();
var playerIconButton = rowInfo.transform.GetChild(2).GetComponent<Button>();
var playerOverlayIcon = playerIcon.transform.GetChild(0).GetComponent<Image>();
var messageText = rowInfo.transform.GetChild(3).GetComponent<TMP_Text>();
var optionsButton = rowInfo.transform.GetChild(4).GetComponent<Button>();
usernameText.text = message.Username;
messageText.text = Encoding.UTF8.GetString(Convert.FromBase64String(message.Content));
if (message.CustomIcon == null)
{
playerIcon.sprite = Resources.Load<Sprite>("Icons/Icons/bird_" + message.Icon);
if (message.Icon == 1)
{
playerIcon.sprite = Tools.GetIconForUser(message.UserID);
}
playerOverlayIcon.sprite = Resources.Load<Sprite>("Icons/Overlays/overlay_" + message.Overlay);
if (message.Overlay == 0)
{
playerOverlayIcon.gameObject.SetActive(false);
}
else if (message.Overlay == 8)
{
playerOverlayIcon.transform.localPosition = new UnityEngine.Vector2(-16.56f, 14.81f);
}
else if (message.Overlay == 11)
{
playerOverlayIcon.transform.localPosition = new UnityEngine.Vector2(-14.74451f, 20.39122f);
}
else if (message.Overlay == 13)
{
playerOverlayIcon.transform.localPosition = new UnityEngine.Vector2(-16.54019f, 14.70365f);
}
try
{
playerIcon.color = new Color(message.BirdColor[0] / 255f, message.BirdColor[1] / 255f, message.BirdColor[2] / 255f);
playerOverlayIcon.color = new Color(message.OverlayColor[0] / 255f, message.OverlayColor[1] / 255f, message.OverlayColor[2] / 255f);
}
catch (Exception)
{
playerIcon.color = Color.white;
playerOverlayIcon.color = Color.white;
}
}
else
{
Tools.RenderFromBase64(customIcons[message.CustomIcon], playerIcon);
playerOverlayIcon.gameObject.SetActive(false);
}
playerIconButton.onClick.AddListener(async () =>
{
var clone = Instantiate(profilePrefab.gameObject, profilePrefab.gameObject.transform.parent);
clone.SetActive(true);
await clone.GetComponent<ProfileMenu>().Init(message.UserID);
});
optionsButton.onClick.AddListener(() => OptionsButtonClick(message, localUserId ?? 0));
rowInfo.name = "ChatroomRow_" + message.ID;
var entryComponet = rowInfo.AddComponent<ChatroomMenuEntry>();
entryComponet.Init(bgImg, optionsButton);
rowInfo.SetActive(true);
}
break;
}
if (shouldClear)
{
foreach (Transform item in content.transform)
{
if (!item.gameObject.activeSelf) continue;
Destroy(item.gameObject);
break;
}
}
if (shouldScrollToBottom)
{
shouldScrollToBottom = false;
StartCoroutine(ScrollToBottom());
}
}
async Task HandleDelete()
{
WWWForm dataForm = new();
dataForm.AddField("id", selectedMessageForOptions.ID.ToString());
dataForm.AddField("token", BazookaManager.Instance.GetAccountSession());
dataForm.AddField("username", BazookaManager.Instance.GetAccountName());
using UnityWebRequest request = UnityWebRequest.Post(SensitiveInfo.SERVER_DATABASE_PREFIX + "berrydash/deleteChatroomMessage.php", dataForm);
request.SetRequestHeader("Requester", "BerryDashClient");
request.SetRequestHeader("ClientVersion", Application.version);
request.SetRequestHeader("ClientPlatform", Application.platform.ToString());
await request.SendWebRequest();
shouldScrollToBottom = true;
StopCoroutine(refreshLoopRoutine);
refreshLoopRoutine = StartCoroutine(Loop());
}
async Task HandleEdit()
{
var newContent = editMessagePanelCurrent.transform.GetChild(0).GetChild(4).GetComponent<TMP_InputField>().text;
selectedMessageForOptions.Content = newContent;
WWWForm dataForm = new();
dataForm.AddField("id", selectedMessageForOptions.ID.ToString());
dataForm.AddField("content", newContent);
dataForm.AddField("token", BazookaManager.Instance.GetAccountSession());
dataForm.AddField("username", BazookaManager.Instance.GetAccountName());
using UnityWebRequest request = UnityWebRequest.Post(SensitiveInfo.SERVER_DATABASE_PREFIX + "berrydash/editChatroomMessage.php", dataForm);
request.SetRequestHeader("Requester", "BerryDashClient");
request.SetRequestHeader("ClientVersion", Application.version);
request.SetRequestHeader("ClientPlatform", Application.platform.ToString());
await request.SendWebRequest();
shouldScrollToBottom = true;
StopCoroutine(refreshLoopRoutine);
refreshLoopRoutine = StartCoroutine(Loop());
var button = content.transform.Find("ChatroomRow_" + selectedMessageForOptions.ID).GetChild(4).GetComponent<Button>();
button.onClick.RemoveAllListeners();
button.interactable = false;
}
async Task HandleReport()
{
WWWForm dataForm = new();
dataForm.AddField("id", selectedMessageForOptions.ID.ToString());
dataForm.AddField("reason", reportMessagePanelReportReason.text);
dataForm.AddField("token", BazookaManager.Instance.GetAccountSession());
dataForm.AddField("username", BazookaManager.Instance.GetAccountName());
using UnityWebRequest request = UnityWebRequest.Post(SensitiveInfo.SERVER_DATABASE_PREFIX + "berrydash/reportChatroomMessage.php", dataForm);
request.SetRequestHeader("Requester", "BerryDashClient");
request.SetRequestHeader("ClientVersion", Application.version);
request.SetRequestHeader("ClientPlatform", Application.platform.ToString());
await request.SendWebRequest();
shouldScrollToBottom = true;
StopCoroutine(refreshLoopRoutine);
refreshLoopRoutine = StartCoroutine(Loop());
}
IEnumerator ScrollToBottom()
{
yield return new WaitForEndOfFrame();
content.transform.localPosition = new UnityEngine.Vector2(0f, content.GetComponent<RectTransform>().sizeDelta.y);
}
void OptionsButtonClick(ChatroomMessage message, BigInteger localUserId)
{
selectedMessageForOptions = message;
optionsPanelDeleteButton.transform.parent.gameObject.SetActive(localUserId != 0 && message.UserID == localUserId);
optionsPanelEditButton.transform.parent.gameObject.SetActive(localUserId != 0 && message.UserID == localUserId);
optionsPanelReportButton.transform.parent.gameObject.SetActive(localUserId != 0 && message.UserID != localUserId);
optionsPanel.SetActive(true);
}
}