I created my NetPlayerlist you suggest here with:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using Unity.Services.Lobbies.Models;
public class NetPlayerList : MonoBehaviour
{
public static NetPlayerList singleton;
Dictionary<uint, Player> players = new Dictionary<uint, Player>();
public Dictionary<uint, Player> Players { get => players; }
}
in My NetworkBicyleScript i have:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
using Unity.Collections;
using Unity.Services.Lobbies;
using Unity.Services.Lobbies.Models;
using Unity.Services.Relay;
using TMPro;
//Handles network specific functions for multiplayer bicycles
public class NetworkBicycle : NetworkBehaviour {
public GameObject nameTag; // try to add to a list
public GameObject wkg;
//Network variables can not be nullable, so we have to use a fixed string
private NetworkVariable<FixedString32Bytes> playerName = new NetworkVariable<FixedString32Bytes>();
private NetworkVariable<FixedString128Bytes> playerLobbyId = new NetworkVariable<FixedString128Bytes>();
private NetworkVariable<FixedString32Bytes> playerWKG = new NetworkVariable<FixedString32Bytes>();
public override void OnNetworkSpawn()
{
playerName.OnValueChanged += OnPlayerNameChanged;
if (IsOwner)
{
SetPlayerNameServerRpc(PlayerPrefs.GetString("BikerName", "Unnamed Player"));
SetPlayerLobbyIdServerRpc(LobbyManager.singleton.GetCurPlayerId());
if (IsLocalPlayer)
{
SetPlayerNameServerRpc(PlayerPrefs.GetString("BikerName", "Unnamed Player"));
SetPlayerLobbyIdServerRpc(LobbyManager.singleton.GetCurPlayerId());
}
} else {
SetNameTag(playerName.Value.ToString());
SetWattKG(playerWKG.Value.ToString());
}
}
[ServerRpc]
public void SetPlayerNameServerRpc(string name)
{
playerName.Value = name;
}
[ServerRpc]
public void SetPlayerLobbyIdServerRpc(string id)
{
playerLobbyId.Value = id;
}
private void OnPlayerNameChanged(FixedString32Bytes previousValue, FixedString32Bytes newValue)
{
Debug.Log("Player OnPlayerNameChanged playerName: " + newValue);
// add player to list
// display tag on UI
}
private void SetNameTag(string name)
{
if (nameTag == null) {
return;
}
nameTag.GetComponent<TextMeshPro>().text = name;
}
public void SetWattKG(string _wkg)
{
if (wkg == null)
{
return;
}
wkg.GetComponent<TextMeshPro>().text = playerWKG.Value.ToString();
//Debug.Log("MoreValue" + playerWKG.Value.ToString());
}
private void Update()
{
if (IsOwner)
{
var bikeUI = GameObject.FindGameObjectWithTag("BikeComputer").GetComponent<BikeComputerUI>();
SetWattKGServerRpc(bikeUI.wkg.text);
// Debug.Log("UpdatedValue" + playerWKG.Value.ToString());
}
SetWattKG(playerWKG.Value.ToString());
}
[ServerRpc]
public void SetWattKGServerRpc(string _wkg)
{
playerWKG.Value = _wkg;
// Debug.Log("We ve got value" + _wkg);
}
public override void OnNetworkDespawn()
{
string playerId =
NetPlayerList.Instance().Players.Remove(playerId);
// remove player from UI
}
private void OnDestroy() {
if (IsServer) {
LobbyService.Instance.RemovePlayerAsync(LobbyManager.singleton.GetCurLobby().Id, playerLobbyId.Value.ToString());
}
if (IsOwner) {
LobbyManager.singleton.Shutdown(true);
}
}
}
changes like you suggested. but gives me a âno definationâ for
NetPlayerList.Instance().Players.Remove(playerId);
I have also my LobbyManager posted here:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using Unity.Services;
using Unity.Services.Authentication;
using Unity.Services.Core;
using Unity.Services.Relay;
using Unity.Services.Relay.Models;
using Unity.Services.Lobbies;
using Unity.Services.Lobbies.Models;
using ParrelSync; ///Needs to be Disabled when you build
using System.Threading.Tasks;
using UnityEngine.SceneManagement;
[RequireComponent(typeof(NetworkManager))]
public class LobbyManager : MonoBehaviour {
public static LobbyManager singleton;
private string playerId;
private UnityTransport transport;
public const string joinCodeKey = "jc";
public const string sceneNameKey = "scnm";
public const string hostNameKey = "hname";
private Lobby curLobby;
private void Awake() {
LobbyManager.singleton = this;
transport = FindObjectOfType<UnityTransport>();
}
private void Start() {
Authenticate();
}
private async Task Authenticate() {
if (UnityServices.State == ServicesInitializationState.Uninitialized) {
var options = new InitializationOptions();
//Needs to be Disabled when you build
#if UNITY_EDITOR
//Used to differentiate clients when using ParrelSync
options.SetProfile(ClonesManager.IsClone() ? ClonesManager.GetArgument() : "Primary");
#endif
await UnityServices.InitializeAsync(options);
}
if (!AuthenticationService.Instance.IsSignedIn) {
await AuthenticationService.Instance.SignInAnonymouslyAsync();
}
playerId = AuthenticationService.Instance.PlayerId;
}
private static IEnumerator HeartbeatLobbyCoroutine(string lobbyId, float waitTimeSeconds) {
var delay = new WaitForSecondsRealtime(waitTimeSeconds);
while (true) {
LobbyService.Instance.SendHeartbeatPingAsync(lobbyId);
yield return delay;
}
}
public async Task<List<Lobby>> GatherLobbies() {
var options = new QueryLobbiesOptions { Count = 15, };
var allLobbies = await LobbyService.Instance.QueryLobbiesAsync(options);
return allLobbies.Results;
}
public async Task<Lobby> CreateLobby(string hostName) {
try {
string joinCode = await RelayManager.singleton.CreateGame();
var options = new CreateLobbyOptions {
Data = new Dictionary<string, DataObject> {
{ joinCodeKey, new DataObject(DataObject.VisibilityOptions.Public, joinCode) },
{ sceneNameKey, new DataObject(DataObject.VisibilityOptions.Public, SceneManager.GetActiveScene().name) },
{ hostNameKey, new DataObject(DataObject.VisibilityOptions.Public, hostName)}
}
};
var lobby = await LobbyService.Instance.CreateLobbyAsync("Lobby Name", RelayManager.singleton.maxPlayerCount, options);
curLobby = lobby;
StartCoroutine(HeartbeatLobbyCoroutine(lobby.Id, 15));
return lobby;
} catch (System.Exception e) {
Debug.LogError("Failed to create lobby");
Debug.LogError(e);
throw;
}
}
public async Task<Lobby> CreateLobbyDedServer(string hostName)
{
try
{
string joinCode = await RelayManager.singleton.CreateDedicatedServer();
var options = new CreateLobbyOptions
{
Data = new Dictionary<string, DataObject> {
{ joinCodeKey, new DataObject(DataObject.VisibilityOptions.Public, joinCode) },
{ sceneNameKey, new DataObject(DataObject.VisibilityOptions.Public, SceneManager.GetActiveScene().name) },
{ hostNameKey, new DataObject(DataObject.VisibilityOptions.Public, hostName)}
}
};
var lobby = await LobbyService.Instance.CreateLobbyAsync("Lobby Name", RelayManager.singleton.maxPlayerCount, options);
curLobby = lobby;
StartCoroutine(HeartbeatLobbyCoroutine(lobby.Id, 15));
//NetworkManager.Singleton.
return lobby;
}
catch (System.Exception e)
{
Debug.LogError("Failed to create lobby");
Debug.LogError(e);
throw;
}
}
public async Task JoinLobby(string lobbyId) {
try {
curLobby = await LobbyService.Instance.JoinLobbyByIdAsync(lobbyId);
await RelayManager.singleton.JoinGame(curLobby.Data[LobbyManager.joinCodeKey].Value);
} catch (System.Exception e) {
Debug.LogError("Failed to join lobby");
Debug.LogError(e);
throw;
}
}
//To be called by other scripts to shut down network services and optionally to return to menu
public void Shutdown(bool returnToMenu) {
if (GlobalValues.GetGameMode() == GlobalValues.GameMode.Single || curLobby == null) {
return;
}
// Destroy(NetworkManager.Singleton.gameObject);
NetworkManager.Singleton.Shutdown();
if (returnToMenu) {
ReturnToMenu();
}
}
//Returns to menu
private void ReturnToMenu() {
Destroy(NetworkManager.Singleton.gameObject);
// SceneManager.LoadScene(0);
}
public Lobby GetCurLobby() {
return curLobby;
}
public string GetCurPlayerId() {
return playerId;
}
}
I am still struggle and i think i mix to much different places 
The complete day i am busy with that 
The playerId i grab now with:
string playerId = LobbyManager.singleton.GetCurPlayerId();