diff --git a/Explorer/Assets/DCL/Communities/CommunitiesFeatureAccess.cs b/Explorer/Assets/DCL/Communities/CommunitiesFeatureAccess.cs index 9c7f1a4e61d..b3216fcb0b4 100644 --- a/Explorer/Assets/DCL/Communities/CommunitiesFeatureAccess.cs +++ b/Explorer/Assets/DCL/Communities/CommunitiesFeatureAccess.cs @@ -65,6 +65,19 @@ public async UniTask IsUserAllowedToUseTheFeatureAsync(CancellationToken c return result; } + /// + /// Synchronous counterpart of : returns the cached + /// result of the last completed check, or false while no check has resolved for the current identity. + /// + public bool IsUserAllowedCached() + { +#if UNITY_EDITOR && !COMMUNITIES_FORCE_USER_WHITELIST + return true; +#else + return storedResult ?? false; +#endif + } + public bool TryGetCommunityIdFromAppArgs(out string? communityId) => appArgs.TryGetValue(AppArgsFlags.COMMUNITY, out communityId) && !string.IsNullOrEmpty(communityId); diff --git a/Explorer/Assets/DCL/ExplorePanel/ExplorePanelController.cs b/Explorer/Assets/DCL/ExplorePanel/ExplorePanelController.cs index f2af676a4aa..a7b8f416fa7 100644 --- a/Explorer/Assets/DCL/ExplorePanel/ExplorePanelController.cs +++ b/Explorer/Assets/DCL/ExplorePanel/ExplorePanelController.cs @@ -45,7 +45,6 @@ public class ExplorePanelController : ControllerBase? communitiesLiveBadgeSubscription; @@ -61,7 +60,6 @@ public class ExplorePanelController : ControllerBase CanvasOrdering.SortingLayer.FULLSCREEN; - public bool CanBeClosedByEscape => State != ControllerState.ViewShowing; - public event Action? PlacesOpenedFromStartMenu; public event Action? EventsOpenedFromStartMenu; @@ -103,11 +99,9 @@ public ExplorePanelController(ViewFactoryMethod viewFactory, this.inputBlock = inputBlock; this.includeCameraReel = FeaturesRegistry.Instance.IsEnabled(FeatureId.CAMERA_REEL); this.mvcManager = mvcManager; - this.communitiesBrowserController = communitiesBrowserController; this.includeDiscover = FeaturesRegistry.Instance.IsEnabled(FeatureId.DISCOVER); this.eventsApiService = eventsApiService; this.communitiesLiveTracker = communitiesLiveTracker; - this.creditsPanelController = creditsPanelController; CommunitiesBrowserController = communitiesBrowserController; PlacesController = placesController; diff --git a/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi.meta b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi.meta new file mode 100644 index 00000000000..15080ce9d65 --- /dev/null +++ b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4e6b917f1b8a41dfb527be137fc85f01 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi/ExplorerUiActions.cs b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi/ExplorerUiActions.cs new file mode 100644 index 00000000000..c05452d5fac --- /dev/null +++ b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi/ExplorerUiActions.cs @@ -0,0 +1,77 @@ +using Cysharp.Threading.Tasks; +using DCL.Communities; +using DCL.CrdtEcsBridge.JsModulesImplementation; +using DCL.Diagnostics; +using DCL.ExplorePanel; +using DCL.UI; +using Decentraland.Kernel.Apis; +using MVC; +using System; + +namespace DCL.Infrastructure.CrdtEcsBridge.JsModulesImplementation.RestrictedActions +{ + /// + /// Implementation of . The sibling asmref compiles it into + /// DCL.Social (not into SceneRuntime like the rest of this folder) because it references + /// , and DCL.Social already depends on SceneRuntime. + /// + public class ExplorerUiActions : IExplorerUiActions + { + private readonly IMVCManager mvcManager; + + private bool isExplorePanelOpen; + + public ExplorerUiActions(IMVCManager mvcManager) + { + this.mvcManager = mvcManager; + mvcManager.OnViewShowed += OnViewShowed; + mvcManager.OnViewClosed += OnViewClosed; + } + + public void Dispose() + { + mvcManager.OnViewShowed -= OnViewShowed; + mvcManager.OnViewClosed -= OnViewClosed; + } + + public OpenExplorerUiResult OpenSection(ExploreSections section) + { + // Communities availability depends on the user identity (feature flag + wallets allowlist), + // so it cannot be gated through FeaturesRegistry like the other sections. + if (section == ExploreSections.Communities && !CommunitiesFeatureAccess.Instance.IsUserAllowedCached()) + { + ReportHub.Log(ReportCategory.RESTRICTED_ACTIONS, "OpenSection: the Communities feature is not available for this user"); + return OpenExplorerUiResult.RejectedFeatureDisabled; + } + + if (isExplorePanelOpen) + return OpenExplorerUiResult.WasAlreadyOpen; + + OpenSectionAsync(section).Forget(); + return OpenExplorerUiResult.Opened; + } + + private async UniTask OpenSectionAsync(ExploreSections section) + { + try + { + await UniTask.SwitchToMainThread(); + await mvcManager.ShowAsync(ExplorePanelController.IssueCommand(new ExplorePanelParameter(section))); + } + catch (OperationCanceledException) { } + catch (Exception e) { ReportHub.LogException(e, ReportCategory.RESTRICTED_ACTIONS); } + } + + private void OnViewShowed(IController controller) + { + if (controller is ExplorePanelController) + isExplorePanelOpen = true; + } + + private void OnViewClosed(IController controller) + { + if (controller is ExplorePanelController) + isExplorePanelOpen = false; + } + } +} diff --git a/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi/ExplorerUiActions.cs.meta b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi/ExplorerUiActions.cs.meta new file mode 100644 index 00000000000..613dac862ef --- /dev/null +++ b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi/ExplorerUiActions.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ac414eae9e741154fbef2275a6bb3b14 \ No newline at end of file diff --git a/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi/RestrictedActions.ExplorerUi.asmref b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi/RestrictedActions.ExplorerUi.asmref new file mode 100644 index 00000000000..d4469b6c9b2 --- /dev/null +++ b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi/RestrictedActions.ExplorerUi.asmref @@ -0,0 +1,3 @@ +{ + "reference": "GUID:f56000518aba31544aa96f4739e50a64" +} diff --git a/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi/RestrictedActions.ExplorerUi.asmref.meta b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi/RestrictedActions.ExplorerUi.asmref.meta new file mode 100644 index 00000000000..932991080c8 --- /dev/null +++ b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/ExplorerUi/RestrictedActions.ExplorerUi.asmref.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f87e2f0948e04b8783b34de90fcd45df +AssemblyDefinitionReferenceImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/IExplorerUiActions.cs b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/IExplorerUiActions.cs new file mode 100644 index 00000000000..afbf90ddb09 --- /dev/null +++ b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/IExplorerUiActions.cs @@ -0,0 +1,11 @@ +using DCL.UI; +using Decentraland.Kernel.Apis; +using System; + +namespace DCL.CrdtEcsBridge.JsModulesImplementation +{ + public interface IExplorerUiActions : IDisposable + { + OpenExplorerUiResult OpenSection(ExploreSections section); + } +} diff --git a/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/IExplorerUiActions.cs.meta b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/IExplorerUiActions.cs.meta new file mode 100644 index 00000000000..632e1eb0e11 --- /dev/null +++ b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/IExplorerUiActions.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9f1003dd0c500f04994ca5ebb17d3a51 \ No newline at end of file diff --git a/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/RestrictedActionsAPIImplementation.cs b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/RestrictedActionsAPIImplementation.cs index 32f001023ed..a5ea1ff8454 100644 --- a/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/RestrictedActionsAPIImplementation.cs +++ b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/RestrictedActionsAPIImplementation.cs @@ -2,16 +2,20 @@ using DCL.AvatarRendering.Emotes; using DCL.ChangeRealmPrompt; using DCL.Clipboard; +using DCL.CrdtEcsBridge.JsModulesImplementation; using DCL.Diagnostics; using DCL.ECSComponents; +using DCL.FeatureFlags; +using DCL.UI; using Utility.Arch; using DCL.ExternalUrlPrompt; using DCL.NftPrompt; +using DCL.SceneRuntime.Apis.RestrictedActionsApi; using DCL.TeleportPrompt; using DCL.Utilities; +using Decentraland.Kernel.Apis; using MVC; using SceneRunner.Scene; -using SceneRuntime.Apis.Modules.RestrictedActionsApi; using SceneRuntime.ScenePermissions; using System; using System.Threading; @@ -22,12 +26,15 @@ namespace CrdtEcsBridge.RestrictedActions { public class RestrictedActionsAPIImplementation : IRestrictedActionsAPI { + private const uint USER_GESTURE_WINDOW_TICKS = 1; + private readonly IMVCManager mvcManager; private readonly ISceneStateProvider sceneStateProvider; private readonly IGlobalWorldActions globalWorldActions; private readonly ISceneData sceneData; private readonly IJsApiPermissionsProvider permissionsProvider; private readonly ISystemClipboard systemClipboard; + private readonly IExplorerUiActions explorerUiActions; private readonly Arch.Core.World sceneWorld; private readonly Arch.Core.Entity scenePlayerEntity; @@ -39,7 +46,8 @@ public RestrictedActionsAPIImplementation( IJsApiPermissionsProvider permissionsProvider, ISystemClipboard systemClipboard, Arch.Core.World sceneWorld, - Arch.Core.Entity scenePlayerEntity) + Arch.Core.Entity scenePlayerEntity, + IExplorerUiActions explorerUiActions) { this.mvcManager = mvcManager; this.sceneStateProvider = sceneStateProvider; @@ -49,6 +57,7 @@ public RestrictedActionsAPIImplementation( this.systemClipboard = systemClipboard; this.sceneWorld = sceneWorld; this.scenePlayerEntity = scenePlayerEntity; + this.explorerUiActions = explorerUiActions; } public bool TryOpenExternalUrl(string url) @@ -200,6 +209,41 @@ public bool TryOpenNftDialog(string urn) return true; } + public int TryOpenExplorerUi(int ui) + { + if (!sceneStateProvider.IsCurrent) + return (int)OpenExplorerUiResult.RejectedNotCurrentScene; + + // Underflow-safe recent-gesture check: never subtract unsigned ticks. The "== 0" guard is + // load-bearing — a scene where no user input has ever been recorded must be rejected. + uint lastUserInputTick = sceneStateProvider.LastUserInputTick; + + if (lastUserInputTick == 0 || lastUserInputTick + USER_GESTURE_WINDOW_TICKS < sceneStateProvider.TickNumber) + { + ReportHub.Log(ReportCategory.RESTRICTED_ACTIONS, "OpenExplorerUi: rejected, call did not originate from a recent user gesture"); + return (int)OpenExplorerUiResult.RejectedNoUserGesture; + } + + if (!TryMapExplorerUi((ExplorerUi)ui, out ExploreSections section, out FeatureId? gatingFeature)) + { + ReportHub.LogWarning(ReportCategory.RESTRICTED_ACTIONS, $"OpenExplorerUi: unsupported ui value '{ui}'"); + return (int)OpenExplorerUiResult.RejectedFeatureDisabled; + } + + if (gatingFeature.HasValue && !FeaturesRegistry.Instance.IsEnabled(gatingFeature.Value)) + { + ReportHub.Log(ReportCategory.RESTRICTED_ACTIONS, $"OpenExplorerUi: feature '{gatingFeature.Value}' is disabled"); + return (int)OpenExplorerUiResult.RejectedFeatureDisabled; + } + + return (int)explorerUiActions.OpenSection(section); + } + + public void Dispose() + { + explorerUiActions.Dispose(); + } + public void TryCopyToClipboard(string text) { if (!sceneStateProvider.IsCurrent) @@ -253,5 +297,52 @@ private async UniTask CopyToClipboardAsync(string text) await UniTask.SwitchToMainThread(); systemClipboard.Set(text); } + + /// + /// Maps a protocol value to its explore panel section and, when the + /// section is behind a synchronous feature flag, the that gates it. + /// Returns false for unknown values so the caller can reject the request. + /// + private static bool TryMapExplorerUi(ExplorerUi ui, out ExploreSections section, out FeatureId? gatingFeature) + { + switch (ui) + { + case ExplorerUi.EuMap: + section = ExploreSections.Navmap; + gatingFeature = null; + return true; + case ExplorerUi.EuSettings: + section = ExploreSections.Settings; + gatingFeature = null; + return true; + case ExplorerUi.EuBackpack: + section = ExploreSections.Backpack; + gatingFeature = null; + return true; + case ExplorerUi.EuCameraReel: + section = ExploreSections.CameraReel; + gatingFeature = FeatureId.CAMERA_REEL; + return true; + case ExplorerUi.EuCommunities: + section = ExploreSections.Communities; + // FeatureId.COMMUNITIES is never populated in FeaturesRegistry (its state is + // identity-dependent), so the gate lives in the IExplorerUiActions implementation, + // which can reach CommunitiesFeatureAccess. + gatingFeature = null; + return true; + case ExplorerUi.EuPlaces: + section = ExploreSections.Places; + gatingFeature = FeatureId.DISCOVER; + return true; + case ExplorerUi.EuEvents: + section = ExploreSections.Events; + gatingFeature = FeatureId.DISCOVER; + return true; + default: + section = default(ExploreSections); + gatingFeature = null; + return false; + } + } } } diff --git a/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/Tests/RestrictedActionsAPIImplementationShould.cs b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/Tests/RestrictedActionsAPIImplementationShould.cs index ba9b6d7e18c..0c4240a78d0 100644 --- a/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/Tests/RestrictedActionsAPIImplementationShould.cs +++ b/Explorer/Assets/DCL/Infrastructure/CrdtEcsBridge/JsModulesImplementation/RestrictedActions/Tests/RestrictedActionsAPIImplementationShould.cs @@ -3,10 +3,14 @@ using Cysharp.Threading.Tasks; using DCL.ChangeRealmPrompt; using DCL.Clipboard; +using DCL.CrdtEcsBridge.JsModulesImplementation; using DCL.ECSComponents; using DCL.ExternalUrlPrompt; using DCL.NftPrompt; using DCL.TeleportPrompt; +using DCL.UI; +using Decentraland.Kernel.Apis; +using ECS.TestSuite; using MVC; using NSubstitute; using NUnit.Framework; @@ -27,14 +31,22 @@ public class RestrictedActionsAPIImplementationShould private IGlobalWorldActions globalWorldActions; private ISceneData sceneData; private ISystemClipboard systemClipboard; + private IExplorerUiActions explorerUiActions; private World sceneWorld; [SetUp] public void SetUp() { + EcsTestsUtils.SetUpFeaturesRegistry(); + mvcManager = Substitute.For(); sceneStateProvider = Substitute.For(); sceneStateProvider.IsCurrent.Returns(true); + + // Stamp a recent user gesture so the OpenExplorerUi gesture gate passes by default. + sceneStateProvider.TickNumber.Returns((uint)10); + sceneStateProvider.LastUserInputTick.Returns((uint)10); + globalWorldActions = Substitute.For(); sceneData = Substitute.For(); sceneData.Geometry.Returns(ParcelMathHelper.UNDEFINED_SCENE_GEOMETRY); @@ -45,6 +57,8 @@ public void SetUp() new Vector2Int(0, 2), }); systemClipboard = Substitute.For(); + explorerUiActions = Substitute.For(); + explorerUiActions.OpenSection(Arg.Any()).Returns(OpenExplorerUiResult.Opened); sceneWorld = World.Create(); Entity scenePlayerEntity = sceneWorld.Create(); restrictedActionsAPIImplementation = new RestrictedActionsAPIImplementation( @@ -55,13 +69,15 @@ public void SetUp() new AllowEverythingJsApiPermissionsProvider(), systemClipboard, sceneWorld, - scenePlayerEntity); + scenePlayerEntity, + explorerUiActions); } [TearDown] public void TearDown() { World.Destroy(sceneWorld); + EcsTestsUtils.TearDownFeaturesRegistry(); } [Test] @@ -145,6 +161,104 @@ public void OpenNftDialog() mvcManager.Received(1).ShowAsync(NftPromptController.IssueCommand(new NftPromptController.Params("ethereum", "0x06012c8cf97bead5deae237070f9587f8e7a266d", "1540722"))); } + [Test] + public void OpenExplorerUi_MapOpensNavmap() + { + // Act + int result = restrictedActionsAPIImplementation.TryOpenExplorerUi((int)ExplorerUi.EuMap); + + // Assert + Assert.AreEqual((int)OpenExplorerUiResult.Opened, result); + explorerUiActions.Received(1).OpenSection(ExploreSections.Navmap); + } + + [Test] + public void OpenExplorerUi_NotCurrentScene_Rejects() + { + // Arrange + sceneStateProvider.IsCurrent.Returns(false); + + // Act + int result = restrictedActionsAPIImplementation.TryOpenExplorerUi((int)ExplorerUi.EuMap); + + // Assert + Assert.AreEqual((int)OpenExplorerUiResult.RejectedNotCurrentScene, result); + explorerUiActions.DidNotReceive().OpenSection(Arg.Any()); + } + + [Test] + [TestCase(0)] // underflow-safe: no user gesture has ever been recorded + [TestCase(5)] // stale: the last gesture is older than the allowed window + public void OpenExplorerUi_NoRecentGesture_Rejects(int lastUserInputTick) + { + // Arrange + sceneStateProvider.TickNumber.Returns((uint)10); + sceneStateProvider.LastUserInputTick.Returns((uint)lastUserInputTick); + + // Act + int result = restrictedActionsAPIImplementation.TryOpenExplorerUi((int)ExplorerUi.EuMap); + + // Assert + Assert.AreEqual((int)OpenExplorerUiResult.RejectedNoUserGesture, result); + explorerUiActions.DidNotReceive().OpenSection(Arg.Any()); + } + + [Test] + public void OpenExplorerUi_AlreadyOpen_ReturnsWasAlreadyOpen() + { + // Arrange + explorerUiActions.OpenSection(Arg.Any()).Returns(OpenExplorerUiResult.WasAlreadyOpen); + + // Act + int result = restrictedActionsAPIImplementation.TryOpenExplorerUi((int)ExplorerUi.EuMap); + + // Assert + Assert.AreEqual((int)OpenExplorerUiResult.WasAlreadyOpen, result); + } + + [Test] + public void OpenExplorerUi_UnknownUiValue_Rejects() + { + // Act: 99 is not a member of the ExplorerUi enum, so the section mapping must fail. + int result = restrictedActionsAPIImplementation.TryOpenExplorerUi(99); + + // Assert + Assert.AreEqual((int)OpenExplorerUiResult.RejectedFeatureDisabled, result); + explorerUiActions.DidNotReceive().OpenSection(Arg.Any()); + } + + [Test] + public void OpenExplorerUi_FeatureDisabled_Rejects() + { + // Arrange + // CAMERA_REEL is force-enabled in the editor, so an app-args override is the only way + // to exercise the disabled branch of the features-registry gate. + EcsTestsUtils.TearDownFeaturesRegistry(); + EcsTestsUtils.SetUpFeaturesRegistryWithAppArgs(new[] { "--camera-reel", "false" }); + + // Act + int result = restrictedActionsAPIImplementation.TryOpenExplorerUi((int)ExplorerUi.EuCameraReel); + + // Assert + Assert.AreEqual((int)OpenExplorerUiResult.RejectedFeatureDisabled, result); + explorerUiActions.DidNotReceive().OpenSection(Arg.Any()); + } + + [Test] + public void OpenExplorerUi_CommunitiesRejectionPropagates() + { + // Arrange + // Communities availability is identity-dependent, so its gate lives inside the + // IExplorerUiActions implementation; the API must return that rejection to the scene. + explorerUiActions.OpenSection(ExploreSections.Communities).Returns(OpenExplorerUiResult.RejectedFeatureDisabled); + + // Act + int result = restrictedActionsAPIImplementation.TryOpenExplorerUi((int)ExplorerUi.EuCommunities); + + // Assert + Assert.AreEqual((int)OpenExplorerUiResult.RejectedFeatureDisabled, result); + } + [Test] public void CopyToClipboard() { diff --git a/Explorer/Assets/DCL/Infrastructure/ECS/TestSuite/EcsTestsUtils.cs b/Explorer/Assets/DCL/Infrastructure/ECS/TestSuite/EcsTestsUtils.cs index f25e88f6ab5..adee4dc0b97 100644 --- a/Explorer/Assets/DCL/Infrastructure/ECS/TestSuite/EcsTestsUtils.cs +++ b/Explorer/Assets/DCL/Infrastructure/ECS/TestSuite/EcsTestsUtils.cs @@ -4,6 +4,7 @@ using ECS.Unity.Materials.Components; using ECS.Unity.Transforms.Components; using Global.AppArgs; +using System; using System.Collections.Generic; using UnityEngine; using Utility; @@ -49,12 +50,17 @@ public static MaterialComponent AddMaterialToEntity(World world, in Entity entit } public static void SetUpFeaturesRegistry(params string[] flags) + { + SetUpFeaturesRegistryWithAppArgs(Array.Empty(), flags); + } + + public static void SetUpFeaturesRegistryWithAppArgs(string[] appArgs, params string[] flags) { var featureFlagsDto = new FeatureFlagsResultDto { flags = new Dictionary() }; foreach (string flag in flags) featureFlagsDto.flags.Add(flag, true); FeatureFlagsConfiguration.Initialize(new FeatureFlagsConfiguration(featureFlagsDto)); - FeaturesRegistry.Initialize(new FeaturesRegistry(new ApplicationParametersParser(), false)); + FeaturesRegistry.Initialize(new FeaturesRegistry(new ApplicationParametersParser(appArgs), false)); } public static void TearDownFeaturesRegistry() diff --git a/Explorer/Assets/DCL/Infrastructure/SceneRunner/Scene/ISceneStateProvider.cs b/Explorer/Assets/DCL/Infrastructure/SceneRunner/Scene/ISceneStateProvider.cs index 5b1f6d71ff3..b26c90df127 100644 --- a/Explorer/Assets/DCL/Infrastructure/SceneRunner/Scene/ISceneStateProvider.cs +++ b/Explorer/Assets/DCL/Infrastructure/SceneRunner/Scene/ISceneStateProvider.cs @@ -13,6 +13,11 @@ public interface ISceneStateProvider uint TickNumber { get; set; } + /// + /// Tick at which the most recent non-hover pointer (down/up) result was written for this scene. + /// + uint LastUserInputTick { get; set; } + ref readonly SceneEngineStartInfo EngineStartInfo { get; } void Start(SceneEngineStartInfo startInfo); diff --git a/Explorer/Assets/DCL/Infrastructure/SceneRunner/Scene/SceneStateProvider.cs b/Explorer/Assets/DCL/Infrastructure/SceneRunner/Scene/SceneStateProvider.cs index e2fb065089b..77b770feb75 100644 --- a/Explorer/Assets/DCL/Infrastructure/SceneRunner/Scene/SceneStateProvider.cs +++ b/Explorer/Assets/DCL/Infrastructure/SceneRunner/Scene/SceneStateProvider.cs @@ -15,6 +15,8 @@ public class SceneStateProvider : ISceneStateProvider public uint TickNumber { get; set; } + public uint LastUserInputTick { get; set; } + public ref readonly SceneEngineStartInfo EngineStartInfo => ref engineStartInfo; public void Start(SceneEngineStartInfo startInfo) @@ -22,6 +24,7 @@ public void Start(SceneEngineStartInfo startInfo) State.Set(SceneState.Starting); engineStartInfo = startInfo; TickNumber = 0; + LastUserInputTick = 0; } } } diff --git a/Explorer/Assets/DCL/Infrastructure/SceneRunner/SceneInstanceDeps.cs b/Explorer/Assets/DCL/Infrastructure/SceneRunner/SceneInstanceDeps.cs index 1ba1f18fe67..30ea726b3eb 100644 --- a/Explorer/Assets/DCL/Infrastructure/SceneRunner/SceneInstanceDeps.cs +++ b/Explorer/Assets/DCL/Infrastructure/SceneRunner/SceneInstanceDeps.cs @@ -16,11 +16,14 @@ using CrdtEcsBridge.UpdateGate; using CrdtEcsBridge.WorldSynchronizer; using DCL.Clipboard; +using DCL.Infrastructure.CrdtEcsBridge.JsModulesImplementation.RestrictedActions; using DCL.Interaction.Utility; using DCL.Multiplayer.Connections.RoomHubs; using DCL.PluginSystem.World.Dependencies; using DCL.Profiles; using DCL.Profiling; +using DCL.SceneRunner; +using DCL.SceneRuntime.Apis.RestrictedActionsApi; using DCL.SDKComponents.MediaStream; using DCL.SkyBox; using DCL.Utilities; @@ -38,7 +41,6 @@ using SceneRuntime.Apis.Modules.CommunicationsControllerApi; using SceneRuntime.Apis.Modules.EngineApi; using SceneRuntime.Apis.Modules.FetchApi; -using SceneRuntime.Apis.Modules.RestrictedActionsApi; using SceneRuntime.Apis.Modules.Runtime; using SceneRuntime.Apis.Modules.SceneApi; using SceneRuntime.ScenePermissions; @@ -241,7 +243,7 @@ protected WithRuntimeAndJsAPIBase( string installSource) : this( engineApi, - new RestrictedActionsAPIImplementation(mvcManager, syncDeps.ecsWorldSharedDependencies.SceneStateProvider, globalWorldActions, syncDeps.sceneData, syncDeps.permissionsProvider, systemClipboard, syncDeps.ECSWorldFacade.EcsWorld, syncDeps.ECSWorldFacade.PersistentEntities.Player), + new RestrictedActionsAPIImplementation(mvcManager, syncDeps.ecsWorldSharedDependencies.SceneStateProvider, globalWorldActions, syncDeps.sceneData, syncDeps.permissionsProvider, systemClipboard, syncDeps.ECSWorldFacade.EcsWorld, syncDeps.ECSWorldFacade.PersistentEntities.Player, new ExplorerUiActions(mvcManager)), new RuntimeImplementation(jsOperations, syncDeps.sceneData, realmData, webRequestController, skyboxSettings, roomHub, installSource), new SceneApiImplementation(syncDeps.sceneData), new ClientWebSocketApiImplementation(syncDeps.PoolsProvider, jsOperations, syncDeps.permissionsProvider), diff --git a/Explorer/Assets/DCL/Infrastructure/SceneRunner/Tests/SceneFacadeShould.cs b/Explorer/Assets/DCL/Infrastructure/SceneRunner/Tests/SceneFacadeShould.cs index ccc38f68390..4f90d61f71c 100644 --- a/Explorer/Assets/DCL/Infrastructure/SceneRunner/Tests/SceneFacadeShould.cs +++ b/Explorer/Assets/DCL/Infrastructure/SceneRunner/Tests/SceneFacadeShould.cs @@ -23,6 +23,7 @@ using DCL.PluginSystem.World; using DCL.PluginSystem.World.Dependencies; using DCL.Profiles; +using DCL.SceneRuntime.Apis.RestrictedActionsApi; using DCL.SkyBox; using DCL.Utilities.Extensions; using DCL.Web3; @@ -45,7 +46,6 @@ using SceneRuntime.Apis.Modules.CommunicationsControllerApi; using SceneRuntime.Apis.Modules.EngineApi; using SceneRuntime.Apis.Modules.FetchApi; -using SceneRuntime.Apis.Modules.RestrictedActionsApi; using SceneRuntime.Apis.Modules.Runtime; using SceneRuntime.Apis.Modules.SceneApi; using SceneRuntime.Factory; diff --git a/Explorer/Assets/DCL/Infrastructure/SceneRuntime/Apis/Modules/RestrictedActionsApi/IRestrictedActionsAPI.cs b/Explorer/Assets/DCL/Infrastructure/SceneRuntime/Apis/Modules/RestrictedActionsApi/IRestrictedActionsAPI.cs index 599b716d98e..80fec74144c 100644 --- a/Explorer/Assets/DCL/Infrastructure/SceneRuntime/Apis/Modules/RestrictedActionsApi/IRestrictedActionsAPI.cs +++ b/Explorer/Assets/DCL/Infrastructure/SceneRuntime/Apis/Modules/RestrictedActionsApi/IRestrictedActionsAPI.cs @@ -1,11 +1,12 @@ using Cysharp.Threading.Tasks; using DCL.ECSComponents; +using System; using System.Threading; using UnityEngine; -namespace SceneRuntime.Apis.Modules.RestrictedActionsApi +namespace DCL.SceneRuntime.Apis.RestrictedActionsApi { - public interface IRestrictedActionsAPI + public interface IRestrictedActionsAPI : IDisposable { bool TryOpenExternalUrl(string url); @@ -21,6 +22,8 @@ public interface IRestrictedActionsAPI bool TryOpenNftDialog(string urn); + int TryOpenExplorerUi(int ui); + void TryCopyToClipboard(string text); void TryStopEmote(); diff --git a/Explorer/Assets/DCL/Infrastructure/SceneRuntime/Apis/Modules/RestrictedActionsApi/RestrictedActionsAPIWrapper.cs b/Explorer/Assets/DCL/Infrastructure/SceneRuntime/Apis/Modules/RestrictedActionsApi/RestrictedActionsAPIWrapper.cs index 44fecfbc5f5..02b66df953c 100644 --- a/Explorer/Assets/DCL/Infrastructure/SceneRuntime/Apis/Modules/RestrictedActionsApi/RestrictedActionsAPIWrapper.cs +++ b/Explorer/Assets/DCL/Infrastructure/SceneRuntime/Apis/Modules/RestrictedActionsApi/RestrictedActionsAPIWrapper.cs @@ -1,11 +1,13 @@ using Cysharp.Threading.Tasks; using DCL.ECSComponents; using JetBrains.Annotations; +using SceneRuntime; +using SceneRuntime.Apis; using System.Threading; using UnityEngine; using Utility; -namespace SceneRuntime.Apis.Modules.RestrictedActionsApi +namespace DCL.SceneRuntime.Apis.RestrictedActionsApi { public class RestrictedActionsAPIWrapper : JsApiWrapper { @@ -93,6 +95,10 @@ public void CopyToClipboard(string text) => public bool OpenNftDialog(string urn) => api.TryOpenNftDialog(urn); + [UsedImplicitly] + public int OpenExplorerUi(int ui) => + api.TryOpenExplorerUi(ui); + [UsedImplicitly] public object StopEmote() { @@ -109,6 +115,7 @@ async UniTask StopEmoteAsync() } } - public override void Dispose() { } + public override void Dispose() => + api.Dispose(); } } diff --git a/Explorer/Assets/DCL/Infrastructure/SceneRuntime/Apis/Modules/UserActions/UserActionsWrapper.cs b/Explorer/Assets/DCL/Infrastructure/SceneRuntime/Apis/Modules/UserActions/UserActionsWrapper.cs index 28928b65719..41b23760745 100644 --- a/Explorer/Assets/DCL/Infrastructure/SceneRuntime/Apis/Modules/UserActions/UserActionsWrapper.cs +++ b/Explorer/Assets/DCL/Infrastructure/SceneRuntime/Apis/Modules/UserActions/UserActionsWrapper.cs @@ -1,6 +1,6 @@ using DCL.Diagnostics; +using DCL.SceneRuntime.Apis.RestrictedActionsApi; using JetBrains.Annotations; -using SceneRuntime.Apis.Modules.RestrictedActionsApi; using System; using System.Threading; using UnityEngine; diff --git a/Explorer/Assets/DCL/Infrastructure/SceneRuntime/ISceneRuntime.cs b/Explorer/Assets/DCL/Infrastructure/SceneRuntime/ISceneRuntime.cs index ac9bba31d85..a8016bf6884 100644 --- a/Explorer/Assets/DCL/Infrastructure/SceneRuntime/ISceneRuntime.cs +++ b/Explorer/Assets/DCL/Infrastructure/SceneRuntime/ISceneRuntime.cs @@ -6,6 +6,7 @@ using DCL.Multiplayer.Profiles.Poses; using DCL.Profiles; using DCL.Profiling; +using DCL.SceneRuntime.Apis.RestrictedActionsApi; using DCL.Web3; using DCL.Web3.Identities; using DCL.WebRequests; @@ -24,7 +25,6 @@ using SceneRuntime.Apis.Modules.FetchApi; using SceneRuntime.Apis.Modules.Players; using SceneRuntime.Apis.Modules.PortableExperiencesApi; -using SceneRuntime.Apis.Modules.RestrictedActionsApi; using SceneRuntime.Apis.Modules.Runtime; using SceneRuntime.Apis.Modules.SceneApi; using SceneRuntime.Apis.Modules.SignedFetch; diff --git a/Explorer/Assets/DCL/Interaction/Systems/WritePointerEventResultsSystem.cs b/Explorer/Assets/DCL/Interaction/Systems/WritePointerEventResultsSystem.cs index aec1bc7c9f4..a878a99e786 100644 --- a/Explorer/Assets/DCL/Interaction/Systems/WritePointerEventResultsSystem.cs +++ b/Explorer/Assets/DCL/Interaction/Systems/WritePointerEventResultsSystem.cs @@ -113,7 +113,13 @@ private bool AppendSingleResult(CRDTEntity sdkEntity, in Vector3 scenePosition, RaycastHit raycastHit = raycastHitPool.Get(); raycastHit.FillSDKRaycastHit(scenePosition, intent, sdkEntity); AppendMessage(sdkEntity, raycastHit, button, eventType); - return eventType is not (PointerEventType.PetHoverEnter or PointerEventType.PetHoverLeave); + + bool isNonHover = eventType is not (PointerEventType.PetHoverEnter or PointerEventType.PetHoverLeave); + + if (isNonHover) + sceneStateProvider.LastUserInputTick = sceneStateProvider.TickNumber; + + return isNonHover; } private void AppendMessage(CRDTEntity sdkEntity, RaycastHit? sdkHit, InputAction button, PointerEventType eventType) diff --git a/Explorer/Assets/DCL/TeleportPrompt/TeleportPromptController.cs b/Explorer/Assets/DCL/TeleportPrompt/TeleportPromptController.cs index 823d61ed679..f0451da9317 100644 --- a/Explorer/Assets/DCL/TeleportPrompt/TeleportPromptController.cs +++ b/Explorer/Assets/DCL/TeleportPrompt/TeleportPromptController.cs @@ -3,7 +3,6 @@ using DCL.Input; using DCL.PlacesAPIService; using DCL.UI; -using DCL.WebRequests; using MVC; using System; using System.Threading; diff --git a/Explorer/Assets/Protocol/DecentralandProtocol/AvatarEmoteCommand.gen.cs b/Explorer/Assets/Protocol/DecentralandProtocol/AvatarEmoteCommand.gen.cs index 003d69284a9..20a3c8ac920 100644 --- a/Explorer/Assets/Protocol/DecentralandProtocol/AvatarEmoteCommand.gen.cs +++ b/Explorer/Assets/Protocol/DecentralandProtocol/AvatarEmoteCommand.gen.cs @@ -25,14 +25,17 @@ static AvatarEmoteCommandReflection() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "CjZkZWNlbnRyYWxhbmQvc2RrL2NvbXBvbmVudHMvYXZhdGFyX2Vtb3RlX2Nv", - "bW1hbmQucHJvdG8SG2RlY2VudHJhbGFuZC5zZGsuY29tcG9uZW50cyJKChRQ", - "QkF2YXRhckVtb3RlQ29tbWFuZBIRCgllbW90ZV91cm4YASABKAkSDAoEbG9v", - "cBgCIAEoCBIRCgl0aW1lc3RhbXAYAyABKA1CFKoCEURDTC5FQ1NDb21wb25l", - "bnRzYgZwcm90bzM=")); + "bW1hbmQucHJvdG8SG2RlY2VudHJhbGFuZC5zZGsuY29tcG9uZW50cxo0ZGVj", + "ZW50cmFsYW5kL3Nkay9jb21wb25lbnRzL2NvbW1vbi9hdmF0YXJfbWFzay5w", + "cm90byKWAQoUUEJBdmF0YXJFbW90ZUNvbW1hbmQSEQoJZW1vdGVfdXJuGAEg", + "ASgJEgwKBGxvb3AYAiABKAgSEQoJdGltZXN0YW1wGAMgASgNEkEKBG1hc2sY", + "BCABKA4yLi5kZWNlbnRyYWxhbmQuc2RrLmNvbXBvbmVudHMuY29tbW9uLkF2", + "YXRhck1hc2tIAIgBAUIHCgVfbWFza0IUqgIRRENMLkVDU0NvbXBvbmVudHNi", + "BnByb3RvMw==")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, - new pbr::FileDescriptor[] { }, + new pbr::FileDescriptor[] { global::DCL.ECSComponents.AvatarMaskReflection.Descriptor, }, new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { - new pbr::GeneratedClrTypeInfo(typeof(global::DCL.ECSComponents.PBAvatarEmoteCommand), global::DCL.ECSComponents.PBAvatarEmoteCommand.Parser, new[]{ "EmoteUrn", "Loop", "Timestamp" }, null, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::DCL.ECSComponents.PBAvatarEmoteCommand), global::DCL.ECSComponents.PBAvatarEmoteCommand.Parser, new[]{ "EmoteUrn", "Loop", "Timestamp", "Mask" }, new[]{ "Mask" }, null, null, null) })); } #endregion @@ -51,6 +54,7 @@ public sealed partial class PBAvatarEmoteCommand : pb::IMessage _parser = new pb::MessageParser(() => new PBAvatarEmoteCommand()); private pb::UnknownFieldSet _unknownFields; + private int _hasBits0; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public static pb::MessageParser Parser { get { return _parser; } } @@ -78,9 +82,11 @@ public PBAvatarEmoteCommand() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public PBAvatarEmoteCommand(PBAvatarEmoteCommand other) : this() { + _hasBits0 = other._hasBits0; emoteUrn_ = other.emoteUrn_; loop_ = other.loop_; timestamp_ = other.timestamp_; + mask_ = other.mask_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } @@ -129,6 +135,33 @@ public uint Timestamp { } } + /// Field number for the "mask" field. + public const int MaskFieldNumber = 4; + private readonly static global::DCL.ECSComponents.AvatarMask MaskDefaultValue = global::DCL.ECSComponents.AvatarMask.AmUpperBody; + + private global::DCL.ECSComponents.AvatarMask mask_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::DCL.ECSComponents.AvatarMask Mask { + get { if ((_hasBits0 & 1) != 0) { return mask_; } else { return MaskDefaultValue; } } + set { + _hasBits0 |= 1; + mask_ = value; + } + } + /// Gets whether the "mask" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasMask { + get { return (_hasBits0 & 1) != 0; } + } + /// Clears the value of the "mask" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearMask() { + _hasBits0 &= ~1; + } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public override bool Equals(object other) { @@ -147,6 +180,7 @@ public bool Equals(PBAvatarEmoteCommand other) { if (EmoteUrn != other.EmoteUrn) return false; if (Loop != other.Loop) return false; if (Timestamp != other.Timestamp) return false; + if (Mask != other.Mask) return false; return Equals(_unknownFields, other._unknownFields); } @@ -157,6 +191,7 @@ public override int GetHashCode() { if (EmoteUrn.Length != 0) hash ^= EmoteUrn.GetHashCode(); if (Loop != false) hash ^= Loop.GetHashCode(); if (Timestamp != 0) hash ^= Timestamp.GetHashCode(); + if (HasMask) hash ^= Mask.GetHashCode(); if (_unknownFields != null) { hash ^= _unknownFields.GetHashCode(); } @@ -187,6 +222,10 @@ public void WriteTo(pb::CodedOutputStream output) { output.WriteRawTag(24); output.WriteUInt32(Timestamp); } + if (HasMask) { + output.WriteRawTag(32); + output.WriteEnum((int) Mask); + } if (_unknownFields != null) { _unknownFields.WriteTo(output); } @@ -209,6 +248,10 @@ public void WriteTo(pb::CodedOutputStream output) { output.WriteRawTag(24); output.WriteUInt32(Timestamp); } + if (HasMask) { + output.WriteRawTag(32); + output.WriteEnum((int) Mask); + } if (_unknownFields != null) { _unknownFields.WriteTo(ref output); } @@ -228,6 +271,9 @@ public int CalculateSize() { if (Timestamp != 0) { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Timestamp); } + if (HasMask) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Mask); + } if (_unknownFields != null) { size += _unknownFields.CalculateSize(); } @@ -249,6 +295,9 @@ public void MergeFrom(PBAvatarEmoteCommand other) { if (other.Timestamp != 0) { Timestamp = other.Timestamp; } + if (other.HasMask) { + Mask = other.Mask; + } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); } @@ -280,6 +329,10 @@ public void MergeFrom(pb::CodedInputStream input) { Timestamp = input.ReadUInt32(); break; } + case 32: { + Mask = (global::DCL.ECSComponents.AvatarMask) input.ReadEnum(); + break; + } } } #endif @@ -311,6 +364,10 @@ public void MergeFrom(pb::CodedInputStream input) { Timestamp = input.ReadUInt32(); break; } + case 32: { + Mask = (global::DCL.ECSComponents.AvatarMask) input.ReadEnum(); + break; + } } } } diff --git a/Explorer/Assets/Protocol/DecentralandProtocol/RestrictedActions.gen.cs b/Explorer/Assets/Protocol/DecentralandProtocol/RestrictedActions.gen.cs index 23f30a74040..809b9a191e3 100644 --- a/Explorer/Assets/Protocol/DecentralandProtocol/RestrictedActions.gen.cs +++ b/Explorer/Assets/Protocol/DecentralandProtocol/RestrictedActions.gen.cs @@ -50,36 +50,49 @@ static RestrictedActionsReflection() { "Y2Nlc3MYASABKAgiFgoUVHJpZ2dlckVtb3RlUmVzcG9uc2UiJwoUTW92ZVBs", "YXllclRvUmVzcG9uc2USDwoHc3VjY2VzcxgBIAEoCCIUChJUZWxlcG9ydFRv", "UmVzcG9uc2UiJgoWQ29weVRvQ2xpcGJvYXJkUmVxdWVzdBIMCgR0ZXh0GAEg", - "ASgJIg8KDUVtcHR5UmVzcG9uc2UiEgoQU3RvcEVtb3RlUmVxdWVzdDL1CAoY", - "UmVzdHJpY3RlZEFjdGlvbnNTZXJ2aWNlEm8KDE1vdmVQbGF5ZXJUbxItLmRl", - "Y2VudHJhbGFuZC5rZXJuZWwuYXBpcy5Nb3ZlUGxheWVyVG9SZXF1ZXN0Gi4u", - "ZGVjZW50cmFsYW5kLmtlcm5lbC5hcGlzLk1vdmVQbGF5ZXJUb1Jlc3BvbnNl", - "IgASaQoKVGVsZXBvcnRUbxIrLmRlY2VudHJhbGFuZC5rZXJuZWwuYXBpcy5U", - "ZWxlcG9ydFRvUmVxdWVzdBosLmRlY2VudHJhbGFuZC5rZXJuZWwuYXBpcy5U", - "ZWxlcG9ydFRvUmVzcG9uc2UiABJvCgxUcmlnZ2VyRW1vdGUSLS5kZWNlbnRy", - "YWxhbmQua2VybmVsLmFwaXMuVHJpZ2dlckVtb3RlUmVxdWVzdBouLmRlY2Vu", - "dHJhbGFuZC5rZXJuZWwuYXBpcy5UcmlnZ2VyRW1vdGVSZXNwb25zZSIAEmgK", - "C0NoYW5nZVJlYWxtEiwuZGVjZW50cmFsYW5kLmtlcm5lbC5hcGlzLkNoYW5n", - "ZVJlYWxtUmVxdWVzdBopLmRlY2VudHJhbGFuZC5rZXJuZWwuYXBpcy5TdWNj", - "ZXNzUmVzcG9uc2UiABJwCg9PcGVuRXh0ZXJuYWxVcmwSMC5kZWNlbnRyYWxh", - "bmQua2VybmVsLmFwaXMuT3BlbkV4dGVybmFsVXJsUmVxdWVzdBopLmRlY2Vu", - "dHJhbGFuZC5rZXJuZWwuYXBpcy5TdWNjZXNzUmVzcG9uc2UiABJsCg1PcGVu", - "TmZ0RGlhbG9nEi4uZGVjZW50cmFsYW5kLmtlcm5lbC5hcGlzLk9wZW5OZnRE", - "aWFsb2dSZXF1ZXN0GikuZGVjZW50cmFsYW5kLmtlcm5lbC5hcGlzLlN1Y2Nl", - "c3NSZXNwb25zZSIAEnYKGFNldENvbW11bmljYXRpb25zQWRhcHRlchItLmRl", - "Y2VudHJhbGFuZC5rZXJuZWwuYXBpcy5Db21tc0FkYXB0ZXJSZXF1ZXN0Giku", - "ZGVjZW50cmFsYW5kLmtlcm5lbC5hcGlzLlN1Y2Nlc3NSZXNwb25zZSIAEnQK", - "EVRyaWdnZXJTY2VuZUVtb3RlEjIuZGVjZW50cmFsYW5kLmtlcm5lbC5hcGlz", - "LlRyaWdnZXJTY2VuZUVtb3RlUmVxdWVzdBopLmRlY2VudHJhbGFuZC5rZXJu", - "ZWwuYXBpcy5TdWNjZXNzUmVzcG9uc2UiABJuCg9Db3B5VG9DbGlwYm9hcmQS", - "MC5kZWNlbnRyYWxhbmQua2VybmVsLmFwaXMuQ29weVRvQ2xpcGJvYXJkUmVx", - "dWVzdBonLmRlY2VudHJhbGFuZC5rZXJuZWwuYXBpcy5FbXB0eVJlc3BvbnNl", - "IgASZAoJU3RvcEVtb3RlEiouZGVjZW50cmFsYW5kLmtlcm5lbC5hcGlzLlN0", - "b3BFbW90ZVJlcXVlc3QaKS5kZWNlbnRyYWxhbmQua2VybmVsLmFwaXMuU3Vj", - "Y2Vzc1Jlc3BvbnNlIgBiBnByb3RvMw==")); + "ASgJIg8KDUVtcHR5UmVzcG9uc2UiEgoQU3RvcEVtb3RlUmVxdWVzdCJJChVP", + "cGVuRXhwbG9yZXJVaVJlcXVlc3QSMAoCdWkYASABKA4yJC5kZWNlbnRyYWxh", + "bmQua2VybmVsLmFwaXMuRXhwbG9yZXJVaSJdChZPcGVuRXhwbG9yZXJVaVJl", + "c3BvbnNlEkMKC29wZW5fcmVzdWx0GAEgASgOMi4uZGVjZW50cmFsYW5kLmtl", + "cm5lbC5hcGlzLk9wZW5FeHBsb3JlclVpUmVzdWx0KoABCgpFeHBsb3JlclVp", + "Eg8KC0VVX1NFVFRJTkdTEAASCgoGRVVfTUFQEAESDwoLRVVfQkFDS1BBQ0sQ", + "AhISCg5FVV9DQU1FUkFfUkVFTBADEhIKDkVVX0NPTU1VTklUSUVTEAQSDQoJ", + "RVVfUExBQ0VTEAUSDQoJRVVfRVZFTlRTEAYqpgEKFE9wZW5FeHBsb3JlclVp", + "UmVzdWx0Eg8KC1VOU1BFQ0lGSUVEEAASCgoGT1BFTkVEEAESFAoQV0FTX0FM", + "UkVBRFlfT1BFThACEh4KGlJFSkVDVEVEX05PVF9DVVJSRU5UX1NDRU5FEAMS", + "HQoZUkVKRUNURURfRkVBVFVSRV9ESVNBQkxFRBAEEhwKGFJFSkVDVEVEX05P", + "X1VTRVJfR0VTVFVSRRAFMuwJChhSZXN0cmljdGVkQWN0aW9uc1NlcnZpY2US", + "bwoMTW92ZVBsYXllclRvEi0uZGVjZW50cmFsYW5kLmtlcm5lbC5hcGlzLk1v", + "dmVQbGF5ZXJUb1JlcXVlc3QaLi5kZWNlbnRyYWxhbmQua2VybmVsLmFwaXMu", + "TW92ZVBsYXllclRvUmVzcG9uc2UiABJpCgpUZWxlcG9ydFRvEisuZGVjZW50", + "cmFsYW5kLmtlcm5lbC5hcGlzLlRlbGVwb3J0VG9SZXF1ZXN0GiwuZGVjZW50", + "cmFsYW5kLmtlcm5lbC5hcGlzLlRlbGVwb3J0VG9SZXNwb25zZSIAEm8KDFRy", + "aWdnZXJFbW90ZRItLmRlY2VudHJhbGFuZC5rZXJuZWwuYXBpcy5UcmlnZ2Vy", + "RW1vdGVSZXF1ZXN0Gi4uZGVjZW50cmFsYW5kLmtlcm5lbC5hcGlzLlRyaWdn", + "ZXJFbW90ZVJlc3BvbnNlIgASaAoLQ2hhbmdlUmVhbG0SLC5kZWNlbnRyYWxh", + "bmQua2VybmVsLmFwaXMuQ2hhbmdlUmVhbG1SZXF1ZXN0GikuZGVjZW50cmFs", + "YW5kLmtlcm5lbC5hcGlzLlN1Y2Nlc3NSZXNwb25zZSIAEnAKD09wZW5FeHRl", + "cm5hbFVybBIwLmRlY2VudHJhbGFuZC5rZXJuZWwuYXBpcy5PcGVuRXh0ZXJu", + "YWxVcmxSZXF1ZXN0GikuZGVjZW50cmFsYW5kLmtlcm5lbC5hcGlzLlN1Y2Nl", + "c3NSZXNwb25zZSIAEmwKDU9wZW5OZnREaWFsb2cSLi5kZWNlbnRyYWxhbmQu", + "a2VybmVsLmFwaXMuT3Blbk5mdERpYWxvZ1JlcXVlc3QaKS5kZWNlbnRyYWxh", + "bmQua2VybmVsLmFwaXMuU3VjY2Vzc1Jlc3BvbnNlIgASdgoYU2V0Q29tbXVu", + "aWNhdGlvbnNBZGFwdGVyEi0uZGVjZW50cmFsYW5kLmtlcm5lbC5hcGlzLkNv", + "bW1zQWRhcHRlclJlcXVlc3QaKS5kZWNlbnRyYWxhbmQua2VybmVsLmFwaXMu", + "U3VjY2Vzc1Jlc3BvbnNlIgASdAoRVHJpZ2dlclNjZW5lRW1vdGUSMi5kZWNl", + "bnRyYWxhbmQua2VybmVsLmFwaXMuVHJpZ2dlclNjZW5lRW1vdGVSZXF1ZXN0", + "GikuZGVjZW50cmFsYW5kLmtlcm5lbC5hcGlzLlN1Y2Nlc3NSZXNwb25zZSIA", + "Em4KD0NvcHlUb0NsaXBib2FyZBIwLmRlY2VudHJhbGFuZC5rZXJuZWwuYXBp", + "cy5Db3B5VG9DbGlwYm9hcmRSZXF1ZXN0GicuZGVjZW50cmFsYW5kLmtlcm5l", + "bC5hcGlzLkVtcHR5UmVzcG9uc2UiABJkCglTdG9wRW1vdGUSKi5kZWNlbnRy", + "YWxhbmQua2VybmVsLmFwaXMuU3RvcEVtb3RlUmVxdWVzdBopLmRlY2VudHJh", + "bGFuZC5rZXJuZWwuYXBpcy5TdWNjZXNzUmVzcG9uc2UiABJ1Cg5PcGVuRXhw", + "bG9yZXJVaRIvLmRlY2VudHJhbGFuZC5rZXJuZWwuYXBpcy5PcGVuRXhwbG9y", + "ZXJVaVJlcXVlc3QaMC5kZWNlbnRyYWxhbmQua2VybmVsLmFwaXMuT3BlbkV4", + "cGxvcmVyVWlSZXNwb25zZSIAYgZwcm90bzM=")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { global::Decentraland.Common.VectorsReflection.Descriptor, global::DCL.ECSComponents.AvatarMaskReflection.Descriptor, }, - new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Decentraland.Kernel.Apis.ExplorerUi), typeof(global::Decentraland.Kernel.Apis.OpenExplorerUiResult), }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Decentraland.Kernel.Apis.MovePlayerToRequest), global::Decentraland.Kernel.Apis.MovePlayerToRequest.Parser, new[]{ "NewRelativePosition", "CameraTarget", "AvatarTarget", "Duration" }, new[]{ "CameraTarget", "AvatarTarget", "Duration" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Decentraland.Kernel.Apis.TeleportToRequest), global::Decentraland.Kernel.Apis.TeleportToRequest.Parser, new[]{ "WorldCoordinates" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Decentraland.Kernel.Apis.TriggerEmoteRequest), global::Decentraland.Kernel.Apis.TriggerEmoteRequest.Parser, new[]{ "PredefinedEmote", "Mask" }, new[]{ "Mask" }, null, null, null), @@ -95,12 +108,55 @@ static RestrictedActionsReflection() { new pbr::GeneratedClrTypeInfo(typeof(global::Decentraland.Kernel.Apis.TeleportToResponse), global::Decentraland.Kernel.Apis.TeleportToResponse.Parser, null, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Decentraland.Kernel.Apis.CopyToClipboardRequest), global::Decentraland.Kernel.Apis.CopyToClipboardRequest.Parser, new[]{ "Text" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Decentraland.Kernel.Apis.EmptyResponse), global::Decentraland.Kernel.Apis.EmptyResponse.Parser, null, null, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Decentraland.Kernel.Apis.StopEmoteRequest), global::Decentraland.Kernel.Apis.StopEmoteRequest.Parser, null, null, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::Decentraland.Kernel.Apis.StopEmoteRequest), global::Decentraland.Kernel.Apis.StopEmoteRequest.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Decentraland.Kernel.Apis.OpenExplorerUiRequest), global::Decentraland.Kernel.Apis.OpenExplorerUiRequest.Parser, new[]{ "Ui" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Decentraland.Kernel.Apis.OpenExplorerUiResponse), global::Decentraland.Kernel.Apis.OpenExplorerUiResponse.Parser, new[]{ "OpenResult" }, null, null, null, null) })); } #endregion } + #region Enums + /// + /// Identifies which fullscreen explorer panel OpenExplorerUi targets. + /// EU_SETTINGS holds 0 so an unset `ui` field defaults to the least-intrusive panel. + /// + public enum ExplorerUi { + [pbr::OriginalName("EU_SETTINGS")] EuSettings = 0, + [pbr::OriginalName("EU_MAP")] EuMap = 1, + [pbr::OriginalName("EU_BACKPACK")] EuBackpack = 2, + [pbr::OriginalName("EU_CAMERA_REEL")] EuCameraReel = 3, + [pbr::OriginalName("EU_COMMUNITIES")] EuCommunities = 4, + [pbr::OriginalName("EU_PLACES")] EuPlaces = 5, + [pbr::OriginalName("EU_EVENTS")] EuEvents = 6, + } + + /// + /// Verdict of an OpenExplorerUi request (enum rather than a bool so new outcomes stay expressible). + /// + public enum OpenExplorerUiResult { + [pbr::OriginalName("UNSPECIFIED")] Unspecified = 0, + [pbr::OriginalName("OPENED")] Opened = 1, + /// + /// a fullscreen panel is already open + /// + [pbr::OriginalName("WAS_ALREADY_OPEN")] WasAlreadyOpen = 2, + /// + /// the standard restricted-actions current-scene gate rejected the call + /// + [pbr::OriginalName("REJECTED_NOT_CURRENT_SCENE")] RejectedNotCurrentScene = 3, + /// + /// the requested section is hidden by feature flags or client doesn't have that feature + /// + [pbr::OriginalName("REJECTED_FEATURE_DISABLED")] RejectedFeatureDisabled = 4, + /// + /// rejected: the call did not originate from a user gesture + /// + [pbr::OriginalName("REJECTED_NO_USER_GESTURE")] RejectedNoUserGesture = 5, + } + + #endregion + #region Messages [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] public sealed partial class MovePlayerToRequest : pb::IMessage @@ -3463,6 +3519,405 @@ public void MergeFrom(pb::CodedInputStream input) { } + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class OpenExplorerUiRequest : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new OpenExplorerUiRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Decentraland.Kernel.Apis.RestrictedActionsReflection.Descriptor.MessageTypes[16]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public OpenExplorerUiRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public OpenExplorerUiRequest(OpenExplorerUiRequest other) : this() { + ui_ = other.ui_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public OpenExplorerUiRequest Clone() { + return new OpenExplorerUiRequest(this); + } + + /// Field number for the "ui" field. + public const int UiFieldNumber = 1; + private global::Decentraland.Kernel.Apis.ExplorerUi ui_ = global::Decentraland.Kernel.Apis.ExplorerUi.EuSettings; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Decentraland.Kernel.Apis.ExplorerUi Ui { + get { return ui_; } + set { + ui_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as OpenExplorerUiRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(OpenExplorerUiRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Ui != other.Ui) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Ui != global::Decentraland.Kernel.Apis.ExplorerUi.EuSettings) hash ^= Ui.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Ui != global::Decentraland.Kernel.Apis.ExplorerUi.EuSettings) { + output.WriteRawTag(8); + output.WriteEnum((int) Ui); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Ui != global::Decentraland.Kernel.Apis.ExplorerUi.EuSettings) { + output.WriteRawTag(8); + output.WriteEnum((int) Ui); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Ui != global::Decentraland.Kernel.Apis.ExplorerUi.EuSettings) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Ui); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(OpenExplorerUiRequest other) { + if (other == null) { + return; + } + if (other.Ui != global::Decentraland.Kernel.Apis.ExplorerUi.EuSettings) { + Ui = other.Ui; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Ui = (global::Decentraland.Kernel.Apis.ExplorerUi) input.ReadEnum(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Ui = (global::Decentraland.Kernel.Apis.ExplorerUi) input.ReadEnum(); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class OpenExplorerUiResponse : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new OpenExplorerUiResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Decentraland.Kernel.Apis.RestrictedActionsReflection.Descriptor.MessageTypes[17]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public OpenExplorerUiResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public OpenExplorerUiResponse(OpenExplorerUiResponse other) : this() { + openResult_ = other.openResult_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public OpenExplorerUiResponse Clone() { + return new OpenExplorerUiResponse(this); + } + + /// Field number for the "open_result" field. + public const int OpenResultFieldNumber = 1; + private global::Decentraland.Kernel.Apis.OpenExplorerUiResult openResult_ = global::Decentraland.Kernel.Apis.OpenExplorerUiResult.Unspecified; + /// + /// Carries only the verdict of the open action. + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Decentraland.Kernel.Apis.OpenExplorerUiResult OpenResult { + get { return openResult_; } + set { + openResult_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as OpenExplorerUiResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(OpenExplorerUiResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (OpenResult != other.OpenResult) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (OpenResult != global::Decentraland.Kernel.Apis.OpenExplorerUiResult.Unspecified) hash ^= OpenResult.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (OpenResult != global::Decentraland.Kernel.Apis.OpenExplorerUiResult.Unspecified) { + output.WriteRawTag(8); + output.WriteEnum((int) OpenResult); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (OpenResult != global::Decentraland.Kernel.Apis.OpenExplorerUiResult.Unspecified) { + output.WriteRawTag(8); + output.WriteEnum((int) OpenResult); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (OpenResult != global::Decentraland.Kernel.Apis.OpenExplorerUiResult.Unspecified) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) OpenResult); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(OpenExplorerUiResponse other) { + if (other == null) { + return; + } + if (other.OpenResult != global::Decentraland.Kernel.Apis.OpenExplorerUiResult.Unspecified) { + OpenResult = other.OpenResult; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + OpenResult = (global::Decentraland.Kernel.Apis.OpenExplorerUiResult) input.ReadEnum(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + OpenResult = (global::Decentraland.Kernel.Apis.OpenExplorerUiResult) input.ReadEnum(); + break; + } + } + } + } + #endif + + } + #endregion } diff --git a/Explorer/Assets/StreamingAssets/Js/Modules/RestrictedActions.js b/Explorer/Assets/StreamingAssets/Js/Modules/RestrictedActions.js index 211d5d0889e..b853ce555bd 100644 --- a/Explorer/Assets/StreamingAssets/Js/Modules/RestrictedActions.js +++ b/Explorer/Assets/StreamingAssets/Js/Modules/RestrictedActions.js @@ -1,6 +1,35 @@ // Responses should always correspond to the protocol definitions at // https://github.com/decentraland/protocol/blob/main/proto/decentraland/kernel/apis/restricted_actions.proto +// Protocol enums exposed to scenes as runtime values (mirroring the generated +// ts-proto enums: both forward name->value and reverse value->name mappings). +// Scenes import these from `~system/RestrictedActions` and use them at runtime, +// e.g. `openExplorerUi({ ui: ExplorerUi.EU_MAP })` and `OpenExplorerUiResult[openResult]`. +function makeEnum(entries) { + const e = {}; + for (const [name, value] of entries) { e[name] = value; e[value] = name; } + return e; +} + +module.exports.ExplorerUi = makeEnum([ + ['EU_SETTINGS', 0], + ['EU_MAP', 1], + ['EU_BACKPACK', 2], + ['EU_CAMERA_REEL', 3], + ['EU_COMMUNITIES', 4], + ['EU_PLACES', 5], + ['EU_EVENTS', 6], +]); + +module.exports.OpenExplorerUiResult = makeEnum([ + ['UNSPECIFIED', 0], + ['OPENED', 1], + ['WAS_ALREADY_OPEN', 2], + ['REJECTED_NOT_CURRENT_SCENE', 3], + ['REJECTED_FEATURE_DISABLED', 4], + ['REJECTED_NO_USER_GESTURE', 5], +]); + module.exports.movePlayerTo = async function(message) { const cameraTarget = message.cameraTarget != undefined const avatarTarget = message.avatarTarget != undefined @@ -62,6 +91,11 @@ module.exports.openNftDialog = async function(message) { }; } +module.exports.openExplorerUi = async function(message) { + const openResult = UnityRestrictedActionsApi.OpenExplorerUi(message.ui) + return { openResult }; +} + module.exports.setCommunicationsAdapter = async function(message) { console.log('JSMODULE: setCommunicationsAdapter') return { diff --git a/Explorer/DCL.EditMode.Tests.csproj.DotSettings b/Explorer/DCL.EditMode.Tests.csproj.DotSettings index 6769ea07494..c5777b99330 100644 --- a/Explorer/DCL.EditMode.Tests.csproj.DotSettings +++ b/Explorer/DCL.EditMode.Tests.csproj.DotSettings @@ -5,6 +5,7 @@ True True True + True True True True diff --git a/Explorer/DCL.Social.csproj.DotSettings b/Explorer/DCL.Social.csproj.DotSettings index 655c63f932d..c472703d180 100644 --- a/Explorer/DCL.Social.csproj.DotSettings +++ b/Explorer/DCL.Social.csproj.DotSettings @@ -2,6 +2,7 @@ True True True + True True True True diff --git a/Explorer/SceneRuntime.csproj.DotSettings b/Explorer/SceneRuntime.csproj.DotSettings index b6666aa0390..798fbd4ac03 100644 --- a/Explorer/SceneRuntime.csproj.DotSettings +++ b/Explorer/SceneRuntime.csproj.DotSettings @@ -1,5 +1,6 @@  True + True True True True \ No newline at end of file diff --git a/scripts/package-lock.json b/scripts/package-lock.json index 42f0aa2d89b..4c51a7c3bcb 100644 --- a/scripts/package-lock.json +++ b/scripts/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "@dcl/protocol": "https://sdk-team-cdn.decentraland.org/@dcl/protocol/branch//dcl-protocol-1.0.0-29092627614.commit-d2f272f.tgz", + "@dcl/protocol": "https://sdk-team-cdn.decentraland.org/@dcl/protocol/branch//dcl-protocol-1.0.0-30037355888.commit-0e7de00.tgz", "@protobuf-ts/protoc": "^2.11.0", "@types/fs-extra": "^11.0.1", "@types/glob": "^8.0.1", @@ -37,9 +37,9 @@ } }, "node_modules/@dcl/protocol": { - "version": "1.0.0-29092627614.commit-d2f272f", - "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/protocol/branch//dcl-protocol-1.0.0-29092627614.commit-d2f272f.tgz", - "integrity": "sha512-ETnLajHgCy0KCwnQ+oC5faEY53sa/y29Z1/0kHmiTsq5EWZLl1r6kwnFBSV0NrZD7iw8Cmz0XX694XonYqH37w==", + "version": "1.0.0-30037355888.commit-0e7de00", + "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/protocol/branch//dcl-protocol-1.0.0-30037355888.commit-0e7de00.tgz", + "integrity": "sha512-zAKzFGm2WNtJztN7FjAma2Uj5b72yyymTXwFTNb+VQRFceNRnS05bEKyAWjUfX1QbKT56Ln8Bd1n261BnWPzWA==", "license": "Apache-2.0", "dependencies": { "@dcl/ts-proto": "1.154.0", @@ -608,8 +608,8 @@ } }, "@dcl/protocol": { - "version": "https://sdk-team-cdn.decentraland.org/@dcl/protocol/branch//dcl-protocol-1.0.0-29092627614.commit-d2f272f.tgz", - "integrity": "sha512-ETnLajHgCy0KCwnQ+oC5faEY53sa/y29Z1/0kHmiTsq5EWZLl1r6kwnFBSV0NrZD7iw8Cmz0XX694XonYqH37w==", + "version": "https://sdk-team-cdn.decentraland.org/@dcl/protocol/branch//dcl-protocol-1.0.0-30037355888.commit-0e7de00.tgz", + "integrity": "sha512-zAKzFGm2WNtJztN7FjAma2Uj5b72yyymTXwFTNb+VQRFceNRnS05bEKyAWjUfX1QbKT56Ln8Bd1n261BnWPzWA==", "requires": { "@dcl/ts-proto": "1.154.0", "protobufjs": "7.2.4" diff --git a/scripts/package.json b/scripts/package.json index f57bf4cb1c0..83f032d8205 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -16,7 +16,7 @@ "typescript": "^4.2.3" }, "dependencies": { - "@dcl/protocol": "https://sdk-team-cdn.decentraland.org/@dcl/protocol/branch//dcl-protocol-1.0.0-29092627614.commit-d2f272f.tgz", + "@dcl/protocol": "https://sdk-team-cdn.decentraland.org/@dcl/protocol/branch//dcl-protocol-1.0.0-30037355888.commit-0e7de00.tgz", "@protobuf-ts/protoc": "^2.11.0", "@types/fs-extra": "^11.0.1", "@types/glob": "^8.0.1",