Skip to content

Commit

Permalink
Prepare Remote Player List for Display
Browse files Browse the repository at this point in the history
Introduce a `RemotePlayer` class with `PlayerId`,  `Nickname` and `ItransientData`, extendable with Role (e.g., observer/editor/owner) and VoiceStatus (e.g., muted/active speaker). Abstracts player details from the Photon SDK for better flexibility and clarity.
Includes a list of `RemotePlayer` ready to be displayed and interacted with on a panel.
  • Loading branch information
sbanca committed Jan 18, 2025
1 parent 8c674bf commit a7879bb
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 18 deletions.
2 changes: 2 additions & 0 deletions Assets/Scripts/Multiplayer/MultiplayerDataStructs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,6 @@ public struct ConnectionUserInfo
public string Nickname;
public string Role;
}


}
34 changes: 17 additions & 17 deletions Assets/Scripts/Multiplayer/MultiplayerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ public class MultiplayerManager : MonoBehaviour
private IVoiceConnectionHandler m_VoiceManager;

public ITransientData<PlayerRigData> m_LocalPlayer;
public List<ITransientData<PlayerRigData>> m_RemotePlayers;
public List<RemotePlayer> m_RemotePlayers;

public Action<int, ITransientData<PlayerRigData>> localPlayerJoined;
public Action<int, ITransientData<PlayerRigData>> remotePlayerJoined;
public Action<RemotePlayer> remotePlayerJoined;
public Action<int, GameObject> remoteVoiceAdded;
public Action<int> playerLeft;
public Action<List<RoomData>> roomDataRefreshed;
Expand Down Expand Up @@ -110,7 +110,7 @@ void Awake()
{
m_Instance = this;
oculusPlayerIds = new List<ulong>();
m_RemotePlayers = new List<ITransientData<PlayerRigData>>();
m_RemotePlayers = new List<RemotePlayer>();
}

void Start()
Expand Down Expand Up @@ -374,8 +374,10 @@ void Update()

// Update remote user refs, and send Anchors if new player joins.
bool newUser = false;
foreach (var player in m_RemotePlayers)
foreach (var playerData in m_RemotePlayers)
{
ITransientData<PlayerRigData> player = playerData.TransientData;

if (!player.IsSpawned) continue;

data = player.ReceiveData();
Expand Down Expand Up @@ -409,43 +411,41 @@ void OnLocalPlayerJoined(int id, ITransientData<PlayerRigData> playerData)

}

void OnRemotePlayerJoined(int id, ITransientData<PlayerRigData> playerData)
{
playerData.PlayerId = id;
m_RemotePlayers.Add(playerData);
void OnRemotePlayerJoined(RemotePlayer newRemotePlayer)
{
m_RemotePlayers.Add(newRemotePlayer);

if (isUserRoomOwner)
{
MultiplayerSceneSync.m_Instance.StartSyncronizationForUser(id);
MultiplayerSceneSync.m_Instance.StartSyncronizationForUser(newRemotePlayer.PlayerId);
}

}

public void OnRemoteVoiceConnected(int id, GameObject voicePrefab)
{
ITransientData<PlayerRigData> playerData = m_RemotePlayers.First(x => x.PlayerId == id);
if (playerData == null)
RemotePlayer playerData = m_RemotePlayers.First(x => x.PlayerId == id);
if (playerData == default)
{
Debug.LogWarning($"PlayerRigData with ID {id} not found");
return;
}


GameObject RemotePlayerGameObject = m_Manager.GetPlayerPrefab(id);
if (RemotePlayerGameObject == null)
if (playerData.PlayerGameObject == null)
{
Debug.LogWarning($"RemotePlayerGameObject with ID {id} not found");
return;
}

Transform headTransform = RemotePlayerGameObject.transform.Find("HeadTransform");
Transform headTransform = playerData.PlayerGameObject.transform.Find("HeadTransform");
if (headTransform != null)
{
voicePrefab.transform.SetParent(headTransform, false);
playerData.VoiceGameObject = voicePrefab;
}
else
{
Debug.LogWarning($"HeadTransform not found in {RemotePlayerGameObject.name}");
Debug.LogWarning($"HeadTransform not found in {playerData.PlayerGameObject.name}");
}

AudioSource audioSource = voicePrefab.GetComponent<AudioSource>();
Expand Down Expand Up @@ -496,7 +496,7 @@ void OnPlayerLeft(int id)

// Since There are other players left
// Determine the new room owner by the lowest PlayerId
var allPlayers = new List<ITransientData<PlayerRigData>> { m_LocalPlayer };
var allPlayers = new List<RemotePlayer> { new RemotePlayer { PlayerId = m_LocalPlayer.PlayerId } };
allPlayers.AddRange(m_RemotePlayers);

// Find the player with the lowest PlayerId
Expand Down
21 changes: 20 additions & 1 deletion Assets/Scripts/Multiplayer/Photon/PhotonManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,15 @@ public void Update()
NetworkObject newPlayer = m_Runner.GetPlayerObject(player);
if (newPlayer != null)
{
m_Manager.remotePlayerJoined?.Invoke(player.RawEncoded, newPlayer.GetComponent<PhotonPlayerRig>());
RemotePlayer newRemotePlayer = new RemotePlayer
{
PlayerId = player.RawEncoded,
Nickname = GetPlayerNickname(player.RawEncoded),
TransientData = newPlayer.GetComponent<PhotonPlayerRig>(),
PlayerGameObject = newPlayer.gameObject
};

m_Manager.remotePlayerJoined?.Invoke(newRemotePlayer);
m_PlayersSpawning.Remove(player);
}
}
Expand Down Expand Up @@ -272,6 +280,17 @@ public bool GetPlayerRoomOwnershipStatus(int playerId)
else return false;
}

public string GetPlayerNickname(int playerId)
{
var remotePlayer = m_PlayersSpawning
.Select(playerRef => m_Runner.GetPlayerObject(playerRef)?.GetComponent<PhotonPlayerRig>())
.FirstOrDefault(playerRig => playerRig != null && playerRig.PlayerId == playerId);

if (remotePlayer != null && remotePlayer.Object != null && remotePlayer.Object.IsValid)
return remotePlayer.Nickname;
else return "default";
}

public GameObject GetPlayerPrefab(int playerId)
{
if (m_Runner == null) return null;
Expand Down
36 changes: 36 additions & 0 deletions Assets/Scripts/Multiplayer/RemotePlayer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2023 The Open Brush Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace OpenBrush.Multiplayer
{

[System.Serializable]
public class RemotePlayer
{
public int PlayerId;
public string Nickname;

// send/receive rig data interface
public ITransientData<PlayerRigData> TransientData;

// The underlying GameObjects in the scene that represents this player
public GameObject PlayerGameObject;
public GameObject VoiceGameObject;
}

}
11 changes: 11 additions & 0 deletions Assets/Scripts/Multiplayer/RemotePlayer.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a7879bb

Please sign in to comment.