Show silver coffers
This commit is contained in:
parent
89d1c46009
commit
c5d3c90b85
@ -1,15 +1,11 @@
|
||||
using Dalamud.Interface.Windowing;
|
||||
using ECommons.Automation;
|
||||
using ECommons.DalamudServices;
|
||||
using Dalamud.Interface.Components;
|
||||
using Dalamud.Interface.Windowing;
|
||||
using ECommons.SplatoonAPI;
|
||||
using ImGuiNET;
|
||||
using ImGuizmoNET;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pal.Client
|
||||
@ -21,6 +17,10 @@ namespace Pal.Client
|
||||
private Vector4 _trapColor;
|
||||
private bool _showHoard;
|
||||
private Vector4 _hoardColor;
|
||||
private bool _showSilverCoffers;
|
||||
private Vector4 _silverCofferColor;
|
||||
private bool _fillSilverCoffers;
|
||||
|
||||
private string _connectionText;
|
||||
|
||||
public ConfigWindow() : base("Palace Pal - Configuration###PalPalaceConfig")
|
||||
@ -39,6 +39,9 @@ namespace Pal.Client
|
||||
_trapColor = config.TrapColor;
|
||||
_showHoard = config.ShowHoard;
|
||||
_hoardColor = config.HoardColor;
|
||||
_showSilverCoffers = config.ShowSilverCoffers;
|
||||
_silverCofferColor = config.SilverCofferColor;
|
||||
_fillSilverCoffers = config.FillSilverCoffers;
|
||||
_connectionText = null;
|
||||
}
|
||||
|
||||
@ -70,6 +73,18 @@ namespace Pal.Client
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
ImGui.Checkbox("Show silver coffers on current floor", ref _showSilverCoffers);
|
||||
ImGuiComponents.HelpMarker("Shows all the silver coffers visible to you on the current floor.\nThis is not synchronized with other players and not saved between floors/runs.\n\nExperimental feature.");
|
||||
ImGui.Indent();
|
||||
ImGui.BeginDisabled(!_showSilverCoffers);
|
||||
ImGui.Spacing();
|
||||
ImGui.ColorEdit4("Silver Coffer color", ref _silverCofferColor, ImGuiColorEditFlags.NoInputs);
|
||||
ImGui.Checkbox("Draw filled", ref _fillSilverCoffers);
|
||||
ImGui.EndDisabled();
|
||||
ImGui.Unindent();
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
save = ImGui.Button("Save");
|
||||
ImGui.SameLine();
|
||||
saveAndClose = ImGui.Button("Save & Close");
|
||||
@ -125,13 +140,25 @@ namespace Pal.Client
|
||||
if (plugin.FloorMarkers.TryGetValue(plugin.LastTerritory, out var currentFloorMarkers))
|
||||
{
|
||||
if (_showTraps)
|
||||
ImGui.Text($"{currentFloorMarkers.Count(x => x != null && x.Type == Palace.ObjectType.Trap)} known traps");
|
||||
{
|
||||
int traps = currentFloorMarkers.Count(x => x != null && x.Type == Marker.EType.Trap);
|
||||
ImGui.Text($"{traps} known trap{(traps == 1 ? "" : "s")}");
|
||||
}
|
||||
if (_showHoard)
|
||||
ImGui.Text($"{currentFloorMarkers.Count(x => x != null && x.Type == Palace.ObjectType.Hoard)} known hoard coffers");
|
||||
{
|
||||
int hoardCoffers = currentFloorMarkers.Count(x => x != null && x.Type == Marker.EType.Hoard);
|
||||
ImGui.Text($"{hoardCoffers} known hoard coffer{(hoardCoffers == 1 ? "" : "s")}");
|
||||
}
|
||||
if (_showSilverCoffers)
|
||||
{
|
||||
int silverCoffers = plugin.EphemeralMarkers.Count(x => x != null && x.Type == Marker.EType.SilverCoffer);
|
||||
ImGui.Text($"{silverCoffers} silver coffer{(silverCoffers == 1 ? "" : "s")} visible on current floor");
|
||||
}
|
||||
}
|
||||
else
|
||||
ImGui.Text("Could not query current trap/coffer count.");
|
||||
ImGui.Unindent();
|
||||
ImGui.TextWrapped("Traps and coffers may not be discovered even after using a pomander if they're far away (around 1,5-2 rooms).");
|
||||
}
|
||||
else
|
||||
ImGui.Text("You are NOT in a deep dungeon.");
|
||||
@ -145,8 +172,8 @@ namespace Pal.Client
|
||||
var pos = Service.ClientState.LocalPlayer.Position;
|
||||
var elements = new List<Element>
|
||||
{
|
||||
Plugin.CreateSplatoonElement(Palace.ObjectType.Trap, pos, _trapColor),
|
||||
Plugin.CreateSplatoonElement(Palace.ObjectType.Hoard, pos, _hoardColor),
|
||||
Plugin.CreateSplatoonElement(Marker.EType.Trap, pos, _trapColor),
|
||||
Plugin.CreateSplatoonElement(Marker.EType.Hoard, pos, _hoardColor),
|
||||
};
|
||||
|
||||
if (!Splatoon.AddDynamicElements("PalacePal.Test", elements.ToArray(), new long[] { Environment.TickCount64 + 10000 }))
|
||||
@ -174,6 +201,9 @@ namespace Pal.Client
|
||||
config.TrapColor = _trapColor;
|
||||
config.ShowHoard = _showHoard;
|
||||
config.HoardColor = _hoardColor;
|
||||
config.ShowSilverCoffers = _showSilverCoffers;
|
||||
config.SilverCofferColor = _silverCofferColor;
|
||||
config.FillSilverCoffers = _fillSilverCoffers;
|
||||
config.Save();
|
||||
|
||||
if (saveAndClose)
|
||||
|
@ -20,6 +20,9 @@ namespace Pal.Client
|
||||
public Vector4 TrapColor { get; set; } = new Vector4(1, 0, 0, 0.4f);
|
||||
public bool ShowHoard { get; set; } = true;
|
||||
public Vector4 HoardColor { get; set; } = new Vector4(0, 1, 1, 0.4f);
|
||||
public bool ShowSilverCoffers { get; set; } = false;
|
||||
public Vector4 SilverCofferColor { get; set; } = new Vector4(1, 1, 1, 0.4f);
|
||||
public bool FillSilverCoffers { get; set; } = true;
|
||||
#endregion
|
||||
|
||||
public delegate void OnSaved();
|
||||
|
@ -8,7 +8,7 @@ namespace Pal.Client
|
||||
{
|
||||
internal class Marker
|
||||
{
|
||||
public ObjectType Type { get; set; } = ObjectType.Unknown;
|
||||
public EType Type { get; set; } = EType.Unknown;
|
||||
public Vector3 Position { get; set; }
|
||||
public bool Seen { get; set; } = false;
|
||||
|
||||
@ -18,7 +18,7 @@ namespace Pal.Client
|
||||
[JsonIgnore]
|
||||
public Element SplatoonElement { get; set; }
|
||||
|
||||
public Marker(ObjectType type, Vector3 position)
|
||||
public Marker(EType type, Vector3 position)
|
||||
{
|
||||
Type = type;
|
||||
Position = position;
|
||||
@ -31,7 +31,34 @@ namespace Pal.Client
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Marker otherMarker && Type == otherMarker.Type && Position == otherMarker.Position;
|
||||
return obj is Marker otherMarker && Type == otherMarker.Type && (int)Position.X == (int)otherMarker.Position.X && (int)Position.Y == (int)otherMarker.Position.Y && (int)Position.Z == (int)otherMarker.Position.Z;
|
||||
}
|
||||
|
||||
public static bool operator ==(Marker a, object b)
|
||||
{
|
||||
return Equals(a, b);
|
||||
}
|
||||
|
||||
public static bool operator !=(Marker a, object b)
|
||||
{
|
||||
return !Equals(a, b);
|
||||
}
|
||||
|
||||
|
||||
public bool IsPermanent() => Type == EType.Trap || Type == EType.Hoard;
|
||||
|
||||
public enum EType
|
||||
{
|
||||
Unknown = ObjectType.Unknown,
|
||||
|
||||
#region Permanent Markers
|
||||
Trap = ObjectType.Trap,
|
||||
Hoard = ObjectType.Hoard,
|
||||
#endregion
|
||||
|
||||
# region Markers that only show up if they're currently visible
|
||||
SilverCoffer = 100,
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<Version>1.3.0.0</Version>
|
||||
<Version>1.4.0.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
@ -1,8 +1,5 @@
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Command;
|
||||
using Dalamud.Interface.Windowing;
|
||||
@ -10,9 +7,7 @@ using Dalamud.Plugin;
|
||||
using ECommons;
|
||||
using ECommons.Schedulers;
|
||||
using ECommons.SplatoonAPI;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using ImGuiNET;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@ -30,9 +25,16 @@ namespace Pal.Client
|
||||
private const long ON_TERRITORY_CHANGE = -2;
|
||||
|
||||
private readonly ConcurrentQueue<(ushort territoryId, bool success, IList<Marker> markers)> _remoteDownloads = new();
|
||||
private readonly static Dictionary<Marker.EType, MarkerConfig> _markerConfig = new Dictionary<Marker.EType, MarkerConfig>
|
||||
{
|
||||
{ Marker.EType.Trap, new MarkerConfig { Radius = 1.7f } },
|
||||
{ Marker.EType.Hoard, new MarkerConfig { Radius = 1.7f, OffsetY = -0.03f } },
|
||||
{ Marker.EType.SilverCoffer, new MarkerConfig { Radius = 1f } },
|
||||
};
|
||||
private bool _configUpdated = false;
|
||||
|
||||
internal ConcurrentDictionary<ushort, ConcurrentBag<Marker>> FloorMarkers { get; } = new();
|
||||
internal ConcurrentBag<Marker> EphemeralMarkers { get; set; } = new();
|
||||
internal ushort LastTerritory { get; private set; }
|
||||
public SyncState TerritorySyncState { get; set; }
|
||||
public string DebugMessage { get; set; }
|
||||
@ -127,6 +129,7 @@ namespace Pal.Client
|
||||
{
|
||||
try
|
||||
{
|
||||
bool recreateLayout = false;
|
||||
if (_configUpdated)
|
||||
{
|
||||
if (Service.Configuration.Mode == Configuration.EMode.Offline)
|
||||
@ -141,12 +144,13 @@ namespace Pal.Client
|
||||
}
|
||||
|
||||
FloorMarkers.Clear();
|
||||
EphemeralMarkers.Clear();
|
||||
LastTerritory = 0;
|
||||
}
|
||||
_configUpdated = false;
|
||||
recreateLayout = true;
|
||||
}
|
||||
|
||||
bool recreateLayout = false;
|
||||
bool saveMarkers = false;
|
||||
if (LastTerritory != Service.ClientState.TerritoryType)
|
||||
{
|
||||
@ -155,6 +159,7 @@ namespace Pal.Client
|
||||
|
||||
if (IsInPotdOrHoh())
|
||||
FloorMarkers[LastTerritory] = new ConcurrentBag<Marker>(LoadSavedMarkers());
|
||||
EphemeralMarkers.Clear();
|
||||
recreateLayout = true;
|
||||
DebugMessage = null;
|
||||
}
|
||||
@ -179,9 +184,21 @@ namespace Pal.Client
|
||||
FloorMarkers[LastTerritory] = currentFloorMarkers = new ConcurrentBag<Marker>();
|
||||
|
||||
IList<Marker> visibleMarkers = GetRelevantGameObjects();
|
||||
HandlePersistentMarkers(currentFloorMarkers, visibleMarkers.Where(x => x.IsPermanent()).ToList(), saveMarkers, recreateLayout);
|
||||
HandleEphemeralMarkers(visibleMarkers.Where(x => !x.IsPermanent()).ToList(), recreateLayout);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugMessage = $"{DateTime.Now}\n{e}";
|
||||
}
|
||||
}
|
||||
|
||||
private void HandlePersistentMarkers(ConcurrentBag<Marker> currentFloorMarkers, IList<Marker> visibleMarkers, bool saveMarkers, bool recreateLayout)
|
||||
{
|
||||
|
||||
foreach (var visibleMarker in visibleMarkers)
|
||||
{
|
||||
Marker knownMarker = currentFloorMarkers.SingleOrDefault(x => x != null && x.GetHashCode() == visibleMarker.GetHashCode());
|
||||
Marker knownMarker = currentFloorMarkers.SingleOrDefault(x => x == visibleMarker);
|
||||
if (knownMarker != null)
|
||||
{
|
||||
if (!knownMarker.Seen)
|
||||
@ -203,15 +220,14 @@ namespace Pal.Client
|
||||
|
||||
if (TerritorySyncState == SyncState.Complete)
|
||||
{
|
||||
var markersToUpload = currentFloorMarkers.Where(x => !x.RemoteSeen).ToList();
|
||||
var markersToUpload = currentFloorMarkers.Where(x => x.IsPermanent() && !x.RemoteSeen).ToList();
|
||||
Task.Run(async () => await Service.RemoteApi.UploadMarker(LastTerritory, markersToUpload));
|
||||
}
|
||||
}
|
||||
|
||||
if (recreateLayout)
|
||||
{
|
||||
Splatoon.RemoveDynamicElements("PalacePal.Markers");
|
||||
|
||||
Splatoon.RemoveDynamicElements("PalacePal.TrapHoard");
|
||||
|
||||
var config = Service.Configuration;
|
||||
|
||||
@ -220,13 +236,13 @@ namespace Pal.Client
|
||||
{
|
||||
if (marker.Seen || config.Mode == Configuration.EMode.Online)
|
||||
{
|
||||
if (marker.Type == Palace.ObjectType.Trap && config.ShowTraps)
|
||||
if (marker.Type == Marker.EType.Trap && config.ShowTraps)
|
||||
{
|
||||
var element = CreateSplatoonElement(marker.Type, marker.Position, config.TrapColor);
|
||||
marker.SplatoonElement = element;
|
||||
elements.Add(element);
|
||||
}
|
||||
else if (marker.Type == Palace.ObjectType.Hoard && config.ShowHoard)
|
||||
else if (marker.Type == Marker.EType.Hoard && config.ShowHoard)
|
||||
{
|
||||
var element = CreateSplatoonElement(marker.Type, marker.Position, config.HoardColor);
|
||||
marker.SplatoonElement = element;
|
||||
@ -235,12 +251,15 @@ namespace Pal.Client
|
||||
}
|
||||
}
|
||||
|
||||
if (elements.Count == 0)
|
||||
return;
|
||||
|
||||
// we need to delay this, as the current framework update could be before splatoon's, in which case it would immediately delete the layout
|
||||
new TickScheduler(delegate
|
||||
{
|
||||
try
|
||||
{
|
||||
Splatoon.AddDynamicElements("PalacePal.Markers", elements.ToArray(), new long[] { Environment.TickCount64 + 60 * 60 * 1000, ON_TERRITORY_CHANGE });
|
||||
Splatoon.AddDynamicElements("PalacePal.TrapHoard", elements.ToArray(), new long[] { Environment.TickCount64 + 60 * 60 * 1000, ON_TERRITORY_CHANGE });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -249,10 +268,47 @@ namespace Pal.Client
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleEphemeralMarkers(IList<Marker> visibleMarkers, bool recreateLayout)
|
||||
{
|
||||
recreateLayout |= EphemeralMarkers.Any(existingMarker => !visibleMarkers.Any(x => x == existingMarker));
|
||||
recreateLayout |= visibleMarkers.Any(visibleMarker => !EphemeralMarkers.Any(x => x == visibleMarker));
|
||||
|
||||
if (recreateLayout)
|
||||
{
|
||||
Splatoon.RemoveDynamicElements("PalacePal.RegularCoffers");
|
||||
EphemeralMarkers.Clear();
|
||||
|
||||
var config = Service.Configuration;
|
||||
|
||||
List<Element> elements = new List<Element>();
|
||||
foreach (var marker in visibleMarkers)
|
||||
{
|
||||
EphemeralMarkers.Add(marker);
|
||||
|
||||
if (marker.Type == Marker.EType.SilverCoffer && config.ShowSilverCoffers)
|
||||
{
|
||||
var element = CreateSplatoonElement(marker.Type, marker.Position, config.SilverCofferColor, config.FillSilverCoffers);
|
||||
marker.SplatoonElement = element;
|
||||
elements.Add(element);
|
||||
}
|
||||
}
|
||||
|
||||
if (elements.Count == 0)
|
||||
return;
|
||||
|
||||
new TickScheduler(delegate
|
||||
{
|
||||
try
|
||||
{
|
||||
Splatoon.AddDynamicElements("PalacePal.RegularCoffers", elements.ToArray(), new long[] { Environment.TickCount64 + 60 * 60 * 1000, ON_TERRITORY_CHANGE });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugMessage = $"{DateTime.Now}\n{e}";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public string GetSaveForCurrentTerritory() => Path.Join(Service.PluginInterface.GetPluginConfigDirectory(), $"{LastTerritory}.json");
|
||||
@ -294,7 +350,7 @@ namespace Pal.Client
|
||||
{
|
||||
foreach (var downloadedMarker in downloadedMarkers)
|
||||
{
|
||||
Marker seenMarker = currentFloorMarkers.SingleOrDefault(x => x.GetHashCode() == downloadedMarker.GetHashCode());
|
||||
Marker seenMarker = currentFloorMarkers.SingleOrDefault(x => x == downloadedMarker);
|
||||
if (seenMarker != null)
|
||||
{
|
||||
seenMarker.RemoteSeen = true;
|
||||
@ -333,12 +389,16 @@ namespace Pal.Client
|
||||
case 2007185:
|
||||
case 2007186:
|
||||
case 2009504:
|
||||
result.Add(new Marker(Palace.ObjectType.Trap, obj.Position) { Seen = true });
|
||||
result.Add(new Marker(Marker.EType.Trap, obj.Position) { Seen = true });
|
||||
break;
|
||||
|
||||
case 2007542:
|
||||
case 2007543:
|
||||
result.Add(new Marker(Palace.ObjectType.Hoard, obj.Position) { Seen = true });
|
||||
result.Add(new Marker(Marker.EType.Hoard, obj.Position) { Seen = true });
|
||||
break;
|
||||
|
||||
case 2007357:
|
||||
result.Add(new Marker(Marker.EType.SilverCoffer, obj.Position) { Seen = true });
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -348,7 +408,7 @@ namespace Pal.Client
|
||||
|
||||
internal bool IsInPotdOrHoh() => Service.ClientState.IsLoggedIn && Service.Condition[ConditionFlag.InDeepDungeon];
|
||||
|
||||
internal static Element CreateSplatoonElement(Palace.ObjectType type, Vector3 pos, Vector4 color)
|
||||
internal static Element CreateSplatoonElement(Marker.EType type, Vector3 pos, Vector4 color, bool fill = false)
|
||||
{
|
||||
return new Element(ElementType.CircleAtFixedCoordinates)
|
||||
{
|
||||
@ -357,9 +417,9 @@ namespace Pal.Client
|
||||
refZ = pos.Y,
|
||||
offX = 0,
|
||||
offY = 0,
|
||||
offZ = type == Palace.ObjectType.Trap ? 0 : -0.03f,
|
||||
Filled = false,
|
||||
radius = 1.7f,
|
||||
offZ = _markerConfig[type].OffsetY,
|
||||
Filled = fill,
|
||||
radius = _markerConfig[type].Radius,
|
||||
FillStep = 1,
|
||||
color = ImGui.ColorConvertFloat4ToU32(color),
|
||||
thicc = 2,
|
||||
@ -373,5 +433,11 @@ namespace Pal.Client
|
||||
Complete,
|
||||
Failed,
|
||||
}
|
||||
|
||||
private class MarkerConfig
|
||||
{
|
||||
public float OffsetY { get; set; } = 0;
|
||||
public float Radius { get; set; } = 0.25f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ namespace Pal.Client
|
||||
|
||||
var palaceClient = new PalaceService.PalaceServiceClient(_channel);
|
||||
var downloadReply = await palaceClient.DownloadFloorsAsync(new DownloadFloorsRequest { TerritoryType = territoryId }, headers: AuthorizedHeaders(), cancellationToken: cancellationToken);
|
||||
return (downloadReply.Success, downloadReply.Objects.Select(o => new Marker(o.Type, new Vector3(o.X, o.Y, o.Z)) { RemoteSeen = true }).ToList());
|
||||
return (downloadReply.Success, downloadReply.Objects.Select(o => new Marker((Marker.EType)o.Type, new Vector3(o.X, o.Y, o.Z)) { RemoteSeen = true }).ToList());
|
||||
}
|
||||
|
||||
public async Task<bool> UploadMarker(ushort territoryType, IList<Marker> markers, CancellationToken cancellationToken = default)
|
||||
@ -133,7 +133,7 @@ namespace Pal.Client
|
||||
};
|
||||
uploadRequest.Objects.AddRange(markers.Select(m => new PalaceObject
|
||||
{
|
||||
Type = m.Type,
|
||||
Type = (ObjectType)m.Type,
|
||||
X = m.Position.X,
|
||||
Y = m.Position.Y,
|
||||
Z = m.Position.Z
|
||||
|
Loading…
Reference in New Issue
Block a user