Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added remote player pins #2841

Merged
merged 4 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public enum DecentralandUrl
OpenSea,

PeerAbout,
RemotePeers,

DAO,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ private static string RawUrl(DecentralandUrl decentralandUrl) =>
DecentralandUrl.Host => $"https://decentraland.{ENV}",
DecentralandUrl.ApiChunks => $"https://api.decentraland.{ENV}/v1/map.png",
DecentralandUrl.PeerAbout => $"https://peer.decentraland.{ENV}/about",
DecentralandUrl.RemotePeers => $"https://archipelago-ea-stats.decentraland.{ENV}/comms/peers",
DecentralandUrl.DAO => $"https://decentraland.{ENV}/dao/",
DecentralandUrl.Notification => $"https://notifications.decentraland.{ENV}/notifications",
DecentralandUrl.NotificationRead => $"https://notifications.decentraland.{ENV}/notifications/read",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
using Cysharp.Threading.Tasks;
using DCL.AssetsProvision;
using DCL.Browser.DecentralandUrls;
using DCL.MapRenderer.CoordsUtils;
using DCL.MapRenderer.Culling;
using DCL.MapRenderer.MapLayers;
using DCL.MapRenderer.MapLayers.Users;
using DCL.MapRenderer.MapLayers.UsersMarker;
using DCL.Multiplayer.Connections.DecentralandUrls;
using DCL.WebRequests;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using UnityEngine.Pool;
using Utility.TeleportBus;

namespace DCL.MapRenderer.ComponentsFactory
{
Expand All @@ -26,6 +30,8 @@ public async UniTask InstallAsync(
IMapCullingController cullingController,
IAssetsProvisioner assetsProv,
IMapRendererSettings settings,
ITeleportBusController teleportBusController,
RemoteUsersRequestController remoteUsersRequestController,
CancellationToken cancellationToken)
{
assetsProvisioner = assetsProv;
Expand All @@ -43,8 +49,8 @@ IHotUserMarker CreateWrap() =>

var wrapsPool = new ObjectPool<IHotUserMarker>(CreateWrap, actionOnRelease: m => m.Dispose(), defaultCapacity: HOT_USER_MARKERS_PREWARM_COUNT);

var controller = new UsersMarkersHotAreaController(objectsPool, wrapsPool, configuration.HotUserMarkersRoot, coordsUtils, cullingController);

var controller = new UsersMarkersHotAreaController(objectsPool, wrapsPool, configuration.HotUserMarkersRoot, coordsUtils, cullingController, teleportBusController, remoteUsersRequestController);
await controller.InitializeAsync(cancellationToken);
writer.Add(MapLayer.HotUsersMarkers, controller);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using DCL.MapRenderer.MapLayers.ParcelHighlight;
using DCL.MapRenderer.MapLayers.Pins;
using DCL.MapRenderer.MapLayers.SatelliteAtlas;
using DCL.MapRenderer.MapLayers.UsersMarker;
using DCL.Multiplayer.Connections.DecentralandUrls;
using DCL.NotificationsBusController.NotificationsBus;
using DCL.PlacesAPIService;
Expand All @@ -19,6 +20,7 @@
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Pool;
using Utility.TeleportBus;
using Object = UnityEngine.Object;

namespace DCL.MapRenderer.ComponentsFactory
Expand All @@ -34,6 +36,7 @@ public class MapRendererChunkComponentsFactory : IMapRendererComponentsFactory
private readonly IPlacesAPIService placesAPIService;
private readonly IMapRendererSettings mapSettings;
private readonly IMapPathEventBus mapPathEventBus;
private readonly ITeleportBusController teleportBusController;
private readonly INotificationsBusController notificationsBusController;
private PlayerMarkerInstaller playerMarkerInstaller { get; }
private SceneOfInterestsMarkersInstaller sceneOfInterestMarkerInstaller { get; }
Expand All @@ -51,6 +54,7 @@ public MapRendererChunkComponentsFactory(
MapRendererTextureContainer textureContainer,
IPlacesAPIService placesAPIService,
IMapPathEventBus mapPathEventBus,
ITeleportBusController teleportBusController,
INotificationsBusController notificationsBusController)
{
this.assetsProvisioner = assetsProvisioner;
Expand All @@ -60,6 +64,7 @@ public MapRendererChunkComponentsFactory(
this.textureContainer = textureContainer;
this.placesAPIService = placesAPIService;
this.mapPathEventBus = mapPathEventBus;
this.teleportBusController = teleportBusController;
this.notificationsBusController = notificationsBusController;
}

Expand All @@ -83,6 +88,7 @@ async UniTask<MapRendererComponents> IMapRendererComponentsFactory.CreateAsync(C

MapCameraObject mapCameraObjectPrefab = (await assetsProvisioner.ProvideMainAssetAsync(mapSettings.MapCameraObject, ct: cancellationToken)).Value;
PinMarkerController pinMarkerController = await pinMarkerInstaller.InstallAsync(layers, zoomScalingLayers, configuration, coordsUtils, cullingController, mapSettings, assetsProvisioner, mapPathEventBus, cancellationToken);
RemoteUsersRequestController remoteUsersRequestController = new RemoteUsersRequestController(webRequestController, decentralandUrlsSource);

IObjectPool<IMapCameraControllerInternal> cameraControllersPool = new ObjectPool<IMapCameraControllerInternal>(
CameraControllerBuilder,
Expand All @@ -104,7 +110,7 @@ await UniTask.WhenAll(
sceneOfInterestMarkerInstaller.InstallAsync(layers, zoomScalingLayers, configuration, coordsUtils, cullingController, assetsProvisioner, mapSettings, placesAPIService, clusterObjectsPool, cancellationToken),
categoriesMarkerInstaller.InstallAsync(layers, zoomScalingLayers, configuration, coordsUtils, cullingController, assetsProvisioner, mapSettings, placesAPIService, clusterObjectsPool, cancellationToken),
favoritesMarkersInstaller.InstallAsync(layers, zoomScalingLayers, configuration, coordsUtils, cullingController, placesAPIService, assetsProvisioner, mapSettings, clusterObjectsPool, cancellationToken),
hotUsersMarkersInstaller.InstallAsync(layers, configuration, coordsUtils, cullingController, assetsProvisioner, mapSettings, cancellationToken),
hotUsersMarkersInstaller.InstallAsync(layers, configuration, coordsUtils, cullingController, assetsProvisioner, mapSettings, teleportBusController, remoteUsersRequestController, cancellationToken),
mapPathInstaller.InstallAsync(layers, zoomScalingLayers, configuration, coordsUtils, cullingController, mapSettings, assetsProvisioner, mapPathEventBus, notificationsBusController, cancellationToken)
/* List of other creators that can be executed in parallel */);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;
using UnityEngine;

namespace DCL.MapRenderer.MapLayers.UsersMarker
{
[Serializable] public class RemotePlayerData
{
public Vector3 position;
public string avatarId;
}
}

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
@@ -0,0 +1,53 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace DCL.MapRenderer.MapLayers.UsersMarker
{
public class RemotePlayersJsonDtoConverter : JsonConverter<List<RemotePlayerData>>
{
public override void WriteJson(JsonWriter writer, List<RemotePlayerData>? value, JsonSerializer serializer)
{
writer.WriteStartArray();
foreach (var item in value)
serializer.Serialize(writer, item);

writer.WriteEndArray();
}

public override List<RemotePlayerData> ReadJson(JsonReader reader, Type objectType, List<RemotePlayerData> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;

existingValue ??= new List<RemotePlayerData>();

var rootObject = JObject.Load(reader).ToObject<RootObject>();
foreach (DataObject rootObjectPeer in rootObject.peers)
{
existingValue.Add(new RemotePlayerData()
{
position = ConvertStringToVector3(rootObjectPeer.position[0], rootObjectPeer.position[2]),
avatarId = rootObjectPeer.address
});
}
return existingValue;
}

private static Vector3 ConvertStringToVector3(float x, float z) =>
new (Convert.ToInt32(x), 0, Convert.ToInt32(z));

private class RootObject
{
public List<DataObject> peers { get; set; }
}

private class DataObject
{
public string address { get; set; }
public float[] position { get; set; }
}
}
}

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
@@ -0,0 +1,31 @@
using Cysharp.Threading.Tasks;
using DCL.Diagnostics;
using DCL.Multiplayer.Connections.DecentralandUrls;
using DCL.WebRequests;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;

namespace DCL.MapRenderer.MapLayers.UsersMarker
{
public class RemoteUsersRequestController
{
private static readonly JsonSerializerSettings SERIALIZER_SETTINGS = new () { Converters = new JsonConverter[] { new RemotePlayersJsonDtoConverter() } };

private readonly IDecentralandUrlsSource decentralandUrlsSource;
private string baseURL => decentralandUrlsSource.Url(DecentralandUrl.RemotePeers);
private readonly IWebRequestController webRequestController;

public RemoteUsersRequestController(IWebRequestController webRequestController, IDecentralandUrlsSource decentralandUrlsSource)
{
this.webRequestController = webRequestController;
this.decentralandUrlsSource = decentralandUrlsSource;
}

public async UniTask<List<RemotePlayerData>> RequestUsers(CancellationToken ct) =>
await webRequestController.GetAsync(baseURL, ct, ReportCategory.UI)
.CreateFromNewtonsoftJsonAsync<List<RemotePlayerData>>(serializerSettings: SERIALIZER_SETTINGS);
}

}

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 @@ -10,37 +10,57 @@
using DCL.MapRenderer.CoordsUtils;
using DCL.MapRenderer.Culling;
using DCL.MapRenderer.MapLayers.UsersMarker;
using ECS.Groups;
using DCL.Multiplayer.Connections.DecentralandUrls;
using DCL.WebRequests;
using ECS.LifeCycle.Components;
using MVC;
using System;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using UnityEngine.Pool;
using Utility;
using Utility.TeleportBus;

namespace DCL.MapRenderer.MapLayers.Users
{
internal partial class UsersMarkersHotAreaController : MapLayerControllerBase, IMapLayerController
{
private readonly IObjectPool<HotUserMarkerObject> objectsPool;
private readonly IObjectPool<IHotUserMarker> wrapsPool;
private readonly ITeleportBusController teleportBusController;
private readonly RemoteUsersRequestController remoteUsersRequestController;
private TrackPlayersPositionSystem trackSystem;
private RemovedTrackedPlayersPositionSystem untrackSystem;

private readonly Dictionary<string, IHotUserMarker> markers = new ();
private readonly HashSet<string> remoteUsers = new ();
private readonly HashSet<string> closebyUsers = new ();
private CancellationTokenSource cancellationToken;
private bool isEnabled;

public UsersMarkersHotAreaController(
IObjectPool<HotUserMarkerObject> objectsPool,
IObjectPool<IHotUserMarker> wrapsPool,
Transform parent,
ICoordsUtils coordsUtils,
IMapCullingController cullingController)
IMapCullingController cullingController,
ITeleportBusController teleportBusController,
RemoteUsersRequestController remoteUsersRequestController)
: base(parent, coordsUtils, cullingController)
{
this.objectsPool = objectsPool;
this.wrapsPool = wrapsPool;
this.teleportBusController = teleportBusController;
this.remoteUsersRequestController = remoteUsersRequestController;
this.teleportBusController.SubscribeToTeleportOperation(OnTeleport);
cancellationToken = new CancellationTokenSource();
}

private void OnTeleport(Vector2Int destinationcoordinates)
{
cancellationToken = cancellationToken.SafeRestart();
ProcessRemoteUsers(cancellationToken.Token).Forget();
}

protected override void DisposeImpl()
Expand Down Expand Up @@ -69,13 +89,17 @@ private void SetPlayerMarker(in CharacterTransform transformComponent, in Avatar
if (!isEnabled)
return;

if (remoteUsers.Contains(avatarShape.ID))
remoteUsers.Remove(avatarShape.ID);

if (markers.TryGetValue(avatarShape.ID, out var marker))
{
marker.UpdateMarkerPosition(avatarShape.ID, transformComponent.Transform.position);
mapCullingController.SetTrackedObjectPositionDirty(marker);
}
else
{
closebyUsers.Add(avatarShape.ID);
var wrap = wrapsPool.Get();
markers.Add(avatarShape.ID, wrap);
mapCullingController.StartTracking(wrap, wrap);
Expand All @@ -86,6 +110,7 @@ private void SetPlayerMarker(in CharacterTransform transformComponent, in Avatar
[All(typeof(DeleteEntityIntention))]
private void RemoveMarker(in AvatarShapeComponent avatarShape)
{
closebyUsers.Remove(avatarShape.ID);
if (markers.TryGetValue(avatarShape.ID, out var marker))
{
mapCullingController.StopTracking(marker);
Expand All @@ -94,10 +119,44 @@ private void RemoveMarker(in AvatarShapeComponent avatarShape)
}
}

public UniTask Enable(CancellationToken cancellationToken)
private async UniTask ProcessRemoteUsers(CancellationToken ct)
{
List<RemotePlayerData> remotePlayersData = await remoteUsersRequestController.RequestUsers(ct);

//Reset the markers bound to remote users by releasing them
foreach (string remoteUser in remoteUsers)
{
if(closebyUsers.Contains(remoteUser)) continue;

if (!markers.TryGetValue(remoteUser, out var marker)) continue;

mapCullingController.StopTracking(marker);
wrapsPool.Release(marker);
markers.Remove(remoteUser);
}
remoteUsers.Clear();

foreach (RemotePlayerData remotePlayerData in remotePlayersData)
{
if (closebyUsers.Contains(remotePlayerData.avatarId))
continue;

remoteUsers.Add(remotePlayerData.avatarId);

if (markers.TryGetValue(remotePlayerData.avatarId, out var marker)) continue;

var wrap = wrapsPool.Get();
markers.Add(remotePlayerData.avatarId, wrap);
wrap.UpdateMarkerPosition(remotePlayerData.avatarId, remotePlayerData.position);
mapCullingController.StartTracking(wrap, wrap);
}
}

public async UniTask Enable(CancellationToken cancellationToken)
{
isEnabled = true;
return UniTask.CompletedTask;

await ProcessRemoteUsers(cancellationToken);
}

public UniTask Disable(CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
using UnityEngine.Pool;
using Utility.Ownership;
using Utility.PriorityQueue;
using Utility.TeleportBus;
using Object = UnityEngine.Object;

namespace Global.Dynamic
Expand Down Expand Up @@ -168,6 +169,7 @@ public override void Dispose()
IWeb3IdentityCache identityCache = dynamicWorldDependencies.Web3IdentityCache;
IAssetsProvisioner assetsProvisioner = dynamicWorldDependencies.AssetsProvisioner;
IDebugContainerBuilder debugBuilder = dynamicWorldDependencies.DebugContainerBuilder;
ITeleportBusController teleportBusController = new TeleportBusController();

// If we have many undesired delays when using the third-party providers, it might be useful to cache it at app's bootstrap
// So far, the chance of using it is quite low, so it's preferable to do it lazy avoiding extra requests & memory allocations
Expand All @@ -188,7 +190,7 @@ async UniTask InitializeContainersAsync(IPluginSettingsContainer settingsContain
// Init other containers
container.DefaultTexturesContainer = await DefaultTexturesContainer.CreateAsync(settingsContainer, assetsProvisioner, ct).ThrowOnFail();
container.LODContainer = await LODContainer.CreateAsync(assetsProvisioner, bootstrapContainer.DecentralandUrlsSource, staticContainer, settingsContainer, staticContainer.RealmData, container.DefaultTexturesContainer.TextureArrayContainerFactory, debugBuilder, dynamicWorldParams.EnableLOD, ct).ThrowOnFail();
container.MapRendererContainer = await MapRendererContainer.CreateAsync(settingsContainer, staticContainer, bootstrapContainer.DecentralandUrlsSource, assetsProvisioner, placesAPIService, mapPathEventBus, notificationsBusController, ct);
container.MapRendererContainer = await MapRendererContainer.CreateAsync(settingsContainer, staticContainer, bootstrapContainer.DecentralandUrlsSource, assetsProvisioner, placesAPIService, mapPathEventBus, notificationsBusController, teleportBusController, ct);
}

try { await InitializeContainersAsync(dynamicWorldDependencies.SettingsContainer, ct); }
Expand Down Expand Up @@ -357,7 +359,8 @@ IMultiPool MultiPoolFactory() =>
staticContainer.LoadingStatus,
staticContainer.CacheCleaner,
staticContainer.SingletonSharedDependencies.MemoryBudget,
staticContainer.FeatureFlagsCache);
staticContainer.FeatureFlagsCache,
teleportBusController);

IHealthCheck livekitHealthCheck = bootstrapContainer.DebugSettings.EnableEmulateNoLivekitConnection
? new IHealthCheck.AlwaysFails("Livekit connection is in debug, always fail mode")
Expand Down
Loading
Loading