Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d6d746c1ed | |||
| 50a8dc6d09 | |||
| 6ad3faa922 | |||
| 64dd38a2a3 | |||
| e748ba7138 | |||
| 62ce794e8b | |||
| 0f6c3a5332 | |||
| ca638c19a2 | |||
| 2680d24a39 | |||
| 082e9e5580 | |||
| 004056b648 | |||
| ca28a9d6f7 | |||
| 83d705c4c6 | |||
| 5b75e305eb | |||
| 0669b2cecb | |||
| 3df83a8fa7 | |||
| e92662969b | |||
| 86686bf0ca | |||
| 8d92c79822 | |||
| 9900230520 | |||
| a9264fdd21 | |||
| 331bd63e2e | |||
| dfc85d7890 | |||
| ddd6954142 | |||
| 22c3497fec | |||
| 675225658c | |||
| 8273c68318 | |||
| 7f41e593c3 | |||
| ab3bf20ffa | |||
| 4b21e569a0 | |||
| bfd5cd1b12 | |||
| 83fdf5613e | |||
| 545a812b66 | |||
| cb2cd8e32c | |||
| e699a758f3 | |||
| e6e90cdcd3 | |||
| e7ce31dc0b | |||
| 1e9bd2484a | |||
| a4d3e8b0f3 | |||
| 5695a0823b | |||
| 22475d7223 | |||
| 348d8f50e6 | |||
| 5f78d24c78 | |||
| 0af7217e63 | |||
| e01ebcde37 | |||
| d127662959 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -360,4 +360,7 @@ MigrationBackup/
|
|||||||
.ionide/
|
.ionide/
|
||||||
|
|
||||||
# Fody - auto-generated XML schema
|
# Fody - auto-generated XML schema
|
||||||
FodyWeavers.xsd
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# Idea
|
||||||
|
.idea
|
||||||
|
|||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Pilzinsel64
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,25 +1,18 @@
|
|||||||
using System;
|
namespace Pilz.Dalamud.ActivityContexts;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.ActivityContexts
|
public class ActivityContext
|
||||||
{
|
{
|
||||||
public class ActivityContext
|
public ActivityType ActivityType { get; init; }
|
||||||
|
public ZoneType ZoneType { get; init; }
|
||||||
|
|
||||||
|
public ActivityContext(ActivityType activityType, ZoneType zoneType)
|
||||||
{
|
{
|
||||||
public ActivityType ActivityType { get; init; }
|
ActivityType = activityType;
|
||||||
public ZoneType ZoneType { get; init; }
|
ZoneType = zoneType;
|
||||||
|
}
|
||||||
|
|
||||||
public ActivityContext(ActivityType activityType, ZoneType zoneType)
|
public bool IsInDuty
|
||||||
{
|
{
|
||||||
ActivityType = activityType;
|
get => ZoneType != ZoneType.Overworld;
|
||||||
ZoneType = zoneType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsInDuty
|
|
||||||
{
|
|
||||||
get => ZoneType != ZoneType.Overworld;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,89 +1,82 @@
|
|||||||
using Dalamud.Logging;
|
using Lumina.Excel;
|
||||||
using Lumina.Excel;
|
using Lumina.Excel.Sheets;
|
||||||
using Lumina.Excel.GeneratedSheets;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.ActivityContexts
|
namespace Pilz.Dalamud.ActivityContexts;
|
||||||
|
|
||||||
|
public class ActivityContextManager : IDisposable
|
||||||
{
|
{
|
||||||
public class ActivityContextManager : IDisposable
|
public delegate void ActivityContextChangedEventHandler(ActivityContextManager sender, ActivityContext activityContext);
|
||||||
|
public event ActivityContextChangedEventHandler ActivityContextChanged;
|
||||||
|
|
||||||
|
private readonly ExcelSheet<ContentFinderCondition> contentFinderConditionsSheet;
|
||||||
|
|
||||||
|
public ActivityContext CurrentActivityContext { get; protected set; }
|
||||||
|
|
||||||
|
public ActivityContextManager()
|
||||||
{
|
{
|
||||||
public delegate void ActivityContextChangedEventHandler(ActivityContextManager sender, ActivityContext activityContext);
|
// Get condition sheet
|
||||||
public event ActivityContextChangedEventHandler ActivityContextChanged;
|
contentFinderConditionsSheet = PluginServices.DataManager.GameData.GetExcelSheet<ContentFinderCondition>();
|
||||||
|
|
||||||
private readonly ExcelSheet<ContentFinderCondition> contentFinderConditionsSheet;
|
// Checks current territory type (if enabled/installed during a dutiy e.g.)
|
||||||
|
CheckCurrentTerritory();
|
||||||
|
|
||||||
public ActivityContext CurrentActivityContext { get; protected set; }
|
// Enable event for automatic checks
|
||||||
|
PluginServices.ClientState.TerritoryChanged += ClientState_TerritoryChanged;
|
||||||
|
}
|
||||||
|
|
||||||
public ActivityContextManager()
|
public void Dispose()
|
||||||
|
{
|
||||||
|
PluginServices.ClientState.TerritoryChanged -= ClientState_TerritoryChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClientState_TerritoryChanged(ushort obj)
|
||||||
|
{
|
||||||
|
CheckCurrentTerritory();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckCurrentTerritory()
|
||||||
|
{
|
||||||
|
var content = contentFinderConditionsSheet.FirstOrDefault(c => c.TerritoryType.RowId == PluginServices.ClientState.TerritoryType);
|
||||||
|
ActivityType newActivityContext;
|
||||||
|
ZoneType newZoneType;
|
||||||
|
|
||||||
|
if (content.RowId == 0)
|
||||||
{
|
{
|
||||||
// Get condition sheet
|
// No content found, so we must be on the overworld
|
||||||
contentFinderConditionsSheet = PluginServices.DataManager.GameData.GetExcelSheet<ContentFinderCondition>();
|
newActivityContext = ActivityType.None;
|
||||||
|
newZoneType = ZoneType.Overworld;
|
||||||
// Checks current territory type (if enabled/installed during a dutiy e.g.)
|
|
||||||
CheckCurrentTerritory();
|
|
||||||
|
|
||||||
// Enable event for automatic checks
|
|
||||||
PluginServices.ClientState.TerritoryChanged += ClientState_TerritoryChanged;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
PluginServices.ClientState.TerritoryChanged -= ClientState_TerritoryChanged;
|
if (content.PvP)
|
||||||
}
|
|
||||||
|
|
||||||
private void ClientState_TerritoryChanged(object? sender, ushort e)
|
|
||||||
{
|
|
||||||
CheckCurrentTerritory();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CheckCurrentTerritory()
|
|
||||||
{
|
|
||||||
var content = contentFinderConditionsSheet.FirstOrDefault(c => c.TerritoryType.Row == PluginServices.ClientState.TerritoryType);
|
|
||||||
ActivityType newActivityContext;
|
|
||||||
ZoneType newZoneType;
|
|
||||||
|
|
||||||
if (content == null)
|
|
||||||
{
|
{
|
||||||
// No content found, so we must be on the overworld
|
newActivityContext = ActivityType.PvpDuty;
|
||||||
newActivityContext = ActivityType.None;
|
newZoneType = ZoneType.Pvp;
|
||||||
newZoneType = ZoneType.Overworld;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (content.PvP)
|
newActivityContext = ActivityType.PveDuty;
|
||||||
{
|
|
||||||
newActivityContext = ActivityType.PvpDuty;
|
|
||||||
newZoneType = ZoneType.Pvp;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newActivityContext = ActivityType.PveDuty;
|
|
||||||
|
|
||||||
// Find correct member type
|
// Find correct member type
|
||||||
var memberType = content.ContentMemberType.Row;
|
var memberType = content.ContentMemberType.RowId;
|
||||||
if (content.RowId == 16 || content.RowId == 15)
|
if (content.RowId == 16 || content.RowId == 15)
|
||||||
memberType = 2; // Praetorium and Castrum Meridianum
|
memberType = 2; // Praetorium and Castrum Meridianum
|
||||||
else if (content.RowId == 735 || content.RowId == 778)
|
else if (content.RowId == 735 || content.RowId == 778)
|
||||||
memberType = 127; // Bozja
|
memberType = 127; // Bozja
|
||||||
|
|
||||||
// Check for ZoneType
|
// Check for ZoneType
|
||||||
newZoneType = memberType switch
|
newZoneType = memberType switch
|
||||||
{
|
{
|
||||||
2 => ZoneType.Doungen,
|
2 => ZoneType.Doungen,
|
||||||
3 => ZoneType.Raid,
|
3 => ZoneType.Raid,
|
||||||
4 => ZoneType.AllianceRaid,
|
4 => ZoneType.AllianceRaid,
|
||||||
127 => ZoneType.Foray,
|
127 => ZoneType.Foray,
|
||||||
_ => ZoneType.Doungen,
|
_ => ZoneType.Doungen,
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentActivityContext = new(newActivityContext, newZoneType);
|
|
||||||
ActivityContextChanged?.Invoke(this, CurrentActivityContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CurrentActivityContext = new(newActivityContext, newZoneType);
|
||||||
|
ActivityContextChanged?.Invoke(this, CurrentActivityContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,12 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.ActivityContexts
|
namespace Pilz.Dalamud.ActivityContexts;
|
||||||
|
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public enum ActivityType
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(StringEnumConverter))]
|
None = 0x0,
|
||||||
public enum ActivityType
|
PveDuty = 0x1,
|
||||||
{
|
PvpDuty = 0x2
|
||||||
None = 0x0,
|
|
||||||
PveDuty = 0x1,
|
|
||||||
PvpDuty = 0x2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,16 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.ActivityContexts
|
namespace Pilz.Dalamud.ActivityContexts;
|
||||||
|
|
||||||
|
[Flags, JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public enum ZoneType
|
||||||
{
|
{
|
||||||
[Flags, JsonConverter(typeof(StringEnumConverter))]
|
Overworld = 1,
|
||||||
public enum ZoneType
|
Doungen = 2,
|
||||||
{
|
Raid = 4,
|
||||||
Overworld = 1,
|
AllianceRaid = 8,
|
||||||
Doungen = 2,
|
Foray = 16,
|
||||||
Raid = 4,
|
Pvp = 32,
|
||||||
AllianceRaid = 8,
|
Everywhere = int.MaxValue
|
||||||
Foray = 16,
|
|
||||||
Pvp = 32,
|
|
||||||
Everywhere = int.MaxValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,44 @@
|
|||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using System;
|
using Lumina.Text.ReadOnly;
|
||||||
using System.Collections.Generic;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud
|
namespace Pilz.Dalamud;
|
||||||
|
|
||||||
|
public static class Extensions
|
||||||
{
|
{
|
||||||
public static class Extensions
|
/// <summary>
|
||||||
|
/// Removes a Payload from a given SeString.
|
||||||
|
/// Using <code>SeString.Payloads.Remove()</code> does not use the reference to compare for some reason. Tis is a workaround.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="seString"></param>
|
||||||
|
/// <param name="payload"></param>
|
||||||
|
public static void Remove(this SeString seString, Payload payload)
|
||||||
{
|
{
|
||||||
/// <summary>
|
Remove(seString.Payloads, payload);
|
||||||
/// Removes a Payload from a given SeString.
|
}
|
||||||
/// Using <code>SeString.Payloads.Remove()</code> does not use the reference to compare for some reason. Tis is a workaround.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="seString"></param>
|
|
||||||
/// <param name="payload"></param>
|
|
||||||
public static void Remove(this SeString seString, Payload payload)
|
|
||||||
{
|
|
||||||
Remove(seString.Payloads, payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes a Payload from a given list.
|
/// Removes a Payload from a given list.
|
||||||
/// Using <code>List.Remove()</code> does not use the reference to compare for some reason. Tis is a workaround.
|
/// Using <code>List.Remove()</code> does not use the reference to compare for some reason. Tis is a workaround.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="seString"></param>
|
/// <param name="payloads"></param>
|
||||||
/// <param name="payload"></param>
|
/// <param name="payload"></param>
|
||||||
public static void Remove(this List<Payload> payloads, Payload payload)
|
public static void Remove(this List<Payload> payloads, Payload payload)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < payloads.Count; i++)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < payloads.Count; i++)
|
if (ReferenceEquals(payloads[i], payload))
|
||||||
{
|
{
|
||||||
if (ReferenceEquals(payloads[i], payload))
|
payloads.RemoveAt(i);
|
||||||
{
|
break;
|
||||||
payloads.RemoveAt(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
public static string ParseString(this ReadOnlySeString readOnlySeString)
|
||||||
|
{
|
||||||
|
return Encoding.UTF8.GetString(readOnlySeString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,153 +1,148 @@
|
|||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using FFXIVClientStructs.FFXIV.Client.System.Memory;
|
using FFXIVClientStructs.FFXIV.Client.System.Memory;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud
|
namespace Pilz.Dalamud;
|
||||||
|
|
||||||
|
public static class GameInterfaceHelper
|
||||||
{
|
{
|
||||||
public static class GameInterfaceHelper
|
public static SeString ReadSeString(IntPtr ptr)
|
||||||
{
|
{
|
||||||
public static SeString ReadSeString(IntPtr ptr)
|
if (ptr == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
if (ptr == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
return new SeString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TryReadStringBytes(ptr, out var bytes) && bytes != null)
|
|
||||||
{
|
|
||||||
return SeString.Parse(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new SeString();
|
return new SeString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryReadSeString(IntPtr ptr, out SeString? seString)
|
if (TryReadStringBytes(ptr, out var bytes) && bytes != null)
|
||||||
{
|
{
|
||||||
seString = null;
|
return SeString.Parse(bytes);
|
||||||
if (ptr == IntPtr.Zero)
|
}
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TryReadStringBytes(ptr, out var bytes) && bytes != null)
|
return new SeString();
|
||||||
{
|
}
|
||||||
seString = SeString.Parse(bytes);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public static bool TryReadSeString(IntPtr ptr, out SeString? seString)
|
||||||
|
{
|
||||||
|
seString = null;
|
||||||
|
if (ptr == IntPtr.Zero)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string? ReadString(IntPtr ptr)
|
if (TryReadStringBytes(ptr, out var bytes) && bytes != null)
|
||||||
{
|
{
|
||||||
if (ptr == IntPtr.Zero)
|
seString = SeString.Parse(bytes);
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TryReadStringBytes(ptr, out var bytes) && bytes != null)
|
|
||||||
{
|
|
||||||
return Encoding.UTF8.GetString(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool TryReadString(IntPtr ptr, out string? str)
|
|
||||||
{
|
|
||||||
str = null;
|
|
||||||
if (ptr == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TryReadStringBytes(ptr, out var bytes) && bytes != null)
|
|
||||||
{
|
|
||||||
str = Encoding.UTF8.GetString(bytes);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool TryReadStringBytes(IntPtr ptr, out byte[]? bytes)
|
|
||||||
{
|
|
||||||
bytes = null;
|
|
||||||
if (ptr == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var size = 0;
|
|
||||||
while (Marshal.ReadByte(ptr, size) != 0)
|
|
||||||
{
|
|
||||||
size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes = new byte[size];
|
|
||||||
Marshal.Copy(ptr, bytes, 0, size);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IntPtr PluginAllocate(byte[] bytes)
|
return false;
|
||||||
{
|
}
|
||||||
IntPtr pointer = Marshal.AllocHGlobal(bytes.Length + 1);
|
|
||||||
Marshal.Copy(bytes, 0, pointer, bytes.Length);
|
|
||||||
Marshal.WriteByte(pointer, bytes.Length, 0);
|
|
||||||
|
|
||||||
return pointer;
|
public static string? ReadString(IntPtr ptr)
|
||||||
|
{
|
||||||
|
if (ptr == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IntPtr PluginAllocate(SeString seString)
|
if (TryReadStringBytes(ptr, out var bytes) && bytes != null)
|
||||||
{
|
{
|
||||||
return PluginAllocate(seString.Encode());
|
return Encoding.UTF8.GetString(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void PluginFree(IntPtr ptr)
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryReadString(IntPtr ptr, out string? str)
|
||||||
|
{
|
||||||
|
str = null;
|
||||||
|
if (ptr == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal(ptr);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void PluginFree(ref IntPtr ptr)
|
if (TryReadStringBytes(ptr, out var bytes) && bytes != null)
|
||||||
{
|
{
|
||||||
PluginFree(ptr);
|
str = Encoding.UTF8.GetString(bytes);
|
||||||
ptr = IntPtr.Zero;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] NullTerminate(this byte[] bytes)
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryReadStringBytes(IntPtr ptr, out byte[]? bytes)
|
||||||
|
{
|
||||||
|
bytes = null;
|
||||||
|
if (ptr == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
if (bytes.Length == 0 || bytes[bytes.Length - 1] != 0)
|
return false;
|
||||||
{
|
|
||||||
var newBytes = new byte[bytes.Length + 1];
|
|
||||||
Array.Copy(bytes, newBytes, bytes.Length);
|
|
||||||
newBytes[^1] = 0;
|
|
||||||
|
|
||||||
return newBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe IntPtr GameUIAllocate(ulong size)
|
var size = 0;
|
||||||
|
while (Marshal.ReadByte(ptr, size) != 0)
|
||||||
{
|
{
|
||||||
return (IntPtr)IMemorySpace.GetUISpace()->Malloc(size, 0);
|
size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe void GameFree(ref IntPtr ptr, ulong size)
|
bytes = new byte[size];
|
||||||
{
|
Marshal.Copy(ptr, bytes, 0, size);
|
||||||
if (ptr == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IMemorySpace.Free((void*)ptr, size);
|
return true;
|
||||||
ptr = IntPtr.Zero;
|
}
|
||||||
|
|
||||||
|
public static IntPtr PluginAllocate(byte[] bytes)
|
||||||
|
{
|
||||||
|
IntPtr pointer = Marshal.AllocHGlobal(bytes.Length + 1);
|
||||||
|
Marshal.Copy(bytes, 0, pointer, bytes.Length);
|
||||||
|
Marshal.WriteByte(pointer, bytes.Length, 0);
|
||||||
|
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntPtr PluginAllocate(SeString seString)
|
||||||
|
{
|
||||||
|
return PluginAllocate(seString.Encode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PluginFree(IntPtr ptr)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PluginFree(ref IntPtr ptr)
|
||||||
|
{
|
||||||
|
PluginFree(ptr);
|
||||||
|
ptr = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] NullTerminate(this byte[] bytes)
|
||||||
|
{
|
||||||
|
if (bytes.Length == 0 || bytes[bytes.Length - 1] != 0)
|
||||||
|
{
|
||||||
|
var newBytes = new byte[bytes.Length + 1];
|
||||||
|
Array.Copy(bytes, newBytes, bytes.Length);
|
||||||
|
newBytes[^1] = 0;
|
||||||
|
|
||||||
|
return newBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe IntPtr GameUIAllocate(ulong size)
|
||||||
|
{
|
||||||
|
return (IntPtr)IMemorySpace.GetUISpace()->Malloc(size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe void GameFree(ref IntPtr ptr, ulong size)
|
||||||
|
{
|
||||||
|
if (ptr == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IMemorySpace.Free((void*)ptr, size);
|
||||||
|
ptr = IntPtr.Zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,19 @@
|
|||||||
using System;
|
namespace Pilz.Dalamud.Icons;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Icons
|
public class JobIconSet
|
||||||
{
|
{
|
||||||
public class JobIconSet
|
private readonly int[] icons;
|
||||||
|
|
||||||
|
public float IconScale { get; init; }
|
||||||
|
|
||||||
|
public JobIconSet(int[] icons, float iconScale)
|
||||||
{
|
{
|
||||||
private readonly int[] icons;
|
this.icons = icons;
|
||||||
|
IconScale = iconScale;
|
||||||
|
}
|
||||||
|
|
||||||
public float IconScale { get; init; }
|
public int GetIcon(uint jobID)
|
||||||
|
{
|
||||||
public JobIconSet(int[] icons, float iconScale)
|
return icons[jobID - 1];
|
||||||
{
|
|
||||||
this.icons = icons;
|
|
||||||
IconScale = iconScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetIcon(uint jobID)
|
|
||||||
{
|
|
||||||
return icons[jobID - 1];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,17 @@
|
|||||||
using System;
|
namespace Pilz.Dalamud.Icons;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Icons
|
public enum JobIconSetName
|
||||||
{
|
{
|
||||||
public enum JobIconSetName
|
Gold,
|
||||||
{
|
Framed,
|
||||||
Gold,
|
Glowing,
|
||||||
Framed,
|
Blue,
|
||||||
Glowing,
|
Red,
|
||||||
Blue,
|
Purple,
|
||||||
Red,
|
Black,
|
||||||
Purple,
|
Yellow,
|
||||||
Black,
|
Orange,
|
||||||
Yellow,
|
Green,
|
||||||
Orange,
|
Grey,
|
||||||
Green,
|
Role
|
||||||
Grey,
|
|
||||||
Role
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,128 +1,132 @@
|
|||||||
using Lumina.Excel.GeneratedSheets;
|
namespace Pilz.Dalamud.Icons;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Icons
|
public class JobIconSets
|
||||||
{
|
{
|
||||||
public class JobIconSets
|
private readonly Dictionary<JobIconSetName, JobIconSet> iconSets = [];
|
||||||
|
|
||||||
|
public JobIconSets()
|
||||||
{
|
{
|
||||||
private readonly Dictionary<JobIconSetName, JobIconSet> iconSets = new();
|
Add(JobIconSetName.Gold,
|
||||||
|
[
|
||||||
|
62001, 62002, 62003, 62004, 62005, 62006, 62007, 62008, 62009, 62010,
|
||||||
|
62011, 62012, 62013, 62014, 62015, 62016, 62017, 62018, 62019, 62020,
|
||||||
|
62021, 62022, 62023, 62024, 62025, 62026, 62027, 62028, 62029, 62030,
|
||||||
|
62031, 62032, 62033, 62034, 62035, 62036, 62037, 62038, 62039, 62040,
|
||||||
|
62041, 62042,
|
||||||
|
], 1);
|
||||||
|
|
||||||
public JobIconSets()
|
Add(JobIconSetName.Framed,
|
||||||
|
[
|
||||||
|
62101, 62102, 62103, 62104, 62105, 62106, 62107, 62108, 62109, 62110,
|
||||||
|
62111, 62112, 62113, 62114, 62115, 62116, 62117, 62118, 62119, 62120,
|
||||||
|
62121, 62122, 62123, 62124, 62125, 62126, 62127, 62128, 62129, 62130,
|
||||||
|
62131, 62132, 62133, 62134, 62135, 62136, 62137, 62138, 62139, 62140,
|
||||||
|
62141, 62142,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Add(JobIconSetName.Glowing,
|
||||||
|
[
|
||||||
|
62301, 62302, 62303, 62304, 62305, 62306, 62307, 62310, 62311, 62312,
|
||||||
|
62313, 62314, 62315, 62316, 62317, 62318, 62319, 62320, 62401, 62402,
|
||||||
|
62403, 62404, 62405, 62406, 62407, 62308, 62408, 62409, 62309, 62410,
|
||||||
|
62411, 62412, 62413, 62414, 62415, 62416, 62417, 62418, 62419, 62420,
|
||||||
|
62421, 62422,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Add(JobIconSetName.Grey,
|
||||||
|
[
|
||||||
|
91022, 91023, 91024, 91025, 91026, 91028, 91029, 91031, 91032, 91033,
|
||||||
|
91034, 91035, 91036, 91037, 91038, 91039, 91040, 91041, 91079, 91080,
|
||||||
|
91081, 91082, 91083, 91084, 91085, 91030, 91086, 91087, 91121, 91122,
|
||||||
|
91125, 91123, 91124, 91127, 91128, 91129, 91130, 91131, 91132, 91133,
|
||||||
|
91185, 91186,
|
||||||
|
], 2);
|
||||||
|
|
||||||
|
Add(JobIconSetName.Black,
|
||||||
|
[
|
||||||
|
91522, 91523, 91524, 91525, 91526, 91528, 91529, 91531, 91532, 91533,
|
||||||
|
91534, 91535, 91536, 91537, 91538, 91539, 91540, 91541, 91579, 91580,
|
||||||
|
91581, 91582, 91583, 91584, 91585, 91530, 91586, 91587, 91621, 91622,
|
||||||
|
91625, 91623, 91624, 91627, 91628, 91629, 91630, 91631, 91632, 91633,
|
||||||
|
91685, 91686,
|
||||||
|
], 2);
|
||||||
|
|
||||||
|
Add(JobIconSetName.Yellow,
|
||||||
|
[
|
||||||
|
92022, 92023, 92024, 92025, 92026, 92028, 92029, 92031, 92032, 92033,
|
||||||
|
92034, 92035, 92036, 92037, 92038, 92039, 92040, 92041, 92079, 92080,
|
||||||
|
92081, 92082, 92083, 92084, 92085, 92030, 92086, 92087, 92121, 92122,
|
||||||
|
92125, 92123, 92124, 92127, 92128, 92129, 92130, 92131, 92132, 92133,
|
||||||
|
92185, 92186,
|
||||||
|
], 2);
|
||||||
|
|
||||||
|
Add(JobIconSetName.Orange,
|
||||||
|
[
|
||||||
|
92522, 92523, 92524, 92525, 92526, 92528, 92529, 92531, 92532, 92533,
|
||||||
|
92534, 92535, 92536, 92537, 92538, 92539, 92540, 92541, 92579, 92580,
|
||||||
|
92581, 92582, 92583, 92584, 92585, 92530, 92586, 92587, 92621, 92622,
|
||||||
|
92625, 92623, 92624, 92627, 92628, 92629, 92630, 92631, 92632, 92633,
|
||||||
|
92685, 92686,
|
||||||
|
], 2);
|
||||||
|
|
||||||
|
Add(JobIconSetName.Red,
|
||||||
|
[
|
||||||
|
93022, 93023, 93024, 93025, 93026, 93028, 93029, 93031, 93032, 93033,
|
||||||
|
93034, 93035, 93036, 93037, 93038, 93039, 93040, 93041, 93079, 93080,
|
||||||
|
93081, 93082, 93083, 93084, 93085, 93030, 93086, 93087, 93121, 93122,
|
||||||
|
93125, 93123, 93124, 93127, 93128, 93129, 93130, 93131, 93132, 93133,
|
||||||
|
93185, 93186,
|
||||||
|
], 2);
|
||||||
|
|
||||||
|
Add(JobIconSetName.Purple, icons: new[]
|
||||||
{
|
{
|
||||||
Add(JobIconSetName.Gold, new[]
|
93522, 93523, 93524, 93525, 93526, 93528, 93529, 93531, 93532, 93533,
|
||||||
{
|
93534, 93535, 93536, 93537, 93538, 93539, 93540, 93541, 93579, 93580,
|
||||||
62001, 62002, 62003, 62004, 62005, 62006, 62007, 62008, 62009, 62010,
|
93581, 93582, 93583, 93584, 93585, 93530, 93586, 93587, 93621, 93622,
|
||||||
62011, 62012, 62013, 62014, 62015, 62016, 62017, 62018, 62019, 62020,
|
93625, 93623, 93624, 93627, 93628, 93629, 93630, 93631, 93632, 93633,
|
||||||
62021, 62022, 62023, 62024, 62025, 62026, 62027, 62028, 62029, 62030,
|
93685, 93686,
|
||||||
62031, 62032, 62033, 62034, 62035, 62036, 62037, 62038, 62039, 62040
|
}, scale: 2);
|
||||||
}, 1);
|
|
||||||
|
|
||||||
Add(JobIconSetName.Framed, new[]
|
Add(JobIconSetName.Blue,
|
||||||
{
|
[
|
||||||
62101, 62102, 62103, 62104, 62105, 62106, 62107, 62108, 62109, 62110,
|
94022, 94023, 94024, 94025, 94026, 94028, 94029, 94031, 94032, 94033,
|
||||||
62111, 62112, 62113, 62114, 62115, 62116, 62117, 62118, 62119, 62120,
|
94034, 94035, 94036, 94037, 94038, 94039, 94040, 94041, 94079, 94080,
|
||||||
62121, 62122, 62123, 62124, 62125, 62126, 62127, 62128, 62129, 62130,
|
94081, 94082, 94083, 94084, 94085, 94030, 94086, 94087, 94121, 94122,
|
||||||
62131, 62132, 62133, 62134, 62135, 62136, 62137, 62138, 62139, 62140
|
94125, 94123, 94124, 94127, 94128, 94129, 94130, 94131, 94132, 94133,
|
||||||
});
|
94185, 94186,
|
||||||
|
], 2);
|
||||||
|
|
||||||
Add(JobIconSetName.Glowing, new[]
|
Add(JobIconSetName.Green,
|
||||||
{
|
[
|
||||||
62301, 62302, 62303, 62304, 62305, 62306, 62307, 62310, 62311, 62312,
|
94522, 94523, 94524, 94525, 94526, 94528, 94529, 94531, 94532, 94533,
|
||||||
62313, 62314, 62315, 62316, 62317, 62318, 62319, 62320, 62401, 62402,
|
94534, 94535, 94536, 94537, 94538, 94539, 94540, 94541, 94579, 94580,
|
||||||
62403, 62404, 62405, 62406, 62407, 62308, 62408, 62409, 62309, 62410,
|
94581, 94582, 94583, 94584, 94585, 94530, 94586, 94587, 94621, 94622,
|
||||||
62411, 62412, 62413, 62414, 62415, 62416, 62417, 62418, 62419, 62420
|
94625, 94623, 94624, 94627, 94628, 94629, 94630, 94631, 94632, 94633,
|
||||||
});
|
94685, 94686,
|
||||||
|
], 2);
|
||||||
|
|
||||||
Add(JobIconSetName.Grey, new[]
|
Add(JobIconSetName.Role,
|
||||||
{
|
[
|
||||||
91022, 91023, 91024, 91025, 91026, 91028, 91029, 91031, 91032, 91033,
|
62581, 62584, 62581, 62584, 62586, 62582, 62502, 62502, 62503, 62504,
|
||||||
91034, 91035, 91036, 91037, 91038, 91039, 91040, 91041, 91079, 91080,
|
62505, 62506, 62507, 62508, 62509, 62510, 62511, 62512, 62581, 62584,
|
||||||
91081, 91082, 91083, 91084, 91085, 91030, 91086, 91087, 91121, 91122,
|
62581, 62584, 62586, 62582, 62587, 62587, 62587, 62582, 62584, 62584,
|
||||||
91125, 91123, 91124, 91127, 91128, 91129, 91130, 91131, 91132, 91133
|
62586, 62581, 62582, 62584, 62587, 62587, 62581, 62586, 62584, 62582,
|
||||||
}, 2);
|
62584, 62584,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
Add(JobIconSetName.Black, new[]
|
private void Add(JobIconSetName id, int[] icons, float scale = 1f)
|
||||||
{
|
{
|
||||||
91522, 91523, 91524, 91525, 91526, 91528, 91529, 91531, 91532, 91533,
|
iconSets[id] = new JobIconSet(icons, scale);
|
||||||
91534, 91535, 91536, 91537, 91538, 91539, 91540, 91541, 91579, 91580,
|
}
|
||||||
91581, 91582, 91583, 91584, 91585, 91530, 91586, 91587, 91621, 91622,
|
|
||||||
91625, 91623, 91624, 91627, 91628, 91629, 91630, 91631, 91632, 91633
|
|
||||||
}, 2);
|
|
||||||
|
|
||||||
Add(JobIconSetName.Yellow, new[]
|
public int GetJobIcon(JobIconSetName set, uint jobId)
|
||||||
{
|
{
|
||||||
92022, 92023, 92024, 92025, 92026, 92028, 92029, 92031, 92032, 92033,
|
return iconSets[set].GetIcon(jobId);
|
||||||
92034, 92035, 92036, 92037, 92038, 92039, 92040, 92041, 92079, 92080,
|
}
|
||||||
92081, 92082, 92083, 92084, 92085, 92030, 92086, 92087, 92121, 92122,
|
|
||||||
92125, 92123, 92124, 92127, 92128, 92129, 92130, 92131, 92132, 92133
|
|
||||||
}, 2);
|
|
||||||
|
|
||||||
Add(JobIconSetName.Orange, new[]
|
public float GetJobIconSale(JobIconSetName set)
|
||||||
{
|
{
|
||||||
92522, 92523, 92524, 92525, 92526, 92528, 92529, 92531, 92532, 92533,
|
return iconSets[set].IconScale;
|
||||||
92534, 92535, 92536, 92537, 92538, 92539, 92540, 92541, 92579, 92580,
|
|
||||||
92581, 92582, 92583, 92584, 92585, 92530, 92586, 92587, 92621, 92622,
|
|
||||||
92625, 92623, 92624, 92627, 92628, 92629, 92630, 92631, 92632, 92633
|
|
||||||
}, 2);
|
|
||||||
|
|
||||||
Add(JobIconSetName.Red, new[]
|
|
||||||
{
|
|
||||||
93022, 93023, 93024, 93025, 93026, 93028, 93029, 93031, 93032, 93033,
|
|
||||||
93034, 93035, 93036, 93037, 93038, 93039, 93040, 93041, 93079, 93080,
|
|
||||||
93081, 93082, 93083, 93084, 93085, 93030, 93086, 93087, 93121, 93122,
|
|
||||||
93125, 93123, 93124, 93127, 93128, 93129, 93130, 93131, 93132, 93133
|
|
||||||
}, 2);
|
|
||||||
|
|
||||||
Add(JobIconSetName.Purple, new[]
|
|
||||||
{
|
|
||||||
93522, 93523, 93524, 93525, 93526, 93528, 93529, 93531, 93532, 93533,
|
|
||||||
93534, 93535, 93536, 93537, 93538, 93539, 93540, 93541, 93579, 93580,
|
|
||||||
93581, 93582, 93583, 93584, 93585, 93530, 93586, 93587, 93621, 93622,
|
|
||||||
93625, 93623, 93624, 93627, 93628, 93629, 93630, 93631, 93632, 93633
|
|
||||||
}, 2);
|
|
||||||
|
|
||||||
Add(JobIconSetName.Blue, new[]
|
|
||||||
{
|
|
||||||
94022, 94023, 94024, 94025, 94026, 94028, 94029, 94031, 94032, 94033,
|
|
||||||
94034, 94035, 94036, 94037, 94038, 94039, 94040, 94041, 94079, 94080,
|
|
||||||
94081, 94082, 94083, 94084, 94085, 94030, 94086, 94087, 94121, 94122,
|
|
||||||
94125, 94123, 94124, 94127, 94128, 94129, 94130, 94131, 94132, 94133
|
|
||||||
}, 2);
|
|
||||||
|
|
||||||
Add(JobIconSetName.Green, new[]
|
|
||||||
{
|
|
||||||
94522, 94523, 94524, 94525, 94526, 94528, 94529, 94531, 94532, 94533,
|
|
||||||
94534, 94535, 94536, 94537, 94538, 94539, 94540, 94541, 94579, 94580,
|
|
||||||
94581, 94582, 94583, 94584, 94585, 94530, 94586, 94587, 94621, 94622,
|
|
||||||
94625, 94623, 94624, 94627, 94628, 94629, 94630, 94631, 94632, 94633
|
|
||||||
}, 2);
|
|
||||||
|
|
||||||
Add(JobIconSetName.Role, new[]
|
|
||||||
{
|
|
||||||
62581, 62584, 62581, 62584, 62586, 62582, 62502, 62502, 62503, 62504,
|
|
||||||
62505, 62506, 62507, 62508, 62509, 62510, 62511, 62512, 62581, 62584,
|
|
||||||
62581, 62584, 62586, 62582, 62587, 62587, 62587, 62582, 62584, 62584,
|
|
||||||
62586, 62581, 62582, 62584, 62587, 62587, 62581, 62586, 62584, 62582
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Add(JobIconSetName id, int[] icons, float scale = 1f)
|
|
||||||
{
|
|
||||||
iconSets[id] = new JobIconSet(icons, scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetJobIcon(JobIconSetName set, uint jobId)
|
|
||||||
{
|
|
||||||
return iconSets[set].GetIcon(jobId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public float GetJobIconSale(JobIconSetName set)
|
|
||||||
{
|
|
||||||
return iconSets[set].IconScale;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
25
Pilz.Dalamud/Icons/StatusIcons.cs
Normal file
25
Pilz.Dalamud/Icons/StatusIcons.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
|
namespace Pilz.Dalamud.Icons;
|
||||||
|
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public enum StatusIcons
|
||||||
|
{
|
||||||
|
Disconnecting = 061503,
|
||||||
|
InDuty = 061506,
|
||||||
|
ViewingCutscene = 061508,
|
||||||
|
Busy = 061509,
|
||||||
|
Idle = 061511,
|
||||||
|
DutyFinder = 061517,
|
||||||
|
PartyLeader = 061521,
|
||||||
|
PartyMember = 061522,
|
||||||
|
RolePlaying = 061545,
|
||||||
|
GroupPose = 061546,
|
||||||
|
NewAdventurer = 061523,
|
||||||
|
Mentor = 061540,
|
||||||
|
MentorPvE = 061542,
|
||||||
|
MentorCrafting = 061543,
|
||||||
|
MentorPvP = 061544,
|
||||||
|
Returner = 061547,
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.EventArgs
|
|
||||||
{
|
|
||||||
public class AddonNamePlate_SetPlayerNameEventArgs : HookWithResultBaseEventArgs<IntPtr>
|
|
||||||
{
|
|
||||||
public IntPtr PlayerNameplateObjectPtr { get; set; }
|
|
||||||
public IntPtr TitlePtr { get; set; }
|
|
||||||
public IntPtr NamePtr { get; set; }
|
|
||||||
public IntPtr FreeCompanyPtr { get; set; }
|
|
||||||
public IntPtr PrefixPtr { get; set; }
|
|
||||||
public bool IsTitleAboveName { get; set; }
|
|
||||||
public bool IsTitleVisible { get; set; }
|
|
||||||
public int IconID { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
using Dalamud.Game.Text.SeStringHandling;
|
|
||||||
using Pilz.Dalamud.Nameplates.Model;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.EventArgs
|
|
||||||
{
|
|
||||||
public class AddonNamePlate_SetPlayerNameManagedEventArgs : HookWithResultManagedBaseEventArgs<IntPtr>
|
|
||||||
{
|
|
||||||
public new AddonNamePlate_SetPlayerNameEventArgs OriginalEventArgs
|
|
||||||
{
|
|
||||||
get => base.OriginalEventArgs as AddonNamePlate_SetPlayerNameEventArgs;
|
|
||||||
set => base.OriginalEventArgs = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SafeNameplateObject SafeNameplateObject { get; set; }
|
|
||||||
public SeString Title { get; internal set; }
|
|
||||||
public SeString Name { get; internal set; }
|
|
||||||
public SeString FreeCompany { get; internal set; }
|
|
||||||
public SeString Prefix { get; internal set; }
|
|
||||||
|
|
||||||
public bool IsTitleAboveName
|
|
||||||
{
|
|
||||||
get => OriginalEventArgs.IsTitleAboveName;
|
|
||||||
set => OriginalEventArgs.IsTitleAboveName = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsTitleVisible
|
|
||||||
{
|
|
||||||
get => OriginalEventArgs.IsTitleVisible;
|
|
||||||
set => OriginalEventArgs.IsTitleVisible = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int IconID
|
|
||||||
{
|
|
||||||
get => OriginalEventArgs.IconID;
|
|
||||||
set => OriginalEventArgs.IconID = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.EventArgs
|
|
||||||
{
|
|
||||||
public abstract class HookBaseEventArgs
|
|
||||||
{
|
|
||||||
internal event Action CallOriginal;
|
|
||||||
|
|
||||||
public void Original()
|
|
||||||
{
|
|
||||||
CallOriginal?.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.EventArgs
|
|
||||||
{
|
|
||||||
public abstract class HookManagedBaseEventArgs
|
|
||||||
{
|
|
||||||
public HookBaseEventArgs OriginalEventArgs { get; internal set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.EventArgs
|
|
||||||
{
|
|
||||||
public abstract class HookWithResultBaseEventArgs<TResult>
|
|
||||||
{
|
|
||||||
internal event Func<TResult> CallOriginal;
|
|
||||||
|
|
||||||
public TResult Result { get; set; }
|
|
||||||
|
|
||||||
// Call Original based on the given properties
|
|
||||||
public TResult Original()
|
|
||||||
{
|
|
||||||
return CallOriginal.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.EventArgs
|
|
||||||
{
|
|
||||||
public abstract class HookWithResultManagedBaseEventArgs<TResult>
|
|
||||||
{
|
|
||||||
public HookWithResultBaseEventArgs<TResult> OriginalEventArgs { get; internal set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
using Dalamud.Logging;
|
|
||||||
using Dalamud.Plugin;
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.Model
|
|
||||||
{
|
|
||||||
public class SafeAddonNameplate
|
|
||||||
{
|
|
||||||
private readonly DalamudPluginInterface Interface;
|
|
||||||
|
|
||||||
public IntPtr Pointer => PluginServices.GameGui.GetAddonByName("NamePlate", 1);
|
|
||||||
|
|
||||||
public SafeAddonNameplate(DalamudPluginInterface pluginInterface)
|
|
||||||
{
|
|
||||||
Interface = pluginInterface;
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe SafeNameplateObject GetNamePlateObject(int index)
|
|
||||||
{
|
|
||||||
SafeNameplateObject result = null;
|
|
||||||
|
|
||||||
if (Pointer != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
var npObjectArrayPtrPtr = Pointer + Marshal.OffsetOf(typeof(AddonNamePlate), nameof(AddonNamePlate.NamePlateObjectArray)).ToInt32();
|
|
||||||
var npObjectArrayPtr = Marshal.ReadIntPtr(npObjectArrayPtrPtr);
|
|
||||||
|
|
||||||
if (npObjectArrayPtr != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
var npObjectPtr = npObjectArrayPtr + Marshal.SizeOf(typeof(AddonNamePlate.NamePlateObject)) * index;
|
|
||||||
result = new(npObjectPtr, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
using FFXIVClientStructs.FFXIV.Client.System.String;
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.Model
|
|
||||||
{
|
|
||||||
public class SafeNameplateInfo
|
|
||||||
{
|
|
||||||
public readonly IntPtr Pointer;
|
|
||||||
public readonly RaptureAtkModule.NamePlateInfo Data;
|
|
||||||
|
|
||||||
public SafeNameplateInfo(IntPtr pointer)
|
|
||||||
{
|
|
||||||
Pointer = pointer;
|
|
||||||
Data = Marshal.PtrToStructure<RaptureAtkModule.NamePlateInfo>(Pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal IntPtr NameAddress => GetStringPtr(nameof(RaptureAtkModule.NamePlateInfo.Name));
|
|
||||||
internal IntPtr FcNameAddress => GetStringPtr(nameof(RaptureAtkModule.NamePlateInfo.FcName));
|
|
||||||
internal IntPtr TitleAddress => GetStringPtr(nameof(RaptureAtkModule.NamePlateInfo.Title));
|
|
||||||
internal IntPtr DisplayTitleAddress => GetStringPtr(nameof(RaptureAtkModule.NamePlateInfo.DisplayTitle));
|
|
||||||
internal IntPtr LevelTextAddress => GetStringPtr(nameof(RaptureAtkModule.NamePlateInfo.LevelText));
|
|
||||||
|
|
||||||
public string Name => GetString(NameAddress);
|
|
||||||
public string FcName => GetString(FcNameAddress);
|
|
||||||
public string Title => GetString(TitleAddress);
|
|
||||||
public string DisplayTitle => GetString(DisplayTitleAddress);
|
|
||||||
public string LevelText => GetString(LevelTextAddress);
|
|
||||||
|
|
||||||
//public bool IsPlayerCharacter() => XivApi.IsPlayerCharacter(Data.ObjectID.ObjectID);
|
|
||||||
|
|
||||||
//public bool IsPartyMember() => XivApi.IsPartyMember(Data.ObjectID.ObjectID);
|
|
||||||
|
|
||||||
//public bool IsAllianceMember() => XivApi.IsAllianceMember(Data.ObjectID.ObjectID);
|
|
||||||
|
|
||||||
//public uint GetJobID() => GetJobId(Data.ObjectID.ObjectID);
|
|
||||||
|
|
||||||
private unsafe IntPtr GetStringPtr(string name)
|
|
||||||
{
|
|
||||||
var namePtr = Pointer + Marshal.OffsetOf(typeof(RaptureAtkModule.NamePlateInfo), name).ToInt32();
|
|
||||||
var stringPtrPtr = namePtr + Marshal.OffsetOf(typeof(Utf8String), nameof(Utf8String.StringPtr)).ToInt32();
|
|
||||||
var stringPtr = Marshal.ReadIntPtr(stringPtrPtr);
|
|
||||||
return stringPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetString(IntPtr stringPtr)
|
|
||||||
{
|
|
||||||
return Marshal.PtrToStringUTF8(stringPtr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
using Dalamud.Logging;
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
|
||||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.Model
|
|
||||||
{
|
|
||||||
public class SafeNameplateObject
|
|
||||||
{
|
|
||||||
public IntPtr Pointer { get; }
|
|
||||||
public AddonNamePlate.NamePlateObject Data { get; }
|
|
||||||
|
|
||||||
private int _Index;
|
|
||||||
private SafeNameplateInfo _NamePlateInfo;
|
|
||||||
|
|
||||||
public SafeNameplateObject(IntPtr pointer, int index = -1)
|
|
||||||
{
|
|
||||||
Pointer = pointer;
|
|
||||||
Data = Marshal.PtrToStructure<AddonNamePlate.NamePlateObject>(pointer);
|
|
||||||
_Index = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Index
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
int result = _Index;
|
|
||||||
|
|
||||||
if (_Index == -1)
|
|
||||||
{
|
|
||||||
var addon = XivApi.GetSafeAddonNamePlate();
|
|
||||||
var npObject0 = addon.GetNamePlateObject(0);
|
|
||||||
|
|
||||||
if (npObject0 == null)
|
|
||||||
result = -1; // NamePlateObject0 was null
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var npObjectBase = npObject0.Pointer;
|
|
||||||
var npObjectSize = Marshal.SizeOf(typeof(AddonNamePlate.NamePlateObject));
|
|
||||||
var index = (Pointer.ToInt64() - npObjectBase.ToInt64()) / npObjectSize;
|
|
||||||
|
|
||||||
if (index < 0 || index >= 50)
|
|
||||||
result = -2; // NamePlateObject index was out of bounds
|
|
||||||
else
|
|
||||||
result = _Index = (int)index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public SafeNameplateInfo NamePlateInfo
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
SafeNameplateInfo result = null;
|
|
||||||
|
|
||||||
if (_NamePlateInfo != null)
|
|
||||||
{
|
|
||||||
var rapturePtr = XivApi.RaptureAtkModulePtr;
|
|
||||||
|
|
||||||
if (rapturePtr != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
var npInfoArrayPtr = rapturePtr + Marshal.OffsetOf(typeof(RaptureAtkModule), nameof(RaptureAtkModule.NamePlateInfoArray)).ToInt32();
|
|
||||||
var npInfoPtr = npInfoArrayPtr + Marshal.SizeOf(typeof(RaptureAtkModule.NamePlateInfo)) * Index;
|
|
||||||
result = _NamePlateInfo = new SafeNameplateInfo(npInfoPtr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Getters
|
|
||||||
|
|
||||||
public unsafe IntPtr IconImageNodeAddress => Marshal.ReadIntPtr(Pointer + Marshal.OffsetOf(typeof(AddonNamePlate.NamePlateObject), nameof(AddonNamePlate.NamePlateObject.IconImageNode)).ToInt32());
|
|
||||||
public unsafe IntPtr NameNodeAddress => Marshal.ReadIntPtr(Pointer + Marshal.OffsetOf(typeof(AddonNamePlate.NamePlateObject), nameof(AddonNamePlate.NamePlateObject.NameText)).ToInt32());
|
|
||||||
|
|
||||||
public AtkImageNode IconImageNode => Marshal.PtrToStructure<AtkImageNode>(IconImageNodeAddress);
|
|
||||||
public AtkTextNode NameTextNode => Marshal.PtrToStructure<AtkTextNode>(NameNodeAddress);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public unsafe bool IsVisible => Data.IsVisible;
|
|
||||||
public unsafe bool IsLocalPlayer => Data.IsLocalPlayer;
|
|
||||||
public bool IsPlayer => Data.NameplateKind == 0;
|
|
||||||
|
|
||||||
//public void SetIconScale(float scale, bool force = false)
|
|
||||||
//{
|
|
||||||
// if (force || IconImageNode.AtkResNode.ScaleX != scale || IconImageNode.AtkResNode.ScaleY != scale)
|
|
||||||
// {
|
|
||||||
// Instance.SetNodeScale(IconImageNodeAddress, scale, scale);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public void SetNameScale(float scale, bool force = false)
|
|
||||||
//{
|
|
||||||
// if (force || NameTextNode.AtkResNode.ScaleX != scale || NameTextNode.AtkResNode.ScaleY != scale)
|
|
||||||
// {
|
|
||||||
// Instance.SetNodeScale(NameNodeAddress, scale, scale);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public unsafe void SetName(IntPtr ptr)
|
|
||||||
//{
|
|
||||||
// NameTextNode.SetText("aaa");
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public void SetIcon(int icon)
|
|
||||||
//{
|
|
||||||
// IconImageNode.LoadIconTexture(icon, 1);
|
|
||||||
//}
|
|
||||||
|
|
||||||
public void SetIconPosition(short x, short y)
|
|
||||||
{
|
|
||||||
var iconXAdjustPtr = Pointer + Marshal.OffsetOf(typeof(AddonNamePlate.NamePlateObject), nameof(AddonNamePlate.NamePlateObject.IconXAdjust)).ToInt32();
|
|
||||||
var iconYAdjustPtr = Pointer + Marshal.OffsetOf(typeof(AddonNamePlate.NamePlateObject), nameof(AddonNamePlate.NamePlateObject.IconYAdjust)).ToInt32();
|
|
||||||
Marshal.WriteInt16(iconXAdjustPtr, x);
|
|
||||||
Marshal.WriteInt16(iconYAdjustPtr, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Converters;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.Model
|
|
||||||
{
|
|
||||||
[JsonConverter(typeof(StringEnumConverter))]
|
|
||||||
public enum StatusIcons
|
|
||||||
{
|
|
||||||
Disconnecting = 061503,
|
|
||||||
InDuty = 061506,
|
|
||||||
ViewingCutscene = 061508,
|
|
||||||
Busy = 061509,
|
|
||||||
Idle = 061511,
|
|
||||||
DutyFinder = 061517,
|
|
||||||
PartyLeader = 061521,
|
|
||||||
PartyMember = 061522,
|
|
||||||
RolePlaying = 061545,
|
|
||||||
GroupPose = 061546,
|
|
||||||
NewAdventurer = 061523,
|
|
||||||
Mentor = 061540,
|
|
||||||
MentorPvE = 061542,
|
|
||||||
MentorCrafting = 061543,
|
|
||||||
MentorPvP = 061544,
|
|
||||||
Returner = 061547,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,218 +0,0 @@
|
|||||||
using Dalamud.Hooking;
|
|
||||||
using Pilz.Dalamud.Nameplates.EventArgs;
|
|
||||||
using Dalamud.Utility.Signatures;
|
|
||||||
using ImGuiNET;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Pilz.Dalamud.Nameplates.Model;
|
|
||||||
using Lumina.Excel.GeneratedSheets;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates
|
|
||||||
{
|
|
||||||
public class NameplateHooks : IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Will be executed when the the Game wants to update the content of a nameplate with the details of the Player.
|
|
||||||
/// </summary>
|
|
||||||
public event AddonNamePlate_SetPlayerNameEventHandler AddonNamePlate_SetPlayerName;
|
|
||||||
public delegate void AddonNamePlate_SetPlayerNameEventHandler(AddonNamePlate_SetPlayerNameEventArgs eventArgs);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Will be executed when the the Game wants to update the content of a nameplate with the details of the Player.
|
|
||||||
/// This will event acts on a higher level with SeString instead of IntPtr e.g.
|
|
||||||
/// </summary>
|
|
||||||
public event AddonNamePlate_SetPlayerNameManagedEventHandler AddonNamePlate_SetPlayerNameManaged;
|
|
||||||
public delegate void AddonNamePlate_SetPlayerNameManagedEventHandler(AddonNamePlate_SetPlayerNameManagedEventArgs eventArgs);
|
|
||||||
|
|
||||||
[Signature("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 48 8B 5C 24 ?? 45 38 BE", DetourName = nameof(SetPlayerNameplateDetour))]
|
|
||||||
private Hook<AddonNamePlate_SetPlayerNameplateDetour>? hook_AddonNamePlate_SetPlayerNameplateDetour = null;
|
|
||||||
private unsafe delegate IntPtr AddonNamePlate_SetPlayerNameplateDetour(IntPtr playerNameplateObjectPtr, bool isTitleAboveName, bool isTitleVisible, IntPtr titlePtr, IntPtr namePtr, IntPtr freeCompanyPtr, IntPtr prefix, int iconId);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines if all hooks are enabled. If this is false, then there might be something wrong or the class already has been disposed.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsValid
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var isValid = true;
|
|
||||||
|
|
||||||
isValid &= IsHookEnabled(hook_AddonNamePlate_SetPlayerNameplateDetour);
|
|
||||||
|
|
||||||
return isValid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new instance of NAmeplateHooks and automatically initialize and enable all Hooks.
|
|
||||||
/// </summary>
|
|
||||||
public NameplateHooks()
|
|
||||||
{
|
|
||||||
SignatureHelper.Initialise(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
~NameplateHooks()
|
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Unhook();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initialize and enable all Hooks.
|
|
||||||
/// </summary>
|
|
||||||
internal void Initialize()
|
|
||||||
{
|
|
||||||
hook_AddonNamePlate_SetPlayerNameplateDetour?.Enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disable all Hooks.
|
|
||||||
/// </summary>
|
|
||||||
internal void Unhook()
|
|
||||||
{
|
|
||||||
hook_AddonNamePlate_SetPlayerNameplateDetour?.Disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsHookEnabled<T>(Hook<T> hook) where T : Delegate
|
|
||||||
{
|
|
||||||
return hook != null && hook.IsEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IntPtr SetPlayerNameplateDetour(IntPtr playerNameplateObjectPtr, bool isTitleAboveName, bool isTitleVisible, IntPtr titlePtr, IntPtr namePtr, IntPtr freeCompanyPtr, IntPtr prefix, int iconId)
|
|
||||||
{
|
|
||||||
var result = IntPtr.Zero;
|
|
||||||
|
|
||||||
if (IsHookEnabled(hook_AddonNamePlate_SetPlayerNameplateDetour))
|
|
||||||
{
|
|
||||||
var eventArgs = new AddonNamePlate_SetPlayerNameEventArgs
|
|
||||||
{
|
|
||||||
PlayerNameplateObjectPtr = playerNameplateObjectPtr,
|
|
||||||
TitlePtr = titlePtr,
|
|
||||||
NamePtr = namePtr,
|
|
||||||
FreeCompanyPtr = freeCompanyPtr,
|
|
||||||
PrefixPtr = prefix,
|
|
||||||
IsTitleAboveName = isTitleAboveName,
|
|
||||||
IsTitleVisible = isTitleVisible,
|
|
||||||
IconID = iconId
|
|
||||||
};
|
|
||||||
|
|
||||||
void callOriginal()
|
|
||||||
{
|
|
||||||
eventArgs.Result = eventArgs.Original();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add handler for the Original call
|
|
||||||
eventArgs.CallOriginal += () =>
|
|
||||||
{
|
|
||||||
return hook_AddonNamePlate_SetPlayerNameplateDetour.Original(
|
|
||||||
eventArgs.PlayerNameplateObjectPtr,
|
|
||||||
eventArgs.IsTitleAboveName,
|
|
||||||
eventArgs.IsTitleVisible,
|
|
||||||
eventArgs.TitlePtr,
|
|
||||||
eventArgs.NamePtr,
|
|
||||||
eventArgs.FreeCompanyPtr,
|
|
||||||
prefix,
|
|
||||||
eventArgs.IconID);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Invoke Event
|
|
||||||
var hasDefaultHookEvent = AddonNamePlate_SetPlayerName != null;
|
|
||||||
AddonNamePlate_SetPlayerName?.Invoke(eventArgs);
|
|
||||||
|
|
||||||
if (AddonNamePlate_SetPlayerNameManaged != null)
|
|
||||||
{
|
|
||||||
var freeTitle = false;
|
|
||||||
var freeName = false;
|
|
||||||
var freeFreeCompany = false;
|
|
||||||
var freePrefix = false;
|
|
||||||
|
|
||||||
// Create NamePlateObject if possible
|
|
||||||
var namePlateObj = new SafeNameplateObject(playerNameplateObjectPtr);
|
|
||||||
|
|
||||||
// Create new event
|
|
||||||
var managedEventArgs = new AddonNamePlate_SetPlayerNameManagedEventArgs
|
|
||||||
{
|
|
||||||
OriginalEventArgs = eventArgs,
|
|
||||||
SafeNameplateObject = namePlateObj,
|
|
||||||
Title = GameInterfaceHelper.ReadSeString(eventArgs.TitlePtr),
|
|
||||||
Name = GameInterfaceHelper.ReadSeString(eventArgs.NamePtr),
|
|
||||||
FreeCompany = GameInterfaceHelper.ReadSeString(eventArgs.FreeCompanyPtr),
|
|
||||||
Prefix = GameInterfaceHelper.ReadSeString(eventArgs.PrefixPtr)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get raw string content
|
|
||||||
var titleRaw = managedEventArgs.Title.Encode();
|
|
||||||
var nameRaw = managedEventArgs.Name.Encode();
|
|
||||||
var freeCompanyRaw = managedEventArgs.FreeCompany.Encode();
|
|
||||||
var prefixRaw = managedEventArgs.Prefix.Encode();
|
|
||||||
|
|
||||||
// Invoke Managed Event
|
|
||||||
AddonNamePlate_SetPlayerNameManaged.Invoke(managedEventArgs);
|
|
||||||
|
|
||||||
// Get new Title string content
|
|
||||||
var titleNewRaw = managedEventArgs.Title.Encode();
|
|
||||||
if (!titleRaw.SequenceEqual(titleNewRaw))
|
|
||||||
{
|
|
||||||
eventArgs.TitlePtr = GameInterfaceHelper.PluginAllocate(titleNewRaw);
|
|
||||||
freeTitle = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get new Name string content
|
|
||||||
var nameNewRaw = managedEventArgs.Name.Encode();
|
|
||||||
if (!nameRaw.SequenceEqual(nameNewRaw))
|
|
||||||
{
|
|
||||||
eventArgs.NamePtr = GameInterfaceHelper.PluginAllocate(nameNewRaw);
|
|
||||||
freeName = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get new Free Company string content
|
|
||||||
var freeCompanyNewRaw = managedEventArgs.FreeCompany.Encode();
|
|
||||||
if (!freeCompanyRaw.SequenceEqual(freeCompanyNewRaw))
|
|
||||||
{
|
|
||||||
eventArgs.FreeCompanyPtr = GameInterfaceHelper.PluginAllocate(freeCompanyNewRaw);
|
|
||||||
freeFreeCompany = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get new Prefix string content
|
|
||||||
var prefixNewRaw = managedEventArgs.Prefix.Encode();
|
|
||||||
if (!prefixRaw.SequenceEqual(prefixNewRaw))
|
|
||||||
{
|
|
||||||
eventArgs.PrefixPtr = GameInterfaceHelper.PluginAllocate(prefixNewRaw);
|
|
||||||
freePrefix = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call Original as we changed something
|
|
||||||
callOriginal();
|
|
||||||
|
|
||||||
// Free memory
|
|
||||||
if (freeTitle)
|
|
||||||
GameInterfaceHelper.PluginFree(eventArgs.TitlePtr);
|
|
||||||
if (freeName)
|
|
||||||
GameInterfaceHelper.PluginFree(eventArgs.NamePtr);
|
|
||||||
if (freeFreeCompany)
|
|
||||||
GameInterfaceHelper.PluginFree(eventArgs.FreeCompanyPtr);
|
|
||||||
if (freePrefix)
|
|
||||||
GameInterfaceHelper.PluginFree(eventArgs.PrefixPtr);
|
|
||||||
}
|
|
||||||
else if(!hasDefaultHookEvent)
|
|
||||||
{
|
|
||||||
// Call original in case of nothing get called, just to get secure it will not break the game when not calling it.
|
|
||||||
callOriginal();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set result
|
|
||||||
result = eventArgs.Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
using Dalamud.Hooking;
|
|
||||||
using Pilz.Dalamud.Nameplates.EventArgs;
|
|
||||||
using Dalamud.Utility.Signatures;
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
|
||||||
using Pilz.Dalamud.Nameplates.Model;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates
|
|
||||||
{
|
|
||||||
public class NameplateManager : IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Provides events that you can hook to.
|
|
||||||
/// </summary>
|
|
||||||
public NameplateHooks Hooks { get; init; } = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines if all hooks are enabled and the NameplateManager is ready to go. If this is false, then there might be something wrong or something already has been disposed.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsValid => Hooks.IsValid;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the NameplateManager.
|
|
||||||
/// </summary>
|
|
||||||
public NameplateManager()
|
|
||||||
{
|
|
||||||
Hooks.Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
~NameplateManager()
|
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Hooks?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T? GetNameplateGameObject<T>(SafeNameplateObject namePlateObject) where T : GameObject
|
|
||||||
{
|
|
||||||
return GetNameplateGameObject<T>(namePlateObject.Pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T? GetNameplateGameObject<T>(IntPtr nameplateObjectPtr) where T : GameObject
|
|
||||||
{
|
|
||||||
// Get the nameplate object array
|
|
||||||
var nameplateAddonPtr = PluginServices.GameGui.GetAddonByName("NamePlate", 1);
|
|
||||||
var nameplateObjectArrayPtrPtr = nameplateAddonPtr + Marshal.OffsetOf(typeof(AddonNamePlate), nameof(AddonNamePlate.NamePlateObjectArray)).ToInt32();
|
|
||||||
var nameplateObjectArrayPtr = Marshal.ReadIntPtr(nameplateObjectArrayPtrPtr);
|
|
||||||
if (nameplateObjectArrayPtr == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the index of the nameplate object within the nameplate object array
|
|
||||||
var namePlateObjectSize = Marshal.SizeOf(typeof(AddonNamePlate.NamePlateObject));
|
|
||||||
var namePlateObjectPtr0 = nameplateObjectArrayPtr + namePlateObjectSize * 0;
|
|
||||||
var namePlateIndex = (nameplateObjectPtr.ToInt64() - namePlateObjectPtr0.ToInt64()) / namePlateObjectSize;
|
|
||||||
if (namePlateIndex < 0 || namePlateIndex >= AddonNamePlate.NumNamePlateObjects)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the nameplate info array
|
|
||||||
IntPtr nameplateInfoArrayPtr = IntPtr.Zero;
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
var framework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework.Instance();
|
|
||||||
nameplateInfoArrayPtr = new IntPtr(&framework->GetUiModule()->GetRaptureAtkModule()->NamePlateInfoArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the nameplate info for the nameplate object
|
|
||||||
var namePlateInfoPtr = new IntPtr(nameplateInfoArrayPtr.ToInt64() + Marshal.SizeOf(typeof(RaptureAtkModule.NamePlateInfo)) * namePlateIndex);
|
|
||||||
RaptureAtkModule.NamePlateInfo namePlateInfo = Marshal.PtrToStructure<RaptureAtkModule.NamePlateInfo>(namePlateInfoPtr);
|
|
||||||
|
|
||||||
// Return the object for its object id
|
|
||||||
var objectId = namePlateInfo.ObjectID.ObjectID;
|
|
||||||
return PluginServices.ObjectTable.SearchById(objectId) as T;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Pilz.Dalamud.Nameplates.EventArgs;
|
|
||||||
using Pilz.Dalamud.Tools.Strings;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.Tools
|
|
||||||
{
|
|
||||||
public class NameplateChanges
|
|
||||||
{
|
|
||||||
private readonly Dictionary<NameplateElements, StringChangesProps> changes = new();
|
|
||||||
|
|
||||||
public NameplateChanges()
|
|
||||||
{
|
|
||||||
changes.Add(NameplateElements.Title, new());
|
|
||||||
changes.Add(NameplateElements.Name, new());
|
|
||||||
changes.Add(NameplateElements.FreeCompany, new());
|
|
||||||
}
|
|
||||||
|
|
||||||
public NameplateChanges(AddonNamePlate_SetPlayerNameManagedEventArgs eventArgs) : this()
|
|
||||||
{
|
|
||||||
GetProps(NameplateElements.Title).Destination = eventArgs.Title;
|
|
||||||
GetProps(NameplateElements.Name).Destination = eventArgs.Name;
|
|
||||||
GetProps(NameplateElements.FreeCompany).Destination = eventArgs.FreeCompany;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the properties with the changes of an element of your choice where you can add your payloads to a change and setup some options.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="element">The position of your choice.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public StringChangesProps GetProps(NameplateElements element)
|
|
||||||
{
|
|
||||||
return changes[element];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the changes of an element of your choice where you can add your payloads to a change.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="element">The position of your choice.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public StringChanges GetChanges(NameplateElements element)
|
|
||||||
{
|
|
||||||
return GetProps(element).StringChanges;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a change of the position of the element of your choice where you can add your payloads.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="element">The position of your choice.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public StringChange GetChange(NameplateElements element, StringPosition position)
|
|
||||||
{
|
|
||||||
return GetChanges(element).GetChange(position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.Tools
|
|
||||||
{
|
|
||||||
public class NameplateChangesProps
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// All the changes to the nameplate that should be made.
|
|
||||||
/// </summary>
|
|
||||||
public NameplateChanges Changes { get; set; }
|
|
||||||
|
|
||||||
public NameplateChangesProps()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public NameplateChangesProps(NameplateChanges changes) : this()
|
|
||||||
{
|
|
||||||
Changes = changes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.Tools
|
|
||||||
{
|
|
||||||
public enum NameplateElements
|
|
||||||
{
|
|
||||||
Name,
|
|
||||||
Title,
|
|
||||||
FreeCompany
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
using Dalamud.Game.Text.SeStringHandling;
|
|
||||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
|
||||||
using Pilz.Dalamud.ActivityContexts;
|
|
||||||
using Pilz.Dalamud.Nameplates.Model;
|
|
||||||
using Pilz.Dalamud.Tools;
|
|
||||||
using Pilz.Dalamud.Tools.Strings;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.Tools
|
|
||||||
{
|
|
||||||
public static class NameplateUpdateFactory
|
|
||||||
{
|
|
||||||
public static void ApplyNameplateChanges(NameplateChangesProps props)
|
|
||||||
{
|
|
||||||
foreach (NameplateElements element in Enum.GetValues(typeof(NameplateElements)))
|
|
||||||
{
|
|
||||||
var change = props.Changes.GetProps(element);
|
|
||||||
StringUpdateFactory.ApplyStringChanges(change);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool ApplyStatusIconWithPrio(ref int statusIcon, int newStatusIcon, StringChange stringChange, ActivityContext activityContext, StatusIconPriorizer priorizer, bool moveIconToNameplateIfPossible)
|
|
||||||
{
|
|
||||||
bool? isPrio = null;
|
|
||||||
var fontIcon = StatusIconFontConverter.GetBitmapFontIconFromStatusIcon((StatusIcons)statusIcon);
|
|
||||||
|
|
||||||
if (moveIconToNameplateIfPossible)
|
|
||||||
{
|
|
||||||
if (fontIcon != null)
|
|
||||||
{
|
|
||||||
// Set new font icon as string change
|
|
||||||
var iconPayload = new IconPayload(fontIcon.Value);
|
|
||||||
stringChange.Payloads.Insert(0, iconPayload);
|
|
||||||
|
|
||||||
// If we moved it, we don't need it as icon anymore, yay :D
|
|
||||||
isPrio = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isPrio ??= priorizer.IsPriorityIcon(statusIcon, activityContext);
|
|
||||||
|
|
||||||
if (!isPrio.Value)
|
|
||||||
statusIcon = newStatusIcon;
|
|
||||||
|
|
||||||
return isPrio.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
using Lumina.Excel.GeneratedSheets;
|
|
||||||
using Pilz.Dalamud.ActivityContexts;
|
|
||||||
using Pilz.Dalamud.Nameplates.Model;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.Tools
|
|
||||||
{
|
|
||||||
public class StatusIconPriorizer
|
|
||||||
{
|
|
||||||
private static StatusIconPriorizerSettings DefaultSettings { get; } = new();
|
|
||||||
public StatusIconPriorizerSettings Settings { get; init; }
|
|
||||||
|
|
||||||
public StatusIconPriorizer() : this(DefaultSettings)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public StatusIconPriorizer(StatusIconPriorizerSettings settings)
|
|
||||||
{
|
|
||||||
Settings = settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check for an icon that should take priority over the job icon,
|
|
||||||
/// taking into account whether or not the player is in a duty.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="iconId">The incoming icon id that is being overwritten by the plugin.</param>
|
|
||||||
/// <param name="priorityIconId">The icon id that should be used.</param>
|
|
||||||
/// <returns>Whether a priority icon was found.</returns>
|
|
||||||
public bool IsPriorityIcon(int iconId, ActivityContext activityContext)
|
|
||||||
{
|
|
||||||
bool isPrioIcon;
|
|
||||||
|
|
||||||
if (!Settings.UsePriorizedIcons && iconId != (int)StatusIcons.Disconnecting && iconId != (int)StatusIcons.Disconnecting + 50)
|
|
||||||
isPrioIcon = false;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Select which set of priority icons to use based on whether we're in a duty
|
|
||||||
// In the future, there can be a third list used when in combat
|
|
||||||
var priorityIcons = GetPriorityIcons(activityContext);
|
|
||||||
|
|
||||||
// Determine whether the incoming icon should take priority over the job icon
|
|
||||||
// Check the id plus 50 as that's an alternately sized version
|
|
||||||
isPrioIcon = priorityIcons.Contains(iconId) || priorityIcons.Contains(iconId + 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
return isPrioIcon;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<int> GetPriorityIcons(ActivityContext activityContext)
|
|
||||||
{
|
|
||||||
StatusIconPriorizerConditionSets set;
|
|
||||||
|
|
||||||
if (activityContext.ZoneType == ZoneType.Foray)
|
|
||||||
set = StatusIconPriorizerConditionSets.InForay;
|
|
||||||
else if (activityContext.IsInDuty)
|
|
||||||
set = StatusIconPriorizerConditionSets.InDuty;
|
|
||||||
else
|
|
||||||
set = StatusIconPriorizerConditionSets.Overworld;
|
|
||||||
|
|
||||||
return Settings.GetConditionSet(set).Select(n => (int)n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.Tools
|
|
||||||
{
|
|
||||||
public enum StatusIconPriorizerConditionSets
|
|
||||||
{
|
|
||||||
Overworld,
|
|
||||||
InDuty,
|
|
||||||
InForay
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using Pilz.Dalamud.ActivityContexts;
|
|
||||||
using Pilz.Dalamud.Nameplates.Model;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Nameplates.Tools
|
|
||||||
{
|
|
||||||
public class StatusIconPriorizerSettings
|
|
||||||
{
|
|
||||||
[JsonProperty("IconConditionSets")]
|
|
||||||
private Dictionary<StatusIconPriorizerConditionSets, List<StatusIcons>> iconConditionSets = new();
|
|
||||||
public bool UsePriorizedIcons { get; set; } = true;
|
|
||||||
|
|
||||||
[JsonConstructor]
|
|
||||||
private StatusIconPriorizerSettings(JsonConstructorAttribute dummy)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public StatusIconPriorizerSettings() : this(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public StatusIconPriorizerSettings(bool fillWithDefaultSettings)
|
|
||||||
{
|
|
||||||
foreach (StatusIconPriorizerConditionSets set in Enum.GetValues(typeof(StatusIconPriorizerConditionSets)))
|
|
||||||
iconConditionSets.Add(set, new List<StatusIcons>());
|
|
||||||
|
|
||||||
if (fillWithDefaultSettings)
|
|
||||||
FillWithDefaultSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<StatusIcons> GetConditionSet(StatusIconPriorizerConditionSets set)
|
|
||||||
{
|
|
||||||
return iconConditionSets[set];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetToEmpty()
|
|
||||||
{
|
|
||||||
foreach (var kvp in iconConditionSets)
|
|
||||||
kvp.Value.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetToDefault()
|
|
||||||
{
|
|
||||||
ResetToEmpty();
|
|
||||||
FillWithDefaultSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FillWithDefaultSettings()
|
|
||||||
{
|
|
||||||
var setOverworld = GetConditionSet(StatusIconPriorizerConditionSets.Overworld);
|
|
||||||
setOverworld.AddRange(new[]
|
|
||||||
{
|
|
||||||
StatusIcons.Disconnecting, // Disconnecting
|
|
||||||
StatusIcons.InDuty, // In Duty
|
|
||||||
StatusIcons.ViewingCutscene, // Viewing Cutscene
|
|
||||||
StatusIcons.Busy, // Busy
|
|
||||||
StatusIcons.Idle, // Idle
|
|
||||||
StatusIcons.DutyFinder, // Duty Finder
|
|
||||||
StatusIcons.PartyLeader, // Party Leader
|
|
||||||
StatusIcons.PartyMember, // Party Member
|
|
||||||
StatusIcons.RolePlaying, // Role Playing
|
|
||||||
StatusIcons.GroupPose, // Group Pose
|
|
||||||
StatusIcons.Mentor,
|
|
||||||
StatusIcons.MentorCrafting,
|
|
||||||
StatusIcons.MentorPvE,
|
|
||||||
StatusIcons.MentorPvP,
|
|
||||||
StatusIcons.Returner,
|
|
||||||
StatusIcons.NewAdventurer,
|
|
||||||
});
|
|
||||||
|
|
||||||
var setInDuty = GetConditionSet(StatusIconPriorizerConditionSets.InDuty);
|
|
||||||
setInDuty.AddRange(new[]
|
|
||||||
{
|
|
||||||
StatusIcons.Disconnecting, // Disconnecting
|
|
||||||
StatusIcons.ViewingCutscene, // Viewing Cutscene
|
|
||||||
StatusIcons.Idle, // Idle
|
|
||||||
StatusIcons.GroupPose, // Group Pose
|
|
||||||
StatusIcons.Mentor,
|
|
||||||
StatusIcons.MentorCrafting,
|
|
||||||
StatusIcons.MentorPvE,
|
|
||||||
StatusIcons.MentorPvP,
|
|
||||||
StatusIcons.Returner,
|
|
||||||
StatusIcons.NewAdventurer,
|
|
||||||
});
|
|
||||||
|
|
||||||
var setInForay = GetConditionSet(StatusIconPriorizerConditionSets.InForay);
|
|
||||||
setInForay.AddRange(new[]
|
|
||||||
{
|
|
||||||
// This allows you to see which players don't have a party
|
|
||||||
StatusIcons.InDuty, // In Duty
|
|
||||||
|
|
||||||
StatusIcons.Disconnecting, // Disconnecting
|
|
||||||
StatusIcons.ViewingCutscene, // Viewing Cutscene
|
|
||||||
StatusIcons.Idle, // Idle
|
|
||||||
StatusIcons.GroupPose, // Group Pose
|
|
||||||
StatusIcons.Mentor,
|
|
||||||
StatusIcons.MentorCrafting,
|
|
||||||
StatusIcons.MentorPvE,
|
|
||||||
StatusIcons.MentorPvP,
|
|
||||||
StatusIcons.Returner,
|
|
||||||
StatusIcons.NewAdventurer,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +1,33 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>annotations</Nullable>
|
<Nullable>annotations</Nullable>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<LangVersion>latest</LangVersion>
|
<Use_DalamudPackager>false</Use_DalamudPackager>
|
||||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
|
||||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
|
||||||
<Platforms>x64</Platforms>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<Copyright>Pilzinsel64</Copyright>
|
||||||
</PropertyGroup>
|
<PackageProjectUrl>https://github.com/Pilzinsel64/Pilz.Dalamud</PackageProjectUrl>
|
||||||
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<PropertyGroup>
|
<RepositoryUrl>https://github.com/Pilzinsel64/Pilz.Dalamud</RepositoryUrl>
|
||||||
<DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
|
<RepositoryType>git</RepositoryType>
|
||||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
<Version>1.0.3</Version>
|
||||||
<Copyright>Pilzinsel64</Copyright>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
<PackageProjectUrl>https://github.com/Pilzinsel64/Pilz.Dalamud</PackageProjectUrl>
|
</PropertyGroup>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
|
||||||
<RepositoryUrl>https://github.com/Pilzinsel64/Pilz.Dalamud</RepositoryUrl>
|
|
||||||
<RepositoryType>git</RepositoryType>
|
|
||||||
<Version>0.4.0</Version>
|
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="FFXIVClientStructs">
|
|
||||||
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Newtonsoft.Json">
|
|
||||||
<HintPath>$(DalamudLibPath)Newtonsoft.Json.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Dalamud">
|
|
||||||
<HintPath>$(DalamudLibPath)Dalamud.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="ImGui.NET">
|
|
||||||
<HintPath>$(DalamudLibPath)ImGui.NET.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="ImGuiScene">
|
|
||||||
<HintPath>$(DalamudLibPath)ImGuiScene.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Lumina">
|
|
||||||
<HintPath>$(DalamudLibPath)Lumina.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Lumina.Excel">
|
|
||||||
<HintPath>$(DalamudLibPath)Lumina.Excel.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<None Include="..\README.md" Pack="true" PackagePath="\"/>
|
<NoWarn>1701;1702;1591</NoWarn>
|
||||||
</ItemGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<NoWarn>1701;1702;1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\README.md" Pack="true" PackagePath="\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,28 +1,21 @@
|
|||||||
using Dalamud.Data;
|
using Dalamud.IoC;
|
||||||
using Dalamud.Game.ClientState;
|
|
||||||
using Dalamud.Game.ClientState.Objects;
|
|
||||||
using Dalamud.Game.Gui;
|
|
||||||
using Dalamud.IoC;
|
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using System;
|
using Dalamud.Plugin.Services;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud
|
namespace Pilz.Dalamud;
|
||||||
|
|
||||||
|
public class PluginServices
|
||||||
{
|
{
|
||||||
public class PluginServices
|
[PluginService] public static IDalamudPluginInterface PluginInterface { get; set; }
|
||||||
{
|
[PluginService] public static IGameGui GameGui { get; set; }
|
||||||
[PluginService] public static GameGui GameGui { get; set; } = null;
|
[PluginService] public static IClientState ClientState { get; set; }
|
||||||
[PluginService] public static DalamudPluginInterface PluginInterface { get; set; } = null;
|
[PluginService] public static IDataManager DataManager { get; set; }
|
||||||
[PluginService] public static ClientState ClientState { get; set; } = null;
|
[PluginService] public static IObjectTable ObjectTable { get; set; }
|
||||||
[PluginService] public static DataManager DataManager { get; set; } = null;
|
[PluginService] public static IGameInteropProvider GameInteropProvider { get; set; }
|
||||||
[PluginService] public static ObjectTable ObjectTable { get; set; } = null;
|
[PluginService] public static IAddonLifecycle AddonLifecycle { get; set; }
|
||||||
|
|
||||||
public static void Initialize(DalamudPluginInterface dalamudPluginInterface)
|
public static void Initialize(IDalamudPluginInterface dalamudPluginInterface)
|
||||||
{
|
{
|
||||||
dalamudPluginInterface.Create<PluginServices>();
|
dalamudPluginInterface.Create<PluginServices>();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
25
Pilz.Dalamud/Tools/NamePlates/NameplateChanges.cs
Normal file
25
Pilz.Dalamud/Tools/NamePlates/NameplateChanges.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using Dalamud.Game.Gui.NamePlate;
|
||||||
|
|
||||||
|
namespace Pilz.Dalamud.Tools.NamePlates;
|
||||||
|
|
||||||
|
public class NameplateChanges
|
||||||
|
{
|
||||||
|
private readonly List<NameplateElementChange> changes = [];
|
||||||
|
|
||||||
|
public NameplateChanges(INamePlateUpdateHandler handler)
|
||||||
|
{
|
||||||
|
changes.Add(new(NameplateElements.Title, handler));
|
||||||
|
changes.Add(new(NameplateElements.Name, handler));
|
||||||
|
changes.Add(new(NameplateElements.FreeCompany, handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the properties with the changes of an element of your choice where you can add your payloads to a change and setup some options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="element">The position of your choice.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public NameplateElementChange GetChange(NameplateElements element)
|
||||||
|
{
|
||||||
|
return changes.FirstOrDefault(n => n.Element == element);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Pilz.Dalamud/Tools/NamePlates/NameplateChangesProps.cs
Normal file
18
Pilz.Dalamud/Tools/NamePlates/NameplateChangesProps.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace Pilz.Dalamud.Tools.NamePlates;
|
||||||
|
|
||||||
|
public class NameplateChangesProps
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// All the changes to the nameplate that should be made.
|
||||||
|
/// </summary>
|
||||||
|
public NameplateChanges Changes { get; set; }
|
||||||
|
|
||||||
|
public NameplateChangesProps()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public NameplateChangesProps(NameplateChanges changes) : this()
|
||||||
|
{
|
||||||
|
Changes = changes;
|
||||||
|
}
|
||||||
|
}
|
||||||
47
Pilz.Dalamud/Tools/NamePlates/NameplateElementChange.cs
Normal file
47
Pilz.Dalamud/Tools/NamePlates/NameplateElementChange.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using Dalamud.Game.Gui.NamePlate;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
|
using Pilz.Dalamud.Tools.Strings;
|
||||||
|
|
||||||
|
namespace Pilz.Dalamud.Tools.NamePlates;
|
||||||
|
|
||||||
|
public class NameplateElementChange(NameplateElements element, INamePlateUpdateHandler handler)
|
||||||
|
{
|
||||||
|
public NameplateElements Element => element;
|
||||||
|
public StringChanges Changes { get; set; } = new();
|
||||||
|
|
||||||
|
public void ApplyFormatting(SeString prefix, SeString postfix)
|
||||||
|
{
|
||||||
|
var parts = (prefix, postfix);
|
||||||
|
|
||||||
|
switch (element)
|
||||||
|
{
|
||||||
|
case NameplateElements.Name:
|
||||||
|
handler.NameParts.TextWrap = parts;
|
||||||
|
break;
|
||||||
|
case NameplateElements.Title:
|
||||||
|
handler.TitleParts.OuterWrap = parts;
|
||||||
|
break;
|
||||||
|
case NameplateElements.FreeCompany:
|
||||||
|
handler.FreeCompanyTagParts.OuterWrap = parts;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyChanges()
|
||||||
|
{
|
||||||
|
if (Changes.Any())
|
||||||
|
{
|
||||||
|
StringUpdateFactory.ApplyStringChanges(new()
|
||||||
|
{
|
||||||
|
StringChanges = Changes,
|
||||||
|
Destination = element switch
|
||||||
|
{
|
||||||
|
NameplateElements.Name => handler.NameParts.Text ??= handler.InfoView.Name,
|
||||||
|
NameplateElements.Title => handler.TitleParts.Text ??= handler.InfoView.Title,
|
||||||
|
NameplateElements.FreeCompany => handler.FreeCompanyTagParts.Text ??= handler.InfoView.FreeCompanyTag,
|
||||||
|
_ => null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
Pilz.Dalamud/Tools/NamePlates/NameplateElements.cs
Normal file
8
Pilz.Dalamud/Tools/NamePlates/NameplateElements.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Pilz.Dalamud.Tools.NamePlates;
|
||||||
|
|
||||||
|
public enum NameplateElements
|
||||||
|
{
|
||||||
|
Name,
|
||||||
|
Title,
|
||||||
|
FreeCompany,
|
||||||
|
}
|
||||||
48
Pilz.Dalamud/Tools/NamePlates/NameplateUpdateFactory.cs
Normal file
48
Pilz.Dalamud/Tools/NamePlates/NameplateUpdateFactory.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using Dalamud.Game.Gui.NamePlate;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||||
|
using Pilz.Dalamud.ActivityContexts;
|
||||||
|
using Pilz.Dalamud.Icons;
|
||||||
|
|
||||||
|
namespace Pilz.Dalamud.Tools.NamePlates;
|
||||||
|
|
||||||
|
public static class NameplateUpdateFactory
|
||||||
|
{
|
||||||
|
public static void ApplyNameplateChanges(NameplateChangesProps props)
|
||||||
|
{
|
||||||
|
foreach (NameplateElements element in Enum.GetValues(typeof(NameplateElements)))
|
||||||
|
{
|
||||||
|
var change = props.Changes.GetChange(element);
|
||||||
|
change.ApplyChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ApplyStatusIconWithPrio(INamePlateUpdateHandler handler, int newStatusIcon, ActivityContext activityContext, StatusIconPriorizer priorizer, bool moveIconToNameplateIfPossible)
|
||||||
|
{
|
||||||
|
bool? isPrio = null;
|
||||||
|
var fontIcon = StatusIconFontConverter.GetBitmapFontIconFromStatusIcon((StatusIcons)handler.NameIconId);
|
||||||
|
|
||||||
|
if (moveIconToNameplateIfPossible)
|
||||||
|
{
|
||||||
|
if (fontIcon != null)
|
||||||
|
{
|
||||||
|
// Set new font icon as string change
|
||||||
|
var icon = new IconPayload(fontIcon.Value); ;
|
||||||
|
if (handler.StatusPrefix is SeString str)
|
||||||
|
str.Payloads.Insert(0, icon);
|
||||||
|
else
|
||||||
|
handler.StatusPrefix = SeString.Empty.Append(icon);
|
||||||
|
|
||||||
|
// If we moved it, we don't need it as icon anymore, yay :D
|
||||||
|
isPrio = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isPrio ??= priorizer.IsPriorityIcon(handler.NameIconId, activityContext);
|
||||||
|
|
||||||
|
if (!isPrio.Value)
|
||||||
|
handler.NameIconId = newStatusIcon;
|
||||||
|
|
||||||
|
return isPrio.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
60
Pilz.Dalamud/Tools/NamePlates/StatusIconPriorizer.cs
Normal file
60
Pilz.Dalamud/Tools/NamePlates/StatusIconPriorizer.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using Pilz.Dalamud.ActivityContexts;
|
||||||
|
using Pilz.Dalamud.Icons;
|
||||||
|
|
||||||
|
namespace Pilz.Dalamud.Tools.NamePlates;
|
||||||
|
|
||||||
|
public class StatusIconPriorizer
|
||||||
|
{
|
||||||
|
private static StatusIconPriorizerSettings DefaultSettings { get; } = new();
|
||||||
|
public StatusIconPriorizerSettings Settings { get; init; }
|
||||||
|
|
||||||
|
public StatusIconPriorizer() : this(DefaultSettings)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatusIconPriorizer(StatusIconPriorizerSettings settings)
|
||||||
|
{
|
||||||
|
Settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check for an icon that should take priority over the job icon,
|
||||||
|
/// taking into account whether or not the player is in a duty.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="iconId">The incoming icon id that is being overwritten by the plugin.</param>
|
||||||
|
/// <param name="activityContext"></param>
|
||||||
|
/// <returns>Whether a priority icon was found.</returns>
|
||||||
|
public bool IsPriorityIcon(int iconId, ActivityContext activityContext)
|
||||||
|
{
|
||||||
|
bool isPrioIcon;
|
||||||
|
|
||||||
|
if (!Settings.UsePriorizedIcons && iconId != (int)StatusIcons.Disconnecting && iconId != (int)StatusIcons.Disconnecting + 50)
|
||||||
|
isPrioIcon = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Select which set of priority icons to use based on whether we're in a duty
|
||||||
|
// In the future, there can be a third list used when in combat
|
||||||
|
var priorityIcons = GetPriorityIcons(activityContext);
|
||||||
|
|
||||||
|
// Determine whether the incoming icon should take priority over the job icon
|
||||||
|
// Check the id plus 50 as that's an alternately sized version
|
||||||
|
isPrioIcon = priorityIcons.Contains(iconId) || priorityIcons.Contains(iconId + 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
return isPrioIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<int> GetPriorityIcons(ActivityContext activityContext)
|
||||||
|
{
|
||||||
|
StatusIconPriorizerConditionSets set;
|
||||||
|
|
||||||
|
if (activityContext.ZoneType == ZoneType.Foray)
|
||||||
|
set = StatusIconPriorizerConditionSets.InForay;
|
||||||
|
else if (activityContext.IsInDuty)
|
||||||
|
set = StatusIconPriorizerConditionSets.InDuty;
|
||||||
|
else
|
||||||
|
set = StatusIconPriorizerConditionSets.Overworld;
|
||||||
|
|
||||||
|
return Settings.GetConditionSet(set).Select(n => (int)n);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Pilz.Dalamud.Tools.NamePlates;
|
||||||
|
|
||||||
|
public enum StatusIconPriorizerConditionSets
|
||||||
|
{
|
||||||
|
Overworld,
|
||||||
|
InDuty,
|
||||||
|
InForay
|
||||||
|
}
|
||||||
103
Pilz.Dalamud/Tools/NamePlates/StatusIconPriorizerSettings.cs
Normal file
103
Pilz.Dalamud/Tools/NamePlates/StatusIconPriorizerSettings.cs
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using Pilz.Dalamud.Icons;
|
||||||
|
|
||||||
|
namespace Pilz.Dalamud.Tools.NamePlates;
|
||||||
|
|
||||||
|
public class StatusIconPriorizerSettings
|
||||||
|
{
|
||||||
|
[JsonProperty("IconConditionSets")]
|
||||||
|
private Dictionary<StatusIconPriorizerConditionSets, List<StatusIcons>> iconConditionSets = [];
|
||||||
|
public bool UsePriorizedIcons { get; set; } = true;
|
||||||
|
|
||||||
|
[JsonConstructor]
|
||||||
|
private StatusIconPriorizerSettings(JsonConstructorAttribute dummy)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatusIconPriorizerSettings() : this(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatusIconPriorizerSettings(bool fillWithDefaultSettings)
|
||||||
|
{
|
||||||
|
foreach (StatusIconPriorizerConditionSets set in Enum.GetValues(typeof(StatusIconPriorizerConditionSets)))
|
||||||
|
iconConditionSets.Add(set, []);
|
||||||
|
|
||||||
|
if (fillWithDefaultSettings)
|
||||||
|
FillWithDefaultSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<StatusIcons> GetConditionSet(StatusIconPriorizerConditionSets set)
|
||||||
|
{
|
||||||
|
return iconConditionSets[set];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetToEmpty()
|
||||||
|
{
|
||||||
|
foreach (var kvp in iconConditionSets)
|
||||||
|
kvp.Value.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetToDefault()
|
||||||
|
{
|
||||||
|
ResetToEmpty();
|
||||||
|
FillWithDefaultSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FillWithDefaultSettings()
|
||||||
|
{
|
||||||
|
var setOverworld = GetConditionSet(StatusIconPriorizerConditionSets.Overworld);
|
||||||
|
setOverworld.AddRange(new[]
|
||||||
|
{
|
||||||
|
StatusIcons.Disconnecting, // Disconnecting
|
||||||
|
StatusIcons.InDuty, // In Duty
|
||||||
|
StatusIcons.ViewingCutscene, // Viewing Cutscene
|
||||||
|
StatusIcons.Busy, // Busy
|
||||||
|
StatusIcons.Idle, // Idle
|
||||||
|
StatusIcons.DutyFinder, // Duty Finder
|
||||||
|
StatusIcons.PartyLeader, // Party Leader
|
||||||
|
StatusIcons.PartyMember, // Party Member
|
||||||
|
StatusIcons.RolePlaying, // Role Playing
|
||||||
|
StatusIcons.GroupPose, // Group Pose
|
||||||
|
StatusIcons.Mentor,
|
||||||
|
StatusIcons.MentorCrafting,
|
||||||
|
StatusIcons.MentorPvE,
|
||||||
|
StatusIcons.MentorPvP,
|
||||||
|
StatusIcons.Returner,
|
||||||
|
StatusIcons.NewAdventurer,
|
||||||
|
});
|
||||||
|
|
||||||
|
var setInDuty = GetConditionSet(StatusIconPriorizerConditionSets.InDuty);
|
||||||
|
setInDuty.AddRange(new[]
|
||||||
|
{
|
||||||
|
StatusIcons.Disconnecting, // Disconnecting
|
||||||
|
StatusIcons.ViewingCutscene, // Viewing Cutscene
|
||||||
|
StatusIcons.Idle, // Idle
|
||||||
|
StatusIcons.GroupPose, // Group Pose
|
||||||
|
StatusIcons.Mentor,
|
||||||
|
StatusIcons.MentorCrafting,
|
||||||
|
StatusIcons.MentorPvE,
|
||||||
|
StatusIcons.MentorPvP,
|
||||||
|
StatusIcons.Returner,
|
||||||
|
StatusIcons.NewAdventurer,
|
||||||
|
});
|
||||||
|
|
||||||
|
var setInForay = GetConditionSet(StatusIconPriorizerConditionSets.InForay);
|
||||||
|
setInForay.AddRange(new[]
|
||||||
|
{
|
||||||
|
// This allows you to see which players don't have a party
|
||||||
|
StatusIcons.InDuty, // In Duty
|
||||||
|
|
||||||
|
StatusIcons.Disconnecting, // Disconnecting
|
||||||
|
StatusIcons.ViewingCutscene, // Viewing Cutscene
|
||||||
|
StatusIcons.Idle, // Idle
|
||||||
|
StatusIcons.GroupPose, // Group Pose
|
||||||
|
StatusIcons.Mentor,
|
||||||
|
StatusIcons.MentorCrafting,
|
||||||
|
StatusIcons.MentorPvE,
|
||||||
|
StatusIcons.MentorPvP,
|
||||||
|
StatusIcons.Returner,
|
||||||
|
StatusIcons.NewAdventurer,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,41 +1,35 @@
|
|||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using Pilz.Dalamud.Nameplates.Model;
|
using Pilz.Dalamud.Icons;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Tools
|
namespace Pilz.Dalamud.Tools;
|
||||||
|
|
||||||
|
public static class StatusIconFontConverter
|
||||||
{
|
{
|
||||||
public static class StatusIconFontConverter
|
public static StatusIcons? GetStatusIconFromBitmapFontIcon(BitmapFontIcon fontIcon)
|
||||||
{
|
{
|
||||||
public static StatusIcons? GetStatusIconFromBitmapFontIcon(BitmapFontIcon fontIcon)
|
return fontIcon switch
|
||||||
{
|
{
|
||||||
return fontIcon switch
|
BitmapFontIcon.NewAdventurer => StatusIcons.NewAdventurer,
|
||||||
{
|
BitmapFontIcon.Mentor => StatusIcons.Mentor,
|
||||||
BitmapFontIcon.NewAdventurer => StatusIcons.NewAdventurer,
|
BitmapFontIcon.MentorPvE => StatusIcons.MentorPvE,
|
||||||
BitmapFontIcon.Mentor => StatusIcons.Mentor,
|
BitmapFontIcon.MentorCrafting => StatusIcons.MentorCrafting,
|
||||||
BitmapFontIcon.MentorPvE => StatusIcons.MentorPvE,
|
BitmapFontIcon.MentorPvP => StatusIcons.MentorPvP,
|
||||||
BitmapFontIcon.MentorCrafting => StatusIcons.MentorCrafting,
|
BitmapFontIcon.Returner => StatusIcons.Returner,
|
||||||
BitmapFontIcon.MentorPvP => StatusIcons.MentorPvP,
|
_ => null
|
||||||
BitmapFontIcon.Returner => StatusIcons.Returner,
|
};
|
||||||
_ => null
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BitmapFontIcon? GetBitmapFontIconFromStatusIcon(StatusIcons icon)
|
public static BitmapFontIcon? GetBitmapFontIconFromStatusIcon(StatusIcons icon)
|
||||||
|
{
|
||||||
|
return icon switch
|
||||||
{
|
{
|
||||||
return icon switch
|
StatusIcons.NewAdventurer => BitmapFontIcon.NewAdventurer,
|
||||||
{
|
StatusIcons.Mentor => BitmapFontIcon.Mentor,
|
||||||
StatusIcons.NewAdventurer => BitmapFontIcon.NewAdventurer,
|
StatusIcons.MentorPvE => BitmapFontIcon.MentorPvE,
|
||||||
StatusIcons.Mentor => BitmapFontIcon.Mentor,
|
StatusIcons.MentorCrafting => BitmapFontIcon.MentorCrafting,
|
||||||
StatusIcons.MentorPvE => BitmapFontIcon.MentorPvE,
|
StatusIcons.MentorPvP => BitmapFontIcon.MentorPvP,
|
||||||
StatusIcons.MentorCrafting => BitmapFontIcon.MentorCrafting,
|
StatusIcons.Returner => BitmapFontIcon.Returner,
|
||||||
StatusIcons.MentorPvP => BitmapFontIcon.MentorPvP,
|
_ => null
|
||||||
StatusIcons.Returner => BitmapFontIcon.Returner,
|
};
|
||||||
_ => null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,18 @@
|
|||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Tools.Strings
|
namespace Pilz.Dalamud.Tools.Strings;
|
||||||
|
|
||||||
|
public class StringChange
|
||||||
{
|
{
|
||||||
public class StringChange
|
/// <summary>
|
||||||
{
|
/// The payloads to use for inserting/replacing.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// The payloads to use for inserting/replacing.
|
public List<Payload> Payloads { get; init; } = [];
|
||||||
/// </summary>
|
|
||||||
public List<Payload> Payloads { get; init; } = new();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines if only one anchor payload should be used, if using anchor payloads.
|
/// Defines if only one anchor payload should be used, if using anchor payloads.
|
||||||
/// With this true the single anchor payload will be used in StringUpdateFactory instead of the anchor payload list.
|
/// With this true the single anchor payload will be used in StringUpdateFactory instead of the anchor payload list.
|
||||||
/// Not needed to be true for the most cases.
|
/// Not needed to be true for the most cases.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ForceUsingSingleAnchorPayload { get; set; } = false;
|
public bool ForceUsingSingleAnchorPayload { get; set; } = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +1,32 @@
|
|||||||
using Dalamud.Game.Text.SeStringHandling;
|
namespace Pilz.Dalamud.Tools.Strings;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Tools.Strings
|
public class StringChanges
|
||||||
{
|
{
|
||||||
public class StringChanges
|
private readonly Dictionary<StringPosition, StringChange> changes = [];
|
||||||
|
|
||||||
|
public StringChanges()
|
||||||
{
|
{
|
||||||
private readonly Dictionary<StringPosition, StringChange> changes = new();
|
changes.Add(StringPosition.Before, new StringChange());
|
||||||
|
changes.Add(StringPosition.After, new StringChange());
|
||||||
|
changes.Add(StringPosition.Replace, new StringChange());
|
||||||
|
}
|
||||||
|
|
||||||
public StringChanges()
|
/// <summary>
|
||||||
{
|
/// Gets a change of the position of your choice where you can add your payloads.
|
||||||
changes.Add(StringPosition.Before, new StringChange());
|
/// </summary>
|
||||||
changes.Add(StringPosition.After, new StringChange());
|
/// <param name="position">The position of your choice.</param>
|
||||||
changes.Add(StringPosition.Replace, new StringChange());
|
/// <returns></returns>
|
||||||
}
|
public StringChange GetChange(StringPosition position)
|
||||||
|
{
|
||||||
|
return changes[position];
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a change of the position of your choice where you can add your payloads.
|
/// Checks if there is any string change listed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="position">The position of your choice.</param>
|
/// <returns></returns>
|
||||||
/// <returns></returns>
|
public bool Any()
|
||||||
public StringChange GetChange(StringPosition position)
|
{
|
||||||
{
|
return changes.Sum(n => n.Value.Payloads.Count) != 0;
|
||||||
return changes[position];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if there is any string change listed.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool Any()
|
|
||||||
{
|
|
||||||
return changes.Sum(n => n.Value.Payloads.Count) != 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,24 @@
|
|||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using Dalamud.Game.Text.SeStringHandling;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Tools.Strings
|
namespace Pilz.Dalamud.Tools.Strings;
|
||||||
|
|
||||||
|
public class StringChangesProps
|
||||||
{
|
{
|
||||||
public class StringChangesProps
|
/// <summary>
|
||||||
{
|
/// The string where the changes should be applied.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// The string where the changes should be applied.
|
public SeString Destination { get; set; }
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public SeString Destination { get; set; }
|
/// The changes that should be applied to the destination.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// The changes that should be applied to the destination.
|
public StringChanges StringChanges { get; set; } = new();
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public StringChanges StringChanges { get; set; } = new();
|
/// Payloads to use as anchor where the changes should be applied to.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Payloads to use as anchor where the changes should be applied to.
|
public List<Payload> AnchorPayloads { get; set; } = [];
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public List<Payload> AnchorPayloads { get; set; } = new();
|
/// A single payload to use as anchor where the changes should be applied to.
|
||||||
/// <summary>
|
/// This property will only be used if StringChange.ForceSingleAnchorPayload is true.
|
||||||
/// A single payload to use as anchor where the changes should be applied to.
|
/// </summary>
|
||||||
/// This property will only be used if StringChange.ForceSingleAnchorPayload is true.
|
public Payload AnchorPayload { get; set; }
|
||||||
/// </summary>
|
|
||||||
public Payload AnchorPayload { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
using System;
|
namespace Pilz.Dalamud.Tools.Strings;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Tools.Strings
|
public enum StringPosition
|
||||||
{
|
{
|
||||||
public enum StringPosition
|
Before,
|
||||||
{
|
After,
|
||||||
Before,
|
Replace
|
||||||
After,
|
|
||||||
Replace
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,132 +1,125 @@
|
|||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||||
using Lumina.Text;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Tools.Strings
|
namespace Pilz.Dalamud.Tools.Strings;
|
||||||
|
|
||||||
|
public static class StringUpdateFactory
|
||||||
{
|
{
|
||||||
public static class StringUpdateFactory
|
public static void ApplyStringChanges(StringChangesProps props)
|
||||||
{
|
{
|
||||||
public static void ApplyStringChanges(StringChangesProps props)
|
if (props.StringChanges != null && props.StringChanges.Any())
|
||||||
{
|
{
|
||||||
if (props.StringChanges != null && props.StringChanges.Any())
|
var seString = props.Destination;
|
||||||
|
List<StringPosition> stringPositionsOrdered = GetOrderedStringPositions(props);
|
||||||
|
|
||||||
|
foreach (var stringPosition in stringPositionsOrdered)
|
||||||
{
|
{
|
||||||
var seString = props.Destination;
|
var stringChange = props.StringChanges.GetChange(stringPosition);
|
||||||
List<StringPosition> stringPositionsOrdered = GetOrderedStringPositions(props);
|
if (stringChange != null && stringChange.Payloads.Any())
|
||||||
|
|
||||||
foreach (var stringPosition in stringPositionsOrdered)
|
|
||||||
{
|
{
|
||||||
var stringChange = props.StringChanges.GetChange(stringPosition);
|
AddSpacesBetweenTextPayloads(stringChange.Payloads, stringPosition);
|
||||||
if (stringChange != null && stringChange.Payloads.Any())
|
|
||||||
|
if (stringPosition == StringPosition.Before)
|
||||||
{
|
{
|
||||||
AddSpacesBetweenTextPayloads(stringChange.Payloads, stringPosition);
|
Payload anchorFirst = stringChange.ForceUsingSingleAnchorPayload ? props.AnchorPayload : props.AnchorPayloads?.FirstOrDefault();
|
||||||
|
|
||||||
if (stringPosition == StringPosition.Before)
|
if (anchorFirst != null)
|
||||||
{
|
{
|
||||||
Payload anchorFirst = stringChange.ForceUsingSingleAnchorPayload ? props.AnchorPayload : props.AnchorPayloads?.FirstOrDefault();
|
var anchorPayloadIndex = seString.Payloads.IndexOf(anchorFirst);
|
||||||
|
seString.Payloads.InsertRange(anchorPayloadIndex, stringChange.Payloads);
|
||||||
if (anchorFirst != null)
|
|
||||||
{
|
|
||||||
var anchorPayloadIndex = seString.Payloads.IndexOf(anchorFirst);
|
|
||||||
seString.Payloads.InsertRange(anchorPayloadIndex, stringChange.Payloads);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
seString.Payloads.InsertRange(0, stringChange.Payloads);
|
|
||||||
}
|
}
|
||||||
else if (stringPosition == StringPosition.After)
|
else
|
||||||
{
|
seString.Payloads.InsertRange(0, stringChange.Payloads);
|
||||||
Payload anchorLast = stringChange.ForceUsingSingleAnchorPayload ? props.AnchorPayload : props.AnchorPayloads?.LastOrDefault();
|
}
|
||||||
|
else if (stringPosition == StringPosition.After)
|
||||||
|
{
|
||||||
|
Payload anchorLast = stringChange.ForceUsingSingleAnchorPayload ? props.AnchorPayload : props.AnchorPayloads?.LastOrDefault();
|
||||||
|
|
||||||
if (anchorLast != null)
|
if (anchorLast != null)
|
||||||
{
|
{
|
||||||
var anchorPayloadIndex = seString.Payloads.IndexOf(anchorLast);
|
var anchorPayloadIndex = seString.Payloads.IndexOf(anchorLast);
|
||||||
seString.Payloads.InsertRange(anchorPayloadIndex + 1, stringChange.Payloads);
|
seString.Payloads.InsertRange(anchorPayloadIndex + 1, stringChange.Payloads);
|
||||||
}
|
|
||||||
else
|
|
||||||
seString.Payloads.AddRange(stringChange.Payloads);
|
|
||||||
}
|
}
|
||||||
else if (stringPosition == StringPosition.Replace)
|
else
|
||||||
{
|
seString.Payloads.AddRange(stringChange.Payloads);
|
||||||
Payload anchorReplace = props.AnchorPayload;
|
}
|
||||||
|
else if (stringPosition == StringPosition.Replace)
|
||||||
|
{
|
||||||
|
Payload anchorReplace = props.AnchorPayload;
|
||||||
|
|
||||||
if (anchorReplace != null)
|
if (anchorReplace != null)
|
||||||
{
|
{
|
||||||
var anchorPayloadIndex = seString.Payloads.IndexOf(anchorReplace);
|
var anchorPayloadIndex = seString.Payloads.IndexOf(anchorReplace);
|
||||||
seString.Payloads.InsertRange(anchorPayloadIndex, stringChange.Payloads);
|
seString.Payloads.InsertRange(anchorPayloadIndex, stringChange.Payloads);
|
||||||
seString.Remove(anchorReplace);
|
seString.Remove(anchorReplace);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
seString.Payloads.Clear();
|
seString.Payloads.Clear();
|
||||||
seString.Payloads.AddRange(stringChange.Payloads);
|
seString.Payloads.AddRange(stringChange.Payloads);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private static void AddSpacesBetweenTextPayloads(List<Payload> payloads, StringPosition tagPosition)
|
|
||||||
{
|
private static void AddSpacesBetweenTextPayloads(List<Payload> payloads, StringPosition tagPosition)
|
||||||
if (payloads != null && payloads.Any())
|
{
|
||||||
{
|
if (payloads != null && payloads.Any())
|
||||||
var indicesToInsertSpacesAt = new List<int>();
|
{
|
||||||
var lastTextPayloadIndex = -1;
|
var indicesToInsertSpacesAt = new List<int>();
|
||||||
|
var lastTextPayloadIndex = -1;
|
||||||
static TextPayload getNewTextPayload() => new(" ");
|
|
||||||
|
static TextPayload getNewTextPayload() => new(" ");
|
||||||
foreach (var payload in payloads.Reverse<Payload>())
|
|
||||||
{
|
foreach (var payload in payloads.Reverse<Payload>())
|
||||||
if (payload is IconPayload iconPayload)
|
{
|
||||||
lastTextPayloadIndex = -1;
|
if (payload is IconPayload iconPayload)
|
||||||
else if (payload is TextPayload textPayload)
|
lastTextPayloadIndex = -1;
|
||||||
{
|
else if (payload is TextPayload textPayload)
|
||||||
if (lastTextPayloadIndex != -1)
|
{
|
||||||
indicesToInsertSpacesAt.Add(payloads.IndexOf(textPayload) + 1);
|
if (lastTextPayloadIndex != -1)
|
||||||
lastTextPayloadIndex = payloads.IndexOf(textPayload);
|
indicesToInsertSpacesAt.Add(payloads.IndexOf(textPayload) + 1);
|
||||||
}
|
lastTextPayloadIndex = payloads.IndexOf(textPayload);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
foreach (var indexToInsertSpaceAt in indicesToInsertSpacesAt)
|
|
||||||
payloads.Insert(indexToInsertSpaceAt, getNewTextPayload());
|
foreach (var indexToInsertSpaceAt in indicesToInsertSpacesAt)
|
||||||
|
payloads.Insert(indexToInsertSpaceAt, getNewTextPayload());
|
||||||
// Decide whether to add a space to the end
|
|
||||||
if (tagPosition == StringPosition.Before)
|
// Decide whether to add a space to the end
|
||||||
{
|
if (tagPosition == StringPosition.Before)
|
||||||
var significantPayloads = payloads.Where(payload => payload is TextPayload || payload is IconPayload);
|
{
|
||||||
if (significantPayloads.LastOrDefault() is TextPayload)
|
var significantPayloads = payloads.Where(payload => payload is TextPayload || payload is IconPayload);
|
||||||
payloads.Add(getNewTextPayload());
|
if (significantPayloads.LastOrDefault() is TextPayload)
|
||||||
}
|
payloads.Add(getNewTextPayload());
|
||||||
// Decide whether to add a space to the beginning
|
}
|
||||||
else if (tagPosition == StringPosition.After)
|
// Decide whether to add a space to the beginning
|
||||||
{
|
else if (tagPosition == StringPosition.After)
|
||||||
var significantPayloads = payloads.Where(payload => payload is TextPayload || payload is IconPayload);
|
{
|
||||||
if (significantPayloads.FirstOrDefault() is TextPayload)
|
var significantPayloads = payloads.Where(payload => payload is TextPayload || payload is IconPayload);
|
||||||
payloads.Insert(0, getNewTextPayload());
|
if (significantPayloads.FirstOrDefault() is TextPayload)
|
||||||
}
|
payloads.Insert(0, getNewTextPayload());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private static List<StringPosition> GetOrderedStringPositions(StringChangesProps props)
|
|
||||||
{
|
private static List<StringPosition> GetOrderedStringPositions(StringChangesProps props)
|
||||||
var tagPositionsOrdered = new List<StringPosition>();
|
{
|
||||||
|
var tagPositionsOrdered = new List<StringPosition>();
|
||||||
// If there's no anchor payload, do replaces first so that befores and afters are based on the replaced data
|
|
||||||
if (props.AnchorPayloads == null || !props.AnchorPayloads.Any())
|
// If there's no anchor payload, do replaces first so that befores and afters are based on the replaced data
|
||||||
tagPositionsOrdered.Add(StringPosition.Replace);
|
if (props.AnchorPayloads == null || !props.AnchorPayloads.Any())
|
||||||
|
tagPositionsOrdered.Add(StringPosition.Replace);
|
||||||
tagPositionsOrdered.Add(StringPosition.Before);
|
|
||||||
tagPositionsOrdered.Add(StringPosition.After);
|
tagPositionsOrdered.Add(StringPosition.Before);
|
||||||
|
tagPositionsOrdered.Add(StringPosition.After);
|
||||||
// If there is an anchor payload, do replaces last so that we still know which payload needs to be removed
|
|
||||||
if (props.AnchorPayloads != null && props.AnchorPayloads.Any())
|
// If there is an anchor payload, do replaces last so that we still know which payload needs to be removed
|
||||||
tagPositionsOrdered.Add(StringPosition.Replace);
|
if (props.AnchorPayloads != null && props.AnchorPayloads.Any())
|
||||||
|
tagPositionsOrdered.Add(StringPosition.Replace);
|
||||||
return tagPositionsOrdered;
|
|
||||||
}
|
return tagPositionsOrdered;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
using FFXIVClientStructs.FFXIV.Client.System.Framework;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Pilz.Dalamud.Nameplates.Model;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud
|
|
||||||
{
|
|
||||||
public class XivApi
|
|
||||||
{
|
|
||||||
private static IntPtr _RaptureAtkModulePtr = IntPtr.Zero;
|
|
||||||
|
|
||||||
public static IntPtr RaptureAtkModulePtr
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_RaptureAtkModulePtr == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
var framework = Framework.Instance();
|
|
||||||
var uiModule = framework->GetUiModule();
|
|
||||||
|
|
||||||
_RaptureAtkModulePtr = new IntPtr(uiModule->GetRaptureAtkModule());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _RaptureAtkModulePtr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SafeAddonNameplate GetSafeAddonNamePlate()
|
|
||||||
{
|
|
||||||
return new(PluginServices.PluginInterface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"net7.0-windows7.0": {}
|
"net9.0-windows7.0": {
|
||||||
|
"DotNet.ReproducibleBuilds": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.2.25, )",
|
||||||
|
"resolved": "1.2.25",
|
||||||
|
"contentHash": "xCXiw7BCxHJ8pF6wPepRUddlh2dlQlbr81gXA72hdk4FLHkKXas7EH/n+fk5UCA/YfMqG1Z6XaPiUjDbUNBUzg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
77
README.md
77
README.md
@@ -8,6 +8,9 @@ At the moment it's far away from being complete or even good. Right now it as so
|
|||||||
Install the latest version of `Pilz.Dalamud` via NuGet Package Manager or NuGet Console:\
|
Install the latest version of `Pilz.Dalamud` via NuGet Package Manager or NuGet Console:\
|
||||||
https://www.nuget.org/packages/Pilz.Dalamud
|
https://www.nuget.org/packages/Pilz.Dalamud
|
||||||
|
|
||||||
|
Or add the alternative package source for slightly quicker updates:\
|
||||||
|
`<add key="Pilz" value="https://git.pilzinsel64.de/api/packages/Pilz.NET/nuget/index.json" />`\
|
||||||
|
|
||||||
## Get started
|
## Get started
|
||||||
|
|
||||||
### Initialize Plugin Services
|
### Initialize Plugin Services
|
||||||
@@ -25,79 +28,9 @@ public Plugin(DalamudPluginInterface pluginInterface)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Hook into Nameplates
|
### Hook into NamePlates
|
||||||
|
|
||||||
To edit the nameplate, you first need to hook and listen to the Game's updates. Also don't forget to unhook and dispose on unloading the plugins!
|
__**DEPRICATED!** Use the ``INameplate`` service wich is now implemented [within Dalamud](https://github.com/goatcorp/Dalamud/pull/1915). The old Nameplate Addon and the new temporary Nameplate service has been removed since v0.7.0 of this library.__
|
||||||
|
|
||||||
```cs
|
|
||||||
public class NameplateFeature : IDisposable
|
|
||||||
{
|
|
||||||
public NameplateManager NameplateManager { get; init; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Occurs when a player nameplate is updated by the game.
|
|
||||||
/// </summary>
|
|
||||||
public event PlayerNameplateUpdatedDelegate? PlayerNameplateUpdated;
|
|
||||||
|
|
||||||
public NameplateFeature()
|
|
||||||
{
|
|
||||||
NameplateManager = new();
|
|
||||||
NameplateManager.Hooks.AddonNamePlate_SetPlayerNameManaged += Hooks_AddonNamePlate_SetPlayerNameManaged;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
NameplateManager.Hooks.AddonNamePlate_SetPlayerNameManaged -= Hooks_AddonNamePlate_SetPlayerNameManaged;
|
|
||||||
NameplateManager.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Hooks_AddonNamePlate_SetPlayerNameManaged(Pilz.Dalamud.Nameplates.EventArgs.AddonNamePlate_SetPlayerNameManagedEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This is an example of editing the title to "Good Player", make the name italic and also force the title to always be above the name:
|
|
||||||
|
|
||||||
```cs
|
|
||||||
private void Hooks_AddonNamePlate_SetPlayerNameManaged(Pilz.Dalamud.Nameplates.EventArgs.AddonNamePlate_SetPlayerNameManagedEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Get the referenced player object for the nameplate object
|
|
||||||
PlayerCharacter? playerCharacter = NameplateManager.GetNameplateGameObject<PlayerCharacter>(eventArgs.SafeNameplateObject);
|
|
||||||
|
|
||||||
if (playerCharacter != null && playerCharacter.StatusFlags.HasFlag(StatusFlags.Friend))
|
|
||||||
{
|
|
||||||
const string TEXT_GOOD_PLAYER = "Good Player";
|
|
||||||
|
|
||||||
// Create a new change
|
|
||||||
var nameplateChanges = new NameplateChanges(eventArgs);
|
|
||||||
|
|
||||||
// Replace the title
|
|
||||||
var titleChange = nameplateChanges.GetChange(NameplateElements.Title, StringPosition.Replace);
|
|
||||||
titleChange.Payloads.Add(new TextPayload(TEXT_GOOD_PLAYER));
|
|
||||||
|
|
||||||
// Make the name italic
|
|
||||||
var nameChangeBefore = nameplateChanges.GetChange(NameplateElements.Name, StringPosition.Before);
|
|
||||||
nameChangeBefore.Payloads.Add(new EmphasisItalicPayload(true));
|
|
||||||
|
|
||||||
var nameChangeAfter = nameplateChanges.GetChange(NameplateElements.Name, StringPosition.After);
|
|
||||||
nameChangeAfter.Payloads.Add(new EmphasisItalicPayload(false));
|
|
||||||
|
|
||||||
// Forge the title to be always above the name (this we can edit directly)
|
|
||||||
eventArgs.IsTitleAboveName = true;
|
|
||||||
|
|
||||||
// Apply the string changes!
|
|
||||||
NameplateUpdateFactory.ApplyNameplateChanges(new NameplateChangesProps(nameplateChanges));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
PluginLog.Error(ex, $"SetPlayerNameplateDetour");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
|
|||||||
14
deploy-nugets.bat
Normal file
14
deploy-nugets.bat
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
set sourceP="https://git.pilzinsel64.de/api/packages/Pilz.NET/nuget/index.json"
|
||||||
|
set apikeyP=%Gitea_git_pilzinsel64_de%
|
||||||
|
|
||||||
|
set sourceN="https://api.nuget.org/v3/index.json"
|
||||||
|
set apikeyN=%NuGet_ApiKey%
|
||||||
|
|
||||||
|
for %%x in (%*) do (
|
||||||
|
dotnet nuget push "%%x" --source "%sourceP%" --api-key "%apikeyP%" --skip-duplicate
|
||||||
|
dotnet nuget push "%%x" --source "%sourceN%" --api-key "%apikeyN%" --skip-duplicate
|
||||||
|
)
|
||||||
|
|
||||||
|
pause
|
||||||
13
deploy-nugets.sh
Normal file
13
deploy-nugets.sh
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
sourceP="https://git.pilzinsel64.de/api/packages/Pilz.NET/nuget/index.json"
|
||||||
|
apikeyP="$Gitea_git_pilzinsel64_de"
|
||||||
|
|
||||||
|
sourceN="https://api.nuget.org/v3/index.json"
|
||||||
|
apikeyN="$NuGet_ApiKey"
|
||||||
|
|
||||||
|
for pkg in "$@"; do
|
||||||
|
dotnet nuget push "$pkg" --source "$sourceP" --api-key "$apikeyP" --skip-duplicate
|
||||||
|
dotnet nuget push "$pkg" --source "$sourceN" --api-key "$apikeyN" --skip-duplicate
|
||||||
|
done
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"dependencies": {
|
|
||||||
"net7.0-windows7.0": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user