Compare commits
6 Commits
master
...
lifestream
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de9c9955ef | ||
|
|
df33a0f0a2 | ||
| c439d1c822 | |||
| 7e61954541 | |||
|
|
fb58d8657d | ||
| bbb3375661 |
Submodule LightlessAPI updated: 56566003e0...4ecd5375e6
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Lifestream.Enums;
|
||||||
|
|
||||||
|
public enum ResidentialAetheryteKind
|
||||||
|
{
|
||||||
|
None = -1,
|
||||||
|
Uldah = 9,
|
||||||
|
Gridania = 2,
|
||||||
|
Limsa = 8,
|
||||||
|
Foundation = 70,
|
||||||
|
Kugane = 111,
|
||||||
|
}
|
||||||
1
LightlessSync/Interop/InteropModel/GlobalModels.cs
Normal file
1
LightlessSync/Interop/InteropModel/GlobalModels.cs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
global using AddressBookEntryTuple = (string Name, int World, int City, int Ward, int PropertyType, int Plot, int Apartment, bool ApartmentSubdivision, bool AliasEnabled, string Alias);
|
||||||
129
LightlessSync/Interop/Ipc/IpcCallerLifestream.cs
Normal file
129
LightlessSync/Interop/Ipc/IpcCallerLifestream.cs
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
using Dalamud.Plugin;
|
||||||
|
using Dalamud.Plugin.Ipc;
|
||||||
|
using Lifestream.Enums;
|
||||||
|
using LightlessSync.Interop.Ipc.Framework;
|
||||||
|
using LightlessSync.Services.Mediator;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
|
||||||
|
namespace LightlessSync.Interop.Ipc;
|
||||||
|
|
||||||
|
public sealed class IpcCallerLifestream : IpcServiceBase
|
||||||
|
{
|
||||||
|
private static readonly IpcServiceDescriptor LifestreamDescriptor = new("Lifestream", "Lifestream", new Version(0, 0, 0, 0));
|
||||||
|
|
||||||
|
private readonly ICallGateSubscriber<string, object> _executeLifestreamCommand;
|
||||||
|
private readonly ICallGateSubscriber<AddressBookEntryTuple, bool> _isHere;
|
||||||
|
private readonly ICallGateSubscriber<AddressBookEntryTuple, object> _goToHousingAddress;
|
||||||
|
private readonly ICallGateSubscriber<bool> _isBusy;
|
||||||
|
private readonly ICallGateSubscriber<object> _abort;
|
||||||
|
private readonly ICallGateSubscriber<string, bool> _changeWorld;
|
||||||
|
private readonly ICallGateSubscriber<uint, bool> _changeWorldById;
|
||||||
|
private readonly ICallGateSubscriber<string, bool> _aetheryteTeleport;
|
||||||
|
private readonly ICallGateSubscriber<uint, bool> _aetheryteTeleportById;
|
||||||
|
private readonly ICallGateSubscriber<bool> _canChangeInstance;
|
||||||
|
private readonly ICallGateSubscriber<int> _getCurrentInstance;
|
||||||
|
private readonly ICallGateSubscriber<int> _getNumberOfInstances;
|
||||||
|
private readonly ICallGateSubscriber<int, object> _changeInstance;
|
||||||
|
private readonly ICallGateSubscriber<(ResidentialAetheryteKind, int, int)> _getCurrentPlotInfo;
|
||||||
|
|
||||||
|
public IpcCallerLifestream(IDalamudPluginInterface pi, LightlessMediator lightlessMediator, ILogger<IpcCallerLifestream> logger)
|
||||||
|
: base(logger, lightlessMediator, pi, LifestreamDescriptor)
|
||||||
|
{
|
||||||
|
_executeLifestreamCommand = pi.GetIpcSubscriber<string, object>("Lifestream.ExecuteCommand");
|
||||||
|
_isHere = pi.GetIpcSubscriber<AddressBookEntryTuple, bool>("Lifestream.IsHere");
|
||||||
|
_goToHousingAddress = pi.GetIpcSubscriber<AddressBookEntryTuple, object>("Lifestream.GoToHousingAddress");
|
||||||
|
_isBusy = pi.GetIpcSubscriber<bool>("Lifestream.IsBusy");
|
||||||
|
_abort = pi.GetIpcSubscriber<object>("Lifestream.Abort");
|
||||||
|
_changeWorld = pi.GetIpcSubscriber<string, bool>("Lifestream.ChangeWorld");
|
||||||
|
_changeWorldById = pi.GetIpcSubscriber<uint, bool>("Lifestream.ChangeWorldById");
|
||||||
|
_aetheryteTeleport = pi.GetIpcSubscriber<string, bool>("Lifestream.AetheryteTeleport");
|
||||||
|
_aetheryteTeleportById = pi.GetIpcSubscriber<uint, bool>("Lifestream.AetheryteTeleportById");
|
||||||
|
_canChangeInstance = pi.GetIpcSubscriber<bool>("Lifestream.CanChangeInstance");
|
||||||
|
_getCurrentInstance = pi.GetIpcSubscriber<int>("Lifestream.GetCurrentInstance");
|
||||||
|
_getNumberOfInstances = pi.GetIpcSubscriber<int>("Lifestream.GetNumberOfInstances");
|
||||||
|
_changeInstance = pi.GetIpcSubscriber<int, object>("Lifestream.ChangeInstance");
|
||||||
|
_getCurrentPlotInfo = pi.GetIpcSubscriber<(ResidentialAetheryteKind, int, int)>("Lifestream.GetCurrentPlotInfo");
|
||||||
|
CheckAPI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ExecuteLifestreamCommand(string command)
|
||||||
|
{
|
||||||
|
if (!APIAvailable) return;
|
||||||
|
_executeLifestreamCommand.InvokeAction(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsHere(AddressBookEntryTuple entry)
|
||||||
|
{
|
||||||
|
if (!APIAvailable) return false;
|
||||||
|
return _isHere.InvokeFunc(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GoToHousingAddress(AddressBookEntryTuple entry)
|
||||||
|
{
|
||||||
|
if (!APIAvailable) return;
|
||||||
|
_goToHousingAddress.InvokeAction(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsBusy()
|
||||||
|
{
|
||||||
|
if (!APIAvailable) return false;
|
||||||
|
return _isBusy.InvokeFunc();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Abort()
|
||||||
|
{
|
||||||
|
if (!APIAvailable) return;
|
||||||
|
_abort.InvokeAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ChangeWorld(string worldName)
|
||||||
|
{
|
||||||
|
if (!APIAvailable) return false;
|
||||||
|
return _changeWorld.InvokeFunc(worldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AetheryteTeleport(string aetheryteName)
|
||||||
|
{
|
||||||
|
if (!APIAvailable) return false;
|
||||||
|
return _aetheryteTeleport.InvokeFunc(aetheryteName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ChangeWorldById(uint worldId)
|
||||||
|
{
|
||||||
|
if (!APIAvailable) return false;
|
||||||
|
return _changeWorldById.InvokeFunc(worldId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AetheryteTeleportById(uint aetheryteId)
|
||||||
|
{
|
||||||
|
if (!APIAvailable) return false;
|
||||||
|
return _aetheryteTeleportById.InvokeFunc(aetheryteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanChangeInstance()
|
||||||
|
{
|
||||||
|
if (!APIAvailable) return false;
|
||||||
|
return _canChangeInstance.InvokeFunc();
|
||||||
|
}
|
||||||
|
public int GetCurrentInstance()
|
||||||
|
{
|
||||||
|
if (!APIAvailable) return -1;
|
||||||
|
return _getCurrentInstance.InvokeFunc();
|
||||||
|
}
|
||||||
|
public int GetNumberOfInstances()
|
||||||
|
{
|
||||||
|
if (!APIAvailable) return -1;
|
||||||
|
return _getNumberOfInstances.InvokeFunc();
|
||||||
|
}
|
||||||
|
public void ChangeInstance(int instanceNumber)
|
||||||
|
{
|
||||||
|
if (!APIAvailable) return;
|
||||||
|
_changeInstance.InvokeAction(instanceNumber);
|
||||||
|
}
|
||||||
|
public (ResidentialAetheryteKind, int, int)? GetCurrentPlotInfo()
|
||||||
|
{
|
||||||
|
if (!APIAvailable) return (ResidentialAetheryteKind.None, -1, -1);
|
||||||
|
return _getCurrentPlotInfo.InvokeFunc();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,8 @@ public sealed partial class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
public IpcManager(ILogger<IpcManager> logger, LightlessMediator mediator,
|
public IpcManager(ILogger<IpcManager> logger, LightlessMediator mediator,
|
||||||
IpcCallerPenumbra penumbraIpc, IpcCallerGlamourer glamourerIpc, IpcCallerCustomize customizeIpc, IpcCallerHeels heelsIpc,
|
IpcCallerPenumbra penumbraIpc, IpcCallerGlamourer glamourerIpc, IpcCallerCustomize customizeIpc, IpcCallerHeels heelsIpc,
|
||||||
IpcCallerHonorific honorificIpc, IpcCallerMoodles moodlesIpc, IpcCallerPetNames ipcCallerPetNames, IpcCallerBrio ipcCallerBrio) : base(logger, mediator)
|
IpcCallerHonorific honorificIpc, IpcCallerMoodles moodlesIpc, IpcCallerPetNames ipcCallerPetNames, IpcCallerBrio ipcCallerBrio,
|
||||||
|
IpcCallerLifestream ipcCallerLifestream) : base(logger, mediator)
|
||||||
{
|
{
|
||||||
CustomizePlus = customizeIpc;
|
CustomizePlus = customizeIpc;
|
||||||
Heels = heelsIpc;
|
Heels = heelsIpc;
|
||||||
@@ -17,6 +18,7 @@ public sealed partial class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
Moodles = moodlesIpc;
|
Moodles = moodlesIpc;
|
||||||
PetNames = ipcCallerPetNames;
|
PetNames = ipcCallerPetNames;
|
||||||
Brio = ipcCallerBrio;
|
Brio = ipcCallerBrio;
|
||||||
|
Lifestream = ipcCallerLifestream;
|
||||||
|
|
||||||
if (Initialized)
|
if (Initialized)
|
||||||
{
|
{
|
||||||
@@ -44,8 +46,8 @@ public sealed partial class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
public IpcCallerPenumbra Penumbra { get; }
|
public IpcCallerPenumbra Penumbra { get; }
|
||||||
public IpcCallerMoodles Moodles { get; }
|
public IpcCallerMoodles Moodles { get; }
|
||||||
public IpcCallerPetNames PetNames { get; }
|
public IpcCallerPetNames PetNames { get; }
|
||||||
|
|
||||||
public IpcCallerBrio Brio { get; }
|
public IpcCallerBrio Brio { get; }
|
||||||
|
public IpcCallerLifestream Lifestream { get; }
|
||||||
|
|
||||||
private void PeriodicApiStateCheck()
|
private void PeriodicApiStateCheck()
|
||||||
{
|
{
|
||||||
@@ -58,5 +60,6 @@ public sealed partial class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
Moodles.CheckAPI();
|
Moodles.CheckAPI();
|
||||||
PetNames.CheckAPI();
|
PetNames.CheckAPI();
|
||||||
Brio.CheckAPI();
|
Brio.CheckAPI();
|
||||||
|
Lifestream.CheckAPI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors></Authors>
|
<Authors></Authors>
|
||||||
<Company></Company>
|
<Company></Company>
|
||||||
<Version>2.0.2</Version>
|
<Version>2.0.3</Version>
|
||||||
<Description></Description>
|
<Description></Description>
|
||||||
<Copyright></Copyright>
|
<Copyright></Copyright>
|
||||||
<PackageProjectUrl>https://github.com/Light-Public-Syncshells/LightlessClient</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/Light-Public-Syncshells/LightlessClient</PackageProjectUrl>
|
||||||
@@ -37,6 +37,7 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="10.0.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="10.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="10.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.1" />
|
||||||
<PackageReference Include="Glamourer.Api" Version="2.8.0" />
|
<PackageReference Include="Glamourer.Api" Version="2.8.0" />
|
||||||
<PackageReference Include="NReco.Logging.File" Version="1.3.1" />
|
<PackageReference Include="NReco.Logging.File" Version="1.3.1" />
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
services.AddSingleton<IdDisplayHandler>();
|
services.AddSingleton<IdDisplayHandler>();
|
||||||
services.AddSingleton<PlayerPerformanceService>();
|
services.AddSingleton<PlayerPerformanceService>();
|
||||||
services.AddSingleton<PenumbraTempCollectionJanitor>();
|
services.AddSingleton<PenumbraTempCollectionJanitor>();
|
||||||
|
services.AddSingleton<LocationShareService>();
|
||||||
|
|
||||||
services.AddSingleton<TextureMetadataHelper>(sp =>
|
services.AddSingleton<TextureMetadataHelper>(sp =>
|
||||||
new TextureMetadataHelper(sp.GetRequiredService<ILogger<TextureMetadataHelper>>(), gameData));
|
new TextureMetadataHelper(sp.GetRequiredService<ILogger<TextureMetadataHelper>>(), gameData));
|
||||||
@@ -372,6 +373,11 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
sp.GetRequiredService<DalamudUtilService>(),
|
sp.GetRequiredService<DalamudUtilService>(),
|
||||||
sp.GetRequiredService<LightlessMediator>()));
|
sp.GetRequiredService<LightlessMediator>()));
|
||||||
|
|
||||||
|
services.AddSingleton(sp => new IpcCallerLifestream(
|
||||||
|
pluginInterface,
|
||||||
|
sp.GetRequiredService<LightlessMediator>(),
|
||||||
|
sp.GetRequiredService<ILogger<IpcCallerLifestream>>()));
|
||||||
|
|
||||||
services.AddSingleton(sp => new IpcManager(
|
services.AddSingleton(sp => new IpcManager(
|
||||||
sp.GetRequiredService<ILogger<IpcManager>>(),
|
sp.GetRequiredService<ILogger<IpcManager>>(),
|
||||||
sp.GetRequiredService<LightlessMediator>(),
|
sp.GetRequiredService<LightlessMediator>(),
|
||||||
@@ -382,7 +388,9 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
sp.GetRequiredService<IpcCallerHonorific>(),
|
sp.GetRequiredService<IpcCallerHonorific>(),
|
||||||
sp.GetRequiredService<IpcCallerMoodles>(),
|
sp.GetRequiredService<IpcCallerMoodles>(),
|
||||||
sp.GetRequiredService<IpcCallerPetNames>(),
|
sp.GetRequiredService<IpcCallerPetNames>(),
|
||||||
sp.GetRequiredService<IpcCallerBrio>()));
|
sp.GetRequiredService<IpcCallerBrio>(),
|
||||||
|
sp.GetRequiredService<IpcCallerLifestream>()
|
||||||
|
));
|
||||||
|
|
||||||
// Notifications / HTTP
|
// Notifications / HTTP
|
||||||
services.AddSingleton(sp => new NotificationService(
|
services.AddSingleton(sp => new NotificationService(
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ using LightlessSync.UI;
|
|||||||
using LightlessSync.UI.Services;
|
using LightlessSync.UI.Services;
|
||||||
using LightlessSync.Utils;
|
using LightlessSync.Utils;
|
||||||
using LightlessSync.WebAPI;
|
using LightlessSync.WebAPI;
|
||||||
using Lumina.Excel.Sheets;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
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);
|
_logger.LogTrace("Cannot send pair request to {TargetName}@{World} while in PvP or GPose.", target.TargetName, target.TargetHomeWorld.RowId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var world = GetWorld(target.TargetHomeWorld.RowId);
|
if (!IsWorldValid(target.TargetHomeWorld.RowId))
|
||||||
if (!IsWorldValid(world))
|
|
||||||
{
|
{
|
||||||
_logger.LogTrace("Target player {TargetName}@{World} is on an invalid world.", target.TargetName, target.TargetHomeWorld.RowId);
|
_logger.LogTrace("Target player {TargetName}@{World} is on an invalid world.", target.TargetName, target.TargetHomeWorld.RowId);
|
||||||
return;
|
return;
|
||||||
@@ -226,9 +224,8 @@ internal class ContextMenuService : IHostedService
|
|||||||
{
|
{
|
||||||
if (args.Target is not MenuTargetDefault target)
|
if (args.Target is not MenuTargetDefault target)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var world = GetWorld(target.TargetHomeWorld.RowId);
|
if (!target.TargetHomeWorld.IsValid || !IsWorldValid(target.TargetHomeWorld.RowId))
|
||||||
if (!IsWorldValid(world))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -237,7 +234,7 @@ internal class ContextMenuService : IHostedService
|
|||||||
|
|
||||||
if (targetData == null || targetData.Address == nint.Zero)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,7 +249,7 @@ internal class ContextMenuService : IHostedService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Notify in chat when NotificationService is disabled
|
// 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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -312,37 +309,8 @@ internal class ContextMenuService : IHostedService
|
|||||||
p.HomeWorld.RowId == target.TargetHomeWorld.RowId);
|
p.HomeWorld.RowId == target.TargetHomeWorld.RowId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private World GetWorld(uint worldId)
|
private bool IsWorldValid(uint worldId)
|
||||||
{
|
{
|
||||||
var sheet = _gameData.GetExcelSheet<World>()!;
|
return _dalamudUtil.WorldData.Value.ContainsKey((ushort)worldId);
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
using Dalamud.Game.ClientState.Conditions;
|
using Dalamud.Game.ClientState.Conditions;
|
||||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
|
using Dalamud.Game.Text;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Control;
|
using FFXIVClientStructs.FFXIV.Client.Game.Control;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
using LightlessSync.API.Dto.CharaData;
|
using LightlessSync.API.Dto.CharaData;
|
||||||
@@ -26,6 +28,7 @@ using System.Text;
|
|||||||
using BattleNpcSubKind = FFXIVClientStructs.FFXIV.Client.Game.Object.BattleNpcSubKind;
|
using BattleNpcSubKind = FFXIVClientStructs.FFXIV.Client.Game.Object.BattleNpcSubKind;
|
||||||
using DalamudObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind;
|
using DalamudObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind;
|
||||||
using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
|
using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
|
||||||
|
using Map = Lumina.Excel.Sheets.Map;
|
||||||
using VisibilityFlags = FFXIVClientStructs.FFXIV.Client.Game.Object.VisibilityFlags;
|
using VisibilityFlags = FFXIVClientStructs.FFXIV.Client.Game.Object.VisibilityFlags;
|
||||||
|
|
||||||
namespace LightlessSync.Services;
|
namespace LightlessSync.Services;
|
||||||
@@ -57,6 +60,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
|
|||||||
private string _lastGlobalBlockReason = string.Empty;
|
private string _lastGlobalBlockReason = string.Empty;
|
||||||
private ushort _lastZone = 0;
|
private ushort _lastZone = 0;
|
||||||
private ushort _lastWorldId = 0;
|
private ushort _lastWorldId = 0;
|
||||||
|
private uint _lastMapId = 0;
|
||||||
private bool _sentBetweenAreas = false;
|
private bool _sentBetweenAreas = false;
|
||||||
private Lazy<ulong> _cid;
|
private Lazy<ulong> _cid;
|
||||||
|
|
||||||
@@ -86,7 +90,8 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
|
|||||||
WorldData = new(() =>
|
WorldData = new(() =>
|
||||||
{
|
{
|
||||||
return gameData.GetExcelSheet<Lumina.Excel.Sheets.World>(clientLanguage)!
|
return gameData.GetExcelSheet<Lumina.Excel.Sheets.World>(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());
|
.ToDictionary(w => (ushort)w.RowId, w => w.Name.ToString());
|
||||||
});
|
});
|
||||||
JobData = new(() =>
|
JobData = new(() =>
|
||||||
@@ -659,7 +664,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
|
|||||||
|
|
||||||
var location = new LocationInfo();
|
var location = new LocationInfo();
|
||||||
location.ServerId = _playerState.CurrentWorld.RowId;
|
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.TerritoryId = _clientState.TerritoryType;
|
||||||
location.MapId = _clientState.MapId;
|
location.MapId = _clientState.MapId;
|
||||||
if (houseMan != null)
|
if (houseMan != null)
|
||||||
@@ -685,7 +690,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
|
|||||||
var outside = houseMan->OutdoorTerritory;
|
var outside = houseMan->OutdoorTerritory;
|
||||||
var house = outside->HouseId;
|
var house = outside->HouseId;
|
||||||
location.WardId = house.WardIndex + 1u;
|
location.WardId = house.WardIndex + 1u;
|
||||||
location.HouseId = (uint)houseMan->GetCurrentPlot() + 1;
|
//location.HouseId = (uint)houseMan->GetCurrentPlot() + 1;
|
||||||
location.DivisionId = houseMan->GetCurrentDivision();
|
location.DivisionId = houseMan->GetCurrentDivision();
|
||||||
}
|
}
|
||||||
//_logger.LogWarning(LocationToString(location));
|
//_logger.LogWarning(LocationToString(location));
|
||||||
@@ -713,10 +718,10 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
|
|||||||
str += $" - {MapData.Value[(ushort)location.MapId].MapName}";
|
str += $" - {MapData.Value[(ushort)location.MapId].MapName}";
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (location.InstanceId is not 0)
|
if (location.InstanceId is not 0)
|
||||||
// {
|
{
|
||||||
// str += ((SeIconChar)(57520 + location.InstanceId)).ToIconString();
|
str += ((SeIconChar)(57520 + location.InstanceId)).ToIconString();
|
||||||
// }
|
}
|
||||||
|
|
||||||
if (location.WardId is not 0)
|
if (location.WardId is not 0)
|
||||||
{
|
{
|
||||||
@@ -1135,6 +1140,18 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
|
|||||||
Mediator.Publish(new ZoneSwitchEndMessage());
|
Mediator.Publish(new ZoneSwitchEndMessage());
|
||||||
Mediator.Publish(new ResumeScanMessage(nameof(ConditionFlag.BetweenAreas)));
|
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;
|
var localPlayer = _objectTable.LocalPlayer;
|
||||||
if (localPlayer != null)
|
if (localPlayer != null)
|
||||||
|
|||||||
137
LightlessSync/Services/LocationShareService.cs
Normal file
137
LightlessSync/Services/LocationShareService.cs
Normal file
@@ -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<LocationShareService> logger, LightlessMediator mediator, DalamudUtilService dalamudUtilService, ApiController apiController) : base(logger, mediator)
|
||||||
|
{
|
||||||
|
_dalamudUtilService = dalamudUtilService;
|
||||||
|
_apiController = apiController;
|
||||||
|
|
||||||
|
|
||||||
|
Mediator.Subscribe<DisconnectedMessage>(this, (msg) =>
|
||||||
|
{
|
||||||
|
_resetToken.Cancel();
|
||||||
|
_resetToken.Dispose();
|
||||||
|
_resetToken = new CancellationTokenSource();
|
||||||
|
});
|
||||||
|
Mediator.Subscribe<ConnectedMessage>(this, (msg) =>
|
||||||
|
{
|
||||||
|
_ = _apiController.UpdateLocation(new LocationDto(new UserData(_apiController.UID, apiController.DisplayName), _dalamudUtilService.GetMapData()));
|
||||||
|
_ = RequestAllLocation();
|
||||||
|
} );
|
||||||
|
Mediator.Subscribe<LocationSharingMessage>(this, UpdateLocationList);
|
||||||
|
Mediator.Subscribe<MapChangedMessage>(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<LocationInfo>(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<DateTimeOffset>(uid, out var expireAt))
|
||||||
|
{
|
||||||
|
return expireAt;
|
||||||
|
}
|
||||||
|
return DateTimeOffset.MinValue;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(e,"GetSharingStatus error : ");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateSharingStatus(List<string> users, DateTimeOffset expireAt)
|
||||||
|
{
|
||||||
|
foreach (var user in users)
|
||||||
|
{
|
||||||
|
AddStatus(user, expireAt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -135,5 +135,7 @@ public record ChatChannelsUpdated : MessageBase;
|
|||||||
public record ChatChannelMessageAdded(string ChannelKey, ChatMessageEntry Message) : MessageBase;
|
public record ChatChannelMessageAdded(string ChannelKey, ChatMessageEntry Message) : MessageBase;
|
||||||
public record GroupCollectionChangedMessage : MessageBase;
|
public record GroupCollectionChangedMessage : MessageBase;
|
||||||
public record OpenUserProfileMessage(UserData User) : 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 S2094
|
||||||
#pragma warning restore MA0048 // File name must match type name
|
#pragma warning restore MA0048 // File name must match type name
|
||||||
@@ -37,6 +37,7 @@ public class DrawUserPair
|
|||||||
private readonly UiSharedService _uiSharedService;
|
private readonly UiSharedService _uiSharedService;
|
||||||
private readonly PlayerPerformanceConfigService _performanceConfigService;
|
private readonly PlayerPerformanceConfigService _performanceConfigService;
|
||||||
private readonly LightlessConfigService _configService;
|
private readonly LightlessConfigService _configService;
|
||||||
|
private readonly LocationShareService _locationShareService;
|
||||||
private readonly CharaDataManager _charaDataManager;
|
private readonly CharaDataManager _charaDataManager;
|
||||||
private readonly PairLedger _pairLedger;
|
private readonly PairLedger _pairLedger;
|
||||||
private float _menuWidth = -1;
|
private float _menuWidth = -1;
|
||||||
@@ -57,6 +58,7 @@ public class DrawUserPair
|
|||||||
UiSharedService uiSharedService,
|
UiSharedService uiSharedService,
|
||||||
PlayerPerformanceConfigService performanceConfigService,
|
PlayerPerformanceConfigService performanceConfigService,
|
||||||
LightlessConfigService configService,
|
LightlessConfigService configService,
|
||||||
|
LocationShareService locationShareService,
|
||||||
CharaDataManager charaDataManager,
|
CharaDataManager charaDataManager,
|
||||||
PairLedger pairLedger)
|
PairLedger pairLedger)
|
||||||
{
|
{
|
||||||
@@ -74,6 +76,7 @@ public class DrawUserPair
|
|||||||
_uiSharedService = uiSharedService;
|
_uiSharedService = uiSharedService;
|
||||||
_performanceConfigService = performanceConfigService;
|
_performanceConfigService = performanceConfigService;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
|
_locationShareService = locationShareService;
|
||||||
_charaDataManager = charaDataManager;
|
_charaDataManager = charaDataManager;
|
||||||
_pairLedger = pairLedger;
|
_pairLedger = pairLedger;
|
||||||
}
|
}
|
||||||
@@ -216,6 +219,48 @@ public class DrawUserPair
|
|||||||
_ = _apiController.UserSetPairPermissions(new UserPermissionsDto(_pair.UserData, permissions));
|
_ = _apiController.UserSetPairPermissions(new UserPermissionsDto(_pair.UserData, permissions));
|
||||||
}
|
}
|
||||||
UiSharedService.AttachToolTip("Changes VFX sync permissions with this user." + (individual ? individualText : string.Empty));
|
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<string> users, DateTimeOffset expireAt)
|
||||||
|
{
|
||||||
|
var updated = await _apiController.ToggleLocationSharing(new LocationSharingToggleDto(users, expireAt)).ConfigureAwait(false);
|
||||||
|
if (updated)
|
||||||
|
{
|
||||||
|
_locationShareService.UpdateSharingStatus(users, expireAt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawIndividualMenu()
|
private void DrawIndividualMenu()
|
||||||
@@ -574,6 +619,71 @@ public class DrawUserPair
|
|||||||
var individualVFXDisabled = (_pair.UserPair?.OwnPermissions.IsDisableVFX() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableVFX() ?? false);
|
var individualVFXDisabled = (_pair.UserPair?.OwnPermissions.IsDisableVFX() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableVFX() ?? false);
|
||||||
var individualIsSticky = _pair.UserPair!.OwnPermissions.IsSticky();
|
var individualIsSticky = _pair.UserPair!.OwnPermissions.IsSticky();
|
||||||
var individualIcon = individualIsSticky ? FontAwesomeIcon.ArrowCircleUp : FontAwesomeIcon.InfoCircle;
|
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)
|
if (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled || individualIsSticky)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2183,7 +2183,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
bool toggleClicked = false;
|
bool toggleClicked = false;
|
||||||
if (showToggle)
|
if (showToggle)
|
||||||
{
|
{
|
||||||
var icon = isCollapsed ? FontAwesomeIcon.ChevronRight : FontAwesomeIcon.ChevronLeft;
|
var icon = !isCollapsed ? FontAwesomeIcon.ChevronRight : FontAwesomeIcon.ChevronLeft;
|
||||||
Vector2 iconSize;
|
Vector2 iconSize;
|
||||||
using (_uiSharedService.IconFont.Push())
|
using (_uiSharedService.IconFont.Push())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public class DrawEntityFactory
|
|||||||
private readonly LightlessConfigService _configService;
|
private readonly LightlessConfigService _configService;
|
||||||
private readonly UiSharedService _uiSharedService;
|
private readonly UiSharedService _uiSharedService;
|
||||||
private readonly PlayerPerformanceConfigService _playerPerformanceConfigService;
|
private readonly PlayerPerformanceConfigService _playerPerformanceConfigService;
|
||||||
|
private readonly LocationShareService _locationShareService;
|
||||||
private readonly CharaDataManager _charaDataManager;
|
private readonly CharaDataManager _charaDataManager;
|
||||||
private readonly SelectTagForPairUi _selectTagForPairUi;
|
private readonly SelectTagForPairUi _selectTagForPairUi;
|
||||||
private readonly RenamePairTagUi _renamePairTagUi;
|
private readonly RenamePairTagUi _renamePairTagUi;
|
||||||
@@ -53,6 +54,7 @@ public class DrawEntityFactory
|
|||||||
LightlessConfigService configService,
|
LightlessConfigService configService,
|
||||||
UiSharedService uiSharedService,
|
UiSharedService uiSharedService,
|
||||||
PlayerPerformanceConfigService playerPerformanceConfigService,
|
PlayerPerformanceConfigService playerPerformanceConfigService,
|
||||||
|
LocationShareService locationShareService,
|
||||||
CharaDataManager charaDataManager,
|
CharaDataManager charaDataManager,
|
||||||
SelectTagForSyncshellUi selectTagForSyncshellUi,
|
SelectTagForSyncshellUi selectTagForSyncshellUi,
|
||||||
RenameSyncshellTagUi renameSyncshellTagUi,
|
RenameSyncshellTagUi renameSyncshellTagUi,
|
||||||
@@ -72,6 +74,7 @@ public class DrawEntityFactory
|
|||||||
_configService = configService;
|
_configService = configService;
|
||||||
_uiSharedService = uiSharedService;
|
_uiSharedService = uiSharedService;
|
||||||
_playerPerformanceConfigService = playerPerformanceConfigService;
|
_playerPerformanceConfigService = playerPerformanceConfigService;
|
||||||
|
_locationShareService = locationShareService;
|
||||||
_charaDataManager = charaDataManager;
|
_charaDataManager = charaDataManager;
|
||||||
_selectTagForSyncshellUi = selectTagForSyncshellUi;
|
_selectTagForSyncshellUi = selectTagForSyncshellUi;
|
||||||
_renameSyncshellTagUi = renameSyncshellTagUi;
|
_renameSyncshellTagUi = renameSyncshellTagUi;
|
||||||
@@ -162,6 +165,7 @@ public class DrawEntityFactory
|
|||||||
_uiSharedService,
|
_uiSharedService,
|
||||||
_playerPerformanceConfigService,
|
_playerPerformanceConfigService,
|
||||||
_configService,
|
_configService,
|
||||||
|
_locationShareService,
|
||||||
_charaDataManager,
|
_charaDataManager,
|
||||||
_pairLedger);
|
_pairLedger);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Dalamud.Interface.Colors;
|
|||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
using Dalamud.Interface.Utility.Raii;
|
using Dalamud.Interface.Utility.Raii;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
|
using Lifestream.Enums;
|
||||||
using LightlessSync.API.Data;
|
using LightlessSync.API.Data;
|
||||||
using LightlessSync.API.Data.Comparer;
|
using LightlessSync.API.Data.Comparer;
|
||||||
using LightlessSync.API.Data.Enum;
|
using LightlessSync.API.Data.Enum;
|
||||||
@@ -1243,7 +1244,6 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
ImGui.TreePop();
|
ImGui.TreePop();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if (_uiShared.IconTextButton(FontAwesomeIcon.Copy, "[DEBUG] Copy Last created Character Data to clipboard"))
|
if (_uiShared.IconTextButton(FontAwesomeIcon.Copy, "[DEBUG] Copy Last created Character Data to clipboard"))
|
||||||
{
|
{
|
||||||
if (LastCreatedCharacterData != null)
|
if (LastCreatedCharacterData != null)
|
||||||
@@ -1259,6 +1259,39 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
UiSharedService.AttachToolTip("Use this when reporting mods being rejected from the server.");
|
UiSharedService.AttachToolTip("Use this when reporting mods being rejected from the server.");
|
||||||
|
|
||||||
|
if (_uiShared.IconTextButton(FontAwesomeIcon.Home, "Teleport to Limsa [LIFESTREAM TEST]") && _ipcManager.Lifestream.APIAvailable)
|
||||||
|
{
|
||||||
|
_ipcManager.Lifestream.ExecuteLifestreamCommand("limsa");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_uiShared.IconTextButton(FontAwesomeIcon.Home, "Teleport to JoyHouse [LIFESTREAM TEST]") && _ipcManager.Lifestream.APIAvailable)
|
||||||
|
{
|
||||||
|
var twintania = _dalamudUtilService.WorldData.Value
|
||||||
|
.FirstOrDefault(kvp => kvp.Value.Equals("Twintania", StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
int ward = 29;
|
||||||
|
int plot = 7;
|
||||||
|
|
||||||
|
AddressBookEntryTuple addressEntry = (
|
||||||
|
Name: "",
|
||||||
|
World: (int)twintania.Key,
|
||||||
|
City: (int)ResidentialAetheryteKind.Kugane,
|
||||||
|
Ward: ward,
|
||||||
|
PropertyType: 0,
|
||||||
|
Plot: plot,
|
||||||
|
Apartment: 1,
|
||||||
|
ApartmentSubdivision: false,
|
||||||
|
AliasEnabled: false,
|
||||||
|
Alias: ""
|
||||||
|
);
|
||||||
|
|
||||||
|
_logger.LogInformation("going to: {address}", addressEntry);
|
||||||
|
|
||||||
|
_ipcManager.Lifestream.GoToHousingAddress(addressEntry);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
_uiShared.DrawCombo("Log Level", Enum.GetValues<LogLevel>(), (l) => l.ToString(), (l) =>
|
_uiShared.DrawCombo("Log Level", Enum.GetValues<LogLevel>(), (l) => l.ToString(), (l) =>
|
||||||
{
|
{
|
||||||
_configService.Current.LogLevel = l;
|
_configService.Current.LogLevel = l;
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
|||||||
private readonly Dictionary<string, DateTime> _oauthTokenExpiry = [];
|
private readonly Dictionary<string, DateTime> _oauthTokenExpiry = [];
|
||||||
private bool _penumbraExists = false;
|
private bool _penumbraExists = false;
|
||||||
private bool _petNamesExists = false;
|
private bool _petNamesExists = false;
|
||||||
|
private bool _lifestreamExists = false;
|
||||||
private int _serverSelectionIndex = -1;
|
private int _serverSelectionIndex = -1;
|
||||||
public UiSharedService(ILogger<UiSharedService> logger, IpcManager ipcManager, ApiController apiController,
|
public UiSharedService(ILogger<UiSharedService> logger, IpcManager ipcManager, ApiController apiController,
|
||||||
CacheMonitor cacheMonitor, FileDialogManager fileDialogManager,
|
CacheMonitor cacheMonitor, FileDialogManager fileDialogManager,
|
||||||
@@ -112,6 +113,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
|||||||
_moodlesExists = _ipcManager.Moodles.APIAvailable;
|
_moodlesExists = _ipcManager.Moodles.APIAvailable;
|
||||||
_petNamesExists = _ipcManager.PetNames.APIAvailable;
|
_petNamesExists = _ipcManager.PetNames.APIAvailable;
|
||||||
_brioExists = _ipcManager.Brio.APIAvailable;
|
_brioExists = _ipcManager.Brio.APIAvailable;
|
||||||
|
_lifestreamExists = _ipcManager.Lifestream.APIAvailable;
|
||||||
});
|
});
|
||||||
|
|
||||||
UidFont = _pluginInterface.UiBuilder.FontAtlas.NewDelegateFontHandle(e =>
|
UidFont = _pluginInterface.UiBuilder.FontAtlas.NewDelegateFontHandle(e =>
|
||||||
@@ -1105,6 +1107,10 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
|||||||
ColorText("Brio", GetBoolColor(_brioExists));
|
ColorText("Brio", GetBoolColor(_brioExists));
|
||||||
AttachToolTip(BuildPluginTooltip("Brio", _brioExists, _ipcManager.Brio.State));
|
AttachToolTip(BuildPluginTooltip("Brio", _brioExists, _ipcManager.Brio.State));
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ColorText("Lifestream", GetBoolColor(_lifestreamExists));
|
||||||
|
AttachToolTip(BuildPluginTooltip("Lifestream", _lifestreamExists, _ipcManager.Lifestream.State));
|
||||||
|
|
||||||
if (!_penumbraExists || !_glamourerExists)
|
if (!_penumbraExists || !_glamourerExists)
|
||||||
{
|
{
|
||||||
ImGui.TextColored(ImGuiColors.DalamudRed, "You need to install both Penumbra and Glamourer and keep them up to date to use Lightless Sync.");
|
ImGui.TextColored(ImGuiColors.DalamudRed, "You need to install both Penumbra and Glamourer and keep them up to date to use Lightless Sync.");
|
||||||
|
|||||||
@@ -200,5 +200,21 @@ public partial class ApiController
|
|||||||
|
|
||||||
await UserPushData(new(visibleCharacters, character, censusDto)).ConfigureAwait(false);
|
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<LocationWithTimeDto>, List<SharingStatusDto>)> RequestAllLocationInfo()
|
||||||
|
{
|
||||||
|
if (!IsConnected) return ([],[]);
|
||||||
|
return await _lightlessHub!.InvokeAsync<(List<LocationWithTimeDto>, List<SharingStatusDto>)>(nameof(RequestAllLocationInfo)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
public async Task<bool> ToggleLocationSharing(LocationSharingToggleDto dto)
|
||||||
|
{
|
||||||
|
if (!IsConnected) return false;
|
||||||
|
return await _lightlessHub!.InvokeAsync<bool>(nameof(ToggleLocationSharing), dto).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore MA0040
|
#pragma warning restore MA0040
|
||||||
@@ -259,6 +259,13 @@ public partial class ApiController
|
|||||||
ExecuteSafely(() => Mediator.Publish(new GPoseLobbyReceiveWorldData(userData, worldData)));
|
ExecuteSafely(() => Mediator.Publish(new GPoseLobbyReceiveWorldData(userData, worldData)));
|
||||||
return Task.CompletedTask;
|
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<Guid> act)
|
public void OnDownloadReady(Action<Guid> act)
|
||||||
{
|
{
|
||||||
@@ -441,6 +448,12 @@ public partial class ApiController
|
|||||||
_lightlessHub!.On(nameof(Client_GposeLobbyPushWorldData), act);
|
_lightlessHub!.On(nameof(Client_GposeLobbyPushWorldData), act);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnReceiveLocation(Action<LocationDto, DateTimeOffset> act)
|
||||||
|
{
|
||||||
|
if (_initialized) return;
|
||||||
|
_lightlessHub!.On(nameof(Client_SendLocationToClient), act);
|
||||||
|
}
|
||||||
|
|
||||||
private void ExecuteSafely(Action act)
|
private void ExecuteSafely(Action act)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -606,6 +606,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL
|
|||||||
OnGposeLobbyPushCharacterData((dto) => _ = Client_GposeLobbyPushCharacterData(dto));
|
OnGposeLobbyPushCharacterData((dto) => _ = Client_GposeLobbyPushCharacterData(dto));
|
||||||
OnGposeLobbyPushPoseData((dto, data) => _ = Client_GposeLobbyPushPoseData(dto, data));
|
OnGposeLobbyPushPoseData((dto, data) => _ = Client_GposeLobbyPushPoseData(dto, data));
|
||||||
OnGposeLobbyPushWorldData((dto, data) => _ = Client_GposeLobbyPushWorldData(dto, data));
|
OnGposeLobbyPushWorldData((dto, data) => _ = Client_GposeLobbyPushWorldData(dto, data));
|
||||||
|
OnReceiveLocation((dto, time) => _ = Client_SendLocationToClient(dto, time));
|
||||||
|
|
||||||
_healthCheckTokenSource?.Cancel();
|
_healthCheckTokenSource?.Cancel();
|
||||||
_healthCheckTokenSource?.Dispose();
|
_healthCheckTokenSource?.Dispose();
|
||||||
@@ -774,5 +775,6 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL
|
|||||||
|
|
||||||
ServerState = state;
|
ServerState = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#pragma warning restore MA0040
|
#pragma warning restore MA0040
|
||||||
|
|||||||
@@ -76,6 +76,19 @@
|
|||||||
"Microsoft.AspNetCore.SignalR.Common": "10.0.1"
|
"Microsoft.AspNetCore.SignalR.Common": "10.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Caching.Memory": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[10.0.1, )",
|
||||||
|
"resolved": "10.0.1",
|
||||||
|
"contentHash": "NxqSP0Ky4dZ5ybszdZCqs1X2C70s+dXflqhYBUh/vhcQVTIooNCXIYnLVbafoAFGZMs51d9+rHxveXs0ZC3SQQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Caching.Abstractions": "10.0.1",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.1",
|
||||||
|
"Microsoft.Extensions.Logging.Abstractions": "10.0.1",
|
||||||
|
"Microsoft.Extensions.Options": "10.0.1",
|
||||||
|
"Microsoft.Extensions.Primitives": "10.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.Hosting": {
|
"Microsoft.Extensions.Hosting": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[10.0.1, )",
|
"requested": "[10.0.1, )",
|
||||||
@@ -233,6 +246,14 @@
|
|||||||
"Microsoft.AspNetCore.SignalR.Common": "10.0.1"
|
"Microsoft.AspNetCore.SignalR.Common": "10.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Caching.Abstractions": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "10.0.1",
|
||||||
|
"contentHash": "Vb1vVAQDxHpXVdL9fpOX2BzeV7bbhzG4pAcIKRauRl0/VfkE8mq0f+fYC+gWICh3dlzTZInJ/cTeBS2MgU/XvQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Primitives": "10.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.Configuration": {
|
"Microsoft.Extensions.Configuration": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "10.0.1",
|
"resolved": "10.0.1",
|
||||||
@@ -618,7 +639,7 @@
|
|||||||
"FlatSharp.Compiler": "[7.9.0, )",
|
"FlatSharp.Compiler": "[7.9.0, )",
|
||||||
"FlatSharp.Runtime": "[7.9.0, )",
|
"FlatSharp.Runtime": "[7.9.0, )",
|
||||||
"OtterGui": "[1.0.0, )",
|
"OtterGui": "[1.0.0, )",
|
||||||
"Penumbra.Api": "[5.13.0, )",
|
"Penumbra.Api": "[5.13.1, )",
|
||||||
"Penumbra.String": "[1.0.7, )"
|
"Penumbra.String": "[1.0.7, )"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user