Initial commit

This commit is contained in:
Thorbjoern
2025-05-26 00:46:28 +02:00
commit e5bca03433
3896 changed files with 1434297 additions and 0 deletions
@@ -0,0 +1,17 @@
using UnityEngine;
namespace XRMultiplayer
{
public class PlayerListInitializer : MonoBehaviour
{
[SerializeField] PlayerListUI[] m_PlayerListUIs;
void Start()
{
foreach (var l in m_PlayerListUIs)
{
l.InitializeCallbacks();
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7bee81ae8e4186d45a1a593720a17674
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,131 @@
using System.Collections.Generic;
using TMPro;
using UnityEngine;
namespace XRMultiplayer
{
public class PlayerListUI : MonoBehaviour
{
[SerializeField] TMP_Text m_PlayerCountText;
[SerializeField] Transform m_ConnectedPlayersViewportContentTransform;
[SerializeField] GameObject m_PlayerSlotPrefab;
[SerializeField] bool m_AutoInitializeCallbacks = true;
readonly Dictionary<PlayerSlot, XRINetworkPlayer> m_PlayerDictionary = new();
bool m_CallbacksInitialized = false;
private void Start()
{
if (!m_CallbacksInitialized && m_AutoInitializeCallbacks)
InitializeCallbacks();
}
private void Update()
{
if (XRINetworkGameManager.Connected.Value)
{
foreach (var kvp in m_PlayerDictionary)
{
kvp.Key.voiceChatFillImage.fillAmount = kvp.Value.playerVoiceAmp;
}
}
}
public void OnDestroy()
{
XRINetworkGameManager.Instance.playerStateChanged -= ConnectedPlayerStateChange;
XRINetworkGameManager.Connected.Unsubscribe(OnConnected);
}
/// <summary>
/// Use this function to initialize the callbacks on objects that start out disabled or inactive.
/// </summary>
public void InitializeCallbacks()
{
if (m_CallbacksInitialized) return;
m_CallbacksInitialized = true;
//Remove Prefab placeholders
foreach (Transform t in m_ConnectedPlayersViewportContentTransform)
{
Destroy(t.gameObject);
}
XRINetworkGameManager.Instance.playerStateChanged += ConnectedPlayerStateChange;
XRINetworkGameManager.Connected.Subscribe(OnConnected);
}
void OnConnected(bool connected)
{
if (!connected)
{
foreach (Transform t in m_ConnectedPlayersViewportContentTransform)
{
Destroy(t.gameObject);
}
m_PlayerDictionary.Clear();
}
}
void ConnectedPlayerStateChange(ulong playerId, bool connected)
{
if (connected)
{
SetupPlayerSlotUI(playerId);
}
else
{
RemovePlayerSlotUI(playerId);
}
}
void RemovePlayerSlotUI(ulong playerId)
{
PlayerSlot slotToRemove = null;
foreach (PlayerSlot slot in m_PlayerDictionary.Keys)
{
if (slot.playerID == playerId)
{
slotToRemove = slot;
break;
}
}
if (slotToRemove != null)
{
m_PlayerDictionary.Remove(slotToRemove);
Destroy(slotToRemove.gameObject);
m_PlayerCountText.text = $"{m_PlayerDictionary.Keys.Count}/{XRINetworkGameManager.Instance.lobbyManager.connectedLobby.MaxPlayers}";
}
}
void SetupPlayerSlotUI(ulong playerId)
{
PlayerSlot slot = Instantiate(m_PlayerSlotPrefab, m_ConnectedPlayersViewportContentTransform).GetComponent<PlayerSlot>();
slot.playerID = playerId;
if (XRINetworkGameManager.Instance.GetPlayerByID(playerId, out XRINetworkPlayer player))
{
if (m_PlayerDictionary.TryAdd(slot, player))
{
slot.Setup(player);
if (player.IsLocalPlayer)
{
slot.playerSlotName.text += " (You)";
}
slot.playerIconImage.color = player.playerColor;
m_PlayerCountText.text = $"{m_PlayerDictionary.Keys.Count}/{XRINetworkGameManager.Instance.lobbyManager.connectedLobby.MaxPlayers}";
}
}
else
{
Utils.Log($"Player with id {playerId} is null. This is a bug.", 2);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 890d351bcb11f5245838066b83e72d7c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,92 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using WebSocketSharp;
namespace XRMultiplayer
{
public class PlayerSlot : MonoBehaviour
{
public TMP_Text playerSlotName;
public TMP_Text playerInitial;
public Image playerIconImage;
[Header("Mic Button")]
public Image voiceChatFillImage;
[SerializeField] Button m_MicButton;
[SerializeField] Image m_PlayerVoiceIcon;
[SerializeField] Image m_SquelchedIcon;
[SerializeField] Sprite[] micIcons;
XRINetworkPlayer m_Player;
internal ulong playerID = 0;
public void Setup(XRINetworkPlayer player)
{
m_Player = player;
m_Player.onColorUpdated += UpdateColor;
m_Player.onNameUpdated += UpdateName;
m_Player.selfMuted.OnValueChanged += UpdateSelfMutedState;
m_MicButton.onClick.AddListener(Squelch);
m_Player.squelched.Subscribe(UpdateSquelchedState);
m_SquelchedIcon.enabled = false;
if (m_Player.IsLocalPlayer)
{
m_MicButton.interactable = false;
}
if (m_Player.selfMuted.Value)
{
m_PlayerVoiceIcon.sprite = micIcons[1];
}
}
void OnDestroy()
{
m_Player.onColorUpdated -= UpdateColor;
m_Player.onNameUpdated -= UpdateName;
m_Player.selfMuted.OnValueChanged -= UpdateSelfMutedState;
m_MicButton.onClick.RemoveListener(Squelch);
m_Player.squelched.Unsubscribe(UpdateSquelchedState);
}
void UpdateColor(Color newColor)
{
playerIconImage.color = newColor;
}
void UpdateName(string newName)
{
if (!newName.IsNullOrEmpty())
{
string playerName = newName;
if (m_Player.IsLocalPlayer)
{
playerName += " (You)";
}
else if (m_Player.IsOwnedByServer)
{
playerName += " (Host)";
}
playerSlotName.text = playerName;
playerInitial.text = newName.Substring(0, 1);
}
}
#region Muting
public void Squelch()
{
m_Player.ToggleSquelch();
}
void UpdateSelfMutedState(bool old, bool current)
{
m_PlayerVoiceIcon.sprite = micIcons[current ? 1 : 0];
}
void UpdateSquelchedState(bool squelched)
{
m_SquelchedIcon.enabled = squelched;
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7282738eeb6afb24e9419b8ff287a61e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: