Initial checkin
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.vs/
|
||||
obj/
|
||||
bin/
|
||||
*.user
|
||||
25
PlayerTags.sln
Normal file
25
PlayerTags.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29709.97
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlayerTags", "PlayerTags\PlayerTags.csproj", "{13C812E9-0D42-4B95-8646-40EEBF30636F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.Build.0 = Debug|x64
|
||||
{13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.ActiveCfg = Release|x64
|
||||
{13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {B17E85B1-5F60-4440-9F9A-3DDE877E8CDF}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
7
PlayerTags/Config/CustomColorConfig.cs
Normal file
7
PlayerTags/Config/CustomColorConfig.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
public class CustomColorConfig
|
||||
{
|
||||
public ushort? Id = null;
|
||||
}
|
||||
}
|
||||
26
PlayerTags/Config/CustomTagConfig.cs
Normal file
26
PlayerTags/Config/CustomTagConfig.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
[Serializable]
|
||||
public class CustomTagConfig : TagConfig
|
||||
{
|
||||
public CustomColorConfig CustomColor = new CustomColorConfig();
|
||||
public string Name = "";
|
||||
public string FormattedGameObjectNames = "";
|
||||
|
||||
private string[] GameObjectNames
|
||||
{
|
||||
get
|
||||
{
|
||||
return FormattedGameObjectNames.Split(';').Select(gameObjectName => gameObjectName.ToLower().Trim()).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IncludesGameObjectName(string gameObjectName)
|
||||
{
|
||||
return GameObjectNames.Contains(gameObjectName);
|
||||
}
|
||||
}
|
||||
}
|
||||
8
PlayerTags/Config/FreeCompanyNameplateVisibility.cs
Normal file
8
PlayerTags/Config/FreeCompanyNameplateVisibility.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
public enum FreeCompanyNameplateVisibility
|
||||
{
|
||||
Default,
|
||||
Never
|
||||
}
|
||||
}
|
||||
10
PlayerTags/Config/JobOverrideConfig.cs
Normal file
10
PlayerTags/Config/JobOverrideConfig.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
[Serializable]
|
||||
public class JobOverrideConfig
|
||||
{
|
||||
public CustomColorConfig CustomColor = new CustomColorConfig();
|
||||
}
|
||||
}
|
||||
73
PlayerTags/Config/MainConfig.cs
Normal file
73
PlayerTags/Config/MainConfig.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using Dalamud.Configuration;
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Plugin;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
[Serializable]
|
||||
public class MainConfig : IPluginConfiguration
|
||||
{
|
||||
public static Dictionary<byte, Role> RolesById { get; } = new Dictionary<byte, Role>()
|
||||
{
|
||||
{ 0, Role.LandHand },
|
||||
{ 1, Role.Tank },
|
||||
{ 2, Role.DPS },
|
||||
{ 3, Role.DPS },
|
||||
{ 4, Role.Healer },
|
||||
};
|
||||
|
||||
public int Version { get; set; } = 0;
|
||||
|
||||
public FreeCompanyNameplateVisibility FreeCompanyVisibility = FreeCompanyNameplateVisibility.Default;
|
||||
public TitleNameplateVisibility TitleVisibility = TitleNameplateVisibility.Default;
|
||||
public TitleNameplatePosition TitlePosition = TitleNameplatePosition.Default;
|
||||
|
||||
public RoleTagConfig RoleTag = new RoleTagConfig();
|
||||
|
||||
public List<CustomTagConfig> CustomTagConfigs = new List<CustomTagConfig>();
|
||||
|
||||
public bool IsPlayerNameRandomlyGenerated = false;
|
||||
|
||||
[NonSerialized]
|
||||
private DalamudPluginInterface? m_PluginInterface;
|
||||
|
||||
public event System.Action? Saved;
|
||||
|
||||
public void Initialize(DalamudPluginInterface pluginInterface, DataManager dataManager)
|
||||
{
|
||||
m_PluginInterface = pluginInterface;
|
||||
|
||||
// Populate each role config with all of its jobs if they aren't already in it
|
||||
foreach (var roleConfigPair in RoleTag.RoleOverrideConfigs)
|
||||
{
|
||||
var role = roleConfigPair.Key;
|
||||
var roleConfig = roleConfigPair.Value;
|
||||
|
||||
var classJobs = dataManager.GetExcelSheet<ClassJob>();
|
||||
if (classJobs != null)
|
||||
{
|
||||
foreach (var classJob in classJobs.Where(classJob => RolesById[classJob.Role] == role))
|
||||
{
|
||||
if (!roleConfig.JobOverrideConfigs.ContainsKey(classJob.Abbreviation))
|
||||
{
|
||||
roleConfig.JobOverrideConfigs[classJob.Abbreviation] = new JobOverrideConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
if (m_PluginInterface != null)
|
||||
{
|
||||
m_PluginInterface.SavePluginConfig(this);
|
||||
Saved?.Invoke();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
403
PlayerTags/Config/MainConfigUI.cs
Normal file
403
PlayerTags/Config/MainConfigUI.cs
Normal file
@@ -0,0 +1,403 @@
|
||||
using Dalamud.Interface.Components;
|
||||
using Dalamud.Logging;
|
||||
using ImGuiNET;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using PlayerTags.Resources;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
public class MainConfigUI
|
||||
{
|
||||
private MainConfig m_Config;
|
||||
|
||||
private bool m_OpenPopupRequested;
|
||||
|
||||
private CustomColorConfig? m_ColorPickerPopupDataContext;
|
||||
|
||||
private bool m_IsVisible = false;
|
||||
public bool IsVisible
|
||||
{
|
||||
get { return m_IsVisible; }
|
||||
set { m_IsVisible = value; }
|
||||
}
|
||||
|
||||
public MainConfigUI(MainConfig config)
|
||||
{
|
||||
m_Config = config;
|
||||
}
|
||||
|
||||
private string GetLocString<TEnum>(bool isDescription)
|
||||
where TEnum : Enum
|
||||
{
|
||||
return GetLocString(typeof(TEnum).Name, isDescription);
|
||||
}
|
||||
|
||||
private string GetLocString<TEnum>(TEnum enumValue, bool isDescription)
|
||||
where TEnum : Enum
|
||||
{
|
||||
return GetLocString($"{typeof(TEnum).Name}_{enumValue}", isDescription);
|
||||
}
|
||||
|
||||
private string GetLocString(string locStringId, bool isDescription)
|
||||
{
|
||||
string completeLocStringId = $"Loc_{locStringId}";
|
||||
|
||||
if (isDescription)
|
||||
{
|
||||
completeLocStringId += "_Description";
|
||||
}
|
||||
|
||||
return GetLocString(completeLocStringId);
|
||||
}
|
||||
|
||||
private string GetLocString(string completeLocStringId)
|
||||
{
|
||||
string? value = Strings.ResourceManager.GetString(completeLocStringId, Strings.Culture);
|
||||
if (value != null)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
PluginLog.Error($"Failed to get localized string for id {completeLocStringId}");
|
||||
return completeLocStringId;
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if (m_Config == null || !IsVisible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ImGui.Begin(Strings.Loc_Static_PluginName, ref m_IsVisible))
|
||||
{
|
||||
if (ImGui.BeginTabBar("MainTabBar"))
|
||||
{
|
||||
if (ImGui.BeginTabItem(Strings.Loc_Static_General))
|
||||
{
|
||||
DrawHeading(Strings.Loc_Static_Nameplates);
|
||||
DrawEnumComboBox(
|
||||
ref m_Config.FreeCompanyVisibility,
|
||||
() => m_Config.Save());
|
||||
DrawEnumComboBox(
|
||||
ref m_Config.TitleVisibility,
|
||||
() => m_Config.Save());
|
||||
DrawEnumComboBox(
|
||||
ref m_Config.TitlePosition,
|
||||
() => m_Config.Save());
|
||||
DrawHeading(Strings.Loc_Static_Development);
|
||||
DrawCheckbox(
|
||||
nameof(m_Config.IsPlayerNameRandomlyGenerated),
|
||||
ref m_Config.IsPlayerNameRandomlyGenerated,
|
||||
() => m_Config.Save());
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui.BeginTabItem(Strings.Loc_Static_RoleAndJobTags))
|
||||
{
|
||||
DrawEnumComboBox(
|
||||
ref m_Config.RoleTag.Format,
|
||||
() => m_Config.Save());
|
||||
DrawTagConfig(m_Config.RoleTag);
|
||||
|
||||
DrawHeading(Strings.Loc_Static_Roles);
|
||||
if (ImGui.BeginTabBar("JobAndRolesTabBar"))
|
||||
{
|
||||
foreach (var rolePair in m_Config.RoleTag.RoleOverrideConfigs)
|
||||
{
|
||||
var role = rolePair.Key;
|
||||
var roleConfig = rolePair.Value;
|
||||
|
||||
if (ImGui.BeginTabItem(GetLocString($"{role.GetType().Name}_{role}", false)))
|
||||
{
|
||||
DrawCheckbox(
|
||||
$"{roleConfig.GetType().Name}_{nameof(roleConfig.IsEnabled)}",
|
||||
ref roleConfig.IsEnabled,
|
||||
() => m_Config.Save());
|
||||
DrawTextBox(
|
||||
$"{roleConfig.GetType().Name}_{nameof(roleConfig.Name)}",
|
||||
ref roleConfig.Name,
|
||||
() => m_Config.Save());
|
||||
DrawOptionalCustomColor(
|
||||
$"{roleConfig.CustomColor.GetType().Name}_IsEnabled",
|
||||
roleConfig.CustomColor.Id.ToString()!,
|
||||
roleConfig.CustomColor);
|
||||
DrawHeading(Strings.Loc_Static_Jobs);
|
||||
foreach (var key in roleConfig.JobOverrideConfigs.Keys.OrderBy(key => key))
|
||||
{
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
JobOverrideConfig jobConfig = roleConfig.JobOverrideConfigs[key];
|
||||
|
||||
ImGui.Columns(2, "columns", false);
|
||||
ImGui.SetColumnWidth(0, 42);
|
||||
ImGui.Text(key);
|
||||
ImGui.NextColumn();
|
||||
DrawOptionalCustomColor(
|
||||
$"{roleConfig.CustomColor.GetType().Name}_IsEnabled",
|
||||
key,
|
||||
jobConfig.CustomColor);
|
||||
|
||||
ImGui.Columns();
|
||||
}
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndTabBar();
|
||||
}
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui.BeginTabItem(Strings.Loc_Static_CustomTags))
|
||||
{
|
||||
if (ImGui.Button(Strings.Loc_Static_AddCustomTag))
|
||||
{
|
||||
m_Config.CustomTagConfigs.Add(new CustomTagConfig());
|
||||
m_Config.Save();
|
||||
}
|
||||
|
||||
if (!m_Config.CustomTagConfigs.Any())
|
||||
{
|
||||
ImGui.Text(Strings.Loc_Static_NoCustomTagsAdded);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var customTagConfig in m_Config.CustomTagConfigs.ToArray())
|
||||
{
|
||||
ImGui.PushID(customTagConfig.GetHashCode().ToString());
|
||||
ImGui.Separator();
|
||||
DrawTextBox(
|
||||
$"{customTagConfig.GetType().Name}_{nameof(customTagConfig.Name)}",
|
||||
ref customTagConfig.Name,
|
||||
() => { m_Config.Save(); });
|
||||
DrawOptionalCustomColor(
|
||||
$"{customTagConfig.CustomColor.GetType().Name}_IsEnabled",
|
||||
customTagConfig.CustomColor.Id.ToString()!,
|
||||
customTagConfig.CustomColor);
|
||||
DrawTextBox(
|
||||
$"{customTagConfig.GetType().Name}_{nameof(customTagConfig.FormattedGameObjectNames)}",
|
||||
ref customTagConfig.FormattedGameObjectNames,
|
||||
() => { m_Config.Save(); });
|
||||
DrawTagConfig(customTagConfig);
|
||||
ImGui.Spacing();
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.4f, 0.1f, 0.1f, 1));
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(0.6f, 0.2f, 0.2f, 1));
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(0.6f, 0.2f, 0.2f, 1));
|
||||
if (ImGui.Button(Strings.Loc_Static_RemoveCustomTag))
|
||||
{
|
||||
m_Config.CustomTagConfigs.Remove(customTagConfig);
|
||||
m_Config.Save();
|
||||
}
|
||||
ImGui.PopStyleColor();
|
||||
ImGui.PopStyleColor();
|
||||
ImGui.PopStyleColor();
|
||||
ImGui.PopID();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
ImGui.EndTabBar();
|
||||
}
|
||||
|
||||
if (m_OpenPopupRequested == true)
|
||||
{
|
||||
m_OpenPopupRequested = false;
|
||||
ImGui.OpenPopup("ColorPickerPopup");
|
||||
}
|
||||
|
||||
ImGui.SetNextWindowSize(new Vector2(400, 284));
|
||||
if (ImGui.BeginPopup("ColorPickerPopup"))
|
||||
{
|
||||
DrawUIColorPicker(
|
||||
(UIColor value) =>
|
||||
{
|
||||
if (m_ColorPickerPopupDataContext != null)
|
||||
{
|
||||
m_ColorPickerPopupDataContext.Id = (ushort)value.RowId;
|
||||
m_ColorPickerPopupDataContext = null;
|
||||
m_Config.Save();
|
||||
}
|
||||
|
||||
ImGui.CloseCurrentPopup();
|
||||
});
|
||||
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
ImGui.End();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawTagConfig(TagConfig tagConfig)
|
||||
{
|
||||
if (m_Config == null || !IsVisible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DrawHeading(Strings.Loc_Static_ChatTag);
|
||||
ImGui.PushID("Chat");
|
||||
DrawEnumComboBox(
|
||||
ref tagConfig.ChatPosition,
|
||||
() => m_Config.Save());
|
||||
ImGui.PopID();
|
||||
DrawHeading(Strings.Loc_Static_NameplateTag);
|
||||
ImGui.PushID("Nameplate");
|
||||
DrawEnumComboBox(
|
||||
ref tagConfig.NameplatePosition,
|
||||
() => m_Config.Save());
|
||||
DrawEnumComboBox(
|
||||
ref tagConfig.NameplateElement,
|
||||
() => m_Config.Save());
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
private void DrawOptionalCustomColor(string locStringId, string colorId, CustomColorConfig customColorConfig)
|
||||
{
|
||||
if (customColorConfig.Id.HasValue)
|
||||
{
|
||||
DrawColorButton(
|
||||
colorId,
|
||||
UIColorHelper.ToColor(customColorConfig.Id.Value),
|
||||
() =>
|
||||
{
|
||||
m_ColorPickerPopupDataContext = customColorConfig;
|
||||
m_OpenPopupRequested = true;
|
||||
});
|
||||
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
var isChecked = customColorConfig.Id != null;
|
||||
DrawCheckbox(
|
||||
locStringId,
|
||||
ref isChecked,
|
||||
() =>
|
||||
{
|
||||
if (!isChecked)
|
||||
{
|
||||
customColorConfig.Id = null;
|
||||
m_Config.Save();
|
||||
}
|
||||
else
|
||||
{
|
||||
customColorConfig.Id = (ushort)UIColorHelper.UIColors.First().RowId;
|
||||
m_Config.Save();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void DrawSeparator()
|
||||
{
|
||||
ImGui.Spacing();
|
||||
ImGui.Spacing();
|
||||
ImGui.Spacing();
|
||||
ImGui.Spacing();
|
||||
}
|
||||
|
||||
private void DrawHeading(string label)
|
||||
{
|
||||
ImGui.TextColored(new Vector4(0.7f, 0.6f, 1f, 1f), label);
|
||||
}
|
||||
|
||||
private void DrawEnumComboBox<TEnum>(ref TEnum currentValue, System.Action changed)
|
||||
where TEnum : Enum
|
||||
{
|
||||
ImGui.Text(GetLocString<TEnum>(false));
|
||||
ImGuiComponents.HelpMarker(GetLocString<TEnum>(true));
|
||||
|
||||
if (ImGui.BeginCombo($"###{currentValue.GetType().Name}", GetLocString(currentValue, false)))
|
||||
{
|
||||
foreach (string enumValueString in typeof(TEnum).GetEnumNames())
|
||||
{
|
||||
TEnum enumValue = (TEnum)Enum.Parse(typeof(TEnum), enumValueString);
|
||||
bool isSelected = enumValueString == currentValue.ToString();
|
||||
if (ImGui.Selectable($"{GetLocString(enumValue, false)}###{enumValueString}", isSelected))
|
||||
{
|
||||
currentValue = (TEnum)Enum.Parse(typeof(TEnum), enumValueString);
|
||||
ImGui.SetItemDefaultFocus();
|
||||
changed();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.SetTooltip(GetLocString(enumValue, true));
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndCombo();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.SetTooltip(GetLocString(currentValue, true));
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawCheckbox(string locStringId, ref bool isChecked, System.Action changed)
|
||||
{
|
||||
if (ImGui.Checkbox(GetLocString(locStringId, false), ref isChecked))
|
||||
{
|
||||
changed();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.SetTooltip(GetLocString(locStringId, true));
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawColorButton(string colorId, Vector4 color, System.Action clicked)
|
||||
{
|
||||
if (ImGui.ColorButton(colorId, color))
|
||||
{
|
||||
clicked();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawTextBox(string locStringId, ref string text, System.Action changed)
|
||||
{
|
||||
ImGui.Text(GetLocString(locStringId, false));
|
||||
ImGuiComponents.HelpMarker(GetLocString(locStringId, true));
|
||||
|
||||
var oldText = text;
|
||||
ImGui.InputText($"###{locStringId}", ref text, 1024);
|
||||
if (text != oldText)
|
||||
{
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawUIColorPicker(System.Action<UIColor> clicked)
|
||||
{
|
||||
ImGui.PushID(clicked.GetHashCode());
|
||||
ImGui.Columns(12, "columns", false);
|
||||
foreach (var uiColor in UIColorHelper.UIColors)
|
||||
{
|
||||
DrawColorButton(
|
||||
uiColor.RowId.ToString(),
|
||||
UIColorHelper.ToColor(uiColor),
|
||||
() =>
|
||||
{
|
||||
clicked(uiColor);
|
||||
});
|
||||
|
||||
ImGui.NextColumn();
|
||||
}
|
||||
ImGui.Columns();
|
||||
ImGui.PopID();
|
||||
}
|
||||
}
|
||||
}
|
||||
9
PlayerTags/Config/NameplateElement.cs
Normal file
9
PlayerTags/Config/NameplateElement.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
public enum NameplateElement
|
||||
{
|
||||
Name,
|
||||
Title,
|
||||
FreeCompany
|
||||
}
|
||||
}
|
||||
10
PlayerTags/Config/Role.cs
Normal file
10
PlayerTags/Config/Role.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
public enum Role
|
||||
{
|
||||
LandHand,
|
||||
Tank,
|
||||
Healer,
|
||||
DPS
|
||||
}
|
||||
}
|
||||
14
PlayerTags/Config/RoleOverrideConfig.cs
Normal file
14
PlayerTags/Config/RoleOverrideConfig.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
[Serializable]
|
||||
public class RoleOverrideConfig
|
||||
{
|
||||
public bool IsEnabled = true;
|
||||
public string Name = "";
|
||||
public CustomColorConfig CustomColor = new CustomColorConfig();
|
||||
public Dictionary<string, JobOverrideConfig> JobOverrideConfigs = new Dictionary<string, JobOverrideConfig>();
|
||||
}
|
||||
}
|
||||
19
PlayerTags/Config/RoleTagConfig.cs
Normal file
19
PlayerTags/Config/RoleTagConfig.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
[Serializable]
|
||||
public class RoleTagConfig : TagConfig
|
||||
{
|
||||
public RoleTagFormat Format = RoleTagFormat.AbbreviatedJobName;
|
||||
|
||||
public Dictionary<Role, RoleOverrideConfig> RoleOverrideConfigs = new Dictionary<Role, RoleOverrideConfig>()
|
||||
{
|
||||
{ Role.LandHand, new RoleOverrideConfig() { IsEnabled = true, Name = "Land/Hand", CustomColor = new CustomColorConfig() { Id = 3 } } },
|
||||
{ Role.Tank, new RoleOverrideConfig() { IsEnabled = true, Name = "Tank", CustomColor = new CustomColorConfig() { Id = 542 } } },
|
||||
{ Role.Healer, new RoleOverrideConfig() { IsEnabled = true, Name = "Healer", CustomColor = new CustomColorConfig() { Id = 45 } } },
|
||||
{ Role.DPS, new RoleOverrideConfig() { IsEnabled = true, Name = "DPS", CustomColor = new CustomColorConfig() { Id = 511 } } },
|
||||
};
|
||||
}
|
||||
}
|
||||
9
PlayerTags/Config/RoleTagFormat.cs
Normal file
9
PlayerTags/Config/RoleTagFormat.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
public enum RoleTagFormat
|
||||
{
|
||||
AbbreviatedJobName,
|
||||
JobName,
|
||||
RoleName
|
||||
}
|
||||
}
|
||||
10
PlayerTags/Config/StringPosition.cs
Normal file
10
PlayerTags/Config/StringPosition.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
public enum StringPosition
|
||||
{
|
||||
None,
|
||||
Before,
|
||||
After,
|
||||
Replace
|
||||
}
|
||||
}
|
||||
14
PlayerTags/Config/TagConfig.cs
Normal file
14
PlayerTags/Config/TagConfig.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
[Serializable]
|
||||
public class TagConfig
|
||||
{
|
||||
public NameplateElement NameplateElement = NameplateElement.Name;
|
||||
|
||||
public StringPosition NameplatePosition = StringPosition.Before;
|
||||
|
||||
public StringPosition ChatPosition = StringPosition.Before;
|
||||
}
|
||||
}
|
||||
9
PlayerTags/Config/TitleNameplatePosition.cs
Normal file
9
PlayerTags/Config/TitleNameplatePosition.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
public enum TitleNameplatePosition
|
||||
{
|
||||
Default,
|
||||
AlwaysAboveName,
|
||||
AlwaysBelowName
|
||||
}
|
||||
}
|
||||
10
PlayerTags/Config/TitleNameplateVisibility.cs
Normal file
10
PlayerTags/Config/TitleNameplateVisibility.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace PlayerTags.Config
|
||||
{
|
||||
public enum TitleNameplateVisibility
|
||||
{
|
||||
Default,
|
||||
Always,
|
||||
Never,
|
||||
WhenHasTags
|
||||
}
|
||||
}
|
||||
12
PlayerTags/DalamudPackager.targets
Normal file
12
PlayerTags/DalamudPackager.targets
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project>
|
||||
<Target Name="PackagePlugin" AfterTargets="Build" Condition="'$(Configuration)' == 'Release'">
|
||||
<DalamudPackager
|
||||
ProjectDir="$(ProjectDir)"
|
||||
OutputPath="$(OutputPath)"
|
||||
AssemblyName="$(AssemblyName)"
|
||||
MakeZip="true"
|
||||
Exclude="PlayerTags.pdb;PlayerTags.deps.json"
|
||||
/>
|
||||
</Target>
|
||||
</Project>
|
||||
78
PlayerTags/PlayerTags.csproj
Normal file
78
PlayerTags/PlayerTags.csproj
Normal file
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Authors>r00telement</Authors>
|
||||
<Version>1.0.0.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0-windows7.0</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<OutputPath>$(AppData)\XIVLauncher\devPlugins\PlayerTags\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.2" />
|
||||
<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>
|
||||
<Compile Update="Resources\Strings.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Strings.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<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>
|
||||
11
PlayerTags/PlayerTags.json
Normal file
11
PlayerTags/PlayerTags.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"Author": "r00telement",
|
||||
"Name": "Player Tags",
|
||||
"Description": "See tags for players in nameplates and chat, such as their role and job, or custom tags for players you know.",
|
||||
"RepoUrl": "https://github.com/r00telement/PlayerTags",
|
||||
"IconUrl": "https://github.com/r00telement/PlayerTags/master/Resources/Chat_1.png",
|
||||
"ImageUrls": [
|
||||
"https://github.com/r00telement/PlayerTags/master/Resources/Chat_1.png",
|
||||
"https://github.com/r00telement/PlayerTags/master/Resources/Nameplates_1.png"
|
||||
]
|
||||
}
|
||||
619
PlayerTags/Plugin.cs
Normal file
619
PlayerTags/Plugin.cs
Normal file
@@ -0,0 +1,619 @@
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Command;
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.Game.Text;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.Logging;
|
||||
using Dalamud.Plugin;
|
||||
using PlayerTags.Config;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace PlayerTags
|
||||
{
|
||||
public sealed class Plugin : IDalamudPlugin
|
||||
{
|
||||
public string Name => "Player Tags";
|
||||
|
||||
private const string c_CommandName = "/playertags";
|
||||
|
||||
[PluginService]
|
||||
private static DalamudPluginInterface PluginInterface { get; set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
private static Framework Framework { get; set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
private static ChatGui ChatGui { get; set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
private static GameGui GameGui { get; set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
private static ObjectTable ObjectTable { get; set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
private static DataManager DataManager { get; set; } = null!;
|
||||
|
||||
[PluginService]
|
||||
private static CommandManager CommandManager { get; set; } = null!;
|
||||
|
||||
private MainConfig m_Config;
|
||||
|
||||
private MainConfigUI m_ConfigUI;
|
||||
|
||||
private Dictionary<string, Payload[]> m_JobTagPayloads = new Dictionary<string, Payload[]>();
|
||||
|
||||
private Dictionary<CustomTagConfig, Payload[]> m_CustomTagPayloads = new Dictionary<CustomTagConfig, Payload[]>();
|
||||
|
||||
private TextPayload m_SpaceTextPayload = new TextPayload($" ");
|
||||
|
||||
private PluginHooks m_PluginHooks;
|
||||
|
||||
private RandomNameGenerator? m_RandomNameGenerator = null;
|
||||
|
||||
public Plugin()
|
||||
{
|
||||
UIColorHelper.Initialize(DataManager);
|
||||
|
||||
m_Config = PluginInterface.GetPluginConfig() as MainConfig ?? new MainConfig();
|
||||
m_Config.Initialize(PluginInterface, DataManager);
|
||||
m_Config.Saved += Configuration_Saved;
|
||||
|
||||
m_ConfigUI = new MainConfigUI(m_Config);
|
||||
|
||||
CommandManager.AddHandler(c_CommandName, new CommandInfo((string command, string arguments) =>
|
||||
{
|
||||
m_ConfigUI.IsVisible = true;
|
||||
})
|
||||
{
|
||||
HelpMessage = "Shows the config"
|
||||
});
|
||||
|
||||
PluginInterface.UiBuilder.Draw += UiBuilder_Draw;
|
||||
PluginInterface.UiBuilder.OpenConfigUi += UiBuilder_OpenConfigUi;
|
||||
|
||||
m_PluginHooks = new PluginHooks(Framework, ObjectTable, GameGui, SetNameplate);
|
||||
|
||||
ChatGui.ChatMessage += Chat_ChatMessage;
|
||||
|
||||
if (m_Config.IsPlayerNameRandomlyGenerated && m_RandomNameGenerator == null)
|
||||
{
|
||||
m_RandomNameGenerator = new RandomNameGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
PluginInterface.UiBuilder.OpenConfigUi -= UiBuilder_OpenConfigUi;
|
||||
CommandManager.RemoveHandler(c_CommandName);
|
||||
ChatGui.ChatMessage -= Chat_ChatMessage;
|
||||
m_Config.Saved -= Configuration_Saved;
|
||||
m_PluginHooks?.Dispose();
|
||||
}
|
||||
|
||||
private void Configuration_Saved()
|
||||
{
|
||||
// Invalidate the cached payloads so they get remade
|
||||
m_JobTagPayloads.Clear();
|
||||
m_CustomTagPayloads.Clear();
|
||||
|
||||
if (m_Config.IsPlayerNameRandomlyGenerated && m_RandomNameGenerator == null)
|
||||
{
|
||||
m_RandomNameGenerator = new RandomNameGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
private void UiBuilder_Draw()
|
||||
{
|
||||
m_ConfigUI.Draw();
|
||||
}
|
||||
|
||||
private void UiBuilder_OpenConfigUi()
|
||||
{
|
||||
m_ConfigUI.IsVisible = true;
|
||||
}
|
||||
|
||||
private void Chat_ChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled)
|
||||
{
|
||||
AddTagsToChat(sender, out _);
|
||||
AddTagsToChat(message, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the strings on a nameplate.
|
||||
/// </summary>
|
||||
/// <param name="gameObject">The game object context.</param>
|
||||
/// <param name="name">The name text.</param>
|
||||
/// <param name="title">The title text.</param>
|
||||
/// <param name="freeCompany">The free company text.</param>
|
||||
/// <param name="isTitleVisible">Whether the title is visible.</param>
|
||||
/// <param name="isTitleAboveName">Whether the title is above the name or below it.</param>
|
||||
/// <param name="iconId">The icon id.</param>
|
||||
/// <param name="isNameChanged">Whether the name was changed.</param>
|
||||
/// <param name="isTitleChanged">Whether the title was changed.</param>
|
||||
/// <param name="isFreeCompanyChanged">Whether the free company was changed.</param>
|
||||
private void SetNameplate(GameObject gameObject, SeString name, SeString title, SeString freeCompany, ref bool isTitleVisible, ref bool isTitleAboveName, ref int iconId, out bool isNameChanged, out bool isTitleChanged, out bool isFreeCompanyChanged)
|
||||
{
|
||||
AddTagsToNameplate(gameObject, name, title, freeCompany, out isNameChanged, out isTitleChanged, out isFreeCompanyChanged);
|
||||
|
||||
if (m_Config.TitlePosition == TitleNameplatePosition.AlwaysAboveName)
|
||||
{
|
||||
isTitleAboveName = true;
|
||||
}
|
||||
else if (m_Config.TitlePosition == TitleNameplatePosition.AlwaysBelowName)
|
||||
{
|
||||
isTitleAboveName = false;
|
||||
}
|
||||
|
||||
if (m_Config.TitleVisibility == TitleNameplateVisibility.Default)
|
||||
{
|
||||
}
|
||||
else if (m_Config.TitleVisibility == TitleNameplateVisibility.Always)
|
||||
{
|
||||
isTitleVisible = true;
|
||||
}
|
||||
else if (m_Config.TitleVisibility == TitleNameplateVisibility.Never)
|
||||
{
|
||||
isTitleVisible = false;
|
||||
}
|
||||
else if (m_Config.TitleVisibility == TitleNameplateVisibility.WhenHasTags)
|
||||
{
|
||||
isTitleVisible = isTitleChanged;
|
||||
}
|
||||
|
||||
if (m_Config.FreeCompanyVisibility == FreeCompanyNameplateVisibility.Default)
|
||||
{
|
||||
}
|
||||
else if (m_Config.FreeCompanyVisibility == FreeCompanyNameplateVisibility.Never)
|
||||
{
|
||||
freeCompany.Payloads.Clear();
|
||||
isFreeCompanyChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the job tag payloads for the given character. If the payloads don't yet exist then they are created.
|
||||
/// </summary>
|
||||
/// <param name="character">The character to get job tag payloads for.</param>
|
||||
/// <returns>A list of job tag payloads for the given character.</returns>
|
||||
private IEnumerable<Payload> GetJobTagPayloads(Character character)
|
||||
{
|
||||
var roleId = character.ClassJob.GameData.Role;
|
||||
var jobAbbreviation = character.ClassJob.GameData.Abbreviation;
|
||||
var role = MainConfig.RolesById[roleId];
|
||||
|
||||
var roleConfig = m_Config.RoleTag.RoleOverrideConfigs[role];
|
||||
if (!roleConfig.IsEnabled)
|
||||
{
|
||||
return new Payload[] { };
|
||||
}
|
||||
|
||||
if (m_JobTagPayloads.TryGetValue(jobAbbreviation, out var payloads))
|
||||
{
|
||||
return payloads;
|
||||
}
|
||||
|
||||
string text = "";
|
||||
if (m_Config.RoleTag.Format == RoleTagFormat.AbbreviatedJobName)
|
||||
{
|
||||
text = character.ClassJob.GameData.Abbreviation;
|
||||
}
|
||||
else if (m_Config.RoleTag.Format == RoleTagFormat.JobName)
|
||||
{
|
||||
text = character.ClassJob.GameData.NameEnglish;
|
||||
}
|
||||
else if (m_Config.RoleTag.Format == RoleTagFormat.RoleName)
|
||||
{
|
||||
text = m_Config.RoleTag.RoleOverrideConfigs[role].Name;
|
||||
}
|
||||
|
||||
List<Payload> newPayloads = new List<Payload>();
|
||||
|
||||
// There will always be a text payload
|
||||
newPayloads.Add(new TextPayload(text));
|
||||
|
||||
ushort? colorId = null;
|
||||
|
||||
// Pick a color id if one is available
|
||||
if (roleConfig.JobOverrideConfigs[jobAbbreviation].CustomColor.Id != null)
|
||||
{
|
||||
colorId = roleConfig.JobOverrideConfigs[jobAbbreviation].CustomColor.Id!.Value;
|
||||
}
|
||||
else if (roleConfig.CustomColor.Id != null)
|
||||
{
|
||||
colorId = roleConfig.CustomColor.Id.Value;
|
||||
}
|
||||
|
||||
// If we picked a color id, add the payloads for it
|
||||
if (colorId != null)
|
||||
{
|
||||
newPayloads.Insert(0, new UIForegroundPayload(colorId.Value));
|
||||
newPayloads.Add(new UIForegroundPayload(0));
|
||||
}
|
||||
|
||||
var newPayloadsArray = newPayloads.ToArray();
|
||||
m_JobTagPayloads[jobAbbreviation] = newPayloadsArray;
|
||||
|
||||
return newPayloadsArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the payloads for the given custom tag. If the payloads don't yet exist then they are created.
|
||||
/// </summary>
|
||||
/// <param name="customTagConfig">The custom tag config to get payloads for.</param>
|
||||
/// <returns>A list of payloads for the given custom tag.</returns>
|
||||
private IEnumerable<Payload> GetCustomTagPayloads(CustomTagConfig customTagConfig)
|
||||
{
|
||||
if (m_CustomTagPayloads.TryGetValue(customTagConfig, out var payloads))
|
||||
{
|
||||
return payloads;
|
||||
}
|
||||
|
||||
List<Payload> newPayloads = new List<Payload>();
|
||||
|
||||
// There will always be a text payload
|
||||
newPayloads.Add(new TextPayload(customTagConfig.Name));
|
||||
|
||||
ushort? colorId = null;
|
||||
|
||||
// Pick a color id if one is available
|
||||
if (customTagConfig.CustomColor.Id != null)
|
||||
{
|
||||
colorId = customTagConfig.CustomColor.Id!.Value;
|
||||
}
|
||||
|
||||
// If we picked a color id, add the payloads for it
|
||||
if (colorId != null)
|
||||
{
|
||||
newPayloads.Insert(0, new UIForegroundPayload(colorId.Value));
|
||||
newPayloads.Add(new UIForegroundPayload(0));
|
||||
}
|
||||
|
||||
var newPayloadsArray = newPayloads.ToArray();
|
||||
m_CustomTagPayloads[customTagConfig] = newPayloadsArray;
|
||||
|
||||
return newPayloadsArray;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds an additional space text payload in between any existing text payloads.
|
||||
/// </summary>
|
||||
/// <param name="payloads">The payloads to add spaces between.</param>
|
||||
private void AddSpacesBetweenTextPayloads(List<Payload> payloads)
|
||||
{
|
||||
var textPayloads = payloads.Where(payload => payload is TextPayload).ToList();
|
||||
foreach (var textPayload in textPayloads.Skip(1))
|
||||
{
|
||||
var index = payloads.IndexOf(textPayload);
|
||||
payloads.Insert(index, m_SpaceTextPayload);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A match found within a string.
|
||||
/// </summary>
|
||||
private class StringMatch
|
||||
{
|
||||
/// <summary>
|
||||
/// The string that the match was found in.
|
||||
/// </summary>
|
||||
public SeString SeString { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The matching text payload.
|
||||
/// </summary>
|
||||
public TextPayload TextPayload { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The matching game object.
|
||||
/// </summary>
|
||||
public GameObject? GameObject { get; init; }
|
||||
|
||||
public StringMatch(SeString seString, TextPayload textPayload, GameObject? gameObject = null)
|
||||
{
|
||||
SeString = seString;
|
||||
TextPayload = textPayload;
|
||||
GameObject = gameObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the matches text.
|
||||
/// </summary>
|
||||
/// <returns>The match text.</returns>
|
||||
public string GetMatchText()
|
||||
{
|
||||
if (GameObject != null)
|
||||
{
|
||||
return GameObject.Name.TextValue;
|
||||
}
|
||||
|
||||
return TextPayload.Text;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 = new List<StringMatch>();
|
||||
|
||||
for (int payloadIndex = 0; payloadIndex < seString.Payloads.Count; ++payloadIndex)
|
||||
{
|
||||
var payload = seString.Payloads[payloadIndex];
|
||||
if (payload is PlayerPayload playerPayload)
|
||||
{
|
||||
var gameObject = ObjectTable.FirstOrDefault(gameObject => gameObject.Name.TextValue == playerPayload.PlayerName);
|
||||
|
||||
// The next payload MUST be a text payload
|
||||
if (payloadIndex + 1 < seString.Payloads.Count && seString.Payloads[payloadIndex + 1] is TextPayload textPayload)
|
||||
{
|
||||
var stringMatch = new StringMatch(seString, textPayload, gameObject);
|
||||
stringMatches.Add(stringMatch);
|
||||
|
||||
// Don't handle the text payload twice
|
||||
payloadIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
PluginLog.Error("Expected payload after player payload to be a text payload but it wasn't");
|
||||
}
|
||||
}
|
||||
|
||||
// If it's just a text payload then either a character NEEDS to exist for it, or it needs to be identified as a character by custom tag configs
|
||||
else if (payload is TextPayload textPayload)
|
||||
{
|
||||
var gameObject = ObjectTable.FirstOrDefault(gameObject => gameObject.Name.TextValue == textPayload.Text);
|
||||
var isIncludedInCustomTagConfig = m_Config.CustomTagConfigs.Any(customTagConfig => customTagConfig.IncludesGameObjectName(textPayload.Text));
|
||||
|
||||
if (gameObject != null || isIncludedInCustomTagConfig)
|
||||
{
|
||||
var stringMatch = new StringMatch(seString, textPayload, gameObject);
|
||||
stringMatches.Add(stringMatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stringMatches;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given payload changes to the dictionary.
|
||||
/// </summary>
|
||||
/// <param name="stringPosition">The position of the string to add changes to.</param>
|
||||
/// <param name="payloads">The payloads to add.</param>
|
||||
/// <param name="stringChanges">The dictionary to add the changes to.</param>
|
||||
private void AddPayloadChanges(StringPosition stringPosition, IEnumerable<Payload> payloads, Dictionary<StringPosition, List<Payload>> stringChanges)
|
||||
{
|
||||
if (!payloads.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!stringChanges.Keys.Contains(stringPosition))
|
||||
{
|
||||
stringChanges[stringPosition] = new List<Payload>();
|
||||
}
|
||||
|
||||
stringChanges[stringPosition].AddRange(payloads);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given payload changes to the dictionary.
|
||||
/// </summary>
|
||||
/// <param name="nameplateElement">The nameplate element to add changes to.</param>
|
||||
/// <param name="stringPosition">The position of the string to add changes to.</param>
|
||||
/// <param name="payloads">The payloads to add.</param>
|
||||
/// <param name="nameplateChanges">The dictionary to add the changes to.</param>
|
||||
private void AddPayloadChanges(NameplateElement nameplateElement, StringPosition stringPosition, IEnumerable<Payload> payloads, Dictionary<NameplateElement, Dictionary<StringPosition, List<Payload>>> nameplateChanges)
|
||||
{
|
||||
if (!payloads.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nameplateChanges.Keys.Contains(nameplateElement))
|
||||
{
|
||||
nameplateChanges[nameplateElement] = new Dictionary<StringPosition, List<Payload>>();
|
||||
}
|
||||
|
||||
AddPayloadChanges(stringPosition, payloads, nameplateChanges[nameplateElement]);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
private void ApplyStringChanges(SeString seString, Dictionary<StringPosition, List<Payload>> stringChanges, Payload? anchorPayload = null)
|
||||
{
|
||||
foreach ((var stringPosition, var payloads) in stringChanges)
|
||||
{
|
||||
if (!payloads.Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AddSpacesBetweenTextPayloads(payloads);
|
||||
|
||||
if (stringPosition == StringPosition.Before)
|
||||
{
|
||||
if (anchorPayload != null)
|
||||
{
|
||||
var payloadIndex = seString.Payloads.IndexOf(anchorPayload);
|
||||
seString.Payloads.InsertRange(payloadIndex, payloads.Append(m_SpaceTextPayload));
|
||||
}
|
||||
else
|
||||
{
|
||||
seString.Payloads.InsertRange(0, payloads.Append(m_SpaceTextPayload));
|
||||
}
|
||||
}
|
||||
else if (stringPosition == StringPosition.After)
|
||||
{
|
||||
if (anchorPayload != null)
|
||||
{
|
||||
var payloadIndex = seString.Payloads.IndexOf(anchorPayload);
|
||||
seString.Payloads.InsertRange(payloadIndex + 1, payloads.Prepend(m_SpaceTextPayload));
|
||||
}
|
||||
else
|
||||
{
|
||||
seString.Payloads.AddRange(payloads.Prepend(m_SpaceTextPayload));
|
||||
}
|
||||
}
|
||||
else if (stringPosition == StringPosition.Replace)
|
||||
{
|
||||
if (anchorPayload != null)
|
||||
{
|
||||
var payloadIndex = seString.Payloads.IndexOf(anchorPayload);
|
||||
seString.Payloads.InsertRange(payloadIndex, payloads);
|
||||
seString.Payloads.Remove(anchorPayload);
|
||||
}
|
||||
else
|
||||
{
|
||||
seString.Payloads.Clear();
|
||||
seString.Payloads.AddRange(payloads);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all configured 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>
|
||||
/// <param name="isNameChanged">Whether the name was changed.</param>
|
||||
/// <param name="isTitleChanged">Whether the title was changed.</param>
|
||||
/// <param name="isFreeCompanyChanged">Whether the free company was changed.</param>
|
||||
private void AddTagsToNameplate(GameObject gameObject, SeString name, SeString title, SeString freeCompany, out bool isNameChanged, out bool isTitleChanged, out bool isFreeCompanyChanged)
|
||||
{
|
||||
isNameChanged = false;
|
||||
isTitleChanged = false;
|
||||
isFreeCompanyChanged = false;
|
||||
|
||||
Dictionary<NameplateElement, Dictionary<StringPosition, List<Payload>>> nameplateChanges = new Dictionary<NameplateElement, Dictionary<StringPosition, List<Payload>>>();
|
||||
|
||||
if (gameObject is Character character)
|
||||
{
|
||||
// Add the role tag payloads
|
||||
if (m_Config.RoleTag.NameplatePosition != StringPosition.None)
|
||||
{
|
||||
AddPayloadChanges(m_Config.RoleTag.NameplateElement, m_Config.RoleTag.NameplatePosition, GetJobTagPayloads(character), nameplateChanges);
|
||||
}
|
||||
|
||||
// Add randomly generated name tag payload
|
||||
if (m_Config.IsPlayerNameRandomlyGenerated && m_RandomNameGenerator != null)
|
||||
{
|
||||
var characterName = character.Name.TextValue;
|
||||
if (characterName != null)
|
||||
{
|
||||
var generatedName = m_RandomNameGenerator.GetGeneratedName(characterName);
|
||||
if (generatedName != null)
|
||||
{
|
||||
AddPayloadChanges(NameplateElement.Name, StringPosition.Replace, Enumerable.Empty<Payload>().Append(new TextPayload(generatedName)), nameplateChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the custom tag payloads
|
||||
foreach (var customTagConfig in m_Config.CustomTagConfigs)
|
||||
{
|
||||
if (customTagConfig.NameplatePosition != StringPosition.None && customTagConfig.FormattedGameObjectNames.Split(',').Contains(gameObject.Name.TextValue))
|
||||
{
|
||||
AddPayloadChanges(customTagConfig.NameplateElement, customTagConfig.NameplatePosition, GetCustomTagPayloads(customTagConfig), nameplateChanges);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the final strings out of the payloads
|
||||
foreach ((var nameplateElement, var stringChanges) in nameplateChanges)
|
||||
{
|
||||
SeString? seString = null;
|
||||
if (nameplateElement == NameplateElement.Name)
|
||||
{
|
||||
seString = name;
|
||||
isNameChanged = true;
|
||||
}
|
||||
else if (nameplateElement == NameplateElement.Title)
|
||||
{
|
||||
seString = title;
|
||||
isTitleChanged = true;
|
||||
}
|
||||
else if (nameplateElement == NameplateElement.FreeCompany)
|
||||
{
|
||||
seString = freeCompany;
|
||||
isFreeCompanyChanged = true;
|
||||
}
|
||||
|
||||
if (seString != null)
|
||||
{
|
||||
ApplyStringChanges(seString, stringChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all configured tags to chat.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to change.</param>
|
||||
/// <param name="isMessageChanged">Whether the message was changed.</param>
|
||||
private void AddTagsToChat(SeString message, out bool isMessageChanged)
|
||||
{
|
||||
isMessageChanged = false;
|
||||
|
||||
var stringMatches = GetStringMatches(message);
|
||||
foreach (var stringMatch in stringMatches)
|
||||
{
|
||||
Dictionary<StringPosition, List<Payload>> stringChanges = new Dictionary<StringPosition, List<Payload>>();
|
||||
|
||||
// The role tag payloads
|
||||
if (stringMatch.GameObject is Character character)
|
||||
{
|
||||
if (m_Config.RoleTag.ChatPosition != StringPosition.None)
|
||||
{
|
||||
AddPayloadChanges(m_Config.RoleTag.ChatPosition, GetJobTagPayloads(character), stringChanges);
|
||||
}
|
||||
}
|
||||
|
||||
// Add randomly generated name tag payload
|
||||
if (m_Config.IsPlayerNameRandomlyGenerated && m_RandomNameGenerator != null)
|
||||
{
|
||||
var playerName = stringMatch.GetMatchText();
|
||||
if (playerName != null)
|
||||
{
|
||||
var generatedName = m_RandomNameGenerator.GetGeneratedName(playerName);
|
||||
if (generatedName != null)
|
||||
{
|
||||
AddPayloadChanges(StringPosition.Replace, Enumerable.Empty<Payload>().Append(new TextPayload(generatedName)), stringChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the custom tag payloads
|
||||
foreach (var customTagConfig in m_Config.CustomTagConfigs)
|
||||
{
|
||||
if (customTagConfig.IncludesGameObjectName(stringMatch.GetMatchText()))
|
||||
{
|
||||
AddPayloadChanges(customTagConfig.ChatPosition, GetCustomTagPayloads(customTagConfig), stringChanges);
|
||||
}
|
||||
}
|
||||
|
||||
ApplyStringChanges(message, stringChanges, stringMatch.TextPayload);
|
||||
isMessageChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
238
PlayerTags/PluginHooks.cs
Normal file
238
PlayerTags/PluginHooks.cs
Normal file
@@ -0,0 +1,238 @@
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Logging;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace PlayerTags
|
||||
{
|
||||
public class PluginHooks : IDisposable
|
||||
{
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Ansi)]
|
||||
private delegate IntPtr SetNameplateDelegate_Private(IntPtr nameplateObjectPtr, bool isTitleAboveName, bool isTitleVisible, IntPtr titlePtr, IntPtr namePtr, IntPtr freeCompanyPtr, int iconId);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Ansi)]
|
||||
private delegate IntPtr UIModule_GetRaptureAtkModuleDelegate_Private(IntPtr uiModule);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Ansi)]
|
||||
private delegate IntPtr Framework_GetUIModuleDelegate_Private(IntPtr framework);
|
||||
|
||||
private class PluginAddressResolver : BaseAddressResolver
|
||||
{
|
||||
private const string SetNameplateSignature = "48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 54 41 56 41 57 48 83 EC 40 44 0F B6 E2";
|
||||
internal IntPtr SetNameplatePtr;
|
||||
|
||||
private const string Framework_GetUIModuleSignature = "E8 ?? ?? ?? ?? 48 8B C8 48 8B 10 FF 92 ?? ?? ?? ?? 48 8B C8 BA ?? ?? ?? ??";
|
||||
internal IntPtr Framework_GetUIModulePtr;
|
||||
|
||||
protected override void Setup64Bit(SigScanner scanner)
|
||||
{
|
||||
SetNameplatePtr = scanner.ScanText(SetNameplateSignature);
|
||||
Framework_GetUIModulePtr = scanner.ScanText(Framework_GetUIModuleSignature);
|
||||
}
|
||||
}
|
||||
|
||||
private Framework m_Framework;
|
||||
private ObjectTable m_ObjectTable;
|
||||
private GameGui m_GameGui;
|
||||
private SetNameplateDelegate m_SetNameplate;
|
||||
|
||||
private PluginAddressResolver m_PluginAddressResolver;
|
||||
private Hook<SetNameplateDelegate_Private> m_SetNameplateHook;
|
||||
private readonly Framework_GetUIModuleDelegate_Private m_GetUIModule;
|
||||
private IntPtr? m_NameplateObjectArrayPtr;
|
||||
private IntPtr? m_NameplateInfoArrayPtr;
|
||||
|
||||
public PluginHooks(Framework framework, ObjectTable objectTable, GameGui gameGui, SetNameplateDelegate setNameplate)
|
||||
{
|
||||
m_Framework = framework;
|
||||
m_ObjectTable = objectTable;
|
||||
m_GameGui = gameGui;
|
||||
m_SetNameplate = setNameplate;
|
||||
|
||||
m_PluginAddressResolver = new PluginAddressResolver();
|
||||
m_PluginAddressResolver.Setup();
|
||||
|
||||
m_GetUIModule = Marshal.GetDelegateForFunctionPointer<Framework_GetUIModuleDelegate_Private>(m_PluginAddressResolver.Framework_GetUIModulePtr);
|
||||
|
||||
m_SetNameplateHook = new Hook<SetNameplateDelegate_Private>(m_PluginAddressResolver.SetNameplatePtr, new SetNameplateDelegate_Private(SetNameplateDetour));
|
||||
m_SetNameplateHook.Enable();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
m_SetNameplateHook.Disable();
|
||||
}
|
||||
|
||||
private IntPtr SetNameplateDetour(IntPtr nameplateObjectPtrOriginal, bool isTitleAboveNameOriginal, bool isTitleVisibleOriginal, IntPtr titlePtrOriginal, IntPtr namePtrOriginal, IntPtr freeCompanyPtrOriginal, int iconIdOriginal)
|
||||
{
|
||||
if (m_SetNameplate != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
GameObject? gameObject = GetNameplateObject<GameObject>(nameplateObjectPtrOriginal);
|
||||
if (gameObject != null)
|
||||
{
|
||||
SeString title = ReadSeString(titlePtrOriginal);
|
||||
SeString name = ReadSeString(namePtrOriginal);
|
||||
SeString freeCompany = ReadSeString(freeCompanyPtrOriginal);
|
||||
bool isTitleVisible = isTitleVisibleOriginal;
|
||||
bool isTitleAboveName = isTitleAboveNameOriginal;
|
||||
int iconId = iconIdOriginal;
|
||||
bool isTitleChanged;
|
||||
bool isNameChanged;
|
||||
bool isFreeCompanyChanged;
|
||||
m_SetNameplate(gameObject, name, title, freeCompany, ref isTitleVisible, ref isTitleAboveName, ref iconId, out isNameChanged, out isTitleChanged, out isFreeCompanyChanged);
|
||||
|
||||
IntPtr namePtr = namePtrOriginal;
|
||||
if (isNameChanged)
|
||||
{
|
||||
namePtr = Allocate(name);
|
||||
}
|
||||
|
||||
IntPtr titlePtr = titlePtrOriginal;
|
||||
if (isTitleChanged)
|
||||
{
|
||||
titlePtr = Allocate(title);
|
||||
}
|
||||
|
||||
IntPtr freeCompanyPtr = freeCompanyPtrOriginal;
|
||||
if (isFreeCompanyChanged)
|
||||
{
|
||||
freeCompanyPtr = Allocate(freeCompany);
|
||||
}
|
||||
|
||||
var result = m_SetNameplateHook.Original(nameplateObjectPtrOriginal, isTitleAboveName, isTitleVisible, titlePtr, namePtr, freeCompanyPtr, iconId);
|
||||
|
||||
if (isNameChanged)
|
||||
{
|
||||
Release(ref namePtr);
|
||||
}
|
||||
|
||||
if (isTitleChanged)
|
||||
{
|
||||
Release(ref titlePtr);
|
||||
}
|
||||
|
||||
if (isFreeCompanyChanged)
|
||||
{
|
||||
Release(ref freeCompanyPtr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginLog.Error(ex, $"SetNameplateDetour encountered a critical error");
|
||||
}
|
||||
}
|
||||
|
||||
return m_SetNameplateHook.Original(nameplateObjectPtrOriginal, isTitleAboveNameOriginal, isTitleVisibleOriginal, titlePtrOriginal, namePtrOriginal, freeCompanyPtrOriginal, iconIdOriginal);
|
||||
}
|
||||
|
||||
private static SeString ReadSeString(IntPtr stringPtr)
|
||||
{
|
||||
return SeString.Parse(ReadStringBytes(stringPtr));
|
||||
}
|
||||
|
||||
private static byte[] ReadStringBytes(IntPtr stringPtr)
|
||||
{
|
||||
if (stringPtr == IntPtr.Zero)
|
||||
{
|
||||
return null!;
|
||||
}
|
||||
|
||||
var size = 0;
|
||||
while (Marshal.ReadByte(stringPtr, size) != 0)
|
||||
{
|
||||
size++;
|
||||
}
|
||||
|
||||
var bytes = new byte[size];
|
||||
Marshal.Copy(stringPtr, bytes, 0, size);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private static IntPtr Allocate(SeString seString)
|
||||
{
|
||||
var bytes = seString.Encode();
|
||||
IntPtr pointer = Marshal.AllocHGlobal(bytes.Length + 1);
|
||||
Marshal.Copy(bytes, 0, pointer, bytes.Length);
|
||||
Marshal.WriteByte(pointer, bytes.Length, 0);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
private static void Release(ref IntPtr ptr)
|
||||
{
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
ptr = IntPtr.Zero;
|
||||
}
|
||||
|
||||
private T? GetNameplateObject<T>(IntPtr nameplateObjectPtr)
|
||||
where T : GameObject
|
||||
{
|
||||
if (!m_NameplateInfoArrayPtr.HasValue)
|
||||
{
|
||||
// Get the nameplate object array
|
||||
var namePlateAddonPtr = m_GameGui.GetAddonByName("NamePlate", 1);
|
||||
var namePlateObjectArrayPtrPtr = namePlateAddonPtr + Marshal.OffsetOf(typeof(AddonNamePlate), nameof(AddonNamePlate.NamePlateObjectArray)).ToInt32();
|
||||
var nameplateObjectArrayPtr = Marshal.ReadIntPtr(namePlateObjectArrayPtrPtr);
|
||||
if (nameplateObjectArrayPtr == IntPtr.Zero)
|
||||
{
|
||||
return null!;
|
||||
}
|
||||
|
||||
m_NameplateObjectArrayPtr = nameplateObjectArrayPtr;
|
||||
|
||||
// Get the nameplate info
|
||||
IntPtr raptureAtkModulePtr;
|
||||
var frameworkPtr = m_Framework.Address.BaseAddress;
|
||||
var uiModulePtr = m_GetUIModule(frameworkPtr);
|
||||
unsafe
|
||||
{
|
||||
var uiModule = *(UIModule*)uiModulePtr;
|
||||
var UIModule_GetRaptureAtkModuleAddress = new IntPtr(uiModule.vfunc[7]);
|
||||
var GetRaptureAtkModule = Marshal.GetDelegateForFunctionPointer<UIModule_GetRaptureAtkModuleDelegate_Private>(UIModule_GetRaptureAtkModuleAddress);
|
||||
raptureAtkModulePtr = GetRaptureAtkModule(uiModulePtr);
|
||||
}
|
||||
|
||||
if (raptureAtkModulePtr == IntPtr.Zero)
|
||||
{
|
||||
return null!;
|
||||
}
|
||||
|
||||
m_NameplateInfoArrayPtr = raptureAtkModulePtr + Marshal.OffsetOf(typeof(RaptureAtkModule), nameof(RaptureAtkModule.NamePlateInfoArray)).ToInt32();
|
||||
}
|
||||
|
||||
// Determine the index of this nameplate
|
||||
var namePlateObjectSize = Marshal.SizeOf(typeof(AddonNamePlate.NamePlateObject));
|
||||
var namePlateObjectPtr0 = m_NameplateObjectArrayPtr!.Value + namePlateObjectSize * 0;
|
||||
var namePlateIndex = (nameplateObjectPtr.ToInt64() - namePlateObjectPtr0.ToInt64()) / namePlateObjectSize;
|
||||
if (namePlateIndex < 0 || namePlateIndex >= 50)
|
||||
{
|
||||
return null!;
|
||||
}
|
||||
|
||||
var namePlateInfoPtr = new IntPtr(m_NameplateInfoArrayPtr.Value.ToInt64() + Marshal.SizeOf(typeof(RaptureAtkModule.NamePlateInfo)) * namePlateIndex);
|
||||
RaptureAtkModule.NamePlateInfo namePlateInfo = Marshal.PtrToStructure<RaptureAtkModule.NamePlateInfo>(namePlateInfoPtr);
|
||||
|
||||
// Get the player character for this nameplate info
|
||||
var objectId = namePlateInfo.ObjectID.ObjectID;
|
||||
|
||||
T? gameObject = m_ObjectTable.FirstOrDefault(obj => obj.ObjectId == objectId) as T;
|
||||
if (gameObject == null)
|
||||
{
|
||||
return null!;
|
||||
}
|
||||
|
||||
return gameObject!;
|
||||
}
|
||||
}
|
||||
}
|
||||
96
PlayerTags/RandomNameGenerator.cs
Normal file
96
PlayerTags/RandomNameGenerator.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using Dalamud.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace PlayerTags
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates names based on an existing list of words.
|
||||
/// </summary>
|
||||
public class RandomNameGenerator
|
||||
{
|
||||
private const string c_AdjectivesPath = "Resources/Words/Adjectives.txt";
|
||||
private string[]? m_Adjectives;
|
||||
|
||||
private const string c_NounsPath = "Resources/Words/Nouns.txt";
|
||||
private string[]? m_Nouns;
|
||||
|
||||
private Dictionary<int, string> m_GeneratedNames = new Dictionary<int, string>();
|
||||
|
||||
private string? PluginDirectory
|
||||
{
|
||||
get { return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); }
|
||||
}
|
||||
|
||||
public RandomNameGenerator()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_Adjectives = File.ReadAllLines($"{PluginDirectory}/{c_AdjectivesPath}");
|
||||
m_Nouns = File.ReadAllLines($"{PluginDirectory}/{c_NounsPath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginLog.Error(ex, $"RandomNameGenerator failed to create");
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 string? GetGeneratedName(string str)
|
||||
{
|
||||
if (m_Adjectives == null || m_Nouns == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int hash = GetDeterministicHashCode(str);
|
||||
|
||||
if (!m_GeneratedNames.ContainsKey(hash))
|
||||
{
|
||||
// Use the seed as the hash so that player always gets the same name
|
||||
Random random = new Random(hash);
|
||||
var adjective = m_Adjectives[random.Next(0, m_Adjectives.Length)];
|
||||
var noun = m_Nouns[random.Next(0, m_Nouns.Length)];
|
||||
var generatedName = $"{adjective} {noun}";
|
||||
|
||||
m_GeneratedNames[hash] = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(generatedName);
|
||||
}
|
||||
|
||||
return m_GeneratedNames[hash];
|
||||
}
|
||||
|
||||
/// <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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
PlayerTags/Resources/Promo/Chat_1.png
Normal file
BIN
PlayerTags/Resources/Promo/Chat_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 149 KiB |
BIN
PlayerTags/Resources/Promo/Nameplates_1.png
Normal file
BIN
PlayerTags/Resources/Promo/Nameplates_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 847 KiB |
828
PlayerTags/Resources/Strings.Designer.cs
generated
Normal file
828
PlayerTags/Resources/Strings.Designer.cs
generated
Normal file
@@ -0,0 +1,828 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace PlayerTags.Resources {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Strings {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Strings() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PlayerTags.Resources.Strings", typeof(Strings).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Color.
|
||||
/// </summary>
|
||||
public static string Loc_CustomColorConfig_IsEnabled {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_CustomColorConfig_IsEnabled", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Enable a custom color..
|
||||
/// </summary>
|
||||
public static string Loc_CustomColorConfig_IsEnabled_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_CustomColorConfig_IsEnabled_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Apply to game object names.
|
||||
/// </summary>
|
||||
public static string Loc_CustomTagConfig_FormattedGameObjectNames {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_CustomTagConfig_FormattedGameObjectNames", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to A list of game object names to apply the tag to, separated by commas. E.g. "Cloud Strife, Tifa Lockhart".
|
||||
/// </summary>
|
||||
public static string Loc_CustomTagConfig_FormattedGameObjectNames_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_CustomTagConfig_FormattedGameObjectNames_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Name.
|
||||
/// </summary>
|
||||
public static string Loc_CustomTagConfig_Name {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_CustomTagConfig_Name", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The name of the tag to display..
|
||||
/// </summary>
|
||||
public static string Loc_CustomTagConfig_Name_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_CustomTagConfig_Name_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Free company visibility.
|
||||
/// </summary>
|
||||
public static string Loc_FreeCompanyNameplateVisibility {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_FreeCompanyNameplateVisibility", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Default.
|
||||
/// </summary>
|
||||
public static string Loc_FreeCompanyNameplateVisibility_Default {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_FreeCompanyNameplateVisibility_Default", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The free company on nameplates will only be visible when the character is in a free company..
|
||||
/// </summary>
|
||||
public static string Loc_FreeCompanyNameplateVisibility_Default_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_FreeCompanyNameplateVisibility_Default_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The visibility of the free company on nameplates..
|
||||
/// </summary>
|
||||
public static string Loc_FreeCompanyNameplateVisibility_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_FreeCompanyNameplateVisibility_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Never visible.
|
||||
/// </summary>
|
||||
public static string Loc_FreeCompanyNameplateVisibility_Never {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_FreeCompanyNameplateVisibility_Never", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The free company on nameplates will never be visible..
|
||||
/// </summary>
|
||||
public static string Loc_FreeCompanyNameplateVisibility_Never_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_FreeCompanyNameplateVisibility_Never_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Randomly generate player names.
|
||||
/// </summary>
|
||||
public static string Loc_IsPlayerNameRandomlyGenerated {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_IsPlayerNameRandomlyGenerated", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Use tags to replace every player's name with a randomly generated one. Helpful for preserving anonymity when taking screenshots..
|
||||
/// </summary>
|
||||
public static string Loc_IsPlayerNameRandomlyGenerated_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_IsPlayerNameRandomlyGenerated_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Data element.
|
||||
/// </summary>
|
||||
public static string Loc_NameplateElement {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_NameplateElement", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to A data element on nameplates..
|
||||
/// </summary>
|
||||
public static string Loc_NameplateElement_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_NameplateElement_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Free company.
|
||||
/// </summary>
|
||||
public static string Loc_NameplateElement_FreeCompany {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_NameplateElement_FreeCompany", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The free company on nameplates..
|
||||
/// </summary>
|
||||
public static string Loc_NameplateElement_FreeCompany_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_NameplateElement_FreeCompany_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Name.
|
||||
/// </summary>
|
||||
public static string Loc_NameplateElement_Name {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_NameplateElement_Name", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The name on nameplates..
|
||||
/// </summary>
|
||||
public static string Loc_NameplateElement_Name_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_NameplateElement_Name_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Title.
|
||||
/// </summary>
|
||||
public static string Loc_NameplateElement_Title {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_NameplateElement_Title", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The title on nameplates..
|
||||
/// </summary>
|
||||
public static string Loc_NameplateElement_Title_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_NameplateElement_Title_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Role.
|
||||
/// </summary>
|
||||
public static string Loc_Role {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Role", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to A character role..
|
||||
/// </summary>
|
||||
public static string Loc_Role_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Role_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to DPS.
|
||||
/// </summary>
|
||||
public static string Loc_Role_DPS {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Role_DPS", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The DPS role..
|
||||
/// </summary>
|
||||
public static string Loc_Role_DPS_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Role_DPS_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Healer.
|
||||
/// </summary>
|
||||
public static string Loc_Role_Healer {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Role_Healer", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The healer role..
|
||||
/// </summary>
|
||||
public static string Loc_Role_Healer_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Role_Healer_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Land/Hand.
|
||||
/// </summary>
|
||||
public static string Loc_Role_LandHand {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Role_LandHand", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The land/hand role..
|
||||
/// </summary>
|
||||
public static string Loc_Role_LandHand_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Role_LandHand_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Tank.
|
||||
/// </summary>
|
||||
public static string Loc_Role_Tank {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Role_Tank", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The tank role..
|
||||
/// </summary>
|
||||
public static string Loc_Role_Tank_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Role_Tank_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Enabled.
|
||||
/// </summary>
|
||||
public static string Loc_RoleOverrideConfig_IsEnabled {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_RoleOverrideConfig_IsEnabled", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Enable the tag for this role..
|
||||
/// </summary>
|
||||
public static string Loc_RoleOverrideConfig_IsEnabled_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_RoleOverrideConfig_IsEnabled_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Name.
|
||||
/// </summary>
|
||||
public static string Loc_RoleOverrideConfig_Name {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_RoleOverrideConfig_Name", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The name to use for this role when the format is set to use role names..
|
||||
/// </summary>
|
||||
public static string Loc_RoleOverrideConfig_Name_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_RoleOverrideConfig_Name_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Tag format.
|
||||
/// </summary>
|
||||
public static string Loc_RoleTagFormat {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_RoleTagFormat", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Abbreviated job name.
|
||||
/// </summary>
|
||||
public static string Loc_RoleTagFormat_AbbreviatedJobName {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_RoleTagFormat_AbbreviatedJobName", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The tag will appear as an abbreviated job name, e.g. SAM, WHM, GNB..
|
||||
/// </summary>
|
||||
public static string Loc_RoleTagFormat_AbbreviatedJobName_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_RoleTagFormat_AbbreviatedJobName_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The format that the role tag should be displayed as..
|
||||
/// </summary>
|
||||
public static string Loc_RoleTagFormat_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_RoleTagFormat_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Job name.
|
||||
/// </summary>
|
||||
public static string Loc_RoleTagFormat_JobName {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_RoleTagFormat_JobName", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The tag will appear as a job name in English, e.g. Samurai, White Mage, Gunbreaker..
|
||||
/// </summary>
|
||||
public static string Loc_RoleTagFormat_JobName_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_RoleTagFormat_JobName_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Role name.
|
||||
/// </summary>
|
||||
public static string Loc_RoleTagFormat_RoleName {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_RoleTagFormat_RoleName", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The tag will appear as the configured role name, e.g. DPS, Healer, Tank..
|
||||
/// </summary>
|
||||
public static string Loc_RoleTagFormat_RoleName_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_RoleTagFormat_RoleName_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Add custom tag.
|
||||
/// </summary>
|
||||
public static string Loc_Static_AddCustomTag {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_AddCustomTag", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Chat tag.
|
||||
/// </summary>
|
||||
public static string Loc_Static_ChatTag {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_ChatTag", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Custom tags.
|
||||
/// </summary>
|
||||
public static string Loc_Static_CustomTags {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_CustomTags", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Development.
|
||||
/// </summary>
|
||||
public static string Loc_Static_Development {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_Development", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to General.
|
||||
/// </summary>
|
||||
public static string Loc_Static_General {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_General", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Jobs.
|
||||
/// </summary>
|
||||
public static string Loc_Static_Jobs {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_Jobs", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Nameplates.
|
||||
/// </summary>
|
||||
public static string Loc_Static_Nameplates {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_Nameplates", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Nameplate tag.
|
||||
/// </summary>
|
||||
public static string Loc_Static_NameplateTag {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_NameplateTag", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to No custom tags added..
|
||||
/// </summary>
|
||||
public static string Loc_Static_NoCustomTagsAdded {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_NoCustomTagsAdded", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Player Tags.
|
||||
/// </summary>
|
||||
public static string Loc_Static_PluginName {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_PluginName", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Remove custom tag.
|
||||
/// </summary>
|
||||
public static string Loc_Static_RemoveCustomTag {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_RemoveCustomTag", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Role and job tags.
|
||||
/// </summary>
|
||||
public static string Loc_Static_RoleAndJobTags {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_RoleAndJobTags", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Roles.
|
||||
/// </summary>
|
||||
public static string Loc_Static_Roles {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_Roles", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to String position.
|
||||
/// </summary>
|
||||
public static string Loc_StringPosition {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_StringPosition", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to After.
|
||||
/// </summary>
|
||||
public static string Loc_StringPosition_After {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_StringPosition_After", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The tag will be positioned after the data element..
|
||||
/// </summary>
|
||||
public static string Loc_StringPosition_After_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_StringPosition_After_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Before.
|
||||
/// </summary>
|
||||
public static string Loc_StringPosition_Before {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_StringPosition_Before", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The tag will be positioned before the data element..
|
||||
/// </summary>
|
||||
public static string Loc_StringPosition_Before_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_StringPosition_Before_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The position in a string where tags will be displayed..
|
||||
/// </summary>
|
||||
public static string Loc_StringPosition_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_StringPosition_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to None.
|
||||
/// </summary>
|
||||
public static string Loc_StringPosition_None {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_StringPosition_None", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The tag will not be positioned in the string..
|
||||
/// </summary>
|
||||
public static string Loc_StringPosition_None_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_StringPosition_None_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Replace.
|
||||
/// </summary>
|
||||
public static string Loc_StringPosition_Replace {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_StringPosition_Replace", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The tag will replace its data element..
|
||||
/// </summary>
|
||||
public static string Loc_StringPosition_Replace_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_StringPosition_Replace_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Title position.
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplatePosition {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplatePosition", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Always above the name.
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplatePosition_AlwaysAboveName {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplatePosition_AlwaysAboveName", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The title on nameplates will always be positioned above the name..
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplatePosition_AlwaysAboveName_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplatePosition_AlwaysAboveName_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Always below the name.
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplatePosition_AlwaysBelowName {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplatePosition_AlwaysBelowName", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The title on nameplates will always be positioned below the name..
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplatePosition_AlwaysBelowName_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplatePosition_AlwaysBelowName_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Default.
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplatePosition_Default {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplatePosition_Default", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The title on nameplates will be positioned depending on the title..
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplatePosition_Default_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplatePosition_Default_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The position of the title on nameplates..
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplatePosition_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplatePosition_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Title visibility.
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplateVisibility {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplateVisibility", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Always.
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplateVisibility_Always {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplateVisibility_Always", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The title on nameplates will always be visible, even when the character does not have a title..
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplateVisibility_Always_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplateVisibility_Always_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Default.
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplateVisibility_Default {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplateVisibility_Default", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The title on nameplates will only be visible when the character has a title..
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplateVisibility_Default_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplateVisibility_Default_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The visibility of the title on nameplates..
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplateVisibility_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplateVisibility_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Never.
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplateVisibility_Never {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplateVisibility_Never", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The title on nameplates will never visible..
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplateVisibility_Never_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplateVisibility_Never_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to When it has tags.
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplateVisibility_WhenHasTags {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplateVisibility_WhenHasTags", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The title on nameplates will only be visible when it has tags..
|
||||
/// </summary>
|
||||
public static string Loc_TitleNameplateVisibility_WhenHasTags_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_TitleNameplateVisibility_WhenHasTags_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
375
PlayerTags/Resources/Strings.resx
Normal file
375
PlayerTags/Resources/Strings.resx
Normal file
@@ -0,0 +1,375 @@
|
||||
<?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 id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<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>Player Tags</value>
|
||||
</data>
|
||||
<data name="Loc_Static_General" xml:space="preserve">
|
||||
<value>General</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Development" xml:space="preserve">
|
||||
<value>Development</value>
|
||||
</data>
|
||||
<data name="Loc_Static_CustomTags" xml:space="preserve">
|
||||
<value>Custom tags</value>
|
||||
</data>
|
||||
<data name="Loc_Static_AddCustomTag" xml:space="preserve">
|
||||
<value>Add custom tag</value>
|
||||
</data>
|
||||
<data name="Loc_Static_RemoveCustomTag" xml:space="preserve">
|
||||
<value>Remove custom tag</value>
|
||||
</data>
|
||||
<data name="Loc_Static_NoCustomTagsAdded" xml:space="preserve">
|
||||
<value>No custom tags added.</value>
|
||||
</data>
|
||||
<data name="Loc_Static_RoleAndJobTags" xml:space="preserve">
|
||||
<value>Role and job tags</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Roles" xml:space="preserve">
|
||||
<value>Roles</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Jobs" xml:space="preserve">
|
||||
<value>Jobs</value>
|
||||
</data>
|
||||
<data name="Loc_Static_ChatTag" xml:space="preserve">
|
||||
<value>Chat tag</value>
|
||||
</data>
|
||||
<data name="Loc_Static_NameplateTag" xml:space="preserve">
|
||||
<value>Nameplate tag</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Nameplates" xml:space="preserve">
|
||||
<value>Nameplates</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayerNameRandomlyGenerated" xml:space="preserve">
|
||||
<value>Randomly generate player names</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayerNameRandomlyGenerated_Description" xml:space="preserve">
|
||||
<value>Use tags to replace every player's name with a randomly generated one. Helpful for preserving anonymity when taking screenshots.</value>
|
||||
</data>
|
||||
<data name="Loc_RoleOverrideConfig_IsEnabled" xml:space="preserve">
|
||||
<value>Enabled</value>
|
||||
</data>
|
||||
<data name="Loc_RoleOverrideConfig_IsEnabled_Description" xml:space="preserve">
|
||||
<value>Enable the tag for this role.</value>
|
||||
</data>
|
||||
<data name="Loc_RoleOverrideConfig_Name" xml:space="preserve">
|
||||
<value>Name</value>
|
||||
</data>
|
||||
<data name="Loc_RoleOverrideConfig_Name_Description" xml:space="preserve">
|
||||
<value>The name to use for this role when the format is set to use role names.</value>
|
||||
</data>
|
||||
<data name="Loc_CustomColorConfig_IsEnabled" xml:space="preserve">
|
||||
<value>Color</value>
|
||||
</data>
|
||||
<data name="Loc_CustomColorConfig_IsEnabled_Description" xml:space="preserve">
|
||||
<value>Enable a custom color.</value>
|
||||
</data>
|
||||
<data name="Loc_CustomTagConfig_Name" xml:space="preserve">
|
||||
<value>Name</value>
|
||||
</data>
|
||||
<data name="Loc_CustomTagConfig_Name_Description" xml:space="preserve">
|
||||
<value>The name of the tag to display.</value>
|
||||
</data>
|
||||
<data name="Loc_CustomTagConfig_FormattedGameObjectNames" xml:space="preserve">
|
||||
<value>Apply to game object names</value>
|
||||
</data>
|
||||
<data name="Loc_CustomTagConfig_FormattedGameObjectNames_Description" xml:space="preserve">
|
||||
<value>A list of game object names to apply the tag to, separated by commas. E.g. "Cloud Strife, Tifa Lockhart"</value>
|
||||
</data>
|
||||
<data name="Loc_FreeCompanyNameplateVisibility" xml:space="preserve">
|
||||
<value>Free company visibility</value>
|
||||
</data>
|
||||
<data name="Loc_FreeCompanyNameplateVisibility_Description" xml:space="preserve">
|
||||
<value>The visibility of the free company on nameplates.</value>
|
||||
</data>
|
||||
<data name="Loc_FreeCompanyNameplateVisibility_Default" xml:space="preserve">
|
||||
<value>Default</value>
|
||||
</data>
|
||||
<data name="Loc_FreeCompanyNameplateVisibility_Default_Description" xml:space="preserve">
|
||||
<value>The free company on nameplates will only be visible when the character is in a free company.</value>
|
||||
</data>
|
||||
<data name="Loc_FreeCompanyNameplateVisibility_Never" xml:space="preserve">
|
||||
<value>Never visible</value>
|
||||
</data>
|
||||
<data name="Loc_FreeCompanyNameplateVisibility_Never_Description" xml:space="preserve">
|
||||
<value>The free company on nameplates will never be visible.</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateElement" xml:space="preserve">
|
||||
<value>Data element</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateElement_Description" xml:space="preserve">
|
||||
<value>A data element on nameplates.</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateElement_FreeCompany" xml:space="preserve">
|
||||
<value>Free company</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateElement_FreeCompany_Description" xml:space="preserve">
|
||||
<value>The free company on nameplates.</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateElement_Name" xml:space="preserve">
|
||||
<value>Name</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateElement_Name_Description" xml:space="preserve">
|
||||
<value>The name on nameplates.</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateElement_Title" xml:space="preserve">
|
||||
<value>Title</value>
|
||||
</data>
|
||||
<data name="Loc_NameplateElement_Title_Description" xml:space="preserve">
|
||||
<value>The title on nameplates.</value>
|
||||
</data>
|
||||
<data name="Loc_RoleTagFormat" xml:space="preserve">
|
||||
<value>Tag format</value>
|
||||
</data>
|
||||
<data name="Loc_RoleTagFormat_Description" xml:space="preserve">
|
||||
<value>The format that the role tag should be displayed as.</value>
|
||||
</data>
|
||||
<data name="Loc_RoleTagFormat_AbbreviatedJobName" xml:space="preserve">
|
||||
<value>Abbreviated job name</value>
|
||||
</data>
|
||||
<data name="Loc_RoleTagFormat_JobName" xml:space="preserve">
|
||||
<value>Job name</value>
|
||||
</data>
|
||||
<data name="Loc_RoleTagFormat_AbbreviatedJobName_Description" xml:space="preserve">
|
||||
<value>The tag will appear as an abbreviated job name, e.g. SAM, WHM, GNB.</value>
|
||||
</data>
|
||||
<data name="Loc_RoleTagFormat_JobName_Description" xml:space="preserve">
|
||||
<value>The tag will appear as a job name in English, e.g. Samurai, White Mage, Gunbreaker.</value>
|
||||
</data>
|
||||
<data name="Loc_RoleTagFormat_RoleName" xml:space="preserve">
|
||||
<value>Role name</value>
|
||||
</data>
|
||||
<data name="Loc_RoleTagFormat_RoleName_Description" xml:space="preserve">
|
||||
<value>The tag will appear as the configured role name, e.g. DPS, Healer, Tank.</value>
|
||||
</data>
|
||||
<data name="Loc_Role" xml:space="preserve">
|
||||
<value>Role</value>
|
||||
</data>
|
||||
<data name="Loc_Role_Description" xml:space="preserve">
|
||||
<value>A character role.</value>
|
||||
</data>
|
||||
<data name="Loc_Role_DPS" xml:space="preserve">
|
||||
<value>DPS</value>
|
||||
</data>
|
||||
<data name="Loc_Role_DPS_Description" xml:space="preserve">
|
||||
<value>The DPS role.</value>
|
||||
</data>
|
||||
<data name="Loc_Role_Healer" xml:space="preserve">
|
||||
<value>Healer</value>
|
||||
</data>
|
||||
<data name="Loc_Role_Healer_Description" xml:space="preserve">
|
||||
<value>The healer role.</value>
|
||||
</data>
|
||||
<data name="Loc_Role_LandHand" xml:space="preserve">
|
||||
<value>Land/Hand</value>
|
||||
</data>
|
||||
<data name="Loc_Role_LandHand_Description" xml:space="preserve">
|
||||
<value>The land/hand role.</value>
|
||||
</data>
|
||||
<data name="Loc_Role_Tank" xml:space="preserve">
|
||||
<value>Tank</value>
|
||||
</data>
|
||||
<data name="Loc_Role_Tank_Description" xml:space="preserve">
|
||||
<value>The tank role.</value>
|
||||
</data>
|
||||
<data name="Loc_StringPosition" xml:space="preserve">
|
||||
<value>String position</value>
|
||||
</data>
|
||||
<data name="Loc_StringPosition_Description" xml:space="preserve">
|
||||
<value>The position in a string where tags will be displayed.</value>
|
||||
</data>
|
||||
<data name="Loc_StringPosition_After" xml:space="preserve">
|
||||
<value>After</value>
|
||||
</data>
|
||||
<data name="Loc_StringPosition_After_Description" xml:space="preserve">
|
||||
<value>The tag will be positioned after the data element.</value>
|
||||
</data>
|
||||
<data name="Loc_StringPosition_Before" xml:space="preserve">
|
||||
<value>Before</value>
|
||||
</data>
|
||||
<data name="Loc_StringPosition_Before_Description" xml:space="preserve">
|
||||
<value>The tag will be positioned before the data element.</value>
|
||||
</data>
|
||||
<data name="Loc_StringPosition_None" xml:space="preserve">
|
||||
<value>None</value>
|
||||
</data>
|
||||
<data name="Loc_StringPosition_None_Description" xml:space="preserve">
|
||||
<value>The tag will not be positioned in the string.</value>
|
||||
</data>
|
||||
<data name="Loc_StringPosition_Replace" xml:space="preserve">
|
||||
<value>Replace</value>
|
||||
</data>
|
||||
<data name="Loc_StringPosition_Replace_Description" xml:space="preserve">
|
||||
<value>The tag will replace its data element.</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplatePosition" xml:space="preserve">
|
||||
<value>Title position</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplatePosition_Description" xml:space="preserve">
|
||||
<value>The position of the title on nameplates.</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplatePosition_AlwaysAboveName" xml:space="preserve">
|
||||
<value>Always above the name</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplatePosition_AlwaysAboveName_Description" xml:space="preserve">
|
||||
<value>The title on nameplates will always be positioned above the name.</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplatePosition_AlwaysBelowName" xml:space="preserve">
|
||||
<value>Always below the name</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplatePosition_AlwaysBelowName_Description" xml:space="preserve">
|
||||
<value>The title on nameplates will always be positioned below the name.</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplatePosition_Default" xml:space="preserve">
|
||||
<value>Default</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplatePosition_Default_Description" xml:space="preserve">
|
||||
<value>The title on nameplates will be positioned depending on the title.</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplateVisibility" xml:space="preserve">
|
||||
<value>Title visibility</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplateVisibility_Description" xml:space="preserve">
|
||||
<value>The visibility of the title on nameplates.</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplateVisibility_Always" xml:space="preserve">
|
||||
<value>Always</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplateVisibility_Always_Description" xml:space="preserve">
|
||||
<value>The title on nameplates will always be visible, even when the character does not have a title.</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplateVisibility_Default" xml:space="preserve">
|
||||
<value>Default</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplateVisibility_Default_Description" xml:space="preserve">
|
||||
<value>The title on nameplates will only be visible when the character has a title.</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplateVisibility_Never" xml:space="preserve">
|
||||
<value>Never</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplateVisibility_Never_Description" xml:space="preserve">
|
||||
<value>The title on nameplates will never visible.</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplateVisibility_WhenHasTags" xml:space="preserve">
|
||||
<value>When it has tags</value>
|
||||
</data>
|
||||
<data name="Loc_TitleNameplateVisibility_WhenHasTags_Description" xml:space="preserve">
|
||||
<value>The title on nameplates will only be visible when it has tags.</value>
|
||||
</data>
|
||||
</root>
|
||||
3060
PlayerTags/Resources/Words/Adjectives.txt
Normal file
3060
PlayerTags/Resources/Words/Adjectives.txt
Normal file
File diff suppressed because it is too large
Load Diff
2642
PlayerTags/Resources/Words/Nouns.txt
Normal file
2642
PlayerTags/Resources/Words/Nouns.txt
Normal file
File diff suppressed because it is too large
Load Diff
7
PlayerTags/SetNameplateDelegate.cs
Normal file
7
PlayerTags/SetNameplateDelegate.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
|
||||
namespace PlayerTags
|
||||
{
|
||||
public delegate void SetNameplateDelegate(GameObject gameObject, SeString name, SeString title, SeString freeCompany, ref bool isTitleVisible, ref bool isTitleAboveName, ref int iconId, out bool isNameChanged, out bool isTitleChanged, out bool isFreeCompanyChanged);
|
||||
}
|
||||
97
PlayerTags/UIColorHelper.cs
Normal file
97
PlayerTags/UIColorHelper.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using Dalamud.Data;
|
||||
using ImGuiNET;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace PlayerTags
|
||||
{
|
||||
public static class UIColorHelper
|
||||
{
|
||||
private class UIColorComparer : IEqualityComparer<UIColor>
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private static UIColor[] s_UIColors = new UIColor[] { };
|
||||
|
||||
public static IEnumerable<UIColor> UIColors { get { return s_UIColors; } }
|
||||
|
||||
public static void Initialize(DataManager dataManager)
|
||||
{
|
||||
var uiColors = 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;
|
||||
});
|
||||
|
||||
s_UIColors = filteredUIColors.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user