diff --git a/Explorer/Assets/DCL/Browser/DecentralandUrls/DecentralandUrl.cs b/Explorer/Assets/DCL/Browser/DecentralandUrls/DecentralandUrl.cs index 2bb6a01e52..dd381a07c9 100644 --- a/Explorer/Assets/DCL/Browser/DecentralandUrls/DecentralandUrl.cs +++ b/Explorer/Assets/DCL/Browser/DecentralandUrls/DecentralandUrl.cs @@ -30,6 +30,7 @@ public enum DecentralandUrl OpenSea, PeerAbout, + RemotePeers, DAO, diff --git a/Explorer/Assets/DCL/Browser/DecentralandUrls/DecentralandUrlsSource.cs b/Explorer/Assets/DCL/Browser/DecentralandUrls/DecentralandUrlsSource.cs index c6d3237283..f0e1444d69 100644 --- a/Explorer/Assets/DCL/Browser/DecentralandUrls/DecentralandUrlsSource.cs +++ b/Explorer/Assets/DCL/Browser/DecentralandUrls/DecentralandUrlsSource.cs @@ -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", diff --git a/Explorer/Assets/DCL/MapRenderer/ComponentsFactory/HotUsersMarkersInstaller.cs b/Explorer/Assets/DCL/MapRenderer/ComponentsFactory/HotUsersMarkersInstaller.cs index dfef3ffd86..577fb97786 100644 --- a/Explorer/Assets/DCL/MapRenderer/ComponentsFactory/HotUsersMarkersInstaller.cs +++ b/Explorer/Assets/DCL/MapRenderer/ComponentsFactory/HotUsersMarkersInstaller.cs @@ -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 { @@ -26,6 +30,8 @@ public async UniTask InstallAsync( IMapCullingController cullingController, IAssetsProvisioner assetsProv, IMapRendererSettings settings, + ITeleportBusController teleportBusController, + RemoteUsersRequestController remoteUsersRequestController, CancellationToken cancellationToken) { assetsProvisioner = assetsProv; @@ -43,8 +49,8 @@ IHotUserMarker CreateWrap() => var wrapsPool = new ObjectPool(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); } diff --git a/Explorer/Assets/DCL/MapRenderer/ComponentsFactory/MapRendererChunkComponentsFactory.cs b/Explorer/Assets/DCL/MapRenderer/ComponentsFactory/MapRendererChunkComponentsFactory.cs index 7fcad557e3..9cff87e9a5 100644 --- a/Explorer/Assets/DCL/MapRenderer/ComponentsFactory/MapRendererChunkComponentsFactory.cs +++ b/Explorer/Assets/DCL/MapRenderer/ComponentsFactory/MapRendererChunkComponentsFactory.cs @@ -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; @@ -19,6 +20,7 @@ using System.Threading.Tasks; using UnityEngine; using UnityEngine.Pool; +using Utility.TeleportBus; using Object = UnityEngine.Object; namespace DCL.MapRenderer.ComponentsFactory @@ -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; } @@ -51,6 +54,7 @@ public MapRendererChunkComponentsFactory( MapRendererTextureContainer textureContainer, IPlacesAPIService placesAPIService, IMapPathEventBus mapPathEventBus, + ITeleportBusController teleportBusController, INotificationsBusController notificationsBusController) { this.assetsProvisioner = assetsProvisioner; @@ -60,6 +64,7 @@ public MapRendererChunkComponentsFactory( this.textureContainer = textureContainer; this.placesAPIService = placesAPIService; this.mapPathEventBus = mapPathEventBus; + this.teleportBusController = teleportBusController; this.notificationsBusController = notificationsBusController; } @@ -83,6 +88,7 @@ async UniTask 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 cameraControllersPool = new ObjectPool( CameraControllerBuilder, @@ -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 */); diff --git a/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemotePlayerData.cs b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemotePlayerData.cs new file mode 100644 index 0000000000..5f27951d8c --- /dev/null +++ b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemotePlayerData.cs @@ -0,0 +1,11 @@ +using System; +using UnityEngine; + +namespace DCL.MapRenderer.MapLayers.UsersMarker +{ + [Serializable] public class RemotePlayerData + { + public Vector3 position; + public string avatarId; + } +} diff --git a/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemotePlayerData.cs.meta b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemotePlayerData.cs.meta new file mode 100644 index 0000000000..969a04a119 --- /dev/null +++ b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemotePlayerData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d94d613050864b5a8cf9128adc5de6f2 +timeCreated: 1732014718 \ No newline at end of file diff --git a/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemotePlayersJsonDtoConverter.cs b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemotePlayersJsonDtoConverter.cs new file mode 100644 index 0000000000..6b05407f14 --- /dev/null +++ b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemotePlayersJsonDtoConverter.cs @@ -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> + { + public override void WriteJson(JsonWriter writer, List? value, JsonSerializer serializer) + { + writer.WriteStartArray(); + foreach (var item in value) + serializer.Serialize(writer, item); + + writer.WriteEndArray(); + } + + public override List ReadJson(JsonReader reader, Type objectType, List existingValue, bool hasExistingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + return null; + + existingValue ??= new List(); + + var rootObject = JObject.Load(reader).ToObject(); + 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 peers { get; set; } + } + + private class DataObject + { + public string address { get; set; } + public float[] position { get; set; } + } + } +} diff --git a/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemotePlayersJsonDtoConverter.cs.meta b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemotePlayersJsonDtoConverter.cs.meta new file mode 100644 index 0000000000..dcb64cf90e --- /dev/null +++ b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemotePlayersJsonDtoConverter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d78e7a478c7247e08841e93fd0cc74a9 +timeCreated: 1732013495 \ No newline at end of file diff --git a/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemoteUsersRequestController.cs b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemoteUsersRequestController.cs new file mode 100644 index 0000000000..791fcc236e --- /dev/null +++ b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemoteUsersRequestController.cs @@ -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> RequestUsers(CancellationToken ct) => + await webRequestController.GetAsync(baseURL, ct, ReportCategory.UI) + .CreateFromNewtonsoftJsonAsync>(serializerSettings: SERIALIZER_SETTINGS); + } + +} diff --git a/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemoteUsersRequestController.cs.meta b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemoteUsersRequestController.cs.meta new file mode 100644 index 0000000000..e550f0a343 --- /dev/null +++ b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/RemoteUsersRequestController.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ab4172b504de4230bb12064c982bdc66 +timeCreated: 1732012852 \ No newline at end of file diff --git a/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/UsersMarkersHotAreaController.cs b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/UsersMarkersHotAreaController.cs index 9175ce2f3a..085e5bdba3 100644 --- a/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/UsersMarkersHotAreaController.cs +++ b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/UsersMarkersHotAreaController.cs @@ -10,7 +10,8 @@ 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; @@ -18,6 +19,8 @@ using System.Threading; using UnityEngine; using UnityEngine.Pool; +using Utility; +using Utility.TeleportBus; namespace DCL.MapRenderer.MapLayers.Users { @@ -25,10 +28,15 @@ internal partial class UsersMarkersHotAreaController : MapLayerControllerBase, I { private readonly IObjectPool objectsPool; private readonly IObjectPool wrapsPool; + private readonly ITeleportBusController teleportBusController; + private readonly RemoteUsersRequestController remoteUsersRequestController; private TrackPlayersPositionSystem trackSystem; private RemovedTrackedPlayersPositionSystem untrackSystem; private readonly Dictionary markers = new (); + private readonly HashSet remoteUsers = new (); + private readonly HashSet closebyUsers = new (); + private CancellationTokenSource cancellationToken; private bool isEnabled; public UsersMarkersHotAreaController( @@ -36,11 +44,23 @@ public UsersMarkersHotAreaController( IObjectPool 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() @@ -69,6 +89,9 @@ 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); @@ -76,6 +99,7 @@ private void SetPlayerMarker(in CharacterTransform transformComponent, in Avatar } else { + closebyUsers.Add(avatarShape.ID); var wrap = wrapsPool.Get(); markers.Add(avatarShape.ID, wrap); mapCullingController.StartTracking(wrap, wrap); @@ -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); @@ -94,10 +119,44 @@ private void RemoveMarker(in AvatarShapeComponent avatarShape) } } - public UniTask Enable(CancellationToken cancellationToken) + private async UniTask ProcessRemoteUsers(CancellationToken ct) + { + List 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) diff --git a/Explorer/Assets/Scripts/Global/Dynamic/DynamicWorldContainer.cs b/Explorer/Assets/Scripts/Global/Dynamic/DynamicWorldContainer.cs index 96cb49ea07..cfa7947977 100644 --- a/Explorer/Assets/Scripts/Global/Dynamic/DynamicWorldContainer.cs +++ b/Explorer/Assets/Scripts/Global/Dynamic/DynamicWorldContainer.cs @@ -93,6 +93,7 @@ using UnityEngine.Pool; using Utility.Ownership; using Utility.PriorityQueue; +using Utility.TeleportBus; using Object = UnityEngine.Object; namespace Global.Dynamic @@ -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 @@ -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); } @@ -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") diff --git a/Explorer/Assets/Scripts/Global/Dynamic/MapRendererContainer.cs b/Explorer/Assets/Scripts/Global/Dynamic/MapRendererContainer.cs index 9a7626d34c..83d77962b4 100644 --- a/Explorer/Assets/Scripts/Global/Dynamic/MapRendererContainer.cs +++ b/Explorer/Assets/Scripts/Global/Dynamic/MapRendererContainer.cs @@ -10,6 +10,7 @@ using System.Threading; using UnityEngine; using UnityEngine.AddressableAssets; +using Utility.TeleportBus; namespace Global.Dynamic { @@ -34,6 +35,7 @@ public static async UniTask CreateAsync( IPlacesAPIService placesAPIService, IMapPathEventBus mapPathEventBus, INotificationsBusController notificationsBusController, + ITeleportBusController teleportBusController, CancellationToken ct) { var mapRendererContainer = new MapRendererContainer(assetsProvisioner, new MapRendererTextureContainer()); @@ -48,6 +50,7 @@ await mapRendererContainer.InitializeContainerAsync TryInitializeTeleportToParcelAsync(Vector2Int parce ReportHub.LogError(ReportCategory.SCENE_LOADING, $"Error trying to teleport to a parcel {parcel}: {loadResult.ErrorMessage}"); } + teleportBusController.PushTeleportOperation(parcel); return loadResult; } diff --git a/Explorer/Assets/Scripts/Utility/TeleportBus.meta b/Explorer/Assets/Scripts/Utility/TeleportBus.meta new file mode 100644 index 0000000000..29d2eea1b4 --- /dev/null +++ b/Explorer/Assets/Scripts/Utility/TeleportBus.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7e71eeaaa320475688e9ba7b200d26d8 +timeCreated: 1732092490 \ No newline at end of file diff --git a/Explorer/Assets/Scripts/Utility/TeleportBus/ITeleportBusController.cs b/Explorer/Assets/Scripts/Utility/TeleportBus/ITeleportBusController.cs new file mode 100644 index 0000000000..954a59b603 --- /dev/null +++ b/Explorer/Assets/Scripts/Utility/TeleportBus/ITeleportBusController.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +namespace Utility.TeleportBus +{ + public interface ITeleportBusController + { + void PushTeleportOperation(Vector2Int destinationCoordinates); + void SubscribeToTeleportOperation(TeleportBusController.TeleportOperationDelegate callback); + } +} diff --git a/Explorer/Assets/Scripts/Utility/TeleportBus/ITeleportBusController.cs.meta b/Explorer/Assets/Scripts/Utility/TeleportBus/ITeleportBusController.cs.meta new file mode 100644 index 0000000000..fa5598c949 --- /dev/null +++ b/Explorer/Assets/Scripts/Utility/TeleportBus/ITeleportBusController.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dac0dc9a23564bd7a682f6bd0d3cbfbe +timeCreated: 1732092504 \ No newline at end of file diff --git a/Explorer/Assets/Scripts/Utility/TeleportBus/TeleportBusController.cs b/Explorer/Assets/Scripts/Utility/TeleportBus/TeleportBusController.cs new file mode 100644 index 0000000000..e2ed444c8d --- /dev/null +++ b/Explorer/Assets/Scripts/Utility/TeleportBus/TeleportBusController.cs @@ -0,0 +1,18 @@ +using System; +using UnityEngine; + +namespace Utility.TeleportBus +{ + public class TeleportBusController : ITeleportBusController + { + public delegate void TeleportOperationDelegate(Vector2Int destinationCoordinates); + + private TeleportOperationDelegate teleportOperationDelegate; + + public void PushTeleportOperation(Vector2Int destinationCoordinates) => + teleportOperationDelegate?.Invoke(destinationCoordinates); + + public void SubscribeToTeleportOperation(TeleportOperationDelegate callback)=> + teleportOperationDelegate += callback; + } +} diff --git a/Explorer/Assets/Scripts/Utility/TeleportBus/TeleportBusController.cs.meta b/Explorer/Assets/Scripts/Utility/TeleportBus/TeleportBusController.cs.meta new file mode 100644 index 0000000000..0283f33043 --- /dev/null +++ b/Explorer/Assets/Scripts/Utility/TeleportBus/TeleportBusController.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ce849ba05bc24996b42c073e983bdf35 +timeCreated: 1732093097 \ No newline at end of file