diff --git a/LightlessSync/LightlessSync.csproj b/LightlessSync/LightlessSync.csproj index f04696c..938d413 100644 --- a/LightlessSync/LightlessSync.csproj +++ b/LightlessSync/LightlessSync.csproj @@ -37,6 +37,7 @@ + diff --git a/LightlessSync/Plugin.cs b/LightlessSync/Plugin.cs index 058559f..09c4cd8 100644 --- a/LightlessSync/Plugin.cs +++ b/LightlessSync/Plugin.cs @@ -141,6 +141,7 @@ public sealed class Plugin : IDalamudPlugin services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(sp => new TextureMetadataHelper(sp.GetRequiredService>(), gameData)); diff --git a/LightlessSync/Services/ContextMenuService.cs b/LightlessSync/Services/ContextMenuService.cs index 3fe893c..024e17b 100644 --- a/LightlessSync/Services/ContextMenuService.cs +++ b/LightlessSync/Services/ContextMenuService.cs @@ -10,7 +10,6 @@ using LightlessSync.UI; using LightlessSync.UI.Services; using LightlessSync.Utils; using LightlessSync.WebAPI; -using Lumina.Excel.Sheets; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -172,9 +171,8 @@ internal class ContextMenuService : IHostedService _logger.LogTrace("Cannot send pair request to {TargetName}@{World} while in PvP or GPose.", target.TargetName, target.TargetHomeWorld.RowId); return; } - - var world = GetWorld(target.TargetHomeWorld.RowId); - if (!IsWorldValid(world)) + + if (!IsWorldValid(target.TargetHomeWorld.RowId)) { _logger.LogTrace("Target player {TargetName}@{World} is on an invalid world.", target.TargetName, target.TargetHomeWorld.RowId); return; @@ -226,9 +224,8 @@ internal class ContextMenuService : IHostedService { if (args.Target is not MenuTargetDefault target) return; - - var world = GetWorld(target.TargetHomeWorld.RowId); - if (!IsWorldValid(world)) + + if (!target.TargetHomeWorld.IsValid || !IsWorldValid(target.TargetHomeWorld.RowId)) return; try @@ -237,7 +234,7 @@ internal class ContextMenuService : IHostedService if (targetData == null || targetData.Address == nint.Zero) { - _logger.LogWarning("Target player {TargetName}@{World} not found in object table.", target.TargetName, world.Name); + _logger.LogWarning("Target player {TargetName}@{World} not found in object table.", target.TargetName, target.TargetHomeWorld.Value.Name); return; } @@ -252,7 +249,7 @@ internal class ContextMenuService : IHostedService } // Notify in chat when NotificationService is disabled - NotifyInChat($"Pair request sent to {target.TargetName}@{world.Name}.", NotificationType.Info); + NotifyInChat($"Pair request sent to {target.TargetName}@{target.TargetHomeWorld.Value.Name}.", NotificationType.Info); } catch (Exception ex) { @@ -312,37 +309,8 @@ internal class ContextMenuService : IHostedService p.HomeWorld.RowId == target.TargetHomeWorld.RowId); } - private World GetWorld(uint worldId) + private bool IsWorldValid(uint worldId) { - var sheet = _gameData.GetExcelSheet()!; - var luminaWorlds = sheet.Where(x => - { - var dc = x.DataCenter.ValueNullable; - var name = x.Name.ExtractText(); - var internalName = x.InternalName.ExtractText(); - - if (dc == null || dc.Value.Region == 0 || string.IsNullOrWhiteSpace(dc.Value.Name.ExtractText())) - return false; - - if (string.IsNullOrWhiteSpace(name) || string.IsNullOrWhiteSpace(internalName)) - return false; - - if (name.Contains('-', StringComparison.Ordinal) || name.Contains('_', StringComparison.Ordinal)) - return false; - - return x.DataCenter.Value.Region != 5 || x.RowId > 3001 && x.RowId != 1200 && IsChineseJapaneseKoreanString(name); - }); - - return luminaWorlds.FirstOrDefault(x => x.RowId == worldId); - } - - private static bool IsChineseJapaneseKoreanString(string text) => text.All(IsChineseJapaneseKoreanCharacter); - - private static bool IsChineseJapaneseKoreanCharacter(char c) => c >= 0x4E00 && c <= 0x9FFF; - - public static bool IsWorldValid(World world) - { - var name = world.Name.ToString(); - return !string.IsNullOrWhiteSpace(name) && char.IsUpper(name[0]); + return _dalamudUtil.WorldData.Value.ContainsKey((ushort)worldId); } } diff --git a/LightlessSync/Services/DalamudUtilService.cs b/LightlessSync/Services/DalamudUtilService.cs index 0b93997..b278667 100644 --- a/LightlessSync/Services/DalamudUtilService.cs +++ b/LightlessSync/Services/DalamudUtilService.cs @@ -1,11 +1,13 @@ using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Game.ClientState.Objects.Types; +using Dalamud.Game.Text; using Dalamud.Plugin.Services; using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Control; +using FFXIVClientStructs.FFXIV.Client.Game.UI; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.UI.Agent; using LightlessSync.API.Dto.CharaData; @@ -26,6 +28,7 @@ using System.Text; using BattleNpcSubKind = FFXIVClientStructs.FFXIV.Client.Game.Object.BattleNpcSubKind; using DalamudObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind; using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject; +using Map = Lumina.Excel.Sheets.Map; using VisibilityFlags = FFXIVClientStructs.FFXIV.Client.Game.Object.VisibilityFlags; namespace LightlessSync.Services; @@ -57,6 +60,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber private string _lastGlobalBlockReason = string.Empty; private ushort _lastZone = 0; private ushort _lastWorldId = 0; + private uint _lastMapId = 0; private bool _sentBetweenAreas = false; private Lazy _cid; @@ -86,7 +90,8 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber WorldData = new(() => { return gameData.GetExcelSheet(clientLanguage)! - .Where(w => !w.Name.IsEmpty && w.DataCenter.RowId != 0 && (w.IsPublic || char.IsUpper(w.Name.ToString()[0]))) + .Where(w => !w.Name.IsEmpty && w.DataCenter.RowId != 0 && (w.IsPublic || char.IsUpper(w.Name.ToString()[0]) + || w is { RowId: > 1000, Region: 101 or 201 })) .ToDictionary(w => (ushort)w.RowId, w => w.Name.ToString()); }); JobData = new(() => @@ -659,7 +664,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber var location = new LocationInfo(); location.ServerId = _playerState.CurrentWorld.RowId; - //location.InstanceId = UIState.Instance()->PublicInstance.InstanceId; //TODO:Need API update first + location.InstanceId = UIState.Instance()->PublicInstance.InstanceId; location.TerritoryId = _clientState.TerritoryType; location.MapId = _clientState.MapId; if (houseMan != null) @@ -685,7 +690,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber var outside = houseMan->OutdoorTerritory; var house = outside->HouseId; location.WardId = house.WardIndex + 1u; - location.HouseId = (uint)houseMan->GetCurrentPlot() + 1; + //location.HouseId = (uint)houseMan->GetCurrentPlot() + 1; location.DivisionId = houseMan->GetCurrentDivision(); } //_logger.LogWarning(LocationToString(location)); @@ -713,10 +718,10 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber str += $" - {MapData.Value[(ushort)location.MapId].MapName}"; } - // if (location.InstanceId is not 0) - // { - // str += ((SeIconChar)(57520 + location.InstanceId)).ToIconString(); - // } + if (location.InstanceId is not 0) + { + str += ((SeIconChar)(57520 + location.InstanceId)).ToIconString(); + } if (location.WardId is not 0) { @@ -1135,6 +1140,18 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber Mediator.Publish(new ZoneSwitchEndMessage()); Mediator.Publish(new ResumeScanMessage(nameof(ConditionFlag.BetweenAreas))); } + + //Map + if (!_sentBetweenAreas) + { + var mapid = _clientState.MapId; + if (mapid != _lastMapId) + { + _lastMapId = mapid; + Mediator.Publish(new MapChangedMessage(mapid)); + } + } + var localPlayer = _objectTable.LocalPlayer; if (localPlayer != null) diff --git a/LightlessSync/Services/LocationShareService.cs b/LightlessSync/Services/LocationShareService.cs new file mode 100644 index 0000000..38b2834 --- /dev/null +++ b/LightlessSync/Services/LocationShareService.cs @@ -0,0 +1,137 @@ +using LightlessSync.API.Data; +using LightlessSync.API.Dto.CharaData; +using LightlessSync.API.Dto.User; +using LightlessSync.Services.Mediator; +using LightlessSync.WebAPI; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; + +namespace LightlessSync.Services +{ + public class LocationShareService : DisposableMediatorSubscriberBase + { + private readonly DalamudUtilService _dalamudUtilService; + private readonly ApiController _apiController; + private IMemoryCache _locations = new MemoryCache(new MemoryCacheOptions()); + private IMemoryCache _sharingStatus = new MemoryCache(new MemoryCacheOptions()); + private CancellationTokenSource _resetToken = new CancellationTokenSource(); + + public LocationShareService(ILogger logger, LightlessMediator mediator, DalamudUtilService dalamudUtilService, ApiController apiController) : base(logger, mediator) + { + _dalamudUtilService = dalamudUtilService; + _apiController = apiController; + + + Mediator.Subscribe(this, (msg) => + { + _resetToken.Cancel(); + _resetToken.Dispose(); + _resetToken = new CancellationTokenSource(); + }); + Mediator.Subscribe(this, (msg) => + { + _ = _apiController.UpdateLocation(new LocationDto(new UserData(_apiController.UID, apiController.DisplayName), _dalamudUtilService.GetMapData())); + _ = RequestAllLocation(); + } ); + Mediator.Subscribe(this, UpdateLocationList); + Mediator.Subscribe(this, + msg => _ = _apiController.UpdateLocation(new LocationDto(new UserData(_apiController.UID, _apiController.DisplayName), _dalamudUtilService.GetMapData()))); + } + + private void UpdateLocationList(LocationSharingMessage msg) + { + if (_locations.TryGetValue(msg.User.UID, out _) && msg.LocationInfo.ServerId is 0) + { + _locations.Remove(msg.User.UID); + return; + } + + if ( msg.LocationInfo.ServerId is not 0 && msg.ExpireAt > DateTime.UtcNow) + { + AddLocationInfo(msg.User.UID, msg.LocationInfo, msg.ExpireAt); + } + } + + private void AddLocationInfo(string uid, LocationInfo location, DateTimeOffset expireAt) + { + var options = new MemoryCacheEntryOptions() + .SetAbsoluteExpiration(expireAt) + .AddExpirationToken(new CancellationChangeToken(_resetToken.Token)); + _locations.Set(uid, location, options); + } + + private async Task RequestAllLocation() + { + try + { + var (data, status) = await _apiController.RequestAllLocationInfo().ConfigureAwait(false); + foreach (var dto in data) + { + AddLocationInfo(dto.LocationDto.User.UID, dto.LocationDto.Location, dto.ExpireAt); + } + + foreach (var dto in status) + { + AddStatus(dto.User.UID, dto.ExpireAt); + } + } + catch (Exception e) + { + Logger.LogError(e,"RequestAllLocation error : "); + throw; + } + } + + private void AddStatus(string uid, DateTimeOffset expireAt) + { + var options = new MemoryCacheEntryOptions() + .SetAbsoluteExpiration(expireAt) + .AddExpirationToken(new CancellationChangeToken(_resetToken.Token)); + _sharingStatus.Set(uid, expireAt, options); + } + + public string GetUserLocation(string uid) + { + try + { + if (_locations.TryGetValue(uid, out var location)) + { + return _dalamudUtilService.LocationToString(location); + } + return String.Empty; + } + catch (Exception e) + { + Logger.LogError(e,"GetUserLocation error : "); + throw; + } + } + + public DateTimeOffset GetSharingStatus(string uid) + { + try + { + if (_sharingStatus.TryGetValue(uid, out var expireAt)) + { + return expireAt; + } + return DateTimeOffset.MinValue; + } + catch (Exception e) + { + Logger.LogError(e,"GetSharingStatus error : "); + throw; + } + } + + public void UpdateSharingStatus(List users, DateTimeOffset expireAt) + { + foreach (var user in users) + { + AddStatus(user, expireAt); + } + } + + } +} \ No newline at end of file diff --git a/LightlessSync/Services/Mediator/Messages.cs b/LightlessSync/Services/Mediator/Messages.cs index 7767d74..08e47da 100644 --- a/LightlessSync/Services/Mediator/Messages.cs +++ b/LightlessSync/Services/Mediator/Messages.cs @@ -136,5 +136,7 @@ public record ChatChannelsUpdated : MessageBase; public record ChatChannelMessageAdded(string ChannelKey, ChatMessageEntry Message) : MessageBase; public record GroupCollectionChangedMessage : MessageBase; public record OpenUserProfileMessage(UserData User) : MessageBase; +public record LocationSharingMessage(UserData User, LocationInfo LocationInfo, DateTimeOffset ExpireAt) : MessageBase; +public record MapChangedMessage(uint MapId) : MessageBase; #pragma warning restore S2094 #pragma warning restore MA0048 // File name must match type name \ No newline at end of file diff --git a/LightlessSync/UI/Components/DrawUserPair.cs b/LightlessSync/UI/Components/DrawUserPair.cs index a5fa953..c8725e2 100644 --- a/LightlessSync/UI/Components/DrawUserPair.cs +++ b/LightlessSync/UI/Components/DrawUserPair.cs @@ -37,6 +37,7 @@ public class DrawUserPair private readonly UiSharedService _uiSharedService; private readonly PlayerPerformanceConfigService _performanceConfigService; private readonly LightlessConfigService _configService; + private readonly LocationShareService _locationShareService; private readonly CharaDataManager _charaDataManager; private readonly PairLedger _pairLedger; private float _menuWidth = -1; @@ -57,6 +58,7 @@ public class DrawUserPair UiSharedService uiSharedService, PlayerPerformanceConfigService performanceConfigService, LightlessConfigService configService, + LocationShareService locationShareService, CharaDataManager charaDataManager, PairLedger pairLedger) { @@ -74,6 +76,7 @@ public class DrawUserPair _uiSharedService = uiSharedService; _performanceConfigService = performanceConfigService; _configService = configService; + _locationShareService = locationShareService; _charaDataManager = charaDataManager; _pairLedger = pairLedger; } @@ -216,6 +219,48 @@ public class DrawUserPair _ = _apiController.UserSetPairPermissions(new UserPermissionsDto(_pair.UserData, permissions)); } UiSharedService.AttachToolTip("Changes VFX sync permissions with this user." + (individual ? individualText : string.Empty)); + + ImGui.SetCursorPosX(10f); + _uiSharedService.IconText(FontAwesomeIcon.Globe); + ImGui.SameLine(); + if (ImGui.BeginMenu("Toggle Location sharing")) + { + if (ImGui.MenuItem("Share for 30 Mins")) + { + _ = ToggleLocationSharing([_pair.UserData.UID], DateTimeOffset.UtcNow.AddMinutes(30)); + } + + if (ImGui.MenuItem("Share for 1 Hour")) + { + _ = ToggleLocationSharing([_pair.UserData.UID], DateTimeOffset.UtcNow.AddHours(1)); + } + + if (ImGui.MenuItem("Share for 3 Hours")) + { + _ = ToggleLocationSharing([_pair.UserData.UID], DateTimeOffset.UtcNow.AddHours(3)); + } + + if (ImGui.MenuItem("Share until manually stop")) + { + _ = ToggleLocationSharing([_pair.UserData.UID], DateTimeOffset.MaxValue); + } + + ImGui.Separator(); + if (ImGui.MenuItem("Stop Sharing")) + { + _ = ToggleLocationSharing([_pair.UserData.UID], DateTimeOffset.MinValue); + } + ImGui.EndMenu(); + } + } + + private async Task ToggleLocationSharing(List users, DateTimeOffset expireAt) + { + var updated = await _apiController.ToggleLocationSharing(new LocationSharingToggleDto(users, expireAt)).ConfigureAwait(false); + if (updated) + { + _locationShareService.UpdateSharingStatus(users, expireAt); + } } private void DrawIndividualMenu() @@ -574,6 +619,71 @@ public class DrawUserPair var individualVFXDisabled = (_pair.UserPair?.OwnPermissions.IsDisableVFX() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableVFX() ?? false); var individualIsSticky = _pair.UserPair!.OwnPermissions.IsSticky(); var individualIcon = individualIsSticky ? FontAwesomeIcon.ArrowCircleUp : FontAwesomeIcon.InfoCircle; + + var shareLocationIcon = FontAwesomeIcon.Globe; + var location = _locationShareService.GetUserLocation(_pair.UserPair!.User.UID); + var shareLocation = !string.IsNullOrEmpty(location); + var expireAt = _locationShareService.GetSharingStatus(_pair.UserPair!.User.UID); + var shareLocationToOther = expireAt > DateTimeOffset.UtcNow; + var shareColor = shareLocation switch + { + true when shareLocationToOther => UIColors.Get("LightlessGreen"), + true when !shareLocationToOther => UIColors.Get("LightlessBlue"), + _ => UIColors.Get("LightlessYellow"), + }; + + if (shareLocation || shareLocationToOther) + { + currentRightSide -= (_uiSharedService.GetIconSize(shareLocationIcon).X + spacingX); + ImGui.SameLine(currentRightSide); + using (ImRaii.PushColor(ImGuiCol.Text, shareColor, shareLocation || shareLocationToOther)) + _uiSharedService.IconText(shareLocationIcon); + + if (ImGui.IsItemHovered()) + { + ImGui.BeginTooltip(); + + if (_pair.IsOnline) + { + if (shareLocation) + { + if (!string.IsNullOrEmpty(location)) + { + _uiSharedService.IconText(FontAwesomeIcon.LocationArrow); + ImGui.SameLine(); + ImGui.TextUnformatted(location); + } + else + { + ImGui.TextUnformatted("Location info not updated, reconnect or wait for update."); + } + } + else + { + ImGui.TextUnformatted("NOT Sharing location with you. o(TヘTo)"); + } + } + else + { + ImGui.TextUnformatted("User not online. (´・ω・`)?"); + } + ImGui.Separator(); + + if (shareLocationToOther) + { + ImGui.TextUnformatted("Sharing your location. ヾ(•ω•`)o"); + if (expireAt != DateTimeOffset.MaxValue) + { + ImGui.TextUnformatted("Expires at " + expireAt.ToLocalTime().ToString("g")); + } + } + else + { + ImGui.TextUnformatted("NOT sharing your location.  ̄へ ̄"); + } + ImGui.EndTooltip(); + } + } if (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled || individualIsSticky) { diff --git a/LightlessSync/UI/DataAnalysisUi.cs b/LightlessSync/UI/DataAnalysisUi.cs index 32245d2..a3061a7 100644 --- a/LightlessSync/UI/DataAnalysisUi.cs +++ b/LightlessSync/UI/DataAnalysisUi.cs @@ -2183,7 +2183,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase bool toggleClicked = false; if (showToggle) { - var icon = isCollapsed ? FontAwesomeIcon.ChevronRight : FontAwesomeIcon.ChevronLeft; + var icon = !isCollapsed ? FontAwesomeIcon.ChevronRight : FontAwesomeIcon.ChevronLeft; Vector2 iconSize; using (_uiSharedService.IconFont.Push()) { diff --git a/LightlessSync/UI/DrawEntityFactory.cs b/LightlessSync/UI/DrawEntityFactory.cs index 3c71f5c..e7bcc87 100644 --- a/LightlessSync/UI/DrawEntityFactory.cs +++ b/LightlessSync/UI/DrawEntityFactory.cs @@ -29,6 +29,7 @@ public class DrawEntityFactory private readonly LightlessConfigService _configService; private readonly UiSharedService _uiSharedService; private readonly PlayerPerformanceConfigService _playerPerformanceConfigService; + private readonly LocationShareService _locationShareService; private readonly CharaDataManager _charaDataManager; private readonly SelectTagForPairUi _selectTagForPairUi; private readonly RenamePairTagUi _renamePairTagUi; @@ -53,6 +54,7 @@ public class DrawEntityFactory LightlessConfigService configService, UiSharedService uiSharedService, PlayerPerformanceConfigService playerPerformanceConfigService, + LocationShareService locationShareService, CharaDataManager charaDataManager, SelectTagForSyncshellUi selectTagForSyncshellUi, RenameSyncshellTagUi renameSyncshellTagUi, @@ -72,6 +74,7 @@ public class DrawEntityFactory _configService = configService; _uiSharedService = uiSharedService; _playerPerformanceConfigService = playerPerformanceConfigService; + _locationShareService = locationShareService; _charaDataManager = charaDataManager; _selectTagForSyncshellUi = selectTagForSyncshellUi; _renameSyncshellTagUi = renameSyncshellTagUi; @@ -162,6 +165,7 @@ public class DrawEntityFactory _uiSharedService, _playerPerformanceConfigService, _configService, + _locationShareService, _charaDataManager, _pairLedger); } diff --git a/LightlessSync/WebAPI/SignalR/ApIController.Functions.Users.cs b/LightlessSync/WebAPI/SignalR/ApIController.Functions.Users.cs index fdc4719..37b91f9 100644 --- a/LightlessSync/WebAPI/SignalR/ApIController.Functions.Users.cs +++ b/LightlessSync/WebAPI/SignalR/ApIController.Functions.Users.cs @@ -200,5 +200,21 @@ public partial class ApiController await UserPushData(new(visibleCharacters, character, censusDto)).ConfigureAwait(false); } + + public async Task UpdateLocation(LocationDto locationDto, bool offline = false) + { + if (!IsConnected) return; + await _lightlessHub!.SendAsync(nameof(UpdateLocation), locationDto, offline).ConfigureAwait(false); + } + public async Task<(List, List)> RequestAllLocationInfo() + { + if (!IsConnected) return ([],[]); + return await _lightlessHub!.InvokeAsync<(List, List)>(nameof(RequestAllLocationInfo)).ConfigureAwait(false); + } + public async Task ToggleLocationSharing(LocationSharingToggleDto dto) + { + if (!IsConnected) return false; + return await _lightlessHub!.InvokeAsync(nameof(ToggleLocationSharing), dto).ConfigureAwait(false); + } } #pragma warning restore MA0040 \ No newline at end of file diff --git a/LightlessSync/WebAPI/SignalR/ApiController.Functions.Callbacks.cs b/LightlessSync/WebAPI/SignalR/ApiController.Functions.Callbacks.cs index 490800f..d0a05f7 100644 --- a/LightlessSync/WebAPI/SignalR/ApiController.Functions.Callbacks.cs +++ b/LightlessSync/WebAPI/SignalR/ApiController.Functions.Callbacks.cs @@ -259,6 +259,13 @@ public partial class ApiController ExecuteSafely(() => Mediator.Publish(new GPoseLobbyReceiveWorldData(userData, worldData))); return Task.CompletedTask; } + + public Task Client_SendLocationToClient(LocationDto locationDto, DateTimeOffset expireAt) + { + Logger.LogDebug($"{nameof(Client_SendLocationToClient)}: {locationDto.User} {expireAt}"); + ExecuteSafely(() => Mediator.Publish(new LocationSharingMessage(locationDto.User, locationDto.Location, expireAt))); + return Task.CompletedTask; + } public void OnDownloadReady(Action act) { @@ -441,6 +448,12 @@ public partial class ApiController _lightlessHub!.On(nameof(Client_GposeLobbyPushWorldData), act); } + public void OnReceiveLocation(Action act) + { + if (_initialized) return; + _lightlessHub!.On(nameof(Client_SendLocationToClient), act); + } + private void ExecuteSafely(Action act) { try diff --git a/LightlessSync/WebAPI/SignalR/ApiController.cs b/LightlessSync/WebAPI/SignalR/ApiController.cs index 9639f6f..45705bf 100644 --- a/LightlessSync/WebAPI/SignalR/ApiController.cs +++ b/LightlessSync/WebAPI/SignalR/ApiController.cs @@ -606,6 +606,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL OnGposeLobbyPushCharacterData((dto) => _ = Client_GposeLobbyPushCharacterData(dto)); OnGposeLobbyPushPoseData((dto, data) => _ = Client_GposeLobbyPushPoseData(dto, data)); OnGposeLobbyPushWorldData((dto, data) => _ = Client_GposeLobbyPushWorldData(dto, data)); + OnReceiveLocation((dto, time) => _ = Client_SendLocationToClient(dto, time)); _healthCheckTokenSource?.Cancel(); _healthCheckTokenSource?.Dispose(); @@ -774,5 +775,6 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL ServerState = state; } + } #pragma warning restore MA0040