4 Commits
1.0.2 ... api9

Author SHA1 Message Date
ca8d5425e6 v0.5.1 2023-10-06 21:06:26 +02:00
ef4e46c5e4 v0.5 final 2023-10-03 16:23:01 +02:00
3715dcb9ac migrate to GameConfig & cleanup warnings 2023-09-24 17:13:41 +02:00
f9ab3462eb some adjustments for API9 2023-09-24 16:41:15 +02:00
51 changed files with 1869 additions and 987 deletions

3
.gitignore vendored
View File

@@ -361,6 +361,3 @@ MigrationBackup/
# Fody - auto-generated XML schema # Fody - auto-generated XML schema
FodyWeavers.xsd FodyWeavers.xsd
# Idea
.idea

21
LICENSE
View File

@@ -1,21 +0,0 @@
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.

View File

@@ -1,5 +1,11 @@
namespace Pilz.Dalamud.ActivityContexts; using System;
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 ActivityType ActivityType { get; init; }
@@ -16,3 +22,4 @@ public class ActivityContext
get => ZoneType != ZoneType.Overworld; get => ZoneType != ZoneType.Overworld;
} }
} }
}

View File

@@ -1,8 +1,14 @@
using Lumina.Excel; using Dalamud.Logging;
using Lumina.Excel.Sheets; using Lumina.Excel;
using Lumina.Excel.GeneratedSheets;
namespace Pilz.Dalamud.ActivityContexts; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Pilz.Dalamud.ActivityContexts
{
public class ActivityContextManager : IDisposable public class ActivityContextManager : IDisposable
{ {
public delegate void ActivityContextChangedEventHandler(ActivityContextManager sender, ActivityContext activityContext); public delegate void ActivityContextChangedEventHandler(ActivityContextManager sender, ActivityContext activityContext);
@@ -36,11 +42,11 @@ public class ActivityContextManager : IDisposable
private void CheckCurrentTerritory() private void CheckCurrentTerritory()
{ {
var content = contentFinderConditionsSheet.FirstOrDefault(c => c.TerritoryType.RowId == PluginServices.ClientState.TerritoryType); var content = contentFinderConditionsSheet.FirstOrDefault(c => c.TerritoryType.Row == PluginServices.ClientState.TerritoryType);
ActivityType newActivityContext; ActivityType newActivityContext;
ZoneType newZoneType; ZoneType newZoneType;
if (content.RowId == 0) if (content == null)
{ {
// No content found, so we must be on the overworld // No content found, so we must be on the overworld
newActivityContext = ActivityType.None; newActivityContext = ActivityType.None;
@@ -58,7 +64,7 @@ public class ActivityContextManager : IDisposable
newActivityContext = ActivityType.PveDuty; newActivityContext = ActivityType.PveDuty;
// Find correct member type // Find correct member type
var memberType = content.ContentMemberType.RowId; var memberType = content.ContentMemberType.Row;
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)
@@ -80,3 +86,4 @@ public class ActivityContextManager : IDisposable
ActivityContextChanged?.Invoke(this, CurrentActivityContext); ActivityContextChanged?.Invoke(this, CurrentActivityContext);
} }
} }
}

View File

@@ -1,8 +1,13 @@
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))] [JsonConverter(typeof(StringEnumConverter))]
public enum ActivityType public enum ActivityType
{ {
@@ -10,3 +15,4 @@ public enum ActivityType
PveDuty = 0x1, PveDuty = 0x1,
PvpDuty = 0x2 PvpDuty = 0x2
} }
}

View File

@@ -1,8 +1,13 @@
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))] [Flags, JsonConverter(typeof(StringEnumConverter))]
public enum ZoneType public enum ZoneType
{ {
@@ -14,3 +19,4 @@ public enum ZoneType
Pvp = 32, Pvp = 32,
Everywhere = int.MaxValue Everywhere = int.MaxValue
} }
}

View File

@@ -1,10 +1,12 @@
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Lumina.Text.ReadOnly; using System;
using System.Runtime.CompilerServices; using System.Collections.Generic;
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> /// <summary>
@@ -35,10 +37,5 @@ public static class Extensions
} }
} }
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static string ParseString(this ReadOnlySeString readOnlySeString)
{
return Encoding.UTF8.GetString(readOnlySeString);
} }
} }

View File

@@ -1,10 +1,14 @@
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)
@@ -146,3 +150,4 @@ public static class GameInterfaceHelper
ptr = IntPtr.Zero; ptr = IntPtr.Zero;
} }
} }
}

View File

@@ -1,5 +1,12 @@
namespace Pilz.Dalamud.Icons; using System;
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; private readonly int[] icons;
@@ -17,3 +24,4 @@ public class JobIconSet
return icons[jobID - 1]; return icons[jobID - 1];
} }
} }
}

View File

@@ -1,5 +1,11 @@
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 enum JobIconSetName public enum JobIconSetName
{ {
Gold, Gold,
@@ -15,3 +21,4 @@ public enum JobIconSetName
Grey, Grey,
Role Role
} }
}

View File

@@ -1,118 +1,113 @@
namespace Pilz.Dalamud.Icons; using Lumina.Excel.GeneratedSheets;
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 = []; private readonly Dictionary<JobIconSetName, JobIconSet> iconSets = new();
public JobIconSets() public JobIconSets()
{ {
Add(JobIconSetName.Gold, Add(JobIconSetName.Gold, new[]
[ {
62001, 62002, 62003, 62004, 62005, 62006, 62007, 62008, 62009, 62010, 62001, 62002, 62003, 62004, 62005, 62006, 62007, 62008, 62009, 62010,
62011, 62012, 62013, 62014, 62015, 62016, 62017, 62018, 62019, 62020, 62011, 62012, 62013, 62014, 62015, 62016, 62017, 62018, 62019, 62020,
62021, 62022, 62023, 62024, 62025, 62026, 62027, 62028, 62029, 62030, 62021, 62022, 62023, 62024, 62025, 62026, 62027, 62028, 62029, 62030,
62031, 62032, 62033, 62034, 62035, 62036, 62037, 62038, 62039, 62040, 62031, 62032, 62033, 62034, 62035, 62036, 62037, 62038, 62039, 62040
62041, 62042, }, 1);
], 1);
Add(JobIconSetName.Framed, Add(JobIconSetName.Framed, new[]
[ {
62101, 62102, 62103, 62104, 62105, 62106, 62107, 62108, 62109, 62110, 62101, 62102, 62103, 62104, 62105, 62106, 62107, 62108, 62109, 62110,
62111, 62112, 62113, 62114, 62115, 62116, 62117, 62118, 62119, 62120, 62111, 62112, 62113, 62114, 62115, 62116, 62117, 62118, 62119, 62120,
62121, 62122, 62123, 62124, 62125, 62126, 62127, 62128, 62129, 62130, 62121, 62122, 62123, 62124, 62125, 62126, 62127, 62128, 62129, 62130,
62131, 62132, 62133, 62134, 62135, 62136, 62137, 62138, 62139, 62140, 62131, 62132, 62133, 62134, 62135, 62136, 62137, 62138, 62139, 62140
62141, 62142, });
]);
Add(JobIconSetName.Glowing, Add(JobIconSetName.Glowing, new[]
[ {
62301, 62302, 62303, 62304, 62305, 62306, 62307, 62310, 62311, 62312, 62301, 62302, 62303, 62304, 62305, 62306, 62307, 62310, 62311, 62312,
62313, 62314, 62315, 62316, 62317, 62318, 62319, 62320, 62401, 62402, 62313, 62314, 62315, 62316, 62317, 62318, 62319, 62320, 62401, 62402,
62403, 62404, 62405, 62406, 62407, 62308, 62408, 62409, 62309, 62410, 62403, 62404, 62405, 62406, 62407, 62308, 62408, 62409, 62309, 62410,
62411, 62412, 62413, 62414, 62415, 62416, 62417, 62418, 62419, 62420, 62411, 62412, 62413, 62414, 62415, 62416, 62417, 62418, 62419, 62420
62421, 62422, });
]);
Add(JobIconSetName.Grey, Add(JobIconSetName.Grey, new[]
[ {
91022, 91023, 91024, 91025, 91026, 91028, 91029, 91031, 91032, 91033, 91022, 91023, 91024, 91025, 91026, 91028, 91029, 91031, 91032, 91033,
91034, 91035, 91036, 91037, 91038, 91039, 91040, 91041, 91079, 91080, 91034, 91035, 91036, 91037, 91038, 91039, 91040, 91041, 91079, 91080,
91081, 91082, 91083, 91084, 91085, 91030, 91086, 91087, 91121, 91122, 91081, 91082, 91083, 91084, 91085, 91030, 91086, 91087, 91121, 91122,
91125, 91123, 91124, 91127, 91128, 91129, 91130, 91131, 91132, 91133, 91125, 91123, 91124, 91127, 91128, 91129, 91130, 91131, 91132, 91133
91185, 91186, }, 2);
], 2);
Add(JobIconSetName.Black, Add(JobIconSetName.Black, new[]
[ {
91522, 91523, 91524, 91525, 91526, 91528, 91529, 91531, 91532, 91533, 91522, 91523, 91524, 91525, 91526, 91528, 91529, 91531, 91532, 91533,
91534, 91535, 91536, 91537, 91538, 91539, 91540, 91541, 91579, 91580, 91534, 91535, 91536, 91537, 91538, 91539, 91540, 91541, 91579, 91580,
91581, 91582, 91583, 91584, 91585, 91530, 91586, 91587, 91621, 91622, 91581, 91582, 91583, 91584, 91585, 91530, 91586, 91587, 91621, 91622,
91625, 91623, 91624, 91627, 91628, 91629, 91630, 91631, 91632, 91633, 91625, 91623, 91624, 91627, 91628, 91629, 91630, 91631, 91632, 91633
91685, 91686, }, 2);
], 2);
Add(JobIconSetName.Yellow, Add(JobIconSetName.Yellow, new[]
[ {
92022, 92023, 92024, 92025, 92026, 92028, 92029, 92031, 92032, 92033, 92022, 92023, 92024, 92025, 92026, 92028, 92029, 92031, 92032, 92033,
92034, 92035, 92036, 92037, 92038, 92039, 92040, 92041, 92079, 92080, 92034, 92035, 92036, 92037, 92038, 92039, 92040, 92041, 92079, 92080,
92081, 92082, 92083, 92084, 92085, 92030, 92086, 92087, 92121, 92122, 92081, 92082, 92083, 92084, 92085, 92030, 92086, 92087, 92121, 92122,
92125, 92123, 92124, 92127, 92128, 92129, 92130, 92131, 92132, 92133, 92125, 92123, 92124, 92127, 92128, 92129, 92130, 92131, 92132, 92133
92185, 92186, }, 2);
], 2);
Add(JobIconSetName.Orange, Add(JobIconSetName.Orange, new[]
[ {
92522, 92523, 92524, 92525, 92526, 92528, 92529, 92531, 92532, 92533, 92522, 92523, 92524, 92525, 92526, 92528, 92529, 92531, 92532, 92533,
92534, 92535, 92536, 92537, 92538, 92539, 92540, 92541, 92579, 92580, 92534, 92535, 92536, 92537, 92538, 92539, 92540, 92541, 92579, 92580,
92581, 92582, 92583, 92584, 92585, 92530, 92586, 92587, 92621, 92622, 92581, 92582, 92583, 92584, 92585, 92530, 92586, 92587, 92621, 92622,
92625, 92623, 92624, 92627, 92628, 92629, 92630, 92631, 92632, 92633, 92625, 92623, 92624, 92627, 92628, 92629, 92630, 92631, 92632, 92633
92685, 92686, }, 2);
], 2);
Add(JobIconSetName.Red, Add(JobIconSetName.Red, new[]
[ {
93022, 93023, 93024, 93025, 93026, 93028, 93029, 93031, 93032, 93033, 93022, 93023, 93024, 93025, 93026, 93028, 93029, 93031, 93032, 93033,
93034, 93035, 93036, 93037, 93038, 93039, 93040, 93041, 93079, 93080, 93034, 93035, 93036, 93037, 93038, 93039, 93040, 93041, 93079, 93080,
93081, 93082, 93083, 93084, 93085, 93030, 93086, 93087, 93121, 93122, 93081, 93082, 93083, 93084, 93085, 93030, 93086, 93087, 93121, 93122,
93125, 93123, 93124, 93127, 93128, 93129, 93130, 93131, 93132, 93133, 93125, 93123, 93124, 93127, 93128, 93129, 93130, 93131, 93132, 93133
93185, 93186, }, 2);
], 2);
Add(JobIconSetName.Purple, icons: new[] Add(JobIconSetName.Purple, new[]
{ {
93522, 93523, 93524, 93525, 93526, 93528, 93529, 93531, 93532, 93533, 93522, 93523, 93524, 93525, 93526, 93528, 93529, 93531, 93532, 93533,
93534, 93535, 93536, 93537, 93538, 93539, 93540, 93541, 93579, 93580, 93534, 93535, 93536, 93537, 93538, 93539, 93540, 93541, 93579, 93580,
93581, 93582, 93583, 93584, 93585, 93530, 93586, 93587, 93621, 93622, 93581, 93582, 93583, 93584, 93585, 93530, 93586, 93587, 93621, 93622,
93625, 93623, 93624, 93627, 93628, 93629, 93630, 93631, 93632, 93633, 93625, 93623, 93624, 93627, 93628, 93629, 93630, 93631, 93632, 93633
93685, 93686, }, 2);
}, scale: 2);
Add(JobIconSetName.Blue, Add(JobIconSetName.Blue, new[]
[ {
94022, 94023, 94024, 94025, 94026, 94028, 94029, 94031, 94032, 94033, 94022, 94023, 94024, 94025, 94026, 94028, 94029, 94031, 94032, 94033,
94034, 94035, 94036, 94037, 94038, 94039, 94040, 94041, 94079, 94080, 94034, 94035, 94036, 94037, 94038, 94039, 94040, 94041, 94079, 94080,
94081, 94082, 94083, 94084, 94085, 94030, 94086, 94087, 94121, 94122, 94081, 94082, 94083, 94084, 94085, 94030, 94086, 94087, 94121, 94122,
94125, 94123, 94124, 94127, 94128, 94129, 94130, 94131, 94132, 94133, 94125, 94123, 94124, 94127, 94128, 94129, 94130, 94131, 94132, 94133
94185, 94186, }, 2);
], 2);
Add(JobIconSetName.Green, Add(JobIconSetName.Green, new[]
[ {
94522, 94523, 94524, 94525, 94526, 94528, 94529, 94531, 94532, 94533, 94522, 94523, 94524, 94525, 94526, 94528, 94529, 94531, 94532, 94533,
94534, 94535, 94536, 94537, 94538, 94539, 94540, 94541, 94579, 94580, 94534, 94535, 94536, 94537, 94538, 94539, 94540, 94541, 94579, 94580,
94581, 94582, 94583, 94584, 94585, 94530, 94586, 94587, 94621, 94622, 94581, 94582, 94583, 94584, 94585, 94530, 94586, 94587, 94621, 94622,
94625, 94623, 94624, 94627, 94628, 94629, 94630, 94631, 94632, 94633, 94625, 94623, 94624, 94627, 94628, 94629, 94630, 94631, 94632, 94633
94685, 94686, }, 2);
], 2);
Add(JobIconSetName.Role, Add(JobIconSetName.Role, new[]
[ {
62581, 62584, 62581, 62584, 62586, 62582, 62502, 62502, 62503, 62504, 62581, 62584, 62581, 62584, 62586, 62582, 62502, 62502, 62503, 62504,
62505, 62506, 62507, 62508, 62509, 62510, 62511, 62512, 62581, 62584, 62505, 62506, 62507, 62508, 62509, 62510, 62511, 62512, 62581, 62584,
62581, 62584, 62586, 62582, 62587, 62587, 62587, 62582, 62584, 62584, 62581, 62584, 62586, 62582, 62587, 62587, 62587, 62582, 62584, 62584,
62586, 62581, 62582, 62584, 62587, 62587, 62581, 62586, 62584, 62582, 62586, 62581, 62582, 62584, 62587, 62587, 62581, 62586, 62584, 62582
62584, 62584, });
]);
} }
private void Add(JobIconSetName id, int[] icons, float scale = 1f) private void Add(JobIconSetName id, int[] icons, float scale = 1f)
@@ -130,3 +125,4 @@ public class JobIconSets
return iconSets[set].IconScale; return iconSets[set].IconScale;
} }
} }
}

View File

@@ -1,25 +0,0 @@
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,
}

View File

@@ -0,0 +1,20 @@
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; }
}
}

View File

@@ -0,0 +1,43 @@
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;
}
}
}

View File

@@ -0,0 +1,18 @@
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();
}
}
}

View File

@@ -0,0 +1,13 @@
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; }
}
}

View File

@@ -0,0 +1,21 @@
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();
}
}
}

View File

@@ -0,0 +1,13 @@
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; }
}
}

View File

@@ -0,0 +1,43 @@
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;
}
}
}

View File

@@ -0,0 +1,57 @@
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);
}
}
}

View File

@@ -0,0 +1,128 @@
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);
}
}
}

View File

@@ -0,0 +1,31 @@
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,
}
}

View File

@@ -0,0 +1,219 @@
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;
using Dalamud.Plugin.Services;
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()
{
PluginServices.GameInteropProvider.InitializeFromAttributes(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;
}
}
}

View File

@@ -0,0 +1,83 @@
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;
}
}
}

View File

@@ -0,0 +1,60 @@
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>
/// <param name="position">The position of your choice.</param>
/// <returns></returns>
public StringChange GetChange(NameplateElements element, StringPosition position)
{
return GetChanges(element).GetChange(position);
}
}
}

View File

@@ -0,0 +1,25 @@
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;
}
}
}

View File

@@ -0,0 +1,15 @@
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
}
}

View File

@@ -0,0 +1,52 @@
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;
}
}
}

View File

@@ -0,0 +1,67 @@
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="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);
}
}
}

View File

@@ -0,0 +1,15 @@
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
}
}

View File

@@ -0,0 +1,110 @@
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,
});
}
}
}

View File

@@ -1,20 +1,30 @@
<Project Sdk="Dalamud.NET.Sdk/12.0.2"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>annotations</Nullable> <Nullable>annotations</Nullable>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Use_DalamudPackager>false</Use_DalamudPackager> <LangVersion>latest</LangVersion>
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<Platforms>x64</Platforms>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<PropertyGroup>
<DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild> <GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<Copyright>Pilzinsel64</Copyright> <Copyright>Pilzinsel64</Copyright>
<PackageProjectUrl>https://github.com/Pilzinsel64/Pilz.Dalamud</PackageProjectUrl> <PackageProjectUrl>https://github.com/Pilzinsel64/Pilz.Dalamud</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile> <PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/Pilzinsel64/Pilz.Dalamud</RepositoryUrl> <RepositoryUrl>https://github.com/Pilzinsel64/Pilz.Dalamud</RepositoryUrl>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<Version>1.0.2</Version> <Version>0.5.1</Version>
<GenerateDocumentationFile>True</GenerateDocumentationFile> <GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup> </PropertyGroup>
@@ -26,6 +36,37 @@
<NoWarn>1701;1702;1591</NoWarn> <NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup> </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> <ItemGroup>
<None Include="..\README.md" Pack="true" PackagePath="\" /> <None Include="..\README.md" Pack="true" PackagePath="\" />
</ItemGroup> </ItemGroup>

View File

@@ -1,21 +1,30 @@
using Dalamud.IoC; using Dalamud.Data;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.Gui;
using Dalamud.IoC;
using Dalamud.Plugin; using Dalamud.Plugin;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using System;
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 DalamudPluginInterface PluginInterface { get; set; } = null;
[PluginService] public static IGameGui GameGui { get; set; } [PluginService] public static IGameGui GameGui { get; set; } = null;
[PluginService] public static IClientState ClientState { get; set; } [PluginService] public static IClientState ClientState { get; set; } = null;
[PluginService] public static IDataManager DataManager { get; set; } [PluginService] public static IDataManager DataManager { get; set; } = null;
[PluginService] public static IObjectTable ObjectTable { get; set; } [PluginService] public static IObjectTable ObjectTable { get; set; } = null;
[PluginService] public static IGameInteropProvider GameInteropProvider { get; set; } [PluginService] public static IGameInteropProvider GameInteropProvider { get; set; } = null;
[PluginService] public static IAddonLifecycle AddonLifecycle { get; set; }
public static void Initialize(IDalamudPluginInterface dalamudPluginInterface) public static void Initialize(DalamudPluginInterface dalamudPluginInterface)
{ {
dalamudPluginInterface.Create<PluginServices>(); dalamudPluginInterface.Create<PluginServices>();
} }
} }
}

View File

@@ -1,25 +0,0 @@
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);
}
}

View File

@@ -1,18 +0,0 @@
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;
}
}

View File

@@ -1,47 +0,0 @@
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,
},
});
}
}
}

View File

@@ -1,8 +0,0 @@
namespace Pilz.Dalamud.Tools.NamePlates;
public enum NameplateElements
{
Name,
Title,
FreeCompany,
}

View File

@@ -1,48 +0,0 @@
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;
}
}

View File

@@ -1,60 +0,0 @@
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);
}
}

View File

@@ -1,8 +0,0 @@
namespace Pilz.Dalamud.Tools.NamePlates;
public enum StatusIconPriorizerConditionSets
{
Overworld,
InDuty,
InForay
}

View File

@@ -1,103 +0,0 @@
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,
});
}
}

View File

@@ -1,8 +1,13 @@
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Pilz.Dalamud.Icons; using Pilz.Dalamud.Nameplates.Model;
using System;
namespace Pilz.Dalamud.Tools; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Pilz.Dalamud.Tools
{
public static class StatusIconFontConverter public static class StatusIconFontConverter
{ {
public static StatusIcons? GetStatusIconFromBitmapFontIcon(BitmapFontIcon fontIcon) public static StatusIcons? GetStatusIconFromBitmapFontIcon(BitmapFontIcon fontIcon)
@@ -33,3 +38,4 @@ public static class StatusIconFontConverter
}; };
} }
} }
}

View File

@@ -1,13 +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> /// <summary>
/// The payloads to use for inserting/replacing. /// The payloads to use for inserting/replacing.
/// </summary> /// </summary>
public List<Payload> Payloads { get; init; } = []; 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.
@@ -16,3 +21,4 @@ public class StringChange
/// </summary> /// </summary>
public bool ForceUsingSingleAnchorPayload { get; set; } = false; public bool ForceUsingSingleAnchorPayload { get; set; } = false;
} }
}

View File

@@ -1,8 +1,15 @@
namespace Pilz.Dalamud.Tools.Strings; 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
{
public class StringChanges public class StringChanges
{ {
private readonly Dictionary<StringPosition, StringChange> changes = []; private readonly Dictionary<StringPosition, StringChange> changes = new();
public StringChanges() public StringChanges()
{ {
@@ -30,3 +37,4 @@ public class StringChanges
return changes.Sum(n => n.Value.Payloads.Count) != 0; return changes.Sum(n => n.Value.Payloads.Count) != 0;
} }
} }
}

View File

@@ -1,7 +1,13 @@
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.ClientState.Objects.Types;
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 StringChangesProps public class StringChangesProps
{ {
/// <summary> /// <summary>
@@ -15,10 +21,11 @@ public class StringChangesProps
/// <summary> /// <summary>
/// Payloads to use as anchor where the changes should be applied to. /// Payloads to use as anchor where the changes should be applied to.
/// </summary> /// </summary>
public List<Payload> AnchorPayloads { get; set; } = []; public List<Payload> AnchorPayloads { get; set; } = new();
/// <summary> /// <summary>
/// A single payload to use as anchor where the changes should be applied to. /// A single payload to use as anchor where the changes should be applied to.
/// This property will only be used if StringChange.ForceSingleAnchorPayload is true. /// This property will only be used if StringChange.ForceSingleAnchorPayload is true.
/// </summary> /// </summary>
public Payload AnchorPayload { get; set; } public Payload AnchorPayload { get; set; }
} }
}

View File

@@ -1,8 +1,15 @@
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 enum StringPosition public enum StringPosition
{ {
Before, Before,
After, After,
Replace Replace
} }
}

View File

@@ -1,8 +1,14 @@
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)
@@ -123,3 +129,4 @@ public static class StringUpdateFactory
return tagPositionsOrdered; return tagPositionsOrdered;
} }
} }
}

39
Pilz.Dalamud/XivApi.cs Normal file
View File

@@ -0,0 +1,39 @@
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);
}
}
}

View File

@@ -1,13 +1,6 @@
{ {
"version": 1, "version": 1,
"dependencies": { "dependencies": {
"net9.0-windows7.0": { "net7.0-windows7.0": {}
"DotNet.ReproducibleBuilds": {
"type": "Direct",
"requested": "[1.2.25, )",
"resolved": "1.2.25",
"contentHash": "xCXiw7BCxHJ8pF6wPepRUddlh2dlQlbr81gXA72hdk4FLHkKXas7EH/n+fk5UCA/YfMqG1Z6XaPiUjDbUNBUzg=="
}
}
} }
} }

View File

@@ -1,14 +0,0 @@
@echo off
set sourceP="https://git.pilzinsel64.de/api/v4/projects/25/packages/nuget/index.json"
set apikeyP=%GitLab_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

View File

@@ -8,9 +8,6 @@ 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.Dalamud" value="https://git.pilzinsel64.de/api/v4/projects/8/packages/nuget/index.json" />`\
## Get started ## Get started
### Initialize Plugin Services ### Initialize Plugin Services
@@ -28,9 +25,79 @@ public Plugin(DalamudPluginInterface pluginInterface)
} }
``` ```
### Hook into NamePlates ### Hook into Nameplates
__**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.__ 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!
```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