diff --git a/Explorer/Assets/DCL/Infrastructure/ECS/SceneLifeCycle/IncreasingRadius/ResolveSceneStateByIncreasingRadiusSystem.cs b/Explorer/Assets/DCL/Infrastructure/ECS/SceneLifeCycle/IncreasingRadius/ResolveSceneStateByIncreasingRadiusSystem.cs index 3e7a542587c..6d188df2a20 100644 --- a/Explorer/Assets/DCL/Infrastructure/ECS/SceneLifeCycle/IncreasingRadius/ResolveSceneStateByIncreasingRadiusSystem.cs +++ b/Explorer/Assets/DCL/Infrastructure/ECS/SceneLifeCycle/IncreasingRadius/ResolveSceneStateByIncreasingRadiusSystem.cs @@ -281,6 +281,10 @@ private void Unload(in Entity entity, ref SceneLoadingState sceneState) private void UpdateLoadingState(IIpfsRealm ipfsRealm, in Entity entity, in SceneDefinitionComponent sceneDefinitionComponent, in PartitionComponent partitionComponent, SceneLoadingState sceneState) { + // Promises for banned-scene entities are not consumed downstream; issuing one here would leak its SceneFacade. + if (World.Has(entity)) + return; + VisualSceneState candidateBy = visualSceneStateResolver.ResolveVisualSceneState(partitionComponent, sceneDefinitionComponent, sceneState.VisualSceneState, ipfsRealm.SceneUrns.Count > 0); diff --git a/Explorer/Assets/DCL/RealmNavigation/TeleportController.cs b/Explorer/Assets/DCL/RealmNavigation/TeleportController.cs index 5ed55e9a9a9..4b0c2af8615 100644 --- a/Explorer/Assets/DCL/RealmNavigation/TeleportController.cs +++ b/Explorer/Assets/DCL/RealmNavigation/TeleportController.cs @@ -5,8 +5,11 @@ using DCL.Ipfs; using DCL.Utilities; using ECS.SceneLifeCycle; +using ECS.SceneLifeCycle.Components; using ECS.SceneLifeCycle.Reporting; +using ECS.SceneLifeCycle.SceneDefinition; using System; +using System.Runtime.CompilerServices; using System.Threading; using UnityEngine; @@ -14,6 +17,9 @@ namespace DCL.RealmNavigation { public class TeleportController : ITeleportController { + private static readonly QueryDescription BANNED_SCENES_QUERY = + new QueryDescription().WithAll(); + private readonly ISceneReadinessReportQueue sceneReadinessReportQueue; private IRetrieveScene? retrieveScene; @@ -88,7 +94,37 @@ public void StartTeleportToSpawnPoint(SceneEntityDefinition sceneDataSceneEntity return null; } + // Banned destination: the scene has been disposed and won't be reloaded, so no system will ever + // dequeue the readiness report. Complete it now so the loading screen closes and the avatar lands + // at the requested position with the scene unloaded (same UX as cross-realm entry into a banned world). + if (IsSceneBanned(sceneDef.id)) + { + loadReport.SetProgress(1f); + return null; + } + return new WaitForSceneReadiness(parcel, loadReport, sceneReadinessReportQueue); } + + private bool IsSceneBanned(string? sceneId) + { + if (world == null || string.IsNullOrEmpty(sceneId)) return false; + + // Chunk iteration to avoid the delegate/closure allocation of World.Query(ForEach). + // The matched archetype is empty in the common case (no current bans), so iteration is effectively free. + foreach (ref Chunk chunk in world.Query(in BANNED_SCENES_QUERY).GetChunkIterator()) + { + ref SceneDefinitionComponent first = ref chunk.GetFirst(); + + foreach (int i in chunk) + { + ref SceneDefinitionComponent definition = ref Unsafe.Add(ref first, i); + if (definition.Definition.id == sceneId) + return true; + } + } + + return false; + } } }