diff --git a/README.md b/README.md index 821e444b05..464cfbab79 100644 --- a/README.md +++ b/README.md @@ -88,10 +88,10 @@ This is the most useful debugging scenario for advanced feature implementation. ### Steps 1. Make sure you have the proper Unity version up and running -3. Make sure you are running browser-interface through `make watch` command on `browser-interface` path. -4. Back in unity editor, open the `DebugConfig` component inspector of `InitialScene` -5. Make sure that the component is setup correctly -6. Hit 'Play' button +2. Make sure you are running browser-interface through `make watch` command on `browser-interface` path. +3. Back in unity editor, open the `DebugConfig` component inspector of `InitialScene` +4. Make sure that the component is setup correctly +5. Hit 'Play' button ## Debug with browsers + local Unity build @@ -102,16 +102,16 @@ When the steps are followed, you will be able to run the local Unity build by go ### Steps 1. Make sure you have the proper Unity version up and running -3. Make sure you are running browser-interface through `make watch` command. -4. Produce a Unity wasm targeted build using the Build menu. -5. When the build finishes, copy all the files inside the resulting `/build` folder (`unity.loader.js` is not necessary as we use a modified loader) and paste them inside `browser-interface/node_modules/@dcl/unity-renderer`. -6. Run the browser explorer through `localhost:8080&ENABLE_WEB3`. Now, it should use your local Unity build. Don't mind the white screen at the beginning, that's because the website repo is not being used and it's only loading Browser Interface with the build. -7. If you need a Unity re-build, you can just replace the files and reload the browser without restarting the `make watch` process. +2. Make sure you are running browser-interface correctly by running `npm install`, `make build-unity-local` and `make watch` commands in that directory and leave that server running. +3. Produce a Unity wasm targeted build using the Build menu (the build should be named just "unity" to avoid renamings later). +4. When the build finishes, copy all the files inside the resulting `/build` folder (`unity.loader.js` may not be necessary) and paste them inside `browser-interface/node_modules/@dcl/explorer`. +5. Run the browser explorer through `http://localhost:8080/?ENABLE_WEB3`. Now, it should use your local Unity build. Don't mind the white screen at the beginning, that's because the website repo is not being used and it's only loading Browser Interface with the build. +6. If you need a Unity re-build, you can just replace the files and reload the browser without restarting the `make watch` process. -Alternatively you can go through these 2 steps after step 3 and load the build locally using `localhost:3000` +Alternatively you can go through these steps after step 3 and load the build locally using `localhost:3000` 1. Make sure you have the [explorer website repository](https://github.com/decentraland/explorer-website) cloned. 2. Make sure you have the local website up and running by executing `npm run start:linked` in the cloned repo directory (`npm i` first just in case). -3. When the WebGL build finishes, copy all the files inside the resulting `/build` folder (`unity.loader.js` is not necessary as we use a modified loader) and paste them inside `explorer-website/node_modules/@dcl/unity-renderer`. +3. When the WebGL build finishes, copy all the files inside the resulting `/build` folder (`unity.loader.js` is not necessary as we use a modified loader) and paste them inside `explorer-website/node_modules/@dcl/explorer`. 4. Access using `localhost:3000` ### Troubleshooting @@ -147,4 +147,4 @@ If the local WebGL build always fails with the error `System.ComponentModel.Win3 ## Copyright info This repository is protected with a standard Apache 2 license. See the terms and conditions in -the [LICENSE](https://github.com/decentraland/unity-renderer/blob/master/LICENSE) file. \ No newline at end of file +the [LICENSE](https://github.com/decentraland/unity-renderer/blob/master/LICENSE) file. diff --git a/unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesRequestWeb.cs b/unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesBatchRequest.cs similarity index 68% rename from unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesRequestWeb.cs rename to unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesBatchRequest.cs index 5bab11d9fd..03ae4ca2c4 100644 --- a/unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesRequestWeb.cs +++ b/unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesBatchRequest.cs @@ -6,10 +6,11 @@ using System.Collections.Generic; using System.Linq; using System.Threading; +using UnityEngine.Pool; namespace DCLServices.EmotesCatalog { - public class EmotesRequestWeb : IEmotesRequestSource + public class EmotesBatchRequest : IEmotesRequestSource { [Serializable] public class OwnedEmotesRequestDto @@ -35,18 +36,18 @@ public class EmoteRequestDto private readonly ILambdasService lambdasService; private readonly ICatalyst catalyst; - private readonly List pendingRequests = new (); + private readonly HashSet pendingRequests = new (); private readonly CancellationTokenSource cts; private readonly BaseVariable featureFlags; private UniTaskCompletionSource> lastRequestSource; private string assetBundlesUrl => featureFlags.Get().IsFeatureEnabled("ab-new-cdn") ? "https://ab-cdn.decentraland.org/" : "https://content-assets-as-bundle.decentraland.org/"; - public EmotesRequestWeb(ILambdasService lambdasService, IServiceProviders serviceProviders, BaseVariable featureFlags) + public EmotesBatchRequest(ILambdasService lambdasService, IServiceProviders serviceProviders, BaseVariable featureFlags) { this.featureFlags = featureFlags; this.lambdasService = lambdasService; - this.catalyst = serviceProviders.catalyst; + catalyst = serviceProviders.catalyst; cts = new CancellationTokenSource(); } @@ -65,15 +66,15 @@ private async UniTask RequestOwnedEmotesAsync(string userId) { var url = $"{catalyst.lambdasUrl}/users/{userId}/emotes"; - List requestedEmotes = new List(); + var requestedEmotes = new List(); if (!await FullListEmoteFetch(userId, url, requestedEmotes)) return; - var tempList = PoolUtils.RentList(); - var emoteUrns = tempList.GetList(); + PoolUtils.ListPoolRent tempList = PoolUtils.RentList(); + List emoteUrns = tempList.GetList(); - Dictionary urnToAmountMap = new Dictionary(); + var urnToAmountMap = new Dictionary(); foreach (OwnedEmotesRequestDto.EmoteRequestDto emoteRequestDto in requestedEmotes) { @@ -81,7 +82,7 @@ private async UniTask RequestOwnedEmotesAsync(string userId) urnToAmountMap[emoteRequestDto.urn] = emoteRequestDto.amount; } - var emotes = await FetchEmotes(emoteUrns, urnToAmountMap); + IReadOnlyList emotes = await FetchEmotes(emoteUrns, urnToAmountMap); tempList.Dispose(); @@ -91,18 +92,18 @@ private async UniTask RequestOwnedEmotesAsync(string userId) // This recursiveness is horrible, we should add proper pagination private async UniTask FullListEmoteFetch(string userId, string url, List requestedEmotes) { - int requestedCount = 0; - int totalEmotes = 99999; - int pageNum = 1; + var requestedCount = 0; + var totalEmotes = 99999; + var pageNum = 1; while (requestedCount < totalEmotes) { - var queryParams = new List<(string name, string value)> + (string name, string value)[] queryParams = new List<(string name, string value)> { - ("pageNum", pageNum.ToString()) + ("pageNum", pageNum.ToString()), }.ToArray(); - var result = await lambdasService.GetFromSpecificUrl(url, url, + (OwnedEmotesRequestDto response, bool success) result = await lambdasService.GetFromSpecificUrl(url, url, cancellationToken: cts.Token, urlEncodedParams: queryParams); if (!result.success) throw new Exception($"Fetching owned wearables failed! {url}\nAddress: {userId}"); @@ -130,8 +131,8 @@ public void RequestEmote(string emoteId) private async UniTask RequestWearableBatchAsync(string id) { pendingRequests.Add(id); - lastRequestSource ??= new (); - var sourceToAwait = lastRequestSource; + lastRequestSource ??= new UniTaskCompletionSource>(); + UniTaskCompletionSource> sourceToAwait = lastRequestSource; // we wait for the latest update possible so we buffer all requests into one await UniTask.Yield(PlayerLoopTiming.PostLateUpdate, cts.Token); @@ -142,29 +143,32 @@ private async UniTask RequestWearableBatchAsync(string id) { lastRequestSource = null; - result = await FetchEmotes(pendingRequests); - + List tempList = ListPool.Get(); + tempList.AddRange(pendingRequests); pendingRequests.Clear(); + result = await FetchEmotes(tempList); + ListPool.Release(tempList); sourceToAwait.TrySetResult(result); + OnEmotesReceived?.Invoke(result); } else - result = await sourceToAwait.Task; - - OnEmotesReceived?.Invoke(result); + await sourceToAwait.Task; } - private async UniTask> FetchEmotes(List ids, Dictionary urnToAmountMap = null) + private async UniTask> FetchEmotes(IReadOnlyCollection ids, Dictionary urnToAmountMap = null) { // the copy of the list is intentional var request = new LambdasEmotesCatalogService.WearableRequest { pointers = new List(ids) }; var url = $"{catalyst.contentUrl}entities/active"; - var response = await lambdasService.PostFromSpecificUrl(url, url, request, cancellationToken: cts.Token); + (EmoteEntityDto[] response, bool success) response = await lambdasService.PostFromSpecificUrl(url, url, request, cancellationToken: cts.Token); if (!response.success) throw new Exception($"Fetching wearables failed! {url}\n{string.Join("\n", request.pointers)}"); - var wearables = response.response.Select(dto => + HashSet receivedIds = HashSetPool.Get(); + + IEnumerable wearables = response.response.Select(dto => { var contentUrl = $"{catalyst.contentUrl}contents/"; var wearableItem = dto.ToWearableItem(contentUrl); @@ -176,6 +180,14 @@ private async UniTask> FetchEmotes(List ids, return wearableItem; }); + foreach (WearableItem wearableItem in wearables) + receivedIds.Add(wearableItem.id); + + foreach (string id in ids) + if (!receivedIds.Contains(id)) + OnEmoteRejected?.Invoke(id, "Empty response from content server"); + + HashSetPool.Release(receivedIds); return wearables.ToList(); } } diff --git a/unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesRequestWeb.cs.meta b/unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesBatchRequest.cs.meta similarity index 100% rename from unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesRequestWeb.cs.meta rename to unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesBatchRequest.cs.meta diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarCurator.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarCurator.cs index 4cbea5d89d..b16b97ee6c 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarCurator.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarCurator.cs @@ -1,8 +1,10 @@ +using Cysharp.Threading.Tasks; +using DCL.Emotes; +using DCLServices.WearablesCatalogService; using System; using System.Collections.Generic; using System.Linq; using System.Threading; -using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.Assertions; using UnityEngine.Pool; @@ -13,12 +15,15 @@ public class AvatarCurator : IAvatarCurator { private readonly IWearableItemResolver wearableItemResolver; private readonly IEmotesCatalogService emotesCatalog; + private EmbeddedEmotesSO embedEmotes; + private string[] embedEmotesId; public AvatarCurator(IWearableItemResolver wearableItemResolver, IEmotesCatalogService emotesCatalog) { Assert.IsNotNull(wearableItemResolver); this.wearableItemResolver = wearableItemResolver; this.emotesCatalog = emotesCatalog; + } /// @@ -49,9 +54,12 @@ List emotes //New emotes flow use the emotes catalog if (emoteIds != null) { + embedEmotes ??= await emotesCatalog.GetEmbeddedEmotes(); + embedEmotesId ??= embedEmotes.GetAllIds(); + DateTime startLoadTime = DateTime.Now; - var emoteIdsList = emoteIds.ToList(); + var emoteIdsList = emoteIds.Select(ExtendedUrnParser.GetShortenedUrn).ToList(); IReadOnlyList resolvedEmotes = await emotesCatalog.RequestEmotesAsync(emoteIdsList, ct); List nonPublishedEmotes = ListPool.Get(); @@ -60,6 +68,8 @@ List emotes if (nonPublishedEmoteId.StartsWith("urn")) continue; bool wasResolved = resolvedEmotes?.Any(item => item?.id == nonPublishedEmoteId) ?? false; if (wasResolved) continue; + bool isEmbedded = embedEmotesId.Contains(nonPublishedEmoteId); + if (isEmbedded) continue; WearableItem nonPublishedEmote = await emotesCatalog.RequestEmoteFromBuilderAsync(nonPublishedEmoteId, ct); if (nonPublishedEmote != null) nonPublishedEmotes.Add(nonPublishedEmote); diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Loader/WearableItemResolver.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Loader/WearableItemResolver.cs index 2adcd67ea0..5edf6cdc02 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Loader/WearableItemResolver.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Loader/WearableItemResolver.cs @@ -1,10 +1,10 @@ +using Cysharp.Threading.Tasks; +using DCL.Helpers; +using DCLServices.WearablesCatalogService; using System; using System.Collections.Generic; using System.Linq; using System.Threading; -using Cysharp.Threading.Tasks; -using DCL.Helpers; -using DCLServices.WearablesCatalogService; namespace AvatarSystem { @@ -23,7 +23,7 @@ public WearableItemResolver(IWearablesCatalogService wearablesCatalogService) { try { - var parsedWearablesIds = wearableIds.Select((wearableId) => ExtendedUrnParser.GetShortenedUrn(wearableId)); + IEnumerable parsedWearablesIds = wearableIds.Select(ExtendedUrnParser.GetShortenedUrn); WearableItem[] allItems = await Resolve(parsedWearablesIds, ct); List wearables = new List(); diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/LoadingScreen/Scripts/LoadingScreenController.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/LoadingScreen/Scripts/LoadingScreenController.cs index 548f7298a2..87fc645e68 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/LoadingScreen/Scripts/LoadingScreenController.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/LoadingScreen/Scripts/LoadingScreenController.cs @@ -105,6 +105,12 @@ private void OnSignupFlow(bool current, bool previous) { onSignUpFlow = current; + if (realmDataStore.playerRealmAboutConfiguration.Get() != null) + { + currentRealm = realmDataStore.playerRealmAboutConfiguration.Get().RealmName; + currentRealmIsWorld = commonDataStore.isWorld.Get(); + } + if (current) FadeOutView(); else diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Environment/Factories/ServiceLocatorFactory/ServiceLocatorFactory.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Environment/Factories/ServiceLocatorFactory/ServiceLocatorFactory.cs index 7a839e48c3..e64e7275e3 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Environment/Factories/ServiceLocatorFactory/ServiceLocatorFactory.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Environment/Factories/ServiceLocatorFactory/ServiceLocatorFactory.cs @@ -129,7 +129,7 @@ public static ServiceLocator CreateDefault() result.Register(() => { - var emotesRequest = new EmotesRequestWeb( + var emotesRequest = new EmotesBatchRequest( result.Get(), result.Get(), featureFlagsDataStore);