Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
038f71ceb2
|
|||
|
a1d5bb5be8
|
|||
| de382eca20 | |||
| 5b3beabac0 | |||
| 5820c8c00e | |||
| b55e3a2f14 | |||
| 098d77bcc2 | |||
| 292b6ea98a | |||
| 9901f98c5b | |||
| 385e43eeef | |||
| b14b39ef4d | |||
| 00bca4562c | |||
| e340c44e43 | |||
| 03833c5155 | |||
| 660b211dd9 | |||
| f66e81d6b6 | |||
| dc1d4581aa | |||
| a11f81ca48 | |||
| 2e76ece592 | |||
| a49e29a4f1 | |||
| 63ede74217 | |||
| 59d6be0ffd | |||
| f83cff5683 | |||
| b52174d3e3 | |||
| 1b23cb5da8 | |||
| 19db0cdf41 | |||
| b570c1c003 | |||
| ffa9f8497a | |||
| b356138732 | |||
| 361bd4ee21 | |||
| 5fe7afe7cf | |||
| 4fb5cc0b9d | |||
| 8f644ce913 | |||
| 2bce938cf3 | |||
| b40f0d5b87 | |||
| 681419e11b | |||
| 56f58e7cbd | |||
| 3ec790296e | |||
| 52f8723f84 | |||
| 0f729a846d | |||
| a6111e45d9 | |||
| aa99228e96 | |||
| 4db9f29747 | |||
| 86448e1490 | |||
| 27d900bee3 | |||
| 746c3adf9d | |||
| e1f80a3dd5 | |||
| e41b875653 | |||
| d1a3d51e18 | |||
| db13d432ab | |||
| 5072246f64 | |||
| 30794201f0 | |||
| cc1bdc7e08 | |||
| 1f1b08cd59 | |||
| 2dcf94eae2 | |||
| 618166aac7 | |||
| f885cd9ce3 | |||
| a8c9b4218b | |||
| e3af61546f | |||
| e8513c9988 | |||
| 3bc996e356 | |||
| a49b19831a | |||
| 9e655f3e0d |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,4 +1,3 @@
|
||||
[submodule "Pilz.Dalamud"]
|
||||
path = Pilz.Dalamud
|
||||
url = https://github.com/Pilzinsel64/Pilz.Dalamud.git
|
||||
branch = master
|
||||
url = https://git.pilzinsel64.de/Pilz.NET/Pilz.Dalamud.git
|
||||
|
||||
Submodule Pilz.Dalamud updated: 8e7d49ca01...62ce794e8b
@@ -26,6 +26,7 @@ Global
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
RESX_ShowErrorsInErrorList = False
|
||||
SolutionGuid = {B17E85B1-5F60-4440-9F9A-3DDE877E8CDF}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -1,74 +1,41 @@
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PlayerTags.Configuration.GameConfig
|
||||
namespace PlayerTags.Configuration.GameConfig;
|
||||
|
||||
public class GameConfigHelper
|
||||
{
|
||||
public class GameConfigHelper
|
||||
private static GameConfigHelper instance = null;
|
||||
private unsafe static ConfigModule* configModule = null;
|
||||
|
||||
public static GameConfigHelper Instance
|
||||
{
|
||||
private static GameConfigHelper instance = null;
|
||||
private unsafe static ConfigModule* configModule = null;
|
||||
|
||||
public static GameConfigHelper Instance
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
instance ??= new GameConfigHelper();
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
private GameConfigHelper()
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
configModule = ConfigModule.Instance();
|
||||
}
|
||||
}
|
||||
|
||||
private int? GetIntValue(ConfigOption option)
|
||||
{
|
||||
int? value = null;
|
||||
|
||||
unsafe
|
||||
{
|
||||
var index = configModule->GetIndex(option);
|
||||
if (index.HasValue)
|
||||
value = configModule->GetIntValue(index.Value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public LogNameType? GetLogNameType()
|
||||
{
|
||||
LogNameType? logNameType = null;
|
||||
int? value = GetIntValue(ConfigOption.LogNameType);
|
||||
|
||||
if (value.HasValue)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
logNameType = LogNameType.FullName;
|
||||
break;
|
||||
case 1:
|
||||
logNameType = LogNameType.LastNameShorted;
|
||||
break;
|
||||
case 2:
|
||||
logNameType = LogNameType.FirstNameShorted;
|
||||
break;
|
||||
case 3:
|
||||
logNameType = LogNameType.Initials;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return logNameType;
|
||||
instance ??= new GameConfigHelper();
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
private GameConfigHelper()
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
configModule = ConfigModule.Instance();
|
||||
}
|
||||
}
|
||||
|
||||
private uint? GetIntValue(ConfigOption option)
|
||||
{
|
||||
if (PluginServices.GameConfig.UiConfig.TryGetUInt(nameof(ConfigOption.LogNameType), out var value))
|
||||
return value;
|
||||
return null;
|
||||
}
|
||||
|
||||
public LogNameType? GetLogNameType()
|
||||
{
|
||||
uint? value = GetIntValue(ConfigOption.LogNameType);
|
||||
if (value != null)
|
||||
return (LogNameType)value;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace PlayerTags.Configuration.GameConfig;
|
||||
|
||||
namespace PlayerTags.Configuration.GameConfig
|
||||
public enum LogNameType : uint
|
||||
{
|
||||
public enum LogNameType
|
||||
{
|
||||
FullName,
|
||||
LastNameShorted,
|
||||
FirstNameShorted,
|
||||
Initials
|
||||
}
|
||||
FullName,
|
||||
LastNameShorted,
|
||||
FirstNameShorted,
|
||||
Initials
|
||||
}
|
||||
|
||||
@@ -2,351 +2,348 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Pilz.Dalamud.ActivityContexts;
|
||||
using Pilz.Dalamud.Nameplates.Tools;
|
||||
using Pilz.Dalamud.Tools.NamePlates;
|
||||
using PlayerTags.Data;
|
||||
using PlayerTags.Inheritables;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace PlayerTags.Configuration
|
||||
namespace PlayerTags.Configuration;
|
||||
|
||||
[Serializable]
|
||||
public class PluginConfiguration : IPluginConfiguration
|
||||
{
|
||||
[Serializable]
|
||||
public class PluginConfiguration : IPluginConfiguration
|
||||
private const int DEFAULT_CONFIG_VERSION = 1;
|
||||
|
||||
[JsonProperty]
|
||||
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()
|
||||
{
|
||||
private const int DEFAULT_CONFIG_VERSION = 1;
|
||||
{ ActivityType.None, new GeneralOptionsClass() },
|
||||
{ ActivityType.PveDuty, new GeneralOptionsClass() },
|
||||
{ ActivityType.PvpDuty, new GeneralOptionsClass() }
|
||||
};
|
||||
|
||||
[JsonProperty]
|
||||
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;
|
||||
public DefaultPluginDataTemplate DefaultPluginDataTemplate = DefaultPluginDataTemplate.None;
|
||||
public StatusIconPriorizerSettings StatusIconPriorizerSettings = new(true);
|
||||
public bool MoveStatusIconToNameplateTextIfPossible = true;
|
||||
public bool IsPlayerNameRandomlyGenerated = false;
|
||||
public bool IsCustomTagsContextMenuEnabled = true;
|
||||
public bool IsShowInheritedPropertiesEnabled = true;
|
||||
public bool IsPlayersTabOrderedByProximity = false;
|
||||
public bool IsPlayersTabSelfVisible = true;
|
||||
public bool IsPlayersTabFriendsVisible = true;
|
||||
public bool IsPlayersTabPartyVisible = true;
|
||||
public bool IsPlayersTabAllianceVisible = true;
|
||||
public bool IsPlayersTabEnemiesVisible = true;
|
||||
public bool IsPlayersTabOthersVisible = false;
|
||||
public bool IsGeneralOptionsAllTheSameEnabled = true;
|
||||
|
||||
[JsonProperty("GeneralOptionsV2")]
|
||||
public Dictionary<ActivityType, GeneralOptionsClass> GeneralOptions = new()
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<string, InheritableData> AllTagsChanges = [];
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<string, InheritableData> AllRoleTagsChanges = [];
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<Role, Dictionary<string, InheritableData>> RoleTagsChanges = [];
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<DpsRole, Dictionary<string, InheritableData>> DpsRoleTagsChanges = [];
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<RangedDpsRole, Dictionary<string, InheritableData>> RangedDpsRoleTagsChanges = [];
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<LandHandRole, Dictionary<string, InheritableData>> LandHandRoleTagsChanges = [];
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<string, Dictionary<string, InheritableData>> JobTagsChanges = [];
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<string, InheritableData> AllCustomTagsChanges = [];
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public List<Dictionary<string, InheritableData>> CustomTagsChanges = [];
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public List<Identity> Identities = [];
|
||||
|
||||
#region Obsulate Properties
|
||||
|
||||
[Obsolete]
|
||||
[JsonProperty("GeneralOptions")]
|
||||
private Dictionary<Data.ActivityContext, GeneralOptionsClass> GeneralOptionsV1
|
||||
{
|
||||
set
|
||||
{
|
||||
{ ActivityType.None, new GeneralOptionsClass() },
|
||||
{ ActivityType.PveDuty, new GeneralOptionsClass() },
|
||||
{ ActivityType.PvpDuty, new GeneralOptionsClass() }
|
||||
GeneralOptions.Clear();
|
||||
foreach (var kvp in value)
|
||||
GeneralOptions.Add((ActivityType)kvp.Key, kvp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("NameplateFreeCompanyVisibility"), Obsolete]
|
||||
private NameplateFreeCompanyVisibility NameplateFreeCompanyVisibilityV1
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var key in GeneralOptions.Keys)
|
||||
GeneralOptions[key].NameplateFreeCompanyVisibility = value;
|
||||
}
|
||||
}
|
||||
[JsonProperty("NameplateTitleVisibility"), Obsolete]
|
||||
public NameplateTitleVisibility NameplateTitleVisibilityV1
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var key in GeneralOptions.Keys)
|
||||
GeneralOptions[key].NameplateTitleVisibility = value;
|
||||
}
|
||||
}
|
||||
[JsonProperty("NameplateTitlePosition"), Obsolete]
|
||||
public NameplateTitlePosition NameplateTitlePositionV1
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var key in GeneralOptions.Keys)
|
||||
GeneralOptions[key].NameplateTitlePosition = value;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("IsApplyTagsToAllChatMessagesEnabled"), Obsolete]
|
||||
private bool IsApplyTagsToAllChatMessagesEnabledV1
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var key in GeneralOptions.Keys)
|
||||
GeneralOptions[key].IsApplyTagsToAllChatMessagesEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public event System.Action? Saved;
|
||||
|
||||
public void Save(PluginData pluginData)
|
||||
{
|
||||
AllTagsChanges = pluginData.AllTags.GetChanges(pluginData.Default.AllTags.GetChanges());
|
||||
AllRoleTagsChanges = pluginData.AllRoleTags.GetChanges(pluginData.Default.AllRoleTags.GetChanges());
|
||||
|
||||
RoleTagsChanges = [];
|
||||
foreach ((var role, var roleTag) in pluginData.RoleTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = [];
|
||||
if (pluginData.Default.RoleTags.TryGetValue(role, out var defaultTag))
|
||||
{
|
||||
defaultChanges = defaultTag.GetChanges();
|
||||
}
|
||||
|
||||
var changes = roleTag.GetChanges(defaultChanges);
|
||||
if (changes.Any())
|
||||
{
|
||||
RoleTagsChanges[role] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
DpsRoleTagsChanges = [];
|
||||
foreach ((var dpsRole, var dpsRoleTag) in pluginData.DpsRoleTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = [];
|
||||
if (pluginData.Default.DpsRoleTags.TryGetValue(dpsRole, out var defaultTag))
|
||||
{
|
||||
defaultChanges = defaultTag.GetChanges();
|
||||
}
|
||||
|
||||
var changes = dpsRoleTag.GetChanges(defaultChanges);
|
||||
if (changes.Any())
|
||||
{
|
||||
DpsRoleTagsChanges[dpsRole] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
RangedDpsRoleTagsChanges = [];
|
||||
foreach ((var rangedDpsRole, var rangedDpsRoleTag) in pluginData.RangedDpsRoleTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = [];
|
||||
if (pluginData.Default.RangedDpsRoleTags.TryGetValue(rangedDpsRole, out var defaultTag))
|
||||
{
|
||||
defaultChanges = defaultTag.GetChanges();
|
||||
}
|
||||
|
||||
var changes = rangedDpsRoleTag.GetChanges(defaultChanges);
|
||||
if (changes.Any())
|
||||
{
|
||||
RangedDpsRoleTagsChanges[rangedDpsRole] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
LandHandRoleTagsChanges = [];
|
||||
foreach ((var landHandRole, var landHandRoleTag) in pluginData.LandHandRoleTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = [];
|
||||
if (pluginData.Default.LandHandRoleTags.TryGetValue(landHandRole, out var defaultTag))
|
||||
{
|
||||
defaultChanges = defaultTag.GetChanges();
|
||||
}
|
||||
|
||||
var changes = landHandRoleTag.GetChanges(defaultChanges);
|
||||
if (changes.Any())
|
||||
{
|
||||
LandHandRoleTagsChanges[landHandRole] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
JobTagsChanges = [];
|
||||
foreach ((var jobAbbreviation, var jobTag) in pluginData.JobTags)
|
||||
{
|
||||
Dictionary<string, InheritableData>? defaultChanges = [];
|
||||
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 = [];
|
||||
foreach (var customTag in pluginData.CustomTags)
|
||||
{
|
||||
CustomTagsChanges.Add(customTag.GetChanges());
|
||||
}
|
||||
|
||||
Identities = pluginData.Identities;
|
||||
|
||||
SavePluginConfig();
|
||||
|
||||
Saved?.Invoke();
|
||||
}
|
||||
|
||||
private void SavePluginConfig()
|
||||
{
|
||||
Version = DEFAULT_CONFIG_VERSION;
|
||||
var configFilePath = GetConfigFilePath();
|
||||
var configFileContent = JsonConvert.SerializeObject(this, Formatting.Indented, GetJsonSettings());
|
||||
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();
|
||||
object config = null;
|
||||
|
||||
if (File.Exists(configFilePath))
|
||||
{
|
||||
var configFileContent = File.ReadAllText(configFilePath);
|
||||
config = JsonConvert.DeserializeObject<PluginConfiguration>(configFileContent, GetJsonSettings());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try loading the old settings, if possible
|
||||
configFilePath = PluginServices.DalamudPluginInterface.ConfigFile.FullName;
|
||||
config = PluginServices.DalamudPluginInterface.GetPluginConfig();
|
||||
}
|
||||
|
||||
if (config is PluginConfiguration pluginConfig)
|
||||
{
|
||||
if (PluginConfigFix(pluginConfig))
|
||||
{
|
||||
BackupPluginConfig();
|
||||
pluginConfig.SavePluginConfig();
|
||||
}
|
||||
}
|
||||
|
||||
return config as PluginConfiguration;
|
||||
}
|
||||
|
||||
private static string GetConfigFilePath()
|
||||
{
|
||||
return Path.Combine(PluginServices.DalamudPluginInterface.ConfigDirectory.FullName, "Config.json");
|
||||
}
|
||||
|
||||
private static JsonSerializerSettings GetJsonSettings()
|
||||
{
|
||||
var jsonSettings = new JsonSerializerSettings
|
||||
{
|
||||
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple,
|
||||
TypeNameHandling = TypeNameHandling.Auto,
|
||||
};
|
||||
|
||||
public DefaultPluginDataTemplate DefaultPluginDataTemplate = DefaultPluginDataTemplate.None;
|
||||
public StatusIconPriorizerSettings StatusIconPriorizerSettings = new(true);
|
||||
public bool MoveStatusIconToNameplateTextIfPossible = true;
|
||||
public bool IsPlayerNameRandomlyGenerated = false;
|
||||
public bool IsCustomTagsContextMenuEnabled = true;
|
||||
public bool IsShowInheritedPropertiesEnabled = true;
|
||||
public bool IsPlayersTabOrderedByProximity = false;
|
||||
public bool IsPlayersTabSelfVisible = true;
|
||||
public bool IsPlayersTabFriendsVisible = true;
|
||||
public bool IsPlayersTabPartyVisible = true;
|
||||
public bool IsPlayersTabAllianceVisible = true;
|
||||
public bool IsPlayersTabEnemiesVisible = true;
|
||||
public bool IsPlayersTabOthersVisible = false;
|
||||
public bool IsGeneralOptionsAllTheSameEnabled = true;
|
||||
jsonSettings.Converters.Add(new StringEnumConverter());
|
||||
|
||||
[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>();
|
||||
|
||||
#region Obsulate Properties
|
||||
|
||||
[Obsolete]
|
||||
[JsonProperty("GeneralOptions")]
|
||||
private Dictionary<Data.ActivityContext, GeneralOptionsClass> GeneralOptionsV1
|
||||
{
|
||||
set
|
||||
{
|
||||
GeneralOptions.Clear();
|
||||
foreach (var kvp in value)
|
||||
GeneralOptions.Add((ActivityType)kvp.Key, kvp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("NameplateFreeCompanyVisibility"), Obsolete]
|
||||
private NameplateFreeCompanyVisibility NameplateFreeCompanyVisibilityV1
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var key in GeneralOptions.Keys)
|
||||
GeneralOptions[key].NameplateFreeCompanyVisibility = value;
|
||||
}
|
||||
}
|
||||
[JsonProperty("NameplateTitleVisibility"), Obsolete]
|
||||
public NameplateTitleVisibility NameplateTitleVisibilityV1
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var key in GeneralOptions.Keys)
|
||||
GeneralOptions[key].NameplateTitleVisibility = value;
|
||||
}
|
||||
}
|
||||
[JsonProperty("NameplateTitlePosition"), Obsolete]
|
||||
public NameplateTitlePosition NameplateTitlePositionV1
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var key in GeneralOptions.Keys)
|
||||
GeneralOptions[key].NameplateTitlePosition = value;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("IsApplyTagsToAllChatMessagesEnabled"), Obsolete]
|
||||
private bool IsApplyTagsToAllChatMessagesEnabledV1
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var key in GeneralOptions.Keys)
|
||||
GeneralOptions[key].IsApplyTagsToAllChatMessagesEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public event System.Action? Saved;
|
||||
|
||||
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;
|
||||
|
||||
SavePluginConfig();
|
||||
|
||||
Saved?.Invoke();
|
||||
}
|
||||
|
||||
private void SavePluginConfig()
|
||||
{
|
||||
Version = DEFAULT_CONFIG_VERSION;
|
||||
var configFilePath = GetConfigFilePath();
|
||||
var configFileContent = JsonConvert.SerializeObject(this, Formatting.Indented, GetJsonSettings());
|
||||
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();
|
||||
object config = null;
|
||||
|
||||
if (File.Exists(configFilePath))
|
||||
{
|
||||
var configFileContent = File.ReadAllText(configFilePath);
|
||||
config = JsonConvert.DeserializeObject<PluginConfiguration>(configFileContent, GetJsonSettings());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try loading the old settings, if possible
|
||||
configFilePath = PluginServices.DalamudPluginInterface.ConfigFile.FullName;
|
||||
config = PluginServices.DalamudPluginInterface.GetPluginConfig();
|
||||
}
|
||||
|
||||
if (config is PluginConfiguration pluginConfig)
|
||||
{
|
||||
if (PluginConfigFix(pluginConfig))
|
||||
{
|
||||
BackupPluginConfig();
|
||||
pluginConfig.SavePluginConfig();
|
||||
}
|
||||
}
|
||||
|
||||
return config as PluginConfiguration;
|
||||
}
|
||||
|
||||
private static string GetConfigFilePath()
|
||||
{
|
||||
return Path.Combine(PluginServices.DalamudPluginInterface.ConfigDirectory.FullName, "Config.json");
|
||||
}
|
||||
|
||||
private static JsonSerializerSettings GetJsonSettings()
|
||||
{
|
||||
var jsonSettings = new JsonSerializerSettings
|
||||
{
|
||||
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple,
|
||||
TypeNameHandling = TypeNameHandling.Auto,
|
||||
};
|
||||
|
||||
jsonSettings.Converters.Add(new StringEnumConverter());
|
||||
|
||||
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;
|
||||
}
|
||||
return jsonSettings;
|
||||
}
|
||||
|
||||
public class GeneralOptionsClass
|
||||
private static bool PluginConfigFix(PluginConfiguration config)
|
||||
{
|
||||
public NameplateFreeCompanyVisibility NameplateFreeCompanyVisibility = NameplateFreeCompanyVisibility.Default;
|
||||
public NameplateTitleVisibility NameplateTitleVisibility = NameplateTitleVisibility.WhenHasTags;
|
||||
public NameplateTitlePosition NameplateTitlePosition = NameplateTitlePosition.AlwaysAboveName;
|
||||
public DeadPlayerHandling NameplateDeadPlayerHandling = DeadPlayerHandling.Include;
|
||||
public bool IsApplyTagsToAllChatMessagesEnabled = true;
|
||||
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;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,14 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
[Obsolete]
|
||||
[Flags]
|
||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||
public enum ActivityContext
|
||||
{
|
||||
[Obsolete]
|
||||
[Flags]
|
||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||
public enum ActivityContext
|
||||
{
|
||||
None = 0x0,
|
||||
PveDuty = 0x1,
|
||||
PvpDuty = 0x2,
|
||||
}
|
||||
None = 0x0,
|
||||
PveDuty = 0x1,
|
||||
PvpDuty = 0x2,
|
||||
}
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
using Pilz.Dalamud.ActivityContexts;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public static class ActivityContextHelper
|
||||
{
|
||||
public static class ActivityContextHelper
|
||||
public static bool GetIsVisible(ActivityType playerContext, bool desiredPveDutyVisibility, bool desiredPvpDutyVisibility, bool desiredOthersVisibility)
|
||||
{
|
||||
public static bool GetIsVisible(ActivityType playerContext, bool desiredPveDutyVisibility, bool desiredPvpDutyVisibility, bool desiredOthersVisibility)
|
||||
{
|
||||
bool isVisible = false;
|
||||
bool isVisible = false;
|
||||
|
||||
if (playerContext.HasFlag(ActivityType.PveDuty))
|
||||
isVisible |= desiredPveDutyVisibility;
|
||||
if (playerContext.HasFlag(ActivityType.PveDuty))
|
||||
isVisible |= desiredPveDutyVisibility;
|
||||
|
||||
if (playerContext.HasFlag(ActivityType.PvpDuty))
|
||||
isVisible |= desiredPvpDutyVisibility;
|
||||
if (playerContext.HasFlag(ActivityType.PvpDuty))
|
||||
isVisible |= desiredPvpDutyVisibility;
|
||||
|
||||
if (playerContext == ActivityType.None)
|
||||
isVisible |= desiredOthersVisibility;
|
||||
if (playerContext == ActivityType.None)
|
||||
isVisible |= desiredOthersVisibility;
|
||||
|
||||
return isVisible;
|
||||
}
|
||||
return isVisible;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
public enum DeadPlayerHandling
|
||||
{
|
||||
public enum DeadPlayerHandling
|
||||
{
|
||||
Ignore,
|
||||
Include,
|
||||
GrayOut
|
||||
}
|
||||
Ignore,
|
||||
Include,
|
||||
GrayOut
|
||||
}
|
||||
|
||||
@@ -1,491 +1,492 @@
|
||||
using Dalamud.Game.Text;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Pilz.Dalamud;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public class DefaultPluginData
|
||||
{
|
||||
public class DefaultPluginData
|
||||
public Tag AllTags { get; private set; }
|
||||
|
||||
public Tag AllRoleTags { get; private set; }
|
||||
public Dictionary<Role, Tag> RoleTags { get; private set; }
|
||||
public Dictionary<DpsRole, Tag> DpsRoleTags { get; private set; }
|
||||
public Dictionary<RangedDpsRole, Tag> RangedDpsRoleTags { get; private set; }
|
||||
public Dictionary<LandHandRole, Tag> LandHandRoleTags { get; private set; }
|
||||
public Dictionary<string, Tag> JobTags { get; private set; }
|
||||
|
||||
public Tag AllCustomTags { get; private set; }
|
||||
|
||||
public DefaultPluginData(DefaultPluginDataTemplate template)
|
||||
{
|
||||
public Tag AllTags { get; private set; }
|
||||
SetupTemplate(template);
|
||||
}
|
||||
|
||||
public Tag AllRoleTags { get; private set; }
|
||||
public Dictionary<Role, Tag> RoleTags { get; private set; }
|
||||
public Dictionary<DpsRole, Tag> DpsRoleTags { get; private set; }
|
||||
public Dictionary<RangedDpsRole, Tag> RangedDpsRoleTags { get; private set; }
|
||||
public Dictionary<LandHandRole, Tag> LandHandRoleTags { get; private set; }
|
||||
public Dictionary<string, Tag> JobTags { get; private set; }
|
||||
private void SetupTemplate(DefaultPluginDataTemplate template)
|
||||
{
|
||||
Clear();
|
||||
|
||||
public Tag AllCustomTags { get; private set; }
|
||||
|
||||
public DefaultPluginData(DefaultPluginDataTemplate template)
|
||||
switch (template)
|
||||
{
|
||||
SetupTemplate(template);
|
||||
case DefaultPluginDataTemplate.None:
|
||||
SetupTemplateNone();
|
||||
break;
|
||||
case DefaultPluginDataTemplate.Basic:
|
||||
SetupTemplateBasic();
|
||||
break;
|
||||
case DefaultPluginDataTemplate.Simple:
|
||||
SetupTemplateSimple();
|
||||
break;
|
||||
case DefaultPluginDataTemplate.Full:
|
||||
SetupTemplateFull();
|
||||
break;
|
||||
}
|
||||
|
||||
private void SetupTemplate(DefaultPluginDataTemplate template)
|
||||
SetupJobTags();
|
||||
}
|
||||
|
||||
private void Clear()
|
||||
{
|
||||
RoleTags = [];
|
||||
DpsRoleTags = [];
|
||||
RangedDpsRoleTags = [];
|
||||
LandHandRoleTags = [];
|
||||
}
|
||||
|
||||
private void SetupTemplateNone()
|
||||
{
|
||||
AllTags = new Tag()
|
||||
{
|
||||
Clear();
|
||||
IsSelected = true,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
switch(template)
|
||||
{
|
||||
case DefaultPluginDataTemplate.None:
|
||||
SetupTemplateNone();
|
||||
break;
|
||||
case DefaultPluginDataTemplate.Basic:
|
||||
SetupTemplateBasic();
|
||||
break;
|
||||
case DefaultPluginDataTemplate.Simple:
|
||||
SetupTemplateSimple();
|
||||
break;
|
||||
case DefaultPluginDataTemplate.Full:
|
||||
SetupTemplateFull();
|
||||
break;
|
||||
}
|
||||
|
||||
SetupJobTags();
|
||||
}
|
||||
|
||||
private void Clear()
|
||||
AllRoleTags = new Tag()
|
||||
{
|
||||
RoleTags = new Dictionary<Role, Tag>();
|
||||
DpsRoleTags = new Dictionary<DpsRole, Tag>();
|
||||
RangedDpsRoleTags = new Dictionary<RangedDpsRole, Tag>();
|
||||
LandHandRoleTags = new Dictionary<LandHandRole, Tag>();
|
||||
}
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
private void SetupTemplateNone()
|
||||
RoleTags[Role.LandHand] = new Tag()
|
||||
{
|
||||
AllTags = new Tag()
|
||||
{
|
||||
IsSelected = true,
|
||||
IsExpanded = true,
|
||||
};
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
AllRoleTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
RoleTags[Role.LandHand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
RoleTags[Role.Tank] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
RoleTags[Role.Healer] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
RoleTags[Role.Dps] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
DpsRoleTags[DpsRole.Melee] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
DpsRoleTags[DpsRole.Ranged] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Magical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Physical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Land] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Hand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
AllCustomTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
}
|
||||
|
||||
private void SetupTemplateBasic()
|
||||
RoleTags[Role.Tank] = new Tag()
|
||||
{
|
||||
AllTags = new Tag()
|
||||
{
|
||||
IsSelected = true,
|
||||
IsExpanded = true,
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
TagPositionInChat = TagPosition.Before,
|
||||
InsertBehindNumberPrefixInChat = true,
|
||||
TagPositionInNameplates = TagPosition.Replace,
|
||||
TagTargetInNameplates = NameplateElement.Title,
|
||||
|
||||
TargetChatTypes = new List<XivChatType>(Enum.GetValues<XivChatType>()),
|
||||
TargetChatTypesIncludeUndefined = true,
|
||||
};
|
||||
|
||||
AllRoleTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
RoleTags[Role.LandHand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false
|
||||
};
|
||||
|
||||
RoleTags[Role.Tank] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Tank,
|
||||
TextColor = 546,
|
||||
};
|
||||
|
||||
RoleTags[Role.Healer] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Healer,
|
||||
TextColor = 43,
|
||||
};
|
||||
|
||||
RoleTags[Role.Dps] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
Icon = BitmapFontIcon.DPS,
|
||||
TextColor = 508,
|
||||
};
|
||||
|
||||
DpsRoleTags[DpsRole.Melee] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
DpsRoleTags[DpsRole.Ranged] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Magical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Physical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Land] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Hand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
AllCustomTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
IsTextVisibleInChat = true,
|
||||
IsTextVisibleInNameplates = true,
|
||||
};
|
||||
}
|
||||
|
||||
private void SetupTemplateSimple()
|
||||
RoleTags[Role.Healer] = new Tag()
|
||||
{
|
||||
AllTags = new Tag()
|
||||
{
|
||||
IsSelected = true,
|
||||
IsExpanded = true,
|
||||
TagPositionInChat = TagPosition.Before,
|
||||
InsertBehindNumberPrefixInChat = true,
|
||||
TagPositionInNameplates = TagPosition.Replace,
|
||||
TagTargetInNameplates = NameplateElement.Title,
|
||||
IsTextItalic = true,
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
IsVisibleInOverworld = true,
|
||||
IsVisibleInPveDuties = true,
|
||||
IsVisibleInPvpDuties = true,
|
||||
|
||||
IsVisibleForSelf = true,
|
||||
IsVisibleForFriendPlayers = true,
|
||||
IsVisibleForPartyPlayers = true,
|
||||
IsVisibleForAlliancePlayers = true,
|
||||
IsVisibleForEnemyPlayers = true,
|
||||
IsVisibleForOtherPlayers = true,
|
||||
|
||||
TargetChatTypes = new List<XivChatType>(Enum.GetValues<XivChatType>()),
|
||||
TargetChatTypesIncludeUndefined = true,
|
||||
};
|
||||
|
||||
AllRoleTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
IsRoleIconVisibleInChat = true,
|
||||
IsTextVisibleInChat = true,
|
||||
IsRoleIconVisibleInNameplates = true,
|
||||
IsTextVisibleInNameplates = true,
|
||||
IsTextColorAppliedToChatName = true,
|
||||
};
|
||||
|
||||
RoleTags[Role.LandHand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Crafter,
|
||||
TextColor = 3,
|
||||
};
|
||||
|
||||
RoleTags[Role.Tank] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Tank,
|
||||
TextColor = 546,
|
||||
};
|
||||
|
||||
RoleTags[Role.Healer] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Healer,
|
||||
TextColor = 43,
|
||||
};
|
||||
|
||||
RoleTags[Role.Dps] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
Icon = BitmapFontIcon.DPS,
|
||||
TextColor = 508,
|
||||
};
|
||||
|
||||
DpsRoleTags[DpsRole.Melee] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
DpsRoleTags[DpsRole.Ranged] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Magical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Physical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Land] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Hand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
AllCustomTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
IsTextVisibleInChat = true,
|
||||
IsTextVisibleInNameplates = true,
|
||||
};
|
||||
}
|
||||
|
||||
private void SetupTemplateFull()
|
||||
RoleTags[Role.Dps] = new Tag()
|
||||
{
|
||||
AllTags = new Tag()
|
||||
{
|
||||
IsSelected = true,
|
||||
IsExpanded = true,
|
||||
TagPositionInChat = TagPosition.Before,
|
||||
InsertBehindNumberPrefixInChat = true,
|
||||
TagPositionInNameplates = TagPosition.Replace,
|
||||
TagTargetInNameplates = NameplateElement.Title,
|
||||
IsTextItalic = true,
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
IsVisibleInOverworld = true,
|
||||
IsVisibleInPveDuties = true,
|
||||
IsVisibleInPvpDuties = true,
|
||||
|
||||
IsVisibleForSelf = true,
|
||||
IsVisibleForFriendPlayers = true,
|
||||
IsVisibleForPartyPlayers = true,
|
||||
IsVisibleForAlliancePlayers = true,
|
||||
IsVisibleForEnemyPlayers = true,
|
||||
IsVisibleForOtherPlayers = true,
|
||||
|
||||
TargetChatTypes = new List<XivChatType>(Enum.GetValues<XivChatType>()),
|
||||
TargetChatTypesIncludeUndefined = true,
|
||||
};
|
||||
|
||||
AllRoleTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
IsRoleIconVisibleInChat = true,
|
||||
IsTextVisibleInChat = true,
|
||||
IsRoleIconVisibleInNameplates = true,
|
||||
IsTextVisibleInNameplates = true,
|
||||
IsTextColorAppliedToNameplateName = true,
|
||||
IsTextColorAppliedToChatName = true,
|
||||
IsJobIconVisibleInNameplates = true,
|
||||
};
|
||||
|
||||
RoleTags[Role.LandHand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Crafter,
|
||||
TextColor = 3,
|
||||
};
|
||||
|
||||
RoleTags[Role.Tank] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Tank,
|
||||
TextColor = 546,
|
||||
};
|
||||
|
||||
RoleTags[Role.Healer] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Healer,
|
||||
TextColor = 43,
|
||||
};
|
||||
|
||||
RoleTags[Role.Dps] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
Icon = BitmapFontIcon.DPS,
|
||||
TextColor = 508,
|
||||
};
|
||||
|
||||
DpsRoleTags[DpsRole.Melee] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
DpsRoleTags[DpsRole.Ranged] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Magical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Physical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Land] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Hand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
AllCustomTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
IsTextVisibleInChat = true,
|
||||
IsTextVisibleInNameplates = true,
|
||||
};
|
||||
}
|
||||
|
||||
private void SetupJobTags()
|
||||
DpsRoleTags[DpsRole.Melee] = new Tag()
|
||||
{
|
||||
JobTags = new Dictionary<string, Tag>();
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
var classJobs = PluginServices.DataManager.GetExcelSheet<ClassJob>();
|
||||
if (classJobs != null)
|
||||
DpsRoleTags[DpsRole.Ranged] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Magical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Physical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Land] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Hand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
AllCustomTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
}
|
||||
|
||||
private void SetupTemplateBasic()
|
||||
{
|
||||
AllTags = new Tag()
|
||||
{
|
||||
IsSelected = true,
|
||||
IsExpanded = true,
|
||||
|
||||
TagPositionInChat = TagPosition.Before,
|
||||
InsertBehindNumberPrefixInChat = true,
|
||||
TagPositionInNameplates = TagPosition.Replace,
|
||||
TagTargetInNameplates = NameplateElement.Title,
|
||||
|
||||
TargetChatTypes = new List<XivChatType>(Enum.GetValues<XivChatType>()),
|
||||
TargetChatTypesIncludeUndefined = true,
|
||||
};
|
||||
|
||||
AllRoleTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
RoleTags[Role.LandHand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false
|
||||
};
|
||||
|
||||
RoleTags[Role.Tank] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Tank,
|
||||
TextColor = 546,
|
||||
};
|
||||
|
||||
RoleTags[Role.Healer] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Healer,
|
||||
TextColor = 43,
|
||||
};
|
||||
|
||||
RoleTags[Role.Dps] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
Icon = BitmapFontIcon.DPS,
|
||||
TextColor = 508,
|
||||
};
|
||||
|
||||
DpsRoleTags[DpsRole.Melee] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
DpsRoleTags[DpsRole.Ranged] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Magical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Physical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Land] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Hand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
AllCustomTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
IsTextVisibleInChat = true,
|
||||
IsTextVisibleInNameplates = true,
|
||||
};
|
||||
}
|
||||
|
||||
private void SetupTemplateSimple()
|
||||
{
|
||||
AllTags = new Tag()
|
||||
{
|
||||
IsSelected = true,
|
||||
IsExpanded = true,
|
||||
TagPositionInChat = TagPosition.Before,
|
||||
InsertBehindNumberPrefixInChat = true,
|
||||
TagPositionInNameplates = TagPosition.Replace,
|
||||
TagTargetInNameplates = NameplateElement.Title,
|
||||
IsTextItalic = true,
|
||||
|
||||
IsVisibleInOverworld = true,
|
||||
IsVisibleInPveDuties = true,
|
||||
IsVisibleInPvpDuties = true,
|
||||
|
||||
IsVisibleForSelf = true,
|
||||
IsVisibleForFriendPlayers = true,
|
||||
IsVisibleForPartyPlayers = true,
|
||||
IsVisibleForAlliancePlayers = true,
|
||||
IsVisibleForEnemyPlayers = true,
|
||||
IsVisibleForOtherPlayers = true,
|
||||
|
||||
TargetChatTypes = new List<XivChatType>(Enum.GetValues<XivChatType>()),
|
||||
TargetChatTypesIncludeUndefined = true,
|
||||
};
|
||||
|
||||
AllRoleTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
IsRoleIconVisibleInChat = true,
|
||||
IsTextVisibleInChat = true,
|
||||
IsRoleIconVisibleInNameplates = true,
|
||||
IsTextVisibleInNameplates = true,
|
||||
IsTextColorAppliedToChatName = true,
|
||||
};
|
||||
|
||||
RoleTags[Role.LandHand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Crafter,
|
||||
TextColor = 3,
|
||||
};
|
||||
|
||||
RoleTags[Role.Tank] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Tank,
|
||||
TextColor = 546,
|
||||
};
|
||||
|
||||
RoleTags[Role.Healer] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Healer,
|
||||
TextColor = 43,
|
||||
};
|
||||
|
||||
RoleTags[Role.Dps] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
Icon = BitmapFontIcon.DPS,
|
||||
TextColor = 508,
|
||||
};
|
||||
|
||||
DpsRoleTags[DpsRole.Melee] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
DpsRoleTags[DpsRole.Ranged] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Magical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Physical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Land] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Hand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
AllCustomTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
IsTextVisibleInChat = true,
|
||||
IsTextVisibleInNameplates = true,
|
||||
};
|
||||
}
|
||||
|
||||
private void SetupTemplateFull()
|
||||
{
|
||||
AllTags = new Tag()
|
||||
{
|
||||
IsSelected = true,
|
||||
IsExpanded = true,
|
||||
TagPositionInChat = TagPosition.Before,
|
||||
InsertBehindNumberPrefixInChat = true,
|
||||
TagPositionInNameplates = TagPosition.Replace,
|
||||
TagTargetInNameplates = NameplateElement.Title,
|
||||
IsTextItalic = true,
|
||||
|
||||
IsVisibleInOverworld = true,
|
||||
IsVisibleInPveDuties = true,
|
||||
IsVisibleInPvpDuties = true,
|
||||
|
||||
IsVisibleForSelf = true,
|
||||
IsVisibleForFriendPlayers = true,
|
||||
IsVisibleForPartyPlayers = true,
|
||||
IsVisibleForAlliancePlayers = true,
|
||||
IsVisibleForEnemyPlayers = true,
|
||||
IsVisibleForOtherPlayers = true,
|
||||
|
||||
TargetChatTypes = new List<XivChatType>(Enum.GetValues<XivChatType>()),
|
||||
TargetChatTypesIncludeUndefined = true,
|
||||
};
|
||||
|
||||
AllRoleTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
IsRoleIconVisibleInChat = true,
|
||||
IsTextVisibleInChat = true,
|
||||
IsRoleIconVisibleInNameplates = true,
|
||||
IsTextVisibleInNameplates = true,
|
||||
IsTextColorAppliedToNameplateName = true,
|
||||
IsTextColorAppliedToChatName = true,
|
||||
IsJobIconVisibleInNameplates = true,
|
||||
};
|
||||
|
||||
RoleTags[Role.LandHand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Crafter,
|
||||
TextColor = 3,
|
||||
};
|
||||
|
||||
RoleTags[Role.Tank] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Tank,
|
||||
TextColor = 546,
|
||||
};
|
||||
|
||||
RoleTags[Role.Healer] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Icon = BitmapFontIcon.Healer,
|
||||
TextColor = 43,
|
||||
};
|
||||
|
||||
RoleTags[Role.Dps] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
Icon = BitmapFontIcon.DPS,
|
||||
TextColor = 508,
|
||||
};
|
||||
|
||||
DpsRoleTags[DpsRole.Melee] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
DpsRoleTags[DpsRole.Ranged] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Magical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
RangedDpsRoleTags[RangedDpsRole.Physical] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Land] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
LandHandRoleTags[LandHandRole.Hand] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
AllCustomTags = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = true,
|
||||
IsTextVisibleInChat = true,
|
||||
IsTextVisibleInNameplates = true,
|
||||
};
|
||||
}
|
||||
|
||||
private void SetupJobTags()
|
||||
{
|
||||
JobTags = [];
|
||||
|
||||
var classJobs = PluginServices.DataManager.GetExcelSheet<ClassJob>();
|
||||
if (classJobs != null)
|
||||
{
|
||||
foreach ((var role, var roleTagChanges) in RoleTags)
|
||||
{
|
||||
foreach ((var role, var roleTagChanges) in RoleTags)
|
||||
foreach (var classJob in classJobs.Where(classJob => RoleHelper.RolesByRoleId[classJob.Role] == role && !string.IsNullOrEmpty(classJob.Abbreviation.ParseString())))
|
||||
{
|
||||
foreach (var classJob in classJobs.Where(classJob => RoleHelper.RolesByRoleId[classJob.Role] == role && !string.IsNullOrEmpty(classJob.Abbreviation.RawString)))
|
||||
var abbrv = classJob.Abbreviation.ParseString();
|
||||
if (!JobTags.ContainsKey(abbrv))
|
||||
{
|
||||
if (!JobTags.ContainsKey(classJob.Abbreviation.RawString))
|
||||
JobTags[abbrv] = new Tag()
|
||||
{
|
||||
JobTags[classJob.Abbreviation.RawString] = new Tag()
|
||||
{
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Text = classJob.Abbreviation.RawString,
|
||||
};
|
||||
}
|
||||
IsSelected = false,
|
||||
IsExpanded = false,
|
||||
Text = abbrv,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
public enum DefaultPluginDataTemplate
|
||||
{
|
||||
public enum DefaultPluginDataTemplate
|
||||
{
|
||||
None,
|
||||
Basic,
|
||||
Simple,
|
||||
Full
|
||||
}
|
||||
None,
|
||||
Basic,
|
||||
Simple,
|
||||
Full
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public enum DpsRole
|
||||
{
|
||||
public enum DpsRole
|
||||
{
|
||||
Melee,
|
||||
Ranged
|
||||
}
|
||||
Melee,
|
||||
Ranged
|
||||
}
|
||||
|
||||
@@ -2,100 +2,99 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public class Identity : IComparable<Identity>, IEquatable<Identity>
|
||||
{
|
||||
public class Identity : IComparable<Identity>, IEquatable<Identity>
|
||||
public string Name { get; init; }
|
||||
public uint? WorldId { get; set; } = null;
|
||||
public List<Guid> CustomTagIds { get; init; } = [];
|
||||
|
||||
[JsonIgnore]
|
||||
public string? WorldName => WorldHelper.GetWorldName(WorldId);
|
||||
|
||||
public Identity(string name)
|
||||
{
|
||||
public string Name { get; init; }
|
||||
public uint? WorldId { get; set; } = null;
|
||||
public List<Guid> CustomTagIds { get; init; } = new List<Guid>();
|
||||
Name = name;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string? WorldName => WorldHelper.GetWorldName(WorldId);
|
||||
public override string ToString()
|
||||
{
|
||||
string str = Name;
|
||||
|
||||
public Identity(string name)
|
||||
if (WorldId != null)
|
||||
{
|
||||
Name = name;
|
||||
str += $"@{WorldName}";
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
return str;
|
||||
}
|
||||
|
||||
public int CompareTo(Identity? other)
|
||||
{
|
||||
string? otherToString = null;
|
||||
if (!(other is null))
|
||||
{
|
||||
string str = Name;
|
||||
|
||||
if (WorldId != null)
|
||||
{
|
||||
str += $"@{WorldName}";
|
||||
}
|
||||
|
||||
return str;
|
||||
otherToString = other.ToString();
|
||||
}
|
||||
|
||||
public int CompareTo(Identity? other)
|
||||
{
|
||||
string? otherToString = null;
|
||||
if (!(other is null))
|
||||
{
|
||||
otherToString = other.ToString();
|
||||
}
|
||||
return ToString().CompareTo(otherToString);
|
||||
}
|
||||
|
||||
return ToString().CompareTo(otherToString);
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Identity identity && Equals(identity);
|
||||
}
|
||||
|
||||
public bool Equals(Identity? obj)
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
return this == obj;
|
||||
}
|
||||
|
||||
public static bool operator ==(Identity? first, Identity? second)
|
||||
{
|
||||
if (ReferenceEquals(first, second))
|
||||
{
|
||||
return obj is Identity identity && Equals(identity);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Equals(Identity? obj)
|
||||
if (first is null && second is null)
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return this == obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool operator ==(Identity? first, Identity? second)
|
||||
if (first is null || second is null)
|
||||
{
|
||||
if (ReferenceEquals(first, second))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (first is null && second is null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (first is null || second is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool areNamesEqual = first.Name.ToLower().Trim() == second.Name.ToLower().Trim();
|
||||
|
||||
// If one of the worlds are null then it's technically equal as it could be promoted to the identity that does have a world
|
||||
bool areWorldsEqual = first.WorldId == null || second.WorldId == null || first.WorldId == second.WorldId;
|
||||
|
||||
return areNamesEqual && areWorldsEqual;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool operator !=(Identity? first, Identity? second)
|
||||
bool areNamesEqual = first.Name.ToLower().Trim() == second.Name.ToLower().Trim();
|
||||
|
||||
// If one of the worlds are null then it's technically equal as it could be promoted to the identity that does have a world
|
||||
bool areWorldsEqual = first.WorldId == null || second.WorldId == null || first.WorldId == second.WorldId;
|
||||
|
||||
return areNamesEqual && areWorldsEqual;
|
||||
}
|
||||
|
||||
public static bool operator !=(Identity? first, Identity? second)
|
||||
{
|
||||
return !(first == second);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hashCode = Name.GetHashCode();
|
||||
|
||||
if (WorldName != null)
|
||||
{
|
||||
return !(first == second);
|
||||
hashCode *= 17 ^ WorldName.GetHashCode();
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hashCode = Name.GetHashCode();
|
||||
|
||||
if (WorldName != null)
|
||||
{
|
||||
hashCode *= 17 ^ WorldName.GetHashCode();
|
||||
}
|
||||
|
||||
return hashCode;
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
{
|
||||
public class InheritableCategoryAttribute : Attribute
|
||||
{
|
||||
public string CategoryId { get; private set; }
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public InheritableCategoryAttribute(string categoryId)
|
||||
{
|
||||
CategoryId = categoryId;
|
||||
}
|
||||
public class InheritableCategoryAttribute : Attribute
|
||||
{
|
||||
public string CategoryId { get; private set; }
|
||||
|
||||
public InheritableCategoryAttribute(string categoryId)
|
||||
{
|
||||
CategoryId = categoryId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public enum LandHandRole
|
||||
{
|
||||
public enum LandHandRole
|
||||
{
|
||||
Land,
|
||||
Hand
|
||||
}
|
||||
Land,
|
||||
Hand
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public enum NameplateElement
|
||||
{
|
||||
public enum NameplateElement
|
||||
{
|
||||
Name,
|
||||
Title,
|
||||
FreeCompany
|
||||
}
|
||||
Name,
|
||||
Title,
|
||||
FreeCompany,
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||
public enum NameplateFreeCompanyVisibility
|
||||
{
|
||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||
public enum NameplateFreeCompanyVisibility
|
||||
{
|
||||
Default,
|
||||
Never
|
||||
}
|
||||
Default,
|
||||
Never
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||
public enum NameplateTitlePosition
|
||||
{
|
||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||
public enum NameplateTitlePosition
|
||||
{
|
||||
Default,
|
||||
AlwaysAboveName,
|
||||
AlwaysBelowName
|
||||
}
|
||||
Default,
|
||||
AlwaysAboveName,
|
||||
AlwaysBelowName
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||
public enum NameplateTitleVisibility
|
||||
{
|
||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||
public enum NameplateTitleVisibility
|
||||
{
|
||||
Default,
|
||||
Always,
|
||||
Never,
|
||||
WhenHasTags
|
||||
}
|
||||
Default,
|
||||
Always,
|
||||
Never,
|
||||
WhenHasTags
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public enum PlayerContext
|
||||
{
|
||||
public enum PlayerContext
|
||||
{
|
||||
None = 0x0,
|
||||
Self = 0x1,
|
||||
Party = 0x2,
|
||||
Alliance = 0x4,
|
||||
Enemy = 0x8,
|
||||
Friend = 0x10
|
||||
}
|
||||
None = 0x0,
|
||||
Self = 0x1,
|
||||
Party = 0x2,
|
||||
Alliance = 0x4,
|
||||
Enemy = 0x8,
|
||||
Friend = 0x10
|
||||
}
|
||||
|
||||
@@ -1,81 +1,59 @@
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public static class PlayerContextHelper
|
||||
{
|
||||
public static class PlayerContextHelper
|
||||
public static PlayerContext GetPlayerContext(IPlayerCharacter playerCharacter)
|
||||
{
|
||||
public static PlayerContext GetPlayerContext(PlayerCharacter playerCharacter)
|
||||
{
|
||||
PlayerContext playerContext = PlayerContext.None;
|
||||
var playerContext = PlayerContext.None;
|
||||
|
||||
if (PluginServices.ClientState.LocalPlayer == playerCharacter)
|
||||
{
|
||||
playerContext |= PlayerContext.Self;
|
||||
}
|
||||
if (PluginServices.ClientState.LocalPlayer == playerCharacter)
|
||||
playerContext |= PlayerContext.Self;
|
||||
|
||||
if (playerCharacter.StatusFlags.HasFlag(StatusFlags.Friend))
|
||||
{
|
||||
playerContext |= PlayerContext.Friend;
|
||||
}
|
||||
if (playerCharacter.StatusFlags.HasFlag(StatusFlags.Friend))
|
||||
playerContext |= PlayerContext.Friend;
|
||||
|
||||
if (playerCharacter.StatusFlags.HasFlag(StatusFlags.PartyMember))
|
||||
{
|
||||
playerContext |= PlayerContext.Party;
|
||||
}
|
||||
if (playerCharacter.StatusFlags.HasFlag(StatusFlags.PartyMember))
|
||||
playerContext |= PlayerContext.Party;
|
||||
|
||||
if (playerCharacter.StatusFlags.HasFlag(StatusFlags.AllianceMember))
|
||||
{
|
||||
playerContext |= PlayerContext.Alliance;
|
||||
}
|
||||
if (playerCharacter.StatusFlags.HasFlag(StatusFlags.AllianceMember))
|
||||
playerContext |= PlayerContext.Alliance;
|
||||
|
||||
if (playerCharacter.StatusFlags.HasFlag(StatusFlags.Hostile))
|
||||
{
|
||||
playerContext |= PlayerContext.Enemy;
|
||||
}
|
||||
if (playerCharacter.StatusFlags.HasFlag(StatusFlags.Hostile))
|
||||
playerContext |= PlayerContext.Enemy;
|
||||
|
||||
return playerContext;
|
||||
}
|
||||
return playerContext;
|
||||
}
|
||||
|
||||
public static bool GetIsVisible(PlayerContext playerContext, bool desiredSelfVisibility, bool desiredFriendsVisibility, bool desiredPartyVisibility, bool desiredAllianceVisibility, bool desiredEnemiesVisibility, bool desiredOthersVisibility)
|
||||
{
|
||||
if (playerContext.HasFlag(PlayerContext.Self))
|
||||
{
|
||||
return desiredSelfVisibility;
|
||||
}
|
||||
public static bool GetIsVisible(PlayerContext playerContext, bool desiredSelfVisibility, bool desiredFriendsVisibility, bool desiredPartyVisibility, bool desiredAllianceVisibility, bool desiredEnemiesVisibility, bool desiredOthersVisibility)
|
||||
{
|
||||
if (playerContext.HasFlag(PlayerContext.Self))
|
||||
return desiredSelfVisibility;
|
||||
|
||||
bool isVisible = false;
|
||||
if (playerContext.HasFlag(PlayerContext.Friend))
|
||||
{
|
||||
isVisible |= desiredFriendsVisibility;
|
||||
}
|
||||
var isVisible = false;
|
||||
|
||||
if (playerContext.HasFlag(PlayerContext.Party))
|
||||
{
|
||||
isVisible |= desiredPartyVisibility;
|
||||
}
|
||||
if (playerContext.HasFlag(PlayerContext.Friend))
|
||||
isVisible |= desiredFriendsVisibility;
|
||||
|
||||
if (!playerContext.HasFlag(PlayerContext.Party) && playerContext.HasFlag(PlayerContext.Alliance))
|
||||
{
|
||||
isVisible |= desiredAllianceVisibility;
|
||||
}
|
||||
if (playerContext.HasFlag(PlayerContext.Party))
|
||||
isVisible |= desiredPartyVisibility;
|
||||
|
||||
if (playerContext.HasFlag(PlayerContext.Enemy))
|
||||
{
|
||||
isVisible |= desiredEnemiesVisibility;
|
||||
}
|
||||
if (!playerContext.HasFlag(PlayerContext.Party) && playerContext.HasFlag(PlayerContext.Alliance))
|
||||
isVisible |= desiredAllianceVisibility;
|
||||
|
||||
if (playerContext == PlayerContext.None)
|
||||
{
|
||||
isVisible |= desiredOthersVisibility;
|
||||
}
|
||||
if (playerContext.HasFlag(PlayerContext.Enemy))
|
||||
isVisible |= desiredEnemiesVisibility;
|
||||
|
||||
return isVisible;
|
||||
}
|
||||
if (playerContext == PlayerContext.None)
|
||||
isVisible |= desiredOthersVisibility;
|
||||
|
||||
public static bool GetIsVisible(PlayerCharacter playerCharacter, bool desiredSelfVisibility, bool desiredFriendsVisibility, bool desiredPartyVisibility, bool desiredAllianceVisibility, bool desiredEnemiesVisibility, bool desiredOthersVisibility)
|
||||
{
|
||||
return GetIsVisible(GetPlayerContext(playerCharacter), desiredSelfVisibility, desiredFriendsVisibility, desiredPartyVisibility, desiredAllianceVisibility, desiredEnemiesVisibility, desiredOthersVisibility);
|
||||
}
|
||||
return isVisible;
|
||||
}
|
||||
|
||||
public static bool GetIsVisible(IPlayerCharacter playerCharacter, bool desiredSelfVisibility, bool desiredFriendsVisibility, bool desiredPartyVisibility, bool desiredAllianceVisibility, bool desiredEnemiesVisibility, bool desiredOthersVisibility)
|
||||
{
|
||||
return GetIsVisible(GetPlayerContext(playerCharacter), desiredSelfVisibility, desiredFriendsVisibility, desiredPartyVisibility, desiredAllianceVisibility, desiredEnemiesVisibility, desiredOthersVisibility);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,307 +1,305 @@
|
||||
using Dalamud.ContextMenu;
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.ClientState.Party;
|
||||
using Dalamud.Game.Gui.ContextMenu;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Dalamud.Logging;
|
||||
using PlayerTags.Configuration;
|
||||
using PlayerTags.PluginStrings;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public class PluginData
|
||||
{
|
||||
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 PluginData(PluginConfiguration pluginConfiguration)
|
||||
{
|
||||
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;
|
||||
this.pluginConfiguration = pluginConfiguration;
|
||||
ReloadDefault();
|
||||
}
|
||||
|
||||
private PluginConfiguration pluginConfiguration;
|
||||
public void ReloadDefault()
|
||||
{
|
||||
Default = new DefaultPluginData(pluginConfiguration.DefaultPluginDataTemplate);
|
||||
|
||||
public PluginData(PluginConfiguration pluginConfiguration)
|
||||
// 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 = [];
|
||||
foreach (var role in Enum.GetValues<Role>())
|
||||
{
|
||||
this.pluginConfiguration = pluginConfiguration;
|
||||
ReloadDefault();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ReloadDefault()
|
||||
DpsRoleTags = [];
|
||||
foreach (var dpsRole in Enum.GetValues<DpsRole>())
|
||||
{
|
||||
Default = new DefaultPluginData(pluginConfiguration.DefaultPluginDataTemplate);
|
||||
|
||||
// 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.DpsRoleTags.TryGetValue(dpsRole, out var defaultTag))
|
||||
{
|
||||
if (Default.RoleTags.TryGetValue(role, out var defaultTag))
|
||||
DpsRoleTags[dpsRole] = new Tag(new LocalizedPluginString(Localizer.GetName(dpsRole)), defaultTag);
|
||||
if (pluginConfiguration.DpsRoleTagsChanges.TryGetValue(dpsRole, out var savedChanges))
|
||||
{
|
||||
RoleTags[role] = new Tag(new LocalizedPluginString(Localizer.GetName(role)), defaultTag);
|
||||
if (pluginConfiguration.RoleTagsChanges.TryGetValue(role, out var savedChanges))
|
||||
{
|
||||
RoleTags[role].SetChanges(savedChanges);
|
||||
}
|
||||
DpsRoleTags[dpsRole].SetChanges(savedChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DpsRoleTags = new Dictionary<DpsRole, Tag>();
|
||||
foreach (var dpsRole in Enum.GetValues<DpsRole>())
|
||||
RangedDpsRoleTags = [];
|
||||
foreach (var rangedDpsRole in Enum.GetValues<RangedDpsRole>())
|
||||
{
|
||||
if (Default.RangedDpsRoleTags.TryGetValue(rangedDpsRole, out var defaultTag))
|
||||
{
|
||||
if (Default.DpsRoleTags.TryGetValue(dpsRole, out var defaultTag))
|
||||
RangedDpsRoleTags[rangedDpsRole] = new Tag(new LocalizedPluginString(Localizer.GetName(rangedDpsRole)), defaultTag);
|
||||
if (pluginConfiguration.RangedDpsRoleTagsChanges.TryGetValue(rangedDpsRole, out var savedChanges))
|
||||
{
|
||||
DpsRoleTags[dpsRole] = new Tag(new LocalizedPluginString(Localizer.GetName(dpsRole)), defaultTag);
|
||||
if (pluginConfiguration.DpsRoleTagsChanges.TryGetValue(dpsRole, out var savedChanges))
|
||||
{
|
||||
DpsRoleTags[dpsRole].SetChanges(savedChanges);
|
||||
}
|
||||
RangedDpsRoleTags[rangedDpsRole].SetChanges(savedChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RangedDpsRoleTags = new Dictionary<RangedDpsRole, Tag>();
|
||||
foreach (var rangedDpsRole in Enum.GetValues<RangedDpsRole>())
|
||||
LandHandRoleTags = [];
|
||||
foreach (var landHandRole in Enum.GetValues<LandHandRole>())
|
||||
{
|
||||
if (Default.LandHandRoleTags.TryGetValue(landHandRole, out var defaultChanges))
|
||||
{
|
||||
if (Default.RangedDpsRoleTags.TryGetValue(rangedDpsRole, out var defaultTag))
|
||||
LandHandRoleTags[landHandRole] = new Tag(new LocalizedPluginString(Localizer.GetName(landHandRole)), defaultChanges);
|
||||
if (pluginConfiguration.LandHandRoleTagsChanges.TryGetValue(landHandRole, out var savedChanges))
|
||||
{
|
||||
RangedDpsRoleTags[rangedDpsRole] = new Tag(new LocalizedPluginString(Localizer.GetName(rangedDpsRole)), defaultTag);
|
||||
if (pluginConfiguration.RangedDpsRoleTagsChanges.TryGetValue(rangedDpsRole, out var savedChanges))
|
||||
{
|
||||
RangedDpsRoleTags[rangedDpsRole].SetChanges(savedChanges);
|
||||
}
|
||||
LandHandRoleTags[landHandRole].SetChanges(savedChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LandHandRoleTags = new Dictionary<LandHandRole, Tag>();
|
||||
foreach (var landHandRole in Enum.GetValues<LandHandRole>())
|
||||
JobTags = [];
|
||||
foreach ((var jobAbbreviation, var role) in RoleHelper.RolesByJobAbbreviation)
|
||||
{
|
||||
if (Default.JobTags.TryGetValue(jobAbbreviation, out var defaultChanges))
|
||||
{
|
||||
if (Default.LandHandRoleTags.TryGetValue(landHandRole, out var defaultChanges))
|
||||
JobTags[jobAbbreviation] = new Tag(new LiteralPluginString(jobAbbreviation), defaultChanges);
|
||||
if (pluginConfiguration.JobTagsChanges.TryGetValue(jobAbbreviation, out var savedChanges))
|
||||
{
|
||||
LandHandRoleTags[landHandRole] = new Tag(new LocalizedPluginString(Localizer.GetName(landHandRole)), defaultChanges);
|
||||
if (pluginConfiguration.LandHandRoleTagsChanges.TryGetValue(landHandRole, out var savedChanges))
|
||||
{
|
||||
LandHandRoleTags[landHandRole].SetChanges(savedChanges);
|
||||
}
|
||||
JobTags[jobAbbreviation].SetChanges(savedChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JobTags = new Dictionary<string, Tag>();
|
||||
foreach ((var jobAbbreviation, var role) in RoleHelper.RolesByJobAbbreviation)
|
||||
AllCustomTags = new Tag(new LocalizedPluginString(nameof(AllCustomTags)), Default.AllCustomTags);
|
||||
AllCustomTags.SetChanges(pluginConfiguration.AllCustomTagsChanges);
|
||||
|
||||
CustomTags = [];
|
||||
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)
|
||||
{
|
||||
if (Default.JobTags.TryGetValue(jobAbbreviation, out var defaultChanges))
|
||||
foreach ((var dpsRole, var dpsRoleTag) in DpsRoleTags)
|
||||
{
|
||||
JobTags[jobAbbreviation] = new Tag(new LiteralPluginString(jobAbbreviation), defaultChanges);
|
||||
if (pluginConfiguration.JobTagsChanges.TryGetValue(jobAbbreviation, out var savedChanges))
|
||||
dpsRoleTag.Parent = roleTag;
|
||||
|
||||
if (dpsRole == DpsRole.Ranged)
|
||||
{
|
||||
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)
|
||||
{
|
||||
foreach ((var rangedDpsRole, var rangedDpsRoleTag) in RangedDpsRoleTags)
|
||||
{
|
||||
rangedDpsRoleTag.Parent = dpsRoleTag;
|
||||
}
|
||||
rangedDpsRoleTag.Parent = dpsRoleTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (role == Role.LandHand)
|
||||
}
|
||||
else if (role == Role.LandHand)
|
||||
{
|
||||
foreach ((var landHandRole, var landHandRoleTag) in LandHandRoleTags)
|
||||
{
|
||||
foreach ((var landHandRole, var landHandRoleTag) in LandHandRoleTags)
|
||||
{
|
||||
landHandRoleTag.Parent = roleTag;
|
||||
}
|
||||
landHandRoleTag.Parent = roleTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ((var jobAbbreviation, var jobTag) in JobTags)
|
||||
foreach ((var jobAbbreviation, var jobTag) in JobTags)
|
||||
{
|
||||
if (RoleHelper.RolesByJobAbbreviation.TryGetValue(jobAbbreviation, out var role))
|
||||
{
|
||||
if (RoleHelper.RolesByJobAbbreviation.TryGetValue(jobAbbreviation, out var role))
|
||||
if (RoleHelper.DpsRolesByJobAbbreviation.TryGetValue(jobAbbreviation, out var dpsRole))
|
||||
{
|
||||
if (RoleHelper.DpsRolesByJobAbbreviation.TryGetValue(jobAbbreviation, out var dpsRole))
|
||||
if (RoleHelper.RangedDpsRolesByJobAbbreviation.TryGetValue(jobAbbreviation, out var rangedDpsRole))
|
||||
{
|
||||
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];
|
||||
jobTag.Parent = RangedDpsRoleTags[rangedDpsRole];
|
||||
}
|
||||
else
|
||||
{
|
||||
jobTag.Parent = RoleTags[RoleHelper.RolesByJobAbbreviation[jobAbbreviation]];
|
||||
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)
|
||||
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)
|
||||
{
|
||||
tag.Parent = AllCustomTags;
|
||||
customTag.CustomId.Behavior = Inheritables.InheritableBehavior.Enabled;
|
||||
customTag.CustomId.Value = Guid.NewGuid();
|
||||
customTagsMigrated = true;
|
||||
}
|
||||
|
||||
Identities = pluginConfiguration.Identities;
|
||||
|
||||
// Migrate old custom tag identity assignments
|
||||
bool customTagsMigrated = false;
|
||||
foreach (var customTag in CustomTags)
|
||||
foreach (string identityToAddTo in customTag.IdentitiesToAddTo)
|
||||
{
|
||||
if (customTag.CustomId.Value == Guid.Empty)
|
||||
Identity? identity = Identities.FirstOrDefault(identity => identity.Name.ToLower() == identityToAddTo.ToLower());
|
||||
if (identity == null)
|
||||
{
|
||||
customTag.CustomId.Behavior = Inheritables.InheritableBehavior.Enabled;
|
||||
customTag.CustomId.Value = Guid.NewGuid();
|
||||
customTagsMigrated = true;
|
||||
identity = new Identity(identityToAddTo);
|
||||
Identities.Add(identity);
|
||||
}
|
||||
|
||||
foreach (string identityToAddTo in customTag.IdentitiesToAddTo)
|
||||
if (identity != null)
|
||||
{
|
||||
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 = "";
|
||||
identity.CustomTagIds.Add(customTag.CustomId.Value);
|
||||
customTagsMigrated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (customTagsMigrated)
|
||||
if (customTag.GameObjectNamesToApplyTo.Behavior != Inheritables.InheritableBehavior.Inherit)
|
||||
{
|
||||
pluginConfiguration.Save(this);
|
||||
customTag.GameObjectNamesToApplyTo.Behavior = Inheritables.InheritableBehavior.Inherit;
|
||||
customTag.GameObjectNamesToApplyTo.Value = "";
|
||||
customTagsMigrated = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddCustomTagToIdentity(Tag customTag, Identity identity)
|
||||
if (customTagsMigrated)
|
||||
{
|
||||
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);
|
||||
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(MenuTargetDefault taget)
|
||||
{
|
||||
if (string.IsNullOrEmpty(taget.TargetName)
|
||||
|| taget.TargetHomeWorld.RowId == 0
|
||||
|| taget.TargetHomeWorld.RowId == 65535)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return GetIdentity(taget.TargetName, taget.TargetHomeWorld.RowId);
|
||||
}
|
||||
|
||||
public Identity GetIdentity(IPlayerCharacter playerCharacter)
|
||||
{
|
||||
return GetIdentity(playerCharacter.Name.TextValue, playerCharacter.HomeWorld.RowId);
|
||||
}
|
||||
|
||||
public Identity GetIdentity(IPartyMember partyMember)
|
||||
{
|
||||
return GetIdentity(partyMember.Name.TextValue, partyMember.World.RowId);
|
||||
}
|
||||
|
||||
public Identity GetIdentity(PlayerPayload playerPayload)
|
||||
{
|
||||
return GetIdentity(playerPayload.PlayerName, playerPayload.World.RowId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public enum RangedDpsRole
|
||||
{
|
||||
public enum RangedDpsRole
|
||||
{
|
||||
Magical,
|
||||
Physical,
|
||||
}
|
||||
Magical,
|
||||
Physical,
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public enum Role
|
||||
{
|
||||
public enum Role
|
||||
{
|
||||
LandHand,
|
||||
Tank,
|
||||
Healer,
|
||||
Dps,
|
||||
}
|
||||
LandHand,
|
||||
Tank,
|
||||
Healer,
|
||||
Dps,
|
||||
}
|
||||
|
||||
@@ -1,153 +1,152 @@
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Pilz.Dalamud;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public static class RoleHelper
|
||||
{
|
||||
public static class RoleHelper
|
||||
public static Dictionary<byte, Role> RolesByRoleId { get; } = new Dictionary<byte, Role>()
|
||||
{
|
||||
public static Dictionary<byte, Role> RolesByRoleId { get; } = new Dictionary<byte, Role>()
|
||||
{
|
||||
{ 0, Role.LandHand },
|
||||
{ 1, Role.Tank },
|
||||
{ 2, Role.Dps },
|
||||
{ 3, Role.Dps },
|
||||
{ 4, Role.Healer },
|
||||
};
|
||||
{ 0, Role.LandHand },
|
||||
{ 1, Role.Tank },
|
||||
{ 2, Role.Dps },
|
||||
{ 3, Role.Dps },
|
||||
{ 4, Role.Healer },
|
||||
};
|
||||
|
||||
public static Dictionary<byte, DpsRole> DpsRolesByRoleId { get; } = new Dictionary<byte, DpsRole>()
|
||||
{
|
||||
{ 2, DpsRole.Melee },
|
||||
{ 3, DpsRole.Ranged },
|
||||
};
|
||||
public static Dictionary<byte, DpsRole> DpsRolesByRoleId { get; } = new Dictionary<byte, DpsRole>()
|
||||
{
|
||||
{ 2, DpsRole.Melee },
|
||||
{ 3, DpsRole.Ranged },
|
||||
};
|
||||
|
||||
public static Dictionary<byte, RangedDpsRole> RangedDpsRolesByPrimaryStat { get; } = new Dictionary<byte, RangedDpsRole>()
|
||||
{
|
||||
{ 4, RangedDpsRole.Magical },
|
||||
{ 2, RangedDpsRole.Physical },
|
||||
};
|
||||
public static Dictionary<byte, RangedDpsRole> RangedDpsRolesByPrimaryStat { get; } = new Dictionary<byte, RangedDpsRole>()
|
||||
{
|
||||
{ 4, RangedDpsRole.Magical },
|
||||
{ 2, RangedDpsRole.Physical },
|
||||
};
|
||||
|
||||
private static Dictionary<string, Role>? s_RolesByJobAbbreviation = null;
|
||||
public static Dictionary<string, Role> RolesByJobAbbreviation
|
||||
private static Dictionary<string, Role>? s_RolesByJobAbbreviation = null;
|
||||
public static Dictionary<string, Role> RolesByJobAbbreviation
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
if (s_RolesByJobAbbreviation == null)
|
||||
{
|
||||
if (s_RolesByJobAbbreviation == null)
|
||||
{
|
||||
s_RolesByJobAbbreviation = new Dictionary<string, Role>();
|
||||
s_RolesByJobAbbreviation = [];
|
||||
|
||||
var classJobs = PluginServices.DataManager.GetExcelSheet<ClassJob>();
|
||||
if (classJobs != null)
|
||||
var classJobs = PluginServices.DataManager.GetExcelSheet<ClassJob>();
|
||||
if (classJobs != null)
|
||||
{
|
||||
foreach (var classJob in classJobs.Where(classJob => !string.IsNullOrEmpty(classJob.Abbreviation.ParseString())))
|
||||
{
|
||||
foreach (var classJob in classJobs.Where(classJob => !string.IsNullOrEmpty(classJob.Abbreviation.RawString)))
|
||||
if (RolesByRoleId.TryGetValue(classJob.Role, out var role))
|
||||
{
|
||||
if (RolesByRoleId.TryGetValue(classJob.Role, out var role))
|
||||
s_RolesByJobAbbreviation[classJob.Abbreviation.ParseString()] = role;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s_RolesByJobAbbreviation;
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, DpsRole>? s_DpsRolesByJobAbbreviation = null;
|
||||
public static Dictionary<string, DpsRole> DpsRolesByJobAbbreviation
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_DpsRolesByJobAbbreviation == null)
|
||||
{
|
||||
s_DpsRolesByJobAbbreviation = [];
|
||||
|
||||
var classJobs = PluginServices.DataManager.GetExcelSheet<ClassJob>();
|
||||
if (classJobs != null)
|
||||
{
|
||||
foreach (var classJob in classJobs.Where(classJob => !string.IsNullOrEmpty(classJob.Abbreviation.ParseString())))
|
||||
{
|
||||
if (DpsRolesByRoleId.TryGetValue(classJob.Role, out var dpsRole))
|
||||
{
|
||||
s_DpsRolesByJobAbbreviation[classJob.Abbreviation.ParseString()] = dpsRole;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s_DpsRolesByJobAbbreviation;
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, RangedDpsRole>? s_RangedDpsRolesByJobAbbreviation = null;
|
||||
public static Dictionary<string, RangedDpsRole> RangedDpsRolesByJobAbbreviation
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_RangedDpsRolesByJobAbbreviation == null)
|
||||
{
|
||||
s_RangedDpsRolesByJobAbbreviation = [];
|
||||
|
||||
var classJobs = PluginServices.DataManager.GetExcelSheet<ClassJob>();
|
||||
if (classJobs != null)
|
||||
{
|
||||
foreach (var classJob in classJobs.Where(classJob => !string.IsNullOrEmpty(classJob.Abbreviation.ParseString())))
|
||||
{
|
||||
if (DpsRolesByJobAbbreviation.TryGetValue(classJob.Abbreviation.ParseString(), out var dpsRole) && dpsRole == DpsRole.Ranged)
|
||||
{
|
||||
if (RangedDpsRolesByPrimaryStat.TryGetValue(classJob.PrimaryStat, out var rangedDPSRole))
|
||||
{
|
||||
s_RolesByJobAbbreviation[classJob.Abbreviation] = role;
|
||||
s_RangedDpsRolesByJobAbbreviation[classJob.Abbreviation.ParseString()] = rangedDPSRole;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s_RolesByJobAbbreviation;
|
||||
}
|
||||
|
||||
return s_RangedDpsRolesByJobAbbreviation;
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, DpsRole>? s_DpsRolesByJobAbbreviation = null;
|
||||
public static Dictionary<string, DpsRole> DpsRolesByJobAbbreviation
|
||||
private static Dictionary<string, LandHandRole>? s_LandHandRolesByJobAbbreviation = null;
|
||||
public static Dictionary<string, LandHandRole> LandHandRolesByJobAbbreviation
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
if (s_LandHandRolesByJobAbbreviation == null)
|
||||
{
|
||||
if (s_DpsRolesByJobAbbreviation == null)
|
||||
s_LandHandRolesByJobAbbreviation = [];
|
||||
|
||||
var classJobs = PluginServices.DataManager.GetExcelSheet<ClassJob>();
|
||||
var gatheringSubCategories = PluginServices.DataManager.GetExcelSheet<GatheringSubCategory>();
|
||||
if (classJobs != null && gatheringSubCategories != null)
|
||||
{
|
||||
s_DpsRolesByJobAbbreviation = new Dictionary<string, DpsRole>();
|
||||
var gatheringJobAbbreviations = gatheringSubCategories
|
||||
.Select(gatheringSubCategory => gatheringSubCategory.ClassJob.Value)
|
||||
.Select(classJob => classJob!.Abbreviation).Distinct();
|
||||
|
||||
var classJobs = PluginServices.DataManager.GetExcelSheet<ClassJob>();
|
||||
if (classJobs != null)
|
||||
foreach (var classJob in classJobs.Where(classJob => !string.IsNullOrEmpty(classJob.Abbreviation.ParseString())))
|
||||
{
|
||||
foreach (var classJob in classJobs.Where(classJob => !string.IsNullOrEmpty(classJob.Abbreviation.RawString)))
|
||||
if (RolesByRoleId.TryGetValue(classJob.Role, out var role))
|
||||
{
|
||||
if (DpsRolesByRoleId.TryGetValue(classJob.Role, out var dpsRole))
|
||||
if (role == Role.LandHand)
|
||||
{
|
||||
s_DpsRolesByJobAbbreviation[classJob.Abbreviation] = dpsRole;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s_DpsRolesByJobAbbreviation;
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, RangedDpsRole>? s_RangedDpsRolesByJobAbbreviation = null;
|
||||
public static Dictionary<string, RangedDpsRole> RangedDpsRolesByJobAbbreviation
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_RangedDpsRolesByJobAbbreviation == null)
|
||||
{
|
||||
s_RangedDpsRolesByJobAbbreviation = new Dictionary<string, RangedDpsRole>();
|
||||
|
||||
var classJobs = PluginServices.DataManager.GetExcelSheet<ClassJob>();
|
||||
if (classJobs != null)
|
||||
{
|
||||
foreach (var classJob in classJobs.Where(classJob => !string.IsNullOrEmpty(classJob.Abbreviation.RawString)))
|
||||
{
|
||||
if (DpsRolesByJobAbbreviation.TryGetValue(classJob.Abbreviation, out var dpsRole) && dpsRole == DpsRole.Ranged)
|
||||
{
|
||||
if (RangedDpsRolesByPrimaryStat.TryGetValue(classJob.PrimaryStat, out var rangedDPSRole))
|
||||
if (gatheringJobAbbreviations.Contains(classJob.Abbreviation))
|
||||
{
|
||||
s_RangedDpsRolesByJobAbbreviation[classJob.Abbreviation] = rangedDPSRole;
|
||||
s_LandHandRolesByJobAbbreviation[classJob.Abbreviation.ParseString()] = LandHandRole.Land;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_LandHandRolesByJobAbbreviation[classJob.Abbreviation.ParseString()] = LandHandRole.Hand;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s_RangedDpsRolesByJobAbbreviation;
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, LandHandRole>? s_LandHandRolesByJobAbbreviation = null;
|
||||
public static Dictionary<string, LandHandRole> LandHandRolesByJobAbbreviation
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_LandHandRolesByJobAbbreviation == null)
|
||||
{
|
||||
s_LandHandRolesByJobAbbreviation = new Dictionary<string, LandHandRole>();
|
||||
|
||||
var classJobs = PluginServices.DataManager.GetExcelSheet<ClassJob>();
|
||||
var gatheringSubCategories = PluginServices.DataManager.GetExcelSheet<GatheringSubCategory>();
|
||||
if (classJobs != null && gatheringSubCategories != null)
|
||||
{
|
||||
var gatheringJobAbbreviations = gatheringSubCategories
|
||||
.Select(gatheringSubCategory => gatheringSubCategory.ClassJob.Value)
|
||||
.Where(classJob => classJob != null)
|
||||
.Select(classJob => classJob!.Abbreviation).Distinct();
|
||||
|
||||
foreach (var classJob in classJobs.Where(classJob => !string.IsNullOrEmpty(classJob.Abbreviation.RawString)))
|
||||
{
|
||||
if (RolesByRoleId.TryGetValue(classJob.Role, out var role))
|
||||
{
|
||||
if (role == Role.LandHand)
|
||||
{
|
||||
if (gatheringJobAbbreviations.Contains(classJob.Abbreviation))
|
||||
{
|
||||
s_LandHandRolesByJobAbbreviation[classJob.Abbreviation] = LandHandRole.Land;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_LandHandRolesByJobAbbreviation[classJob.Abbreviation] = LandHandRole.Hand;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s_LandHandRolesByJobAbbreviation;
|
||||
}
|
||||
return s_LandHandRolesByJobAbbreviation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,330 +1,320 @@
|
||||
using Dalamud.Game.Text;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Pilz.Dalamud.Icons;
|
||||
using PlayerTags.Inheritables;
|
||||
using PlayerTags.PluginStrings;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public class Tag
|
||||
{
|
||||
public class Tag
|
||||
public IPluginString Name { get; init; }
|
||||
|
||||
[JsonProperty("Parent")]
|
||||
private Tag? m_Parent = null;
|
||||
|
||||
[JsonIgnore]
|
||||
public Tag? Parent
|
||||
{
|
||||
public IPluginString Name { get; init; }
|
||||
|
||||
[JsonProperty("Parent")]
|
||||
private Tag? m_Parent = null;
|
||||
|
||||
[JsonIgnore]
|
||||
public Tag? Parent
|
||||
get => m_Parent;
|
||||
set
|
||||
{
|
||||
get => m_Parent;
|
||||
set
|
||||
if (m_Parent != value)
|
||||
{
|
||||
if (m_Parent != value)
|
||||
if (m_Parent != null)
|
||||
{
|
||||
if (m_Parent != null)
|
||||
if (m_Parent.Children.Contains(this))
|
||||
{
|
||||
if (m_Parent.Children.Contains(this))
|
||||
{
|
||||
m_Parent.Children.Remove(this);
|
||||
}
|
||||
m_Parent.Children.Remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
m_Parent = value;
|
||||
if (m_Parent != null)
|
||||
m_Parent = value;
|
||||
if (m_Parent != null)
|
||||
{
|
||||
m_Parent.Children.Add(this);
|
||||
foreach ((var name, IInheritable inheritable) in Inheritables)
|
||||
{
|
||||
m_Parent.Children.Add(this);
|
||||
foreach ((var name, IInheritable inheritable) in Inheritables)
|
||||
{
|
||||
inheritable.Parent = m_Parent.Inheritables[name];
|
||||
}
|
||||
inheritable.Parent = m_Parent.Inheritables[name];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<Tag> Children { get; } = new List<Tag>();
|
||||
public List<Tag> Children { get; } = [];
|
||||
|
||||
[JsonIgnore]
|
||||
public IEnumerable<Tag> Descendents
|
||||
[JsonIgnore]
|
||||
public IEnumerable<Tag> Descendents
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
IEnumerable<Tag> descendents = Children.Prepend(this);
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
IEnumerable<Tag> descendents = Children.Prepend(this);
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
descendents = descendents.Union(child.Descendents);
|
||||
}
|
||||
|
||||
return descendents.Distinct();
|
||||
descendents = descendents.Union(child.Descendents);
|
||||
}
|
||||
|
||||
return descendents.Distinct();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private Dictionary<string, IInheritable>? m_Inheritables = null;
|
||||
[JsonIgnore]
|
||||
public Dictionary<string, IInheritable> Inheritables
|
||||
[JsonIgnore]
|
||||
private Dictionary<string, IInheritable>? m_Inheritables = null;
|
||||
[JsonIgnore]
|
||||
public Dictionary<string, IInheritable> Inheritables
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
if (m_Inheritables == null)
|
||||
{
|
||||
if (m_Inheritables == null)
|
||||
{
|
||||
m_Inheritables = new Dictionary<string, IInheritable>();
|
||||
m_Inheritables = [];
|
||||
|
||||
var inheritableFields = GetType().GetFields().Where(field => typeof(IInheritable).IsAssignableFrom(field.FieldType));
|
||||
foreach (var inheritableField in inheritableFields)
|
||||
var inheritableFields = GetType().GetFields().Where(field => typeof(IInheritable).IsAssignableFrom(field.FieldType));
|
||||
foreach (var inheritableField in inheritableFields)
|
||||
{
|
||||
IInheritable? inheritable = inheritableField.GetValue(this) as IInheritable;
|
||||
if (inheritable != null)
|
||||
{
|
||||
IInheritable? inheritable = inheritableField.GetValue(this) as IInheritable;
|
||||
if (inheritable != null)
|
||||
{
|
||||
Inheritables[inheritableField.Name] = inheritable;
|
||||
}
|
||||
Inheritables[inheritableField.Name] = inheritable;
|
||||
}
|
||||
}
|
||||
|
||||
return m_Inheritables!;
|
||||
}
|
||||
|
||||
return m_Inheritables!;
|
||||
}
|
||||
}
|
||||
|
||||
public InheritableValue<bool> IsSelected = new InheritableValue<bool>(false)
|
||||
public InheritableValue<bool> IsSelected = new(false)
|
||||
{
|
||||
Behavior = InheritableBehavior.Enabled
|
||||
};
|
||||
|
||||
public InheritableValue<bool> IsExpanded = new(false)
|
||||
{
|
||||
Behavior = InheritableBehavior.Enabled
|
||||
};
|
||||
|
||||
// Deprecated
|
||||
public InheritableReference<string> GameObjectNamesToApplyTo = new("");
|
||||
|
||||
public InheritableValue<Guid> CustomId = new(Guid.Empty);
|
||||
|
||||
[JsonProperty, Obsolete]
|
||||
private InheritableValue<bool> IsIconVisibleInChat
|
||||
{
|
||||
set => IsRoleIconVisibleInChat = value;
|
||||
}
|
||||
|
||||
[JsonProperty, Obsolete]
|
||||
private InheritableValue<bool> IsIconVisibleInNameplate
|
||||
{
|
||||
set => IsRoleIconVisibleInNameplates = value;
|
||||
}
|
||||
|
||||
[InheritableCategory("IconCategory")]
|
||||
public InheritableValue<BitmapFontIcon> Icon = new(BitmapFontIcon.Aethernet);
|
||||
[InheritableCategory("IconCategory")]
|
||||
public InheritableValue<bool> IsRoleIconVisibleInChat = new(false);
|
||||
[InheritableCategory("IconCategory")]
|
||||
public InheritableValue<bool> IsRoleIconVisibleInNameplates = new(false);
|
||||
[InheritableCategory("IconCategory")]
|
||||
public InheritableValue<bool> IsJobIconVisibleInNameplates = new(false);
|
||||
[InheritableCategory("IconCategory")]
|
||||
public InheritableValue<JobIconSetName> JobIconSet = new(JobIconSetName.Framed);
|
||||
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableReference<string> Text = new("");
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<ushort> TextColor = new(6);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<ushort> TextGlowColor = new(6);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<bool> IsTextItalic = new(false);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<bool> IsTextVisibleInChat = new(false);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<bool> IsTextVisibleInNameplates = new(false);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<bool> IsTextColorAppliedToChatName = new(false);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<bool> IsTextColorAppliedToNameplateName = new(false);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<bool> IsTextColorAppliedToNameplateTitle = new(false);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<bool> IsTextColorAppliedToNameplateFreeCompany = new(false);
|
||||
|
||||
[InheritableCategory("PositionCategory")]
|
||||
public InheritableValue<TagPosition> TagPositionInChat = new(TagPosition.Before);
|
||||
[InheritableCategory("PositionCategory")]
|
||||
public InheritableValue<bool> InsertBehindNumberPrefixInChat = new(true);
|
||||
[InheritableCategory("PositionCategory")]
|
||||
public InheritableValue<TagPosition> TagPositionInNameplates = new(TagPosition.Before);
|
||||
[InheritableCategory("PositionCategory")]
|
||||
public InheritableValue<NameplateElement> TagTargetInNameplates = new(NameplateElement.Name);
|
||||
|
||||
[InheritableCategory("ActivityCategory")]
|
||||
public InheritableValue<bool> IsVisibleInPveDuties = new(false);
|
||||
[InheritableCategory("ActivityCategory")]
|
||||
public InheritableValue<bool> IsVisibleInPvpDuties = new(false);
|
||||
[InheritableCategory("ActivityCategory")]
|
||||
public InheritableValue<bool> IsVisibleInOverworld = new(false);
|
||||
|
||||
[InheritableCategory("PlayerCategory")]
|
||||
public InheritableValue<bool> IsVisibleForSelf = new(false);
|
||||
[InheritableCategory("PlayerCategory")]
|
||||
public InheritableValue<bool> IsVisibleForFriendPlayers = new(false);
|
||||
[InheritableCategory("PlayerCategory")]
|
||||
public InheritableValue<bool> IsVisibleForPartyPlayers = new(false);
|
||||
[InheritableCategory("PlayerCategory")]
|
||||
public InheritableValue<bool> IsVisibleForAlliancePlayers = new(false);
|
||||
[InheritableCategory("PlayerCategory")]
|
||||
public InheritableValue<bool> IsVisibleForEnemyPlayers = new(false);
|
||||
[InheritableCategory("PlayerCategory")]
|
||||
public InheritableValue<bool> IsVisibleForOtherPlayers = new(false);
|
||||
|
||||
[InheritableCategory("ChatFeatureCategory")]
|
||||
public InheritableReference<List<XivChatType>> TargetChatTypes = new(new List<XivChatType>(Enum.GetValues<XivChatType>()));
|
||||
[InheritableCategory("ChatFeatureCategory")]
|
||||
public InheritableValue<bool> TargetChatTypesIncludeUndefined = new(true);
|
||||
|
||||
[JsonIgnore]
|
||||
public string[] IdentitiesToAddTo
|
||||
{
|
||||
get
|
||||
{
|
||||
Behavior = InheritableBehavior.Enabled
|
||||
};
|
||||
|
||||
public InheritableValue<bool> IsExpanded = new InheritableValue<bool>(false)
|
||||
{
|
||||
Behavior = InheritableBehavior.Enabled
|
||||
};
|
||||
|
||||
// Deprecated
|
||||
public InheritableReference<string> GameObjectNamesToApplyTo = new InheritableReference<string>("");
|
||||
|
||||
public InheritableValue<Guid> CustomId = new InheritableValue<Guid>(Guid.Empty);
|
||||
|
||||
[JsonProperty, Obsolete]
|
||||
private InheritableValue<bool> IsIconVisibleInChat
|
||||
{
|
||||
set => IsRoleIconVisibleInChat = value;
|
||||
}
|
||||
|
||||
[JsonProperty, Obsolete]
|
||||
private InheritableValue<bool> IsIconVisibleInNameplate
|
||||
{
|
||||
set => IsRoleIconVisibleInNameplates = value;
|
||||
}
|
||||
|
||||
[InheritableCategory("IconCategory")]
|
||||
public InheritableValue<BitmapFontIcon> Icon = new InheritableValue<BitmapFontIcon>(BitmapFontIcon.Aethernet);
|
||||
[InheritableCategory("IconCategory")]
|
||||
public InheritableValue<bool> IsRoleIconVisibleInChat = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("IconCategory")]
|
||||
public InheritableValue<bool> IsRoleIconVisibleInNameplates = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("IconCategory")]
|
||||
public InheritableValue<bool> IsJobIconVisibleInNameplates = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("IconCategory")]
|
||||
public InheritableValue<JobIconSetName> JobIconSet = new InheritableValue<JobIconSetName>(JobIconSetName.Framed);
|
||||
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableReference<string> Text = new InheritableReference<string>("");
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<ushort> TextColor = new InheritableValue<ushort>(6);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<ushort> TextGlowColor = new InheritableValue<ushort>(6);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<bool> IsTextItalic = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<bool> IsTextVisibleInChat = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<bool> IsTextVisibleInNameplates = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<bool> IsTextColorAppliedToChatName = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<bool> IsTextColorAppliedToNameplateName = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<bool> IsTextColorAppliedToNameplateTitle = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("TextCategory")]
|
||||
public InheritableValue<bool> IsTextColorAppliedToNameplateFreeCompany = new InheritableValue<bool>(false);
|
||||
|
||||
//[InheritableCategory("NameplateCategory")]
|
||||
//public InheritableValue<NameplateFreeCompanyVisibility> NameplateFreeCompanyVisibility = new InheritableValue<NameplateFreeCompanyVisibility>(Data.NameplateFreeCompanyVisibility.Default);
|
||||
//[InheritableCategory("NameplateCategory")]
|
||||
//public InheritableValue<NameplateTitleVisibility> NameplateTitleVisibility = new InheritableValue<NameplateTitleVisibility>(Data.NameplateTitleVisibility.Default);
|
||||
//[InheritableCategory("NameplateCategory")]
|
||||
//public InheritableValue<NameplateTitlePosition> NameplateTitlePosition = new InheritableValue<NameplateTitlePosition>(Data.NameplateTitlePosition.Default);
|
||||
|
||||
[InheritableCategory("PositionCategory")]
|
||||
public InheritableValue<TagPosition> TagPositionInChat = new InheritableValue<TagPosition>(TagPosition.Before);
|
||||
[InheritableCategory("PositionCategory")]
|
||||
public InheritableValue<bool> InsertBehindNumberPrefixInChat = new InheritableValue<bool>(true);
|
||||
[InheritableCategory("PositionCategory")]
|
||||
public InheritableValue<TagPosition> TagPositionInNameplates = new InheritableValue<TagPosition>(TagPosition.Before);
|
||||
[InheritableCategory("PositionCategory")]
|
||||
public InheritableValue<NameplateElement> TagTargetInNameplates = new InheritableValue<NameplateElement>(NameplateElement.Name);
|
||||
|
||||
[InheritableCategory("ActivityCategory")]
|
||||
public InheritableValue<bool> IsVisibleInPveDuties = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("ActivityCategory")]
|
||||
public InheritableValue<bool> IsVisibleInPvpDuties = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("ActivityCategory")]
|
||||
public InheritableValue<bool> IsVisibleInOverworld = new InheritableValue<bool>(false);
|
||||
|
||||
[InheritableCategory("PlayerCategory")]
|
||||
public InheritableValue<bool> IsVisibleForSelf = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("PlayerCategory")]
|
||||
public InheritableValue<bool> IsVisibleForFriendPlayers = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("PlayerCategory")]
|
||||
public InheritableValue<bool> IsVisibleForPartyPlayers = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("PlayerCategory")]
|
||||
public InheritableValue<bool> IsVisibleForAlliancePlayers = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("PlayerCategory")]
|
||||
public InheritableValue<bool> IsVisibleForEnemyPlayers = new InheritableValue<bool>(false);
|
||||
[InheritableCategory("PlayerCategory")]
|
||||
public InheritableValue<bool> IsVisibleForOtherPlayers = new InheritableValue<bool>(false);
|
||||
|
||||
[InheritableCategory("ChatFeatureCategory")]
|
||||
public InheritableReference<List<XivChatType>> TargetChatTypes = new(new List<XivChatType>(Enum.GetValues<XivChatType>()));
|
||||
[InheritableCategory("ChatFeatureCategory")]
|
||||
public InheritableValue<bool> TargetChatTypesIncludeUndefined = new(true);
|
||||
|
||||
[JsonIgnore]
|
||||
public string[] IdentitiesToAddTo
|
||||
{
|
||||
get
|
||||
if (GameObjectNamesToApplyTo == null || GameObjectNamesToApplyTo.InheritedValue == null)
|
||||
{
|
||||
if (GameObjectNamesToApplyTo == null || GameObjectNamesToApplyTo.InheritedValue == null)
|
||||
{
|
||||
return new string[] { };
|
||||
}
|
||||
|
||||
return GameObjectNamesToApplyTo.InheritedValue.Split(';', ',').Where(item => !string.IsNullOrEmpty(item)).Select(item => item.Trim()).ToArray();
|
||||
return new string[] { };
|
||||
}
|
||||
|
||||
return GameObjectNamesToApplyTo.InheritedValue.Split(';', ',').Where(item => !string.IsNullOrEmpty(item)).Select(item => item.Trim()).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private Tag? m_Defaults;
|
||||
[JsonIgnore]
|
||||
public bool HasDefaults
|
||||
private Tag? m_Defaults;
|
||||
[JsonIgnore]
|
||||
public bool HasDefaults
|
||||
{
|
||||
get { return m_Defaults != null; }
|
||||
}
|
||||
|
||||
public Tag()
|
||||
{
|
||||
Name = new LiteralPluginString("");
|
||||
m_Defaults = null;
|
||||
}
|
||||
|
||||
public Tag(IPluginString name)
|
||||
{
|
||||
Name = name;
|
||||
m_Defaults = null;
|
||||
}
|
||||
|
||||
public Tag(IPluginString name, Tag defaults)
|
||||
{
|
||||
Name = name;
|
||||
m_Defaults = defaults;
|
||||
SetChanges(defaults.GetChanges());
|
||||
}
|
||||
|
||||
public Dictionary<string, InheritableData> GetChanges(Dictionary<string, InheritableData>? defaultChanges = null)
|
||||
{
|
||||
Dictionary<string, InheritableData> changes = [];
|
||||
|
||||
foreach ((var name, var inheritable) in Inheritables)
|
||||
{
|
||||
get { return m_Defaults != null; }
|
||||
}
|
||||
|
||||
public Tag()
|
||||
{
|
||||
Name = new LiteralPluginString("");
|
||||
m_Defaults = null;
|
||||
}
|
||||
|
||||
public Tag(IPluginString name)
|
||||
{
|
||||
Name = name;
|
||||
m_Defaults = null;
|
||||
}
|
||||
|
||||
public Tag(IPluginString name, Tag defaults)
|
||||
{
|
||||
Name = name;
|
||||
m_Defaults = defaults;
|
||||
SetChanges(defaults.GetChanges());
|
||||
}
|
||||
|
||||
public Dictionary<string, InheritableData> GetChanges(Dictionary<string, InheritableData>? defaultChanges = null)
|
||||
{
|
||||
Dictionary<string, InheritableData> changes = new Dictionary<string, InheritableData>();
|
||||
|
||||
foreach ((var name, var inheritable) in Inheritables)
|
||||
// If there's a default for this name, only set the value if it's different from the default
|
||||
if (defaultChanges != null && defaultChanges.TryGetValue(name, out var defaultInheritableData))
|
||||
{
|
||||
// If there's a default for this name, only set the value if it's different from the default
|
||||
if (defaultChanges != null && defaultChanges.TryGetValue(name, out var defaultInheritableData))
|
||||
{
|
||||
var inheritableData = inheritable.GetData();
|
||||
if (inheritableData.Behavior != defaultInheritableData.Behavior ||
|
||||
!EqualsInheritableData(inheritableData, defaultInheritableData))
|
||||
{
|
||||
changes[name] = inheritable.GetData();
|
||||
}
|
||||
}
|
||||
// If there's no default, then only set the value if it's not inherited
|
||||
else if (inheritable.Behavior != InheritableBehavior.Inherit)
|
||||
var inheritableData = inheritable.GetData();
|
||||
if (inheritableData.Behavior != defaultInheritableData.Behavior ||
|
||||
!EqualsInheritableData(inheritableData, defaultInheritableData))
|
||||
{
|
||||
changes[name] = inheritable.GetData();
|
||||
}
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
private static bool EqualsInheritableData(InheritableData data1, InheritableData data2)
|
||||
{
|
||||
if (data1.Value is List<XivChatType>)
|
||||
return EqualsInheritableDataListXivChatType<XivChatType>(data1, data2);
|
||||
else
|
||||
return data1.Value.Equals(data2.Value);
|
||||
}
|
||||
|
||||
private static bool EqualsInheritableDataListXivChatType<TEnum>(InheritableData data1, InheritableData data2)
|
||||
{
|
||||
var list1 = data1.Value as List<TEnum>;
|
||||
var list2 = data2.Value as List<TEnum>;
|
||||
|
||||
if (list1 is null || list2 is null || list1.Count != list2.Count)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < list1.Count; i++)
|
||||
{
|
||||
if (!list1[i].Equals(list2[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, string> ObsulteInheritableStringMap = new()
|
||||
{
|
||||
{ "IsIconVisibleInChat", nameof(IsRoleIconVisibleInChat) },
|
||||
{ "IsIconVisibleInNameplate", nameof(IsRoleIconVisibleInNameplates) },
|
||||
{ "IsIconVisibleInNameplates", nameof(IsRoleIconVisibleInNameplates) }
|
||||
};
|
||||
private static string FixObsuleteInheritableStringName(string name)
|
||||
{
|
||||
if (ObsulteInheritableStringMap.ContainsKey(name))
|
||||
return ObsulteInheritableStringMap[name];
|
||||
else
|
||||
return name;
|
||||
}
|
||||
|
||||
public void SetChanges(IEnumerable<KeyValuePair<string, InheritableData>> changes)
|
||||
{
|
||||
foreach ((var name, var inheritableData) in changes)
|
||||
{
|
||||
var namefixed = FixObsuleteInheritableStringName(name);
|
||||
Inheritables[namefixed].SetData(inheritableData);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, InheritableData> GetAllAsChanges()
|
||||
{
|
||||
Dictionary<string, InheritableData> changes = new Dictionary<string, InheritableData>();
|
||||
|
||||
foreach ((var name, var inheritable) in Inheritables)
|
||||
// If there's no default, then only set the value if it's not inherited
|
||||
else if (inheritable.Behavior != InheritableBehavior.Inherit)
|
||||
{
|
||||
changes[name] = inheritable.GetData();
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
public void SetDefaults()
|
||||
return changes;
|
||||
}
|
||||
|
||||
private static bool EqualsInheritableData(InheritableData data1, InheritableData data2)
|
||||
{
|
||||
if (data1.Value is List<XivChatType>)
|
||||
return EqualsInheritableDataListXivChatType<XivChatType>(data1, data2);
|
||||
else
|
||||
return data1.Value.Equals(data2.Value);
|
||||
}
|
||||
|
||||
private static bool EqualsInheritableDataListXivChatType<TEnum>(InheritableData data1, InheritableData data2)
|
||||
{
|
||||
var list1 = data1.Value as List<TEnum>;
|
||||
var list2 = data2.Value as List<TEnum>;
|
||||
|
||||
if (list1 is null || list2 is null || list1.Count != list2.Count)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < list1.Count; i++)
|
||||
{
|
||||
if (m_Defaults != null)
|
||||
{
|
||||
// Exclude IsSelected and IsExpanded for UX purposes
|
||||
SetChanges(m_Defaults.GetAllAsChanges().Where(change => change.Key != nameof(IsSelected) && change.Key != nameof(IsExpanded)));
|
||||
}
|
||||
if (!list1[i].Equals(list2[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, string> ObsulteInheritableStringMap = new()
|
||||
{
|
||||
{ "IsIconVisibleInChat", nameof(IsRoleIconVisibleInChat) },
|
||||
{ "IsIconVisibleInNameplate", nameof(IsRoleIconVisibleInNameplates) },
|
||||
{ "IsIconVisibleInNameplates", nameof(IsRoleIconVisibleInNameplates) }
|
||||
};
|
||||
private static string FixObsuleteInheritableStringName(string name)
|
||||
{
|
||||
if (ObsulteInheritableStringMap.ContainsKey(name))
|
||||
return ObsulteInheritableStringMap[name];
|
||||
else
|
||||
return name;
|
||||
}
|
||||
|
||||
public void SetChanges(IEnumerable<KeyValuePair<string, InheritableData>> changes)
|
||||
{
|
||||
foreach ((var name, var inheritableData) in changes)
|
||||
{
|
||||
var namefixed = FixObsuleteInheritableStringName(name);
|
||||
Inheritables[namefixed].SetData(inheritableData);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, InheritableData> GetAllAsChanges()
|
||||
{
|
||||
Dictionary<string, InheritableData> changes = [];
|
||||
|
||||
foreach ((var name, var inheritable) in Inheritables)
|
||||
{
|
||||
changes[name] = inheritable.GetData();
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
public void SetDefaults()
|
||||
{
|
||||
if (m_Defaults != null)
|
||||
{
|
||||
// Exclude IsSelected and IsExpanded for UX purposes
|
||||
SetChanges(m_Defaults.GetAllAsChanges().Where(change => change.Key != nameof(IsSelected) && change.Key != nameof(IsExpanded)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public enum TagPosition
|
||||
{
|
||||
public enum TagPosition
|
||||
{
|
||||
Before,
|
||||
After,
|
||||
Replace
|
||||
}
|
||||
Before,
|
||||
After,
|
||||
Replace
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace PlayerTags.Data
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
public enum TagTarget
|
||||
{
|
||||
public enum TagTarget
|
||||
{
|
||||
Chat,
|
||||
Nameplate
|
||||
}
|
||||
Chat,
|
||||
Nameplate
|
||||
}
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Pilz.Dalamud;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PlayerTags.Data
|
||||
{
|
||||
public static class WorldHelper
|
||||
{
|
||||
private static Dictionary<uint, string>? s_WorldNames = null;
|
||||
public static Dictionary<uint, string> WorldNames
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_WorldNames == null)
|
||||
{
|
||||
s_WorldNames = new Dictionary<uint, string>();
|
||||
namespace PlayerTags.Data;
|
||||
|
||||
var worlds = PluginServices.DataManager.GetExcelSheet<World>();
|
||||
if (worlds != null)
|
||||
public static class WorldHelper
|
||||
{
|
||||
private static Dictionary<uint, string>? s_WorldNames = null;
|
||||
public static Dictionary<uint, string> WorldNames
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_WorldNames == null)
|
||||
{
|
||||
s_WorldNames = [];
|
||||
|
||||
var worlds = PluginServices.DataManager.GetExcelSheet<World>();
|
||||
if (worlds != null)
|
||||
{
|
||||
foreach (var world in worlds)
|
||||
{
|
||||
foreach (var world in worlds)
|
||||
{
|
||||
s_WorldNames[world.RowId] = world.Name;
|
||||
}
|
||||
s_WorldNames[world.RowId] = world.Name.ParseString();
|
||||
}
|
||||
}
|
||||
|
||||
return s_WorldNames;
|
||||
}
|
||||
}
|
||||
|
||||
public static string? GetWorldName(uint? worldId)
|
||||
{
|
||||
if (worldId != null && WorldNames.TryGetValue(worldId.Value, out var name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
return null;
|
||||
return s_WorldNames;
|
||||
}
|
||||
}
|
||||
|
||||
public static string? GetWorldName(uint? worldId)
|
||||
{
|
||||
if (worldId != null && WorldNames.TryGetValue(worldId.Value, out var name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,35 @@
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PlayerTags
|
||||
namespace PlayerTags;
|
||||
|
||||
internal static class Extensions
|
||||
{
|
||||
internal static class Extensions
|
||||
/// <summary>
|
||||
/// Removes a Payload from a given SeString.
|
||||
/// Using <code>SeString.Payloads.Remove()</code> does not use the reference to compare for some reason. Tis is a workaround.
|
||||
/// </summary>
|
||||
/// <param name="seString"></param>
|
||||
/// <param name="payload"></param>
|
||||
public static void Remove(this SeString seString, Payload payload)
|
||||
{
|
||||
/// <summary>
|
||||
/// 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);
|
||||
}
|
||||
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)
|
||||
/// <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++)
|
||||
{
|
||||
for (int i = 0; i < payloads.Count; i++)
|
||||
if (ReferenceEquals(payloads[i], payload))
|
||||
{
|
||||
if (ReferenceEquals(payloads[i], payload))
|
||||
{
|
||||
payloads.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
payloads.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,435 +3,489 @@ using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Text;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Pilz.Dalamud;
|
||||
using Pilz.Dalamud.Tools.Strings;
|
||||
using PlayerTags.Configuration;
|
||||
using PlayerTags.Configuration.GameConfig;
|
||||
using PlayerTags.Data;
|
||||
using PlayerTags.Inheritables;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using Action = System.Action;
|
||||
|
||||
namespace PlayerTags.Features
|
||||
namespace PlayerTags.Features;
|
||||
|
||||
/// <summary>
|
||||
/// A feature that adds tags to chat messages.
|
||||
/// </summary>
|
||||
public class ChatTagTargetFeature : TagTargetFeature
|
||||
{
|
||||
/// <summary>
|
||||
/// A feature that adds tags to chat messages.
|
||||
/// A match found within a string.
|
||||
/// </summary>
|
||||
public class ChatTagTargetFeature : TagTargetFeature
|
||||
private class StringMatch(SeString seString)
|
||||
{
|
||||
/// <summary>
|
||||
/// A match found within a string.
|
||||
/// The string that the match was found in.
|
||||
/// </summary>
|
||||
private class StringMatch
|
||||
public SeString SeString { get; init; } = seString;
|
||||
|
||||
public List<Payload> DisplayTextPayloads { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// The matching game object if one exists
|
||||
/// </summary>
|
||||
public IGameObject? GameObject { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// A matching player payload if one exists.
|
||||
/// </summary>
|
||||
public PlayerPayload? PlayerPayload { get; init; }
|
||||
|
||||
public RawPayload LinkTerminatorPayload { get; init; }
|
||||
|
||||
public Payload? PlayerNamePayload
|
||||
{
|
||||
/// <summary>
|
||||
/// The string that the match was found in.
|
||||
/// </summary>
|
||||
public SeString SeString { get; init; }
|
||||
|
||||
public List<Payload> DisplayTextPayloads { get; init; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The matching game object if one exists
|
||||
/// </summary>
|
||||
public GameObject? GameObject { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// A matching player payload if one exists.
|
||||
/// </summary>
|
||||
public PlayerPayload? PlayerPayload { get; init; }
|
||||
|
||||
public RawPayload LinkTerminatorPayload { get; init; }
|
||||
|
||||
public Payload? PlayerNamePayload
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
Payload textPayload = null;
|
||||
string textMatch = GetMatchTextInternal();
|
||||
string textMatchShort = BuildPlayername(textMatch);
|
||||
Payload textPayload = null;
|
||||
string textMatch = GetMatchTextInternal();
|
||||
string textMatchShort = BuildPlayername(textMatch);
|
||||
|
||||
textPayload = DisplayTextPayloads.FirstOrDefault(n => n is TextPayload textPayload && (textPayload.Text.Contains(textMatch) || ((!string.IsNullOrEmpty(textMatchShort)) && textPayload.Text.Contains(textMatchShort))));
|
||||
textPayload ??= PlayerPayload;
|
||||
textPayload ??= DisplayTextPayloads.FirstOrDefault();
|
||||
textPayload = DisplayTextPayloads.FirstOrDefault(n => n is TextPayload textPayload && (textPayload.Text.Contains(textMatch) || ((!string.IsNullOrEmpty(textMatchShort)) && textPayload.Text.Contains(textMatchShort))));
|
||||
textPayload ??= PlayerPayload;
|
||||
textPayload ??= DisplayTextPayloads.FirstOrDefault();
|
||||
|
||||
return textPayload;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsLocalPlayer
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetMatchTextInternal() == PluginServices.ClientState.LocalPlayer.Name.TextValue;
|
||||
}
|
||||
}
|
||||
|
||||
public StringMatch(SeString seString)
|
||||
{
|
||||
SeString = seString;
|
||||
}
|
||||
|
||||
private string GetMatchTextInternal()
|
||||
{
|
||||
if (GameObject != null)
|
||||
return GameObject.Name.TextValue;
|
||||
else if (PlayerPayload != null)
|
||||
return PlayerPayload.PlayerName;
|
||||
else
|
||||
return SeString.TextValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the matches text.
|
||||
/// </summary>
|
||||
/// <returns>The match text.</returns>
|
||||
public string GetMatchText()
|
||||
{
|
||||
var playerNamePayload = PlayerNamePayload;
|
||||
if (playerNamePayload is PlayerPayload pp)
|
||||
return pp.PlayerName;
|
||||
else if (playerNamePayload is TextPayload tp)
|
||||
return tp.Text;
|
||||
else
|
||||
return SeString.TextValue;
|
||||
return textPayload;
|
||||
}
|
||||
}
|
||||
|
||||
public ChatTagTargetFeature(PluginConfiguration pluginConfiguration, PluginData pluginData) : base(pluginConfiguration, pluginData)
|
||||
public bool IsLocalPlayer
|
||||
{
|
||||
PluginServices.ChatGui.ChatMessage += Chat_ChatMessage;
|
||||
get => GetMatchTextInternal() == PluginServices.ClientState.LocalPlayer.Name.TextValue;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
private string GetMatchTextInternal()
|
||||
{
|
||||
PluginServices.ChatGui.ChatMessage -= Chat_ChatMessage;
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
AddTagsToChat(sender, type, true);
|
||||
AddTagsToChat(message, type, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool IsIconVisible(Tag tag)
|
||||
{
|
||||
if (tag.IsRoleIconVisibleInChat.InheritedValue != null)
|
||||
{
|
||||
return tag.IsRoleIconVisibleInChat.InheritedValue.Value;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsTextVisible(Tag tag)
|
||||
{
|
||||
if (tag.IsTextVisibleInChat.InheritedValue != null)
|
||||
{
|
||||
return tag.IsTextVisibleInChat.InheritedValue.Value;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (GameObject != null)
|
||||
return GameObject.Name.TextValue;
|
||||
else if (PlayerPayload != null)
|
||||
return PlayerPayload.PlayerName;
|
||||
else
|
||||
return SeString.TextValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the given string for game object matches.
|
||||
/// Gets the matches text.
|
||||
/// </summary>
|
||||
/// <param name="seString">The string to search.</param>
|
||||
/// <returns>A list of matched game objects.</returns>
|
||||
private List<StringMatch> GetStringMatches(SeString seString)
|
||||
/// <returns>The match text.</returns>
|
||||
public string GetMatchText()
|
||||
{
|
||||
List<StringMatch> stringMatches = new();
|
||||
Stack<PlayerPayload> curPlayerPayload = new();
|
||||
Stack<List<Payload>> curRefPayloads = new();
|
||||
var defaultRawPayload = RawPayload.LinkTerminator.Data;
|
||||
var playerNamePayload = PlayerNamePayload;
|
||||
if (playerNamePayload is PlayerPayload pp)
|
||||
return pp.PlayerName;
|
||||
else if (playerNamePayload is TextPayload tp)
|
||||
return tp.Text;
|
||||
else
|
||||
return SeString.TextValue;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var payload in seString.Payloads)
|
||||
public ChatTagTargetFeature(PluginConfiguration pluginConfiguration, PluginData pluginData) : base(pluginConfiguration, pluginData)
|
||||
{
|
||||
PluginServices.ChatGui.ChatMessage += ChatGui_ChatMessage;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
PluginServices.ChatGui.ChatMessage -= ChatGui_ChatMessage;
|
||||
base.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void ChatGui_ChatMessage(XivChatType type, int timestamp, ref SeString sender, ref SeString message, ref bool isHandled)
|
||||
{
|
||||
if (EnableGlobal && pluginConfiguration.GeneralOptions[ActivityContextManager.CurrentActivityContext.ActivityType].IsApplyTagsToAllChatMessagesEnabled)
|
||||
{
|
||||
AddTagsToChat(sender, type, true);
|
||||
AddTagsToChat(message, type, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool IsIconVisible(Tag tag)
|
||||
{
|
||||
if (tag.IsRoleIconVisibleInChat.InheritedValue != null)
|
||||
return tag.IsRoleIconVisibleInChat.InheritedValue.Value;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsTextVisible(Tag tag)
|
||||
{
|
||||
if (tag.IsTextVisibleInChat.InheritedValue != null)
|
||||
{
|
||||
return tag.IsTextVisibleInChat.InheritedValue.Value;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the given string for game object matches.
|
||||
/// </summary>
|
||||
/// <param name="seString">The string to search.</param>
|
||||
/// <returns>A list of matched game objects.</returns>
|
||||
private List<StringMatch> GetStringMatches(SeString seString)
|
||||
{
|
||||
List<StringMatch> stringMatches = [];
|
||||
Stack<PlayerPayload> curPlayerPayload = new();
|
||||
Stack<List<Payload>> curRefPayloads = new();
|
||||
var defaultRawPayload = RawPayload.LinkTerminator.Data;
|
||||
|
||||
foreach (var payload in seString.Payloads)
|
||||
{
|
||||
|
||||
if (payload is PlayerPayload playerPayload)
|
||||
{
|
||||
curPlayerPayload.Push(playerPayload);
|
||||
curRefPayloads.Push([]);
|
||||
}
|
||||
else if (payload is RawPayload rawPayload)
|
||||
{
|
||||
if (defaultRawPayload.SequenceEqual(rawPayload.Data))
|
||||
finishCurrentMatch(rawPayload);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (curRefPayloads.TryPeek(out List<Payload> result))
|
||||
result.Add(payload);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally finish, if not closed by RawPayload
|
||||
finishCurrentMatch(null);
|
||||
|
||||
void finishCurrentMatch(RawPayload linkTerminatorPayload)
|
||||
{
|
||||
if (curPlayerPayload.TryPop(out PlayerPayload playerPayload))
|
||||
{
|
||||
var gameObject = PluginServices.ObjectTable.FirstOrDefault(gameObject => gameObject.Name.TextValue == playerPayload.PlayerName);
|
||||
var stringMatch = new StringMatch(seString)
|
||||
{
|
||||
GameObject = gameObject,
|
||||
PlayerPayload = playerPayload,
|
||||
LinkTerminatorPayload = linkTerminatorPayload,
|
||||
DisplayTextPayloads = curRefPayloads.Pop()
|
||||
};
|
||||
stringMatches.Add(stringMatch);
|
||||
}
|
||||
}
|
||||
|
||||
return stringMatches;
|
||||
}
|
||||
|
||||
private void SplitOffPartyNumberPrefix(SeString sender, XivChatType type)
|
||||
{
|
||||
if (type == XivChatType.Party || type == XivChatType.Alliance)
|
||||
{
|
||||
PlayerPayload lastPlayerPayload = null;
|
||||
foreach (var payload in sender.Payloads.ToArray())
|
||||
{
|
||||
if (payload is PlayerPayload playerPayload)
|
||||
lastPlayerPayload = playerPayload;
|
||||
else if (payload is TextPayload playerNamePayload && lastPlayerPayload != null)
|
||||
{
|
||||
curPlayerPayload.Push(playerPayload);
|
||||
curRefPayloads.Push(new List<Payload>());
|
||||
}
|
||||
else if (payload is RawPayload rawPayload)
|
||||
{
|
||||
if (defaultRawPayload.SequenceEqual(rawPayload.Data))
|
||||
finishCurrentMatch(rawPayload);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (curRefPayloads.TryPeek(out List<Payload> result))
|
||||
result.Add(payload);
|
||||
}
|
||||
}
|
||||
// Get position of player name in payload
|
||||
var indexOfPlayerName = playerNamePayload.Text.IndexOf(BuildPlayername(lastPlayerPayload.PlayerName));
|
||||
|
||||
// Finally finish, if not closed by RawPayload
|
||||
finishCurrentMatch(null);
|
||||
if (indexOfPlayerName == -1)
|
||||
indexOfPlayerName = playerNamePayload.Text.IndexOf(lastPlayerPayload.PlayerName);
|
||||
|
||||
void finishCurrentMatch(RawPayload linkTerminatorPayload)
|
||||
{
|
||||
if (curPlayerPayload.TryPop(out PlayerPayload playerPayload))
|
||||
{
|
||||
var gameObject = PluginServices.ObjectTable.FirstOrDefault(gameObject => gameObject.Name.TextValue == playerPayload.PlayerName);
|
||||
var stringMatch = new StringMatch(seString)
|
||||
if (indexOfPlayerName > 0)
|
||||
{
|
||||
GameObject = gameObject,
|
||||
PlayerPayload = playerPayload,
|
||||
LinkTerminatorPayload = linkTerminatorPayload,
|
||||
DisplayTextPayloads = curRefPayloads.Pop()
|
||||
};
|
||||
stringMatches.Add(stringMatch);
|
||||
}
|
||||
}
|
||||
// Split off the name from the prefix number
|
||||
var prefixPayload = new TextPayload(playerNamePayload.Text[..indexOfPlayerName]);
|
||||
playerNamePayload.Text = playerNamePayload.Text[indexOfPlayerName..];
|
||||
|
||||
return stringMatches;
|
||||
}
|
||||
|
||||
private void SplitOffPartyNumberPrefix(SeString sender, XivChatType type)
|
||||
{
|
||||
if (type == XivChatType.Party || type == XivChatType.Alliance)
|
||||
{
|
||||
PlayerPayload lastPlayerPayload = null;
|
||||
foreach (var payload in sender.Payloads.ToArray())
|
||||
{
|
||||
if (payload is PlayerPayload playerPayload)
|
||||
lastPlayerPayload = playerPayload;
|
||||
else if (payload is TextPayload playerNamePayload && lastPlayerPayload != null)
|
||||
{
|
||||
// Get position of player name in payload
|
||||
var indexOfPlayerName = playerNamePayload.Text.IndexOf(BuildPlayername(lastPlayerPayload.PlayerName));
|
||||
|
||||
if (indexOfPlayerName == -1)
|
||||
indexOfPlayerName = playerNamePayload.Text.IndexOf(lastPlayerPayload.PlayerName);
|
||||
|
||||
if (indexOfPlayerName > 0)
|
||||
{
|
||||
// Split off the name from the prefix number
|
||||
var prefixPayload = new TextPayload(playerNamePayload.Text[..indexOfPlayerName]);
|
||||
playerNamePayload.Text = playerNamePayload.Text[indexOfPlayerName..];
|
||||
|
||||
// Add prefix number before the player name payload
|
||||
var playerNamePayloadIndex = sender.Payloads.IndexOf(playerNamePayload);
|
||||
sender.Payloads.Insert(playerNamePayloadIndex, prefixPayload);
|
||||
}
|
||||
// Add prefix number before the player name payload
|
||||
var playerNamePayloadIndex = sender.Payloads.IndexOf(playerNamePayload);
|
||||
sender.Payloads.Insert(playerNamePayloadIndex, prefixPayload);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ParsePayloadsForOwnPlayer(SeString seString, XivChatType chatType, bool isSender)
|
||||
{
|
||||
if (PluginServices.ClientState.LocalPlayer != null)
|
||||
{
|
||||
foreach (var payload in seString.Payloads.ToArray())
|
||||
{
|
||||
if (payload is TextPayload textPayload)
|
||||
{
|
||||
List<TextPayload> playerTextPayloads = new List<TextPayload>();
|
||||
|
||||
var playerName = PluginServices.ClientState.LocalPlayer.Name.TextValue;
|
||||
var playerNameShorted = BuildPlayername(playerName);
|
||||
|
||||
if (textPayload.Text == playerName || textPayload.Text == playerNameShorted)
|
||||
{
|
||||
playerTextPayloads.Add(textPayload);
|
||||
}
|
||||
else
|
||||
{
|
||||
var usedPlayerName = chatType == XivChatType.Party || chatType == XivChatType.Alliance ? playerNameShorted : playerName;
|
||||
var textMatchIndex = textPayload.Text.IndexOf(usedPlayerName);
|
||||
|
||||
while (textMatchIndex >= 0)
|
||||
{
|
||||
var textPayloadIndex = seString.Payloads.IndexOf(payload);
|
||||
|
||||
// Chop text to the left and insert it as a new payload
|
||||
if (textMatchIndex > 0)
|
||||
{
|
||||
// Add the content before the player
|
||||
seString.Payloads.Insert(textPayloadIndex++, new TextPayload(textPayload.Text.Substring(0, textMatchIndex)));
|
||||
|
||||
// Remove from the chopped text from the original payload
|
||||
textPayload.Text = textPayload.Text.Substring(textMatchIndex, textPayload.Text.Length - textMatchIndex);
|
||||
}
|
||||
|
||||
// This is the last reference to the local player in this payload
|
||||
if (textPayload.Text.Length == usedPlayerName.Length)
|
||||
{
|
||||
playerTextPayloads.Add(textPayload);
|
||||
break;
|
||||
}
|
||||
|
||||
// Create the new name payload and add it
|
||||
var playerTextPayload = new TextPayload(usedPlayerName);
|
||||
playerTextPayloads.Add(playerTextPayload);
|
||||
seString.Payloads.Insert(textPayloadIndex, playerTextPayload);
|
||||
|
||||
// Remove from the chopped text from the original payload
|
||||
textPayload.Text = textPayload.Text.Substring(usedPlayerName.Length);
|
||||
|
||||
textMatchIndex = textPayload.Text.IndexOf(usedPlayerName);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var playerTextPayload in playerTextPayloads)
|
||||
{
|
||||
// Fix displaying of abbreviated own player name as the game does this after the chat message handler
|
||||
playerTextPayload.Text = BuildPlayername(playerTextPayload.Text);
|
||||
|
||||
var playerPayload = new PlayerPayload(playerName, PluginServices.ClientState.LocalPlayer.HomeWorld.Id);
|
||||
int playerPayloadIndex = seString.Payloads.IndexOf(playerTextPayload);
|
||||
var hasNumberPrefix = isSender && (chatType == XivChatType.Party || chatType == XivChatType.Alliance);
|
||||
|
||||
// Ensure to include the group number prefix within the player link
|
||||
if (hasNumberPrefix)
|
||||
playerPayloadIndex--;
|
||||
|
||||
// Add the Player Link Payload
|
||||
seString.Payloads.Insert(playerPayloadIndex++, playerPayload);
|
||||
|
||||
// Same as above, but reverse
|
||||
if (hasNumberPrefix)
|
||||
playerPayloadIndex++;
|
||||
|
||||
// Add the Link Terminator to end the Player Link. This should be done behind the Text Payload (display text).
|
||||
// Normally used to end PlayerPayload linking. But for the own player it has no affect. Anyway, use it, just because. Maybe it's needed in the future somewhere else.
|
||||
seString.Payloads.Insert(++playerPayloadIndex, RawPayload.LinkTerminator);
|
||||
|
||||
// I M P O R T A N T N O T I C E:
|
||||
// The PlayerPayload is now just temporary. We keep the TextPayload.
|
||||
// The PayerPayload gets removed at the ChatTagTargetFeature at the end and the TextPayload will be keeped there.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all configured tags to a chat message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to change.</param>
|
||||
private void AddTagsToChat(SeString message, XivChatType chatType, bool isSender)
|
||||
{
|
||||
// Parse Payloads for local player to be able to work with in the following code
|
||||
ParsePayloadsForOwnPlayer(message, chatType, isSender);
|
||||
|
||||
// Split out the party/alliance number from the PlayerPayload
|
||||
if (isSender)
|
||||
SplitOffPartyNumberPrefix(message, chatType);
|
||||
|
||||
var stringMatches = GetStringMatches(message);
|
||||
foreach (var stringMatch in stringMatches)
|
||||
{
|
||||
StringChanges stringChanges = new();
|
||||
|
||||
bool isTagEnabled(Tag tag)
|
||||
=> tag.TagPositionInChat.InheritedValue != null && tag.TargetChatTypes.InheritedValue != null &&
|
||||
(tag.TargetChatTypes.InheritedValue.Contains(chatType) || (!Enum.IsDefined(chatType) && (tag.TargetChatTypesIncludeUndefined?.InheritedValue ?? false)));
|
||||
|
||||
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 (isTagEnabled(jobTag))
|
||||
{
|
||||
var payloads = GetPayloads(jobTag, stringMatch.GameObject);
|
||||
if (payloads.Any())
|
||||
{
|
||||
var insertBehindNumberPrefix = jobTag.InsertBehindNumberPrefixInChat?.Value ?? true;
|
||||
addPayloadChanges(jobTag, payloads);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add randomly generated name tag payload
|
||||
if (pluginConfiguration.IsPlayerNameRandomlyGenerated)
|
||||
{
|
||||
var playerName = stringMatch.GetMatchText();
|
||||
if (playerName != null)
|
||||
{
|
||||
var generatedName = BuildPlayername(RandomNameGenerator.Generate(playerName));
|
||||
if (generatedName != null)
|
||||
{
|
||||
AddPayloadChanges(StringPosition.Replace, Enumerable.Empty<Payload>().Append(new TextPayload(generatedName)), stringChanges, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add custom tags
|
||||
if (stringMatch.PlayerPayload != null)
|
||||
{
|
||||
Identity identity = pluginData.GetIdentity(stringMatch.PlayerPayload);
|
||||
foreach (var customTagId in identity.CustomTagIds)
|
||||
{
|
||||
var customTag = pluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
if (customTag != null)
|
||||
{
|
||||
if (isTagEnabled(customTag))
|
||||
{
|
||||
var customTagPayloads = GetPayloads(customTag, stringMatch.GameObject);
|
||||
if (customTagPayloads.Any())
|
||||
{
|
||||
var insertBehindNumberPrefix = customTag.InsertBehindNumberPrefixInChat?.Value ?? true;
|
||||
addPayloadChanges(customTag, customTagPayloads);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addPayloadChanges(Tag tag, IEnumerable<Payload> payloads)
|
||||
{
|
||||
var insertBehindNumberPrefix = tag.InsertBehindNumberPrefixInChat?.Value ?? true;
|
||||
var insertPositionInChat = tag.TagPositionInChat.InheritedValue.Value;
|
||||
AddPayloadChanges((StringPosition)insertPositionInChat, payloads, stringChanges, insertBehindNumberPrefix);
|
||||
}
|
||||
|
||||
// An additional step to apply text color to additional locations
|
||||
if (stringMatch.PlayerPayload != null && stringMatch.DisplayTextPayloads.Any())
|
||||
{
|
||||
Identity identity = pluginData.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))
|
||||
applyTextFormatting(jobTag);
|
||||
}
|
||||
|
||||
foreach (var customTagId in identity.CustomTagIds)
|
||||
{
|
||||
var customTag = pluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
if (customTag != null && isTagEnabled(customTag))
|
||||
applyTextFormatting(customTag);
|
||||
}
|
||||
|
||||
void applyTextFormatting(Tag tag)
|
||||
=> ApplyTextFormatting(stringMatch.GameObject, tag, new[] { message }, new[] { tag.IsTextColorAppliedToChatName }, stringMatch.DisplayTextPayloads);
|
||||
}
|
||||
|
||||
// Finally apply the all the changes to the message
|
||||
ApplyStringChanges(message, stringChanges, stringMatch.DisplayTextPayloads, stringMatch.PlayerNamePayload);
|
||||
|
||||
// Remove PlayerPayload and LinkTerminator if it's your own character (they just got added temporary)
|
||||
if (stringMatch.IsLocalPlayer)
|
||||
{
|
||||
if (stringMatch.PlayerPayload != null)
|
||||
message.Remove(stringMatch.PlayerPayload);
|
||||
if (stringMatch.LinkTerminatorPayload != null)
|
||||
message.Remove(stringMatch.LinkTerminatorPayload);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ParsePayloadsForOwnPlayer(SeString seString, XivChatType chatType, bool isSender)
|
||||
{
|
||||
if (PluginServices.ClientState.LocalPlayer != null)
|
||||
{
|
||||
foreach (var payload in seString.Payloads.ToArray())
|
||||
{
|
||||
if (payload is TextPayload textPayload)
|
||||
{
|
||||
List<TextPayload> playerTextPayloads = [];
|
||||
|
||||
var playerName = PluginServices.ClientState.LocalPlayer.Name.TextValue;
|
||||
var playerNameShorted = BuildPlayername(playerName);
|
||||
|
||||
if (textPayload.Text == playerName || textPayload.Text == playerNameShorted)
|
||||
{
|
||||
playerTextPayloads.Add(textPayload);
|
||||
}
|
||||
else
|
||||
{
|
||||
var usedPlayerName = chatType == XivChatType.Party || chatType == XivChatType.Alliance ? playerNameShorted : playerName;
|
||||
var textMatchIndex = textPayload.Text.IndexOf(usedPlayerName);
|
||||
|
||||
while (textMatchIndex >= 0)
|
||||
{
|
||||
var textPayloadIndex = seString.Payloads.IndexOf(payload);
|
||||
|
||||
// Chop text to the left and insert it as a new payload
|
||||
if (textMatchIndex > 0)
|
||||
{
|
||||
// Add the content before the player
|
||||
seString.Payloads.Insert(textPayloadIndex++, new TextPayload(textPayload.Text.Substring(0, textMatchIndex)));
|
||||
|
||||
// Remove from the chopped text from the original payload
|
||||
textPayload.Text = textPayload.Text.Substring(textMatchIndex, textPayload.Text.Length - textMatchIndex);
|
||||
}
|
||||
|
||||
// This is the last reference to the local player in this payload
|
||||
if (textPayload.Text.Length == usedPlayerName.Length)
|
||||
{
|
||||
playerTextPayloads.Add(textPayload);
|
||||
break;
|
||||
}
|
||||
|
||||
// Create the new name payload and add it
|
||||
var playerTextPayload = new TextPayload(usedPlayerName);
|
||||
playerTextPayloads.Add(playerTextPayload);
|
||||
seString.Payloads.Insert(textPayloadIndex, playerTextPayload);
|
||||
|
||||
// Remove from the chopped text from the original payload
|
||||
textPayload.Text = textPayload.Text.Substring(usedPlayerName.Length);
|
||||
|
||||
textMatchIndex = textPayload.Text.IndexOf(usedPlayerName);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var playerTextPayload in playerTextPayloads)
|
||||
{
|
||||
// Fix displaying of abbreviated own player name as the game does this after the chat message handler
|
||||
playerTextPayload.Text = BuildPlayername(playerTextPayload.Text);
|
||||
|
||||
var playerPayload = new PlayerPayload(playerName, PluginServices.ClientState.LocalPlayer.HomeWorld.RowId);
|
||||
int playerPayloadIndex = seString.Payloads.IndexOf(playerTextPayload);
|
||||
var hasNumberPrefix = isSender && (chatType == XivChatType.Party || chatType == XivChatType.Alliance);
|
||||
|
||||
// Ensure to include the group number prefix within the player link
|
||||
if (hasNumberPrefix)
|
||||
playerPayloadIndex--;
|
||||
|
||||
// Add the Player Link Payload
|
||||
seString.Payloads.Insert(playerPayloadIndex++, playerPayload);
|
||||
|
||||
// Same as above, but reverse
|
||||
if (hasNumberPrefix)
|
||||
playerPayloadIndex++;
|
||||
|
||||
// Add the Link Terminator to end the Player Link. This should be done behind the Text Payload (display text).
|
||||
// Normally used to end PlayerPayload linking. But for the own player it has no affect. Anyway, use it, just because. Maybe it's needed in the future somewhere else.
|
||||
seString.Payloads.Insert(++playerPayloadIndex, RawPayload.LinkTerminator);
|
||||
|
||||
// I M P O R T A N T N O T I C E:
|
||||
// The PlayerPayload is now just temporary. We keep the TextPayload.
|
||||
// The PayerPayload gets removed at the ChatTagTargetFeature at the end and the TextPayload will be keeped there.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all configured tags to a chat message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to change.</param>
|
||||
private void AddTagsToChat(SeString message, XivChatType chatType, bool isSender)
|
||||
{
|
||||
// Parse Payloads for local player to be able to work with in the following code
|
||||
ParsePayloadsForOwnPlayer(message, chatType, isSender);
|
||||
|
||||
// Split out the party/alliance number from the PlayerPayload
|
||||
if (isSender)
|
||||
SplitOffPartyNumberPrefix(message, chatType);
|
||||
|
||||
var stringMatches = GetStringMatches(message);
|
||||
foreach (var stringMatch in stringMatches)
|
||||
{
|
||||
StringChanges stringChanges = new();
|
||||
|
||||
bool isTagEnabled(Tag tag)
|
||||
=> tag.TagPositionInChat.InheritedValue != null && tag.TargetChatTypes.InheritedValue != null &&
|
||||
(tag.TargetChatTypes.InheritedValue.Contains(chatType) || (!Enum.IsDefined(chatType) && (tag.TargetChatTypesIncludeUndefined?.InheritedValue ?? false)));
|
||||
|
||||
if (stringMatch.GameObject is IPlayerCharacter playerCharacter)
|
||||
{
|
||||
// Add the job tag
|
||||
if (playerCharacter.ClassJob.ValueNullable is ClassJob classJob && pluginData.JobTags.TryGetValue(classJob.Abbreviation.ParseString(), out var jobTag))
|
||||
{
|
||||
if (isTagEnabled(jobTag))
|
||||
{
|
||||
var payloads = GetPayloads(jobTag, playerCharacter);
|
||||
if (payloads.Any())
|
||||
{
|
||||
var insertBehindNumberPrefix = jobTag.InsertBehindNumberPrefixInChat?.Value ?? true;
|
||||
addPayloadChanges(jobTag, payloads);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add randomly generated name tag payload
|
||||
if (pluginConfiguration.IsPlayerNameRandomlyGenerated)
|
||||
{
|
||||
var playerName = stringMatch.GetMatchText();
|
||||
if (playerName != null)
|
||||
{
|
||||
var generatedName = BuildPlayername(RandomNameGenerator.Generate(playerName));
|
||||
if (generatedName != null)
|
||||
{
|
||||
AddPayloadChanges(StringPosition.Replace, Enumerable.Empty<Payload>().Append(new TextPayload(generatedName)), stringChanges, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add custom tags
|
||||
if (stringMatch.PlayerPayload != null)
|
||||
{
|
||||
Identity identity = pluginData.GetIdentity(stringMatch.PlayerPayload);
|
||||
foreach (var customTagId in identity.CustomTagIds)
|
||||
{
|
||||
var customTag = pluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
if (customTag != null)
|
||||
{
|
||||
if (isTagEnabled(customTag))
|
||||
{
|
||||
var customTagPayloads = GetPayloads(customTag, stringMatch.GameObject);
|
||||
if (customTagPayloads.Any())
|
||||
{
|
||||
var insertBehindNumberPrefix = customTag.InsertBehindNumberPrefixInChat?.Value ?? true;
|
||||
addPayloadChanges(customTag, customTagPayloads);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addPayloadChanges(Tag tag, IEnumerable<Payload> payloads)
|
||||
{
|
||||
var insertBehindNumberPrefix = tag.InsertBehindNumberPrefixInChat?.Value ?? true;
|
||||
var insertPositionInChat = tag.TagPositionInChat.InheritedValue.Value;
|
||||
AddPayloadChanges((StringPosition)insertPositionInChat, payloads, stringChanges, insertBehindNumberPrefix);
|
||||
}
|
||||
|
||||
// An additional step to apply text color to additional locations
|
||||
if (stringMatch.PlayerPayload != null && stringMatch.DisplayTextPayloads.Any())
|
||||
{
|
||||
Identity identity = pluginData.GetIdentity(stringMatch.PlayerPayload);
|
||||
|
||||
if (stringMatch.GameObject is IPlayerCharacter playerCharacter1)
|
||||
{
|
||||
if (playerCharacter1.ClassJob.ValueNullable is ClassJob classJob && pluginData.JobTags.TryGetValue(classJob.Abbreviation.ParseString(), out var jobTag) && isTagEnabled(jobTag))
|
||||
applyTextFormatting(jobTag);
|
||||
}
|
||||
|
||||
foreach (var customTagId in identity.CustomTagIds)
|
||||
{
|
||||
var customTag = pluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
if (customTag != null && isTagEnabled(customTag))
|
||||
applyTextFormatting(customTag);
|
||||
}
|
||||
|
||||
void applyTextFormatting(Tag tag)
|
||||
=> ApplyTextFormatting(stringMatch.GameObject, tag, new[] { message }, new[] { tag.IsTextColorAppliedToChatName }, stringMatch.DisplayTextPayloads);
|
||||
}
|
||||
|
||||
// Finally apply the all the changes to the message
|
||||
ApplyStringChanges(message, stringChanges, stringMatch.DisplayTextPayloads, stringMatch.PlayerNamePayload);
|
||||
|
||||
// Remove PlayerPayload and LinkTerminator if it's your own character (they just got added temporary)
|
||||
if (stringMatch.IsLocalPlayer)
|
||||
{
|
||||
if (stringMatch.PlayerPayload != null)
|
||||
message.Remove(stringMatch.PlayerPayload);
|
||||
if (stringMatch.LinkTerminatorPayload != null)
|
||||
message.Remove(stringMatch.LinkTerminatorPayload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyTextFormatting(IGameObject? gameObject, Tag tag, SeString[] destStrings, InheritableValue<bool>[] textColorApplied, List<Payload> preferedPayloads, ushort? overwriteTextColor = null)
|
||||
{
|
||||
if (IsTagVisible(tag, gameObject))
|
||||
{
|
||||
for (int i = 0; i < destStrings.Length; i++)
|
||||
{
|
||||
var destString = destStrings[i];
|
||||
var isTextColorApplied = textColorApplied[i];
|
||||
applyTextColor(destString, isTextColorApplied, tag.TextColor);
|
||||
}
|
||||
}
|
||||
|
||||
void applyTextColor(SeString destPayload, InheritableValue<bool> enableFlag, InheritableValue<ushort> colorValue)
|
||||
{
|
||||
var colorToUse = overwriteTextColor ?? colorValue?.InheritedValue;
|
||||
if (shouldApplyFormattingPayloads(destPayload)
|
||||
&& enableFlag.InheritedValue != null
|
||||
&& enableFlag.InheritedValue.Value
|
||||
&& colorToUse != null)
|
||||
applyTextFormattingPayloads(destPayload, new UIForegroundPayload(colorToUse.Value), new UIForegroundPayload(0));
|
||||
}
|
||||
|
||||
bool shouldApplyFormattingPayloads(SeString destPayload)
|
||||
=> destPayload.Payloads.Any(payload => payload is TextPayload || payload is PlayerPayload);
|
||||
|
||||
void applyTextFormattingPayloads(SeString destPayload, Payload startPayload, Payload endPayload)
|
||||
{
|
||||
if (preferedPayloads == null || !preferedPayloads.Any())
|
||||
applyTextFormattingPayloadToStartAndEnd(destPayload, startPayload, endPayload);
|
||||
else
|
||||
applyTextFormattingPayloadsToSpecificPosition(destPayload, startPayload, endPayload, preferedPayloads);
|
||||
}
|
||||
|
||||
void applyTextFormattingPayloadToStartAndEnd(SeString destPayload, Payload startPayload, Payload endPayload)
|
||||
{
|
||||
destPayload.Payloads.Insert(0, startPayload);
|
||||
destPayload.Payloads.Add(endPayload);
|
||||
}
|
||||
|
||||
void applyTextFormattingPayloadsToSpecificPosition(SeString destPayload, Payload startPayload, Payload endPayload, List<Payload> preferedPayload)
|
||||
{
|
||||
int payloadStartIndex = destPayload.Payloads.IndexOf(preferedPayloads.First());
|
||||
destPayload.Payloads.Insert(payloadStartIndex, startPayload);
|
||||
|
||||
int payloadEndIndex = destPayload.Payloads.IndexOf(preferedPayloads.Last());
|
||||
destPayload.Payloads.Insert(payloadEndIndex + 1, endPayload);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies changes to the given string.
|
||||
/// </summary>
|
||||
/// <param name="seString">The string to apply changes to.</param>
|
||||
/// <param name="stringChanges">The changes to apply.</param>
|
||||
/// <param name="anchorPayload">The payload in the string that changes should be anchored to. If there is no anchor, the changes will be applied to the entire string.</param>
|
||||
protected void ApplyStringChanges(SeString seString, StringChanges stringChanges, List<Payload> anchorPayloads = null, Payload anchorReplacePayload = null)
|
||||
{
|
||||
var props = new StringChangesProps
|
||||
{
|
||||
Destination = seString,
|
||||
AnchorPayload = anchorReplacePayload,
|
||||
AnchorPayloads = anchorPayloads,
|
||||
StringChanges = stringChanges
|
||||
};
|
||||
|
||||
StringUpdateFactory.ApplyStringChanges(props);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Dalamud.ContextMenu;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Logging;
|
||||
using Dalamud.Game.Gui.ContextMenu;
|
||||
using PlayerTags.Configuration;
|
||||
using PlayerTags.Data;
|
||||
using PlayerTags.Resources;
|
||||
@@ -8,88 +6,81 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace PlayerTags.Features
|
||||
namespace PlayerTags.Features;
|
||||
|
||||
/// <summary>
|
||||
/// A feature that adds options for the management of custom tags to context menus.
|
||||
/// </summary>
|
||||
public class CustomTagsContextMenuFeature : FeatureBase, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// A feature that adds options for the management of custom tags to context menus.
|
||||
/// </summary>
|
||||
public class CustomTagsContextMenuFeature : FeatureBase, IDisposable
|
||||
private readonly string[] supportedAddonNames =
|
||||
[
|
||||
null,
|
||||
"_PartyList",
|
||||
"ChatLog",
|
||||
"ContactList",
|
||||
"ContentMemberList",
|
||||
"CrossWorldLinkshell",
|
||||
"FreeCompany",
|
||||
"FriendList",
|
||||
"LookingForGroup",
|
||||
"LinkShell",
|
||||
"PartyMemberList",
|
||||
"SocialList",
|
||||
];
|
||||
|
||||
public CustomTagsContextMenuFeature(PluginConfiguration pluginConfiguration, PluginData pluginData) : base(pluginConfiguration, pluginData)
|
||||
{
|
||||
private string?[] SupportedAddonNames = new string?[]
|
||||
{
|
||||
null,
|
||||
"_PartyList",
|
||||
"ChatLog",
|
||||
"ContactList",
|
||||
"ContentMemberList",
|
||||
"CrossWorldLinkshell",
|
||||
"FreeCompany",
|
||||
"FriendList",
|
||||
"LookingForGroup",
|
||||
"LinkShell",
|
||||
"PartyMemberList",
|
||||
"SocialList",
|
||||
};
|
||||
PluginServices.ContextMenu.OnMenuOpened += ContextMenu_OnMenuOpened; ;
|
||||
}
|
||||
|
||||
private DalamudContextMenu? m_ContextMenu;
|
||||
public void Dispose()
|
||||
{
|
||||
PluginServices.ContextMenu.OnMenuOpened -= ContextMenu_OnMenuOpened;
|
||||
}
|
||||
|
||||
public CustomTagsContextMenuFeature(PluginConfiguration pluginConfiguration, PluginData pluginData) : base(pluginConfiguration, pluginData)
|
||||
{
|
||||
m_ContextMenu = new DalamudContextMenu();
|
||||
m_ContextMenu.OnOpenGameObjectContextMenu += ContextMenuHooks_ContextMenuOpened;
|
||||
}
|
||||
private void ContextMenu_OnMenuOpened(IMenuOpenedArgs args)
|
||||
{
|
||||
if (!EnableGlobal || !pluginConfiguration.IsCustomTagsContextMenuEnabled
|
||||
|| args.MenuType != ContextMenuType.Default
|
||||
|| args.Target is not MenuTargetDefault menuTarget
|
||||
|| !supportedAddonNames.Contains(args.AddonName))
|
||||
return;
|
||||
|
||||
public void Dispose()
|
||||
Identity? identity = pluginData.GetIdentity(menuTarget);
|
||||
if (identity != null)
|
||||
{
|
||||
if (m_ContextMenu != null)
|
||||
var allTags = new Dictionary<Tag, bool>();
|
||||
foreach (var customTag in pluginData.CustomTags)
|
||||
{
|
||||
m_ContextMenu.OnOpenGameObjectContextMenu -= ContextMenuHooks_ContextMenuOpened;
|
||||
((IDisposable)m_ContextMenu).Dispose();
|
||||
m_ContextMenu = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void ContextMenuHooks_ContextMenuOpened(GameObjectContextMenuOpenArgs contextMenuOpenedArgs)
|
||||
{
|
||||
if (!EnableGlobal || !pluginConfiguration.IsCustomTagsContextMenuEnabled
|
||||
|| !SupportedAddonNames.Contains(contextMenuOpenedArgs.ParentAddonName))
|
||||
{
|
||||
return;
|
||||
var isAdded = identity.CustomTagIds.Contains(customTag.CustomId.Value);
|
||||
allTags.Add(customTag, isAdded);
|
||||
}
|
||||
|
||||
Identity? identity = pluginData.GetIdentity(contextMenuOpenedArgs);
|
||||
if (identity != null)
|
||||
var sortedTags = allTags.OrderBy(n => n.Value);
|
||||
foreach (var tag in sortedTags)
|
||||
{
|
||||
var allTags = new Dictionary<Tag, bool>();
|
||||
foreach (var customTag in pluginData.CustomTags)
|
||||
{
|
||||
var isAdded = identity.CustomTagIds.Contains(customTag.CustomId.Value);
|
||||
allTags.Add(customTag, isAdded);
|
||||
}
|
||||
|
||||
var sortedTags = allTags.OrderBy(n => n.Value);
|
||||
foreach (var tag in sortedTags)
|
||||
{
|
||||
string menuItemText;
|
||||
if (tag.Value)
|
||||
menuItemText = Strings.Loc_Static_ContextMenu_RemoveTag;
|
||||
else
|
||||
menuItemText = Strings.Loc_Static_ContextMenu_AddTag;
|
||||
menuItemText = string.Format(menuItemText, tag.Key.Text.Value);
|
||||
string menuItemText;
|
||||
if (tag.Value)
|
||||
menuItemText = Strings.Loc_Static_ContextMenu_RemoveTag;
|
||||
else
|
||||
menuItemText = Strings.Loc_Static_ContextMenu_AddTag;
|
||||
menuItemText = string.Format(menuItemText, tag.Key.Text.Value);
|
||||
|
||||
contextMenuOpenedArgs.AddCustomItem(
|
||||
new GameObjectContextMenuItem(menuItemText, openedEventArgs =>
|
||||
{
|
||||
if (tag.Value)
|
||||
pluginData.RemoveCustomTagFromIdentity(tag.Key, identity);
|
||||
else
|
||||
pluginData.AddCustomTagToIdentity(tag.Key, identity);
|
||||
pluginConfiguration.Save(pluginData);
|
||||
})
|
||||
{
|
||||
IsSubMenu = false
|
||||
});
|
||||
}
|
||||
args.AddMenuItem(new()
|
||||
{
|
||||
IsSubmenu = false,
|
||||
IsEnabled = true,
|
||||
Name = menuItemText,
|
||||
OnClicked = openedEventArgs =>
|
||||
{
|
||||
if (tag.Value)
|
||||
pluginData.RemoveCustomTagFromIdentity(tag.Key, identity);
|
||||
else
|
||||
pluginData.AddCustomTagToIdentity(tag.Key, identity);
|
||||
pluginConfiguration.Save(pluginData);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
using PlayerTags.Configuration;
|
||||
using PlayerTags.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PlayerTags.Features
|
||||
namespace PlayerTags.Features;
|
||||
|
||||
public class FeatureBase
|
||||
{
|
||||
public class FeatureBase
|
||||
protected readonly PluginConfiguration pluginConfiguration;
|
||||
protected readonly PluginData pluginData;
|
||||
|
||||
public virtual bool EnableGlobal => pluginConfiguration.EnabledGlobal;
|
||||
|
||||
protected FeatureBase(PluginConfiguration pluginConfiguration, PluginData pluginData)
|
||||
{
|
||||
protected readonly PluginConfiguration pluginConfiguration;
|
||||
protected readonly PluginData pluginData;
|
||||
|
||||
public virtual bool EnableGlobal => pluginConfiguration.EnabledGlobal;
|
||||
|
||||
protected FeatureBase(PluginConfiguration pluginConfiguration, PluginData pluginData)
|
||||
{
|
||||
this.pluginConfiguration = pluginConfiguration;
|
||||
this.pluginData = pluginData;
|
||||
}
|
||||
this.pluginConfiguration = pluginConfiguration;
|
||||
this.pluginData = pluginData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,283 +1,223 @@
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Gui.NamePlate;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Memory;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Pilz.Dalamud;
|
||||
using Pilz.Dalamud.Icons;
|
||||
using Pilz.Dalamud.Nameplates.Tools;
|
||||
using Pilz.Dalamud.Tools.NamePlates;
|
||||
using Pilz.Dalamud.Tools.Strings;
|
||||
using PlayerTags.Configuration;
|
||||
using PlayerTags.Data;
|
||||
using PlayerTags.GameInterface.Nameplates;
|
||||
using PlayerTags.Inheritables;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace PlayerTags.Features
|
||||
namespace PlayerTags.Features;
|
||||
|
||||
/// <summary>
|
||||
/// A feature that adds tags to nameplates.
|
||||
/// </summary>
|
||||
public class NameplateTagTargetFeature : TagTargetFeature
|
||||
{
|
||||
/// <summary>
|
||||
/// A feature that adds tags to nameplates.
|
||||
/// </summary>
|
||||
public class NameplateTagTargetFeature : TagTargetFeature
|
||||
private readonly StatusIconPriorizer statusiconPriorizer;
|
||||
private readonly JobIconSets jobIconSets = new();
|
||||
|
||||
public NameplateTagTargetFeature(PluginConfiguration pluginConfiguration, PluginData pluginData) : base(pluginConfiguration, pluginData)
|
||||
{
|
||||
private readonly StatusIconPriorizer statusiconPriorizer;
|
||||
private readonly JobIconSets jobIconSets = new();
|
||||
private Nameplate? m_Nameplate;
|
||||
statusiconPriorizer = new(pluginConfiguration.StatusIconPriorizerSettings);
|
||||
PluginServices.NamePlateGui.OnNamePlateUpdate += NamePlateGui_OnNamePlateUpdate;
|
||||
}
|
||||
|
||||
public NameplateTagTargetFeature(PluginConfiguration pluginConfiguration, PluginData pluginData) : base(pluginConfiguration, pluginData)
|
||||
public override void Dispose()
|
||||
{
|
||||
PluginServices.NamePlateGui.OnNamePlateUpdate -= NamePlateGui_OnNamePlateUpdate;
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
protected override bool IsIconVisible(Tag tag)
|
||||
{
|
||||
if (tag.IsRoleIconVisibleInNameplates.InheritedValue != null)
|
||||
return tag.IsRoleIconVisibleInNameplates.InheritedValue.Value;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsTextVisible(Tag tag)
|
||||
{
|
||||
if (tag.IsTextVisibleInNameplates.InheritedValue != null)
|
||||
return tag.IsTextVisibleInNameplates.InheritedValue.Value;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void NamePlateGui_OnNamePlateUpdate(INamePlateUpdateContext context, IReadOnlyList<INamePlateUpdateHandler> handlers)
|
||||
{
|
||||
if (!EnableGlobal)
|
||||
return;
|
||||
|
||||
foreach (var handler in handlers)
|
||||
{
|
||||
statusiconPriorizer = new(pluginConfiguration.StatusIconPriorizerSettings);
|
||||
// Only handle player nameplates
|
||||
if (handler.NamePlateKind != NamePlateKind.PlayerCharacter || handler.PlayerCharacter == null)
|
||||
continue;
|
||||
|
||||
PluginServices.ClientState.Login += ClientState_Login;
|
||||
PluginServices.ClientState.Logout += ClientState_Logout;
|
||||
|
||||
Hook();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
Unhook();
|
||||
|
||||
PluginServices.ClientState.Logout -= ClientState_Logout;
|
||||
PluginServices.ClientState.Login -= ClientState_Login;
|
||||
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
private void Hook()
|
||||
{
|
||||
if (m_Nameplate == null)
|
||||
{
|
||||
m_Nameplate = new Nameplate();
|
||||
if (!m_Nameplate.IsValid)
|
||||
{
|
||||
m_Nameplate = null;
|
||||
}
|
||||
|
||||
if (m_Nameplate != null)
|
||||
{
|
||||
m_Nameplate.PlayerNameplateUpdated += Nameplate_PlayerNameplateUpdated;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Unhook()
|
||||
{
|
||||
if (m_Nameplate != null)
|
||||
{
|
||||
m_Nameplate.PlayerNameplateUpdated -= Nameplate_PlayerNameplateUpdated;
|
||||
m_Nameplate.Dispose();
|
||||
m_Nameplate = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClientState_Login(object? sender, EventArgs e)
|
||||
{
|
||||
Hook();
|
||||
}
|
||||
|
||||
private void ClientState_Logout(object? sender, EventArgs e)
|
||||
{
|
||||
Unhook();
|
||||
}
|
||||
|
||||
protected override bool IsIconVisible(Tag tag)
|
||||
{
|
||||
if (tag.IsRoleIconVisibleInNameplates.InheritedValue != null)
|
||||
{
|
||||
return tag.IsRoleIconVisibleInNameplates.InheritedValue.Value;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsTextVisible(Tag tag)
|
||||
{
|
||||
if (tag.IsTextVisibleInNameplates.InheritedValue != null)
|
||||
{
|
||||
return tag.IsTextVisibleInNameplates.InheritedValue.Value;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private unsafe void Nameplate_PlayerNameplateUpdated(PlayerNameplateUpdatedArgs args)
|
||||
{
|
||||
if (!EnableGlobal) return;
|
||||
|
||||
var beforeTitleBytes = args.Title.Encode();
|
||||
var iconID = args.IconId;
|
||||
var beforeTitleBytes = handler.InfoView.Title.Encode();
|
||||
var generalOptions = pluginConfiguration.GeneralOptions[ActivityContextManager.CurrentActivityContext.ActivityType];
|
||||
|
||||
AddTagsToNameplate(args.PlayerCharacter, args.Name, args.Title, args.FreeCompany, ref iconID, generalOptions);
|
||||
|
||||
args.IconId = iconID;
|
||||
AddTagsToNameplate(handler, generalOptions);
|
||||
|
||||
if (generalOptions.NameplateTitlePosition == NameplateTitlePosition.AlwaysAboveName)
|
||||
args.IsTitleAboveName = true;
|
||||
handler.IsPrefixTitle = true;
|
||||
else if (generalOptions.NameplateTitlePosition == NameplateTitlePosition.AlwaysBelowName)
|
||||
args.IsTitleAboveName = false;
|
||||
handler.IsPrefixTitle = false;
|
||||
|
||||
if (generalOptions.NameplateTitleVisibility == NameplateTitleVisibility.Always)
|
||||
args.IsTitleVisible = true;
|
||||
handler.DisplayTitle = true;
|
||||
else if (generalOptions.NameplateTitleVisibility == NameplateTitleVisibility.Never)
|
||||
args.IsTitleVisible = false;
|
||||
handler.DisplayTitle = false;
|
||||
else if (generalOptions.NameplateTitleVisibility == NameplateTitleVisibility.WhenHasTags)
|
||||
{
|
||||
bool hasTitleChanged = !beforeTitleBytes.SequenceEqual(args.Title.Encode());
|
||||
args.IsTitleVisible = hasTitleChanged;
|
||||
}
|
||||
handler.DisplayTitle = !beforeTitleBytes.SequenceEqual(handler.InfoView.Title.Encode());
|
||||
|
||||
if (generalOptions.NameplateFreeCompanyVisibility == NameplateFreeCompanyVisibility.Never)
|
||||
args.FreeCompany.Payloads.Clear();
|
||||
handler.RemoveFreeCompanyTag();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given payload changes to the specified locations.
|
||||
/// </summary>
|
||||
/// <param name="nameplateElement">The nameplate element of the changes.</param>
|
||||
/// <param name="tagPosition">The position of the changes.</param>
|
||||
/// <param name="payloadChanges">The payload changes to add.</param>
|
||||
/// <param name="nameplateChanges">The dictionary to add changes to.</param>
|
||||
private void AddPayloadChanges(NameplateElement nameplateElement, TagPosition tagPosition, IEnumerable<Payload> payloadChanges, NameplateChanges nameplateChanges, bool forceUsingSingleAnchorPayload)
|
||||
/// <summary>
|
||||
/// Adds the given payload changes to the specified locations.
|
||||
/// </summary>
|
||||
/// <param name="nameplateElement">The nameplate element of the changes.</param>
|
||||
/// <param name="tagPosition">The position of the changes.</param>
|
||||
/// <param name="payloadChanges">The payload changes to add.</param>
|
||||
/// <param name="nameplateChanges">The dictionary to add changes to.</param>
|
||||
private void AddPayloadChanges(NameplateElement nameplateElement, TagPosition tagPosition, IEnumerable<Payload> payloadChanges, NameplateChanges nameplateChanges, bool forceUsingSingleAnchorPayload)
|
||||
{
|
||||
if (payloadChanges.Any())
|
||||
{
|
||||
if (payloadChanges.Any())
|
||||
var changes = nameplateChanges.GetChange((NameplateElements)nameplateElement);
|
||||
AddPayloadChanges((StringPosition)tagPosition, payloadChanges, changes.Changes, forceUsingSingleAnchorPayload);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds tags to the nameplate of a game object.
|
||||
/// </summary>
|
||||
/// <param name="playerCharacter">The game object context.</param>
|
||||
/// <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(INamePlateUpdateHandler handler, GeneralOptionsClass generalOptions)
|
||||
{
|
||||
int? newStatusIcon = null;
|
||||
var nameplateChanges = new NameplateChanges(handler);
|
||||
|
||||
if (handler.PlayerCharacter != null && (!handler.PlayerCharacter.IsDead || generalOptions.NameplateDeadPlayerHandling != DeadPlayerHandling.Ignore))
|
||||
{
|
||||
var classJob = handler.PlayerCharacter.ClassJob.ValueNullable;
|
||||
|
||||
// Add the job tags
|
||||
if (classJob.HasValue && pluginData.JobTags.TryGetValue(classJob.Value.Abbreviation.ParseString(), out var jobTag))
|
||||
{
|
||||
var changes = nameplateChanges.GetChanges((NameplateElements)nameplateElement);
|
||||
AddPayloadChanges((StringPosition)tagPosition, payloadChanges, changes, forceUsingSingleAnchorPayload);
|
||||
if (jobTag.TagTargetInNameplates.InheritedValue != null && jobTag.TagPositionInNameplates.InheritedValue != null)
|
||||
checkTag(jobTag);
|
||||
}
|
||||
}
|
||||
|
||||
private NameplateChanges GenerateEmptyNameplateChanges(SeString name, SeString title, SeString freeCompany)
|
||||
{
|
||||
NameplateChanges nameplateChanges = new();
|
||||
|
||||
nameplateChanges.GetProps(NameplateElements.Name).Destination = name;
|
||||
nameplateChanges.GetProps(NameplateElements.Title).Destination = title;
|
||||
nameplateChanges.GetProps(NameplateElements.FreeCompany).Destination = freeCompany;
|
||||
|
||||
return nameplateChanges;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds tags to the nameplate of a game object.
|
||||
/// </summary>
|
||||
/// <param name="gameObject">The game object context.</param>
|
||||
/// <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)
|
||||
{
|
||||
var playerCharacter = gameObject as PlayerCharacter;
|
||||
int? newStatusIcon = null;
|
||||
NameplateChanges nameplateChanges = GenerateEmptyNameplateChanges(name, title, freeCompany);
|
||||
|
||||
if (playerCharacter != null && (!playerCharacter.IsDead || generalOptions.NameplateDeadPlayerHandling != DeadPlayerHandling.Ignore))
|
||||
// Add the randomly generated name tag payload
|
||||
if (pluginConfiguration.IsPlayerNameRandomlyGenerated)
|
||||
{
|
||||
var classJob = playerCharacter.ClassJob;
|
||||
var classJobGameData = classJob?.GameData;
|
||||
|
||||
// Add the job tags
|
||||
if (classJobGameData != null && pluginData.JobTags.TryGetValue(classJobGameData.Abbreviation, out var jobTag))
|
||||
var characterName = handler.PlayerCharacter.Name.TextValue;
|
||||
if (characterName != null)
|
||||
{
|
||||
if (jobTag.TagTargetInNameplates.InheritedValue != null && jobTag.TagPositionInNameplates.InheritedValue != null)
|
||||
checkTag(jobTag);
|
||||
}
|
||||
|
||||
// Add the randomly generated name tag payload
|
||||
if (pluginConfiguration.IsPlayerNameRandomlyGenerated)
|
||||
{
|
||||
var characterName = playerCharacter.Name.TextValue;
|
||||
if (characterName != null)
|
||||
{
|
||||
var generatedName = RandomNameGenerator.Generate(characterName);
|
||||
if (generatedName != null)
|
||||
AddPayloadChanges(NameplateElement.Name, TagPosition.Replace, Enumerable.Empty<Payload>().Append(new TextPayload(generatedName)), nameplateChanges, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Add custom tags
|
||||
Identity identity = pluginData.GetIdentity(playerCharacter);
|
||||
foreach (var customTagId in identity.CustomTagIds)
|
||||
{
|
||||
var customTag = pluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
if (customTag != null)
|
||||
checkTag(customTag);
|
||||
}
|
||||
|
||||
void checkTag(Tag tag)
|
||||
{
|
||||
if (tag.TagTargetInNameplates.InheritedValue != null && tag.TagPositionInNameplates.InheritedValue != null)
|
||||
{
|
||||
var payloads = GetPayloads(tag, gameObject);
|
||||
if (payloads.Any())
|
||||
AddPayloadChanges(tag.TagTargetInNameplates.InheritedValue.Value, tag.TagPositionInNameplates.InheritedValue.Value, payloads, nameplateChanges, false);
|
||||
}
|
||||
if (IsTagVisible(tag, gameObject) && newStatusIcon == null && classJob != null && (tag.IsJobIconVisibleInNameplates?.InheritedValue ?? false))
|
||||
newStatusIcon = jobIconSets.GetJobIcon(tag.JobIconSet?.InheritedValue ?? JobIconSetName.Framed, classJob.Id);
|
||||
var generatedName = RandomNameGenerator.Generate(characterName);
|
||||
if (generatedName != null)
|
||||
AddPayloadChanges(NameplateElement.Name, TagPosition.Replace, Enumerable.Empty<Payload>().Append(new TextPayload(generatedName)), nameplateChanges, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply new status icon
|
||||
if (newStatusIcon != null)
|
||||
// Add custom tags
|
||||
Identity identity = pluginData.GetIdentity(handler.PlayerCharacter);
|
||||
foreach (var customTagId in identity.CustomTagIds)
|
||||
{
|
||||
var change = nameplateChanges.GetChange(NameplateElements.Name, StringPosition.Before);
|
||||
NameplateUpdateFactory.ApplyStatusIconWithPrio(ref statusIcon, (int)newStatusIcon, change, ActivityContextManager.CurrentActivityContext, statusiconPriorizer, pluginConfiguration.MoveStatusIconToNameplateTextIfPossible);
|
||||
var customTag = pluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
if (customTag != null)
|
||||
checkTag(customTag);
|
||||
}
|
||||
|
||||
// Gray out the nameplate
|
||||
if (playerCharacter != null && playerCharacter.IsDead && generalOptions.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))
|
||||
void checkTag(Tag tag)
|
||||
{
|
||||
// An additional step to apply text color to additional locations
|
||||
Identity identity = pluginData.GetIdentity(playerCharacter);
|
||||
foreach (var customTagId in identity.CustomTagIds)
|
||||
if (tag.TagTargetInNameplates.InheritedValue != null && tag.TagPositionInNameplates.InheritedValue != null)
|
||||
{
|
||||
var customTag = pluginData.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))
|
||||
applyTextFormatting(jobTag);
|
||||
|
||||
void applyTextFormatting(Tag tag)
|
||||
{
|
||||
var destStrings = new[] { name, title, freeCompany };
|
||||
var isTextColorApplied = new[] { tag.IsTextColorAppliedToNameplateName, tag.IsTextColorAppliedToNameplateTitle, tag.IsTextColorAppliedToNameplateFreeCompany };
|
||||
ApplyTextFormatting(gameObject, tag, new[] { name, title, freeCompany }, isTextColorApplied, null);
|
||||
var payloads = GetPayloads(tag, handler.PlayerCharacter);
|
||||
if (payloads.Length != 0)
|
||||
AddPayloadChanges(tag.TagTargetInNameplates.InheritedValue.Value, tag.TagPositionInNameplates.InheritedValue.Value, payloads, nameplateChanges, false);
|
||||
}
|
||||
if (IsTagVisible(tag, handler.PlayerCharacter) && newStatusIcon == null && classJob != null && (tag.IsJobIconVisibleInNameplates?.InheritedValue ?? false))
|
||||
newStatusIcon = jobIconSets.GetJobIcon(tag.JobIconSet?.InheritedValue ?? JobIconSetName.Framed, classJob.Value.RowId);
|
||||
}
|
||||
}
|
||||
|
||||
private void GrayOutNameplate(GameObject gameObject, NameplateChanges nameplateChanges)
|
||||
// Apply new status icon
|
||||
if (newStatusIcon != null)
|
||||
{
|
||||
if (gameObject is PlayerCharacter playerCharacter)
|
||||
{
|
||||
foreach (NameplateElements element in Enum.GetValues<NameplateElements>())
|
||||
{
|
||||
nameplateChanges.GetChange(element, StringPosition.Before).Payloads.Add(new UIForegroundPayload(3));
|
||||
nameplateChanges.GetChange(element, StringPosition.After).Payloads.Add(new UIForegroundPayload(0));
|
||||
}
|
||||
}
|
||||
NameplateUpdateFactory.ApplyStatusIconWithPrio(handler, (int)newStatusIcon, ActivityContextManager.CurrentActivityContext, statusiconPriorizer, pluginConfiguration.MoveStatusIconToNameplateTextIfPossible);
|
||||
}
|
||||
|
||||
protected void ApplyNameplateChanges(NameplateChanges nameplateChanges)
|
||||
// Build the final strings out of the payloads
|
||||
NameplateUpdateFactory.ApplyNameplateChanges(new NameplateChangesProps
|
||||
{
|
||||
var props = new NameplateChangesProps
|
||||
Changes = nameplateChanges
|
||||
});
|
||||
|
||||
// Gray out the nameplate
|
||||
if (handler.PlayerCharacter != null && handler.PlayerCharacter.IsDead && generalOptions.NameplateDeadPlayerHandling == DeadPlayerHandling.GrayOut)
|
||||
GrayOutNameplate(handler.PlayerCharacter, nameplateChanges);
|
||||
|
||||
// Apply text color
|
||||
if (handler.PlayerCharacter != null && (!handler.PlayerCharacter.IsDead || generalOptions.NameplateDeadPlayerHandling == DeadPlayerHandling.Include))
|
||||
{
|
||||
Identity identity = pluginData.GetIdentity(handler.PlayerCharacter);
|
||||
foreach (var customTagId in identity.CustomTagIds)
|
||||
{
|
||||
Changes = nameplateChanges
|
||||
};
|
||||
NameplateUpdateFactory.ApplyNameplateChanges(props);
|
||||
var customTag = pluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
|
||||
if (customTag != null)
|
||||
applyTextFormatting(customTag);
|
||||
}
|
||||
|
||||
if (handler.PlayerCharacter.ClassJob.ValueNullable is ClassJob classJob && pluginData.JobTags.TryGetValue(classJob.Abbreviation.ParseString(), out var jobTag))
|
||||
applyTextFormatting(jobTag);
|
||||
|
||||
void applyTextFormatting(Tag tag)
|
||||
{
|
||||
var dic = new Dictionary<NameplateElementChange, InheritableValue<bool>>
|
||||
{
|
||||
{ nameplateChanges.GetChange(NameplateElements.Name), tag.IsTextColorAppliedToNameplateName },
|
||||
{ nameplateChanges.GetChange(NameplateElements.Title), tag.IsTextColorAppliedToNameplateTitle },
|
||||
{ nameplateChanges.GetChange(NameplateElements.FreeCompany), tag.IsTextColorAppliedToNameplateFreeCompany },
|
||||
};
|
||||
ApplyTextFormatting(handler.PlayerCharacter, tag, dic, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GrayOutNameplate(IPlayerCharacter playerCharacter, NameplateChanges nameplateChanges)
|
||||
{
|
||||
foreach (var element in Enum.GetValues<NameplateElements>())
|
||||
nameplateChanges.GetChange(element).ApplyFormatting(new SeString().Append(new UIForegroundPayload(3)), new SeString().Append(new UIForegroundPayload(0)));
|
||||
}
|
||||
|
||||
protected void ApplyTextFormatting(IPlayerCharacter? gameObject, Tag tag, IEnumerable<KeyValuePair<NameplateElementChange, InheritableValue<bool>>> changes, ushort? overwriteTextColor = null)
|
||||
{
|
||||
if (IsTagVisible(tag, gameObject))
|
||||
{
|
||||
foreach (var kvp in changes)
|
||||
{
|
||||
var change = kvp.Key;
|
||||
var enableFlag = kvp.Value;
|
||||
|
||||
if (enableFlag.InheritedValue != null && enableFlag.InheritedValue.Value && (overwriteTextColor ?? tag.TextColor?.InheritedValue) is ushort colorToUse)
|
||||
change.ApplyFormatting(new SeString().Append(new UIForegroundPayload(colorToUse)), new SeString().Append(new UIForegroundPayload(0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,294 +2,171 @@
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
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;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using GameObject = Dalamud.Game.ClientState.Objects.Types.GameObject;
|
||||
|
||||
namespace PlayerTags.Features
|
||||
namespace PlayerTags.Features;
|
||||
|
||||
/// <summary>
|
||||
/// The base of a feature that adds tags to UI elements.
|
||||
/// </summary>
|
||||
public abstract class TagTargetFeature(PluginConfiguration pluginConfiguration, PluginData pluginData) : FeatureBase(pluginConfiguration, pluginData), IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The base of a feature that adds tags to UI elements.
|
||||
/// </summary>
|
||||
public abstract class TagTargetFeature : FeatureBase, IDisposable
|
||||
public ActivityContextManager ActivityContextManager { get; init; } = new();
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
public ActivityContextManager ActivityContextManager { get; init; }
|
||||
ActivityContextManager.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected TagTargetFeature(PluginConfiguration pluginConfiguration, PluginData pluginData) : base(pluginConfiguration, pluginData)
|
||||
protected abstract bool IsIconVisible(Tag tag);
|
||||
|
||||
protected abstract bool IsTextVisible(Tag tag);
|
||||
|
||||
protected bool IsTagVisible(Tag tag, IGameObject? gameObject)
|
||||
{
|
||||
bool isVisibleForActivity = ActivityContextHelper.GetIsVisible(ActivityContextManager.CurrentActivityContext.ActivityType,
|
||||
tag.IsVisibleInPveDuties.InheritedValue ?? false,
|
||||
tag.IsVisibleInPvpDuties.InheritedValue ?? false,
|
||||
tag.IsVisibleInOverworld.InheritedValue ?? false);
|
||||
|
||||
if (!isVisibleForActivity)
|
||||
return false;
|
||||
|
||||
if (gameObject is IPlayerCharacter playerCharacter)
|
||||
{
|
||||
ActivityContextManager = new();
|
||||
}
|
||||
bool isVisibleForPlayer = PlayerContextHelper.GetIsVisible(playerCharacter,
|
||||
tag.IsVisibleForSelf.InheritedValue ?? false,
|
||||
tag.IsVisibleForFriendPlayers.InheritedValue ?? false,
|
||||
tag.IsVisibleForPartyPlayers.InheritedValue ?? false,
|
||||
tag.IsVisibleForAlliancePlayers.InheritedValue ?? false,
|
||||
tag.IsVisibleForEnemyPlayers.InheritedValue ?? false,
|
||||
tag.IsVisibleForOtherPlayers.InheritedValue ?? false);
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
ActivityContextManager.Dispose();
|
||||
}
|
||||
|
||||
protected abstract bool IsIconVisible(Tag tag);
|
||||
|
||||
protected abstract bool IsTextVisible(Tag tag);
|
||||
|
||||
protected bool IsTagVisible(Tag tag, GameObject? gameObject)
|
||||
{
|
||||
bool isVisibleForActivity = ActivityContextHelper.GetIsVisible(ActivityContextManager.CurrentActivityContext.ActivityType,
|
||||
tag.IsVisibleInPveDuties.InheritedValue ?? false,
|
||||
tag.IsVisibleInPvpDuties.InheritedValue ?? false,
|
||||
tag.IsVisibleInOverworld.InheritedValue ?? false);
|
||||
|
||||
if (!isVisibleForActivity)
|
||||
{
|
||||
if (!isVisibleForPlayer)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gameObject is PlayerCharacter playerCharacter)
|
||||
{
|
||||
bool isVisibleForPlayer = PlayerContextHelper.GetIsVisible(playerCharacter,
|
||||
tag.IsVisibleForSelf.InheritedValue ?? false,
|
||||
tag.IsVisibleForFriendPlayers.InheritedValue ?? false,
|
||||
tag.IsVisibleForPartyPlayers.InheritedValue ?? false,
|
||||
tag.IsVisibleForAlliancePlayers.InheritedValue ?? false,
|
||||
tag.IsVisibleForEnemyPlayers.InheritedValue ?? false,
|
||||
tag.IsVisibleForOtherPlayers.InheritedValue ?? false);
|
||||
|
||||
if (!isVisibleForPlayer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the payloads for the given tag and game object depending on visibility conditions.
|
||||
/// </summary>
|
||||
/// <param name="gameObject">The game object to get payloads for.</param>
|
||||
/// <param name="tag">The tag config to get payloads for.</param>
|
||||
/// <returns>A list of payloads for the given tag.</returns>
|
||||
protected Payload[] GetPayloads(Tag tag, GameObject? gameObject)
|
||||
{
|
||||
if (!IsTagVisible(tag, gameObject))
|
||||
{
|
||||
return Array.Empty<Payload>();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return CreatePayloads(tag);
|
||||
/// <summary>
|
||||
/// Gets the payloads for the given tag and game object depending on visibility conditions.
|
||||
/// </summary>
|
||||
/// <param name="gameObject">The game object to get payloads for.</param>
|
||||
/// <param name="tag">The tag config to get payloads for.</param>
|
||||
/// <returns>A list of payloads for the given tag.</returns>
|
||||
protected Payload[] GetPayloads(Tag tag, IGameObject? playerCharacter)
|
||||
{
|
||||
if (!IsTagVisible(tag, playerCharacter))
|
||||
return [];
|
||||
return CreatePayloads(tag);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates payloads for the given tag.
|
||||
/// </summary>
|
||||
/// <param name="tag">The tag to create payloads for.</param>
|
||||
/// <returns>The payloads for the given tag.</returns>
|
||||
private Payload[] CreatePayloads(Tag tag)
|
||||
{
|
||||
List<Payload> newPayloads = [];
|
||||
BitmapFontIcon? icon = null;
|
||||
string? text = null;
|
||||
|
||||
if (IsIconVisible(tag))
|
||||
icon = tag.Icon.InheritedValue;
|
||||
|
||||
if (icon != null && icon.Value != BitmapFontIcon.None)
|
||||
newPayloads.Add(new IconPayload(icon.Value));
|
||||
|
||||
if (IsTextVisible(tag))
|
||||
text = tag.Text.InheritedValue;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
if (tag.IsTextItalic.InheritedValue != null && tag.IsTextItalic.InheritedValue.Value)
|
||||
newPayloads.Add(new EmphasisItalicPayload(true));
|
||||
|
||||
if (tag.TextGlowColor.InheritedValue != null)
|
||||
newPayloads.Add(new UIGlowPayload(tag.TextGlowColor.InheritedValue.Value));
|
||||
|
||||
if (tag.TextColor.InheritedValue != null)
|
||||
newPayloads.Add(new UIForegroundPayload(tag.TextColor.InheritedValue.Value));
|
||||
|
||||
newPayloads.Add(new TextPayload(text));
|
||||
|
||||
if (tag.TextColor.InheritedValue != null)
|
||||
newPayloads.Add(new UIForegroundPayload(0));
|
||||
|
||||
if (tag.TextGlowColor.InheritedValue != null)
|
||||
newPayloads.Add(new UIGlowPayload(0));
|
||||
|
||||
if (tag.IsTextItalic.InheritedValue != null && tag.IsTextItalic.InheritedValue.Value)
|
||||
newPayloads.Add(new EmphasisItalicPayload(false));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates payloads for the given tag.
|
||||
/// </summary>
|
||||
/// <param name="tag">The tag to create payloads for.</param>
|
||||
/// <returns>The payloads for the given tag.</returns>
|
||||
private Payload[] CreatePayloads(Tag tag)
|
||||
return [.. newPayloads];
|
||||
}
|
||||
|
||||
protected static string BuildPlayername(string name)
|
||||
{
|
||||
var logNameType = GameConfigHelper.Instance.GetLogNameType();
|
||||
var result = string.Empty;
|
||||
|
||||
if (logNameType != null && !string.IsNullOrEmpty(name))
|
||||
{
|
||||
List<Payload> newPayloads = new List<Payload>();
|
||||
var nameSplitted = name.Split(' ');
|
||||
|
||||
BitmapFontIcon? icon = null;
|
||||
if (IsIconVisible(tag))
|
||||
if (nameSplitted.Length > 1)
|
||||
{
|
||||
icon = tag.Icon.InheritedValue;
|
||||
}
|
||||
var firstName = nameSplitted[0];
|
||||
var lastName = nameSplitted[1];
|
||||
|
||||
if (icon != null && icon.Value != BitmapFontIcon.None)
|
||||
{
|
||||
newPayloads.Add(new IconPayload(icon.Value));
|
||||
}
|
||||
|
||||
string? text = null;
|
||||
if (IsTextVisible(tag))
|
||||
{
|
||||
text = tag.Text.InheritedValue;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
if (tag.IsTextItalic.InheritedValue != null && tag.IsTextItalic.InheritedValue.Value)
|
||||
switch (logNameType)
|
||||
{
|
||||
newPayloads.Add(new EmphasisItalicPayload(true));
|
||||
case LogNameType.FullName:
|
||||
result = $"{firstName} {lastName}";
|
||||
break;
|
||||
case LogNameType.LastNameShorted:
|
||||
result = $"{firstName} {lastName[..1]}.";
|
||||
break;
|
||||
case LogNameType.FirstNameShorted:
|
||||
result = $"{firstName[..1]}. {lastName}";
|
||||
break;
|
||||
case LogNameType.Initials:
|
||||
result = $"{firstName[..1]}. {lastName[..1]}.";
|
||||
break;
|
||||
}
|
||||
|
||||
if (tag.TextGlowColor.InheritedValue != null)
|
||||
{
|
||||
newPayloads.Add(new UIGlowPayload(tag.TextGlowColor.InheritedValue.Value));
|
||||
}
|
||||
|
||||
if (tag.TextColor.InheritedValue != null)
|
||||
{
|
||||
newPayloads.Add(new UIForegroundPayload(tag.TextColor.InheritedValue.Value));
|
||||
}
|
||||
|
||||
newPayloads.Add(new TextPayload(text));
|
||||
|
||||
if (tag.TextColor.InheritedValue != null)
|
||||
{
|
||||
newPayloads.Add(new UIForegroundPayload(0));
|
||||
}
|
||||
|
||||
if (tag.TextGlowColor.InheritedValue != null)
|
||||
{
|
||||
newPayloads.Add(new UIGlowPayload(0));
|
||||
}
|
||||
|
||||
if (tag.IsTextItalic.InheritedValue != null && tag.IsTextItalic.InheritedValue.Value)
|
||||
{
|
||||
newPayloads.Add(new EmphasisItalicPayload(false));
|
||||
}
|
||||
}
|
||||
|
||||
return newPayloads.ToArray();
|
||||
}
|
||||
|
||||
protected static string BuildPlayername(string name)
|
||||
{
|
||||
var logNameType = GameConfigHelper.Instance.GetLogNameType();
|
||||
var result = string.Empty;
|
||||
|
||||
if (logNameType != null && !string.IsNullOrEmpty(name))
|
||||
{
|
||||
var nameSplitted = name.Split(' ');
|
||||
|
||||
if (nameSplitted.Length > 1)
|
||||
{
|
||||
var firstName = nameSplitted[0];
|
||||
var lastName = nameSplitted[1];
|
||||
|
||||
switch (logNameType)
|
||||
{
|
||||
case LogNameType.FullName:
|
||||
result = $"{firstName} {lastName}";
|
||||
break;
|
||||
case LogNameType.LastNameShorted:
|
||||
result = $"{firstName} {lastName[..1]}.";
|
||||
break;
|
||||
case LogNameType.FirstNameShorted:
|
||||
result = $"{firstName[..1]}. {lastName}";
|
||||
break;
|
||||
case LogNameType.Initials:
|
||||
result = $"{firstName[..1]}. {lastName[..1]}.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(result))
|
||||
result = name;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given payload changes to the dictionary.
|
||||
/// </summary>
|
||||
/// <param name="tagPosition">The position to add changes to.</param>
|
||||
/// <param name="payloads">The payloads to add.</param>
|
||||
/// <param name="stringChanges">The dictionary to add the changes to.</param>
|
||||
protected void AddPayloadChanges(StringPosition tagPosition, IEnumerable<Payload> payloads, StringChanges stringChanges, bool forceUsingSingleAnchorPayload)
|
||||
{
|
||||
if (payloads != null && payloads.Any() && stringChanges != null)
|
||||
{
|
||||
var changes = stringChanges.GetChange(tagPosition);
|
||||
changes.Payloads.AddRange(payloads);
|
||||
changes.ForceUsingSingleAnchorPayload = forceUsingSingleAnchorPayload;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies changes to the given string.
|
||||
/// </summary>
|
||||
/// <param name="seString">The string to apply changes to.</param>
|
||||
/// <param name="stringChanges">The changes to apply.</param>
|
||||
/// <param name="anchorPayload">The payload in the string that changes should be anchored to. If there is no anchor, the changes will be applied to the entire string.</param>
|
||||
protected void ApplyStringChanges(SeString seString, StringChanges stringChanges, List<Payload> anchorPayloads = null, Payload anchorReplacePayload = null)
|
||||
if (string.IsNullOrEmpty(result))
|
||||
result = name;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given payload changes to the dictionary.
|
||||
/// </summary>
|
||||
/// <param name="tagPosition">The position to add changes to.</param>
|
||||
/// <param name="payloads">The payloads to add.</param>
|
||||
/// <param name="stringChanges">The dictionary to add the changes to.</param>
|
||||
protected void AddPayloadChanges(StringPosition tagPosition, IEnumerable<Payload> payloads, StringChanges stringChanges, bool forceUsingSingleAnchorPayload)
|
||||
{
|
||||
if (payloads != null && payloads.Any() && stringChanges != null)
|
||||
{
|
||||
var props = new StringChangesProps
|
||||
{
|
||||
Destination = seString,
|
||||
AnchorPayload = anchorReplacePayload
|
||||
};
|
||||
|
||||
props.AnchorPayloads = anchorPayloads;
|
||||
props.StringChanges = stringChanges;
|
||||
|
||||
StringUpdateFactory.ApplyStringChanges(props);
|
||||
}
|
||||
|
||||
protected void ApplyTextFormatting(GameObject gameObject, Tag tag, SeString[] destStrings, InheritableValue<bool>[] textColorApplied, List<Payload> preferedPayloads, ushort? overwriteTextColor = null)
|
||||
{
|
||||
if (IsTagVisible(tag, gameObject))
|
||||
{
|
||||
for (int i = 0; i < destStrings.Length; i++)
|
||||
{
|
||||
var destString = destStrings[i];
|
||||
var isTextColorApplied = textColorApplied[i];
|
||||
applyTextColor(destString, isTextColorApplied, tag.TextColor);
|
||||
//applyTextGlowColor(destString, isTextColorApplied, tag.TextGlowColor);
|
||||
//applyTextItalicColor(destString, tag.IsTextItalic); // Disabled, because that is needed only for a few parts somewhere else.
|
||||
}
|
||||
}
|
||||
|
||||
void applyTextColor(SeString destPayload, InheritableValue<bool> enableFlag, InheritableValue<ushort> colorValue)
|
||||
{
|
||||
var colorToUse = overwriteTextColor ?? colorValue?.InheritedValue;
|
||||
if (shouldApplyFormattingPayloads(destPayload)
|
||||
&& enableFlag.InheritedValue != null
|
||||
&& enableFlag.InheritedValue.Value
|
||||
&& colorToUse != null)
|
||||
applyTextFormattingPayloads(destPayload, new UIForegroundPayload(colorToUse.Value), new UIForegroundPayload(0));
|
||||
}
|
||||
|
||||
//void applyTextGlowColor(SeString destPayload, InheritableValue<bool> enableFlag, InheritableValue<ushort> colorValue)
|
||||
//{
|
||||
// if (shouldApplyFormattingPayloads(destPayload)
|
||||
// && enableFlag.InheritedValue != null
|
||||
// && enableFlag.InheritedValue.Value
|
||||
// && colorValue.InheritedValue != null)
|
||||
// applyTextFormattingPayloads(destPayload, new UIGlowPayload(colorValue.InheritedValue.Value), new UIGlowPayload(0));
|
||||
//}
|
||||
|
||||
//void applyTextItalicColor(SeString destPayload, InheritableValue<bool> italicValue)
|
||||
//{
|
||||
// if (shouldApplyFormattingPayloads(destPayload)
|
||||
// && italicValue.InheritedValue != null
|
||||
// && italicValue.InheritedValue.Value)
|
||||
// applyTextFormattingPayloads(destPayload, new EmphasisItalicPayload(true), new EmphasisItalicPayload(false));
|
||||
//}
|
||||
|
||||
bool shouldApplyFormattingPayloads(SeString destPayload)
|
||||
=> destPayload.Payloads.Any(payload => payload is TextPayload || payload is PlayerPayload);
|
||||
|
||||
void applyTextFormattingPayloads(SeString destPayload, Payload startPayload, Payload endPayload)
|
||||
{
|
||||
if (preferedPayloads == null || !preferedPayloads.Any())
|
||||
applyTextFormattingPayloadToStartAndEnd(destPayload, startPayload, endPayload);
|
||||
else
|
||||
applyTextFormattingPayloadsToSpecificPosition(destPayload, startPayload, endPayload, preferedPayloads);
|
||||
}
|
||||
|
||||
void applyTextFormattingPayloadToStartAndEnd(SeString destPayload, Payload startPayload, Payload endPayload)
|
||||
{
|
||||
destPayload.Payloads.Insert(0, startPayload);
|
||||
destPayload.Payloads.Add(endPayload);
|
||||
}
|
||||
|
||||
void applyTextFormattingPayloadsToSpecificPosition(SeString destPayload, Payload startPayload, Payload endPayload, List<Payload> preferedPayload)
|
||||
{
|
||||
int payloadStartIndex = destPayload.Payloads.IndexOf(preferedPayloads.First());
|
||||
destPayload.Payloads.Insert(payloadStartIndex, startPayload);
|
||||
|
||||
int payloadEndIndex = destPayload.Payloads.IndexOf(preferedPayloads.Last());
|
||||
destPayload.Payloads.Insert(payloadEndIndex + 1, endPayload);
|
||||
}
|
||||
var changes = stringChanges.GetChange(tagPosition);
|
||||
changes.Payloads.AddRange(payloads);
|
||||
changes.ForceUsingSingleAnchorPayload = forceUsingSingleAnchorPayload;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Memory;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace PlayerTags.GameInterface
|
||||
{
|
||||
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(ref IntPtr ptr)
|
||||
{
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
ptr = IntPtr.Zero;
|
||||
}
|
||||
|
||||
public static byte[] NullTerminate(this byte[] bytes)
|
||||
{
|
||||
if (bytes.Length == 0 || bytes[bytes.Length - 1] != 0)
|
||||
{
|
||||
var newBytes = new byte[bytes.Length + 1];
|
||||
Array.Copy(bytes, newBytes, bytes.Length);
|
||||
newBytes[^1] = 0;
|
||||
|
||||
return newBytes;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static unsafe IntPtr GameUIAllocate(ulong size)
|
||||
{
|
||||
return (IntPtr)IMemorySpace.GetUISpace()->Malloc(size, 0);
|
||||
}
|
||||
|
||||
public static unsafe void GameFree(ref IntPtr ptr, ulong size)
|
||||
{
|
||||
if (ptr == IntPtr.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IMemorySpace.Free((void*)ptr, size);
|
||||
ptr = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Logging;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using Pilz.Dalamud.Nameplates;
|
||||
using System;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace PlayerTags.GameInterface.Nameplates
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an interface to modify nameplates.
|
||||
/// </summary>
|
||||
public class Nameplate : IDisposable
|
||||
{
|
||||
public NameplateManager NameplateManager { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a player nameplate is updated by the game.
|
||||
/// </summary>
|
||||
public event PlayerNameplateUpdatedDelegate? PlayerNameplateUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the required hooks are in place and this instance is valid.
|
||||
/// </summary>
|
||||
public bool IsValid
|
||||
{
|
||||
get => NameplateManager != null && NameplateManager.IsValid;
|
||||
}
|
||||
|
||||
public Nameplate()
|
||||
{
|
||||
NameplateManager = new();
|
||||
NameplateManager.Hooks.AddonNamePlate_SetPlayerNameManaged += Hooks_AddonNamePlate_SetPlayerNameManaged;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
NameplateManager.Hooks.AddonNamePlate_SetPlayerNameManaged -= Hooks_AddonNamePlate_SetPlayerNameManaged;
|
||||
NameplateManager.Dispose();
|
||||
}
|
||||
|
||||
private void Hooks_AddonNamePlate_SetPlayerNameManaged(Pilz.Dalamud.Nameplates.EventArgs.AddonNamePlate_SetPlayerNameManagedEventArgs eventArgs)
|
||||
{
|
||||
try
|
||||
{
|
||||
PlayerCharacter? playerCharacter = NameplateManager.GetNameplateGameObject<PlayerCharacter>(eventArgs.SafeNameplateObject);
|
||||
|
||||
if (playerCharacter != null)
|
||||
{
|
||||
var playerNameplateUpdatedArgs = new PlayerNameplateUpdatedArgs(playerCharacter, eventArgs);
|
||||
PlayerNameplateUpdated?.Invoke(playerNameplateUpdatedArgs);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginLog.Error(ex, $"SetPlayerNameplateDetour");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Pilz.Dalamud.Nameplates.EventArgs;
|
||||
|
||||
namespace PlayerTags.GameInterface.Nameplates
|
||||
{
|
||||
public class PlayerNameplateUpdatedArgs
|
||||
{
|
||||
private readonly AddonNamePlate_SetPlayerNameManagedEventArgs eventArgs;
|
||||
|
||||
public PlayerCharacter PlayerCharacter { get; }
|
||||
|
||||
public SeString Name
|
||||
{
|
||||
get => eventArgs.Name;
|
||||
}
|
||||
|
||||
public SeString Title
|
||||
{
|
||||
get => eventArgs.Title;
|
||||
}
|
||||
|
||||
public SeString FreeCompany
|
||||
{
|
||||
get => eventArgs.FreeCompany;
|
||||
}
|
||||
|
||||
public bool IsTitleVisible
|
||||
{
|
||||
get => eventArgs.IsTitleVisible;
|
||||
set => eventArgs.IsTitleVisible = value;
|
||||
}
|
||||
|
||||
public bool IsTitleAboveName
|
||||
{
|
||||
get => eventArgs.IsTitleAboveName;
|
||||
set => eventArgs.IsTitleAboveName = value;
|
||||
}
|
||||
|
||||
public int IconId
|
||||
{
|
||||
get => eventArgs.IconID;
|
||||
set => eventArgs.IconID = value;
|
||||
}
|
||||
|
||||
public PlayerNameplateUpdatedArgs(PlayerCharacter playerCharacter, AddonNamePlate_SetPlayerNameManagedEventArgs eventArgs)
|
||||
{
|
||||
PlayerCharacter = playerCharacter;
|
||||
this.eventArgs = eventArgs;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace PlayerTags.GameInterface.Nameplates
|
||||
{
|
||||
public delegate void PlayerNameplateUpdatedDelegate(PlayerNameplateUpdatedArgs args);
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
namespace PlayerTags.Inheritables
|
||||
namespace PlayerTags.Inheritables;
|
||||
|
||||
public interface IInheritable
|
||||
{
|
||||
public interface IInheritable
|
||||
{
|
||||
public IInheritable? Parent { get; set; }
|
||||
public IInheritable? Parent { get; set; }
|
||||
|
||||
public InheritableBehavior Behavior { get; set; }
|
||||
public InheritableBehavior Behavior { get; set; }
|
||||
|
||||
public abstract void SetData(InheritableData inheritableData);
|
||||
public abstract void SetData(InheritableData inheritableData);
|
||||
|
||||
public abstract InheritableData GetData();
|
||||
}
|
||||
public abstract InheritableData GetData();
|
||||
}
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
namespace PlayerTags.Inheritables;
|
||||
|
||||
namespace PlayerTags.Inheritables
|
||||
public enum InheritableBehavior
|
||||
{
|
||||
public enum InheritableBehavior
|
||||
{
|
||||
Inherit,
|
||||
Enabled,
|
||||
Disabled
|
||||
}
|
||||
Inherit,
|
||||
Enabled,
|
||||
Disabled
|
||||
}
|
||||
|
||||
@@ -2,16 +2,15 @@
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System;
|
||||
|
||||
namespace PlayerTags.Inheritables
|
||||
{
|
||||
[Serializable]
|
||||
public struct InheritableData
|
||||
{
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
[JsonProperty("Behavior")]
|
||||
public InheritableBehavior Behavior;
|
||||
namespace PlayerTags.Inheritables;
|
||||
|
||||
[JsonProperty("Value")]
|
||||
public object Value;
|
||||
}
|
||||
[Serializable]
|
||||
public struct InheritableData
|
||||
{
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
[JsonProperty("Behavior")]
|
||||
public InheritableBehavior Behavior;
|
||||
|
||||
[JsonProperty("Value")]
|
||||
public object Value;
|
||||
}
|
||||
|
||||
@@ -1,66 +1,63 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PlayerTags.Inheritables
|
||||
namespace PlayerTags.Inheritables;
|
||||
|
||||
public class InheritableReference<T> : IInheritable
|
||||
where T : class
|
||||
{
|
||||
public class InheritableReference<T> : IInheritable
|
||||
where T : class
|
||||
public IInheritable? Parent { get; set; }
|
||||
|
||||
public InheritableBehavior Behavior { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
public T Value;
|
||||
|
||||
[JsonIgnore]
|
||||
public T? InheritedValue
|
||||
{
|
||||
public IInheritable? Parent { get; set; }
|
||||
|
||||
public InheritableBehavior Behavior { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
public T Value;
|
||||
|
||||
[JsonIgnore]
|
||||
public T? InheritedValue
|
||||
get
|
||||
{
|
||||
get
|
||||
IInheritable? current = this;
|
||||
while (current != null)
|
||||
{
|
||||
IInheritable? current = this;
|
||||
while (current != null)
|
||||
if (current.Behavior == InheritableBehavior.Enabled && current is InheritableReference<T> currentOfSameType)
|
||||
{
|
||||
if (current.Behavior == InheritableBehavior.Enabled && current is InheritableReference<T> currentOfSameType)
|
||||
{
|
||||
return currentOfSameType.Value;
|
||||
}
|
||||
else if (current.Behavior == InheritableBehavior.Disabled)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
current = current.Parent;
|
||||
return currentOfSameType.Value;
|
||||
}
|
||||
else if (current.Behavior == InheritableBehavior.Disabled)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return default;
|
||||
current = current.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator InheritableReference<T>(T value) => new InheritableReference<T>(value)
|
||||
{
|
||||
Behavior = InheritableBehavior.Enabled
|
||||
};
|
||||
|
||||
public InheritableReference(T value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public void SetData(InheritableData inheritableData)
|
||||
{
|
||||
Behavior = inheritableData.Behavior;
|
||||
Value = (T)inheritableData.Value;
|
||||
}
|
||||
|
||||
public InheritableData GetData()
|
||||
{
|
||||
return new InheritableData
|
||||
{
|
||||
Behavior = Behavior,
|
||||
Value = Value
|
||||
};
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator InheritableReference<T>(T value) => new(value)
|
||||
{
|
||||
Behavior = InheritableBehavior.Enabled
|
||||
};
|
||||
|
||||
public InheritableReference(T value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public void SetData(InheritableData inheritableData)
|
||||
{
|
||||
Behavior = inheritableData.Behavior;
|
||||
Value = (T)inheritableData.Value;
|
||||
}
|
||||
|
||||
public InheritableData GetData()
|
||||
{
|
||||
return new InheritableData
|
||||
{
|
||||
Behavior = Behavior,
|
||||
Value = Value
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,97 +1,95 @@
|
||||
using Dalamud.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace PlayerTags.Inheritables
|
||||
namespace PlayerTags.Inheritables;
|
||||
|
||||
public class InheritableValue<T> : IInheritable
|
||||
where T : struct
|
||||
{
|
||||
public class InheritableValue<T> : IInheritable
|
||||
where T : struct
|
||||
public IInheritable? Parent { get; set; }
|
||||
|
||||
public InheritableBehavior Behavior { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
public T Value;
|
||||
|
||||
[JsonIgnore]
|
||||
public T? InheritedValue
|
||||
{
|
||||
public IInheritable? Parent { get; set; }
|
||||
|
||||
public InheritableBehavior Behavior { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
public T Value;
|
||||
|
||||
[JsonIgnore]
|
||||
public T? InheritedValue
|
||||
get
|
||||
{
|
||||
get
|
||||
IInheritable? current = this;
|
||||
while (current != null)
|
||||
{
|
||||
IInheritable? current = this;
|
||||
while (current != null)
|
||||
if (current.Behavior == InheritableBehavior.Enabled && current is InheritableValue<T> currentOfSameType)
|
||||
{
|
||||
if (current.Behavior == InheritableBehavior.Enabled && current is InheritableValue<T> currentOfSameType)
|
||||
{
|
||||
return currentOfSameType.Value;
|
||||
}
|
||||
else if (current.Behavior == InheritableBehavior.Disabled)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
current = current.Parent;
|
||||
return currentOfSameType.Value;
|
||||
}
|
||||
else if (current.Behavior == InheritableBehavior.Disabled)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return default;
|
||||
current = current.Parent;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator InheritableValue<T>(T value) => new InheritableValue<T>(value)
|
||||
public static implicit operator InheritableValue<T>(T value) => new(value)
|
||||
{
|
||||
Behavior = InheritableBehavior.Enabled
|
||||
};
|
||||
|
||||
public InheritableValue(T value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public void SetData(InheritableData inheritableData)
|
||||
{
|
||||
Behavior = inheritableData.Behavior;
|
||||
|
||||
try
|
||||
{
|
||||
Behavior = InheritableBehavior.Enabled
|
||||
};
|
||||
|
||||
public InheritableValue(T value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public void SetData(InheritableData inheritableData)
|
||||
{
|
||||
Behavior = inheritableData.Behavior;
|
||||
|
||||
try
|
||||
if (typeof(T).IsEnum && inheritableData.Value != null)
|
||||
{
|
||||
if (typeof(T).IsEnum && inheritableData.Value != null)
|
||||
if (inheritableData.Value is string stringValue)
|
||||
{
|
||||
if (inheritableData.Value is string stringValue)
|
||||
{
|
||||
Value = (T)Enum.Parse(typeof(T), stringValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
Value = (T)Enum.ToObject(typeof(T), inheritableData.Value);
|
||||
}
|
||||
}
|
||||
else if (inheritableData.Value == null)
|
||||
{
|
||||
// This should never happen
|
||||
PluginLog.Error($"Expected value of type {Value.GetType()} but received null");
|
||||
}
|
||||
else if (typeof(T) == typeof(Guid) && inheritableData.Value is string strValue)
|
||||
{
|
||||
Value = (T)(object)Guid.Parse(strValue);
|
||||
Value = (T)Enum.Parse(typeof(T), stringValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
Value = (T)Convert.ChangeType(inheritableData.Value, typeof(T));
|
||||
Value = (T)Enum.ToObject(typeof(T), inheritableData.Value);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
else if (inheritableData.Value == null)
|
||||
{
|
||||
PluginLog.Error(ex, $"Failed to convert {inheritableData.Value.GetType()} value '{inheritableData.Value}' to {Value.GetType()}");
|
||||
// This should never happen
|
||||
PluginServices.PluginLog.Error($"Expected value of type {Value.GetType()} but received null");
|
||||
}
|
||||
else if (typeof(T) == typeof(Guid) && inheritableData.Value is string strValue)
|
||||
{
|
||||
Value = (T)(object)Guid.Parse(strValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
Value = (T)Convert.ChangeType(inheritableData.Value, typeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
public InheritableData GetData()
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new InheritableData
|
||||
{
|
||||
Behavior = Behavior,
|
||||
Value = Value
|
||||
};
|
||||
PluginServices.PluginLog.Error(ex, $"Failed to convert {inheritableData.Value.GetType()} value '{inheritableData.Value}' to {Value.GetType()}");
|
||||
}
|
||||
}
|
||||
|
||||
public InheritableData GetData()
|
||||
{
|
||||
return new InheritableData
|
||||
{
|
||||
Behavior = Behavior,
|
||||
Value = Value
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +1,58 @@
|
||||
using Dalamud.Logging;
|
||||
using Dalamud.Plugin;
|
||||
using PlayerTags.Resources;
|
||||
using PlayerTags.Resources;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
|
||||
namespace PlayerTags
|
||||
namespace PlayerTags;
|
||||
|
||||
public static class Localizer
|
||||
{
|
||||
public static class Localizer
|
||||
public static void SetLanguage(string langCode)
|
||||
{
|
||||
public static void SetLanguage(string langCode)
|
||||
SetLanguage(new CultureInfo(langCode));
|
||||
}
|
||||
|
||||
public static void SetLanguage(CultureInfo cultureInfo)
|
||||
{
|
||||
Strings.Culture = cultureInfo;
|
||||
}
|
||||
|
||||
public static string GetName<TEnum>(TEnum value)
|
||||
{
|
||||
return $"{typeof(TEnum).Name}_{value}";
|
||||
}
|
||||
|
||||
public static string GetString<TEnum>(bool isDescription)
|
||||
where TEnum : Enum
|
||||
{
|
||||
return GetString(typeof(TEnum).Name, isDescription);
|
||||
}
|
||||
|
||||
public static string GetString<TEnum>(TEnum value, bool isDescription)
|
||||
where TEnum : Enum
|
||||
{
|
||||
return GetString(GetName(value), isDescription);
|
||||
}
|
||||
|
||||
public static string GetString(string localizedStringName, bool isDescription)
|
||||
{
|
||||
string localizedStringId = $"Loc_{localizedStringName}";
|
||||
|
||||
if (isDescription)
|
||||
{
|
||||
SetLanguage(new CultureInfo(langCode));
|
||||
localizedStringId += "_Description";
|
||||
}
|
||||
|
||||
public static void SetLanguage(CultureInfo cultureInfo)
|
||||
{
|
||||
Strings.Culture = cultureInfo;
|
||||
}
|
||||
return GetString(localizedStringId);
|
||||
}
|
||||
|
||||
public static string GetName<TEnum>(TEnum value)
|
||||
{
|
||||
return $"{typeof(TEnum).Name}_{value}";
|
||||
}
|
||||
public static string GetString(string localizedStringId)
|
||||
{
|
||||
string? value = Strings.ResourceManager.GetString(localizedStringId, Strings.Culture);
|
||||
|
||||
public static string GetString<TEnum>(bool isDescription)
|
||||
where TEnum : Enum
|
||||
{
|
||||
return GetString(typeof(TEnum).Name, isDescription);
|
||||
}
|
||||
if (value != null)
|
||||
return value;
|
||||
|
||||
public static string GetString<TEnum>(TEnum value, bool isDescription)
|
||||
where TEnum : Enum
|
||||
{
|
||||
return GetString(GetName(value), isDescription);
|
||||
}
|
||||
|
||||
public static string GetString(string localizedStringName, bool isDescription)
|
||||
{
|
||||
string localizedStringId = $"Loc_{localizedStringName}";
|
||||
|
||||
if (isDescription)
|
||||
{
|
||||
localizedStringId += "_Description";
|
||||
}
|
||||
|
||||
return GetString(localizedStringId);
|
||||
}
|
||||
|
||||
public static string GetString(string localizedStringId)
|
||||
{
|
||||
string? value = Strings.ResourceManager.GetString(localizedStringId, Strings.Culture);
|
||||
|
||||
if (value != null)
|
||||
return value;
|
||||
|
||||
PluginLog.Error($"Failed to get localized string for id {localizedStringId}");
|
||||
return localizedStringId;
|
||||
}
|
||||
PluginServices.PluginLog.Error($"Failed to get localized string for id {localizedStringId}");
|
||||
return localizedStringId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
|
||||
namespace PlayerTags
|
||||
namespace PlayerTags;
|
||||
|
||||
internal class MyPaths
|
||||
{
|
||||
internal class MyPaths
|
||||
private static string? _PluginDirectoryPath = null;
|
||||
|
||||
public static string PluginDirectoryPath
|
||||
{
|
||||
private static string? _PluginDirectoryPath = null;
|
||||
|
||||
public static string PluginDirectoryPath
|
||||
get
|
||||
{
|
||||
get
|
||||
if (_PluginDirectoryPath is null)
|
||||
{
|
||||
if (_PluginDirectoryPath is null)
|
||||
{
|
||||
var path = Path.GetDirectoryName(PluginServices.DalamudPluginInterface.AssemblyLocation.FullName);
|
||||
if (path is null)
|
||||
_PluginDirectoryPath = string.Empty;
|
||||
else
|
||||
_PluginDirectoryPath = path;
|
||||
}
|
||||
return _PluginDirectoryPath;
|
||||
var path = Path.GetDirectoryName(PluginServices.DalamudPluginInterface.AssemblyLocation.FullName);
|
||||
if (path is null)
|
||||
_PluginDirectoryPath = string.Empty;
|
||||
else
|
||||
_PluginDirectoryPath = path;
|
||||
}
|
||||
return _PluginDirectoryPath;
|
||||
}
|
||||
|
||||
public static string ResourcePath
|
||||
=> Path.Combine(PluginDirectoryPath, "Resources");
|
||||
}
|
||||
|
||||
public static string ResourcePath
|
||||
=> Path.Combine(PluginDirectoryPath, "Resources");
|
||||
}
|
||||
|
||||
@@ -1,92 +1,49 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Authors>r00telement;Pilzinsel64</Authors>
|
||||
<Version>1.9.2.0</Version>
|
||||
</PropertyGroup>
|
||||
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<Nullable>annotations</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<Authors>r00telement;Pilzinsel64</Authors>
|
||||
<Version>1.12.3.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<Nullable>annotations</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dalamud.ContextMenu" Version="1.2.1" />
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.10" />
|
||||
<ProjectReference Include="..\Pilz.Dalamud\Pilz.Dalamud\Pilz.Dalamud.csproj" />
|
||||
<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>
|
||||
<ProjectReference Include="..\Pilz.Dalamud\Pilz.Dalamud\Pilz.Dalamud.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Resources\Paths.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Paths.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Resources\Strings.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Strings.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="Resources\Paths.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Paths.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Resources\Strings.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Strings.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Resources\Paths.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Paths.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Resources\Strings.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Resources\Paths.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Paths.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Resources\Strings.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Resources\Words\Adjectives.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Resources\Words\Nouns.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
<ItemGroup>
|
||||
<None Update="Resources\Words\Adjectives.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Resources\Words\Nouns.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -5,5 +5,5 @@
|
||||
"Punchline": "Lightweight job visibility in nameplates and chat.",
|
||||
"Tags": [ "Jobs", "UI" ],
|
||||
"CategoryTags": [ "jobs", "UI" ],
|
||||
"RepoUrl": "https://github.com/Pilzinsel64/PlayerTags"
|
||||
"RepoUrl": "https://git.pilzinsel64.de/pilzinsel64/playertags"
|
||||
}
|
||||
@@ -1,123 +1,113 @@
|
||||
using Dalamud.Game.Command;
|
||||
using Dalamud.Logging;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Internal;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||
using PlayerTags.Configuration;
|
||||
using PlayerTags.Data;
|
||||
using PlayerTags.Features;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace PlayerTags
|
||||
namespace PlayerTags;
|
||||
|
||||
public sealed class Plugin : IDalamudPlugin
|
||||
{
|
||||
public sealed class Plugin : IDalamudPlugin
|
||||
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 readonly PluginConfiguration pluginConfiguration = null;
|
||||
private readonly PluginData pluginData = null;
|
||||
private readonly PluginConfigurationUI pluginConfigurationUI = null;
|
||||
|
||||
private readonly CustomTagsContextMenuFeature customTagsContextMenuFeature;
|
||||
private readonly NameplateTagTargetFeature nameplatesTagTargetFeature;
|
||||
private readonly ChatTagTargetFeature chatTagTargetFeature;
|
||||
|
||||
public Plugin(IDalamudPluginInterface pluginInterface)
|
||||
{
|
||||
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";
|
||||
PluginServices.Initialize(pluginInterface);
|
||||
Pilz.Dalamud.PluginServices.Initialize(pluginInterface);
|
||||
|
||||
private PluginConfiguration m_PluginConfiguration;
|
||||
private PluginData m_PluginData;
|
||||
private PluginConfigurationUI m_PluginConfigurationUI;
|
||||
pluginConfiguration = PluginConfiguration.LoadPluginConfig() ?? new();
|
||||
pluginData = new PluginData(pluginConfiguration);
|
||||
pluginConfigurationUI = new PluginConfigurationUI(pluginConfiguration, pluginData);
|
||||
|
||||
private CustomTagsContextMenuFeature m_CustomTagsContextMenuFeature;
|
||||
private NameplateTagTargetFeature m_NameplatesTagTargetFeature;
|
||||
private ChatTagTargetFeature m_ChatTagTargetFeature;
|
||||
Localizer.SetLanguage(PluginServices.DalamudPluginInterface.UiLanguage);
|
||||
PluginServices.DalamudPluginInterface.LanguageChanged += DalamudPluginInterface_LanguageChanged;
|
||||
|
||||
public Plugin(DalamudPluginInterface pluginInterface)
|
||||
PluginServices.DalamudPluginInterface.UiBuilder.Draw += UiBuilder_Draw;
|
||||
PluginServices.DalamudPluginInterface.UiBuilder.OpenConfigUi += UiBuilder_OpenConfigUi;
|
||||
PluginServices.CommandManager.AddHandler(c_CommandName, new CommandInfo(CommandManager_Handler)
|
||||
{
|
||||
PluginServices.Initialize(pluginInterface);
|
||||
Pilz.Dalamud.PluginServices.Initialize(pluginInterface);
|
||||
HelpMessage = Resources.Strings.Loc_Command_playertags_v2
|
||||
});
|
||||
customTagsContextMenuFeature = new CustomTagsContextMenuFeature(pluginConfiguration, pluginData);
|
||||
nameplatesTagTargetFeature = new NameplateTagTargetFeature(pluginConfiguration, pluginData);
|
||||
chatTagTargetFeature = new ChatTagTargetFeature(pluginConfiguration, pluginData);
|
||||
}
|
||||
|
||||
m_PluginConfiguration = PluginConfiguration.LoadPluginConfig() ?? new PluginConfiguration();
|
||||
m_PluginData = new PluginData(m_PluginConfiguration);
|
||||
m_PluginConfigurationUI = new PluginConfigurationUI(m_PluginConfiguration, m_PluginData);
|
||||
public void Dispose()
|
||||
{
|
||||
chatTagTargetFeature.Dispose();
|
||||
nameplatesTagTargetFeature.Dispose();
|
||||
customTagsContextMenuFeature.Dispose();
|
||||
PluginServices.DalamudPluginInterface.LanguageChanged -= DalamudPluginInterface_LanguageChanged;
|
||||
PluginServices.CommandManager.RemoveHandler(c_CommandName);
|
||||
PluginServices.DalamudPluginInterface.UiBuilder.OpenConfigUi -= UiBuilder_OpenConfigUi;
|
||||
PluginServices.DalamudPluginInterface.UiBuilder.Draw -= UiBuilder_Draw;
|
||||
}
|
||||
|
||||
Localizer.SetLanguage(PluginServices.DalamudPluginInterface.UiLanguage);
|
||||
PluginServices.DalamudPluginInterface.LanguageChanged += DalamudPluginInterface_LanguageChanged;
|
||||
private void DalamudPluginInterface_LanguageChanged(string langCode)
|
||||
{
|
||||
Localizer.SetLanguage(langCode);
|
||||
}
|
||||
|
||||
PluginServices.DalamudPluginInterface.UiBuilder.Draw += UiBuilder_Draw;
|
||||
PluginServices.DalamudPluginInterface.UiBuilder.OpenConfigUi += UiBuilder_OpenConfigUi;
|
||||
PluginServices.CommandManager.AddHandler(c_CommandName, new CommandInfo(CommandManager_Handler)
|
||||
{
|
||||
HelpMessage = Resources.Strings.Loc_Command_playertags_v2
|
||||
});
|
||||
m_CustomTagsContextMenuFeature = new CustomTagsContextMenuFeature(m_PluginConfiguration, m_PluginData);
|
||||
m_NameplatesTagTargetFeature = new NameplateTagTargetFeature(m_PluginConfiguration, m_PluginData);
|
||||
m_ChatTagTargetFeature = new ChatTagTargetFeature(m_PluginConfiguration, m_PluginData);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
private void CommandManager_Handler(string command, string arguments)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
m_ChatTagTargetFeature.Dispose();
|
||||
m_NameplatesTagTargetFeature.Dispose();
|
||||
m_CustomTagsContextMenuFeature.Dispose();
|
||||
PluginServices.DalamudPluginInterface.LanguageChanged -= DalamudPluginInterface_LanguageChanged;
|
||||
PluginServices.CommandManager.RemoveHandler(c_CommandName);
|
||||
PluginServices.DalamudPluginInterface.UiBuilder.OpenConfigUi -= UiBuilder_OpenConfigUi;
|
||||
PluginServices.DalamudPluginInterface.UiBuilder.Draw -= UiBuilder_Draw;
|
||||
}
|
||||
|
||||
private void DalamudPluginInterface_LanguageChanged(string langCode)
|
||||
{
|
||||
Localizer.SetLanguage(langCode);
|
||||
}
|
||||
|
||||
private void CommandManager_Handler(string command, string arguments)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case c_CommandName:
|
||||
if (string.IsNullOrWhiteSpace(command))
|
||||
UiBuilder_OpenConfigUi();
|
||||
else
|
||||
case c_CommandName:
|
||||
if (string.IsNullOrWhiteSpace(arguments))
|
||||
UiBuilder_OpenConfigUi();
|
||||
else
|
||||
{
|
||||
var lowerArgs = arguments.ToLower().Split(' ');
|
||||
if (lowerArgs.Length >= 1)
|
||||
{
|
||||
var lowerArgs = arguments.ToLower().Split(' ');
|
||||
if (lowerArgs.Length >= 1)
|
||||
switch (lowerArgs[0])
|
||||
{
|
||||
switch (lowerArgs[0])
|
||||
{
|
||||
case c_SubCommandName_EnableGlobal:
|
||||
if (lowerArgs.Length >= 2)
|
||||
case c_SubCommandName_EnableGlobal:
|
||||
if (lowerArgs.Length >= 2)
|
||||
{
|
||||
switch (lowerArgs[0])
|
||||
{
|
||||
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;
|
||||
}
|
||||
case c_CommandArg_On:
|
||||
pluginConfiguration.EnabledGlobal = true;
|
||||
break;
|
||||
case c_CommandArg_Off:
|
||||
pluginConfiguration.EnabledGlobal = false;
|
||||
break;
|
||||
case c_CommandArg_toggle:
|
||||
pluginConfiguration.EnabledGlobal = !pluginConfiguration.EnabledGlobal;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void UiBuilder_Draw()
|
||||
{
|
||||
if (m_PluginConfiguration.IsVisible)
|
||||
m_PluginConfigurationUI.Draw();
|
||||
}
|
||||
|
||||
private void UiBuilder_OpenConfigUi()
|
||||
{
|
||||
m_PluginConfiguration.IsVisible = true;
|
||||
m_PluginConfiguration.Save(m_PluginData);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void UiBuilder_Draw()
|
||||
{
|
||||
if (pluginConfiguration.IsVisible)
|
||||
pluginConfigurationUI.Draw();
|
||||
}
|
||||
|
||||
private void UiBuilder_OpenConfigUi()
|
||||
{
|
||||
pluginConfiguration.IsVisible = true;
|
||||
pluginConfiguration.Save(pluginData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,28 @@
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.ClientState.Party;
|
||||
using Dalamud.Game.Command;
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
|
||||
namespace PlayerTags
|
||||
namespace PlayerTags;
|
||||
|
||||
public class PluginServices
|
||||
{
|
||||
public class PluginServices
|
||||
{
|
||||
[PluginService] public static ChatGui ChatGui { get; set; } = null!;
|
||||
[PluginService] public static ClientState ClientState { get; set; } = null!;
|
||||
[PluginService] public static CommandManager CommandManager { get; set; } = null!;
|
||||
[PluginService] public static DalamudPluginInterface DalamudPluginInterface { get; set; } = null!;
|
||||
[PluginService] public static DataManager DataManager { get; set; } = null!;
|
||||
[PluginService] public static Framework Framework { get; set; } = null!;
|
||||
[PluginService] public static GameGui GameGui { get; set; } = null!;
|
||||
[PluginService] public static ObjectTable ObjectTable { get; set; } = null!;
|
||||
[PluginService] public static PartyList PartyList { get; set; } = null!;
|
||||
[PluginService] public static IDalamudPluginInterface DalamudPluginInterface { get; set; }
|
||||
[PluginService] public static IPluginLog PluginLog { get; set; }
|
||||
[PluginService] public static IGameConfig GameConfig { get; set; }
|
||||
[PluginService] public static IChatGui ChatGui { get; set; }
|
||||
[PluginService] public static IClientState ClientState { get; set; }
|
||||
[PluginService] public static ICommandManager CommandManager { get; set; }
|
||||
[PluginService] public static IDataManager DataManager { get; set; }
|
||||
[PluginService] public static IFramework Framework { get; set; }
|
||||
[PluginService] public static IGameGui GameGui { get; set; }
|
||||
[PluginService] public static IObjectTable ObjectTable { get; set; }
|
||||
[PluginService] public static IPartyList PartyList { get; set; }
|
||||
[PluginService] public static IGameInteropProvider GameInteropProvider { get; set; }
|
||||
[PluginService] public static IContextMenu ContextMenu { get; set; }
|
||||
[PluginService] public static INamePlateGui NamePlateGui { get; set; }
|
||||
|
||||
public static void Initialize(DalamudPluginInterface pluginInterface)
|
||||
{
|
||||
pluginInterface.Create<PluginServices>();
|
||||
}
|
||||
public static void Initialize(IDalamudPluginInterface pluginInterface)
|
||||
{
|
||||
pluginInterface.Create<PluginServices>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace PlayerTags.PluginStrings
|
||||
namespace PlayerTags.PluginStrings;
|
||||
|
||||
public interface IPluginString
|
||||
{
|
||||
public interface IPluginString
|
||||
{
|
||||
public string Value { get; }
|
||||
}
|
||||
public string Value { get; }
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
namespace PlayerTags.PluginStrings
|
||||
namespace PlayerTags.PluginStrings;
|
||||
|
||||
public class LiteralPluginString : IPluginString
|
||||
{
|
||||
public class LiteralPluginString : IPluginString
|
||||
private string m_Value;
|
||||
public string Value => m_Value;
|
||||
|
||||
public LiteralPluginString(string value)
|
||||
{
|
||||
private string m_Value;
|
||||
public string Value => m_Value;
|
||||
m_Value = value;
|
||||
}
|
||||
|
||||
public LiteralPluginString(string value)
|
||||
{
|
||||
m_Value = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
namespace PlayerTags.PluginStrings
|
||||
namespace PlayerTags.PluginStrings;
|
||||
|
||||
public class LocalizedPluginString : IPluginString
|
||||
{
|
||||
public class LocalizedPluginString : IPluginString
|
||||
public string Key { get; init; }
|
||||
public string Value => Localizer.GetString(Key, false);
|
||||
|
||||
public LocalizedPluginString(string key)
|
||||
{
|
||||
public string Key { get; init; }
|
||||
public string Value => Localizer.GetString(Key, false);
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public LocalizedPluginString(string key)
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,116 +1,113 @@
|
||||
using Dalamud.Logging;
|
||||
using System;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace PlayerTags
|
||||
namespace PlayerTags;
|
||||
|
||||
/// <summary>
|
||||
/// Generates names based on existing lists of words.
|
||||
/// </summary>
|
||||
public static class RandomNameGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates names based on existing lists of words.
|
||||
/// </summary>
|
||||
public static class RandomNameGenerator
|
||||
private static string[]? s_Adjectives;
|
||||
private static string[] Adjectives
|
||||
{
|
||||
private static string[]? s_Adjectives;
|
||||
private static string[] Adjectives
|
||||
get
|
||||
{
|
||||
get
|
||||
if (s_Adjectives == null)
|
||||
{
|
||||
if (s_Adjectives == null)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
s_Adjectives = File.ReadAllLines(Path.Combine(MyPaths.ResourcePath, Resources.Paths.AdjectivesTxt));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginLog.Error(ex, $"RandomNameGenerator failed to read adjectives");
|
||||
}
|
||||
s_Adjectives = File.ReadAllLines(Path.Combine(MyPaths.ResourcePath, Resources.Paths.AdjectivesTxt));
|
||||
}
|
||||
|
||||
if (s_Adjectives != null)
|
||||
catch (Exception ex)
|
||||
{
|
||||
return s_Adjectives;
|
||||
PluginServices.PluginLog.Error(ex, $"RandomNameGenerator failed to read adjectives");
|
||||
}
|
||||
|
||||
return new string[] { };
|
||||
}
|
||||
|
||||
if (s_Adjectives != null)
|
||||
{
|
||||
return s_Adjectives;
|
||||
}
|
||||
|
||||
return new string[] { };
|
||||
}
|
||||
}
|
||||
|
||||
private static string[]? s_Nouns;
|
||||
private static string[] Nouns
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_Nouns == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
s_Nouns = File.ReadAllLines(Path.Combine(MyPaths.ResourcePath, Resources.Paths.NounsTxt));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginServices.PluginLog.Error(ex, $"RandomNameGenerator failed to read nouns");
|
||||
}
|
||||
}
|
||||
|
||||
if (s_Nouns != null)
|
||||
{
|
||||
return s_Nouns;
|
||||
}
|
||||
|
||||
return new string[] { };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a name for the given string.
|
||||
/// </summary>
|
||||
/// <param name="str">The string to generate a name for.</param>
|
||||
/// <returns>A generated name.</returns>
|
||||
public static string? Generate(string str)
|
||||
{
|
||||
if (Adjectives == null || Nouns == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string[]? s_Nouns;
|
||||
private static string[] Nouns
|
||||
int hash = GetDeterministicHashCode(str);
|
||||
|
||||
// Use the seed as the hash so the same player always gets the same name
|
||||
Random random = new(hash);
|
||||
var adjective = Adjectives[random.Next(0, Adjectives.Length)];
|
||||
var noun = Nouns[random.Next(0, Nouns.Length)];
|
||||
var generatedName = $"{adjective} {noun}";
|
||||
|
||||
return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(generatedName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a deterministic hash code for the given string.
|
||||
/// </summary>
|
||||
/// <param name="str">The string to hash.</param>
|
||||
/// <returns>A deterministic hash code.</returns>
|
||||
private static int GetDeterministicHashCode(string str)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
get
|
||||
int hash1 = (5381 << 16) + 5381;
|
||||
int hash2 = hash1;
|
||||
|
||||
for (int index = 0; index < str.Length; index += 2)
|
||||
{
|
||||
if (s_Nouns == null)
|
||||
hash1 = ((hash1 << 5) + hash1) ^ str[index];
|
||||
if (index == str.Length - 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
s_Nouns = File.ReadAllLines(Path.Combine(MyPaths.ResourcePath, Resources.Paths.NounsTxt));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginLog.Error(ex, $"RandomNameGenerator failed to read nouns");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (s_Nouns != null)
|
||||
{
|
||||
return s_Nouns;
|
||||
}
|
||||
|
||||
return new string[] { };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a name for the given string.
|
||||
/// </summary>
|
||||
/// <param name="str">The string to generate a name for.</param>
|
||||
/// <returns>A generated name.</returns>
|
||||
public static string? Generate(string str)
|
||||
{
|
||||
if (Adjectives == null || Nouns == null)
|
||||
{
|
||||
return null;
|
||||
hash2 = ((hash2 << 5) + hash2) ^ str[index + 1];
|
||||
}
|
||||
|
||||
int hash = GetDeterministicHashCode(str);
|
||||
|
||||
// Use the seed as the hash so the same player always gets the same name
|
||||
Random random = new Random(hash);
|
||||
var adjective = Adjectives[random.Next(0, Adjectives.Length)];
|
||||
var noun = Nouns[random.Next(0, Nouns.Length)];
|
||||
var generatedName = $"{adjective} {noun}";
|
||||
|
||||
return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(generatedName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a deterministic hash code for the given string.
|
||||
/// </summary>
|
||||
/// <param name="str">The string to hash.</param>
|
||||
/// <returns>A deterministic hash code.</returns>
|
||||
private static int GetDeterministicHashCode(string str)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hash1 = (5381 << 16) + 5381;
|
||||
int hash2 = hash1;
|
||||
|
||||
for (int index = 0; index < str.Length; index += 2)
|
||||
{
|
||||
hash1 = ((hash1 << 5) + hash1) ^ str[index];
|
||||
if (index == str.Length - 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
hash2 = ((hash2 << 5) + hash2) ^ str[index + 1];
|
||||
}
|
||||
|
||||
return hash1 + (hash2 * 1566083941);
|
||||
}
|
||||
return hash1 + (hash2 * 1566083941);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -829,4 +829,9 @@ 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>
|
||||
120
PlayerTags/Resources/Strings.it.resx
Normal file
120
PlayerTags/Resources/Strings.it.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?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>
|
||||
198
PlayerTags/Resources/Strings.ko.resx
Normal file
198
PlayerTags/Resources/Strings.ko.resx
Normal file
@@ -0,0 +1,198 @@
|
||||
<?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>
|
||||
837
PlayerTags/Resources/Strings.zh-CN.resx
Normal file
837
PlayerTags/Resources/Strings.zh-CN.resx
Normal file
@@ -0,0 +1,837 @@
|
||||
<?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>
|
||||
@@ -1,109 +1,87 @@
|
||||
using ImGuiNET;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.Sheets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace PlayerTags
|
||||
namespace PlayerTags;
|
||||
|
||||
public static class UIColorHelper
|
||||
{
|
||||
public static class UIColorHelper
|
||||
private class UIColorComparer : IEqualityComparer<UIColor>
|
||||
{
|
||||
private class UIColorComparer : IEqualityComparer<UIColor>
|
||||
public bool Equals(UIColor left, UIColor right)
|
||||
{
|
||||
public bool Equals(UIColor? left, UIColor? right)
|
||||
{
|
||||
if (left != null && right != null)
|
||||
{
|
||||
return left.UIForeground == right.UIForeground;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetHashCode(UIColor obj)
|
||||
{
|
||||
return obj.UIForeground.GetHashCode();
|
||||
}
|
||||
return left.Dark == right.Dark;
|
||||
}
|
||||
|
||||
private static UIColor[] s_UIColors = null!;
|
||||
|
||||
public static IEnumerable<UIColor> UIColors
|
||||
public int GetHashCode(UIColor obj)
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_UIColors == null)
|
||||
{
|
||||
s_UIColors = CreateUIColors();
|
||||
}
|
||||
|
||||
return s_UIColors;
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector4 ToColor(UIColor uiColor)
|
||||
{
|
||||
var uiColorBytes = BitConverter.GetBytes(uiColor.UIForeground);
|
||||
return
|
||||
new Vector4((float)uiColorBytes[3] / 255,
|
||||
(float)uiColorBytes[2] / 255,
|
||||
(float)uiColorBytes[1] / 255,
|
||||
(float)uiColorBytes[0] / 255);
|
||||
}
|
||||
|
||||
public static Vector4 ToColor(ushort colorId)
|
||||
{
|
||||
foreach (var uiColor in UIColors)
|
||||
{
|
||||
if ((ushort)uiColor.RowId == colorId)
|
||||
{
|
||||
return ToColor(uiColor);
|
||||
}
|
||||
}
|
||||
|
||||
return new Vector4();
|
||||
}
|
||||
|
||||
private static UIColor[] CreateUIColors()
|
||||
{
|
||||
var uiColors = PluginServices.DataManager.GetExcelSheet<UIColor>();
|
||||
if (uiColors != null)
|
||||
{
|
||||
var filteredUIColors = new List<UIColor>(uiColors.Distinct(new UIColorComparer()).Where(uiColor => uiColor.UIForeground != 0 && uiColor.UIForeground != 255));
|
||||
|
||||
filteredUIColors.Sort((left, right) =>
|
||||
{
|
||||
var leftColor = ToColor(left);
|
||||
var rightColor = ToColor(right);
|
||||
ImGui.ColorConvertRGBtoHSV(leftColor.X, leftColor.Y, leftColor.Z, out float leftHue, out float leftSaturation, out float leftValue);
|
||||
ImGui.ColorConvertRGBtoHSV(rightColor.X, rightColor.Y, rightColor.Z, out float rightHue, out float rightSaturation, out float rightValue);
|
||||
|
||||
var hueDifference = leftHue.CompareTo(rightHue);
|
||||
if (hueDifference != 0)
|
||||
{
|
||||
return hueDifference;
|
||||
}
|
||||
|
||||
var valueDifference = leftValue.CompareTo(rightValue);
|
||||
if (valueDifference != 0)
|
||||
{
|
||||
return valueDifference;
|
||||
}
|
||||
|
||||
var saturationDifference = leftSaturation.CompareTo(rightSaturation);
|
||||
if (saturationDifference != 0)
|
||||
{
|
||||
return saturationDifference;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
return filteredUIColors.ToArray();
|
||||
}
|
||||
|
||||
return new UIColor[] { };
|
||||
return obj.Dark.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
private static UIColor[] s_UIColors = null!;
|
||||
|
||||
public static IEnumerable<UIColor> UIColors => s_UIColors ??= CreateUIColors();
|
||||
|
||||
public static Vector4 ToColor(UIColor uiColor)
|
||||
{
|
||||
var uiColorBytes = BitConverter.GetBytes(uiColor.Dark);
|
||||
return
|
||||
new Vector4((float)uiColorBytes[3] / 255,
|
||||
(float)uiColorBytes[2] / 255,
|
||||
(float)uiColorBytes[1] / 255,
|
||||
(float)uiColorBytes[0] / 255);
|
||||
}
|
||||
|
||||
public static Vector4 ToColor(ushort colorId)
|
||||
{
|
||||
foreach (var uiColor in UIColors)
|
||||
{
|
||||
if ((ushort)uiColor.RowId == colorId)
|
||||
return ToColor(uiColor);
|
||||
}
|
||||
|
||||
return new Vector4();
|
||||
}
|
||||
|
||||
private static UIColor[] CreateUIColors()
|
||||
{
|
||||
if (PluginServices.DataManager.GetExcelSheet<UIColor>() is not ExcelSheet<UIColor> uiColors)
|
||||
return [];
|
||||
|
||||
var filteredUIColors = new List<UIColor>(uiColors.Distinct(new UIColorComparer()).Where(uiColor => uiColor.Dark != 0 && uiColor.Dark != 255));
|
||||
filteredUIColors.Sort((left, right) =>
|
||||
{
|
||||
var leftColor = ToColor(left);
|
||||
var rightColor = ToColor(right);
|
||||
var leftHue = 0f;
|
||||
var leftSaturation = 0f;
|
||||
var leftValue = 0f;
|
||||
var rightHue = 0f;
|
||||
var rightSaturation = 0f;
|
||||
var rightValue = 0f;
|
||||
ImGui.ColorConvertRGBtoHSV(leftColor.X, leftColor.Y, leftColor.Z, ref leftHue, ref leftSaturation, ref leftValue);
|
||||
ImGui.ColorConvertRGBtoHSV(rightColor.X, rightColor.Y, rightColor.Z, ref rightHue, ref rightSaturation, ref rightValue);
|
||||
|
||||
var hueDifference = leftHue.CompareTo(rightHue);
|
||||
if (hueDifference != 0)
|
||||
return hueDifference;
|
||||
|
||||
var valueDifference = leftValue.CompareTo(rightValue);
|
||||
if (valueDifference != 0)
|
||||
return valueDifference;
|
||||
|
||||
var saturationDifference = leftSaturation.CompareTo(rightSaturation);
|
||||
if (saturationDifference != 0)
|
||||
return saturationDifference;
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
return [.. filteredUIColors];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"version": 1,
|
||||
"dependencies": {
|
||||
"net7.0-windows7.0": {
|
||||
"Dalamud.ContextMenu": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.2.1, )",
|
||||
"resolved": "1.2.1",
|
||||
"contentHash": "RiBkn1OYRTnVbfUGYolLBE8MOeXjok+JiZaryb27oGa7YARCTu0XgUzkRiCglujknsHOn5kAaXsT3TUJmqMigg=="
|
||||
},
|
||||
"net9.0-windows7.0": {
|
||||
"DalamudPackager": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.1.10, )",
|
||||
"resolved": "2.1.10",
|
||||
"contentHash": "S6NrvvOnLgT4GDdgwuKVJjbFo+8ZEj+JsEYk9ojjOR/MMfv1dIFpT8aRJQfI24rtDcw1uF+GnSSMN4WW1yt7fw=="
|
||||
"requested": "[13.0.0, )",
|
||||
"resolved": "13.0.0",
|
||||
"contentHash": "Mb3cUDSK/vDPQ8gQIeuCw03EMYrej1B4J44a1AvIJ9C759p9XeqdU9Hg4WgOmlnlPe0G7ILTD32PKSUpkQNa8w=="
|
||||
},
|
||||
"DotNet.ReproducibleBuilds": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.2.25, )",
|
||||
"resolved": "1.2.25",
|
||||
"contentHash": "xCXiw7BCxHJ8pF6wPepRUddlh2dlQlbr81gXA72hdk4FLHkKXas7EH/n+fk5UCA/YfMqG1Z6XaPiUjDbUNBUzg=="
|
||||
},
|
||||
"pilz.dalamud": {
|
||||
"type": "Project"
|
||||
|
||||
18
README.md
18
README.md
@@ -2,12 +2,23 @@
|
||||
|
||||
Lightweight job visibility in nameplates and chat. Create custom tags and add them to players with the context menu.
|
||||
|
||||
# Contribution
|
||||
## Install
|
||||
|
||||
### Via official plugin repo
|
||||
|
||||
This plugin is available via the official plugin repository of Dalamud. Just search for "Player Tags" and install.
|
||||
|
||||
### Via third party repo
|
||||
|
||||
For the case you want instant updates, feel free to add my third party repo for this plugin:\
|
||||
`https://git.pilzinsel64.de/pilzinsel64/playertags/-/snippets/5/raw/main/pluginmaster.json`
|
||||
|
||||
## Contribution
|
||||
|
||||
You want to help and contribute to this project? \
|
||||
Feel free to open a pull request with your enhancements or bug fixes!
|
||||
|
||||
# Translation
|
||||
## Translation
|
||||
|
||||
You want to help and translate this plugin to your/other language(s)? \
|
||||
Start translation [here on Crowdin](https://crowdin.com/project/playertags)!
|
||||
@@ -21,8 +32,9 @@ If you want to contribute to a language that isn't listed, just tell me with an
|
||||
| Spanish | Risu
|
||||
| French | Khayle
|
||||
| Japanese | Refer
|
||||
| Chinese | Andypsl8, yqdyqd
|
||||
| ... | You?
|
||||
|
||||
# Credits
|
||||
## Credits
|
||||
|
||||
This plugin was originally developed by [r00telement](https://github.com/r00telement) but forked and continued by [Pilzinsel64](https://github.com/Pilzinsel64).
|
||||
|
||||
Reference in New Issue
Block a user