Compare commits
6 Commits
v1.9.5
...
feature/ta
| Author | SHA1 | Date | |
|---|---|---|---|
| 094a82b2f0 | |||
| f977d4e9b9 | |||
| 90f554df8c | |||
| 76648b4b94 | |||
| 7b76a2cbd0 | |||
| 84a8aaad31 |
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -1,4 +0,0 @@
|
||||
[submodule "Pilz.Dalamud"]
|
||||
path = Pilz.Dalamud
|
||||
url = https://github.com/Pilzinsel64/Pilz.Dalamud.git
|
||||
branch = master
|
||||
Submodule Pilz.Dalamud deleted from 8e7d49ca01
25
Pilz.Dalamud/ActivityContexts/ActivityContext.cs
Normal file
25
Pilz.Dalamud/ActivityContexts/ActivityContext.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Dalamud.ActivityContexts
|
||||
{
|
||||
public class ActivityContext
|
||||
{
|
||||
public ActivityType ActivityType { get; init; }
|
||||
public ZoneType ZoneType { get; init; }
|
||||
|
||||
public ActivityContext(ActivityType activityType, ZoneType zoneType)
|
||||
{
|
||||
ActivityType = activityType;
|
||||
ZoneType = zoneType;
|
||||
}
|
||||
|
||||
public bool IsInDuty
|
||||
{
|
||||
get => ZoneType != ZoneType.Overworld;
|
||||
}
|
||||
}
|
||||
}
|
||||
89
Pilz.Dalamud/ActivityContexts/ActivityContextManager.cs
Normal file
89
Pilz.Dalamud/ActivityContexts/ActivityContextManager.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using Dalamud.Logging;
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
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 delegate void ActivityContextChangedEventHandler(ActivityContextManager sender, ActivityContext activityContext);
|
||||
public event ActivityContextChangedEventHandler ActivityContextChanged;
|
||||
|
||||
private readonly ExcelSheet<ContentFinderCondition> contentFinderConditionsSheet;
|
||||
|
||||
public ActivityContext CurrentActivityContext { get; protected set; }
|
||||
|
||||
public ActivityContextManager()
|
||||
{
|
||||
// Get condition sheet
|
||||
contentFinderConditionsSheet = PluginServices.DataManager.GameData.GetExcelSheet<ContentFinderCondition>();
|
||||
|
||||
// Checks current territory type (if enabled/installed during a dutiy e.g.)
|
||||
CheckCurrentTerritory();
|
||||
|
||||
// Enable event for automatic checks
|
||||
PluginServices.ClientState.TerritoryChanged += ClientState_TerritoryChanged;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
PluginServices.ClientState.TerritoryChanged -= ClientState_TerritoryChanged;
|
||||
}
|
||||
|
||||
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.None;
|
||||
newZoneType = ZoneType.Overworld;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (content.PvP)
|
||||
{
|
||||
newActivityContext = ActivityType.PvpDuty;
|
||||
newZoneType = ZoneType.Pvp;
|
||||
}
|
||||
else
|
||||
{
|
||||
newActivityContext = ActivityType.PveDuty;
|
||||
|
||||
// Find correct member type
|
||||
var memberType = content.ContentMemberType.Row;
|
||||
if (content.RowId == 16 || content.RowId == 15)
|
||||
memberType = 2; // Praetorium and Castrum Meridianum
|
||||
else if (content.RowId == 735 || content.RowId == 778)
|
||||
memberType = 127; // Bozja
|
||||
|
||||
// Check for ZoneType
|
||||
newZoneType = memberType switch
|
||||
{
|
||||
2 => ZoneType.Doungen,
|
||||
3 => ZoneType.Raid,
|
||||
4 => ZoneType.AllianceRaid,
|
||||
127 => ZoneType.Foray,
|
||||
_ => ZoneType.Doungen,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
CurrentActivityContext = new(newActivityContext, newZoneType);
|
||||
ActivityContextChanged?.Invoke(this, CurrentActivityContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Pilz.Dalamud/ActivityContexts/ActivityType.cs
Normal file
18
Pilz.Dalamud/ActivityContexts/ActivityType.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
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.ActivityContexts
|
||||
{
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum ActivityType
|
||||
{
|
||||
None = 0x0,
|
||||
PveDuty = 0x1,
|
||||
PvpDuty = 0x2
|
||||
}
|
||||
}
|
||||
22
Pilz.Dalamud/ActivityContexts/ZoneType.cs
Normal file
22
Pilz.Dalamud/ActivityContexts/ZoneType.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
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.ActivityContexts
|
||||
{
|
||||
[Flags, JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum ZoneType
|
||||
{
|
||||
Overworld = 1,
|
||||
Doungen = 2,
|
||||
Raid = 4,
|
||||
AllianceRaid = 8,
|
||||
Foray = 16,
|
||||
Pvp = 32,
|
||||
Everywhere = int.MaxValue
|
||||
}
|
||||
}
|
||||
41
Pilz.Dalamud/Extensions.cs
Normal file
41
Pilz.Dalamud/Extensions.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Dalamud
|
||||
{
|
||||
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)
|
||||
{
|
||||
Remove(seString.Payloads, payload);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="seString"></param>
|
||||
/// <param name="payload"></param>
|
||||
public static void Remove(this List<Payload> payloads, Payload payload)
|
||||
{
|
||||
for (int i = 0; i < payloads.Count; i++)
|
||||
{
|
||||
if (ReferenceEquals(payloads[i], payload))
|
||||
{
|
||||
payloads.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
153
Pilz.Dalamud/GameInterfaceHelper.cs
Normal file
153
Pilz.Dalamud/GameInterfaceHelper.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Dalamud
|
||||
{
|
||||
public static class GameInterfaceHelper
|
||||
{
|
||||
public static SeString ReadSeString(IntPtr ptr)
|
||||
{
|
||||
if (ptr == IntPtr.Zero)
|
||||
{
|
||||
return new SeString();
|
||||
}
|
||||
|
||||
if (TryReadStringBytes(ptr, out var bytes) && bytes != null)
|
||||
{
|
||||
return SeString.Parse(bytes);
|
||||
}
|
||||
|
||||
return new SeString();
|
||||
}
|
||||
|
||||
public static bool TryReadSeString(IntPtr ptr, out SeString? seString)
|
||||
{
|
||||
seString = null;
|
||||
if (ptr == IntPtr.Zero)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TryReadStringBytes(ptr, out var bytes) && bytes != null)
|
||||
{
|
||||
seString = SeString.Parse(bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string? ReadString(IntPtr ptr)
|
||||
{
|
||||
if (ptr == IntPtr.Zero)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Pilz.Dalamud/Icons/JobIconSet.cs
Normal file
27
Pilz.Dalamud/Icons/JobIconSet.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
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
|
||||
{
|
||||
private readonly int[] icons;
|
||||
|
||||
public float IconScale { get; init; }
|
||||
|
||||
public JobIconSet(int[] icons, float iconScale)
|
||||
{
|
||||
this.icons = icons;
|
||||
IconScale = iconScale;
|
||||
}
|
||||
|
||||
public int GetIcon(uint jobID)
|
||||
{
|
||||
return icons[jobID - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
24
Pilz.Dalamud/Icons/JobIconSetName.cs
Normal file
24
Pilz.Dalamud/Icons/JobIconSetName.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Dalamud.Icons
|
||||
{
|
||||
public enum JobIconSetName
|
||||
{
|
||||
Gold,
|
||||
Framed,
|
||||
Glowing,
|
||||
Blue,
|
||||
Red,
|
||||
Purple,
|
||||
Black,
|
||||
Yellow,
|
||||
Orange,
|
||||
Green,
|
||||
Grey,
|
||||
Role
|
||||
}
|
||||
}
|
||||
128
Pilz.Dalamud/Icons/JobIconSets.cs
Normal file
128
Pilz.Dalamud/Icons/JobIconSets.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
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
|
||||
{
|
||||
private readonly Dictionary<JobIconSetName, JobIconSet> iconSets = new();
|
||||
|
||||
public JobIconSets()
|
||||
{
|
||||
Add(JobIconSetName.Gold, new[]
|
||||
{
|
||||
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
|
||||
}, 1);
|
||||
|
||||
Add(JobIconSetName.Framed, new[]
|
||||
{
|
||||
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
|
||||
});
|
||||
|
||||
Add(JobIconSetName.Glowing, new[]
|
||||
{
|
||||
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
|
||||
});
|
||||
|
||||
Add(JobIconSetName.Grey, new[]
|
||||
{
|
||||
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
|
||||
}, 2);
|
||||
|
||||
Add(JobIconSetName.Black, new[]
|
||||
{
|
||||
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
|
||||
}, 2);
|
||||
|
||||
Add(JobIconSetName.Yellow, new[]
|
||||
{
|
||||
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
|
||||
}, 2);
|
||||
|
||||
Add(JobIconSetName.Orange, new[]
|
||||
{
|
||||
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
|
||||
}, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
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 bool IsTitleAboveName { get; set; }
|
||||
public bool IsTitleVisible { get; set; }
|
||||
public int IconID { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Pilz.Dalamud/Nameplates/EventArgs/HookBaseEventArgs.cs
Normal file
18
Pilz.Dalamud/Nameplates/EventArgs/HookBaseEventArgs.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
43
Pilz.Dalamud/Nameplates/Model/SafeAddonNameplate.cs
Normal file
43
Pilz.Dalamud/Nameplates/Model/SafeAddonNameplate.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Pilz.Dalamud/Nameplates/Model/SafeNameplateInfo.cs
Normal file
57
Pilz.Dalamud/Nameplates/Model/SafeNameplateInfo.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
128
Pilz.Dalamud/Nameplates/Model/SafeNameplateObject.cs
Normal file
128
Pilz.Dalamud/Nameplates/Model/SafeNameplateObject.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
31
Pilz.Dalamud/Nameplates/Model/StatusIcons.cs
Normal file
31
Pilz.Dalamud/Nameplates/Model/StatusIcons.cs
Normal 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,
|
||||
}
|
||||
}
|
||||
203
Pilz.Dalamud/Nameplates/NameplateHooks.cs
Normal file
203
Pilz.Dalamud/Nameplates/NameplateHooks.cs
Normal file
@@ -0,0 +1,203 @@
|
||||
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("48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 54 41 56 41 57 48 83 EC 40 44 0F B6 E2", DetourName = nameof(SetPlayerNameplateDetour))]
|
||||
private readonly 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, 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, int iconId)
|
||||
{
|
||||
var result = IntPtr.Zero;
|
||||
|
||||
if (IsHookEnabled(hook_AddonNamePlate_SetPlayerNameplateDetour))
|
||||
{
|
||||
var eventArgs = new AddonNamePlate_SetPlayerNameEventArgs
|
||||
{
|
||||
PlayerNameplateObjectPtr = playerNameplateObjectPtr,
|
||||
TitlePtr = titlePtr,
|
||||
NamePtr = namePtr,
|
||||
FreeCompanyPtr = freeCompanyPtr,
|
||||
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,
|
||||
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;
|
||||
|
||||
// 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)
|
||||
};
|
||||
|
||||
// Get raw string content
|
||||
var titleRaw = managedEventArgs.Title.Encode();
|
||||
var nameRaw = managedEventArgs.Name.Encode();
|
||||
var freeCompanyRaw = managedEventArgs.FreeCompany.Encode();
|
||||
|
||||
// Invoke Managed Event
|
||||
AddonNamePlate_SetPlayerNameManaged.Invoke(managedEventArgs);
|
||||
|
||||
// Get new Title string ontent
|
||||
var titleNewRaw = managedEventArgs.Title.Encode();
|
||||
if (!titleRaw.SequenceEqual(titleNewRaw))
|
||||
{
|
||||
eventArgs.TitlePtr = GameInterfaceHelper.PluginAllocate(titleNewRaw);
|
||||
freeTitle = true;
|
||||
}
|
||||
|
||||
// Get new Name string ontent
|
||||
var nameNewRaw = managedEventArgs.Name.Encode();
|
||||
if (!nameRaw.SequenceEqual(nameNewRaw))
|
||||
{
|
||||
eventArgs.NamePtr = GameInterfaceHelper.PluginAllocate(nameNewRaw);
|
||||
freeName = true;
|
||||
}
|
||||
|
||||
// Get new Free Company string ontent
|
||||
var freeCompanyNewRaw = managedEventArgs.FreeCompany.Encode();
|
||||
if (!freeCompanyRaw.SequenceEqual(freeCompanyNewRaw))
|
||||
{
|
||||
eventArgs.FreeCompanyPtr = GameInterfaceHelper.PluginAllocate(freeCompanyNewRaw);
|
||||
freeFreeCompany = 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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
83
Pilz.Dalamud/Nameplates/NameplateManager.cs
Normal file
83
Pilz.Dalamud/Nameplates/NameplateManager.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
59
Pilz.Dalamud/Nameplates/Tools/NameplateChanges.cs
Normal file
59
Pilz.Dalamud/Nameplates/Tools/NameplateChanges.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Pilz.Dalamud/Nameplates/Tools/NameplateChangesProps.cs
Normal file
25
Pilz.Dalamud/Nameplates/Tools/NameplateChangesProps.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Pilz.Dalamud/Nameplates/Tools/NameplateElements.cs
Normal file
15
Pilz.Dalamud/Nameplates/Tools/NameplateElements.cs
Normal 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
|
||||
}
|
||||
}
|
||||
52
Pilz.Dalamud/Nameplates/Tools/NameplateUpdateFactory.cs
Normal file
52
Pilz.Dalamud/Nameplates/Tools/NameplateUpdateFactory.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
Pilz.Dalamud/Nameplates/Tools/StatusIconPriorizer.cs
Normal file
67
Pilz.Dalamud/Nameplates/Tools/StatusIconPriorizer.cs
Normal 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="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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
110
Pilz.Dalamud/Nameplates/Tools/StatusIconPriorizerSettings.cs
Normal file
110
Pilz.Dalamud/Nameplates/Tools/StatusIconPriorizerSettings.cs
Normal 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,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
66
Pilz.Dalamud/Pilz.Dalamud.csproj
Normal file
66
Pilz.Dalamud/Pilz.Dalamud.csproj
Normal file
@@ -0,0 +1,66 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>annotations</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<Platforms>x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<Copyright>Pilzinsel64</Copyright>
|
||||
<PackageProjectUrl>https://github.com/Pilzinsel64/Pilz.Dalamud</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/Pilzinsel64/Pilz.Dalamud</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<Version>0.3.1</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>
|
||||
<None Include="..\README.md" Pack="true" PackagePath="\"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
28
Pilz.Dalamud/PluginServices.cs
Normal file
28
Pilz.Dalamud/PluginServices.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.Plugin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Dalamud
|
||||
{
|
||||
public class PluginServices
|
||||
{
|
||||
[PluginService] public static GameGui GameGui { get; set; } = null;
|
||||
[PluginService] public static DalamudPluginInterface PluginInterface { get; set; } = null;
|
||||
[PluginService] public static ClientState ClientState { get; set; } = null;
|
||||
[PluginService] public static DataManager DataManager { get; set; } = null;
|
||||
[PluginService] public static ObjectTable ObjectTable { get; set; } = null;
|
||||
|
||||
public static void Initialize(DalamudPluginInterface dalamudPluginInterface)
|
||||
{
|
||||
dalamudPluginInterface.Create<PluginServices>();
|
||||
}
|
||||
}
|
||||
}
|
||||
41
Pilz.Dalamud/Tools/StatusIconFontConverter.cs
Normal file
41
Pilz.Dalamud/Tools/StatusIconFontConverter.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
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.Tools
|
||||
{
|
||||
public static class StatusIconFontConverter
|
||||
{
|
||||
public static StatusIcons? GetStatusIconFromBitmapFontIcon(BitmapFontIcon fontIcon)
|
||||
{
|
||||
return fontIcon switch
|
||||
{
|
||||
BitmapFontIcon.NewAdventurer => StatusIcons.NewAdventurer,
|
||||
BitmapFontIcon.Mentor => StatusIcons.Mentor,
|
||||
BitmapFontIcon.MentorPvE => StatusIcons.MentorPvE,
|
||||
BitmapFontIcon.MentorCrafting => StatusIcons.MentorCrafting,
|
||||
BitmapFontIcon.MentorPvP => StatusIcons.MentorPvP,
|
||||
BitmapFontIcon.Returner => StatusIcons.Returner,
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
public static BitmapFontIcon? GetBitmapFontIconFromStatusIcon(StatusIcons icon)
|
||||
{
|
||||
return icon switch
|
||||
{
|
||||
StatusIcons.NewAdventurer => BitmapFontIcon.NewAdventurer,
|
||||
StatusIcons.Mentor => BitmapFontIcon.Mentor,
|
||||
StatusIcons.MentorPvE => BitmapFontIcon.MentorPvE,
|
||||
StatusIcons.MentorCrafting => BitmapFontIcon.MentorCrafting,
|
||||
StatusIcons.MentorPvP => BitmapFontIcon.MentorPvP,
|
||||
StatusIcons.Returner => BitmapFontIcon.Returner,
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
24
Pilz.Dalamud/Tools/Strings/StringChange.cs
Normal file
24
Pilz.Dalamud/Tools/Strings/StringChange.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
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 StringChange
|
||||
{
|
||||
/// <summary>
|
||||
/// The payloads to use for inserting/replacing.
|
||||
/// </summary>
|
||||
public List<Payload> Payloads { get; init; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// Not needed to be true for the most cases.
|
||||
/// </summary>
|
||||
public bool ForceUsingSingleAnchorPayload { get; set; } = false;
|
||||
}
|
||||
}
|
||||
40
Pilz.Dalamud/Tools/Strings/StringChanges.cs
Normal file
40
Pilz.Dalamud/Tools/Strings/StringChanges.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
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
|
||||
{
|
||||
private readonly Dictionary<StringPosition, StringChange> changes = new();
|
||||
|
||||
public StringChanges()
|
||||
{
|
||||
changes.Add(StringPosition.Before, new StringChange());
|
||||
changes.Add(StringPosition.After, new StringChange());
|
||||
changes.Add(StringPosition.Replace, new StringChange());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a change of the position of your choice where you can add your payloads.
|
||||
/// </summary>
|
||||
/// <param name="position">The position of your choice.</param>
|
||||
/// <returns></returns>
|
||||
public StringChange GetChange(StringPosition position)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
Pilz.Dalamud/Tools/Strings/StringChangesProps.cs
Normal file
31
Pilz.Dalamud/Tools/Strings/StringChangesProps.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
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 StringChangesProps
|
||||
{
|
||||
/// <summary>
|
||||
/// The string where the changes should be applied.
|
||||
/// </summary>
|
||||
public SeString Destination { get; set; }
|
||||
/// <summary>
|
||||
/// The changes that should be applied to the destination.
|
||||
/// </summary>
|
||||
public StringChanges StringChanges { get; set; } = new();
|
||||
/// <summary>
|
||||
/// Payloads to use as anchor where the changes should be applied to.
|
||||
/// </summary>
|
||||
public List<Payload> AnchorPayloads { get; set; } = new();
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public Payload AnchorPayload { get; set; }
|
||||
}
|
||||
}
|
||||
15
Pilz.Dalamud/Tools/Strings/StringPosition.cs
Normal file
15
Pilz.Dalamud/Tools/Strings/StringPosition.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Dalamud.Tools.Strings
|
||||
{
|
||||
public enum StringPosition
|
||||
{
|
||||
Before,
|
||||
After,
|
||||
Replace
|
||||
}
|
||||
}
|
||||
132
Pilz.Dalamud/Tools/Strings/StringUpdateFactory.cs
Normal file
132
Pilz.Dalamud/Tools/Strings/StringUpdateFactory.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
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
|
||||
{
|
||||
public static class StringUpdateFactory
|
||||
{
|
||||
public static void ApplyStringChanges(StringChangesProps props)
|
||||
{
|
||||
if (props.StringChanges != null && props.StringChanges.Any())
|
||||
{
|
||||
var seString = props.Destination;
|
||||
List<StringPosition> stringPositionsOrdered = GetOrderedStringPositions(props);
|
||||
|
||||
foreach (var stringPosition in stringPositionsOrdered)
|
||||
{
|
||||
var stringChange = props.StringChanges.GetChange(stringPosition);
|
||||
if (stringChange != null && stringChange.Payloads.Any())
|
||||
{
|
||||
AddSpacesBetweenTextPayloads(stringChange.Payloads, stringPosition);
|
||||
|
||||
if (stringPosition == StringPosition.Before)
|
||||
{
|
||||
Payload anchorFirst = stringChange.ForceUsingSingleAnchorPayload ? props.AnchorPayload : props.AnchorPayloads?.FirstOrDefault();
|
||||
|
||||
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)
|
||||
{
|
||||
Payload anchorLast = stringChange.ForceUsingSingleAnchorPayload ? props.AnchorPayload : props.AnchorPayloads?.LastOrDefault();
|
||||
|
||||
if (anchorLast != null)
|
||||
{
|
||||
var anchorPayloadIndex = seString.Payloads.IndexOf(anchorLast);
|
||||
seString.Payloads.InsertRange(anchorPayloadIndex + 1, stringChange.Payloads);
|
||||
}
|
||||
else
|
||||
seString.Payloads.AddRange(stringChange.Payloads);
|
||||
}
|
||||
else if (stringPosition == StringPosition.Replace)
|
||||
{
|
||||
Payload anchorReplace = props.AnchorPayload;
|
||||
|
||||
if (anchorReplace != null)
|
||||
{
|
||||
var anchorPayloadIndex = seString.Payloads.IndexOf(anchorReplace);
|
||||
seString.Payloads.InsertRange(anchorPayloadIndex, stringChange.Payloads);
|
||||
seString.Remove(anchorReplace);
|
||||
}
|
||||
else
|
||||
{
|
||||
seString.Payloads.Clear();
|
||||
seString.Payloads.AddRange(stringChange.Payloads);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddSpacesBetweenTextPayloads(List<Payload> payloads, StringPosition tagPosition)
|
||||
{
|
||||
if (payloads != null && payloads.Any())
|
||||
{
|
||||
var indicesToInsertSpacesAt = new List<int>();
|
||||
var lastTextPayloadIndex = -1;
|
||||
|
||||
static TextPayload getNewTextPayload() => new(" ");
|
||||
|
||||
foreach (var payload in payloads.Reverse<Payload>())
|
||||
{
|
||||
if (payload is IconPayload iconPayload)
|
||||
lastTextPayloadIndex = -1;
|
||||
else if (payload is TextPayload textPayload)
|
||||
{
|
||||
if (lastTextPayloadIndex != -1)
|
||||
indicesToInsertSpacesAt.Add(payloads.IndexOf(textPayload) + 1);
|
||||
lastTextPayloadIndex = payloads.IndexOf(textPayload);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var indexToInsertSpaceAt in indicesToInsertSpacesAt)
|
||||
payloads.Insert(indexToInsertSpaceAt, getNewTextPayload());
|
||||
|
||||
// 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)
|
||||
payloads.Add(getNewTextPayload());
|
||||
}
|
||||
// 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)
|
||||
payloads.Insert(0, getNewTextPayload());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<StringPosition> GetOrderedStringPositions(StringChangesProps props)
|
||||
{
|
||||
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())
|
||||
tagPositionsOrdered.Add(StringPosition.Replace);
|
||||
|
||||
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())
|
||||
tagPositionsOrdered.Add(StringPosition.Replace);
|
||||
|
||||
return tagPositionsOrdered;
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Pilz.Dalamud/XivApi.cs
Normal file
39
Pilz.Dalamud/XivApi.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
6
Pilz.Dalamud/packages.lock.json
Normal file
6
Pilz.Dalamud/packages.lock.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"version": 1,
|
||||
"dependencies": {
|
||||
"net7.0-windows7.0": {}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ VisualStudioVersion = 17.3.32929.385
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlayerTags", "PlayerTags\PlayerTags.csproj", "{13C812E9-0D42-4B95-8646-40EEBF30636F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pilz.Dalamud", "Pilz.Dalamud\Pilz.Dalamud\Pilz.Dalamud.csproj", "{D0362D71-E77F-4739-80BE-CD4454188B8F}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pilz.Dalamud", "Pilz.Dalamud\Pilz.Dalamud.csproj", "{D0362D71-E77F-4739-80BE-CD4454188B8F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
18
PlayerTags/Configuration/GeneralConfiguration.cs
Normal file
18
PlayerTags/Configuration/GeneralConfiguration.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using PlayerTags.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PlayerTags.Configuration
|
||||
{
|
||||
public class GeneralConfiguration : ZoneConfigurationBase
|
||||
{
|
||||
public NameplateFreeCompanyVisibility NameplateFreeCompanyVisibility = NameplateFreeCompanyVisibility.Default;
|
||||
public NameplateTitleVisibility NameplateTitleVisibility = NameplateTitleVisibility.WhenHasTags;
|
||||
public NameplateTitlePosition NameplateTitlePosition = NameplateTitlePosition.AlwaysAboveName;
|
||||
public DeadPlayerHandling NameplateDeadPlayerHandling = DeadPlayerHandling.Include;
|
||||
public bool IsApplyTagsToAllChatMessagesEnabled = true;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ using System.Runtime.CompilerServices;
|
||||
namespace PlayerTags.Configuration
|
||||
{
|
||||
[Serializable]
|
||||
public class PluginConfiguration : IPluginConfiguration
|
||||
public partial class PluginConfiguration : IPluginConfiguration
|
||||
{
|
||||
private const int DEFAULT_CONFIG_VERSION = 1;
|
||||
|
||||
@@ -23,17 +23,9 @@ namespace PlayerTags.Configuration
|
||||
public int RootVersion { get; private set; } = DEFAULT_CONFIG_VERSION;
|
||||
public int Version { get; set; } = DEFAULT_CONFIG_VERSION;
|
||||
public bool IsVisible = false;
|
||||
public bool EnabledGlobal = true;
|
||||
|
||||
[JsonProperty("GeneralOptionsV2")]
|
||||
public Dictionary<ActivityType, GeneralOptionsClass> GeneralOptions = new()
|
||||
{
|
||||
{ ActivityType.None, new GeneralOptionsClass() },
|
||||
{ ActivityType.PveDuty, new GeneralOptionsClass() },
|
||||
{ ActivityType.PvpDuty, new GeneralOptionsClass() }
|
||||
};
|
||||
|
||||
public DefaultPluginDataTemplate DefaultPluginDataTemplate = DefaultPluginDataTemplate.None;
|
||||
public ZoneConfiguration<GeneralConfiguration> GeneralConfigs = new();
|
||||
public ZoneConfiguration<TagsConfiguration> TagsConfigs = new();
|
||||
public StatusIconPriorizerSettings StatusIconPriorizerSettings = new(true);
|
||||
public bool MoveStatusIconToNameplateTextIfPossible = true;
|
||||
public bool IsPlayerNameRandomlyGenerated = false;
|
||||
@@ -46,88 +38,74 @@ namespace PlayerTags.Configuration
|
||||
public bool IsPlayersTabAllianceVisible = true;
|
||||
public bool IsPlayersTabEnemiesVisible = true;
|
||||
public bool IsPlayersTabOthersVisible = false;
|
||||
public bool IsGeneralOptionsAllTheSameEnabled = true;
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<string, InheritableData> AllTagsChanges = new Dictionary<string, InheritableData>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<string, InheritableData> AllRoleTagsChanges = new Dictionary<string, InheritableData>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<Role, Dictionary<string, InheritableData>> RoleTagsChanges = new Dictionary<Role, Dictionary<string, InheritableData>>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<DpsRole, Dictionary<string, InheritableData>> DpsRoleTagsChanges = new Dictionary<DpsRole, Dictionary<string, InheritableData>>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<RangedDpsRole, Dictionary<string, InheritableData>> RangedDpsRoleTagsChanges = new Dictionary<RangedDpsRole, Dictionary<string, InheritableData>>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<LandHandRole, Dictionary<string, InheritableData>> LandHandRoleTagsChanges = new Dictionary<LandHandRole, Dictionary<string, InheritableData>>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<string, Dictionary<string, InheritableData>> JobTagsChanges = new Dictionary<string, Dictionary<string, InheritableData>>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<string, InheritableData> AllCustomTagsChanges = new Dictionary<string, InheritableData>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public List<Dictionary<string, InheritableData>> CustomTagsChanges = new List<Dictionary<string, InheritableData>>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public List<Identity> Identities = new List<Identity>();
|
||||
public bool IsSimpleUIEnabled = true;
|
||||
|
||||
#region Obsulate Properties
|
||||
|
||||
[Obsolete]
|
||||
[JsonProperty("GeneralOptions")]
|
||||
private Dictionary<Data.ActivityContext, GeneralOptionsClass> GeneralOptionsV1
|
||||
[JsonProperty("GeneralOptionsV2"), Obsolete]
|
||||
private Dictionary<ActivityType, GeneralConfiguration> GeneralOptionsV2
|
||||
{
|
||||
set
|
||||
{
|
||||
GeneralOptions.Clear();
|
||||
foreach (var kvp in value)
|
||||
GeneralOptions.Add((ActivityType)kvp.Key, kvp.Value);
|
||||
void copyOverSettings(ActivityType srcType, ZoneType destType)
|
||||
{
|
||||
var src = value[srcType];
|
||||
var dest = GeneralConfigs.GetConfig(destType);
|
||||
dest.IsApplyTagsToAllChatMessagesEnabled = src.IsApplyTagsToAllChatMessagesEnabled;
|
||||
dest.NameplateDeadPlayerHandling = src.NameplateDeadPlayerHandling;
|
||||
dest.NameplateFreeCompanyVisibility = src.NameplateFreeCompanyVisibility;
|
||||
dest.NameplateTitlePosition = src.NameplateTitlePosition;
|
||||
dest.NameplateTitleVisibility = src.NameplateTitleVisibility;
|
||||
}
|
||||
|
||||
copyOverSettings(ActivityType.None, ZoneType.Everywhere);
|
||||
copyOverSettings(ActivityType.None, ZoneType.Overworld);
|
||||
copyOverSettings(ActivityType.PvpDuty, ZoneType.Pvp);
|
||||
copyOverSettings(ActivityType.PveDuty, ZoneType.Doungen);
|
||||
copyOverSettings(ActivityType.PveDuty, ZoneType.Raid);
|
||||
copyOverSettings(ActivityType.PveDuty, ZoneType.AllianceRaid);
|
||||
copyOverSettings(ActivityType.PveDuty, ZoneType.Foray);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty]
|
||||
[Obsolete]
|
||||
public bool IsApplyToEverywhereEnabled
|
||||
{
|
||||
set
|
||||
{
|
||||
GeneralConfigs.IsEverywhere = value;
|
||||
TagsConfigs.IsEverywhere = value;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty]
|
||||
[Obsolete]
|
||||
private bool IsGeneralOptionsAllTheSameEnabled
|
||||
{
|
||||
set => IsApplyToEverywhereEnabled = value;
|
||||
}
|
||||
|
||||
[JsonProperty("NameplateFreeCompanyVisibility"), Obsolete]
|
||||
private NameplateFreeCompanyVisibility NameplateFreeCompanyVisibilityV1
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var key in GeneralOptions.Keys)
|
||||
GeneralOptions[key].NameplateFreeCompanyVisibility = value;
|
||||
}
|
||||
set => GeneralConfigs.GetConfig(ZoneType.Everywhere).NameplateFreeCompanyVisibility = value;
|
||||
}
|
||||
[JsonProperty("NameplateTitleVisibility"), Obsolete]
|
||||
public NameplateTitleVisibility NameplateTitleVisibilityV1
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var key in GeneralOptions.Keys)
|
||||
GeneralOptions[key].NameplateTitleVisibility = value;
|
||||
}
|
||||
set => GeneralConfigs.GetConfig(ZoneType.Everywhere).NameplateTitleVisibility = value;
|
||||
}
|
||||
[JsonProperty("NameplateTitlePosition"), Obsolete]
|
||||
public NameplateTitlePosition NameplateTitlePositionV1
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var key in GeneralOptions.Keys)
|
||||
GeneralOptions[key].NameplateTitlePosition = value;
|
||||
}
|
||||
set => GeneralConfigs.GetConfig(ZoneType.Everywhere).NameplateTitlePosition = value;
|
||||
}
|
||||
|
||||
[JsonProperty("IsApplyTagsToAllChatMessagesEnabled"), Obsolete]
|
||||
private bool IsApplyTagsToAllChatMessagesEnabledV1
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var key in GeneralOptions.Keys)
|
||||
GeneralOptions[key].IsApplyTagsToAllChatMessagesEnabled = value;
|
||||
}
|
||||
set => GeneralConfigs.GetConfig(ZoneType.Everywhere).IsApplyTagsToAllChatMessagesEnabled = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -136,105 +114,15 @@ namespace PlayerTags.Configuration
|
||||
|
||||
public void Save(PluginData pluginData)
|
||||
{
|
||||
AllTagsChanges = pluginData.AllTags.GetChanges(pluginData.Default.AllTags.GetChanges());
|
||||
AllRoleTagsChanges = pluginData.AllRoleTags.GetChanges(pluginData.Default.AllRoleTags.GetChanges());
|
||||
|
||||
RoleTagsChanges = new Dictionary<Role, Dictionary<string, InheritableData>>();
|
||||
foreach ((var role, var roleTag) in pluginData.RoleTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = new Dictionary<string, InheritableData>();
|
||||
if (pluginData.Default.RoleTags.TryGetValue(role, out var defaultTag))
|
||||
{
|
||||
defaultChanges = defaultTag.GetChanges();
|
||||
}
|
||||
|
||||
var changes = roleTag.GetChanges(defaultChanges);
|
||||
if (changes.Any())
|
||||
{
|
||||
RoleTagsChanges[role] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
DpsRoleTagsChanges = new Dictionary<DpsRole, Dictionary<string, InheritableData>>();
|
||||
foreach ((var dpsRole, var dpsRoleTag) in pluginData.DpsRoleTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = new Dictionary<string, InheritableData>();
|
||||
if (pluginData.Default.DpsRoleTags.TryGetValue(dpsRole, out var defaultTag))
|
||||
{
|
||||
defaultChanges = defaultTag.GetChanges();
|
||||
}
|
||||
|
||||
var changes = dpsRoleTag.GetChanges(defaultChanges);
|
||||
if (changes.Any())
|
||||
{
|
||||
DpsRoleTagsChanges[dpsRole] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
RangedDpsRoleTagsChanges = new Dictionary<RangedDpsRole, Dictionary<string, InheritableData>>();
|
||||
foreach ((var rangedDpsRole, var rangedDpsRoleTag) in pluginData.RangedDpsRoleTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = new Dictionary<string, InheritableData>();
|
||||
if (pluginData.Default.RangedDpsRoleTags.TryGetValue(rangedDpsRole, out var defaultTag))
|
||||
{
|
||||
defaultChanges = defaultTag.GetChanges();
|
||||
}
|
||||
|
||||
var changes = rangedDpsRoleTag.GetChanges(defaultChanges);
|
||||
if (changes.Any())
|
||||
{
|
||||
RangedDpsRoleTagsChanges[rangedDpsRole] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
LandHandRoleTagsChanges = new Dictionary<LandHandRole, Dictionary<string, InheritableData>>();
|
||||
foreach ((var landHandRole, var landHandRoleTag) in pluginData.LandHandRoleTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = new Dictionary<string, InheritableData>();
|
||||
if (pluginData.Default.LandHandRoleTags.TryGetValue(landHandRole, out var defaultTag))
|
||||
{
|
||||
defaultChanges = defaultTag.GetChanges();
|
||||
}
|
||||
|
||||
var changes = landHandRoleTag.GetChanges(defaultChanges);
|
||||
if (changes.Any())
|
||||
{
|
||||
LandHandRoleTagsChanges[landHandRole] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
JobTagsChanges = new Dictionary<string, Dictionary<string, InheritableData>>();
|
||||
foreach ((var jobAbbreviation, var jobTag) in pluginData.JobTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = new Dictionary<string, InheritableData>();
|
||||
if (pluginData.Default.JobTags.TryGetValue(jobAbbreviation, out var defaultTag))
|
||||
{
|
||||
defaultChanges = defaultTag.GetChanges();
|
||||
}
|
||||
|
||||
var changes = jobTag.GetChanges(defaultChanges);
|
||||
if (changes.Any())
|
||||
{
|
||||
JobTagsChanges[jobAbbreviation] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
AllCustomTagsChanges = pluginData.AllCustomTags.GetChanges(pluginData.Default.AllCustomTags.GetChanges());
|
||||
|
||||
CustomTagsChanges = new List<Dictionary<string, InheritableData>>();
|
||||
foreach (var customTag in pluginData.CustomTags)
|
||||
{
|
||||
CustomTagsChanges.Add(customTag.GetChanges());
|
||||
}
|
||||
|
||||
Identities = pluginData.Identities;
|
||||
foreach (var tagConfig in TagsConfigs)
|
||||
tagConfig.Value.ApplyTagsData(pluginData.GetTagsData(tagConfig.Key));
|
||||
|
||||
SavePluginConfig();
|
||||
|
||||
Saved?.Invoke();
|
||||
}
|
||||
|
||||
private void SavePluginConfig()
|
||||
public void SavePluginConfig()
|
||||
{
|
||||
Version = DEFAULT_CONFIG_VERSION;
|
||||
var configFilePath = GetConfigFilePath();
|
||||
@@ -242,13 +130,6 @@ namespace PlayerTags.Configuration
|
||||
File.WriteAllText(configFilePath, configFileContent);
|
||||
}
|
||||
|
||||
private static void BackupPluginConfig()
|
||||
{
|
||||
var configFilePath = GetConfigFilePath();
|
||||
var configFilePathOld = Path.ChangeExtension(configFilePath, ".old" + Path.GetExtension(configFilePath));
|
||||
File.Copy(configFilePath, configFilePathOld, true);
|
||||
}
|
||||
|
||||
public static PluginConfiguration LoadPluginConfig()
|
||||
{
|
||||
var configFilePath = GetConfigFilePath();
|
||||
@@ -266,15 +147,6 @@ namespace PlayerTags.Configuration
|
||||
config = PluginServices.DalamudPluginInterface.GetPluginConfig();
|
||||
}
|
||||
|
||||
if (config is PluginConfiguration pluginConfig)
|
||||
{
|
||||
if (PluginConfigFix(pluginConfig))
|
||||
{
|
||||
BackupPluginConfig();
|
||||
pluginConfig.SavePluginConfig();
|
||||
}
|
||||
}
|
||||
|
||||
return config as PluginConfiguration;
|
||||
}
|
||||
|
||||
@@ -295,58 +167,5 @@ namespace PlayerTags.Configuration
|
||||
|
||||
return jsonSettings;
|
||||
}
|
||||
|
||||
private static bool PluginConfigFix(PluginConfiguration config)
|
||||
{
|
||||
bool hasFixes = false;
|
||||
|
||||
// Patch 6.4 - Disable all Job & Role specific colors & prefix
|
||||
// Not used yet, but keeping it there, just for the case,
|
||||
//if (config.Version <= 1)
|
||||
//{
|
||||
// void fixTags(Dictionary<string, InheritableData> dic)
|
||||
// {
|
||||
// foreach (var change in config.AllRoleTagsChanges.ToArray())
|
||||
// {
|
||||
// var key = change.Key;
|
||||
// if (key == nameof(Tag.IsTextVisibleInChat) ||
|
||||
// key == nameof(Tag.IsTextVisibleInNameplates) ||
|
||||
// key == nameof(Tag.IsRoleIconVisibleInChat) ||
|
||||
// key == nameof(Tag.IsRoleIconVisibleInNameplates) ||
|
||||
// key == nameof(Tag.IsTextColorAppliedToNameplateName) ||
|
||||
// key == nameof(Tag.IsTextColorAppliedToChatName) ||
|
||||
// key == nameof(Tag.IsJobIconVisibleInNameplates))
|
||||
// {
|
||||
// var data = change.Value;
|
||||
// data.Behavior = InheritableBehavior.Disabled;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // "All Roles" tag changes
|
||||
// fixTags(config.AllRoleTagsChanges);
|
||||
|
||||
// // Role tags changes
|
||||
// foreach (var kvp in config.RoleTagsChanges)
|
||||
// fixTags(kvp.Value);
|
||||
|
||||
// // Job tags changes
|
||||
// foreach (var kvp in config.JobTagsChanges)
|
||||
// fixTags(kvp.Value);
|
||||
|
||||
// hasFixes = true;
|
||||
//}
|
||||
|
||||
return hasFixes;
|
||||
}
|
||||
}
|
||||
|
||||
public class GeneralOptionsClass
|
||||
{
|
||||
public NameplateFreeCompanyVisibility NameplateFreeCompanyVisibility = NameplateFreeCompanyVisibility.Default;
|
||||
public NameplateTitleVisibility NameplateTitleVisibility = NameplateTitleVisibility.WhenHasTags;
|
||||
public NameplateTitlePosition NameplateTitlePosition = NameplateTitlePosition.AlwaysAboveName;
|
||||
public DeadPlayerHandling NameplateDeadPlayerHandling = DeadPlayerHandling.Include;
|
||||
public bool IsApplyTagsToAllChatMessagesEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
142
PlayerTags/Configuration/TagsConfiguration.cs
Normal file
142
PlayerTags/Configuration/TagsConfiguration.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using Newtonsoft.Json;
|
||||
using PlayerTags.Data;
|
||||
using PlayerTags.Inheritables;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PlayerTags.Configuration
|
||||
{
|
||||
public class TagsConfiguration : ZoneConfigurationBase
|
||||
{
|
||||
public DefaultPluginDataTemplate DefaultPluginDataTemplate = DefaultPluginDataTemplate.Simple;
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<string, InheritableData> AllTagsChanges = new Dictionary<string, InheritableData>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<string, InheritableData> AllRoleTagsChanges = new Dictionary<string, InheritableData>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<Role, Dictionary<string, InheritableData>> RoleTagsChanges = new Dictionary<Role, Dictionary<string, InheritableData>>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<DpsRole, Dictionary<string, InheritableData>> DpsRoleTagsChanges = new Dictionary<DpsRole, Dictionary<string, InheritableData>>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<RangedDpsRole, Dictionary<string, InheritableData>> RangedDpsRoleTagsChanges = new Dictionary<RangedDpsRole, Dictionary<string, InheritableData>>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<LandHandRole, Dictionary<string, InheritableData>> LandHandRoleTagsChanges = new Dictionary<LandHandRole, Dictionary<string, InheritableData>>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<string, Dictionary<string, InheritableData>> JobTagsChanges = new Dictionary<string, Dictionary<string, InheritableData>>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<string, InheritableData> AllCustomTagsChanges = new Dictionary<string, InheritableData>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public List<Dictionary<string, InheritableData>> CustomTagsChanges = new List<Dictionary<string, InheritableData>>();
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public List<Identity> Identities = new List<Identity>();
|
||||
|
||||
public void ApplyTagsData(PluginTagsData tagsData)
|
||||
{
|
||||
AllTagsChanges = tagsData.AllTags.GetChanges(tagsData.Default.AllTags.GetChanges());
|
||||
AllRoleTagsChanges = tagsData.AllRoleTags.GetChanges(tagsData.Default.AllRoleTags.GetChanges());
|
||||
|
||||
RoleTagsChanges = new Dictionary<Role, Dictionary<string, InheritableData>>();
|
||||
foreach ((var role, var roleTag) in tagsData.RoleTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = new Dictionary<string, InheritableData>();
|
||||
if (tagsData.Default.RoleTags.TryGetValue(role, out var defaultTag))
|
||||
{
|
||||
defaultChanges = defaultTag.GetChanges();
|
||||
}
|
||||
|
||||
var changes = roleTag.GetChanges(defaultChanges);
|
||||
if (changes.Any())
|
||||
{
|
||||
RoleTagsChanges[role] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
DpsRoleTagsChanges = new Dictionary<DpsRole, Dictionary<string, InheritableData>>();
|
||||
foreach ((var dpsRole, var dpsRoleTag) in tagsData.DpsRoleTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = new Dictionary<string, InheritableData>();
|
||||
if (tagsData.Default.DpsRoleTags.TryGetValue(dpsRole, out var defaultTag))
|
||||
{
|
||||
defaultChanges = defaultTag.GetChanges();
|
||||
}
|
||||
|
||||
var changes = dpsRoleTag.GetChanges(defaultChanges);
|
||||
if (changes.Any())
|
||||
{
|
||||
DpsRoleTagsChanges[dpsRole] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
RangedDpsRoleTagsChanges = new Dictionary<RangedDpsRole, Dictionary<string, InheritableData>>();
|
||||
foreach ((var rangedDpsRole, var rangedDpsRoleTag) in tagsData.RangedDpsRoleTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = new Dictionary<string, InheritableData>();
|
||||
if (tagsData.Default.RangedDpsRoleTags.TryGetValue(rangedDpsRole, out var defaultTag))
|
||||
{
|
||||
defaultChanges = defaultTag.GetChanges();
|
||||
}
|
||||
|
||||
var changes = rangedDpsRoleTag.GetChanges(defaultChanges);
|
||||
if (changes.Any())
|
||||
{
|
||||
RangedDpsRoleTagsChanges[rangedDpsRole] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
LandHandRoleTagsChanges = new Dictionary<LandHandRole, Dictionary<string, InheritableData>>();
|
||||
foreach ((var landHandRole, var landHandRoleTag) in tagsData.LandHandRoleTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = new Dictionary<string, InheritableData>();
|
||||
if (tagsData.Default.LandHandRoleTags.TryGetValue(landHandRole, out var defaultTag))
|
||||
{
|
||||
defaultChanges = defaultTag.GetChanges();
|
||||
}
|
||||
|
||||
var changes = landHandRoleTag.GetChanges(defaultChanges);
|
||||
if (changes.Any())
|
||||
{
|
||||
LandHandRoleTagsChanges[landHandRole] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
JobTagsChanges = new Dictionary<string, Dictionary<string, InheritableData>>();
|
||||
foreach ((var jobAbbreviation, var jobTag) in tagsData.JobTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = new Dictionary<string, InheritableData>();
|
||||
if (tagsData.Default.JobTags.TryGetValue(jobAbbreviation, out var defaultTag))
|
||||
{
|
||||
defaultChanges = defaultTag.GetChanges();
|
||||
}
|
||||
|
||||
var changes = jobTag.GetChanges(defaultChanges);
|
||||
if (changes.Any())
|
||||
{
|
||||
JobTagsChanges[jobAbbreviation] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
AllCustomTagsChanges = tagsData.AllCustomTags.GetChanges(tagsData.Default.AllCustomTags.GetChanges());
|
||||
|
||||
CustomTagsChanges = new List<Dictionary<string, InheritableData>>();
|
||||
foreach (var customTag in tagsData.CustomTags)
|
||||
{
|
||||
CustomTagsChanges.Add(customTag.GetChanges());
|
||||
}
|
||||
|
||||
Identities = tagsData.Identities;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
PlayerTags/Configuration/ZoneConfiguration.cs
Normal file
28
PlayerTags/Configuration/ZoneConfiguration.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Newtonsoft.Json;
|
||||
using Pilz.Dalamud.ActivityContexts;
|
||||
using PlayerTags.Data;
|
||||
using PlayerTags.Inheritables;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PlayerTags.Configuration
|
||||
{
|
||||
public class ZoneConfiguration<TConfig> : Dictionary<ZoneType, TConfig> where TConfig : ZoneConfigurationBase, new()
|
||||
{
|
||||
public bool IsEverywhere { get; set; } = true;
|
||||
|
||||
public TConfig GetConfig(ZoneType zoneType)
|
||||
{
|
||||
if (IsEverywhere)
|
||||
zoneType = ZoneType.Everywhere;
|
||||
|
||||
if (!ContainsKey(zoneType))
|
||||
Add(zoneType, new TConfig());
|
||||
|
||||
return this[zoneType];
|
||||
}
|
||||
}
|
||||
}
|
||||
13
PlayerTags/Configuration/ZoneConfigurationBase.cs
Normal file
13
PlayerTags/Configuration/ZoneConfigurationBase.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PlayerTags.Configuration
|
||||
{
|
||||
public abstract class ZoneConfigurationBase
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
{
|
||||
[Obsolete]
|
||||
[Flags]
|
||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||
public enum ActivityContext
|
||||
{
|
||||
None = 0x0,
|
||||
PveDuty = 0x1,
|
||||
PvpDuty = 0x2,
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,7 @@ namespace PlayerTags.Data
|
||||
|
||||
private void Clear()
|
||||
{
|
||||
|
||||
RoleTags = new Dictionary<Role, Tag>();
|
||||
DpsRoleTags = new Dictionary<DpsRole, Tag>();
|
||||
RangedDpsRoleTags = new Dictionary<RangedDpsRole, Tag>();
|
||||
|
||||
@@ -3,6 +3,7 @@ using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.ClientState.Party;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Dalamud.Logging;
|
||||
using Pilz.Dalamud.ActivityContexts;
|
||||
using PlayerTags.Configuration;
|
||||
using PlayerTags.PluginStrings;
|
||||
using System;
|
||||
@@ -13,19 +14,8 @@ namespace PlayerTags.Data
|
||||
{
|
||||
public class PluginData
|
||||
{
|
||||
public DefaultPluginData Default;
|
||||
public Tag AllTags;
|
||||
public Tag AllRoleTags;
|
||||
public Dictionary<Role, Tag> RoleTags;
|
||||
public Dictionary<DpsRole, Tag> DpsRoleTags;
|
||||
public Dictionary<RangedDpsRole, Tag> RangedDpsRoleTags;
|
||||
public Dictionary<LandHandRole, Tag> LandHandRoleTags;
|
||||
public Dictionary<string, Tag> JobTags;
|
||||
public Tag AllCustomTags;
|
||||
public List<Tag> CustomTags;
|
||||
public List<Identity> Identities;
|
||||
|
||||
private PluginConfiguration pluginConfiguration;
|
||||
public Dictionary<ZoneType, PluginTagsData> TagsData = new();
|
||||
private readonly PluginConfiguration pluginConfiguration;
|
||||
|
||||
public PluginData(PluginConfiguration pluginConfiguration)
|
||||
{
|
||||
@@ -33,275 +23,38 @@ namespace PlayerTags.Data
|
||||
ReloadDefault();
|
||||
}
|
||||
|
||||
private void EnsureDataExists(ref ZoneType zoneType)
|
||||
{
|
||||
if (pluginConfiguration.TagsConfigs.IsEverywhere)
|
||||
zoneType = ZoneType.Everywhere;
|
||||
|
||||
if (!TagsData.ContainsKey(zoneType))
|
||||
TagsData.Add(zoneType, new PluginTagsData(pluginConfiguration, pluginConfiguration.TagsConfigs.GetConfig(zoneType)));
|
||||
}
|
||||
|
||||
public PluginTagsData GetTagsData(ZoneType zoneType)
|
||||
{
|
||||
EnsureDataExists(ref zoneType);
|
||||
return TagsData[zoneType];
|
||||
}
|
||||
|
||||
public void ReloadDefault(ZoneType zoneType)
|
||||
{
|
||||
EnsureDataExists(ref zoneType);
|
||||
|
||||
if (TagsData[zoneType].ReloadDefault())
|
||||
pluginConfiguration.Save(this);
|
||||
}
|
||||
|
||||
public void ReloadDefault()
|
||||
{
|
||||
Default = new DefaultPluginData(pluginConfiguration.DefaultPluginDataTemplate);
|
||||
var needToSave = false;
|
||||
|
||||
foreach (var tagsData in TagsData.Values)
|
||||
needToSave |= tagsData.ReloadDefault();
|
||||
|
||||
// Set the default changes and saved changes
|
||||
AllTags = new Tag(new LocalizedPluginString(nameof(AllTags)), Default.AllTags);
|
||||
AllTags.SetChanges(pluginConfiguration.AllTagsChanges);
|
||||
|
||||
AllRoleTags = new Tag(new LocalizedPluginString(nameof(AllRoleTags)), Default.AllRoleTags);
|
||||
AllRoleTags.SetChanges(pluginConfiguration.AllRoleTagsChanges);
|
||||
|
||||
RoleTags = new Dictionary<Role, Tag>();
|
||||
foreach (var role in Enum.GetValues<Role>())
|
||||
{
|
||||
if (Default.RoleTags.TryGetValue(role, out var defaultTag))
|
||||
{
|
||||
RoleTags[role] = new Tag(new LocalizedPluginString(Localizer.GetName(role)), defaultTag);
|
||||
if (pluginConfiguration.RoleTagsChanges.TryGetValue(role, out var savedChanges))
|
||||
{
|
||||
RoleTags[role].SetChanges(savedChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DpsRoleTags = new Dictionary<DpsRole, Tag>();
|
||||
foreach (var dpsRole in Enum.GetValues<DpsRole>())
|
||||
{
|
||||
if (Default.DpsRoleTags.TryGetValue(dpsRole, out var defaultTag))
|
||||
{
|
||||
DpsRoleTags[dpsRole] = new Tag(new LocalizedPluginString(Localizer.GetName(dpsRole)), defaultTag);
|
||||
if (pluginConfiguration.DpsRoleTagsChanges.TryGetValue(dpsRole, out var savedChanges))
|
||||
{
|
||||
DpsRoleTags[dpsRole].SetChanges(savedChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RangedDpsRoleTags = new Dictionary<RangedDpsRole, Tag>();
|
||||
foreach (var rangedDpsRole in Enum.GetValues<RangedDpsRole>())
|
||||
{
|
||||
if (Default.RangedDpsRoleTags.TryGetValue(rangedDpsRole, out var defaultTag))
|
||||
{
|
||||
RangedDpsRoleTags[rangedDpsRole] = new Tag(new LocalizedPluginString(Localizer.GetName(rangedDpsRole)), defaultTag);
|
||||
if (pluginConfiguration.RangedDpsRoleTagsChanges.TryGetValue(rangedDpsRole, out var savedChanges))
|
||||
{
|
||||
RangedDpsRoleTags[rangedDpsRole].SetChanges(savedChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LandHandRoleTags = new Dictionary<LandHandRole, Tag>();
|
||||
foreach (var landHandRole in Enum.GetValues<LandHandRole>())
|
||||
{
|
||||
if (Default.LandHandRoleTags.TryGetValue(landHandRole, out var defaultChanges))
|
||||
{
|
||||
LandHandRoleTags[landHandRole] = new Tag(new LocalizedPluginString(Localizer.GetName(landHandRole)), defaultChanges);
|
||||
if (pluginConfiguration.LandHandRoleTagsChanges.TryGetValue(landHandRole, out var savedChanges))
|
||||
{
|
||||
LandHandRoleTags[landHandRole].SetChanges(savedChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JobTags = new Dictionary<string, Tag>();
|
||||
foreach ((var jobAbbreviation, var role) in RoleHelper.RolesByJobAbbreviation)
|
||||
{
|
||||
if (Default.JobTags.TryGetValue(jobAbbreviation, out var defaultChanges))
|
||||
{
|
||||
JobTags[jobAbbreviation] = new Tag(new LiteralPluginString(jobAbbreviation), defaultChanges);
|
||||
if (pluginConfiguration.JobTagsChanges.TryGetValue(jobAbbreviation, out var savedChanges))
|
||||
{
|
||||
JobTags[jobAbbreviation].SetChanges(savedChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AllCustomTags = new Tag(new LocalizedPluginString(nameof(AllCustomTags)), Default.AllCustomTags);
|
||||
AllCustomTags.SetChanges(pluginConfiguration.AllCustomTagsChanges);
|
||||
|
||||
CustomTags = new List<Tag>();
|
||||
foreach (var savedChanges in pluginConfiguration.CustomTagsChanges)
|
||||
{
|
||||
var tag = new Tag(new LocalizedPluginString(nameof(CustomTags)));
|
||||
tag.SetChanges(savedChanges);
|
||||
CustomTags.Add(tag);
|
||||
}
|
||||
|
||||
// Set up the inheritance heirarchy
|
||||
AllRoleTags.Parent = AllTags;
|
||||
foreach ((var role, var roleTag) in RoleTags)
|
||||
{
|
||||
roleTag.Parent = AllRoleTags;
|
||||
|
||||
if (role == Role.Dps)
|
||||
{
|
||||
foreach ((var dpsRole, var dpsRoleTag) in DpsRoleTags)
|
||||
{
|
||||
dpsRoleTag.Parent = roleTag;
|
||||
|
||||
if (dpsRole == DpsRole.Ranged)
|
||||
{
|
||||
foreach ((var rangedDpsRole, var rangedDpsRoleTag) in RangedDpsRoleTags)
|
||||
{
|
||||
rangedDpsRoleTag.Parent = dpsRoleTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (role == Role.LandHand)
|
||||
{
|
||||
foreach ((var landHandRole, var landHandRoleTag) in LandHandRoleTags)
|
||||
{
|
||||
landHandRoleTag.Parent = roleTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ((var jobAbbreviation, var jobTag) in JobTags)
|
||||
{
|
||||
if (RoleHelper.RolesByJobAbbreviation.TryGetValue(jobAbbreviation, out var role))
|
||||
{
|
||||
if (RoleHelper.DpsRolesByJobAbbreviation.TryGetValue(jobAbbreviation, out var dpsRole))
|
||||
{
|
||||
if (RoleHelper.RangedDpsRolesByJobAbbreviation.TryGetValue(jobAbbreviation, out var rangedDpsRole))
|
||||
{
|
||||
jobTag.Parent = RangedDpsRoleTags[rangedDpsRole];
|
||||
}
|
||||
else
|
||||
{
|
||||
jobTag.Parent = DpsRoleTags[dpsRole];
|
||||
}
|
||||
}
|
||||
else if (RoleHelper.LandHandRolesByJobAbbreviation.TryGetValue(jobAbbreviation, out var landHandRole))
|
||||
{
|
||||
jobTag.Parent = LandHandRoleTags[landHandRole];
|
||||
}
|
||||
else
|
||||
{
|
||||
jobTag.Parent = RoleTags[RoleHelper.RolesByJobAbbreviation[jobAbbreviation]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AllCustomTags.Parent = AllTags;
|
||||
foreach (var tag in CustomTags)
|
||||
{
|
||||
tag.Parent = AllCustomTags;
|
||||
}
|
||||
|
||||
Identities = pluginConfiguration.Identities;
|
||||
|
||||
// Migrate old custom tag identity assignments
|
||||
bool customTagsMigrated = false;
|
||||
foreach (var customTag in CustomTags)
|
||||
{
|
||||
if (customTag.CustomId.Value == Guid.Empty)
|
||||
{
|
||||
customTag.CustomId.Behavior = Inheritables.InheritableBehavior.Enabled;
|
||||
customTag.CustomId.Value = Guid.NewGuid();
|
||||
customTagsMigrated = true;
|
||||
}
|
||||
|
||||
foreach (string identityToAddTo in customTag.IdentitiesToAddTo)
|
||||
{
|
||||
Identity? identity = Identities.FirstOrDefault(identity => identity.Name.ToLower() == identityToAddTo.ToLower());
|
||||
if (identity == null)
|
||||
{
|
||||
identity = new Identity(identityToAddTo);
|
||||
Identities.Add(identity);
|
||||
}
|
||||
|
||||
if (identity != null)
|
||||
{
|
||||
identity.CustomTagIds.Add(customTag.CustomId.Value);
|
||||
customTagsMigrated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (customTag.GameObjectNamesToApplyTo.Behavior != Inheritables.InheritableBehavior.Inherit)
|
||||
{
|
||||
customTag.GameObjectNamesToApplyTo.Behavior = Inheritables.InheritableBehavior.Inherit;
|
||||
customTag.GameObjectNamesToApplyTo.Value = "";
|
||||
customTagsMigrated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (customTagsMigrated)
|
||||
{
|
||||
if (needToSave)
|
||||
pluginConfiguration.Save(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddCustomTagToIdentity(Tag customTag, Identity identity)
|
||||
{
|
||||
if (!identity.CustomTagIds.Contains(customTag.CustomId.Value))
|
||||
{
|
||||
identity.CustomTagIds.Add(customTag.CustomId.Value);
|
||||
}
|
||||
|
||||
if (!Identities.Contains(identity))
|
||||
{
|
||||
Identities.Add(identity);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveCustomTagFromIdentity(Tag customTag, Identity identity)
|
||||
{
|
||||
identity.CustomTagIds.Remove(customTag.CustomId.Value);
|
||||
|
||||
if (!identity.CustomTagIds.Any())
|
||||
{
|
||||
Identities.Remove(identity);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveCustomTagFromIdentities(Tag customTag)
|
||||
{
|
||||
foreach (var identity in Identities.ToArray())
|
||||
{
|
||||
RemoveCustomTagFromIdentity(customTag, identity);
|
||||
}
|
||||
}
|
||||
|
||||
public Identity GetIdentity(string name, uint? worldId)
|
||||
{
|
||||
foreach (var identity in Identities)
|
||||
{
|
||||
if (identity.Name.ToLower().Trim() == name.ToLower().Trim())
|
||||
{
|
||||
if (identity.WorldId == null && worldId != null)
|
||||
{
|
||||
identity.WorldId = worldId;
|
||||
pluginConfiguration.Save(this);
|
||||
}
|
||||
|
||||
return identity;
|
||||
}
|
||||
}
|
||||
|
||||
return new Identity(name)
|
||||
{
|
||||
WorldId = worldId
|
||||
};
|
||||
}
|
||||
|
||||
public Identity? GetIdentity(GameObjectContextMenuOpenArgs contextMenuOpenedArgs)
|
||||
{
|
||||
if (string.IsNullOrEmpty(contextMenuOpenedArgs.Text?.TextValue)
|
||||
|| contextMenuOpenedArgs.ObjectWorld == 0
|
||||
|| contextMenuOpenedArgs.ObjectWorld == 65535)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return GetIdentity(contextMenuOpenedArgs.Text?.TextValue ?? string.Empty, contextMenuOpenedArgs.ObjectWorld);
|
||||
}
|
||||
|
||||
public Identity GetIdentity(PlayerCharacter playerCharacter)
|
||||
{
|
||||
return GetIdentity(playerCharacter.Name.TextValue, playerCharacter.HomeWorld.Id);
|
||||
}
|
||||
|
||||
public Identity GetIdentity(PartyMember partyMember)
|
||||
{
|
||||
return GetIdentity(partyMember.Name.TextValue, partyMember.World.Id);
|
||||
}
|
||||
|
||||
public Identity GetIdentity(PlayerPayload playerPayload)
|
||||
{
|
||||
return GetIdentity(playerPayload.PlayerName, playerPayload.World.RowId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
308
PlayerTags/Data/PluginTagsData.cs
Normal file
308
PlayerTags/Data/PluginTagsData.cs
Normal file
@@ -0,0 +1,308 @@
|
||||
using Dalamud.ContextMenu;
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.ClientState.Party;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using PlayerTags.Configuration;
|
||||
using PlayerTags.PluginStrings;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
{
|
||||
public class PluginTagsData
|
||||
{
|
||||
public DefaultPluginData Default;
|
||||
public Tag AllTags;
|
||||
public Tag AllRoleTags;
|
||||
public Dictionary<Role, Tag> RoleTags;
|
||||
public Dictionary<DpsRole, Tag> DpsRoleTags;
|
||||
public Dictionary<RangedDpsRole, Tag> RangedDpsRoleTags;
|
||||
public Dictionary<LandHandRole, Tag> LandHandRoleTags;
|
||||
public Dictionary<string, Tag> JobTags;
|
||||
public Tag AllCustomTags;
|
||||
public List<Tag> CustomTags;
|
||||
public List<Identity> Identities;
|
||||
private readonly TagsConfiguration pluginZonedConfig;
|
||||
|
||||
public PluginTagsData(PluginConfiguration pluginconfiguration, TagsConfiguration pluginZonedConfiguration)
|
||||
{
|
||||
pluginZonedConfig = pluginZonedConfiguration;
|
||||
ReloadDefault();
|
||||
}
|
||||
|
||||
public bool ReloadDefault()
|
||||
{
|
||||
var needToSave = false;
|
||||
Default = new DefaultPluginData(pluginZonedConfig.DefaultPluginDataTemplate);
|
||||
|
||||
// Set the default changes and saved changes
|
||||
AllTags = new Tag(new LocalizedPluginString(nameof(AllTags)), Default.AllTags);
|
||||
AllTags.SetChanges(pluginZonedConfig.AllTagsChanges);
|
||||
|
||||
AllRoleTags = new Tag(new LocalizedPluginString(nameof(AllRoleTags)), Default.AllRoleTags);
|
||||
AllRoleTags.SetChanges(pluginZonedConfig.AllRoleTagsChanges);
|
||||
|
||||
RoleTags = new Dictionary<Role, Tag>();
|
||||
foreach (var role in Enum.GetValues<Role>())
|
||||
{
|
||||
if (Default.RoleTags.TryGetValue(role, out var defaultTag))
|
||||
{
|
||||
RoleTags[role] = new Tag(new LocalizedPluginString(Localizer.GetName(role)), defaultTag);
|
||||
if (pluginZonedConfig.RoleTagsChanges.TryGetValue(role, out var savedChanges))
|
||||
{
|
||||
RoleTags[role].SetChanges(savedChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DpsRoleTags = new Dictionary<DpsRole, Tag>();
|
||||
foreach (var dpsRole in Enum.GetValues<DpsRole>())
|
||||
{
|
||||
if (Default.DpsRoleTags.TryGetValue(dpsRole, out var defaultTag))
|
||||
{
|
||||
DpsRoleTags[dpsRole] = new Tag(new LocalizedPluginString(Localizer.GetName(dpsRole)), defaultTag);
|
||||
if (pluginZonedConfig.DpsRoleTagsChanges.TryGetValue(dpsRole, out var savedChanges))
|
||||
{
|
||||
DpsRoleTags[dpsRole].SetChanges(savedChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RangedDpsRoleTags = new Dictionary<RangedDpsRole, Tag>();
|
||||
foreach (var rangedDpsRole in Enum.GetValues<RangedDpsRole>())
|
||||
{
|
||||
if (Default.RangedDpsRoleTags.TryGetValue(rangedDpsRole, out var defaultTag))
|
||||
{
|
||||
RangedDpsRoleTags[rangedDpsRole] = new Tag(new LocalizedPluginString(Localizer.GetName(rangedDpsRole)), defaultTag);
|
||||
if (pluginZonedConfig.RangedDpsRoleTagsChanges.TryGetValue(rangedDpsRole, out var savedChanges))
|
||||
{
|
||||
RangedDpsRoleTags[rangedDpsRole].SetChanges(savedChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LandHandRoleTags = new Dictionary<LandHandRole, Tag>();
|
||||
foreach (var landHandRole in Enum.GetValues<LandHandRole>())
|
||||
{
|
||||
if (Default.LandHandRoleTags.TryGetValue(landHandRole, out var defaultChanges))
|
||||
{
|
||||
LandHandRoleTags[landHandRole] = new Tag(new LocalizedPluginString(Localizer.GetName(landHandRole)), defaultChanges);
|
||||
if (pluginZonedConfig.LandHandRoleTagsChanges.TryGetValue(landHandRole, out var savedChanges))
|
||||
{
|
||||
LandHandRoleTags[landHandRole].SetChanges(savedChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JobTags = new Dictionary<string, Tag>();
|
||||
foreach ((var jobAbbreviation, var role) in RoleHelper.RolesByJobAbbreviation)
|
||||
{
|
||||
if (Default.JobTags.TryGetValue(jobAbbreviation, out var defaultChanges))
|
||||
{
|
||||
JobTags[jobAbbreviation] = new Tag(new LiteralPluginString(jobAbbreviation), defaultChanges);
|
||||
if (pluginZonedConfig.JobTagsChanges.TryGetValue(jobAbbreviation, out var savedChanges))
|
||||
{
|
||||
JobTags[jobAbbreviation].SetChanges(savedChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AllCustomTags = new Tag(new LocalizedPluginString(nameof(AllCustomTags)), Default.AllCustomTags);
|
||||
AllCustomTags.SetChanges(pluginZonedConfig.AllCustomTagsChanges);
|
||||
|
||||
CustomTags = new List<Tag>();
|
||||
foreach (var savedChanges in pluginZonedConfig.CustomTagsChanges)
|
||||
{
|
||||
var tag = new Tag(new LocalizedPluginString(nameof(CustomTags)));
|
||||
tag.SetChanges(savedChanges);
|
||||
CustomTags.Add(tag);
|
||||
}
|
||||
|
||||
// Set up the inheritance heirarchy
|
||||
AllRoleTags.Parent = AllTags;
|
||||
foreach ((var role, var roleTag) in RoleTags)
|
||||
{
|
||||
roleTag.Parent = AllRoleTags;
|
||||
|
||||
if (role == Role.Dps)
|
||||
{
|
||||
foreach ((var dpsRole, var dpsRoleTag) in DpsRoleTags)
|
||||
{
|
||||
dpsRoleTag.Parent = roleTag;
|
||||
|
||||
if (dpsRole == DpsRole.Ranged)
|
||||
{
|
||||
foreach ((var rangedDpsRole, var rangedDpsRoleTag) in RangedDpsRoleTags)
|
||||
{
|
||||
rangedDpsRoleTag.Parent = dpsRoleTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (role == Role.LandHand)
|
||||
{
|
||||
foreach ((var landHandRole, var landHandRoleTag) in LandHandRoleTags)
|
||||
{
|
||||
landHandRoleTag.Parent = roleTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ((var jobAbbreviation, var jobTag) in JobTags)
|
||||
{
|
||||
if (RoleHelper.RolesByJobAbbreviation.TryGetValue(jobAbbreviation, out var role))
|
||||
{
|
||||
if (RoleHelper.DpsRolesByJobAbbreviation.TryGetValue(jobAbbreviation, out var dpsRole))
|
||||
{
|
||||
if (RoleHelper.RangedDpsRolesByJobAbbreviation.TryGetValue(jobAbbreviation, out var rangedDpsRole))
|
||||
{
|
||||
jobTag.Parent = RangedDpsRoleTags[rangedDpsRole];
|
||||
}
|
||||
else
|
||||
{
|
||||
jobTag.Parent = DpsRoleTags[dpsRole];
|
||||
}
|
||||
}
|
||||
else if (RoleHelper.LandHandRolesByJobAbbreviation.TryGetValue(jobAbbreviation, out var landHandRole))
|
||||
{
|
||||
jobTag.Parent = LandHandRoleTags[landHandRole];
|
||||
}
|
||||
else
|
||||
{
|
||||
jobTag.Parent = RoleTags[RoleHelper.RolesByJobAbbreviation[jobAbbreviation]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AllCustomTags.Parent = AllTags;
|
||||
foreach (var tag in CustomTags)
|
||||
{
|
||||
tag.Parent = AllCustomTags;
|
||||
}
|
||||
|
||||
Identities = pluginZonedConfig.Identities;
|
||||
|
||||
// Migrate old custom tag identity assignments
|
||||
bool customTagsMigrated = false;
|
||||
foreach (var customTag in CustomTags)
|
||||
{
|
||||
if (customTag.CustomId.Value == Guid.Empty)
|
||||
{
|
||||
customTag.CustomId.Behavior = Inheritables.InheritableBehavior.Enabled;
|
||||
customTag.CustomId.Value = Guid.NewGuid();
|
||||
customTagsMigrated = true;
|
||||
}
|
||||
|
||||
foreach (string identityToAddTo in customTag.IdentitiesToAddTo)
|
||||
{
|
||||
Identity? identity = Identities.FirstOrDefault(identity => identity.Name.ToLower() == identityToAddTo.ToLower());
|
||||
if (identity == null)
|
||||
{
|
||||
identity = new Identity(identityToAddTo);
|
||||
Identities.Add(identity);
|
||||
}
|
||||
|
||||
if (identity != null)
|
||||
{
|
||||
identity.CustomTagIds.Add(customTag.CustomId.Value);
|
||||
customTagsMigrated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (customTag.GameObjectNamesToApplyTo.Behavior != Inheritables.InheritableBehavior.Inherit)
|
||||
{
|
||||
customTag.GameObjectNamesToApplyTo.Behavior = Inheritables.InheritableBehavior.Inherit;
|
||||
customTag.GameObjectNamesToApplyTo.Value = "";
|
||||
customTagsMigrated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (customTagsMigrated)
|
||||
needToSave = true;
|
||||
|
||||
return needToSave;
|
||||
}
|
||||
|
||||
public void AddCustomTagToIdentity(Tag customTag, Identity identity)
|
||||
{
|
||||
if (!identity.CustomTagIds.Contains(customTag.CustomId.Value))
|
||||
{
|
||||
identity.CustomTagIds.Add(customTag.CustomId.Value);
|
||||
}
|
||||
|
||||
if (!Identities.Contains(identity))
|
||||
{
|
||||
Identities.Add(identity);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveCustomTagFromIdentity(Tag customTag, Identity identity)
|
||||
{
|
||||
identity.CustomTagIds.Remove(customTag.CustomId.Value);
|
||||
|
||||
if (!identity.CustomTagIds.Any())
|
||||
{
|
||||
Identities.Remove(identity);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveCustomTagFromIdentities(Tag customTag)
|
||||
{
|
||||
foreach (var identity in Identities.ToArray())
|
||||
{
|
||||
RemoveCustomTagFromIdentity(customTag, identity);
|
||||
}
|
||||
}
|
||||
|
||||
public Identity GetIdentity(string name, uint? worldId)
|
||||
{
|
||||
foreach (var identity in Identities)
|
||||
{
|
||||
if (identity.Name.ToLower().Trim() == name.ToLower().Trim())
|
||||
{
|
||||
if (identity.WorldId == null && worldId != null)
|
||||
{
|
||||
identity.WorldId = worldId;
|
||||
pluginZonedConfig.ApplyTagsData(this);
|
||||
}
|
||||
|
||||
return identity;
|
||||
}
|
||||
}
|
||||
|
||||
return new Identity(name)
|
||||
{
|
||||
WorldId = worldId
|
||||
};
|
||||
}
|
||||
|
||||
public Identity? GetIdentity(GameObjectContextMenuOpenArgs contextMenuOpenedArgs)
|
||||
{
|
||||
if (string.IsNullOrEmpty(contextMenuOpenedArgs.Text?.TextValue)
|
||||
|| contextMenuOpenedArgs.ObjectWorld == 0
|
||||
|| contextMenuOpenedArgs.ObjectWorld == 65535)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return GetIdentity(contextMenuOpenedArgs.Text?.TextValue ?? string.Empty, contextMenuOpenedArgs.ObjectWorld);
|
||||
}
|
||||
|
||||
public Identity GetIdentity(PlayerCharacter playerCharacter)
|
||||
{
|
||||
return GetIdentity(playerCharacter.Name.TextValue, playerCharacter.HomeWorld.Id);
|
||||
}
|
||||
|
||||
public Identity GetIdentity(PartyMember partyMember)
|
||||
{
|
||||
return GetIdentity(partyMember.Name.TextValue, partyMember.World.Id);
|
||||
}
|
||||
|
||||
public Identity GetIdentity(PlayerPayload playerPayload)
|
||||
{
|
||||
return GetIdentity(playerPayload.PlayerName, playerPayload.World.RowId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,8 +102,14 @@ namespace PlayerTags.Features
|
||||
}
|
||||
}
|
||||
|
||||
public ChatTagTargetFeature(PluginConfiguration pluginConfiguration, PluginData pluginData) : base(pluginConfiguration, pluginData)
|
||||
private PluginConfiguration m_PluginConfiguration;
|
||||
private PluginData m_PluginData;
|
||||
|
||||
public ChatTagTargetFeature(PluginConfiguration pluginConfiguration, PluginData pluginData)
|
||||
{
|
||||
m_PluginConfiguration = pluginConfiguration;
|
||||
m_PluginData = pluginData;
|
||||
|
||||
PluginServices.ChatGui.ChatMessage += Chat_ChatMessage;
|
||||
}
|
||||
|
||||
@@ -115,7 +121,7 @@ namespace PlayerTags.Features
|
||||
|
||||
private void Chat_ChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled)
|
||||
{
|
||||
if (EnableGlobal && pluginConfiguration.GeneralOptions[ActivityContextManager.CurrentActivityContext.ActivityType].IsApplyTagsToAllChatMessagesEnabled)
|
||||
if (m_PluginConfiguration.GeneralConfigs.GetConfig(ActivityContextManager.CurrentActivityContext.ZoneType).IsApplyTagsToAllChatMessagesEnabled)
|
||||
{
|
||||
AddTagsToChat(sender, type, true);
|
||||
AddTagsToChat(message, type, false);
|
||||
@@ -329,7 +335,9 @@ namespace PlayerTags.Features
|
||||
if (isSender)
|
||||
SplitOffPartyNumberPrefix(message, chatType);
|
||||
|
||||
var tagsData = m_PluginData.GetTagsData(ActivityContextManager.CurrentActivityContext.ZoneType);
|
||||
var stringMatches = GetStringMatches(message);
|
||||
|
||||
foreach (var stringMatch in stringMatches)
|
||||
{
|
||||
StringChanges stringChanges = new();
|
||||
@@ -341,7 +349,7 @@ namespace PlayerTags.Features
|
||||
if (stringMatch.GameObject is PlayerCharacter playerCharacter)
|
||||
{
|
||||
// Add the job tag
|
||||
if (playerCharacter.ClassJob.GameData != null && pluginData.JobTags.TryGetValue(playerCharacter.ClassJob.GameData.Abbreviation, out var jobTag))
|
||||
if (playerCharacter.ClassJob.GameData != null && tagsData.JobTags.TryGetValue(playerCharacter.ClassJob.GameData.Abbreviation, out var jobTag))
|
||||
{
|
||||
if (isTagEnabled(jobTag))
|
||||
{
|
||||
@@ -355,7 +363,7 @@ namespace PlayerTags.Features
|
||||
}
|
||||
|
||||
// Add randomly generated name tag payload
|
||||
if (pluginConfiguration.IsPlayerNameRandomlyGenerated)
|
||||
if (m_PluginConfiguration.IsPlayerNameRandomlyGenerated)
|
||||
{
|
||||
var playerName = stringMatch.GetMatchText();
|
||||
if (playerName != null)
|
||||
@@ -372,10 +380,10 @@ namespace PlayerTags.Features
|
||||
// Add custom tags
|
||||
if (stringMatch.PlayerPayload != null)
|
||||
{
|
||||
Identity identity = pluginData.GetIdentity(stringMatch.PlayerPayload);
|
||||
Identity identity = tagsData.GetIdentity(stringMatch.PlayerPayload);
|
||||
foreach (var customTagId in identity.CustomTagIds)
|
||||
{
|
||||
var customTag = pluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
var customTag = tagsData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
if (customTag != null)
|
||||
{
|
||||
if (isTagEnabled(customTag))
|
||||
@@ -401,17 +409,17 @@ namespace PlayerTags.Features
|
||||
// An additional step to apply text color to additional locations
|
||||
if (stringMatch.PlayerPayload != null && stringMatch.DisplayTextPayloads.Any())
|
||||
{
|
||||
Identity identity = pluginData.GetIdentity(stringMatch.PlayerPayload);
|
||||
Identity identity = tagsData.GetIdentity(stringMatch.PlayerPayload);
|
||||
|
||||
if (stringMatch.GameObject is PlayerCharacter playerCharacter1)
|
||||
{
|
||||
if (playerCharacter1.ClassJob.GameData != null && pluginData.JobTags.TryGetValue(playerCharacter1.ClassJob.GameData.Abbreviation, out var jobTag) && isTagEnabled(jobTag))
|
||||
if (playerCharacter1.ClassJob.GameData != null && tagsData.JobTags.TryGetValue(playerCharacter1.ClassJob.GameData.Abbreviation, out var jobTag) && isTagEnabled(jobTag))
|
||||
applyTextFormatting(jobTag);
|
||||
}
|
||||
|
||||
foreach (var customTagId in identity.CustomTagIds)
|
||||
{
|
||||
var customTag = pluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
var customTag = tagsData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
if (customTag != null && isTagEnabled(customTag))
|
||||
applyTextFormatting(customTag);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Dalamud.ContextMenu;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Logging;
|
||||
using Pilz.Dalamud.ActivityContexts;
|
||||
using PlayerTags.Configuration;
|
||||
using PlayerTags.Data;
|
||||
using PlayerTags.Resources;
|
||||
@@ -13,7 +14,7 @@ namespace PlayerTags.Features
|
||||
/// <summary>
|
||||
/// A feature that adds options for the management of custom tags to context menus.
|
||||
/// </summary>
|
||||
public class CustomTagsContextMenuFeature : FeatureBase, IDisposable
|
||||
public class CustomTagsContextMenuFeature : FeatureBase
|
||||
{
|
||||
private string?[] SupportedAddonNames = new string?[]
|
||||
{
|
||||
@@ -31,15 +32,20 @@ namespace PlayerTags.Features
|
||||
"SocialList",
|
||||
};
|
||||
|
||||
private PluginConfiguration m_PluginConfiguration;
|
||||
private PluginData m_PluginData;
|
||||
private DalamudContextMenu? m_ContextMenu;
|
||||
|
||||
public CustomTagsContextMenuFeature(PluginConfiguration pluginConfiguration, PluginData pluginData) : base(pluginConfiguration, pluginData)
|
||||
public CustomTagsContextMenuFeature(PluginConfiguration pluginConfiguration, PluginData pluginData)
|
||||
{
|
||||
m_PluginConfiguration = pluginConfiguration;
|
||||
m_PluginData = pluginData;
|
||||
|
||||
m_ContextMenu = new DalamudContextMenu();
|
||||
m_ContextMenu.OnOpenGameObjectContextMenu += ContextMenuHooks_ContextMenuOpened;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
public override void Dispose()
|
||||
{
|
||||
if (m_ContextMenu != null)
|
||||
{
|
||||
@@ -47,21 +53,22 @@ namespace PlayerTags.Features
|
||||
((IDisposable)m_ContextMenu).Dispose();
|
||||
m_ContextMenu = null;
|
||||
}
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
private void ContextMenuHooks_ContextMenuOpened(GameObjectContextMenuOpenArgs contextMenuOpenedArgs)
|
||||
{
|
||||
if (!EnableGlobal || !pluginConfiguration.IsCustomTagsContextMenuEnabled
|
||||
if (!m_PluginConfiguration.IsCustomTagsContextMenuEnabled
|
||||
|| !SupportedAddonNames.Contains(contextMenuOpenedArgs.ParentAddonName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Identity? identity = pluginData.GetIdentity(contextMenuOpenedArgs);
|
||||
var tagsData = m_PluginData.GetTagsData(ActivityContextManager.CurrentActivityContext.ZoneType);
|
||||
Identity? identity = tagsData.GetIdentity(contextMenuOpenedArgs);
|
||||
|
||||
if (identity != null)
|
||||
{
|
||||
var allTags = new Dictionary<Tag, bool>();
|
||||
foreach (var customTag in pluginData.CustomTags)
|
||||
foreach (var customTag in tagsData.CustomTags)
|
||||
{
|
||||
var isAdded = identity.CustomTagIds.Contains(customTag.CustomId.Value);
|
||||
allTags.Add(customTag, isAdded);
|
||||
@@ -81,10 +88,10 @@ namespace PlayerTags.Features
|
||||
new GameObjectContextMenuItem(menuItemText, openedEventArgs =>
|
||||
{
|
||||
if (tag.Value)
|
||||
pluginData.RemoveCustomTagFromIdentity(tag.Key, identity);
|
||||
tagsData.RemoveCustomTagFromIdentity(tag.Key, identity);
|
||||
else
|
||||
pluginData.AddCustomTagToIdentity(tag.Key, identity);
|
||||
pluginConfiguration.Save(pluginData);
|
||||
tagsData.AddCustomTagToIdentity(tag.Key, identity);
|
||||
m_PluginConfiguration.Save(m_PluginData);
|
||||
})
|
||||
{
|
||||
IsSubMenu = false
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using PlayerTags.Configuration;
|
||||
using PlayerTags.Data;
|
||||
using Pilz.Dalamud.ActivityContexts;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -8,17 +7,18 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace PlayerTags.Features
|
||||
{
|
||||
public class FeatureBase
|
||||
public abstract class FeatureBase : IDisposable
|
||||
{
|
||||
protected readonly PluginConfiguration pluginConfiguration;
|
||||
protected readonly PluginData pluginData;
|
||||
public ActivityContextManager ActivityContextManager { get; init; }
|
||||
|
||||
public virtual bool EnableGlobal => pluginConfiguration.EnabledGlobal;
|
||||
|
||||
protected FeatureBase(PluginConfiguration pluginConfiguration, PluginData pluginData)
|
||||
public FeatureBase()
|
||||
{
|
||||
this.pluginConfiguration = pluginConfiguration;
|
||||
this.pluginData = pluginData;
|
||||
ActivityContextManager = new();
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
ActivityContextManager.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,16 @@ namespace PlayerTags.Features
|
||||
/// </summary>
|
||||
public class NameplateTagTargetFeature : TagTargetFeature
|
||||
{
|
||||
private readonly PluginConfiguration m_PluginConfiguration;
|
||||
private readonly PluginData m_PluginData;
|
||||
private readonly StatusIconPriorizer statusiconPriorizer;
|
||||
private readonly JobIconSets jobIconSets = new();
|
||||
private Nameplate? m_Nameplate;
|
||||
|
||||
public NameplateTagTargetFeature(PluginConfiguration pluginConfiguration, PluginData pluginData) : base(pluginConfiguration, pluginData)
|
||||
public NameplateTagTargetFeature(PluginConfiguration pluginConfiguration, PluginData pluginData)
|
||||
{
|
||||
m_PluginConfiguration = pluginConfiguration;
|
||||
m_PluginData = pluginData;
|
||||
statusiconPriorizer = new(pluginConfiguration.StatusIconPriorizerSettings);
|
||||
|
||||
PluginServices.ClientState.Login += ClientState_Login;
|
||||
@@ -107,13 +111,11 @@ namespace PlayerTags.Features
|
||||
|
||||
private unsafe void Nameplate_PlayerNameplateUpdated(PlayerNameplateUpdatedArgs args)
|
||||
{
|
||||
if (!EnableGlobal) return;
|
||||
|
||||
var beforeTitleBytes = args.Title.Encode();
|
||||
var iconID = args.IconId;
|
||||
var generalOptions = pluginConfiguration.GeneralOptions[ActivityContextManager.CurrentActivityContext.ActivityType];
|
||||
var generalOptions = m_PluginConfiguration.GeneralConfigs.GetConfig(ActivityContextManager.CurrentActivityContext.ZoneType);
|
||||
|
||||
AddTagsToNameplate(args.PlayerCharacter, args.Name, args.Title, args.FreeCompany, ref iconID, generalOptions);
|
||||
AddTagsToNameplate(args.PlayerCharacter, args.Name, args.Title, args.FreeCompany, ref iconID);
|
||||
|
||||
args.IconId = iconID;
|
||||
|
||||
@@ -170,26 +172,29 @@ namespace PlayerTags.Features
|
||||
/// <param name="name">The name text to change.</param>
|
||||
/// <param name="title">The title text to change.</param>
|
||||
/// <param name="freeCompany">The free company text to change.</param>
|
||||
private void AddTagsToNameplate(GameObject gameObject, SeString name, SeString title, SeString freeCompany, ref int statusIcon, GeneralOptionsClass generalOptions)
|
||||
private void AddTagsToNameplate(GameObject gameObject, SeString name, SeString title, SeString freeCompany, ref int statusIcon)
|
||||
{
|
||||
var curZoneType = ActivityContextManager.CurrentActivityContext.ZoneType;
|
||||
var generalConfig = m_PluginConfiguration.GeneralConfigs.GetConfig(curZoneType);
|
||||
var tagsData = m_PluginData.GetTagsData(curZoneType);
|
||||
var playerCharacter = gameObject as PlayerCharacter;
|
||||
int? newStatusIcon = null;
|
||||
NameplateChanges nameplateChanges = GenerateEmptyNameplateChanges(name, title, freeCompany);
|
||||
|
||||
if (playerCharacter != null && (!playerCharacter.IsDead || generalOptions.NameplateDeadPlayerHandling != DeadPlayerHandling.Ignore))
|
||||
if (playerCharacter != null && (!playerCharacter.IsDead || generalConfig.NameplateDeadPlayerHandling != DeadPlayerHandling.Ignore))
|
||||
{
|
||||
var classJob = playerCharacter.ClassJob;
|
||||
var classJobGameData = classJob?.GameData;
|
||||
|
||||
// Add the job tags
|
||||
if (classJobGameData != null && pluginData.JobTags.TryGetValue(classJobGameData.Abbreviation, out var jobTag))
|
||||
if (classJobGameData != null && tagsData.JobTags.TryGetValue(classJobGameData.Abbreviation, out var jobTag))
|
||||
{
|
||||
if (jobTag.TagTargetInNameplates.InheritedValue != null && jobTag.TagPositionInNameplates.InheritedValue != null)
|
||||
checkTag(jobTag);
|
||||
}
|
||||
|
||||
// Add the randomly generated name tag payload
|
||||
if (pluginConfiguration.IsPlayerNameRandomlyGenerated)
|
||||
if (m_PluginConfiguration.IsPlayerNameRandomlyGenerated)
|
||||
{
|
||||
var characterName = playerCharacter.Name.TextValue;
|
||||
if (characterName != null)
|
||||
@@ -201,10 +206,10 @@ namespace PlayerTags.Features
|
||||
}
|
||||
|
||||
// Add custom tags
|
||||
Identity identity = pluginData.GetIdentity(playerCharacter);
|
||||
Identity identity = tagsData.GetIdentity(playerCharacter);
|
||||
foreach (var customTagId in identity.CustomTagIds)
|
||||
{
|
||||
var customTag = pluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
var customTag = tagsData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
if (customTag != null)
|
||||
checkTag(customTag);
|
||||
}
|
||||
@@ -226,28 +231,28 @@ namespace PlayerTags.Features
|
||||
if (newStatusIcon != null)
|
||||
{
|
||||
var change = nameplateChanges.GetChange(NameplateElements.Name, StringPosition.Before);
|
||||
NameplateUpdateFactory.ApplyStatusIconWithPrio(ref statusIcon, (int)newStatusIcon, change, ActivityContextManager.CurrentActivityContext, statusiconPriorizer, pluginConfiguration.MoveStatusIconToNameplateTextIfPossible);
|
||||
NameplateUpdateFactory.ApplyStatusIconWithPrio(ref statusIcon, (int)newStatusIcon, change, ActivityContextManager.CurrentActivityContext, statusiconPriorizer, m_PluginConfiguration.MoveStatusIconToNameplateTextIfPossible);
|
||||
}
|
||||
|
||||
// Gray out the nameplate
|
||||
if (playerCharacter != null && playerCharacter.IsDead && generalOptions.NameplateDeadPlayerHandling == DeadPlayerHandling.GrayOut)
|
||||
if (playerCharacter != null && playerCharacter.IsDead && generalConfig.NameplateDeadPlayerHandling == DeadPlayerHandling.GrayOut)
|
||||
GrayOutNameplate(gameObject, nameplateChanges);
|
||||
|
||||
// Build the final strings out of the payloads
|
||||
ApplyNameplateChanges(nameplateChanges);
|
||||
|
||||
if (playerCharacter != null && (!playerCharacter.IsDead || generalOptions.NameplateDeadPlayerHandling == DeadPlayerHandling.Include))
|
||||
if (playerCharacter != null && (!playerCharacter.IsDead || generalConfig.NameplateDeadPlayerHandling == DeadPlayerHandling.Include))
|
||||
{
|
||||
// An additional step to apply text color to additional locations
|
||||
Identity identity = pluginData.GetIdentity(playerCharacter);
|
||||
Identity identity = tagsData.GetIdentity(playerCharacter);
|
||||
foreach (var customTagId in identity.CustomTagIds)
|
||||
{
|
||||
var customTag = pluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
var customTag = tagsData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
if (customTag != null)
|
||||
applyTextFormatting(customTag);
|
||||
}
|
||||
|
||||
if (playerCharacter.ClassJob.GameData != null && pluginData.JobTags.TryGetValue(playerCharacter.ClassJob.GameData.Abbreviation, out var jobTag))
|
||||
if (playerCharacter.ClassJob.GameData != null && tagsData.JobTags.TryGetValue(playerCharacter.ClassJob.GameData.Abbreviation, out var jobTag))
|
||||
applyTextFormatting(jobTag);
|
||||
|
||||
void applyTextFormatting(Tag tag)
|
||||
|
||||
@@ -6,7 +6,6 @@ using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Pilz.Dalamud.ActivityContexts;
|
||||
using Pilz.Dalamud.Tools.Strings;
|
||||
using PlayerTags.Configuration;
|
||||
using PlayerTags.Configuration.GameConfig;
|
||||
using PlayerTags.Data;
|
||||
using PlayerTags.Inheritables;
|
||||
@@ -21,18 +20,16 @@ namespace PlayerTags.Features
|
||||
/// <summary>
|
||||
/// The base of a feature that adds tags to UI elements.
|
||||
/// </summary>
|
||||
public abstract class TagTargetFeature : FeatureBase, IDisposable
|
||||
public abstract class TagTargetFeature : FeatureBase
|
||||
{
|
||||
public ActivityContextManager ActivityContextManager { get; init; }
|
||||
|
||||
protected TagTargetFeature(PluginConfiguration pluginConfiguration, PluginData pluginData) : base(pluginConfiguration, pluginData)
|
||||
public TagTargetFeature()
|
||||
{
|
||||
ActivityContextManager = new();
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
public override void Dispose()
|
||||
{
|
||||
ActivityContextManager.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
protected abstract bool IsIconVisible(Tag tag);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Authors>r00telement;Pilzinsel64</Authors>
|
||||
<Version>1.9.5.0</Version>
|
||||
<Version>1.9.0.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
@@ -24,9 +24,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dalamud.ContextMenu" Version="1.2.3" />
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.11" />
|
||||
<ProjectReference Include="..\Pilz.Dalamud\Pilz.Dalamud\Pilz.Dalamud.csproj" />
|
||||
<PackageReference Include="Dalamud.ContextMenu" Version="1.2.1" />
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.10" />
|
||||
<ProjectReference Include="..\Pilz.Dalamud\Pilz.Dalamud.csproj" />
|
||||
<Reference Include="FFXIVClientStructs">
|
||||
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
|
||||
@@ -10,7 +10,6 @@ using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace PlayerTags
|
||||
{
|
||||
@@ -18,10 +17,6 @@ namespace PlayerTags
|
||||
{
|
||||
public string Name => "Player Tags";
|
||||
private const string c_CommandName = "/playertags";
|
||||
private const string c_SubCommandName_EnableGlobal = "enableglobal";
|
||||
private const string c_CommandArg_On = "on";
|
||||
private const string c_CommandArg_Off = "off";
|
||||
private const string c_CommandArg_toggle = "toggle";
|
||||
|
||||
private PluginConfiguration m_PluginConfiguration;
|
||||
private PluginData m_PluginData;
|
||||
@@ -45,9 +40,9 @@ namespace PlayerTags
|
||||
|
||||
PluginServices.DalamudPluginInterface.UiBuilder.Draw += UiBuilder_Draw;
|
||||
PluginServices.DalamudPluginInterface.UiBuilder.OpenConfigUi += UiBuilder_OpenConfigUi;
|
||||
PluginServices.CommandManager.AddHandler(c_CommandName, new CommandInfo(CommandManager_Handler)
|
||||
PluginServices.CommandManager.AddHandler(c_CommandName, new CommandInfo((string command, string arguments) => UiBuilder_OpenConfigUi())
|
||||
{
|
||||
HelpMessage = Resources.Strings.Loc_Command_playertags_v2
|
||||
HelpMessage = Resources.Strings.Loc_Command_playertags
|
||||
});
|
||||
m_CustomTagsContextMenuFeature = new CustomTagsContextMenuFeature(m_PluginConfiguration, m_PluginData);
|
||||
m_NameplatesTagTargetFeature = new NameplateTagTargetFeature(m_PluginConfiguration, m_PluginData);
|
||||
@@ -70,44 +65,6 @@ namespace PlayerTags
|
||||
Localizer.SetLanguage(langCode);
|
||||
}
|
||||
|
||||
private void CommandManager_Handler(string command, string arguments)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case c_CommandName:
|
||||
if (string.IsNullOrWhiteSpace(arguments))
|
||||
UiBuilder_OpenConfigUi();
|
||||
else
|
||||
{
|
||||
var lowerArgs = arguments.ToLower().Split(' ');
|
||||
if (lowerArgs.Length >= 1)
|
||||
{
|
||||
switch (lowerArgs[0])
|
||||
{
|
||||
case c_SubCommandName_EnableGlobal:
|
||||
if (lowerArgs.Length >= 2)
|
||||
{
|
||||
switch (lowerArgs[0])
|
||||
{
|
||||
case c_CommandArg_On:
|
||||
m_PluginConfiguration.EnabledGlobal = true;
|
||||
break;
|
||||
case c_CommandArg_Off:
|
||||
m_PluginConfiguration.EnabledGlobal = false;
|
||||
break;
|
||||
case c_CommandArg_toggle:
|
||||
m_PluginConfiguration.EnabledGlobal = !m_PluginConfiguration.EnabledGlobal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void UiBuilder_Draw()
|
||||
{
|
||||
if (m_PluginConfiguration.IsVisible)
|
||||
|
||||
8
PlayerTags/Resources/Strings.Designer.cs
generated
8
PlayerTags/Resources/Strings.Designer.cs
generated
@@ -187,13 +187,11 @@ namespace PlayerTags.Resources {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sucht eine lokalisierte Zeichenfolge, die Shows the config window for Player Tags
|
||||
///Subcommands:
|
||||
///enableglobal on|of|toggle -> Set a global master switch that enables or disables all plugin features without changing the current configuration. ähnelt.
|
||||
/// Sucht eine lokalisierte Zeichenfolge, die Shows the config window for Player Tags ähnelt.
|
||||
/// </summary>
|
||||
public static string Loc_Command_playertags_v2 {
|
||||
public static string Loc_Command_playertags {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Command_playertags_v2", resourceCulture);
|
||||
return ResourceManager.GetString("Loc_Command_playertags", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -829,9 +829,4 @@ Benutze dies, wenn du jede Option unter deiner Kontrolle haben möchtest oder nu
|
||||
<value>Wenn aktiviert, gilt das Tag für alle Chat-Nachrichten, die keinen definierten Typ haben.
|
||||
Dieser Fall kann entweder auftreten, wenn das Spiel ein Update bekommt und die Aufzählung aller Chat-Typen aufgrund von geänderten Werten ungültig sind oder Plugins erstellt einen benutzerdefinierten Chat-Typ, aus welchen Gründen auch immer.</value>
|
||||
</data>
|
||||
<data name="Loc_Command_playertags_v2" xml:space="preserve">
|
||||
<value>Zeigt das Konfigurationsfester Player Tags
|
||||
Unterbefehle:
|
||||
enableglobal on|of|toggle -> Setzt einen globalen Hauptschalter, welcher alle PluginFeaturues ein- bzw. ausschalten kann, ohne die Konfiguration selbst zu ändern.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -829,9 +829,4 @@ Utilisez ce modèle si vous souhaitez avoir toutes les options sous votre contr
|
||||
<value>Lorsque cette option est activée, le tag s'appliquera à tous les messages qui n'ont pas de type défini.
|
||||
Cela peut se produire si les mises à jour du jeu et l'énumération de tous les types de chat deviennent invalides en raison de valeurs déplacées ou altérées, ou si un autre plugin crée un type de chat personnalisé pour quelque raison que ce soit.</value>
|
||||
</data>
|
||||
<data name="Loc_Command_playertags_v2" xml:space="preserve">
|
||||
<value>Affiche la fenêtre de configuration des tags du joueur
|
||||
Sous-commandes :
|
||||
enableglobal on|of|toggle -> Commande globale maîtresse qui active ou désactive toutes les fonctionnalités du plugin sans en modifier la configuration actuelle.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,120 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -1,198 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Loc_Static_PluginName" xml:space="preserve">
|
||||
<value>플레이어 태그</value>
|
||||
</data>
|
||||
<data name="Loc_Static_WarningMessage" xml:space="preserve">
|
||||
<value>이 플러그인은 네임태그 및 채팅을 수정할 수 있습니다. 해당 기능을 수정하는 다른 플러그인과 동시에 사용하면 예기치 못한 결과가 나올 수 있습니다. 플러그인 로드 순서에 따라 달라집니다.</value>
|
||||
</data>
|
||||
<data name="Loc_Static_General" xml:space="preserve">
|
||||
<value>기본</value>
|
||||
</data>
|
||||
<data name="Loc_Static_QuickTag" xml:space="preserve">
|
||||
<value>퀵 태그</value>
|
||||
</data>
|
||||
<data name="Loc_Static_TaggedPlayers" xml:space="preserve">
|
||||
<value>태그된 플레이어</value>
|
||||
</data>
|
||||
<data name="Loc_Static_PlayerName" xml:space="preserve">
|
||||
<value>플레이어</value>
|
||||
</data>
|
||||
<data name="Loc_Static_ContextMenu_AddTag" xml:space="preserve">
|
||||
<value>태그 추가: {0}</value>
|
||||
</data>
|
||||
<data name="Loc_Static_ContextMenu_RemoveTag" xml:space="preserve">
|
||||
<value>태그 지우기: {0}</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Nameplates" xml:space="preserve">
|
||||
<value>네임태그</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Format_AddTagToPlayer" xml:space="preserve">
|
||||
<value>추가 '{0}' 또는 {1}.</value>
|
||||
</data>
|
||||
<data name="Loc_IsSelected" xml:space="preserve">
|
||||
<value>선택됨</value>
|
||||
</data>
|
||||
<data name="Loc_IsExpanded" xml:space="preserve">
|
||||
<value>펼침</value>
|
||||
</data>
|
||||
<data name="Loc_IsCustomTagsContextMenuEnabled" xml:space="preserve">
|
||||
<value>상황에 맞는 메뉴 통합</value>
|
||||
</data>
|
||||
<data name="Loc_IsCustomTagsContextMenuEnabled_Description" xml:space="preserve">
|
||||
<value>플레이어에서 사용자 지정 태그를 추가 혹은 제거하기 위한 옵션을 상황에 맞는 메뉴에서 사용할 수 있습니다.</value>
|
||||
</data>
|
||||
<data name="Loc_IsShowInheritedPropertiesEnabled" xml:space="preserve">
|
||||
<value>상속 속성 표시</value>
|
||||
</data>
|
||||
<data name="Loc_IsShowInheritedPropertiesEnabled_Description" xml:space="preserve">
|
||||
<value>상위 노드에서 상속된 속성이 편집기에 표시됩니다.</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateFreeCompanyVisibility" xml:space="preserve">
|
||||
<value>자유부대 표시</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateFreeCompanyVisibility_Default" xml:space="preserve">
|
||||
<value>기본</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateFreeCompanyVisibility_Default_Description" xml:space="preserve">
|
||||
<value>네임태그의 자유부대는 캐릭터가 자유부대에 속해 있을 때만 볼 수 있습니다.</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateFreeCompanyVisibility_Never" xml:space="preserve">
|
||||
<value>안 보이게 하기</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateFreeCompanyVisibility_Never_Description" xml:space="preserve">
|
||||
<value>자유부대를 보이지 않게 합니다.</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility" xml:space="preserve">
|
||||
<value>칭호 표시</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility_Always" xml:space="preserve">
|
||||
<value>항상 표시</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility_Always_Description" xml:space="preserve">
|
||||
<value>네임태그의 칭호는 캐릭터에게 칭호가 없는 경우에도 볼 수 있습니다.</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility_Default" xml:space="preserve">
|
||||
<value>기본</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility_Never" xml:space="preserve">
|
||||
<value>안 보이게 하기</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -829,9 +829,7 @@ Use this if you want to to have every option under your control or just want to
|
||||
<value>When enabled the Tag will apply to all Chat messages that has not a defined type.
|
||||
This case can happen either if the Game updates and the Enumeration of all Chat Types gets invalid due to shifted values, or plugins creates a custom chat type for whatever reason.</value>
|
||||
</data>
|
||||
<data name="Loc_Command_playertags_v2" xml:space="preserve">
|
||||
<value>Shows the config window for Player Tags
|
||||
Subcommands:
|
||||
enableglobal on|of|toggle -> Set a global master switch that enables or disables all plugin features without changing the current configuration.</value>
|
||||
<data name="Loc_Command_playertags" xml:space="preserve">
|
||||
<value>Shows the config window for Player Tags</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,837 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Loc_Static_PluginName" xml:space="preserve">
|
||||
<value>玩家标签</value>
|
||||
</data>
|
||||
<data name="Loc_Static_WarningMessage" xml:space="preserve">
|
||||
<value>此插件可以修改姓名版和聊天栏。当与其他修改这些内容的插件同时使用时,您可能会看到预期之外的行为。 您的插件的加载顺序可能会影响这个现象。</value>
|
||||
</data>
|
||||
<data name="Loc_Static_General" xml:space="preserve">
|
||||
<value>通常设置</value>
|
||||
</data>
|
||||
<data name="Loc_Static_QuickTag" xml:space="preserve">
|
||||
<value>快速标签[国服好像不可用]</value>
|
||||
</data>
|
||||
<data name="Loc_Static_TaggedPlayers" xml:space="preserve">
|
||||
<value>已标记的玩家</value>
|
||||
</data>
|
||||
<data name="Loc_Static_PlayerName" xml:space="preserve">
|
||||
<value>玩家</value>
|
||||
</data>
|
||||
<data name="Loc_Static_ContextMenu_AddTag" xml:space="preserve">
|
||||
<value>添加标签: {0}</value>
|
||||
</data>
|
||||
<data name="Loc_Static_ContextMenu_RemoveTag" xml:space="preserve">
|
||||
<value>移除标签: {0}</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Nameplates" xml:space="preserve">
|
||||
<value>铭牌</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Format_AddTagToPlayer" xml:space="preserve">
|
||||
<value>将 ‘{0}’添加到 {1}.</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Inherited" xml:space="preserve">
|
||||
<value><已继承></value>
|
||||
</data>
|
||||
<data name="Loc_IsSelected" xml:space="preserve">
|
||||
<value>已选择</value>
|
||||
</data>
|
||||
<data name="Loc_IsExpanded" xml:space="preserve">
|
||||
<value>已展开</value>
|
||||
</data>
|
||||
<data name="Loc_IsCustomTagsContextMenuEnabled" xml:space="preserve">
|
||||
<value>上下文菜单集成</value>
|
||||
</data>
|
||||
<data name="Loc_IsCustomTagsContextMenuEnabled_Description" xml:space="preserve">
|
||||
<value>选项将在上下文菜单中可用,用于添加和删除玩家的自定义标签。</value>
|
||||
</data>
|
||||
<data name="Loc_IsShowInheritedPropertiesEnabled" xml:space="preserve">
|
||||
<value>显示继承的属性</value>
|
||||
</data>
|
||||
<data name="Loc_IsShowInheritedPropertiesEnabled_Description" xml:space="preserve">
|
||||
<value>从父节点继承的属性将显示在编辑器中。</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateFreeCompanyVisibility" xml:space="preserve">
|
||||
<value>部队名称可见性</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateFreeCompanyVisibility_Default" xml:space="preserve">
|
||||
<value>默认</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateFreeCompanyVisibility_Default_Description" xml:space="preserve">
|
||||
<value>铭牌上的部队名称部分只有当角色已加入部队时才可见。</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateFreeCompanyVisibility_Never" xml:space="preserve">
|
||||
<value>不可见</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateFreeCompanyVisibility_Never_Description" xml:space="preserve">
|
||||
<value>铭牌上的部队名称部分将永远不可见。</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility" xml:space="preserve">
|
||||
<value>称号可见性</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility_Always" xml:space="preserve">
|
||||
<value>始终可见</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility_Always_Description" xml:space="preserve">
|
||||
<value>铭牌上的标题将始终可见,即使角色没有标题。</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility_Default" xml:space="preserve">
|
||||
<value>默认</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility_Default_Description" xml:space="preserve">
|
||||
<value>只有当角色有头衔时,铭牌上的头衔才会可见。</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility_Never" xml:space="preserve">
|
||||
<value>不可见</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility_Never_Description" xml:space="preserve">
|
||||
<value>铭牌上的称号部分将永远不可见。</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility_WhenHasTags" xml:space="preserve">
|
||||
<value>仅当有标签时可见</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility_WhenHasTags_Description" xml:space="preserve">
|
||||
<value>铭牌上的称号部分只在有标签时才可见。</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitlePosition" xml:space="preserve">
|
||||
<value>称号位置</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitlePosition_AlwaysAboveName" xml:space="preserve">
|
||||
<value>总是在名称上字</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitlePosition_AlwaysAboveName_Description" xml:space="preserve">
|
||||
<value>铭牌上的称号将始终位于名字上方。</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitlePosition_AlwaysBelowName" xml:space="preserve">
|
||||
<value>总是在名字下面</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitlePosition_AlwaysBelowName_Description" xml:space="preserve">
|
||||
<value>铭牌上的称号将始终位于名字下方。</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitlePosition_Default" xml:space="preserve">
|
||||
<value>默认</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitlePosition_Default_Description" xml:space="preserve">
|
||||
<value>铭牌上的称号将根据称号定位。</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateElement_FreeCompany" xml:space="preserve">
|
||||
<value>部队</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateElement_FreeCompany_Description" xml:space="preserve">
|
||||
<value>铭牌上的部队名称部分。</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateElement_Name" xml:space="preserve">
|
||||
<value>名字</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateElement_Name_Description" xml:space="preserve">
|
||||
<value>铭牌上的名字部分。</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateElement_Title" xml:space="preserve">
|
||||
<value>称号</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateElement_Title_Description" xml:space="preserve">
|
||||
<value>铭牌上的称号部分。</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Development" xml:space="preserve">
|
||||
<value>开发</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Experimental" xml:space="preserve">
|
||||
<value>实验</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayerNameRandomlyGenerated" xml:space="preserve">
|
||||
<value>随机生成玩家名字</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayerNameRandomlyGenerated_Description" xml:space="preserve">
|
||||
<value>将每个玩家的名字替换为随机生成的名字。</value>
|
||||
</data>
|
||||
<data name="Loc_IsLinkSelfInChatEnabled" xml:space="preserve">
|
||||
<value>在聊天中为自己应用标签</value>
|
||||
</data>
|
||||
<data name="Loc_IsLinkSelfInChatEnabled_Description" xml:space="preserve">
|
||||
<value>尝试将您的聊天名称链接到您的角色,允许在聊天中将标签应用于自己。</value>
|
||||
</data>
|
||||
<data name="Loc_IsApplyTagsToAllChatMessagesEnabled" xml:space="preserve">
|
||||
<value>将标签应用到所有聊天信息</value>
|
||||
</data>
|
||||
<data name="Loc_IsApplyTagsToAllChatMessagesEnabled_Description" xml:space="preserve">
|
||||
<value>将标签应用于所有聊天消息,包括非社交消息。</value>
|
||||
</data>
|
||||
<data name="Loc_Static_ResetDefault_Description" xml:space="preserve">
|
||||
<value>重置此项为默认值。</value>
|
||||
</data>
|
||||
<data name="Loc_Static_ResetAllDefault_Description" xml:space="preserve">
|
||||
<value>重置所有项为默认值。自定义标签不会被触及。</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Tags" xml:space="preserve">
|
||||
<value>标签</value>
|
||||
</data>
|
||||
<data name="Loc_Static_NoText" xml:space="preserve">
|
||||
<value><无文本></value>
|
||||
</data>
|
||||
<data name="Loc_AllTags" xml:space="preserve">
|
||||
<value>全部</value>
|
||||
</data>
|
||||
<data name="Loc_AllRoleTags" xml:space="preserve">
|
||||
<value>角色</value>
|
||||
</data>
|
||||
<data name="Loc_Role_LandHand" xml:space="preserve">
|
||||
<value>地/手</value>
|
||||
</data>
|
||||
<data name="Loc_Role_Tank" xml:space="preserve">
|
||||
<value>坦克</value>
|
||||
</data>
|
||||
<data name="Loc_Role_Healer" xml:space="preserve">
|
||||
<value>治疗</value>
|
||||
</data>
|
||||
<data name="Loc_Role_Dps" xml:space="preserve">
|
||||
<value>每秒伤害</value>
|
||||
</data>
|
||||
<data name="Loc_DpsRole_Melee" xml:space="preserve">
|
||||
<value>混战</value>
|
||||
</data>
|
||||
<data name="Loc_DpsRole_Ranged" xml:space="preserve">
|
||||
<value>远程</value>
|
||||
</data>
|
||||
<data name="Loc_RangedDpsRole_Magical" xml:space="preserve">
|
||||
<value>魔法</value>
|
||||
</data>
|
||||
<data name="Loc_RangedDpsRole_Physical" xml:space="preserve">
|
||||
<value>物理</value>
|
||||
</data>
|
||||
<data name="Loc_LandHandRole_Hand" xml:space="preserve">
|
||||
<value>手部</value>
|
||||
</data>
|
||||
<data name="Loc_LandHandRole_Land" xml:space="preserve">
|
||||
<value>大地</value>
|
||||
</data>
|
||||
<data name="Loc_AllCustomTags" xml:space="preserve">
|
||||
<value>自定义</value>
|
||||
</data>
|
||||
<data name="Loc_CustomTags" xml:space="preserve">
|
||||
<value>自定义</value>
|
||||
</data>
|
||||
<data name="Loc_IsEnabled_Description" xml:space="preserve">
|
||||
<value>启用此覆盖的值。</value>
|
||||
</data>
|
||||
<data name="Loc_Static_AddPropertyOverride_Description" xml:space="preserve">
|
||||
<value>添加属性覆盖。</value>
|
||||
</data>
|
||||
<data name="Loc_Static_RemovePropertyOverride_Description" xml:space="preserve">
|
||||
<value>移除此属性覆盖。该值将从父项继承。</value>
|
||||
</data>
|
||||
<data name="Loc_Static_NewTag" xml:space="preserve">
|
||||
<value>新标签</value>
|
||||
</data>
|
||||
<data name="Loc_Static_AddCustomTag_Description" xml:space="preserve">
|
||||
<value>添加自定义标签。</value>
|
||||
</data>
|
||||
<data name="Loc_Static_RemoveCustomTag_Description" xml:space="preserve">
|
||||
<value>移除此自定义标签。</value>
|
||||
</data>
|
||||
<data name="Loc_Icon" xml:space="preserve">
|
||||
<value>图标</value>
|
||||
</data>
|
||||
<data name="Loc_Icon_Description" xml:space="preserve">
|
||||
<value>将显示的图标。</value>
|
||||
</data>
|
||||
<data name="Loc_IsIconVisibleInChat" xml:space="preserve">
|
||||
<value>在聊天中显示</value>
|
||||
</data>
|
||||
<data name="Loc_IsRoleIconVisibleInChat_Description" xml:space="preserve">
|
||||
<value>是否在聊天中显示角色图标。</value>
|
||||
</data>
|
||||
<data name="Loc_IsRoleIconVisibleInNameplates" xml:space="preserve">
|
||||
<value>在铭牌上显示角色图标</value>
|
||||
</data>
|
||||
<data name="Loc_IsRoleIconVisibleInNameplates_Description" xml:space="preserve">
|
||||
<value>是否在铭牌上显示角色图标。</value>
|
||||
</data>
|
||||
<data name="Loc_Text" xml:space="preserve">
|
||||
<value>文本</value>
|
||||
</data>
|
||||
<data name="Loc_Text_Description" xml:space="preserve">
|
||||
<value>将显示的文本。</value>
|
||||
</data>
|
||||
<data name="Loc_TextColor" xml:space="preserve">
|
||||
<value>颜色</value>
|
||||
</data>
|
||||
<data name="Loc_TextColor_Description" xml:space="preserve">
|
||||
<value>文本的颜色。</value>
|
||||
</data>
|
||||
<data name="Loc_TextGlowColor" xml:space="preserve">
|
||||
<value>发光颜色</value>
|
||||
</data>
|
||||
<data name="Loc_TextGlowColor_Description" xml:space="preserve">
|
||||
<value>文本的发光颜色。</value>
|
||||
</data>
|
||||
<data name="Loc_IsTextItalic" xml:space="preserve">
|
||||
<value>斜体</value>
|
||||
</data>
|
||||
<data name="Loc_IsTextItalic_Description" xml:space="preserve">
|
||||
<value>文本是否为斜体。</value>
|
||||
</data>
|
||||
<data name="Loc_IsTextVisibleInChat" xml:space="preserve">
|
||||
<value>在聊天中显示</value>
|
||||
</data>
|
||||
<data name="Loc_IsTextVisibleInChat_Description" xml:space="preserve">
|
||||
<value>文本是否会在聊天中显示。</value>
|
||||
</data>
|
||||
<data name="Loc_IsTextVisibleInNameplates" xml:space="preserve">
|
||||
<value>在铭牌上显示</value>
|
||||
</data>
|
||||
<data name="Loc_IsTextVisibleInNameplates_Description" xml:space="preserve">
|
||||
<value>文本是否会显示在铭牌上。</value>
|
||||
</data>
|
||||
<data name="Loc_TagPositionInChat" xml:space="preserve">
|
||||
<value>聊天窗口中的位置</value>
|
||||
</data>
|
||||
<data name="Loc_TagPositionInChat_Description" xml:space="preserve">
|
||||
<value>标签将放置在聊天中的位置。</value>
|
||||
</data>
|
||||
<data name="Loc_TagPositionInNameplates" xml:space="preserve">
|
||||
<value>铭牌中的位置</value>
|
||||
</data>
|
||||
<data name="Loc_TagPositionInNameplates_Description" xml:space="preserve">
|
||||
<value>标签将放置在铭牌上的位置。</value>
|
||||
</data>
|
||||
<data name="Loc_TagTargetInNameplates" xml:space="preserve">
|
||||
<value>铭牌上的目标</value>
|
||||
</data>
|
||||
<data name="Loc_TagTargetInNameplates_Description" xml:space="preserve">
|
||||
<value>标签应在铭牌中针对的元素。</value>
|
||||
</data>
|
||||
<data name="Loc_GameObjectNamesToApplyTo" xml:space="preserve">
|
||||
<value>添加到玩家</value>
|
||||
</data>
|
||||
<data name="Loc_GameObjectNamesToApplyTo_Description" xml:space="preserve">
|
||||
<value>要添加玩家列表的标签,以逗号或分号分隔。例如 “Cloud Strife, Tifa Lockhart”。</value>
|
||||
</data>
|
||||
<data name="Loc_TagPosition_After" xml:space="preserve">
|
||||
<value>之后</value>
|
||||
</data>
|
||||
<data name="Loc_TagPosition_After_Description" xml:space="preserve">
|
||||
<value>在目标元素之后显示标签。</value>
|
||||
</data>
|
||||
<data name="Loc_TagPosition_Before" xml:space="preserve">
|
||||
<value>之前</value>
|
||||
</data>
|
||||
<data name="Loc_TagPosition_Before_Description" xml:space="preserve">
|
||||
<value>在目标元素之前显示标签。</value>
|
||||
</data>
|
||||
<data name="Loc_TagPosition_Replace" xml:space="preserve">
|
||||
<value>替换</value>
|
||||
</data>
|
||||
<data name="Loc_TagPosition_Replace_Description" xml:space="preserve">
|
||||
<value>将目标元素替换为标签。</value>
|
||||
</data>
|
||||
<data name="Loc_IsEnabled" xml:space="preserve">
|
||||
<value>已启用</value>
|
||||
</data>
|
||||
<data name="Loc_CustomId" xml:space="preserve">
|
||||
<value>自定义ID</value>
|
||||
</data>
|
||||
<data name="Loc_GeneralCategory" xml:space="preserve">
|
||||
<value>通用属性</value>
|
||||
</data>
|
||||
<data name="Loc_IconCategory" xml:space="preserve">
|
||||
<value>图标属性</value>
|
||||
</data>
|
||||
<data name="Loc_TextCategory" xml:space="preserve">
|
||||
<value>文本属性</value>
|
||||
</data>
|
||||
<data name="Loc_PositionCategory" xml:space="preserve">
|
||||
<value>位置属性</value>
|
||||
</data>
|
||||
<data name="Loc_ActivityCategory" xml:space="preserve">
|
||||
<value>活动属性</value>
|
||||
</data>
|
||||
<data name="Loc_PlayerCategory" xml:space="preserve">
|
||||
<value>玩家属性</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleInPveDuties" xml:space="preserve">
|
||||
<value>在 PvE 任务中显示</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleInPveDuties_Description" xml:space="preserve">
|
||||
<value>标签是否应该在 PvE 任务中可见。</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleInPvpDuties" xml:space="preserve">
|
||||
<value>在 PvP 任务中显示</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleInPvpDuties_Description" xml:space="preserve">
|
||||
<value>标签是否应该在 PvP 任务中可见。</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleInOverworld" xml:space="preserve">
|
||||
<value>在别处显示</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleInOverworld_Description" xml:space="preserve">
|
||||
<value>标签是否应该在没有特定选项的其他情况下可见。</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleForSelf" xml:space="preserve">
|
||||
<value>为自己显示</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleForSelf_Description" xml:space="preserve">
|
||||
<value>标签是否对本地玩家可见。</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleForPartyPlayers" xml:space="preserve">
|
||||
<value>显示给组队成员</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleForPartyPlayers_Description" xml:space="preserve">
|
||||
<value>标签是否应该对组队成员可见。</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleForAlliancePlayers" xml:space="preserve">
|
||||
<value>显示给联盟成员</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleForAlliancePlayers_Description" xml:space="preserve">
|
||||
<value>标签是否对不在当前组队中的联盟成员可见。</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleForFriendPlayers" xml:space="preserve">
|
||||
<value>显示给朋友</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleForFriendPlayers_Description" xml:space="preserve">
|
||||
<value>标签是否应该对朋友可见。</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleForEnemyPlayers" xml:space="preserve">
|
||||
<value>显示给敌人</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleForEnemyPlayers_Description" xml:space="preserve">
|
||||
<value>标签是否应该对 PvP 中的敌人可见。</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleForOtherPlayers" xml:space="preserve">
|
||||
<value>显示给其他人</value>
|
||||
</data>
|
||||
<data name="Loc_IsVisibleForOtherPlayers_Description" xml:space="preserve">
|
||||
<value>在没有特定选项的其他情况下,标签是否应该对玩家可见。</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayersTabOrderedByProximity" xml:space="preserve">
|
||||
<value>按距离排序</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayersTabOrderedByProximity_Description" xml:space="preserve">
|
||||
<value>离您较近的玩家将被排序到顶部。</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayersTabSelfVisible" xml:space="preserve">
|
||||
<value>显示自己</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayersTabSelfVisible_Description" xml:space="preserve">
|
||||
<value>在玩家列表中显示您自己。</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayersTabFriendsVisible" xml:space="preserve">
|
||||
<value>显示朋友</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayersTabFriendsVisible_Description" xml:space="preserve">
|
||||
<value>在玩家列表中显示朋友。</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayersTabPartyVisible" xml:space="preserve">
|
||||
<value>显示组队成员</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayersTabPartyVisible_Description" xml:space="preserve">
|
||||
<value>在玩家列表中显示组队成员。</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayersTabAllianceVisible" xml:space="preserve">
|
||||
<value>显示联盟成员</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayersTabAllianceVisible_Description" xml:space="preserve">
|
||||
<value>在玩家列表中显示联盟成员。</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayersTabEnemiesVisible" xml:space="preserve">
|
||||
<value>显示敌人</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayersTabEnemiesVisible_Description" xml:space="preserve">
|
||||
<value>在玩家列表中显示敌人。</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayersTabOthersVisible" xml:space="preserve">
|
||||
<value>显示其他人</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayersTabOthersVisible_Description" xml:space="preserve">
|
||||
<value>在玩家列表中显示其他人。</value>
|
||||
</data>
|
||||
<data name="Loc_IsTextColorAppliedToChatName" xml:space="preserve">
|
||||
<value>对聊天名称应用颜色</value>
|
||||
</data>
|
||||
<data name="Loc_IsTextColorAppliedToChatName_Description" xml:space="preserve">
|
||||
<value>颜色是否将应用于聊天中的名称。</value>
|
||||
</data>
|
||||
<data name="Loc_IsTextColorAppliedToNameplateName" xml:space="preserve">
|
||||
<value>将颜色应用于铭牌名称</value>
|
||||
</data>
|
||||
<data name="Loc_IsTextColorAppliedToNameplateName_Description" xml:space="preserve">
|
||||
<value>颜色是否应用于铭牌中的名称。</value>
|
||||
</data>
|
||||
<data name="Loc_IsTextColorAppliedToNameplateTitle" xml:space="preserve">
|
||||
<value>将颜色应用于铭牌标题</value>
|
||||
</data>
|
||||
<data name="Loc_IsTextColorAppliedToNameplateTitle_Description" xml:space="preserve">
|
||||
<value>颜色是否应用于铭牌中的标题。</value>
|
||||
</data>
|
||||
<data name="Loc_IsTextColorAppliedToNameplateFreeCompany" xml:space="preserve">
|
||||
<value>将颜色应用于铭牌自由公司</value>
|
||||
</data>
|
||||
<data name="Loc_IsTextColorAppliedToNameplateFreeCompany_Description" xml:space="preserve">
|
||||
<value>颜色是否应用于铭牌中的自由公司。</value>
|
||||
</data>
|
||||
<data name="Loc_ActivityContextSelection_All" xml:space="preserve">
|
||||
<value>任何位置</value>
|
||||
</data>
|
||||
<data name="Loc_ActivityContextSelection_None" xml:space="preserve">
|
||||
<value>无任务</value>
|
||||
</data>
|
||||
<data name="Loc_ActivityContextSelection_PveDuty" xml:space="preserve">
|
||||
<value>PvE 任务</value>
|
||||
</data>
|
||||
<data name="Loc_ActivityContextSelection_PvpDuty" xml:space="preserve">
|
||||
<value>PvP 任务</value>
|
||||
</data>
|
||||
<data name="Loc_Static_CurrentActivityProfile" xml:space="preserve">
|
||||
<value>当前活动个人资料</value>
|
||||
</data>
|
||||
<data name="Loc_ActivityContextSelection" xml:space="preserve">
|
||||
<value>以下选项将被应用于</value>
|
||||
</data>
|
||||
<data name="Loc_ActivityContextSelection_All_Description" xml:space="preserve">
|
||||
<value>下面的大多数选项将适用于您所在的任何地方。 在主世界、PvE 任务和 PvP 任务中,它们将是相同的。 您专门为另一个上下文定义的选项将被覆盖。</value>
|
||||
</data>
|
||||
<data name="Loc_ActivityContextSelection_None_Description" xml:space="preserve">
|
||||
<value>以下大多数选项仅在您不在任何任务范围内时才适用。</value>
|
||||
</data>
|
||||
<data name="Loc_ActivityContextSelection_PveDuty_Description" xml:space="preserve">
|
||||
<value>以下大多数选项仅适用于 PvE 任务。</value>
|
||||
</data>
|
||||
<data name="Loc_ActivityContextSelection_PvpDuty_Description" xml:space="preserve">
|
||||
<value>以下大多数选项仅适用于 PvP 任务。</value>
|
||||
</data>
|
||||
<data name="Loc_Static_ChatExperimental" xml:space="preserve">
|
||||
<value>聊天(实验性)</value>
|
||||
</data>
|
||||
<data name="Loc_Static_OtherExperimental" xml:space="preserve">
|
||||
<value>其他(实验性)</value>
|
||||
</data>
|
||||
<data name="Loc_InsertBehindNumberPrefixInChat" xml:space="preserve">
|
||||
<value>在聊天中插入组编号前缀</value>
|
||||
</data>
|
||||
<data name="Loc_InsertBehindNumberPrefixInChat_Description" xml:space="preserve">
|
||||
<value>如果启用,标签和图标将插入聊天中组/联盟号码前缀的后面,而不是前面。 </value>
|
||||
</data>
|
||||
<data name="Loc_NameplateCategory" xml:space="preserve">
|
||||
<value>铭牌属性</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateFreeCompanyVisibility_Description" xml:space="preserve">
|
||||
<value>定义铭牌的免费公司元素何时可见或不可见。</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitlePosition_Description" xml:space="preserve">
|
||||
<value>定义铭牌标题元素的位置。它应该在名称上方还是下方? 你来决定!</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateTitleVisibility_Description" xml:space="preserve">
|
||||
<value>定义铭牌的标题元素何时可见或不可见。</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Chat" xml:space="preserve">
|
||||
<value>聊天</value>
|
||||
</data>
|
||||
<data name="Loc_IsRoleJobIconVisibleInNameplates" xml:space="preserve">
|
||||
<value>在铭牌上显示角色图标</value>
|
||||
</data>
|
||||
<data name="Loc_IsJobIconVisibleInNameplates" xml:space="preserve">
|
||||
<value>在铭牌上显示职业图标</value>
|
||||
</data>
|
||||
<data name="Loc_IsJobIconVisibleInNameplates_Description" xml:space="preserve">
|
||||
<value>职业图标是否显示在铭牌上。</value>
|
||||
</data>
|
||||
<data name="Loc_JobIconSet" xml:space="preserve">
|
||||
<value>职业图标集</value>
|
||||
</data>
|
||||
<data name="Loc_JobIconSet_Description" xml:space="preserve">
|
||||
<value>用于显示职业图标的图标集。您也可以选择角色图标集来代替显示角色图标。</value>
|
||||
</data>
|
||||
<data name="Loc_ChatFeatureCategory" xml:space="preserve">
|
||||
<value>高级聊天选项</value>
|
||||
</data>
|
||||
<data name="Loc_TargetChatTypes" xml:space="preserve">
|
||||
<value>目标聊天类型</value>
|
||||
</data>
|
||||
<data name="Loc_TargetChatTypes_Description" xml:space="preserve">
|
||||
<value>定义应为哪种聊天类型启用此标签的聊天功能。</value>
|
||||
</data>
|
||||
<data name="Loc_Static_StatusIconPrioList" xml:space="preserve">
|
||||
<value>状态图标优先级</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIconPriorizerConditionSets_InDuty" xml:space="preserve">
|
||||
<value>在任中</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIconPriorizerConditionSets_InDuty_Description" xml:space="preserve">
|
||||
<value>在任务中应优先考虑的状态图标。</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIconPriorizerConditionSets_InForay" xml:space="preserve">
|
||||
<value>突袭中</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIconPriorizerConditionSets_InForay_Description" xml:space="preserve">
|
||||
<value>在突袭中应优先考虑的状态图标。</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIconPriorizerConditionSets_Overworld" xml:space="preserve">
|
||||
<value>主世界</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIconPriorizerConditionSets_Overworld_Description" xml:space="preserve">
|
||||
<value>应该在主世界范围内优先考虑的状态图标。</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIconPriorizer_ResetToDefault" xml:space="preserve">
|
||||
<value>重置为默认</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIconPriorizer_ResetToDefault_Description" xml:space="preserve">
|
||||
<value>将所有条件集重置为默认设置</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIconPriorizer_ResetToEmpty" xml:space="preserve">
|
||||
<value>重置为空</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIconPriorizer_ResetToEmpty_Description" xml:space="preserve">
|
||||
<value>将所有条件集清除为空集合。 没有状态图标将被优先考虑。</value>
|
||||
</data>
|
||||
<data name="Loc_UsePriorizedIcons" xml:space="preserve">
|
||||
<value>使用优先图标</value>
|
||||
</data>
|
||||
<data name="Loc_UsePriorizedIcons_Description" xml:space="preserve">
|
||||
<value>如果您启用了职业图标,则选中此选项将强制一组状态图标优先于职业图标。
|
||||
禁用时,只有断开连接状态图标优先。</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_Busy" xml:space="preserve">
|
||||
<value>忙碌</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_Disconnecting" xml:space="preserve">
|
||||
<value>正在断开连接</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_DutyFinder" xml:space="preserve">
|
||||
<value>任务查找器</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_GroupPose" xml:space="preserve">
|
||||
<value>集体姿势</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_Idle" xml:space="preserve">
|
||||
<value>空闲</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_InDuty" xml:space="preserve">
|
||||
<value>在任中</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_Mentor" xml:space="preserve">
|
||||
<value>导师</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_MentorCrafting" xml:space="preserve">
|
||||
<value>导师制作</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_MentorPvE" xml:space="preserve">
|
||||
<value>PvE 导师</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_MentorPvP" xml:space="preserve">
|
||||
<value>PvP 导师</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_NewAdventurer" xml:space="preserve">
|
||||
<value>新冒险家</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_PartyLeader" xml:space="preserve">
|
||||
<value>队长</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_PartyMember" xml:space="preserve">
|
||||
<value>队员</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_Returner" xml:space="preserve">
|
||||
<value>归还者</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_RolePlaying" xml:space="preserve">
|
||||
<value>角色扮演</value>
|
||||
</data>
|
||||
<data name="Loc_StatusIcons_ViewingCutscene" xml:space="preserve">
|
||||
<value>观看过场动画</value>
|
||||
</data>
|
||||
<data name="Loc_DefaultPluginDataTemplate" xml:space="preserve">
|
||||
<value>模板</value>
|
||||
</data>
|
||||
<data name="Loc_DefaultPluginDataTemplate_Basic" xml:space="preserve">
|
||||
<value>基本</value>
|
||||
</data>
|
||||
<data name="Loc_DefaultPluginDataTemplate_Basic_Description" xml:space="preserve">
|
||||
<value>与空的相同,但包含一个非常基本的格式和着色预配置。
|
||||
如果您想进行自己的配置但需要基本格式,也可以使用。</value>
|
||||
</data>
|
||||
<data name="Loc_DefaultPluginDataTemplate_Description" xml:space="preserve">
|
||||
<value>您可以在此处为以下所有设置选择模板。
|
||||
该模板用作基本属性集。您所做的每项更改都会被保存。但不会保存此模板中的所有选项。
|
||||
这可以帮助您不需要覆盖那么多属性 - 或者通过在没有模板的情况下进行完全自己的配置。
|
||||
|
||||
警告:
|
||||
更改此项可能会导致属性被重置。您可能会丢失部分配置。
|
||||
更改此设置后,请确保一切都按照您喜欢的方式进行设置。</value>
|
||||
</data>
|
||||
<data name="Loc_DefaultPluginDataTemplate_Full" xml:space="preserve">
|
||||
<value>已满</value>
|
||||
</data>
|
||||
<data name="Loc_DefaultPluginDataTemplate_Full_Description" xml:space="preserve">
|
||||
<value>用颜色显示工作标签,并为玩家名称元素着色。</value>
|
||||
</data>
|
||||
<data name="Loc_DefaultPluginDataTemplate_None" xml:space="preserve">
|
||||
<value>空空如也</value>
|
||||
</data>
|
||||
<data name="Loc_DefaultPluginDataTemplate_None_Description" xml:space="preserve">
|
||||
<value>没有进行单一配置。 这是一个完全空的模板。
|
||||
如果您想控制每个选项或只想进行一些配置,请使用此选项。</value>
|
||||
</data>
|
||||
<data name="Loc_DefaultPluginDataTemplate_Simple" xml:space="preserve">
|
||||
<value>简易</value>
|
||||
</data>
|
||||
<data name="Loc_DefaultPluginDataTemplate_Simple_Description" xml:space="preserve">
|
||||
<value>通过替换标题显示带有颜色的职业标签和角色图标。</value>
|
||||
</data>
|
||||
<data name="Loc_DeadPlayerHandling_GrayOut" xml:space="preserve">
|
||||
<value>变灰</value>
|
||||
</data>
|
||||
<data name="Loc_DeadPlayerHandling_Ignore" xml:space="preserve">
|
||||
<value>忽略</value>
|
||||
</data>
|
||||
<data name="Loc_DeadPlayerHandling_Include" xml:space="preserve">
|
||||
<value>包含</value>
|
||||
</data>
|
||||
<data name="Loc_DeadPlayerHandling" xml:space="preserve">
|
||||
<value>处理死亡玩家</value>
|
||||
</data>
|
||||
<data name="Loc_DeadPlayerHandling_GrayOut_Description" xml:space="preserve">
|
||||
<value>应用任何标签,但将铭牌变灰。</value>
|
||||
</data>
|
||||
<data name="Loc_DeadPlayerHandling_Ignore_Description" xml:space="preserve">
|
||||
<value>不要处理死亡玩家,不要应用任何标签。</value>
|
||||
</data>
|
||||
<data name="Loc_DeadPlayerHandling_Include_Description" xml:space="preserve">
|
||||
<value>在他们还活着的时候处理死去的玩家。 死了和活着的玩家没有区别。</value>
|
||||
</data>
|
||||
<data name="Loc_MoveStatusIconToNameplateTextIfPossible" xml:space="preserve">
|
||||
<value>如果可以,将状态图标移动到铭牌文本</value>
|
||||
</data>
|
||||
<data name="Loc_MoveStatusIconToNameplateTextIfPossible_Description" xml:space="preserve">
|
||||
<value>如果当前状态图标可用作字体图标,则将其移动到铭牌中的玩家姓名文本,这样就有地方可以使用另一个图标,例如职业图标。</value>
|
||||
</data>
|
||||
<data name="Loc_IsRoleIconVisibleInChat" xml:space="preserve">
|
||||
<value>在聊天中显示角色图标</value>
|
||||
</data>
|
||||
<data name="Loc_TargetChatTypesIncludeUndefined" xml:space="preserve">
|
||||
<value>包含未定义的聊天类型</value>
|
||||
</data>
|
||||
<data name="Loc_TargetChatTypesIncludeUndefined_Description" xml:space="preserve">
|
||||
<value>启用后,标签将应用于所有未定义类型的聊天消息。
|
||||
如果游戏更新并且所有聊天类型的枚举由于值偏移而变得无效,或者插件出于任何原因创建自定义聊天类型,就会发生这种情况。</value>
|
||||
</data>
|
||||
<data name="Loc_Command_playertags_v2" xml:space="preserve">
|
||||
<value>显示玩家标签的配置窗口
|
||||
子命令:
|
||||
enableglobal on|of|toggle -> 设置一个全局主开关,在不更改当前配置的情况下启用或禁用所有插件功能。</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -4,15 +4,15 @@
|
||||
"net7.0-windows7.0": {
|
||||
"Dalamud.ContextMenu": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.2.3, )",
|
||||
"resolved": "1.2.3",
|
||||
"contentHash": "ydemplF7DNcA/LLeongDVzWUD/JV0Fw3EwA2+P0jYq3Le2ZYSt4U8qyJq4FyoChqt0lFG8BxYCAzfeWp4Jmnqw=="
|
||||
"requested": "[1.2.1, )",
|
||||
"resolved": "1.2.1",
|
||||
"contentHash": "RiBkn1OYRTnVbfUGYolLBE8MOeXjok+JiZaryb27oGa7YARCTu0XgUzkRiCglujknsHOn5kAaXsT3TUJmqMigg=="
|
||||
},
|
||||
"DalamudPackager": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.1.11, )",
|
||||
"resolved": "2.1.11",
|
||||
"contentHash": "9qlAWoRRTiL/geAvuwR/g6Bcbrd/bJJgVnB/RurBiyKs6srsP0bvpoo8IK+Eg8EA6jWeM6/YJWs66w4FIAzqPw=="
|
||||
"requested": "[2.1.10, )",
|
||||
"resolved": "2.1.10",
|
||||
"contentHash": "S6NrvvOnLgT4GDdgwuKVJjbFo+8ZEj+JsEYk9ojjOR/MMfv1dIFpT8aRJQfI24rtDcw1uF+GnSSMN4WW1yt7fw=="
|
||||
},
|
||||
"pilz.dalamud": {
|
||||
"type": "Project"
|
||||
|
||||
Reference in New Issue
Block a user