Lobby
The Lobby profile card shows the signed-in player's name and level. The profile is loaded during startup, so the Lobby normally opens with it ready; returning from a mission or another scene shows the updated profile with nothing to reload.
| You use | It gives you |
|---|---|
IProjectVLobbyScreen | The screen contract: observe the profile card |
ProjectVLobbyView | What to draw: loading state and the profile |
ProjectVLobbyProfile | The player's name and level |
The screen has no commands: observe it and render. See Screen contracts for how screens work in general.
Quick startโ
using System;
using SilverTiger.ProjectV.Unity.Presentation.Lobby;
using UnityEngine;
using VContainer;
public sealed class LobbyProfileCard : MonoBehaviour
{
private IProjectVLobbyScreen lobby = null!;
private IDisposable? observation;
[Inject]
public void Construct(IProjectVLobbyScreen screen) => lobby = screen;
private void OnEnable()
{
ShowLoading(null); // until the first Render call
observation = lobby.Observe(Render);
}
private void OnDisable()
{
observation?.Dispose();
observation = null;
}
// Always called on the Unity main thread.
private void Render(ProjectVLobbyView view)
{
if (view.IsLoading)
{
ShowLoading(view.LoadError); // null while loading; an error code after a failed load
return;
}
ShowProfile(view.Profile!.DisplayName, view.Profile.Level);
}
// Retry button shown with a load error.
public void OnRetryClicked()
{
observation?.Dispose();
observation = lobby.Observe(Render);
}
private void ShowLoading(string? loadError) { }
private void ShowProfile(string displayName, long level) { }
}
That is the whole card: observe and draw. Render runs again only when the
profile changes, for example after a mission raised the player's level.
What to drawโ
Render receives a ProjectVLobbyView:
| Member | Type | Use it for |
|---|---|---|
IsLoading | bool | True while no profile is shown: before the first load, after a failed load, and after sign-out. Show a spinner |
LoadError | string? | The error code of a failed load, or null. Not player text: show your own "could not load" message with Retry, and keep the code for logs |
Profile | ProjectVLobbyProfile? | The profile; null while IsLoading |
lobby.Current holds the same view.
For the ProjectVLobbyProfile:
| To show | Read |
|---|---|
| The player's name | DisplayName (falls back to Username when the player has none) |
| The level | Level, 1 or higher, as the server sent it |
| The avatar | Your default avatar. AvatarUrl is always empty for now |
| The avatar frame | Nothing yet. AvatarFrameId is always null for now |
UserId is the account ID; do not show it.
When it failsโ
| Situation | What the view does | What the player sees |
|---|---|---|
| The first load failed | IsLoading true with LoadError set | Your load-error message with Retry |
| A later refresh failed | The profile is dropped; back to IsLoading with LoadError set | The same; the old profile is not kept |
| The player signed out | IsLoading true, LoadError null | Nothing; the game is going to Login |
Retry by disposing the observation and calling Observe again, as
OnRetryClicked does. Every Observe call loads the profile when needed.
Rulesโ
- Show your loading state before calling
Observe; the firstRendercall can come a moment later. - Show
Levelas the server sent it. Never work it out from local progress. - Do not refresh on Lobby entry.
Observeloads the profile when needed, and usually it is already there.
Common mistakesโ
- Showing
LoadErrorto the player. It is an error code. - Loading the avatar from
AvatarUrl. It is always empty for now; show the default avatar. - Keeping the old profile on screen after a failed refresh. The view goes
back to loading; draw what
Rendergives you. - Not disposing the observation. Keep the
IDisposablefromObserveand dispose it inOnDisableorOnDestroy.
Presenterโ
IProjectVLobbyPresenter is
the lower-level interface behind the screen contract. Pages normally use
IProjectVLobbyScreen; use the presenter only if you need its extra detail:
| Member | Returns | Use it for |
|---|---|---|
SubscribeAsync(listener) | Task<IDisposable> | The current ProjectVLobbySnapshot, then every change |
RefreshAsync(token) | ProjectVLobbyCommandResult | Load the profile; calls run one at a time |
Current | ProjectVLobbySnapshot | The latest state |
The snapshot has Status (Empty, Refreshing, Ready, Failed),
Profile, IsReady and a full
ProjectVLobbyError with
Category, Code, RequestId and LocalizationKey
(projectv.lobby.<category>). RefreshAsync does not throw for a failed
load: IsSuccess is false when the load failed, was cancelled
(PROJECTV_LOBBY_CANCELLED), or the player signed out meanwhile.
Presenter listeners may run off the Unity main thread; switch to the main
thread (for example await UniTask.SwitchToMainThread()) before touching
Unity objects. The screen's Render does this for you.