Skip to content

Commit

Permalink
fix: logout flow (#3018)
Browse files Browse the repository at this point in the history
* Logout flow

* Be in Mordor while scene loads

* Clear chat history and mordor position encapsulation

* UNload PX, remove unnecessary RestartRealmOperation, start gathering logout operations

* Deleted RestartRealmStartupOperation

* Rollback on condition of `SceneRoomMetaDataSource`

* Fixed issue with PXs entities being removed when changing realm

* Fixed issue with PX scene entity not being properly removed after killing a PX

* Fix async method

* Unified mordor constants and moved the file to a better location

---------

Co-authored-by: Fran Colarich <[email protected]>
  • Loading branch information
dalkia and fcolarich authored Dec 19, 2024
1 parent 739d888 commit ad579eb
Show file tree
Hide file tree
Showing 20 changed files with 113 additions and 119 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ private void TeleportPlayer(Entity entity, CharacterController controller, ref C

switch (status.TaskStatus)
{
case UniTaskStatus.Pending:
// Teleport the character to a far away place while the teleport is executed
controller.transform.position = MordorConstants.PLAYER_MORDOR_POSITION;
return;
case UniTaskStatus.Succeeded:
ResolveAsSuccess(entity, in teleportIntent, controller, ref platformComponent);
return;
Expand Down
2 changes: 1 addition & 1 deletion Explorer/Assets/DCL/PluginSystem/World/TransformsPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ private void CreateReservedTransforms(ArchSystemsWorldBuilder<Arch.Core.World> b
{
//The scene container, which is only modified by the client, starts in a position that cannot be seen by the player. Once it finished loading
//in GatherGLTFAssetSystem.cs, it will be moved to the correct position.
var sceneRootContainerTransform = GetNewTransform(position: new Vector3(0, -10000, 0));
var sceneRootContainerTransform = GetNewTransform(position: MordorConstants.SCENE_MORDOR_POSITION);
sceneRootContainerTransform.name = $"{sharedDependencies.SceneData.SceneShortInfo.BaseParcel}_{sharedDependencies.SceneData.SceneShortInfo.Name}_Container";
builder.World.Add(persistentEntities.SceneContainer, new TransformComponent(sceneRootContainerTransform));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,13 @@
using ECS.LifeCycle.Components;
using ECS.Unity.Transforms.Components;
using SceneRunner.Scene;
using System;
using UnityEngine;

namespace DCL.SDKComponents.AvatarAttach.Systems
{
[UpdateInGroup(typeof(SyncedPreRenderingSystemGroup))]
[LogCategory(ReportCategory.AVATAR_ATTACH)]
public partial class AvatarAttachHandlerSystem : BaseUnityLoopSystem, IFinalizeWorldSystem
{
/// <summary>
/// Integrated from the previous implementation
/// </summary>
private static readonly Vector3 MORDOR = Vector3.one * 8000;

private static readonly QueryDescription ENTITY_DESTRUCTION_QUERY = new QueryDescription().WithAll<DeleteEntityIntention, AvatarAttachComponent>();
private static readonly QueryDescription COMPONENT_REMOVAL_QUERY = new QueryDescription().WithAll<AvatarAttachComponent>().WithNone<DeleteEntityIntention, PBAvatarAttach>();
private readonly ObjectProxy<AvatarBase> mainPlayerAvatarBaseProxy;
Expand Down Expand Up @@ -54,7 +47,7 @@ protected override void Update(float t)
private void HideDetached(ref TransformComponent transformComponent)
{
if (!sceneStateProvider.IsCurrent) return;
transformComponent.Apply(MORDOR);
transformComponent.Apply(MordorConstants.AVATAR_ATTACH_MORDOR_POSITION);
}

[Query]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ await userInAppInitializationFlow.ExecuteAsync(
new UserInAppInitializationFlowParameters(
showAuthentication: true,
showLoading: true,
reloadRealm: true,
loadSource: IUserInAppInitializationFlow.LoadSource.Recover,
world: world,
playerEntity: playerEntity
Expand Down
5 changes: 0 additions & 5 deletions Explorer/Assets/DCL/UI/SystemMenu/SystemMenuController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,9 @@ async UniTaskVoid LogoutAsync(CancellationToken ct)
profileCache.Remove(address);

await userInAppInitializationFlow.ExecuteAsync(

// We have to reload the realm so the scenes are recreated when coming back to the world
// The realm fetches the scene entity definitions again and creates the components in ecs
// so the SceneFacade can be later attached into the entity
new UserInAppInitializationFlowParameters(
showAuthentication: true,
showLoading: true,
reloadRealm: true,
loadSource: IUserInAppInitializationFlow.LoadSource.Logout,
world: world,
playerEntity: playerEntity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
"GUID:a285ec5e26824438b1b2ab8f22969298",
"GUID:e169fa6683c924c7e99a85981a91d953",
"GUID:e25ef972de004615a22937e739de2def",
"GUID:d28a7e4beeca475418c15757abf1b6f1"
"GUID:d28a7e4beeca475418c15757abf1b6f1",
"GUID:766b242fb43af451aaa331f39872177d"
],
"includePlatforms": [],
"excludePlatforms": [],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using CommunicationData.URLHelpers;
using System;
using System.Threading;
using System.Threading.Tasks;
using CommunicationData.URLHelpers;
using Cysharp.Threading.Tasks;
using DCL.Audio;
using DCL.AuthenticationScreenFlow;
using DCL.AvatarRendering.AvatarShape.UnityInterface;
using DCL.Chat.History;
using DCL.Diagnostics;
using DCL.FeatureFlags;
using DCL.Multiplayer.Connections.DecentralandUrls;
Expand Down Expand Up @@ -33,16 +35,20 @@ public class RealUserInAppInitializationFlow : IUserInAppInitializationFlow
private static readonly ILoadingScreen.EmptyLoadingScreen EMPTY_LOADING_SCREEN = new ();

private readonly ILoadingStatus loadingStatus;
private readonly IDecentralandUrlsSource decentralandUrlsSource;
private readonly IMVCManager mvcManager;
private readonly AudioClipConfig backgroundMusic;
private readonly IRealmNavigator realmNavigator;
private readonly ILoadingScreen loadingScreen;
private readonly IRoomHub roomHub;
private readonly LoadPlayerAvatarStartupOperation loadPlayerAvatarStartupOperation;
private readonly CheckOnboardingStartupOperation checkOnboardingStartupOperation;
private readonly RestartRealmStartupOperation restartRealmStartupOperation;
private readonly IStartupOperation startupOperation;
private readonly IStartupOperation reloginOperation;
private readonly IDecentralandUrlsSource decentralandUrlsSource;
private readonly IChatHistory chatHistory;

private readonly IRealmController realmController;
private readonly IRoomHub roomHub;
private readonly IPortableExperiencesController portableExperiencesController;

public RealUserInAppInitializationFlow(
ILoadingStatus loadingStatus,
Expand All @@ -67,7 +73,7 @@ public RealUserInAppInitializationFlow(
IRoomHub roomHub,
IAnalyticsController analyticsController,
DiagnosticsContainer diagnosticsContainer,
URLDomain defaultStartingRealm
ChatHistory chatHistory
)
{
this.loadingStatus = loadingStatus;
Expand All @@ -76,6 +82,9 @@ URLDomain defaultStartingRealm
this.backgroundMusic = backgroundMusic;
this.realmNavigator = realmNavigator;
this.loadingScreen = loadingScreen;
this.realmController = realmController;
this.portableExperiencesController = portableExperiencesController;
this.chatHistory = chatHistory;
this.roomHub = roomHub;

var ensureLivekitConnectionStartupOperation = new EnsureLivekitConnectionStartupOperation(loadingStatus, livekitHealthCheck);
Expand All @@ -85,7 +94,6 @@ URLDomain defaultStartingRealm
loadPlayerAvatarStartupOperation = new LoadPlayerAvatarStartupOperation(loadingStatus, selfProfile, mainPlayerAvatarBaseProxy);
var loadLandscapeStartupOperation = new LoadLandscapeStartupOperation(loadingStatus, landscape);
checkOnboardingStartupOperation = new CheckOnboardingStartupOperation(loadingStatus, selfProfile, featureFlagsCache, decentralandUrlsSource, appParameters, realmNavigator);
restartRealmStartupOperation = new RestartRealmStartupOperation(loadingStatus, realmController, defaultStartingRealm);
var teleportStartupOperation = new TeleportStartupOperation(loadingStatus, realmNavigator, startParcel);
var loadGlobalPxOperation = new LoadGlobalPortableExperiencesStartupOperation(loadingStatus, selfProfile, featureFlagsCache, debugSettings, portableExperiencesController);
var sentryDiagnostics = new SentryDiagnosticStartupOperation(realmController, diagnosticsContainer);
Expand All @@ -99,73 +107,78 @@ URLDomain defaultStartingRealm
loadPlayerAvatarStartupOperation,
loadLandscapeStartupOperation,
checkOnboardingStartupOperation,
restartRealmStartupOperation,
teleportStartupOperation,
loadGlobalPxOperation,
sentryDiagnostics
).WithAnalytics(analyticsController);


reloginOperation = new SequentialStartupOperation(
loadingStatus,
ensureLivekitConnectionStartupOperation,
preloadProfileStartupOperation,
switchRealmMiscVisibilityStartupOperation,
loadPlayerAvatarStartupOperation,
loadLandscapeStartupOperation,
checkOnboardingStartupOperation,
teleportStartupOperation,
loadGlobalPxOperation,
sentryDiagnostics).WithAnalytics(analyticsController);
;
;
}


public async UniTask ExecuteAsync(UserInAppInitializationFlowParameters parameters, CancellationToken ct)
{
loadingStatus.SetCurrentStage(LoadingStatus.LoadingStage.Init);

EnumResult<TaskError> result = parameters.RecoveryError;

loadPlayerAvatarStartupOperation.AssignWorld(parameters.World, parameters.PlayerEntity);
restartRealmStartupOperation.EnableReload(parameters.ReloadRealm);

using UIAudioEventsBus.PlayAudioScope playAudioScope = UIAudioEventsBus.Instance.NewPlayAudioScope(backgroundMusic);

do
{
if (parameters.LoadSource is not IUserInAppInitializationFlow.LoadSource.StartUp)

// Disconnect current livekit connection on logout so the avatar is removed from other peers
await roomHub.StopAsync().Timeout(TimeSpan.FromSeconds(10));

if (parameters.ShowAuthentication)
{
loadingStatus.SetCurrentStage(LoadingStatus.LoadingStage.AuthenticationScreenShowing);

await UniTask.WhenAll(
ShowAuthenticationScreenAsync(ct),
ShowErrorPopupIfRequired(result, ct)
);
if (parameters.LoadSource is IUserInAppInitializationFlow.LoadSource.Logout)
{
await DoLogoutOperationsAsync();
//Restart the realm and show the authentications screen simultaneously to avoid the "empty space" flicker
//No error should be possible at this point
await UniTask.WhenAll(ShowAuthenticationScreenAsync(ct),
realmController.SetRealmAsync(
URLDomain.FromString(decentralandUrlsSource.Url(DecentralandUrl.Genesis)), ct));
}
else
{
await UniTask.WhenAll(
ShowAuthenticationScreenAsync(ct),
ShowErrorPopupIfRequired(result, ct)
);
}
}

if (parameters.LoadSource is IUserInAppInitializationFlow.LoadSource.Logout)
{
// If we are coming from a logout, we teleport the user to Genesis Plaza and force realm change to reset the scene properly
var url = URLDomain.FromString(decentralandUrlsSource.Url(DecentralandUrl.Genesis));
var changeRealmResult = await realmNavigator.TryChangeRealmAsync(url, ct);

if (changeRealmResult.Success == false)
ReportHub.LogError(ReportCategory.AUTHENTICATION, changeRealmResult.AsResult().ErrorMessage!);

// Restart livekit connection
await roomHub.StartAsync().Timeout(TimeSpan.FromSeconds(10));

result = changeRealmResult.As(ChangeRealmErrors.AsTaskError);
var flowToRun = parameters.LoadSource is IUserInAppInitializationFlow.LoadSource.Logout
? reloginOperation
: startupOperation;
var loadingResult = await LoadingScreen(parameters.ShowLoading)
.ShowWhileExecuteTaskAsync(
async (parentLoadReport, ct) =>
{
var operationResult = await flowToRun.ExecuteAsync(parentLoadReport, ct);
if (operationResult.Success)
parentLoadReport.SetProgress(
loadingStatus.SetCurrentStage(LoadingStatus.LoadingStage.Completed));
return operationResult;
},
ct
);

// We need to flag the process as completed, otherwise the multiplayer systems will not run
loadingStatus.SetCurrentStage(LoadingStatus.LoadingStage.Completed);
}
else
{
EnumResult<TaskError> loadingResult = await LoadingScreen(parameters.ShowLoading)
.ShowWhileExecuteTaskAsync(
async (parentLoadReport, ct) =>
{
var operationResult = await startupOperation.ExecuteAsync(parentLoadReport, ct);
if (operationResult.Success) parentLoadReport.SetProgress(loadingStatus.SetCurrentStage(LoadingStatus.LoadingStage.Completed));
return operationResult;
},
ct
);

result = loadingResult;
}
result = loadingResult;

if (result.Success == false)
{
Expand All @@ -179,6 +192,14 @@ await UniTask.WhenAll(
loadingStatus.SetCurrentStage(LoadingStatus.LoadingStage.Completed);
}

private async UniTask DoLogoutOperationsAsync()
{
portableExperiencesController.UnloadAllPortableExperiences();
realmNavigator.RemoveCameraSamplingData();
chatHistory.Clear();
await roomHub.StopAsync().Timeout(TimeSpan.FromSeconds(10));
}

private async UniTask ShowAuthenticationScreenAsync(CancellationToken ct)
{
await mvcManager.ShowAsync(AuthenticationScreenController.IssueCommand(), ct);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ public readonly struct UserInAppInitializationFlowParameters
{
public bool ShowAuthentication { get; }
public bool ShowLoading { get; }
public bool ReloadRealm { get; }
public IUserInAppInitializationFlow.LoadSource LoadSource { get; }
public EnumResult<TaskError> RecoveryError { get; }
public World World { get; }
Expand All @@ -16,7 +15,6 @@ public readonly struct UserInAppInitializationFlowParameters
public UserInAppInitializationFlowParameters(
bool showAuthentication,
bool showLoading,
bool reloadRealm,
IUserInAppInitializationFlow.LoadSource loadSource,
World world,
Entity playerEntity,
Expand All @@ -25,7 +23,6 @@ public UserInAppInitializationFlowParameters(
{
ShowAuthentication = showAuthentication;
ShowLoading = showLoading;
ReloadRealm = reloadRealm;
LoadSource = loadSource;
World = world;
PlayerEntity = playerEntity;
Expand Down
8 changes: 8 additions & 0 deletions Explorer/Assets/DCL/Utilities/MordorConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using UnityEngine;

public static class MordorConstants
{
public static readonly Vector3 PLAYER_MORDOR_POSITION = new(15000, 0, 15000);
public static readonly Vector3 SCENE_MORDOR_POSITION = new(0, -10000, 0);
public static readonly Vector3 AVATAR_ATTACH_MORDOR_POSITION = new(8000,0,0);
}

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

Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,7 @@ UniTask<EnumResult<ChangeRealmError>> TryChangeRealmAsync(
UniTask<EnumResult<TaskError>> TeleportToParcelAsync(Vector2Int parcel, CancellationToken ct, bool isLocal);

UniTask InitializeTeleportToSpawnPointAsync(AsyncLoadProcessReport teleportLoadReport, CancellationToken ct, Vector2Int parcelToTeleport);

void RemoveCameraSamplingData();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private void UnloadLoadedPortableExperienceScene(in Entity entity, ref SceneDefi
{
sceneFacade.DisposeAsync().Forget();
scenesCache.RemovePortableExperienceFacade(definitionComponent.IpfsPath.EntityId);
World.Remove<ISceneFacade, SceneDefinitionComponent>(entity);
World.Destroy(entity);
}

[Query]
Expand Down
1 change: 0 additions & 1 deletion Explorer/Assets/Scripts/Global/Dynamic/Bootstraper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,6 @@ await dynamicWorldContainer.UserInAppInAppInitializationFlow.ExecuteAsync(
(
showAuthentication: debugSettings.ShowAuthentication,
showLoading: debugSettings.ShowLoading,
reloadRealm: false,
IUserInAppInitializationFlow.LoadSource.StartUp,
world: globalWorld.EcsWorld,
playerEntity: playerEntity
Expand Down
Loading

0 comments on commit ad579eb

Please sign in to comment.