Update to API 9 without the Kami touch
This commit is contained in:
parent
32f251720c
commit
2cf6ded1cd
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
|||||||
obj/
|
obj/
|
||||||
bin/
|
bin/
|
||||||
*.user
|
*.user
|
||||||
|
/.idea
|
||||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
|||||||
[submodule "KamiLib"]
|
|
||||||
path = KamiLib
|
|
||||||
url = https://github.com/MidoriKami/KamiLib
|
|
@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<AssemblyName>CurrencyAlertClassic</AssemblyName>
|
||||||
<Version>0.5.0.1</Version>
|
<Version>0.5.0.1</Version>
|
||||||
<Description>Currency Alert</Description>
|
<Description>Currency Alert</Description>
|
||||||
<PackageProjectUrl>https://github.com/Lharz/xiv-currency-alert</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/Lharz/xiv-currency-alert</PackageProjectUrl>
|
||||||
@ -26,7 +27,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DalamudPackager" Version="2.1.10" />
|
<PackageReference Include="DalamudPackager" Version="2.1.12" />
|
||||||
<Reference Include="FFXIVClientStructs">
|
<Reference Include="FFXIVClientStructs">
|
||||||
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
|
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
|
||||||
<Private>false</Private>
|
<Private>false</Private>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"Author": "Lharz",
|
"Author": "Lharz",
|
||||||
"Name": "CurrencyAlert",
|
"Name": "CurrencyAlert Classic",
|
||||||
"Punchline": "Display alerts upon reaching configurable currencies thresholds (such as Poetics or PVP marks).",
|
"Punchline": "Display alerts upon reaching configurable currencies thresholds (such as Poetics or PVP marks).",
|
||||||
"Description": "This plugin lets you easily manage your various currencies to prevent from wasting precious resources.",
|
"Description": "This plugin lets you easily manage your various currencies to prevent from wasting precious resources.",
|
||||||
"Tags": [
|
"Tags": [
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Dalamud.Interface.Internal;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using ImGuiScene;
|
using ImGuiScene;
|
||||||
@ -13,7 +14,7 @@ public class CurrencyInfo : IDisposable
|
|||||||
public uint ItemID { get; }
|
public uint ItemID { get; }
|
||||||
public string ItemName { get; } = string.Empty;
|
public string ItemName { get; } = string.Empty;
|
||||||
public uint IconID { get; }
|
public uint IconID { get; }
|
||||||
public TextureWrap? IconTexture { get; }
|
public IDalamudTextureWrap? IconTexture { get; }
|
||||||
|
|
||||||
public CurrencyInfo(CurrencyName currency)
|
public CurrencyInfo(CurrencyName currency)
|
||||||
{
|
{
|
||||||
|
@ -3,14 +3,15 @@ using Dalamud.Game;
|
|||||||
using Dalamud.Game.ClientState;
|
using Dalamud.Game.ClientState;
|
||||||
using Dalamud.IoC;
|
using Dalamud.IoC;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
|
||||||
namespace CurrencyAlert;
|
namespace CurrencyAlert;
|
||||||
|
|
||||||
public class Service
|
public class Service
|
||||||
{
|
{
|
||||||
[PluginService] public static DalamudPluginInterface PluginInterface { get; private set; } = null!;
|
[PluginService] public static DalamudPluginInterface PluginInterface { get; private set; } = null!;
|
||||||
[PluginService] public static Framework Framework { get; private set; } = null!;
|
[PluginService] public static IFramework Framework { get; private set; } = null!;
|
||||||
[PluginService] public static ClientState ClientState { get; private set; } = null!;
|
[PluginService] public static IClientState ClientState { get; private set; } = null!;
|
||||||
|
|
||||||
public static Configuration Configuration { get; set; } = null!;
|
public static Configuration Configuration { get; set; } = null!;
|
||||||
public static CurrencyTracker CurrencyTracker { get; set; } = null!;
|
public static CurrencyTracker CurrencyTracker { get; set; } = null!;
|
||||||
|
@ -43,7 +43,7 @@ public class CurrencyTracker : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnZoneChange(object? sender, ushort e)
|
private void OnZoneChange(ushort e)
|
||||||
{
|
{
|
||||||
if (!Service.Configuration.ChatNotification) return;
|
if (!Service.Configuration.ChatNotification) return;
|
||||||
if (Condition.IsBoundByDuty()) return;
|
if (Condition.IsBoundByDuty()) return;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using CurrencyAlert.DataModels;
|
using CurrencyAlert.DataModels;
|
||||||
using CurrencyAlert.Localization;
|
using CurrencyAlert.Localization;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using KamiLib.Drawing;
|
using KamiLib.Drawing;
|
||||||
using KamiLib.Interfaces;
|
using KamiLib.Interfaces;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using CurrencyAlert.DataModels;
|
using CurrencyAlert.DataModels;
|
||||||
using CurrencyAlert.Localization;
|
using CurrencyAlert.Localization;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using KamiLib.Drawing;
|
using KamiLib.Drawing;
|
||||||
using KamiLib.Interfaces;
|
using KamiLib.Interfaces;
|
||||||
|
@ -4,6 +4,7 @@ using System.Numerics;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using CurrencyAlert.Windows.Components;
|
using CurrencyAlert.Windows.Components;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using KamiLib.Drawing;
|
using KamiLib.Drawing;
|
||||||
using KamiLib.Interfaces;
|
using KamiLib.Interfaces;
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
"net7.0-windows7.0": {
|
"net7.0-windows7.0": {
|
||||||
"DalamudPackager": {
|
"DalamudPackager": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[2.1.10, )",
|
"requested": "[2.1.12, )",
|
||||||
"resolved": "2.1.10",
|
"resolved": "2.1.12",
|
||||||
"contentHash": "S6NrvvOnLgT4GDdgwuKVJjbFo+8ZEj+JsEYk9ojjOR/MMfv1dIFpT8aRJQfI24rtDcw1uF+GnSSMN4WW1yt7fw=="
|
"contentHash": "Sc0PVxvgg4NQjcI8n10/VfUQBAS4O+Fw2pZrAqBdRMbthYGeogzu5+xmIGCGmsEZ/ukMOBuAqiNiB5qA3MRalg=="
|
||||||
},
|
},
|
||||||
"kamilib": {
|
"kamilib": {
|
||||||
"type": "Project"
|
"type": "Project"
|
||||||
|
1
KamiLib
1
KamiLib
@ -1 +0,0 @@
|
|||||||
Subproject commit f50ff8903e0adeb2dfe1d64103f54da13e055f89
|
|
4
KamiLib/.gitignore
vendored
Normal file
4
KamiLib/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/obj/
|
||||||
|
/bin/x64/Debug/KamiLib.deps.json
|
||||||
|
/bin/x64/Debug/KamiLib.dll
|
||||||
|
/bin/x64/Debug/KamiLib.pdb
|
13
KamiLib/.idea/.idea.KamiLib/.idea/.gitignore
vendored
Normal file
13
KamiLib/.idea/.idea.KamiLib/.idea/.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Rider ignored files
|
||||||
|
/contentModel.xml
|
||||||
|
/projectSettingsUpdater.xml
|
||||||
|
/modules.xml
|
||||||
|
/.idea.KamiLib.iml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
4
KamiLib/.idea/.idea.KamiLib/.idea/encodings.xml
Normal file
4
KamiLib/.idea/.idea.KamiLib/.idea/encodings.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||||
|
</project>
|
8
KamiLib/.idea/.idea.KamiLib/.idea/indexLayout.xml
Normal file
8
KamiLib/.idea/.idea.KamiLib/.idea/indexLayout.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
6
KamiLib/.idea/.idea.KamiLib/.idea/vcs.xml
Normal file
6
KamiLib/.idea/.idea.KamiLib/.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
55
KamiLib/Atk/AtkValueHelper.cs
Normal file
55
KamiLib/Atk/AtkValueHelper.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Dalamud.Logging;
|
||||||
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
|
||||||
|
|
||||||
|
namespace KamiLib.Atk;
|
||||||
|
|
||||||
|
public static class AtkValueHelper
|
||||||
|
{
|
||||||
|
public static unsafe void PrintAtkValue(AtkValue value, int index)
|
||||||
|
{
|
||||||
|
switch (value.Type)
|
||||||
|
{
|
||||||
|
case ValueType.Int:
|
||||||
|
PluginLog.Debug($"[{index:D3}] [{"int", 7}]: {value.Int}");
|
||||||
|
break;
|
||||||
|
case ValueType.Bool:
|
||||||
|
PluginLog.Debug($"[{index:D3}] [{"bool", 7}]: {(value.Byte != 0 ? "true" : "false")}");
|
||||||
|
break;
|
||||||
|
case ValueType.UInt:
|
||||||
|
PluginLog.Debug($"[{index:D3}] [{"uint", 7}]: {value.UInt}");
|
||||||
|
break;
|
||||||
|
case ValueType.Float:
|
||||||
|
PluginLog.Debug($"[{index:D3}] [{"float", 7}]: {value.Float}");
|
||||||
|
break;
|
||||||
|
case ValueType.String:
|
||||||
|
PluginLog.Debug($"[{index:D3}] [{"string", 7}]: {Marshal.PtrToStringUTF8(new nint(value.String))}");
|
||||||
|
break;
|
||||||
|
case ValueType.String8:
|
||||||
|
PluginLog.Debug($"[{index:D3}] [{"string8", 7}]: {Marshal.PtrToStringUTF8(new nint(value.String))}");
|
||||||
|
break;
|
||||||
|
case ValueType.Vector:
|
||||||
|
PluginLog.Debug($"[{index:D3}] [{"vector", 7}]: No Representation Implemented");
|
||||||
|
break;
|
||||||
|
case ValueType.AllocatedString:
|
||||||
|
PluginLog.Debug($"[{index:D3}] [{"aString", 7}]: {Marshal.PtrToStringUTF8(new nint(value.String))}");
|
||||||
|
break;
|
||||||
|
case ValueType.AllocatedVector:
|
||||||
|
PluginLog.Debug($"[{index:D3}] [{"aVector", 7}]: No Representation Implemented");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PluginLog.Debug($"[{index:D3}] [{"unknown", 7}]: [{value.Type}]: {BitConverter.ToString(BitConverter.GetBytes((long)value.String)).Replace("-", " ")}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AtkValueExtensions
|
||||||
|
{
|
||||||
|
public static unsafe string GetString(this AtkValue value)
|
||||||
|
{
|
||||||
|
return Marshal.PtrToStringUTF8(new nint(value.String)) ?? "Unable to Allocate String";
|
||||||
|
}
|
||||||
|
}
|
106
KamiLib/Atk/NodeHelper.cs
Normal file
106
KamiLib/Atk/NodeHelper.cs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
using KamiLib.ChatCommands;
|
||||||
|
|
||||||
|
namespace KamiLib.Atk;
|
||||||
|
|
||||||
|
public unsafe class BaseNode
|
||||||
|
{
|
||||||
|
private readonly AtkUnitBase* node;
|
||||||
|
|
||||||
|
public bool NodeValid => node != null;
|
||||||
|
|
||||||
|
public BaseNode(string addon)
|
||||||
|
{
|
||||||
|
node = (AtkUnitBase*) Service.GameGui.GetAddonByName(addon, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseNode Print()
|
||||||
|
{
|
||||||
|
Chat.Print("AtkUnitBase", $"{new nint(node):X8}");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AtkResNode* GetRootNode() => node == null ? null : node->RootNode;
|
||||||
|
|
||||||
|
public T* GetNode<T>(uint id) where T : unmanaged
|
||||||
|
{
|
||||||
|
if (node == null) return null;
|
||||||
|
|
||||||
|
var targetNode = (T*) node->GetNodeById(id);
|
||||||
|
|
||||||
|
return targetNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ComponentNode GetComponentNode(uint id)
|
||||||
|
{
|
||||||
|
if (node == null) return new ComponentNode(null);
|
||||||
|
|
||||||
|
var targetNode = (AtkComponentNode*) node->GetNodeById(id);
|
||||||
|
|
||||||
|
return new ComponentNode(targetNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ComponentNode GetNestedNode(params uint[] idList)
|
||||||
|
{
|
||||||
|
uint index = 0;
|
||||||
|
|
||||||
|
ComponentNode startingNode;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
startingNode = GetComponentNode(idList[index]);
|
||||||
|
|
||||||
|
} while (index++ < idList.Length);
|
||||||
|
|
||||||
|
return startingNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe class ComponentNode
|
||||||
|
{
|
||||||
|
private readonly AtkComponentNode* node;
|
||||||
|
private readonly AtkComponentBase* componentBase;
|
||||||
|
|
||||||
|
public ComponentNode(AtkComponentNode* node)
|
||||||
|
{
|
||||||
|
this.node = node;
|
||||||
|
|
||||||
|
componentBase = node == null ? null : node->Component;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ComponentNode Print()
|
||||||
|
{
|
||||||
|
Chat.Print("AtkComponentNode", $"{new nint(node):X8}");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ComponentNode GetComponentNode(uint id)
|
||||||
|
{
|
||||||
|
if (componentBase == null) return new ComponentNode(null);
|
||||||
|
|
||||||
|
var targetNode = Node.GetNodeByID<AtkComponentNode>(componentBase->UldManager, id);
|
||||||
|
|
||||||
|
return new ComponentNode(targetNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T* GetNode<T>(uint id) where T : unmanaged => componentBase == null ? null : Node.GetNodeByID<T>(componentBase->UldManager, id);
|
||||||
|
|
||||||
|
public AtkComponentNode* GetPointer() => node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe class Node
|
||||||
|
{
|
||||||
|
public static T* GetNodeByID<T>(AtkUldManager uldManager, uint nodeId) where T : unmanaged
|
||||||
|
{
|
||||||
|
foreach (var index in Enumerable.Range(0, uldManager.NodeListCount))
|
||||||
|
{
|
||||||
|
var currentNode = uldManager.NodeList[index];
|
||||||
|
if (currentNode->NodeID != nodeId) continue;
|
||||||
|
|
||||||
|
return (T*) currentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
208
KamiLib/Blacklist/BlacklistDraw.cs
Normal file
208
KamiLib/Blacklist/BlacklistDraw.cs
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
|
using Dalamud.Logging;
|
||||||
|
using Dalamud.Utility;
|
||||||
|
using ImGuiNET;
|
||||||
|
using KamiLib.Caching;
|
||||||
|
using KamiLib.Configuration;
|
||||||
|
using KamiLib.Drawing;
|
||||||
|
using KamiLib.Extensions;
|
||||||
|
using KamiLib.Localization;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
|
||||||
|
namespace KamiLib.Blacklist;
|
||||||
|
|
||||||
|
public static class BlacklistDraw
|
||||||
|
{
|
||||||
|
private static readonly List<uint> EntriesToRemove = new();
|
||||||
|
private static readonly List<uint> EntriesToAdd = new();
|
||||||
|
private static string _searchString = string.Empty;
|
||||||
|
private static List<SearchResult>? _searchResults = new();
|
||||||
|
|
||||||
|
public static void DrawBlacklist(Setting<List<uint>> blacklistedAreas)
|
||||||
|
{
|
||||||
|
InfoBox.Instance
|
||||||
|
.AddTitle(Strings.Blacklist_CurrentlyBlacklisted, out var innerWidth, 1.0f)
|
||||||
|
.AddDummy(5.0f)
|
||||||
|
.AddAction(() => BlacklistedAreasList(blacklistedAreas))
|
||||||
|
.AddDisabledButton(EntriesToRemove.Count == 0 ? Strings.Blacklist_ClearBlacklist : Strings.Blacklist_RemoveSelectedAreas.Format(EntriesToRemove.Count), () =>
|
||||||
|
{
|
||||||
|
if (EntriesToRemove.Count == 0)
|
||||||
|
{
|
||||||
|
blacklistedAreas.Value.Clear();
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blacklistedAreas.Value.RemoveAll(entry => EntriesToRemove.Contains(entry));
|
||||||
|
EntriesToRemove.Clear();
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
}, !ImGui.GetIO().KeyShift, Strings.DisabledButton_HoldShift, innerWidth)
|
||||||
|
.Draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawAddRemoveHere(Setting<List<uint>> blacklistedZones)
|
||||||
|
{
|
||||||
|
InfoBox.Instance
|
||||||
|
.AddTitle(Strings.Blacklist_AddRemoveZone, 1.0f)
|
||||||
|
.AddAction(() => LuminaCache<TerritoryType>.Instance.GetRow(Service.ClientState.TerritoryType)?.DrawLabel())
|
||||||
|
.BeginTable()
|
||||||
|
.BeginRow()
|
||||||
|
.AddDisabledButton(Strings.Common_Add, () =>
|
||||||
|
{
|
||||||
|
Add(blacklistedZones, Service.ClientState.TerritoryType);
|
||||||
|
}, blacklistedZones.Value.Contains(Service.ClientState.TerritoryType), buttonSize: InfoBox.Instance.InnerWidth / 2.0f - 5.0f * ImGuiHelpers.GlobalScale)
|
||||||
|
.AddDisabledButton(Strings.Common_Remove, () =>
|
||||||
|
{
|
||||||
|
Remove(blacklistedZones, Service.ClientState.TerritoryType);
|
||||||
|
}, !blacklistedZones.Value.Contains(Service.ClientState.TerritoryType), buttonSize: InfoBox.Instance.InnerWidth / 2.0f - 5.0f * ImGuiHelpers.GlobalScale)
|
||||||
|
.EndRow()
|
||||||
|
.EndTable()
|
||||||
|
.Draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawTerritorySearch(Setting<List<uint>> blacklistedZones)
|
||||||
|
{
|
||||||
|
InfoBox.Instance
|
||||||
|
.AddTitle(Strings.Blacklist_ZoneSearch, out var innerWidth, 1.0f)
|
||||||
|
.AddAction(() =>
|
||||||
|
{
|
||||||
|
ImGui.PushItemWidth(InfoBox.Instance.InnerWidth);
|
||||||
|
if (ImGui.InputTextWithHint("###TerritorySearch", Strings.Blacklist_Search, ref _searchString, 60, ImGuiInputTextFlags.AutoSelectAll))
|
||||||
|
{
|
||||||
|
_searchResults = Search(_searchString, 5);
|
||||||
|
PluginLog.Debug("Updating TerritorySearch Results");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.AddAction(() => DisplayResults(_searchResults))
|
||||||
|
.AddDisabledButton(Strings.Blacklist_AddSelectedAreas.Format(EntriesToAdd.Count), () =>
|
||||||
|
{
|
||||||
|
blacklistedZones.Value.AddRange(EntriesToAdd);
|
||||||
|
EntriesToAdd.Clear();
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
|
||||||
|
}, !EntriesToAdd.Any(), Strings.Blacklist_SelectZones, innerWidth)
|
||||||
|
.Draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PrimeSearch()
|
||||||
|
{
|
||||||
|
_searchResults = Search("", 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<SearchResult> Search(string searchTerms, int numResults)
|
||||||
|
{
|
||||||
|
return Service.DataManager.GetExcelSheet<TerritoryType>()!
|
||||||
|
.Where(territory => territory.PlaceName.Row is not 0)
|
||||||
|
.Where(territory => territory.PlaceName.Value is not null)
|
||||||
|
.GroupBy(territory => territory.PlaceName.Value!.Name.ToDalamudString().TextValue)
|
||||||
|
.Select(territory => territory.First())
|
||||||
|
.Where(territory => territory.PlaceName.Value!.Name.ToDalamudString().TextValue.ToLower().Contains(searchTerms.ToLower()))
|
||||||
|
.Select(territory => new SearchResult {
|
||||||
|
TerritoryID = territory.RowId
|
||||||
|
})
|
||||||
|
.OrderBy(searchResult => searchResult.TerritoryName)
|
||||||
|
.Take(numResults)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DisplayResults(List<SearchResult>? results)
|
||||||
|
{
|
||||||
|
if (results is null) return;
|
||||||
|
|
||||||
|
if (ImGui.BeginChild("###SearchResultsChild", new Vector2(InfoBox.Instance.InnerWidth, 21.0f * 5 * ImGuiHelpers.GlobalScale )))
|
||||||
|
{
|
||||||
|
foreach (var result in results)
|
||||||
|
{
|
||||||
|
if (ImGui.Selectable($"###SearchResult{result.TerritoryID}", EntriesToAdd.Contains(result.TerritoryID)))
|
||||||
|
{
|
||||||
|
if (!EntriesToAdd.Contains(result.TerritoryID))
|
||||||
|
{
|
||||||
|
EntriesToAdd.Add(result.TerritoryID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EntriesToAdd.Remove(result.TerritoryID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
LuminaCache<TerritoryType>.Instance.GetRow(result.TerritoryID)?.DrawLabel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui.EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BlacklistedAreasList(Setting<List<uint>> blacklistedAreas)
|
||||||
|
{
|
||||||
|
var itemCount = Math.Min(blacklistedAreas.Value.Count, 10);
|
||||||
|
var listHeight = itemCount * ImGuiHelpers.GlobalScale * 21.0f;
|
||||||
|
var minHeight = 21.0f * ImGuiHelpers.GlobalScale;
|
||||||
|
|
||||||
|
var size = new Vector2(InfoBox.Instance.InnerWidth, MathF.Max(listHeight, minHeight));
|
||||||
|
|
||||||
|
if(ImGui.BeginChild("###BlacklistFrame", size, false))
|
||||||
|
{
|
||||||
|
if (!blacklistedAreas.Value.Any())
|
||||||
|
{
|
||||||
|
ImGui.SetCursorPos(ImGui.GetCursorPos() with { X = ImGui.GetContentRegionAvail().X / 2 - ImGui.CalcTextSize(Strings.Blacklist_Empty).X / 2.0f});
|
||||||
|
ImGui.TextColored(Colors.Orange, Strings.Blacklist_Empty);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawBlacklistedAreas(blacklistedAreas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui.EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DrawBlacklistedAreas(Setting<List<uint>> blacklistedAreas)
|
||||||
|
{
|
||||||
|
var territories = blacklistedAreas.Value
|
||||||
|
.Select(area => LuminaCache<TerritoryType>.Instance.GetRow(area))
|
||||||
|
.OfType<TerritoryType>()
|
||||||
|
.OrderBy(territory => territory.GetPlaceNameString());
|
||||||
|
|
||||||
|
foreach (var territory in territories)
|
||||||
|
{
|
||||||
|
ImGui.PushItemWidth(InfoBox.Instance.InnerWidth);
|
||||||
|
if (ImGui.Selectable($"###{territory}", EntriesToRemove.Contains(territory.RowId)))
|
||||||
|
{
|
||||||
|
if (!EntriesToRemove.Contains(territory.RowId))
|
||||||
|
{
|
||||||
|
EntriesToRemove.Add(territory.RowId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EntriesToRemove.Remove(territory.RowId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
territory.DrawLabel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Add(Setting<List<uint>> zones, uint id)
|
||||||
|
{
|
||||||
|
if (!zones.Value.Contains(id))
|
||||||
|
{
|
||||||
|
zones.Value.Add(id);
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Remove(Setting<List<uint>> zones, uint id)
|
||||||
|
{
|
||||||
|
if (zones.Value.Contains(id))
|
||||||
|
{
|
||||||
|
zones.Value.Remove(id);
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
KamiLib/Blacklist/SearchResult.cs
Normal file
12
KamiLib/Blacklist/SearchResult.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using Dalamud.Utility;
|
||||||
|
using KamiLib.Caching;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
|
||||||
|
namespace KamiLib.Blacklist;
|
||||||
|
|
||||||
|
public class SearchResult
|
||||||
|
{
|
||||||
|
public uint TerritoryID { get; init; }
|
||||||
|
private uint PlaceNameRow => LuminaCache<TerritoryType>.Instance.GetRow(TerritoryID)?.PlaceName.Row ?? 0;
|
||||||
|
public string TerritoryName => LuminaCache<PlaceName>.Instance.GetRow(PlaceNameRow)?.Name.ToDalamudString().TextValue ?? "Unknown PlaceName Row";
|
||||||
|
}
|
69
KamiLib/Caching/IconCache.cs
Normal file
69
KamiLib/Caching/IconCache.cs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Dalamud.Interface.Internal;
|
||||||
|
using Dalamud.Logging;
|
||||||
|
using Dalamud.Utility;
|
||||||
|
using ImGuiScene;
|
||||||
|
|
||||||
|
namespace KamiLib.Caching;
|
||||||
|
|
||||||
|
public class IconCache : IDisposable
|
||||||
|
{
|
||||||
|
private readonly Dictionary<uint, IDalamudTextureWrap?> iconTextures = new();
|
||||||
|
|
||||||
|
private const string IconFilePath = "ui/icon/{0:D3}000/{1:D6}_hr1.tex";
|
||||||
|
|
||||||
|
private static IconCache? _instance;
|
||||||
|
public static IconCache Instance => _instance ??= new IconCache();
|
||||||
|
|
||||||
|
public static void Cleanup()
|
||||||
|
{
|
||||||
|
_instance?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var texture in iconTextures.Values)
|
||||||
|
{
|
||||||
|
texture?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
iconTextures.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadIconTexture(uint iconId)
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var path = IconFilePath.Format(iconId / 1000, iconId);
|
||||||
|
var tex = Service.TextureProvider.GetTextureFromGame(path);
|
||||||
|
|
||||||
|
if (tex is not null && tex.ImGuiHandle != nint.Zero)
|
||||||
|
{
|
||||||
|
iconTextures[iconId] = tex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tex?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
PluginLog.LogError($"Failed loading texture for icon {iconId} - {ex.Message}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDalamudTextureWrap? GetIcon(uint iconId)
|
||||||
|
{
|
||||||
|
if (iconTextures.TryGetValue(iconId, out var value)) return value;
|
||||||
|
|
||||||
|
iconTextures.Add(iconId, null);
|
||||||
|
LoadIconTexture(iconId);
|
||||||
|
|
||||||
|
return iconTextures[iconId];
|
||||||
|
}
|
||||||
|
}
|
61
KamiLib/Caching/LuminaCache.cs
Normal file
61
KamiLib/Caching/LuminaCache.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Dalamud;
|
||||||
|
using Lumina.Excel;
|
||||||
|
|
||||||
|
namespace KamiLib.Caching;
|
||||||
|
|
||||||
|
public class LuminaCache<T> : IEnumerable<T> where T : ExcelRow
|
||||||
|
{
|
||||||
|
private readonly Func<uint, T?> searchAction;
|
||||||
|
|
||||||
|
private static LuminaCache<T>? _instance;
|
||||||
|
public static LuminaCache<T> Instance => _instance ??= new LuminaCache<T>();
|
||||||
|
|
||||||
|
private LuminaCache(Func<uint, T?>? action = null)
|
||||||
|
{
|
||||||
|
searchAction = action ?? (row => Service.DataManager.GetExcelSheet<T>()!.GetRow(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<uint, T> cache = new();
|
||||||
|
private readonly Dictionary<Tuple<uint, uint>, T> subRowCache = new ();
|
||||||
|
|
||||||
|
public ExcelSheet<T> OfLanguage(ClientLanguage language)
|
||||||
|
{
|
||||||
|
return Service.DataManager.GetExcelSheet<T>(language)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T? GetRow(uint id)
|
||||||
|
{
|
||||||
|
if (cache.TryGetValue(id, out var value))
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (searchAction(id) is not { } result) return null;
|
||||||
|
|
||||||
|
return cache[id] = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public T? GetRow(uint row, uint subRow)
|
||||||
|
{
|
||||||
|
var targetRow = new Tuple<uint, uint>(row, subRow);
|
||||||
|
|
||||||
|
if (subRowCache.TryGetValue(targetRow, out var value))
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Service.DataManager.GetExcelSheet<T>()!.GetRow(row, subRow) is not { } result) return null;
|
||||||
|
|
||||||
|
return subRowCache[targetRow] = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<T> GetEnumerator() => Service.DataManager.GetExcelSheet<T>()!.GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
}
|
55
KamiLib/ChatCommands/Chat.cs
Normal file
55
KamiLib/ChatCommands/Chat.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||||
|
using KamiLib.Localization;
|
||||||
|
|
||||||
|
namespace KamiLib.ChatCommands;
|
||||||
|
|
||||||
|
public static class Chat
|
||||||
|
{
|
||||||
|
public static void Print(string tag, string message) => Service.Chat.Print(GetBaseString(tag, message).BuiltString);
|
||||||
|
|
||||||
|
public static void PrintHelp(string command, string? helpText = null)
|
||||||
|
{
|
||||||
|
var message = GetBaseString(Strings.Command_Label, command);
|
||||||
|
|
||||||
|
if (helpText is not null)
|
||||||
|
{
|
||||||
|
message.AddUiForeground("- " + helpText, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
Service.Chat.Print(message.BuiltString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Print(string tag, string message, DalamudLinkPayload? payload)
|
||||||
|
{
|
||||||
|
if (payload is null)
|
||||||
|
{
|
||||||
|
Print(tag, message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Service.Chat.Print(GetBaseString(tag, message, payload).BuiltString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PrintError(string message) => Service.Chat.PrintError(GetBaseString(Strings.Common_Error, message).BuiltString);
|
||||||
|
|
||||||
|
private static SeStringBuilder GetBaseString(string tag, string message, DalamudLinkPayload? payload = null)
|
||||||
|
{
|
||||||
|
if (payload is null)
|
||||||
|
{
|
||||||
|
return new SeStringBuilder()
|
||||||
|
.AddUiForeground($"[{KamiCommon.PluginName}] ", 45)
|
||||||
|
.AddUiForeground($"[{tag}] ", 62)
|
||||||
|
.AddText(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new SeStringBuilder()
|
||||||
|
.AddUiForeground($"[{KamiCommon.PluginName}] ", 45)
|
||||||
|
.AddUiForeground($"[{tag}] ", 62)
|
||||||
|
.Add(payload)
|
||||||
|
.AddUiForeground(message, 35)
|
||||||
|
.Add(RawPayload.LinkTerminator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
KamiLib/ChatCommands/ChatPayloadManager.cs
Normal file
47
KamiLib/ChatCommands/ChatPayloadManager.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||||
|
|
||||||
|
namespace KamiLib.ChatCommands;
|
||||||
|
|
||||||
|
internal record ChatLinkPayload(uint CommandID, uint Type, DalamudLinkPayload Payload);
|
||||||
|
|
||||||
|
public class ChatPayloadManager : IDisposable
|
||||||
|
{
|
||||||
|
private static ChatPayloadManager? _instance;
|
||||||
|
public static ChatPayloadManager Instance => _instance ??= new ChatPayloadManager();
|
||||||
|
|
||||||
|
private List<ChatLinkPayload> ChatLinkPayloads { get; } = new();
|
||||||
|
|
||||||
|
public static void Cleanup()
|
||||||
|
{
|
||||||
|
_instance?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var payload in ChatLinkPayloads)
|
||||||
|
{
|
||||||
|
Service.PluginInterface.RemoveChatLinkHandler( payload.Type + 1000 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DalamudLinkPayload AddChatLink(Enum type, Action<uint, SeString> payloadAction) => AddChatLink(Convert.ToUInt32(type), payloadAction);
|
||||||
|
|
||||||
|
private DalamudLinkPayload AddChatLink(uint type, Action<uint, SeString> payloadAction)
|
||||||
|
{
|
||||||
|
// If the payload is already registered
|
||||||
|
var payload = ChatLinkPayloads.FirstOrDefault(linkPayload => linkPayload.CommandID == type + 1000)?.Payload;
|
||||||
|
if (payload != null) return payload;
|
||||||
|
|
||||||
|
// else
|
||||||
|
Service.PluginInterface.RemoveChatLinkHandler(type + 1000);
|
||||||
|
payload = Service.PluginInterface.AddChatLinkHandler(type + 1000, payloadAction);
|
||||||
|
|
||||||
|
ChatLinkPayloads.Add(new ChatLinkPayload(type + 1000, type, payload));
|
||||||
|
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
}
|
28
KamiLib/ChatCommands/Command.cs
Normal file
28
KamiLib/ChatCommands/Command.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using KamiLib.Interfaces;
|
||||||
|
using KamiLib.Localization;
|
||||||
|
|
||||||
|
namespace KamiLib.ChatCommands;
|
||||||
|
|
||||||
|
public static class Command
|
||||||
|
{
|
||||||
|
public static CommandData GetCommandData(string baseCommand, string arguments) => new(baseCommand, arguments);
|
||||||
|
|
||||||
|
public static void ProcessCommand(CommandData data, IEnumerable<IPluginCommand> commands)
|
||||||
|
{
|
||||||
|
var matchingCommands = commands.Where(command => command.CommandArgument == data.Command).ToList();
|
||||||
|
|
||||||
|
if (matchingCommands.Any())
|
||||||
|
{
|
||||||
|
if (!matchingCommands.Any(command => command.Execute(data)))
|
||||||
|
{
|
||||||
|
Chat.PrintError(string.Format(Strings.Command_DoesntExistExtended, data.BaseCommand, data.Command, data.SubCommand));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Chat.PrintError(string.Format(Strings.Command_DoesntExist, data.BaseCommand, data.Command));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
KamiLib/ChatCommands/CommandData.cs
Normal file
39
KamiLib/ChatCommands/CommandData.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
namespace KamiLib.ChatCommands;
|
||||||
|
|
||||||
|
public class CommandData
|
||||||
|
{
|
||||||
|
public string? BaseCommand;
|
||||||
|
public string? Command;
|
||||||
|
public string? SubCommand;
|
||||||
|
public string?[]? Arguments;
|
||||||
|
|
||||||
|
public CommandData(string rootCommand, string arguments)
|
||||||
|
{
|
||||||
|
BaseCommand = rootCommand;
|
||||||
|
|
||||||
|
if (arguments != string.Empty)
|
||||||
|
{
|
||||||
|
var splits = arguments.Split(' ');
|
||||||
|
|
||||||
|
if (splits.Length >= 1)
|
||||||
|
{
|
||||||
|
Command = splits[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (splits.Length >= 2)
|
||||||
|
{
|
||||||
|
SubCommand = splits[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (splits.Length >= 3)
|
||||||
|
{
|
||||||
|
Arguments = splits[2..];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => $"{BaseCommand ?? "Empty Base Command"}, " +
|
||||||
|
$"{Command ?? "Empty Command"}, " +
|
||||||
|
$"{SubCommand ?? "Empty SubCommand"}, " +
|
||||||
|
$"{(Arguments is null ? "Empty Args" : string.Join(", ", Arguments))}";
|
||||||
|
}
|
66
KamiLib/ChatCommands/CommandManager.cs
Normal file
66
KamiLib/ChatCommands/CommandManager.cs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Dalamud.Game.Command;
|
||||||
|
using Dalamud.Logging;
|
||||||
|
using KamiLib.Interfaces;
|
||||||
|
using KamiLib.Localization;
|
||||||
|
|
||||||
|
namespace KamiLib.ChatCommands;
|
||||||
|
|
||||||
|
public class CommandManager : IDisposable
|
||||||
|
{
|
||||||
|
private static string SettingsCommand => $"/{KamiCommon.PluginName.ToLower()}";
|
||||||
|
private static string HelpCommand => $"/{KamiCommon.PluginName.ToLower()} help";
|
||||||
|
|
||||||
|
public readonly List<IPluginCommand> Commands = new();
|
||||||
|
|
||||||
|
private readonly List<string> additionalCommands = new();
|
||||||
|
|
||||||
|
public CommandManager()
|
||||||
|
{
|
||||||
|
Commands.Add(new HelpCommands());
|
||||||
|
|
||||||
|
Service.Commands.AddHandler(SettingsCommand, new CommandInfo(OnCommand)
|
||||||
|
{
|
||||||
|
HelpMessage = Strings.Command_OpenConfigWindow
|
||||||
|
});
|
||||||
|
|
||||||
|
Service.Commands.AddHandler(HelpCommand, new CommandInfo(OnCommand)
|
||||||
|
{
|
||||||
|
HelpMessage = Strings.Command_DisplayHelpText
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Service.Commands.RemoveHandler(SettingsCommand);
|
||||||
|
Service.Commands.RemoveHandler(HelpCommand);
|
||||||
|
|
||||||
|
foreach (var additionalCommand in additionalCommands)
|
||||||
|
{
|
||||||
|
Service.Commands.RemoveHandler(additionalCommand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddHandler(string additionalCommand, string description)
|
||||||
|
{
|
||||||
|
additionalCommands.Add(additionalCommand);
|
||||||
|
Service.Commands.AddHandler(additionalCommand, new CommandInfo(OnCommand)
|
||||||
|
{
|
||||||
|
HelpMessage = description
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddCommand(IPluginCommand command)
|
||||||
|
{
|
||||||
|
Commands.Add(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCommand(string command, string arguments)
|
||||||
|
{
|
||||||
|
var commandData = Command.GetCommandData(command.ToLower(), arguments.ToLower());
|
||||||
|
|
||||||
|
PluginLog.Debug($"[{KamiCommon.PluginName}] Received Command: {commandData}");
|
||||||
|
Command.ProcessCommand(commandData, Commands);
|
||||||
|
}
|
||||||
|
}
|
92
KamiLib/ChatCommands/HelpCommands.cs
Normal file
92
KamiLib/ChatCommands/HelpCommands.cs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using KamiLib.Interfaces;
|
||||||
|
using KamiLib.Localization;
|
||||||
|
|
||||||
|
namespace KamiLib.ChatCommands;
|
||||||
|
|
||||||
|
public class HelpCommands: IPluginCommand
|
||||||
|
{
|
||||||
|
public string CommandArgument => "help";
|
||||||
|
|
||||||
|
public IEnumerable<ISubCommand> SubCommands { get; } = new List<ISubCommand>
|
||||||
|
{
|
||||||
|
new SubCommand
|
||||||
|
{
|
||||||
|
CommandKeyword = null,
|
||||||
|
CommandAction = () =>
|
||||||
|
{
|
||||||
|
foreach (var command in KamiCommon.CommandManager.Commands)
|
||||||
|
{
|
||||||
|
PrintSubCommands(command);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GetHelpText = () => Strings.Command_ShowThisMessage
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static void PrintSubCommands(IPluginCommand command)
|
||||||
|
{
|
||||||
|
foreach (var subCommand in command.SubCommands.GroupBy(subCommand => subCommand.GetCommand()))
|
||||||
|
{
|
||||||
|
var selectedSubCommand = subCommand.First();
|
||||||
|
|
||||||
|
if (!selectedSubCommand.Hidden)
|
||||||
|
{
|
||||||
|
PrintHelpText(command, selectedSubCommand);
|
||||||
|
|
||||||
|
if (selectedSubCommand.GetAliases() is { } aliases)
|
||||||
|
{
|
||||||
|
foreach (var alias in aliases)
|
||||||
|
{
|
||||||
|
PrintAliasHelpText(command, alias, selectedSubCommand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PrintHelpText(IPluginCommand mainCommand, ISubCommand subCommand)
|
||||||
|
{
|
||||||
|
var commandString = $"/{KamiCommon.PluginName.ToLower()} ";
|
||||||
|
|
||||||
|
if (mainCommand.CommandArgument is not null)
|
||||||
|
{
|
||||||
|
commandString += mainCommand.CommandArgument + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subCommand.GetCommand() is not null)
|
||||||
|
{
|
||||||
|
commandString += subCommand.GetCommand() + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subCommand.HasParameterAction)
|
||||||
|
{
|
||||||
|
commandString += $"[{Strings.Common_Value}] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
Chat.PrintHelp(commandString, subCommand.GetHelpText());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PrintAliasHelpText(IPluginCommand mainCommand, string? alias, ISubCommand subCommand)
|
||||||
|
{
|
||||||
|
var commandString = $"/{KamiCommon.PluginName.ToLower()} ";
|
||||||
|
|
||||||
|
if (mainCommand.CommandArgument is not null)
|
||||||
|
{
|
||||||
|
commandString += mainCommand.CommandArgument + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alias is not null)
|
||||||
|
{
|
||||||
|
commandString += alias + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subCommand.HasParameterAction)
|
||||||
|
{
|
||||||
|
commandString += $"[{Strings.Common_Value}] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
Chat.PrintHelp(commandString, subCommand.GetHelpText());
|
||||||
|
}
|
||||||
|
}
|
62
KamiLib/ChatCommands/OpenWindowCommand.cs
Normal file
62
KamiLib/ChatCommands/OpenWindowCommand.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using Dalamud.Interface.Windowing;
|
||||||
|
using KamiLib.Interfaces;
|
||||||
|
using KamiLib.Localization;
|
||||||
|
|
||||||
|
namespace KamiLib.ChatCommands;
|
||||||
|
|
||||||
|
public class OpenWindowCommand<T> : IPluginCommand where T : Window
|
||||||
|
{
|
||||||
|
public string? CommandArgument { get; }
|
||||||
|
|
||||||
|
public OpenWindowCommand( string? commandArgument = null, bool silent = false, string? windowName = null)
|
||||||
|
{
|
||||||
|
CommandArgument = commandArgument?.ToLower();
|
||||||
|
|
||||||
|
if (commandArgument is not null)
|
||||||
|
{
|
||||||
|
windowName ??= CultureInfo.CurrentCulture.TextInfo.ToTitleCase(commandArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
SubCommands = new List<ISubCommand>
|
||||||
|
{
|
||||||
|
new SubCommand
|
||||||
|
{
|
||||||
|
CommandKeyword = null,
|
||||||
|
CommandAction = () => Chat.PrintError(string.Format(Strings.Command_PvPError, windowName)),
|
||||||
|
CanExecute = () => Service.ClientState.IsPvP,
|
||||||
|
GetHelpText = () => string.Format(Strings.Command_OpenWindow, windowName),
|
||||||
|
Hidden = silent,
|
||||||
|
},
|
||||||
|
new SubCommand
|
||||||
|
{
|
||||||
|
CommandKeyword = null,
|
||||||
|
CommandAction = () =>
|
||||||
|
{
|
||||||
|
if ( KamiCommon.WindowManager.GetWindowOfType<T>() is {} mainWindow )
|
||||||
|
{
|
||||||
|
if (!silent)
|
||||||
|
{
|
||||||
|
Chat.Print(Strings.Command_Label,
|
||||||
|
!mainWindow.IsOpen ?
|
||||||
|
string.Format(Strings.Command_OpeningWindow, windowName) :
|
||||||
|
string.Format(Strings.Command_ClosingWindow, windowName));
|
||||||
|
}
|
||||||
|
|
||||||
|
mainWindow.IsOpen = !mainWindow.IsOpen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Chat.PrintError($"Something went wrong trying to open {windowName} Window");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CanExecute = () => !Service.ClientState.IsPvP,
|
||||||
|
GetHelpText = () => string.Format(Strings.Command_OpenWindow, windowName),
|
||||||
|
Hidden = silent,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ISubCommand> SubCommands { get; }
|
||||||
|
}
|
42
KamiLib/ChatCommands/SubCommand.cs
Normal file
42
KamiLib/ChatCommands/SubCommand.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using KamiLib.Interfaces;
|
||||||
|
|
||||||
|
namespace KamiLib.ChatCommands;
|
||||||
|
|
||||||
|
public class SubCommand : ISubCommand
|
||||||
|
{
|
||||||
|
public string? CommandKeyword { get; init; }
|
||||||
|
public List<string>? Aliases { get; init; }
|
||||||
|
public Action? CommandAction { get; init; }
|
||||||
|
public Action<string?[]?>? ParameterAction { get; init; }
|
||||||
|
public Func<bool>? CanExecute { get; init; }
|
||||||
|
public Func<string>? GetHelpText { get; init; }
|
||||||
|
public bool Hidden { get; init; }
|
||||||
|
public bool HasParameterAction => ParameterAction is not null;
|
||||||
|
|
||||||
|
public string? GetCommand() => CommandKeyword;
|
||||||
|
public IEnumerable<string>? GetAliases() => Aliases;
|
||||||
|
|
||||||
|
string? ISubCommand.GetHelpText() => GetHelpText?.Invoke();
|
||||||
|
|
||||||
|
public bool Execute(CommandData commandData)
|
||||||
|
{
|
||||||
|
if (CanExecute?.Invoke() is null or true)
|
||||||
|
{
|
||||||
|
if (CommandAction is not null)
|
||||||
|
{
|
||||||
|
CommandAction.Invoke();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ParameterAction is not null)
|
||||||
|
{
|
||||||
|
ParameterAction.Invoke(commandData.Arguments);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
66
KamiLib/Configuration/Migrate.cs
Normal file
66
KamiLib/Configuration/Migrate.cs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Numerics;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace KamiLib.Configuration;
|
||||||
|
|
||||||
|
public static class Migrate
|
||||||
|
{
|
||||||
|
private static JObject? _parsedJson;
|
||||||
|
|
||||||
|
public static void LoadFile(FileInfo configFilePath)
|
||||||
|
{
|
||||||
|
var reader = new StreamReader(configFilePath.FullName);
|
||||||
|
var fileText = reader.ReadToEnd();
|
||||||
|
reader.Dispose();
|
||||||
|
|
||||||
|
_parsedJson = JObject.Parse(fileText);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetFileVersion()
|
||||||
|
{
|
||||||
|
return _parsedJson?.GetValue("Version")?.Value<int>() ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Setting<T> GetSettingValue<T>(string key) where T : struct
|
||||||
|
{
|
||||||
|
return new Setting<T>(_parsedJson!.SelectToken(key)!.Value<T>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Setting<T> GetSettingEnum<T>(string key) where T : struct
|
||||||
|
{
|
||||||
|
var readValue = _parsedJson!.SelectToken(key)!.Value<int>();
|
||||||
|
|
||||||
|
return new Setting<T>((T) Enum.ToObject(typeof(T), readValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T GetValue<T>(string key)
|
||||||
|
{
|
||||||
|
return _parsedJson!.SelectToken(key)!.Value<T>()!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JArray GetArray(string key)
|
||||||
|
{
|
||||||
|
return (JArray) _parsedJson!.SelectToken(key)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<T> GetArray<T>(string key)
|
||||||
|
{
|
||||||
|
var array = GetArray(key);
|
||||||
|
|
||||||
|
return array.ToObject<List<T>>()!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Setting<Vector4> GetVector4(string key)
|
||||||
|
{
|
||||||
|
return new Setting<Vector4>(new Vector4
|
||||||
|
{
|
||||||
|
X = GetValue<float>($"{key}.X"),
|
||||||
|
Y = GetValue<float>($"{key}.Y"),
|
||||||
|
Z = GetValue<float>($"{key}.Z"),
|
||||||
|
W = GetValue<float>($"{key}.W"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
45
KamiLib/Configuration/Setting.cs
Normal file
45
KamiLib/Configuration/Setting.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace KamiLib.Configuration;
|
||||||
|
|
||||||
|
public sealed record Setting<T>(T Value) : IEquatable<T> where T : notnull
|
||||||
|
{
|
||||||
|
public T Value = Value;
|
||||||
|
|
||||||
|
public override string ToString() => Value.ToString() ?? "Null";
|
||||||
|
|
||||||
|
public bool Equals(T? other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other)) return false;
|
||||||
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
|
||||||
|
return EqualityComparer<T>.Default.Equals(Value, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Setting<T> leftSide, T rightSide)
|
||||||
|
{
|
||||||
|
return leftSide.Equals(rightSide);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Setting<T> leftSide, T rightSide)
|
||||||
|
{
|
||||||
|
return !leftSide.Equals(rightSide);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator bool(Setting<T> obj)
|
||||||
|
{
|
||||||
|
if (obj.Value is bool value)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("Invalid implicit conversion to bool");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
// ReSharper disable once NonReadonlyMemberInGetHashCode
|
||||||
|
return EqualityComparer<T>.Default.GetHashCode(Value);
|
||||||
|
}
|
||||||
|
}
|
31
KamiLib/Drawing/Colors.cs
Normal file
31
KamiLib/Drawing/Colors.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using ImGuiNET;
|
||||||
|
|
||||||
|
namespace KamiLib.Drawing;
|
||||||
|
|
||||||
|
public static class Colors
|
||||||
|
{
|
||||||
|
public static Vector4 Purple = new(176 / 255.0f, 38 / 255.0f, 236 / 255.0f, 1.0f);
|
||||||
|
public static Vector4 Blue = new(37 / 255.0f, 168 / 255.0f, 1.0f, 1.0f);
|
||||||
|
public static Vector4 ForestGreen = new(0.133f, 0.545f, 0.1333f, 1.0f);
|
||||||
|
public static Vector4 White = new(1.0f, 1.0f, 1.0f,1.0f);
|
||||||
|
public static Vector4 Red = new(1.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
public static Vector4 Green = new(0.0f, 1.0f, 0.0f, 1.0f);
|
||||||
|
public static Vector4 Black = new(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
public static Vector4 HealerGreen = new(33 / 255f, 193 / 255f, 0, 1.0f);
|
||||||
|
public static Vector4 DPSRed = new(210/255f, 42/255f, 43/255f, 1.0f);
|
||||||
|
public static Vector4 SoftRed = new(0.8f, 0.2f, 0.2f, 1.0f);
|
||||||
|
public static Vector4 Grey = new(0.6f, 0.6f, 0.6f, 1.0f);
|
||||||
|
public static Vector4 LightGrey = new(220/250.0f, 220/250.0f, 220/250f, 1.0f);
|
||||||
|
public static Vector4 Orange = new(1.0f, 165.0f / 255.0f, 0.0f, 1.0f);
|
||||||
|
public static Vector4 SoftGreen = new(0.2f, 0.8f, 0.2f, 1.0f);
|
||||||
|
public static Vector4 FatePink = new(0.58f, 0.388f, 0.827f, 0.33f);
|
||||||
|
public static Vector4 FateDarkPink = new(0.58f, 0.388f, 0.827f, 1.0f);
|
||||||
|
public static Vector4 MapTextBrown = new(0.655f, 0.396f, 0.149f, 1.0f);
|
||||||
|
public static Vector4 BabyBlue = new(0.537f, 0.812f, 0.941f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ColorExtensions
|
||||||
|
{
|
||||||
|
public static uint ToU32(this Vector4 color) => ImGui.GetColorU32(color);
|
||||||
|
}
|
491
KamiLib/Drawing/DrawList.cs
Normal file
491
KamiLib/Drawing/DrawList.cs
Normal file
@ -0,0 +1,491 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
using Dalamud.Interface.Components;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
|
using ImGuiNET;
|
||||||
|
using KamiLib.Caching;
|
||||||
|
using KamiLib.Configuration;
|
||||||
|
using Action = System.Action;
|
||||||
|
|
||||||
|
namespace KamiLib.Drawing;
|
||||||
|
|
||||||
|
public abstract class DrawList<T>
|
||||||
|
{
|
||||||
|
protected T DrawListOwner { get; init; } = default!;
|
||||||
|
protected List<Action> DrawActions { get; } = new();
|
||||||
|
|
||||||
|
protected void DrawListContents()
|
||||||
|
{
|
||||||
|
foreach (var action in DrawActions)
|
||||||
|
{
|
||||||
|
action();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddDummy(float value)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() => ImGuiHelpers.ScaledDummy(value));
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddIndent(int tab)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() => ImGui.Indent(15.0f * tab));
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddIcon(uint iconID, Vector2 size, Vector4 color)
|
||||||
|
{
|
||||||
|
var icon = IconCache.Instance.GetIcon(iconID);
|
||||||
|
|
||||||
|
if (icon != null)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
ImGui.Image(icon.ImGuiHandle, size, Vector2.Zero, Vector2.One, color);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddIcon(uint iconID, Vector2 size, float transparency)
|
||||||
|
{
|
||||||
|
var icon = IconCache.Instance.GetIcon(iconID);
|
||||||
|
|
||||||
|
if (icon != null)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
ImGui.Image(icon.ImGuiHandle, size, Vector2.Zero, Vector2.One, Vector4.One with {W = transparency});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddString(string message, Vector4? color = null)
|
||||||
|
{
|
||||||
|
if (color == null)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() => ImGui.Text(message));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawActions.Add(() => ImGui.TextColored(color.Value, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddStringCentered(string message, float? availableArea = null, Vector4? color = null)
|
||||||
|
{
|
||||||
|
if (color == null)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
var area = availableArea / 2.0f ?? ImGui.GetContentRegionAvail().X / 2.0f;
|
||||||
|
|
||||||
|
ImGui.SetCursorPos(ImGui.GetCursorPos() with {X = ImGui.GetCursorPos().X + area - ImGui.CalcTextSize(message).X / 2.0f});
|
||||||
|
ImGui.Text(message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
var area = availableArea / 2.0f ?? ImGui.GetContentRegionAvail().X / 2.0f;
|
||||||
|
|
||||||
|
ImGui.SetCursorPos(ImGui.GetCursorPos() with {X = ImGui.GetCursorPos().X + area - ImGui.CalcTextSize(message).X / 2.0f});
|
||||||
|
ImGui.TextColored(color.Value, message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Indent(int indent)
|
||||||
|
{
|
||||||
|
DrawActions.Add( () => ImGui.Indent(indent) );
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T UnIndent(int indent)
|
||||||
|
{
|
||||||
|
DrawActions.Add( () => ImGui.Unindent(indent) );
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddConfigCheckbox(string label, Setting<bool> setting, string? helpText = null, string? additionalID = null)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
if (additionalID != null) ImGui.PushID(additionalID);
|
||||||
|
|
||||||
|
var cursorPosition = ImGui.GetCursorPos();
|
||||||
|
|
||||||
|
if (ImGui.Checkbox($"##{label}", ref setting.Value))
|
||||||
|
{
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
var spacing = ImGui.GetStyle().ItemSpacing;
|
||||||
|
cursorPosition += spacing;
|
||||||
|
ImGui.SetCursorPos(cursorPosition with { X = cursorPosition.X + 27.0f * ImGuiHelpers.GlobalScale });
|
||||||
|
|
||||||
|
ImGui.TextUnformatted(label);
|
||||||
|
|
||||||
|
if (helpText != null)
|
||||||
|
{
|
||||||
|
ImGuiComponents.HelpMarker(helpText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (additionalID != null) ImGui.PopID();
|
||||||
|
});
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddConfigCombo<TU>(IEnumerable<TU> values, Setting<TU> setting, Func<TU, string> localizeFunction, string label = "", float width = 0.0f) where TU : struct
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
if (width != 0.0f)
|
||||||
|
{
|
||||||
|
ImGui.SetNextItemWidth(width);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.PushItemWidth(ImGui.GetContentRegionAvail().X);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginCombo(label, localizeFunction(setting.Value)))
|
||||||
|
{
|
||||||
|
foreach (var value in values)
|
||||||
|
{
|
||||||
|
if (ImGui.Selectable(localizeFunction(value), setting.Value.Equals(value)))
|
||||||
|
{
|
||||||
|
setting.Value = value;
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndCombo();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddConfigColor(string label, Setting<Vector4> setting)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
if (ImGui.ColorEdit4(label, ref setting.Value, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.AlphaPreviewHalf))
|
||||||
|
{
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddConfigColor(string label, string defaultLabel, Setting<Vector4> setting, Vector4 defaultValue)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
ImGui.PushID(label);
|
||||||
|
|
||||||
|
if (ImGui.ColorEdit4($"##{label}", ref setting.Value, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.AlphaPreviewHalf))
|
||||||
|
{
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.BeginDisabled(setting == defaultValue);
|
||||||
|
if (ImGui.Button(defaultLabel))
|
||||||
|
{
|
||||||
|
setting.Value = defaultValue;
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
ImGui.EndDisabled();
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.TextUnformatted(label);
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
});
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddDragFloat(string label, Setting<float> setting, float minValue, float maxValue, float width = 0.0f, int precision = 2)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
if (width != 0.0f)
|
||||||
|
{
|
||||||
|
ImGui.SetNextItemWidth(width);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.PushItemWidth(ImGui.GetContentRegionAvail().X);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.DragFloat(label, ref setting.Value, 0.01f * maxValue, minValue, maxValue, $"%.{precision}f");
|
||||||
|
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||||
|
{
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddAction(Action action)
|
||||||
|
{
|
||||||
|
DrawActions.Add(action);
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddSliderInt(string label, Setting<int> setting, int minValue, int maxValue, float width = 200.0f)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
if (width != 0.0f)
|
||||||
|
{
|
||||||
|
ImGui.SetNextItemWidth(width);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.PushItemWidth(ImGui.GetContentRegionAvail().X);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SliderInt(label, ref setting.Value, minValue, maxValue);
|
||||||
|
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||||
|
{
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddConfigRadio<TU>(string label, Setting<TU> setting, TU buttonValue, string? helpText = null ) where TU : struct
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
var value = Convert.ToInt32(setting.Value);
|
||||||
|
|
||||||
|
if (ImGui.RadioButton(label, ref value, Convert.ToInt32(buttonValue)))
|
||||||
|
{
|
||||||
|
setting.Value = (TU)Enum.ToObject(typeof(TU), value);
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (helpText != null)
|
||||||
|
{
|
||||||
|
ImGuiComponents.HelpMarker(helpText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddConfigString(Setting<string> settingsCustomName, float width = 0.0f)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
if (width != 0.0f)
|
||||||
|
{
|
||||||
|
ImGui.SetNextItemWidth(width);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.InputText("", ref settingsCustomName.Value, 24);
|
||||||
|
|
||||||
|
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||||
|
{
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddConfigVector2(Setting<Vector2> setting, float width = 200.0f)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
if (width != 0.0f)
|
||||||
|
{
|
||||||
|
ImGui.SetNextItemWidth(width);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.PushItemWidth(ImGui.GetContentRegionAvail().X);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.InputFloat2("", ref setting.Value);
|
||||||
|
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||||
|
{
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddInputInt(string label, Setting<int> settingsPriority, int min, int max, int step = 1, int stepFast = 1, float width = 77.0f)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
ImGui.SetNextItemWidth(width);
|
||||||
|
ImGui.InputInt(label, ref settingsPriority.Value, step, stepFast);
|
||||||
|
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||||
|
{
|
||||||
|
settingsPriority.Value = Math.Clamp(settingsPriority.Value, min, max);
|
||||||
|
KamiCommon.SaveConfiguration();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddHelpMarker(string helpText)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
ImGuiComponents.HelpMarker(helpText);
|
||||||
|
});
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T BeginDisabled(bool shouldDisable)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
ImGui.BeginDisabled(shouldDisable);
|
||||||
|
});
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T EndDisabled()
|
||||||
|
{
|
||||||
|
DrawActions.Add(ImGui.EndDisabled);
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddSeparator()
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
var startPosition = ImGui.GetCursorScreenPos();
|
||||||
|
var stopPosition = startPosition with { X = startPosition.X + InfoBox.Instance.InnerWidth };
|
||||||
|
var color = ImGui.GetColorU32(Colors.White);
|
||||||
|
|
||||||
|
ImGui.GetWindowDrawList().AddLine(startPosition, stopPosition, color);
|
||||||
|
});
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T SameLine(float width = 0)
|
||||||
|
{
|
||||||
|
if (width == 0)
|
||||||
|
{
|
||||||
|
DrawActions.Add(ImGui.SameLine);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawActions.Add(() => ImGui.SameLine(width));
|
||||||
|
}
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddDisabledButton(string label, Action action, bool disable, string? hoverTooltip = null, float? buttonSize = null)
|
||||||
|
{
|
||||||
|
if (buttonSize is not null)
|
||||||
|
{
|
||||||
|
AddDisabledButtonWithSize(label, action, disable, buttonSize.Value, hoverTooltip);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddDisabledButtonWithoutSize(label, action, disable, hoverTooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void AddDisabledButtonWithSize(string label, Action action, bool disable, float buttonSize, string? hoverTooltip = null)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
if(disable) ImGui.PushStyleVar(ImGuiStyleVar.Alpha, 0.5f);
|
||||||
|
if (ImGui.Button(label, new Vector2(buttonSize, 23.0f * ImGuiHelpers.GlobalScale)) && !disable)
|
||||||
|
{
|
||||||
|
action.Invoke();
|
||||||
|
}
|
||||||
|
if(disable) ImGui.PopStyleVar();
|
||||||
|
|
||||||
|
if (hoverTooltip is not null && ImGui.IsItemHovered() && disable)
|
||||||
|
{
|
||||||
|
ImGui.SetTooltip(hoverTooltip);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddDisabledButtonWithoutSize(string label, Action action, bool disable, string? hoverTooltip = null)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
if(disable) ImGui.PushStyleVar(ImGuiStyleVar.Alpha, 0.5f);
|
||||||
|
if (ImGui.Button(label) && !disable)
|
||||||
|
{
|
||||||
|
action.Invoke();
|
||||||
|
}
|
||||||
|
if(disable) ImGui.PopStyleVar();
|
||||||
|
|
||||||
|
if (hoverTooltip is not null && ImGui.IsItemHovered() && disable)
|
||||||
|
{
|
||||||
|
ImGui.SetTooltip(hoverTooltip);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddButton(string label, Action action, Vector2? buttonSize = null)
|
||||||
|
{
|
||||||
|
if (buttonSize is not null)
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
if (ImGui.Button(label, buttonSize.Value))
|
||||||
|
{
|
||||||
|
action.Invoke();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawActions.Add(() =>
|
||||||
|
{
|
||||||
|
if (ImGui.Button(label))
|
||||||
|
{
|
||||||
|
action.Invoke();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
}
|
144
KamiLib/Drawing/InfoBox.cs
Normal file
144
KamiLib/Drawing/InfoBox.cs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
|
using ImGuiNET;
|
||||||
|
using KamiLib.Interfaces;
|
||||||
|
|
||||||
|
namespace KamiLib.Drawing;
|
||||||
|
|
||||||
|
public class InfoBox : DrawList<InfoBox>, IDrawable
|
||||||
|
{
|
||||||
|
private static float CurveRadius => 13.0f * ImGuiHelpers.GlobalScale;
|
||||||
|
private static float BorderThickness => 2.0f;
|
||||||
|
private static ImDrawListPtr DrawList => ImGui.GetWindowDrawList();
|
||||||
|
private static Vector2 RegionAvailable => ImGui.GetContentRegionAvail();
|
||||||
|
private static Vector2 StartPosition { get; set; }
|
||||||
|
private static Vector2 Size { get; set; }
|
||||||
|
private static Vector4 BorderColor { get; } = Colors.White;
|
||||||
|
private static Vector4 TitleColor { get; } = Colors.White;
|
||||||
|
private static float TotalWidth { get; set; }
|
||||||
|
private string Label { get; set; } = "Label Not Set";
|
||||||
|
private float WidthPercentage { get; set; }
|
||||||
|
|
||||||
|
public float InnerWidth { get; private set; }
|
||||||
|
|
||||||
|
private InfoBox()
|
||||||
|
{
|
||||||
|
DrawListOwner = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly InfoBox Instance = new();
|
||||||
|
|
||||||
|
public void Draw()
|
||||||
|
{
|
||||||
|
ImGuiHelpers.ScaledDummy(5.0f);
|
||||||
|
|
||||||
|
TotalWidth = RegionAvailable.X * WidthPercentage;
|
||||||
|
InnerWidth = TotalWidth - CurveRadius * 3.0f;
|
||||||
|
|
||||||
|
var startX = ImGui.GetCursorPos().X + RegionAvailable.X * ( 0.5f - WidthPercentage / 2.0f ) + CurveRadius / 2.0f;
|
||||||
|
ImGui.SetCursorPos(ImGui.GetCursorPos() with { X = startX });
|
||||||
|
StartPosition = ImGui.GetCursorScreenPos();
|
||||||
|
Size = new Vector2(InnerWidth + CurveRadius * 2.0f, 0);
|
||||||
|
|
||||||
|
DrawContents();
|
||||||
|
|
||||||
|
var calculatedHeight = ImGui.GetItemRectMax().Y - ImGui.GetItemRectMin().Y + CurveRadius * 2.0f;
|
||||||
|
Size = new Vector2(InnerWidth + CurveRadius * 2.0f, calculatedHeight);
|
||||||
|
|
||||||
|
DrawCorners();
|
||||||
|
DrawBorders();
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawContents()
|
||||||
|
{
|
||||||
|
var topLeftCurveCenter = new Vector2(StartPosition.X + CurveRadius, StartPosition.Y + CurveRadius);
|
||||||
|
|
||||||
|
ImGui.SetCursorScreenPos(topLeftCurveCenter);
|
||||||
|
ImGui.PushTextWrapPos(ImGui.GetCursorPos().X + Size.X - CurveRadius * 2.0f);
|
||||||
|
|
||||||
|
ImGui.BeginGroup();
|
||||||
|
ImGui.PushID(Label);
|
||||||
|
|
||||||
|
DrawListContents();
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
ImGui.EndGroup();
|
||||||
|
|
||||||
|
ImGui.PopTextWrapPos();
|
||||||
|
|
||||||
|
DrawActions.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawCorners()
|
||||||
|
{
|
||||||
|
var topLeftCurveCenter = new Vector2(StartPosition.X + CurveRadius, StartPosition.Y + CurveRadius);
|
||||||
|
var topRightCurveCenter = new Vector2(StartPosition.X + Size.X - CurveRadius, StartPosition.Y + CurveRadius);
|
||||||
|
var bottomLeftCurveCenter = new Vector2(StartPosition.X + CurveRadius, StartPosition.Y + Size.Y - CurveRadius);
|
||||||
|
var bottomRightCurveCenter = new Vector2(StartPosition.X + Size.X - CurveRadius, StartPosition.Y + Size.Y - CurveRadius);
|
||||||
|
|
||||||
|
DrawList.PathArcTo(topLeftCurveCenter, CurveRadius, MathF.PI, 1.55f * MathF.PI);
|
||||||
|
DrawList.PathStroke(BorderColor.ToU32(), ImDrawFlags.None, BorderThickness);
|
||||||
|
|
||||||
|
DrawList.PathArcTo(topRightCurveCenter, CurveRadius, 2.0f * MathF.PI, 1.45f * MathF.PI);
|
||||||
|
DrawList.PathStroke(BorderColor.ToU32(), ImDrawFlags.None, BorderThickness);
|
||||||
|
|
||||||
|
DrawList.PathArcTo(bottomLeftCurveCenter, CurveRadius, 0.5f * MathF.PI, 1.0f * MathF.PI);
|
||||||
|
DrawList.PathStroke(BorderColor.ToU32(), ImDrawFlags.None, BorderThickness);
|
||||||
|
|
||||||
|
DrawList.PathArcTo(bottomRightCurveCenter, CurveRadius, 0.0f, 0.5f * MathF.PI);
|
||||||
|
DrawList.PathStroke(BorderColor.ToU32(), ImDrawFlags.None, BorderThickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawBorders()
|
||||||
|
{
|
||||||
|
var color = BorderColor.ToU32();
|
||||||
|
|
||||||
|
DrawList.AddLine(new Vector2(StartPosition.X - 0.5f, StartPosition.Y + CurveRadius - 0.5f), new Vector2(StartPosition.X - 0.5f, StartPosition.Y + Size.Y - CurveRadius + 0.5f), color, BorderThickness);
|
||||||
|
DrawList.AddLine(new Vector2(StartPosition.X + Size.X - 0.5f, StartPosition.Y + CurveRadius - 0.5f), new Vector2(StartPosition.X + Size.X - 0.5f, StartPosition.Y + Size.Y - CurveRadius + 0.5f), color, BorderThickness);
|
||||||
|
DrawList.AddLine(new Vector2(StartPosition.X + CurveRadius - 0.5f, StartPosition.Y + Size.Y - 0.5f), new Vector2(StartPosition.X + Size.X - CurveRadius + 0.5f, StartPosition.Y + Size.Y - 0.5f), color, BorderThickness);
|
||||||
|
|
||||||
|
var textSize = ImGui.CalcTextSize(Label);
|
||||||
|
var textStartPadding = 7.0f * ImGuiHelpers.GlobalScale;
|
||||||
|
var textEndPadding = 7.0f * ImGuiHelpers.GlobalScale;
|
||||||
|
var textVerticalOffset = textSize.Y / 2.0f;
|
||||||
|
|
||||||
|
DrawList.AddText(new Vector2(StartPosition.X + CurveRadius + textStartPadding, StartPosition.Y - textVerticalOffset), TitleColor.ToU32(), Label);
|
||||||
|
DrawList.AddLine(new Vector2(StartPosition.X + CurveRadius + textStartPadding + textSize.X + textEndPadding, StartPosition.Y - 0.5f), new Vector2(StartPosition.X + Size.X - CurveRadius - 0.5f, StartPosition.Y - 0.5f), color, BorderThickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfoBox AddTitle(string title, float percentFill = 0.95f)
|
||||||
|
{
|
||||||
|
Label = title;
|
||||||
|
WidthPercentage = percentFill;
|
||||||
|
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfoBox AddTitle(string title, out float innerWidth, float percentFill = .95f)
|
||||||
|
{
|
||||||
|
Label = title;
|
||||||
|
WidthPercentage = percentFill;
|
||||||
|
|
||||||
|
TotalWidth = RegionAvailable.X * WidthPercentage;
|
||||||
|
InnerWidth = TotalWidth - CurveRadius * 3.0f;
|
||||||
|
|
||||||
|
innerWidth = InnerWidth;
|
||||||
|
return DrawListOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfoBoxTable BeginTable(float weight = 0.50f) => new InfoBoxTable(this, weight);
|
||||||
|
|
||||||
|
public InfoBoxList BeginList() => new InfoBoxList(this);
|
||||||
|
|
||||||
|
public InfoBox AddList(IEnumerable<IInfoBoxListConfigurationRow> rows)
|
||||||
|
{
|
||||||
|
return BeginList()
|
||||||
|
.AddRows(rows)
|
||||||
|
.EndList();
|
||||||
|
}
|
||||||
|
}
|
35
KamiLib/Drawing/InfoBoxList.cs
Normal file
35
KamiLib/Drawing/InfoBoxList.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using KamiLib.Interfaces;
|
||||||
|
|
||||||
|
namespace KamiLib.Drawing;
|
||||||
|
|
||||||
|
public class InfoBoxList : DrawList<InfoBoxList>
|
||||||
|
{
|
||||||
|
private readonly InfoBox owner;
|
||||||
|
|
||||||
|
public InfoBoxList(InfoBox owner)
|
||||||
|
{
|
||||||
|
this.owner = owner;
|
||||||
|
DrawListOwner = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfoBox EndList()
|
||||||
|
{
|
||||||
|
foreach (var row in DrawActions)
|
||||||
|
{
|
||||||
|
owner.AddAction(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfoBoxList AddRows(IEnumerable<IInfoBoxListConfigurationRow> rows)
|
||||||
|
{
|
||||||
|
foreach (var row in rows)
|
||||||
|
{
|
||||||
|
row.GetConfigurationRow(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
115
KamiLib/Drawing/InfoBoxTable.cs
Normal file
115
KamiLib/Drawing/InfoBoxTable.cs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
using ImGuiNET;
|
||||||
|
using KamiLib.Interfaces;
|
||||||
|
|
||||||
|
namespace KamiLib.Drawing;
|
||||||
|
|
||||||
|
public class InfoBoxTable
|
||||||
|
{
|
||||||
|
private readonly InfoBox owner;
|
||||||
|
private readonly float weight;
|
||||||
|
|
||||||
|
private readonly List<InfoBoxTableRow> rows = new();
|
||||||
|
private string emptyListString = string.Empty;
|
||||||
|
|
||||||
|
public InfoBoxTable(InfoBox owner, float weight = 0.5f)
|
||||||
|
{
|
||||||
|
this.owner = owner;
|
||||||
|
this.weight = weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfoBoxTableRow BeginRow()
|
||||||
|
{
|
||||||
|
return new InfoBoxTableRow(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfoBoxTable AddRow(InfoBoxTableRow row)
|
||||||
|
{
|
||||||
|
rows.Add(row);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfoBox EndTable()
|
||||||
|
{
|
||||||
|
owner.AddAction(() =>
|
||||||
|
{
|
||||||
|
if (rows.Count == 0)
|
||||||
|
{
|
||||||
|
if (emptyListString != string.Empty)
|
||||||
|
{
|
||||||
|
ImGui.TextColored(Colors.Orange, emptyListString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ImGui.BeginTable($"", 2, ImGuiTableFlags.None, new Vector2(owner.InnerWidth, 0)))
|
||||||
|
{
|
||||||
|
ImGui.TableSetupColumn("", ImGuiTableColumnFlags.None, 1f * (weight));
|
||||||
|
ImGui.TableSetupColumn("", ImGuiTableColumnFlags.None, 1f * (1 - weight));
|
||||||
|
|
||||||
|
foreach (var row in rows)
|
||||||
|
{
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
|
||||||
|
ImGui.PushTextWrapPos(GetWrapPosition());
|
||||||
|
row.FirstColumn?.Invoke();
|
||||||
|
ImGui.PopTextWrapPos();
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.PushTextWrapPos(GetWrapPosition());
|
||||||
|
row.SecondColumn?.Invoke();
|
||||||
|
ImGui.PopTextWrapPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float GetWrapPosition()
|
||||||
|
{
|
||||||
|
var region = ImGui.GetContentRegionAvail();
|
||||||
|
|
||||||
|
var cursor = ImGui.GetCursorPos();
|
||||||
|
|
||||||
|
var wrapPosition = cursor.X + region.X;
|
||||||
|
|
||||||
|
return wrapPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfoBoxTable AddConfigurationRows(IEnumerable<IInfoBoxTableConfigurationRow> configurableRows, string? emptyEnumerableString = null)
|
||||||
|
{
|
||||||
|
if(emptyEnumerableString is not null)
|
||||||
|
{
|
||||||
|
emptyListString = emptyEnumerableString;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var row in configurableRows)
|
||||||
|
{
|
||||||
|
row.GetConfigurationRow(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfoBoxTable AddDataRows(IEnumerable<IInfoBoxTableDataRow> dataRows, string? emptyEnumerableString = null)
|
||||||
|
{
|
||||||
|
if(emptyEnumerableString is not null)
|
||||||
|
{
|
||||||
|
emptyListString = emptyEnumerableString;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var row in dataRows)
|
||||||
|
{
|
||||||
|
row.GetDataRow(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
24
KamiLib/Drawing/InfoBoxTableRow.cs
Normal file
24
KamiLib/Drawing/InfoBoxTableRow.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace KamiLib.Drawing;
|
||||||
|
|
||||||
|
public class InfoBoxTableRow : DrawList<InfoBoxTableRow>
|
||||||
|
{
|
||||||
|
private readonly InfoBoxTable owner;
|
||||||
|
|
||||||
|
public Action? FirstColumn => DrawActions.Count > 0 ? DrawActions[0] : null;
|
||||||
|
public Action? SecondColumn => DrawActions.Count > 1 ? DrawActions[1] : null;
|
||||||
|
|
||||||
|
public InfoBoxTableRow(InfoBoxTable owner)
|
||||||
|
{
|
||||||
|
this.owner = owner;
|
||||||
|
DrawListOwner = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfoBoxTable EndRow()
|
||||||
|
{
|
||||||
|
owner.AddRow(this);
|
||||||
|
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
}
|
50
KamiLib/Drawing/TabBar.cs
Normal file
50
KamiLib/Drawing/TabBar.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
using ImGuiNET;
|
||||||
|
using KamiLib.Interfaces;
|
||||||
|
|
||||||
|
namespace KamiLib.Drawing;
|
||||||
|
|
||||||
|
public class TabBar : IDrawable
|
||||||
|
{
|
||||||
|
private readonly List<ITabItem> tabs = new();
|
||||||
|
private readonly string tabBarID;
|
||||||
|
private readonly Vector2 childSize;
|
||||||
|
|
||||||
|
public TabBar(string id, Vector2? size = null)
|
||||||
|
{
|
||||||
|
tabBarID = id;
|
||||||
|
childSize = size ?? Vector2.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddTab(ITabItem tab) => tabs.Add(tab);
|
||||||
|
public void AddTab(IEnumerable<ITabItem> multipleTabs) => tabs.AddRange(multipleTabs);
|
||||||
|
|
||||||
|
public void Draw()
|
||||||
|
{
|
||||||
|
ImGui.PushID(tabBarID);
|
||||||
|
|
||||||
|
if (ImGui.BeginTabBar($"###{KamiCommon.PluginName}TabBar", ImGuiTabBarFlags.NoTooltip))
|
||||||
|
{
|
||||||
|
foreach (var tab in tabs)
|
||||||
|
{
|
||||||
|
if(tab.Enabled == false) continue;
|
||||||
|
|
||||||
|
if (ImGui.BeginTabItem(tab.TabName))
|
||||||
|
{
|
||||||
|
if (ImGui.BeginChild($"###{KamiCommon.PluginName}TabBarChild", childSize, false, ImGuiWindowFlags.NoScrollbar))
|
||||||
|
{
|
||||||
|
ImGui.PushID(tab.TabName);
|
||||||
|
tab.Draw();
|
||||||
|
ImGui.PopID();
|
||||||
|
}
|
||||||
|
ImGui.EndChild();
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
}
|
||||||
|
}
|
38
KamiLib/Extensions/PartyListExtensions.cs
Normal file
38
KamiLib/Extensions/PartyListExtensions.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Dalamud.Game.ClientState.Party;
|
||||||
|
|
||||||
|
namespace KamiLib.Extensions;
|
||||||
|
|
||||||
|
public static class PartyListExtensions
|
||||||
|
{
|
||||||
|
public static IEnumerable<PartyMember> Alive(this IEnumerable<PartyMember> list)
|
||||||
|
{
|
||||||
|
return list.Where(member => member.GameObject != null && !member.GameObject.IsDead);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<PartyMember> WithRole(this IEnumerable<PartyMember> list, uint roleID)
|
||||||
|
{
|
||||||
|
return list.Where(member => member.ClassJob.GameData?.Role == roleID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<PartyMember> WithJob(this IEnumerable<PartyMember> list, uint jobID)
|
||||||
|
{
|
||||||
|
return list.Where(member => member.ClassJob.Id == jobID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<PartyMember> WithJob(this IEnumerable<PartyMember> list, List<uint> jobList)
|
||||||
|
{
|
||||||
|
return list.Where(member => jobList.Contains(member.ClassJob.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<PartyMember> WithStatus(this IEnumerable<PartyMember> list, uint statusID)
|
||||||
|
{
|
||||||
|
return list.Where(member => member.HasStatus(statusID));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<PartyMember> WithStatus(this IEnumerable<PartyMember> list, List<uint> statusList)
|
||||||
|
{
|
||||||
|
return list.Where(member => member.HasStatus(statusList));
|
||||||
|
}
|
||||||
|
}
|
18
KamiLib/Extensions/PartyMemberExtensions.cs
Normal file
18
KamiLib/Extensions/PartyMemberExtensions.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Dalamud.Game.ClientState.Party;
|
||||||
|
|
||||||
|
namespace KamiLib.Extensions;
|
||||||
|
|
||||||
|
public static class PartyMemberExtensions
|
||||||
|
{
|
||||||
|
public static bool HasStatus(this PartyMember character, uint statusId)
|
||||||
|
{
|
||||||
|
return character.Statuses.Any(status => status.StatusId == statusId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasStatus(this PartyMember character, List<uint> statusList)
|
||||||
|
{
|
||||||
|
return character.Statuses.Any(status => statusList.Contains(status.StatusId));
|
||||||
|
}
|
||||||
|
}
|
62
KamiLib/Extensions/PlayerCharacterExtensions.cs
Normal file
62
KamiLib/Extensions/PlayerCharacterExtensions.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Dalamud.Game.ClientState.Objects.Enums;
|
||||||
|
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||||
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
|
|
||||||
|
namespace KamiLib.Extensions;
|
||||||
|
|
||||||
|
public static class PlayerCharacterExtensions
|
||||||
|
{
|
||||||
|
public static bool HasStatus(this PlayerCharacter character, uint statusId)
|
||||||
|
{
|
||||||
|
return character.StatusList.Any(status => status.StatusId == statusId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasStatus(this PlayerCharacter character, List<uint> statusList)
|
||||||
|
{
|
||||||
|
return character.StatusList.Any(status => statusList.Contains(status.StatusId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasOnlineStatus(this PlayerCharacter character, uint statusId)
|
||||||
|
{
|
||||||
|
return character.OnlineStatus.Id == statusId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int StatusCount(this PlayerCharacter character, List<uint> statusList)
|
||||||
|
{
|
||||||
|
return character.StatusList.Count(status => statusList.Contains(status.StatusId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasPet(this PlayerCharacter character)
|
||||||
|
{
|
||||||
|
var ownedObjects = Service.ObjectTable.Where(obj => obj.OwnerId == character.ObjectId);
|
||||||
|
|
||||||
|
return ownedObjects.Any(obj => obj.ObjectKind == ObjectKind.BattleNpc && (obj as BattleNpc)?.SubKind == (byte) BattleNpcSubKind.Pet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<PlayerCharacter> Alive(this IEnumerable<PlayerCharacter> list)
|
||||||
|
{
|
||||||
|
return list.Where(member => member.CurrentHp > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<PlayerCharacter> WithJob(this IEnumerable<PlayerCharacter> list, uint jobID)
|
||||||
|
{
|
||||||
|
return list.Where(member => member.ClassJob.Id == jobID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<PlayerCharacter> WithJob(this IEnumerable<PlayerCharacter> list, List<uint> jobList)
|
||||||
|
{
|
||||||
|
return list.Where(member => jobList.Contains(member.ClassJob.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<PlayerCharacter> WithStatus(this IEnumerable<PlayerCharacter> list, uint statusID)
|
||||||
|
{
|
||||||
|
return list.Where(member => member.HasStatus(statusID));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<PlayerCharacter> WithStatus(this IEnumerable<PlayerCharacter> list, List<uint> statusList)
|
||||||
|
{
|
||||||
|
return list.Where(member => member.HasStatus(statusList));
|
||||||
|
}
|
||||||
|
}
|
30
KamiLib/Extensions/TerritoryTypeExtensions.cs
Normal file
30
KamiLib/Extensions/TerritoryTypeExtensions.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using Dalamud.Interface.Utility;
|
||||||
|
using Dalamud.Utility;
|
||||||
|
using ImGuiNET;
|
||||||
|
using KamiLib.Caching;
|
||||||
|
using KamiLib.Drawing;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
|
||||||
|
namespace KamiLib.Extensions;
|
||||||
|
|
||||||
|
public static class TerritoryTypeExtensions
|
||||||
|
{
|
||||||
|
public static void DrawLabel(this TerritoryType data)
|
||||||
|
{
|
||||||
|
var placeString = data.GetPlaceNameString();
|
||||||
|
|
||||||
|
var startPosition = ImGui.GetCursorPos();
|
||||||
|
ImGui.TextColored(Colors.Grey, data.RowId.ToString());
|
||||||
|
ImGui.SameLine(startPosition.X + 50.0f * ImGuiHelpers.GlobalScale);
|
||||||
|
ImGui.Text(placeString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPlaceNameString(this TerritoryType data)
|
||||||
|
{
|
||||||
|
var placeNameRow = data.PlaceName.Row;
|
||||||
|
var placeName = LuminaCache<PlaceName>.Instance.GetRow(placeNameRow);
|
||||||
|
var placeString = placeName?.Name.ToDalamudString().TextValue ?? "Unknown PlaceName";
|
||||||
|
|
||||||
|
return placeString;
|
||||||
|
}
|
||||||
|
}
|
79
KamiLib/GameState/Condition.cs
Normal file
79
KamiLib/GameState/Condition.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
using Dalamud.Game.ClientState.Conditions;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
|
using KamiLib.Caching;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
|
||||||
|
namespace KamiLib.GameState;
|
||||||
|
|
||||||
|
public static class Condition
|
||||||
|
{
|
||||||
|
public static bool IsBoundByDuty()
|
||||||
|
{
|
||||||
|
if(IsInIslandSanctuary()) return false;
|
||||||
|
|
||||||
|
return Service.Condition[ConditionFlag.BoundByDuty] ||
|
||||||
|
Service.Condition[ConditionFlag.BoundByDuty56] ||
|
||||||
|
Service.Condition[ConditionFlag.BoundByDuty95];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsInCombat() => Service.Condition[ConditionFlag.InCombat];
|
||||||
|
public static bool IsInCutsceneOrQuestEvent() => IsInCutscene() || IsInQuestEvent();
|
||||||
|
public static bool IsDutyRecorderPlayback() => Service.Condition[ConditionFlag.DutyRecorderPlayback];
|
||||||
|
public static bool IsIslandDoingSomethingMode() => Service.GameGui.GetAddonByName("MJIPadGuide", 1) != nint.Zero;
|
||||||
|
|
||||||
|
public static bool IsInCutscene()
|
||||||
|
{
|
||||||
|
return Service.Condition[ConditionFlag.OccupiedInCutSceneEvent] ||
|
||||||
|
Service.Condition[ConditionFlag.WatchingCutscene] ||
|
||||||
|
Service.Condition[ConditionFlag.WatchingCutscene78];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsInQuestEvent()
|
||||||
|
{
|
||||||
|
if (IsInIslandSanctuary() && IsIslandDoingSomethingMode()) return false;
|
||||||
|
|
||||||
|
return Service.Condition[ConditionFlag.OccupiedInQuestEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsBetweenAreas()
|
||||||
|
{
|
||||||
|
return Service.Condition[ConditionFlag.BetweenAreas] ||
|
||||||
|
Service.Condition[ConditionFlag.BetweenAreas51];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsInIslandSanctuary()
|
||||||
|
{
|
||||||
|
var territoryInfo = LuminaCache<TerritoryType>.Instance.GetRow(Service.ClientState.TerritoryType);
|
||||||
|
if (territoryInfo is null) return false;
|
||||||
|
|
||||||
|
// Island Sanctuary
|
||||||
|
return territoryInfo.TerritoryIntendedUse == 49;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsCrafting()
|
||||||
|
{
|
||||||
|
return Service.Condition[ConditionFlag.Crafting] ||
|
||||||
|
Service.Condition[ConditionFlag.Crafting40];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsCrossWorld()
|
||||||
|
{
|
||||||
|
return Service.Condition[ConditionFlag.ParticipatingInCrossWorldPartyOrAlliance];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsInSanctuary()
|
||||||
|
{
|
||||||
|
return GameMain.IsInSanctuary();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CheckFlag(ConditionFlag flag)
|
||||||
|
{
|
||||||
|
return Service.Condition[flag];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsGathering()
|
||||||
|
{
|
||||||
|
return Service.Condition[ConditionFlag.Gathering] ||
|
||||||
|
Service.Condition[ConditionFlag.Gathering42];
|
||||||
|
}
|
||||||
|
}
|
124
KamiLib/GameState/DutyState.cs
Normal file
124
KamiLib/GameState/DutyState.cs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
using System;
|
||||||
|
using Dalamud.Hooking;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
using Dalamud.Utility.Signatures;
|
||||||
|
using KamiLib.Hooking;
|
||||||
|
|
||||||
|
namespace KamiLib.GameState;
|
||||||
|
|
||||||
|
public unsafe class DutyState : IDisposable
|
||||||
|
{
|
||||||
|
private delegate byte DutyEventDelegate(void* a1, void* a2, ushort* a3);
|
||||||
|
[Signature("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC ?? 48 8B D9 49 8B F8 41 0F B7 08", DetourName = nameof(DutyEventFunction))]
|
||||||
|
private readonly Hook<DutyEventDelegate>? dutyEventHook = null;
|
||||||
|
|
||||||
|
public bool IsDutyStarted { get; private set; }
|
||||||
|
|
||||||
|
public delegate void DutyStateEvent(uint duty);
|
||||||
|
|
||||||
|
public event DutyStateEvent? DutyStarted;
|
||||||
|
public event DutyStateEvent? DutyWiped;
|
||||||
|
public event DutyStateEvent? DutyRecommenced;
|
||||||
|
public event DutyStateEvent? DutyCompleted;
|
||||||
|
|
||||||
|
private bool completedThisTerritory;
|
||||||
|
|
||||||
|
private static DutyState? _instance;
|
||||||
|
public static DutyState Instance => _instance ??= new DutyState();
|
||||||
|
|
||||||
|
private DutyState()
|
||||||
|
{
|
||||||
|
Service.GameInteropProvider.InitializeFromAttributes(this);
|
||||||
|
|
||||||
|
dutyEventHook?.Enable();
|
||||||
|
|
||||||
|
if (Condition.IsBoundByDuty())
|
||||||
|
{
|
||||||
|
IsDutyStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Service.Framework.Update += FrameworkUpdate;
|
||||||
|
Service.ClientState.TerritoryChanged += TerritoryChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cleanup()
|
||||||
|
{
|
||||||
|
_instance?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
dutyEventHook?.Dispose();
|
||||||
|
|
||||||
|
Service.Framework.Update -= FrameworkUpdate;
|
||||||
|
Service.ClientState.TerritoryChanged -= TerritoryChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FrameworkUpdate(IFramework framework)
|
||||||
|
{
|
||||||
|
if (!IsDutyStarted && !completedThisTerritory)
|
||||||
|
{
|
||||||
|
if (Condition.IsBoundByDuty() && Condition.IsInCombat())
|
||||||
|
{
|
||||||
|
IsDutyStarted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!Condition.IsBoundByDuty())
|
||||||
|
{
|
||||||
|
IsDutyStarted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TerritoryChanged(ushort e)
|
||||||
|
{
|
||||||
|
if (IsDutyStarted)
|
||||||
|
{
|
||||||
|
IsDutyStarted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
completedThisTerritory = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte DutyEventFunction(void* a1, void* a2, ushort* a3)
|
||||||
|
{
|
||||||
|
Safety.ExecuteSafe(() =>
|
||||||
|
{
|
||||||
|
var category = *(a3);
|
||||||
|
var type = *(uint*)(a3 + 4);
|
||||||
|
|
||||||
|
// DirectorUpdate Category
|
||||||
|
if (category == 0x6D)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
// Duty Commenced
|
||||||
|
case 0x40000001:
|
||||||
|
IsDutyStarted = true;
|
||||||
|
DutyStarted?.Invoke(Service.ClientState.TerritoryType);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Party Wipe
|
||||||
|
case 0x40000005:
|
||||||
|
IsDutyStarted = false;
|
||||||
|
DutyWiped?.Invoke(Service.ClientState.TerritoryType);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Duty Recommence
|
||||||
|
case 0x40000006:
|
||||||
|
IsDutyStarted = true;
|
||||||
|
DutyRecommenced?.Invoke(Service.ClientState.TerritoryType);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Duty Completed
|
||||||
|
case 0x40000003:
|
||||||
|
IsDutyStarted = false;
|
||||||
|
completedThisTerritory = true;
|
||||||
|
DutyCompleted?.Invoke(Service.ClientState.TerritoryType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return dutyEventHook!.Original(a1, a2, a3);
|
||||||
|
}
|
||||||
|
}
|
26
KamiLib/Hooking/Delegates.cs
Normal file
26
KamiLib/Hooking/Delegates.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
|
||||||
|
namespace KamiLib.Hooking;
|
||||||
|
|
||||||
|
public static class Delegates
|
||||||
|
{
|
||||||
|
public static unsafe class Addon
|
||||||
|
{
|
||||||
|
public delegate nint OnSetup(AtkUnitBase* addon, int valueCount, AtkValue* values);
|
||||||
|
public delegate void Draw(AtkUnitBase* addon);
|
||||||
|
public delegate byte OnRefresh(AtkUnitBase* addon, int valueCount, AtkValue* values);
|
||||||
|
public delegate void Finalize(AtkUnitBase* addon);
|
||||||
|
public delegate byte Update(AtkUnitBase* addon);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe class Agent
|
||||||
|
{
|
||||||
|
public delegate void Show(AgentInterface* agent);
|
||||||
|
public delegate nint ReceiveEvent(AgentInterface* agent, nint rawData, AtkValue* args, uint argCount, ulong sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe class Other
|
||||||
|
{
|
||||||
|
public delegate void* GoldSaucerUpdate(void* a1, byte* a2, uint a3, ushort a4, void* a5, int* data, byte eventID);
|
||||||
|
}
|
||||||
|
}
|
32
KamiLib/Hooking/Safety.cs
Normal file
32
KamiLib/Hooking/Safety.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Reflection;
|
||||||
|
using Dalamud.Logging;
|
||||||
|
|
||||||
|
namespace KamiLib.Hooking;
|
||||||
|
|
||||||
|
public static class Safety
|
||||||
|
{
|
||||||
|
public static void ExecuteSafe(Action action, string? message = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
action();
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
var trace = new StackTrace().GetFrame(1);
|
||||||
|
var callingAssembly = Assembly.GetCallingAssembly().GetName().Name;
|
||||||
|
|
||||||
|
if (trace is not null)
|
||||||
|
{
|
||||||
|
var callingClass = trace.GetMethod()?.DeclaringType;
|
||||||
|
var callingName = trace.GetMethod()?.Name;
|
||||||
|
|
||||||
|
PluginLog.Error($"Exception Source: {callingAssembly} :: {callingClass} :: {callingName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginLog.Error(exception, message ?? "Caught Exception Safely");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
KamiLib/Interfaces/IDrawable.cs
Normal file
6
KamiLib/Interfaces/IDrawable.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace KamiLib.Interfaces;
|
||||||
|
|
||||||
|
public interface IDrawable
|
||||||
|
{
|
||||||
|
void Draw();
|
||||||
|
}
|
18
KamiLib/Interfaces/IInfoBoxTableRow.cs
Normal file
18
KamiLib/Interfaces/IInfoBoxTableRow.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using KamiLib.Drawing;
|
||||||
|
|
||||||
|
namespace KamiLib.Interfaces;
|
||||||
|
|
||||||
|
public interface IInfoBoxTableConfigurationRow
|
||||||
|
{
|
||||||
|
void GetConfigurationRow(InfoBoxTable owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IInfoBoxTableDataRow
|
||||||
|
{
|
||||||
|
void GetDataRow(InfoBoxTable owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IInfoBoxListConfigurationRow
|
||||||
|
{
|
||||||
|
void GetConfigurationRow(InfoBoxList owner);
|
||||||
|
}
|
40
KamiLib/Interfaces/IPluginCommand.cs
Normal file
40
KamiLib/Interfaces/IPluginCommand.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using KamiLib.ChatCommands;
|
||||||
|
|
||||||
|
namespace KamiLib.Interfaces;
|
||||||
|
|
||||||
|
public interface IPluginCommand
|
||||||
|
{
|
||||||
|
string? CommandArgument { get; }
|
||||||
|
|
||||||
|
IEnumerable<ISubCommand> SubCommands { get; }
|
||||||
|
|
||||||
|
public bool Execute(CommandData data)
|
||||||
|
{
|
||||||
|
var matchingSubCommands = SubCommands
|
||||||
|
.Where(subCommand => MatchingSubCommand(subCommand, data.SubCommand))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (matchingSubCommands.Any())
|
||||||
|
{
|
||||||
|
foreach (var subCommand in matchingSubCommands)
|
||||||
|
{
|
||||||
|
subCommand.Execute(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool MatchingSubCommand(ISubCommand subCommand, string? targetCommand)
|
||||||
|
{
|
||||||
|
if (subCommand.GetCommand() == targetCommand) return true;
|
||||||
|
if (subCommand.GetAliases()?.Contains(targetCommand) ?? false) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
8
KamiLib/Interfaces/ISelectable.cs
Normal file
8
KamiLib/Interfaces/ISelectable.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace KamiLib.Interfaces;
|
||||||
|
|
||||||
|
public interface ISelectable
|
||||||
|
{
|
||||||
|
IDrawable Contents { get; }
|
||||||
|
void DrawLabel();
|
||||||
|
string ID { get; }
|
||||||
|
}
|
14
KamiLib/Interfaces/ISubCommand.cs
Normal file
14
KamiLib/Interfaces/ISubCommand.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using KamiLib.ChatCommands;
|
||||||
|
|
||||||
|
namespace KamiLib.Interfaces;
|
||||||
|
|
||||||
|
public interface ISubCommand
|
||||||
|
{
|
||||||
|
string? GetCommand();
|
||||||
|
IEnumerable<string>? GetAliases();
|
||||||
|
bool Execute(CommandData commandData);
|
||||||
|
string? GetHelpText();
|
||||||
|
bool Hidden { get; }
|
||||||
|
bool HasParameterAction { get; }
|
||||||
|
}
|
8
KamiLib/Interfaces/ITabItem.cs
Normal file
8
KamiLib/Interfaces/ITabItem.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace KamiLib.Interfaces;
|
||||||
|
|
||||||
|
public interface ITabItem
|
||||||
|
{
|
||||||
|
string TabName { get; }
|
||||||
|
bool Enabled { get; }
|
||||||
|
void Draw();
|
||||||
|
}
|
51
KamiLib/KamiCommon.cs
Normal file
51
KamiLib/KamiCommon.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
using KamiLib.Blacklist;
|
||||||
|
using KamiLib.Caching;
|
||||||
|
using KamiLib.ChatCommands;
|
||||||
|
using KamiLib.GameState;
|
||||||
|
using KamiLib.Localization;
|
||||||
|
using KamiLib.Teleporter;
|
||||||
|
using KamiLib.UserInterface;
|
||||||
|
using KamiLib.Windows;
|
||||||
|
|
||||||
|
namespace KamiLib;
|
||||||
|
|
||||||
|
public static class KamiCommon
|
||||||
|
{
|
||||||
|
public static string PluginName { get; private set; } = string.Empty;
|
||||||
|
public static CommandManager CommandManager { get; private set; } = null!;
|
||||||
|
public static WindowManager WindowManager { get; private set; } = null!;
|
||||||
|
|
||||||
|
private static Action _saveConfigFunction = null!;
|
||||||
|
|
||||||
|
public static void Initialize(DalamudPluginInterface pluginInterface, string pluginName, Action saveConfig)
|
||||||
|
{
|
||||||
|
pluginInterface.Create<Service>();
|
||||||
|
|
||||||
|
PluginName = pluginName;
|
||||||
|
_saveConfigFunction = saveConfig;
|
||||||
|
|
||||||
|
LocalizationManager.Instance.Initialize();
|
||||||
|
|
||||||
|
BlacklistDraw.PrimeSearch();
|
||||||
|
|
||||||
|
CommandManager = new CommandManager();
|
||||||
|
WindowManager = new WindowManager();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Dispose()
|
||||||
|
{
|
||||||
|
CommandManager.Dispose();
|
||||||
|
WindowManager.Dispose();
|
||||||
|
IconCache.Cleanup();
|
||||||
|
GameUserInterface.Cleanup();
|
||||||
|
DutyState.Cleanup();
|
||||||
|
ChatPayloadManager.Cleanup();
|
||||||
|
TeleportManager.Cleanup();
|
||||||
|
LocalizationManager.Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SaveConfiguration() => _saveConfigFunction();
|
||||||
|
}
|
72
KamiLib/KamiLib.csproj
Normal file
72
KamiLib/KamiLib.csproj
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0-windows</TargetFramework>
|
||||||
|
<Platforms>x64</Platforms>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>preview</LangVersion>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<DalamudLibPath>$(AppData)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="LICENSE" />
|
||||||
|
<None Remove=".gitignore" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="FFXIVClientStructs">
|
||||||
|
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Newtonsoft.Json">
|
||||||
|
<HintPath>$(DalamudLibPath)Newtonsoft.Json.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Dalamud">
|
||||||
|
<HintPath>$(DalamudLibPath)Dalamud.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="CheapLoc">
|
||||||
|
<HintPath>$(DalamudLibPath)CheapLoc.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>
|
||||||
|
<EmbeddedResource Update="Localization\Strings.resx">
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="Localization\Strings.Designer.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Strings.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
16
KamiLib/KamiLib.sln
Normal file
16
KamiLib/KamiLib.sln
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KamiLib", "KamiLib.csproj", "{52A9E8E2-ACC7-4696-8684-5C4984D0350C}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{52A9E8E2-ACC7-4696-8684-5C4984D0350C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{52A9E8E2-ACC7-4696-8684-5C4984D0350C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{52A9E8E2-ACC7-4696-8684-5C4984D0350C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{52A9E8E2-ACC7-4696-8684-5C4984D0350C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
14
KamiLib/LICENSE
Normal file
14
KamiLib/LICENSE
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Copyright (C) 2022 MidoriKami
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
41
KamiLib/Localization/LocalizationManager.cs
Normal file
41
KamiLib/Localization/LocalizationManager.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using Dalamud.Logging;
|
||||||
|
|
||||||
|
namespace KamiLib.Localization;
|
||||||
|
|
||||||
|
internal class LocalizationManager : IDisposable
|
||||||
|
{
|
||||||
|
private static LocalizationManager? _instance;
|
||||||
|
public static LocalizationManager Instance => _instance ??= new LocalizationManager();
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
Strings.Culture = new CultureInfo(Service.PluginInterface.UiLanguage);
|
||||||
|
|
||||||
|
Service.PluginInterface.LanguageChanged += OnLanguageChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cleanup()
|
||||||
|
{
|
||||||
|
_instance?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Service.PluginInterface.LanguageChanged -= OnLanguageChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLanguageChange(string languageCode)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PluginLog.Information($"Loading Localization for {languageCode}");
|
||||||
|
Strings.Culture = new CultureInfo(languageCode);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
PluginLog.Error(ex, "Unable to Load Localization");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
331
KamiLib/Localization/Strings.Designer.cs
generated
Normal file
331
KamiLib/Localization/Strings.Designer.cs
generated
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace KamiLib.Localization {
|
||||||
|
|
||||||
|
|
||||||
|
/// <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", "4.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal 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)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||||
|
get {
|
||||||
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("KamiLib.Localization.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)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
|
get {
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Add or Remove Current Zone.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Blacklist_AddRemoveZone {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Blacklist_AddRemoveZone", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Add {0} Selected Areas.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Blacklist_AddSelectedAreas {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Blacklist_AddSelectedAreas", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Clear Blacklist.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Blacklist_ClearBlacklist {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Blacklist_ClearBlacklist", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Currently Blacklisted Areas.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Blacklist_CurrentlyBlacklisted {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Blacklist_CurrentlyBlacklisted", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Blacklist is Empty.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Blacklist_Empty {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Blacklist_Empty", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Remove {0} Selected Areas.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Blacklist_RemoveSelectedAreas {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Blacklist_RemoveSelectedAreas", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Search . . . .
|
||||||
|
/// </summary>
|
||||||
|
internal static string Blacklist_Search {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Blacklist_Search", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Select zones to add to blacklist.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Blacklist_SelectZones {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Blacklist_SelectZones", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Zone Search.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Blacklist_ZoneSearch {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Blacklist_ZoneSearch", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Closing {0} Window.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Command_ClosingWindow {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Command_ClosingWindow", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to display a list of all available sub-commands.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Command_DisplayHelpText {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Command_DisplayHelpText", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to The command '{0} {1}' does not exist..
|
||||||
|
/// </summary>
|
||||||
|
internal static string Command_DoesntExist {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Command_DoesntExist", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to The command '{0} {1} {2}' does not exist..
|
||||||
|
/// </summary>
|
||||||
|
internal static string Command_DoesntExistExtended {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Command_DoesntExistExtended", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Command.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Command_Label {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Command_Label", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Open Configuration Window.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Command_OpenConfigWindow {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Command_OpenConfigWindow", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Opening {0} Window.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Command_OpeningWindow {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Command_OpeningWindow", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Open {0} Window.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Command_OpenWindow {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Command_OpenWindow", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to The {0} Window cannot be opened while in a PvP area.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Command_PvPError {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Command_PvPError", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Show this message.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Command_ShowThisMessage {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Command_ShowThisMessage", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Add.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Common_Add {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Common_Add", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Error.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Common_Error {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Common_Error", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Remove.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Common_Remove {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Common_Remove", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to value.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Common_Value {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Common_Value", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Hold 'Shift' to enable button.
|
||||||
|
/// </summary>
|
||||||
|
internal static string DisabledButton_HoldShift {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("DisabledButton_HoldShift", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Select an item in the left pane.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Selection_NoItemSelected {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Selection_NoItemSelected", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Cannot teleport in this situation.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Teleport_BadSituation {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Teleport_BadSituation", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to To use the teleport function, you must install the "Teleporter" plugin.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Teleport_InstallTeleporter {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Teleport_InstallTeleporter", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Teleport.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Teleport_Label {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Teleport_Label", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Destination Aetheryte is not unlocked, teleport cancelled.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Teleport_NotUnlocked {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Teleport_NotUnlocked", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Teleporting to '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Teleport_TeleportingTo {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Teleport_TeleportingTo", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
109
KamiLib/Localization/Strings.de.resx
Normal file
109
KamiLib/Localization/Strings.de.resx
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>1.3</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="Blacklist_CurrentlyBlacklisted" xml:space="preserve">
|
||||||
|
<value>Bereiche aktuell auf der Schwarzen Liste</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_ClearBlacklist" xml:space="preserve">
|
||||||
|
<value>Schwarze Liste leeren</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_RemoveSelectedAreas" xml:space="preserve">
|
||||||
|
<value>Löschen der {0} ausgewählten Zonen</value>
|
||||||
|
</data>
|
||||||
|
<data name="DisabledButton_HoldShift" xml:space="preserve">
|
||||||
|
<value>Halten Sie 'Umschalt' gedrückt, um den Knopf zu aktivieren</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_AddRemoveZone" xml:space="preserve">
|
||||||
|
<value>Aktuelle Zone hinzufügen oder entfernen</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Add" xml:space="preserve">
|
||||||
|
<value>Hinzufügen</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Remove" xml:space="preserve">
|
||||||
|
<value>Entfernen</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_ZoneSearch" xml:space="preserve">
|
||||||
|
<value>Zonen Suche</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_AddSelectedAreas" xml:space="preserve">
|
||||||
|
<value>Hinzufügen der {0} ausgewählten Zonen</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_SelectZones" xml:space="preserve">
|
||||||
|
<value>Wählen sie Zonen aus um sie der Schwarzen Liste hinzuzufügen</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_Empty" xml:space="preserve">
|
||||||
|
<value>Die Schwarze Liste ist leer</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DoesntExist" xml:space="preserve">
|
||||||
|
<value>Der Befehl "{0} {1}" existiert nicht.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpenConfigWindow" xml:space="preserve">
|
||||||
|
<value>Öffne Konfigurationsfenster</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DisplayHelpText" xml:space="preserve">
|
||||||
|
<value>Zeige eine Liste aller vorhandenen Sub-Befehle an</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_Label" xml:space="preserve">
|
||||||
|
<value>Befehl</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_Search" xml:space="preserve">
|
||||||
|
<value>Die Suche . . . </value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_ShowThisMessage" xml:space="preserve">
|
||||||
|
<value>Diese Nachricht anzeigen</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Value" xml:space="preserve">
|
||||||
|
<value>Wert</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_PvPError" xml:space="preserve">
|
||||||
|
<value>Das {0}-Fenster kann in einem PvP-Bereich nicht geöffnet werden</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpenWindow" xml:space="preserve">
|
||||||
|
<value>Öffne {0} Fenster</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpeningWindow" xml:space="preserve">
|
||||||
|
<value>Öffne {0} Fenster</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_ClosingWindow" xml:space="preserve">
|
||||||
|
<value>Schließe {0} Fenster</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DoesntExistExtended" xml:space="preserve">
|
||||||
|
<value>Der Befehl "{0} {1} {2}" existiert nicht.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Error" xml:space="preserve">
|
||||||
|
<value>Fehler</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_NotUnlocked" xml:space="preserve">
|
||||||
|
<value>Ziel-Aetheryte ist nicht freigeschaltet, Teleport abgebrochen</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_BadSituation" xml:space="preserve">
|
||||||
|
<value>In dieser Situation kann nicht teleportiert werden</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_TeleportingTo" xml:space="preserve">
|
||||||
|
<value>Teleportiere zu {0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_Label" xml:space="preserve">
|
||||||
|
<value>Teleport</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_InstallTeleporter" xml:space="preserve">
|
||||||
|
<value>Um die Teleport-Funktion nutzen zu können, müssen Sie das "Teleporter"-Plugin installieren</value>
|
||||||
|
</data>
|
||||||
|
<data name="Selection_NoItemSelected" xml:space="preserve">
|
||||||
|
<value>Wählen sie einen Gegenstand im linken Bereich aus</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
109
KamiLib/Localization/Strings.es.resx
Normal file
109
KamiLib/Localization/Strings.es.resx
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>1.3</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="Blacklist_CurrentlyBlacklisted" xml:space="preserve">
|
||||||
|
<value>Zonas en la lista negra</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_ClearBlacklist" xml:space="preserve">
|
||||||
|
<value>Limpiar Lista Negra</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_RemoveSelectedAreas" xml:space="preserve">
|
||||||
|
<value>Eliminar las {0} zonas seleccionadas</value>
|
||||||
|
</data>
|
||||||
|
<data name="DisabledButton_HoldShift" xml:space="preserve">
|
||||||
|
<value>Mantén «mayús» para habilitar botón</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_AddRemoveZone" xml:space="preserve">
|
||||||
|
<value>Añadir o Eliminar zona actual</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Add" xml:space="preserve">
|
||||||
|
<value>Añadir</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Remove" xml:space="preserve">
|
||||||
|
<value>Eliminar</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_ZoneSearch" xml:space="preserve">
|
||||||
|
<value>Buscar zonas</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_AddSelectedAreas" xml:space="preserve">
|
||||||
|
<value>Añadir las {0} zonas seleccionadas</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_SelectZones" xml:space="preserve">
|
||||||
|
<value>Selecciona qué zonas añadir a la lista negra</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_Empty" xml:space="preserve">
|
||||||
|
<value>La lista negra está vacía</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DoesntExist" xml:space="preserve">
|
||||||
|
<value>El comando «{0} {1}» no existe.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpenConfigWindow" xml:space="preserve">
|
||||||
|
<value>Abrir ventana de configuración</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DisplayHelpText" xml:space="preserve">
|
||||||
|
<value>muestra una lista de todos los subcomandos disponibles</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_Label" xml:space="preserve">
|
||||||
|
<value>Comando</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_Search" xml:space="preserve">
|
||||||
|
<value>Buscar . . . </value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_ShowThisMessage" xml:space="preserve">
|
||||||
|
<value>Mostrar este mensaje</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Value" xml:space="preserve">
|
||||||
|
<value>valor</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_PvPError" xml:space="preserve">
|
||||||
|
<value>La ventana {0} no puede abrirse en las zonas PvP</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpenWindow" xml:space="preserve">
|
||||||
|
<value>Abrir ventana {0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpeningWindow" xml:space="preserve">
|
||||||
|
<value>Abriendo ventana {0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_ClosingWindow" xml:space="preserve">
|
||||||
|
<value>Cerrando ventana {0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DoesntExistExtended" xml:space="preserve">
|
||||||
|
<value>El comando «{0} {1} {2}» no existe.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Error" xml:space="preserve">
|
||||||
|
<value>Error</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_NotUnlocked" xml:space="preserve">
|
||||||
|
<value>La eterita de destino no está desbloqueada. Teletransporte cancelado</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_BadSituation" xml:space="preserve">
|
||||||
|
<value>Imposible teletransportarse en esta situación</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_TeleportingTo" xml:space="preserve">
|
||||||
|
<value>Teletransportándose a {0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_Label" xml:space="preserve">
|
||||||
|
<value>Teletransporte</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_InstallTeleporter" xml:space="preserve">
|
||||||
|
<value>Para usar la función de teletransporte, debes instalar el plugin «Teleporter»</value>
|
||||||
|
</data>
|
||||||
|
<data name="Selection_NoItemSelected" xml:space="preserve">
|
||||||
|
<value>Selecciona un objeto en el panel izquierdo</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
109
KamiLib/Localization/Strings.fr.resx
Normal file
109
KamiLib/Localization/Strings.fr.resx
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>1.3</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="Blacklist_CurrentlyBlacklisted" xml:space="preserve">
|
||||||
|
<value>Zones actuellement dans la liste noire</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_ClearBlacklist" xml:space="preserve">
|
||||||
|
<value>Vider la liste noire</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_RemoveSelectedAreas" xml:space="preserve">
|
||||||
|
<value>Enlever les {0} zones sélectionnées</value>
|
||||||
|
</data>
|
||||||
|
<data name="DisabledButton_HoldShift" xml:space="preserve">
|
||||||
|
<value>Tenir 'Maj' pour activer le bouton</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_AddRemoveZone" xml:space="preserve">
|
||||||
|
<value>Ajouter ou enlever la zone actuelle</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Add" xml:space="preserve">
|
||||||
|
<value>Ajouter</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Remove" xml:space="preserve">
|
||||||
|
<value>Enlever</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_ZoneSearch" xml:space="preserve">
|
||||||
|
<value>Recherche de zone</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_AddSelectedAreas" xml:space="preserve">
|
||||||
|
<value>Ajouter les {0} zones sélectionnées</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_SelectZones" xml:space="preserve">
|
||||||
|
<value>Sélectionner les zones à ajouter à la liste noire</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_Empty" xml:space="preserve">
|
||||||
|
<value>La liste noire est vide</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DoesntExist" xml:space="preserve">
|
||||||
|
<value>La commande '{0} {1}' n'existe pas.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpenConfigWindow" xml:space="preserve">
|
||||||
|
<value>Ouvrir la fenêtre de configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DisplayHelpText" xml:space="preserve">
|
||||||
|
<value>afficher une liste de toutes les sous-commandes disponibles</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_Label" xml:space="preserve">
|
||||||
|
<value>Commande</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_Search" xml:space="preserve">
|
||||||
|
<value>Rechercher . . . </value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_ShowThisMessage" xml:space="preserve">
|
||||||
|
<value>Afficher ce message</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Value" xml:space="preserve">
|
||||||
|
<value>valeur</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_PvPError" xml:space="preserve">
|
||||||
|
<value>La fenêtre {0} ne peut pas être ouverte lorsque vous êtes dans une zone JcJ</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpenWindow" xml:space="preserve">
|
||||||
|
<value>Ouvrir la fenêtre {0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpeningWindow" xml:space="preserve">
|
||||||
|
<value>Ouverture de la fenêtre {0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_ClosingWindow" xml:space="preserve">
|
||||||
|
<value>Fermeture de la fenêtre {0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DoesntExistExtended" xml:space="preserve">
|
||||||
|
<value>La commande '{0} {1} {2}' n'existe pas.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Error" xml:space="preserve">
|
||||||
|
<value>Erreur</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_NotUnlocked" xml:space="preserve">
|
||||||
|
<value>L'éthérite de destination n'est pas harmonisée, la téléportation a été annulée</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_BadSituation" xml:space="preserve">
|
||||||
|
<value>La téléportation ne peut pas être effectuée dans cette situation</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_TeleportingTo" xml:space="preserve">
|
||||||
|
<value>Téléportation vers '{0}'</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_Label" xml:space="preserve">
|
||||||
|
<value>Téléportation</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_InstallTeleporter" xml:space="preserve">
|
||||||
|
<value>Pour utiliser la fonction de téléportation, vous devez installer le plugin "Teleporter"</value>
|
||||||
|
</data>
|
||||||
|
<data name="Selection_NoItemSelected" xml:space="preserve">
|
||||||
|
<value>Sélectionnez un élément dans le panneau à gauche</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
109
KamiLib/Localization/Strings.ja.resx
Normal file
109
KamiLib/Localization/Strings.ja.resx
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>1.3</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="Blacklist_CurrentlyBlacklisted" xml:space="preserve">
|
||||||
|
<value>ブラックリストに登録されているエリア</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_ClearBlacklist" xml:space="preserve">
|
||||||
|
<value>ブラックリストをクリア</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_RemoveSelectedAreas" xml:space="preserve">
|
||||||
|
<value>{0} 個の選択された領域を削除</value>
|
||||||
|
</data>
|
||||||
|
<data name="DisabledButton_HoldShift" xml:space="preserve">
|
||||||
|
<value>Shiftキーを押しながらボタンを有効にします</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_AddRemoveZone" xml:space="preserve">
|
||||||
|
<value>現在のゾーンを追加または削除</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Add" xml:space="preserve">
|
||||||
|
<value>追加</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Remove" xml:space="preserve">
|
||||||
|
<value>削除</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_ZoneSearch" xml:space="preserve">
|
||||||
|
<value>ゾーン検索</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_AddSelectedAreas" xml:space="preserve">
|
||||||
|
<value>{0} 個の選択されたエリアを削除</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_SelectZones" xml:space="preserve">
|
||||||
|
<value>ブラックリストに追加するゾーンを選択</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_Empty" xml:space="preserve">
|
||||||
|
<value>ブラックリストは空です。</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DoesntExist" xml:space="preserve">
|
||||||
|
<value>コマンド '{0} {1}' は存在しません。</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpenConfigWindow" xml:space="preserve">
|
||||||
|
<value>設定ウィンドウを開く</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DisplayHelpText" xml:space="preserve">
|
||||||
|
<value>利用可能なコマンドの一覧を表示します。</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_Label" xml:space="preserve">
|
||||||
|
<value>コマンド</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_Search" xml:space="preserve">
|
||||||
|
<value>検索 ... </value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_ShowThisMessage" xml:space="preserve">
|
||||||
|
<value>このメッセージを表示</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Value" xml:space="preserve">
|
||||||
|
<value>値</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_PvPError" xml:space="preserve">
|
||||||
|
<value>PvPエリアでは {0} ウィンドウを開くことができません</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpenWindow" xml:space="preserve">
|
||||||
|
<value>{0} のウィンドウを開く</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpeningWindow" xml:space="preserve">
|
||||||
|
<value>{0} のウィンドウを開いています...</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_ClosingWindow" xml:space="preserve">
|
||||||
|
<value>{0} のウィンドウを閉じる</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DoesntExistExtended" xml:space="preserve">
|
||||||
|
<value>コマンド '{0} {1} {2}' は存在しません。</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Error" xml:space="preserve">
|
||||||
|
<value>エラー</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_NotUnlocked" xml:space="preserve">
|
||||||
|
<value>宛先のエーテライトが未解放のため、テレポートはキャンセルされました。</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_BadSituation" xml:space="preserve">
|
||||||
|
<value>この状況ではテレポートできません</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_TeleportingTo" xml:space="preserve">
|
||||||
|
<value>'{0} ' にテレポート中</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_Label" xml:space="preserve">
|
||||||
|
<value>テレポート</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_InstallTeleporter" xml:space="preserve">
|
||||||
|
<value>テレポート機能を使用するには、"Teleporter" プラグインをインストールする必要があります</value>
|
||||||
|
</data>
|
||||||
|
<data name="Selection_NoItemSelected" xml:space="preserve">
|
||||||
|
<value>左から設定する項目を選択してください</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
111
KamiLib/Localization/Strings.resx
Normal file
111
KamiLib/Localization/Strings.resx
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<root>
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>1.3</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="Blacklist_CurrentlyBlacklisted" xml:space="preserve">
|
||||||
|
<value>Currently Blacklisted Areas</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_ClearBlacklist" xml:space="preserve">
|
||||||
|
<value>Clear Blacklist</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_RemoveSelectedAreas" xml:space="preserve">
|
||||||
|
<value>Remove {0} Selected Areas</value>
|
||||||
|
</data>
|
||||||
|
<data name="DisabledButton_HoldShift" xml:space="preserve">
|
||||||
|
<value>Hold 'Shift' to enable button</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_AddRemoveZone" xml:space="preserve">
|
||||||
|
<value>Add or Remove Current Zone</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Add" xml:space="preserve">
|
||||||
|
<value>Add</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Remove" xml:space="preserve">
|
||||||
|
<value>Remove</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_ZoneSearch" xml:space="preserve">
|
||||||
|
<value>Zone Search</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_AddSelectedAreas" xml:space="preserve">
|
||||||
|
<value>Add {0} Selected Areas</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_SelectZones" xml:space="preserve">
|
||||||
|
<value>Select zones to add to blacklist</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_Empty" xml:space="preserve">
|
||||||
|
<value>Blacklist is Empty</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DoesntExist" xml:space="preserve">
|
||||||
|
<value>The command '{0} {1}' does not exist.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpenConfigWindow" xml:space="preserve">
|
||||||
|
<value>Open Configuration Window</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DisplayHelpText" xml:space="preserve">
|
||||||
|
<value>display a list of all available sub-commands</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_Label" xml:space="preserve">
|
||||||
|
<value>Command</value>
|
||||||
|
</data>
|
||||||
|
<data name="Blacklist_Search" xml:space="preserve">
|
||||||
|
<value>Search . . . </value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_ShowThisMessage" xml:space="preserve">
|
||||||
|
<value>Show this message</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Value" xml:space="preserve">
|
||||||
|
<value>value</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_PvPError" xml:space="preserve">
|
||||||
|
<value>The {0} Window cannot be opened while in a PvP area</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpenWindow" xml:space="preserve">
|
||||||
|
<value>Open {0} Window</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_OpeningWindow" xml:space="preserve">
|
||||||
|
<value>Opening {0} Window</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_ClosingWindow" xml:space="preserve">
|
||||||
|
<value>Closing {0} Window</value>
|
||||||
|
</data>
|
||||||
|
<data name="Command_DoesntExistExtended" xml:space="preserve">
|
||||||
|
<value>The command '{0} {1} {2}' does not exist.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Common_Error" xml:space="preserve">
|
||||||
|
<value>Error</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_NotUnlocked" xml:space="preserve">
|
||||||
|
<value>Destination Aetheryte is not unlocked, teleport cancelled</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_BadSituation" xml:space="preserve">
|
||||||
|
<value>Cannot teleport in this situation</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_TeleportingTo" xml:space="preserve">
|
||||||
|
<value>Teleporting to '{0}'</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_Label" xml:space="preserve">
|
||||||
|
<value>Teleport</value>
|
||||||
|
</data>
|
||||||
|
<data name="Teleport_InstallTeleporter" xml:space="preserve">
|
||||||
|
<value>To use the teleport function, you must install the "Teleporter" plugin</value>
|
||||||
|
</data>
|
||||||
|
<data name="Selection_NoItemSelected" xml:space="preserve">
|
||||||
|
<value>Select an item in the left pane</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
76
KamiLib/Misc/DutyLists.cs
Normal file
76
KamiLib/Misc/DutyLists.cs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Dalamud;
|
||||||
|
using KamiLib.Caching;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
|
||||||
|
namespace KamiLib.Misc;
|
||||||
|
|
||||||
|
public enum DutyType
|
||||||
|
{
|
||||||
|
Savage,
|
||||||
|
Ultimate,
|
||||||
|
ExtremeUnreal,
|
||||||
|
Criterion,
|
||||||
|
Alliance,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DutyLists
|
||||||
|
{
|
||||||
|
private List<uint> Savage { get; }
|
||||||
|
private List<uint> Ultimate { get; }
|
||||||
|
private List<uint> ExtremeUnreal { get; }
|
||||||
|
private List<uint> Criterion { get; }
|
||||||
|
private List<uint> Alliance { get; }
|
||||||
|
|
||||||
|
private static DutyLists? _instance;
|
||||||
|
public static DutyLists Instance => _instance ??= new DutyLists();
|
||||||
|
|
||||||
|
private DutyLists()
|
||||||
|
{
|
||||||
|
// ContentType.Row 5 == Raids
|
||||||
|
Savage = LuminaCache<ContentFinderCondition>.Instance.OfLanguage(ClientLanguage.English)
|
||||||
|
.Where(t => t.ContentType.Row == 5)
|
||||||
|
.Where(t => t.Name.RawString.Contains("Savage"))
|
||||||
|
.Select(r => r.TerritoryType.Row)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// ContentType.Row 28 == Ultimate Raids
|
||||||
|
Ultimate = LuminaCache<ContentFinderCondition>.Instance
|
||||||
|
.Where(t => t.ContentType.Row == 28)
|
||||||
|
.Select(t => t.TerritoryType.Row)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// ContentType.Row 4 == Trials
|
||||||
|
ExtremeUnreal = LuminaCache<ContentFinderCondition>.Instance.OfLanguage(ClientLanguage.English)
|
||||||
|
.Where(t => t.ContentType.Row == 4)
|
||||||
|
.Where(t => t.Name.RawString.Contains("Extreme") || t.Name.RawString.Contains("Unreal") || t.Name.RawString.Contains("The Minstrel"))
|
||||||
|
.Select(t => t.TerritoryType.Row)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
Criterion = LuminaCache<ContentFinderCondition>.Instance
|
||||||
|
.Where(row => row.ContentType.Row is 30)
|
||||||
|
.Select(row => row.TerritoryType.Row)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
Alliance = LuminaCache<TerritoryType>.Instance
|
||||||
|
.Where(r => r.TerritoryIntendedUse is 8)
|
||||||
|
.Select(r => r.RowId)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DutyType GetDutyType(uint dutyId)
|
||||||
|
{
|
||||||
|
if (Savage.Contains(dutyId)) return DutyType.Savage;
|
||||||
|
if (Ultimate.Contains(dutyId)) return DutyType.Ultimate;
|
||||||
|
if (ExtremeUnreal.Contains(dutyId)) return DutyType.ExtremeUnreal;
|
||||||
|
if (Criterion.Contains(dutyId)) return DutyType.Criterion;
|
||||||
|
if (Alliance.Contains(dutyId)) return DutyType.Alliance;
|
||||||
|
|
||||||
|
return DutyType.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsType(uint dutyId, DutyType type) => GetDutyType(dutyId) == type;
|
||||||
|
public bool IsType(uint dutyId, IEnumerable<DutyType> types) => types.Any(type => IsType(dutyId, type));
|
||||||
|
}
|
116
KamiLib/Misc/Time.cs
Normal file
116
KamiLib/Misc/Time.cs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using KamiLib.Caching;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
|
||||||
|
namespace KamiLib.Misc;
|
||||||
|
|
||||||
|
public static class Time
|
||||||
|
{
|
||||||
|
public static DateTime NextDailyReset()
|
||||||
|
{
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
|
if( now.Hour < 15 )
|
||||||
|
{
|
||||||
|
return now.Date.AddHours(15);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return now.AddDays(1).Date.AddHours(15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateTime NextWeeklyReset()
|
||||||
|
{
|
||||||
|
return NextDayOfWeek(DayOfWeek.Tuesday, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateTime NextFashionReportReset()
|
||||||
|
{
|
||||||
|
return NextWeeklyReset().AddDays(-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateTime NextGrandCompanyReset()
|
||||||
|
{
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
var targetHour = 20;
|
||||||
|
|
||||||
|
if( now.Hour < targetHour )
|
||||||
|
{
|
||||||
|
return now.Date.AddHours(targetHour);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return now.AddDays(1).Date.AddHours(targetHour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateTime NextLeveAllowanceReset()
|
||||||
|
{
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
|
if( now.Hour < 12 )
|
||||||
|
{
|
||||||
|
return now.Date.AddHours(12);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return now.Date.AddDays(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateTime NextDayOfWeek(DayOfWeek weekday, int hour)
|
||||||
|
{
|
||||||
|
var today = DateTime.UtcNow;
|
||||||
|
|
||||||
|
if(today.Hour < hour && today.DayOfWeek == weekday)
|
||||||
|
{
|
||||||
|
return today.Date.AddHours(hour);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var nextReset = today.AddDays(1);
|
||||||
|
|
||||||
|
while (nextReset.DayOfWeek != weekday)
|
||||||
|
{
|
||||||
|
nextReset = nextReset.AddDays(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextReset.Date.AddHours(hour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateTime NextJumboCactpotReset()
|
||||||
|
{
|
||||||
|
var region = LookupDatacenterRegion(Service.ClientState.LocalPlayer?.HomeWorld.GameData?.DataCenter.Row);
|
||||||
|
|
||||||
|
return region switch
|
||||||
|
{
|
||||||
|
// Japan
|
||||||
|
1 => NextDayOfWeek(DayOfWeek.Saturday, 12),
|
||||||
|
|
||||||
|
// North America
|
||||||
|
2 => NextDayOfWeek(DayOfWeek.Sunday, 2),
|
||||||
|
|
||||||
|
// Europe
|
||||||
|
3 => NextDayOfWeek(DayOfWeek.Saturday, 19),
|
||||||
|
|
||||||
|
// Australia
|
||||||
|
4 => NextDayOfWeek(DayOfWeek.Saturday, 9),
|
||||||
|
|
||||||
|
// Unknown Region
|
||||||
|
_ => DateTime.MinValue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte LookupDatacenterRegion(uint? playerDatacenterID)
|
||||||
|
{
|
||||||
|
if (playerDatacenterID == null) return 0;
|
||||||
|
|
||||||
|
return LuminaCache<WorldDCGroupType>.Instance
|
||||||
|
.Where(world => world.RowId == playerDatacenterID.Value)
|
||||||
|
.Select(dc => dc.Region)
|
||||||
|
.FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
22
KamiLib/Service.cs
Normal file
22
KamiLib/Service.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using Dalamud.IoC;
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
|
||||||
|
namespace KamiLib;
|
||||||
|
|
||||||
|
internal class Service
|
||||||
|
{
|
||||||
|
[PluginService] public static DalamudPluginInterface PluginInterface { get; private set; } = null!;
|
||||||
|
[PluginService] public static ICommandManager Commands { get; private set; } = null!;
|
||||||
|
[PluginService] public static IClientState ClientState { get; private set; } = null!;
|
||||||
|
[PluginService] public static IChatGui Chat { get; private set; } = null!;
|
||||||
|
[PluginService] public static IGameGui GameGui { get; private set; } = null!;
|
||||||
|
[PluginService] public static ICondition Condition { get; private set; } = null!;
|
||||||
|
[PluginService] public static IDataManager DataManager { get; private set; } = null!;
|
||||||
|
[PluginService] public static IObjectTable ObjectTable { get; private set; } = null!;
|
||||||
|
[PluginService] public static IFramework Framework { get; private set; } = null!;
|
||||||
|
[PluginService] public static IToastGui Toast { get; private set;} = null!;
|
||||||
|
[PluginService] public static IAetheryteList AetheryteList { get; private set;} = null!;
|
||||||
|
[PluginService] public static IGameInteropProvider GameInteropProvider { get; private set;} = null!;
|
||||||
|
[PluginService] public static ITextureProvider TextureProvider { get; private set;} = null!;
|
||||||
|
}
|
151
KamiLib/Teleporter/TeleportManager.cs
Normal file
151
KamiLib/Teleporter/TeleportManager.cs
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Dalamud.Game.ClientState.Aetherytes;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||||
|
using Dalamud.Logging;
|
||||||
|
using Dalamud.Plugin.Ipc;
|
||||||
|
using Dalamud.Plugin.Ipc.Exceptions;
|
||||||
|
using KamiLib.Caching;
|
||||||
|
using KamiLib.ChatCommands;
|
||||||
|
using KamiLib.Localization;
|
||||||
|
using Lumina.Excel;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
|
||||||
|
namespace KamiLib.Teleporter;
|
||||||
|
|
||||||
|
public class TeleportInfo
|
||||||
|
{
|
||||||
|
public uint CommandID { get; }
|
||||||
|
public Enum Target { get; }
|
||||||
|
public Aetheryte Aetherite { get; }
|
||||||
|
|
||||||
|
public TeleportInfo(uint commandID, Enum target, uint aetheriteID)
|
||||||
|
{
|
||||||
|
CommandID = commandID;
|
||||||
|
Target = target;
|
||||||
|
Aetherite = GetAetheryte(aetheriteID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Aetheryte GetAetheryte(uint id) => LuminaCache<Aetheryte>.Instance.GetRow(id)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record TeleportLinkPayloads(Enum Location, DalamudLinkPayload Payload);
|
||||||
|
|
||||||
|
public class TeleportManager : IDisposable
|
||||||
|
{
|
||||||
|
private static TeleportManager? _instance;
|
||||||
|
public static TeleportManager Instance => _instance ??= new TeleportManager();
|
||||||
|
|
||||||
|
private readonly ICallGateSubscriber<uint, byte, bool> teleportIpc;
|
||||||
|
private readonly ICallGateSubscriber<bool> showChatMessageIpc;
|
||||||
|
|
||||||
|
private readonly List<TeleportInfo> teleportInfoList = new();
|
||||||
|
|
||||||
|
private List<TeleportLinkPayloads> ChatLinkPayloads { get; } = new();
|
||||||
|
|
||||||
|
private TeleportManager()
|
||||||
|
{
|
||||||
|
teleportIpc = Service.PluginInterface.GetIpcSubscriber<uint, byte, bool>(Strings.Teleport_Label);
|
||||||
|
showChatMessageIpc = Service.PluginInterface.GetIpcSubscriber<bool>("Teleport.ChatMessage");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cleanup()
|
||||||
|
{
|
||||||
|
_instance?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var payload in teleportInfoList)
|
||||||
|
{
|
||||||
|
Service.PluginInterface.RemoveChatLinkHandler(payload.CommandID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddTeleports(IEnumerable<TeleportInfo> teleports)
|
||||||
|
{
|
||||||
|
teleportInfoList.AddRange(teleports);
|
||||||
|
|
||||||
|
foreach (var teleport in teleportInfoList)
|
||||||
|
{
|
||||||
|
Service.PluginInterface.RemoveChatLinkHandler(teleport.CommandID);
|
||||||
|
|
||||||
|
var linkPayload = Service.PluginInterface.AddChatLinkHandler(teleport.CommandID, TeleportAction);
|
||||||
|
|
||||||
|
ChatLinkPayloads.Add(new TeleportLinkPayloads(teleport.Target, linkPayload));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TeleportAction(uint command, SeString message)
|
||||||
|
{
|
||||||
|
var teleportInfo = teleportInfoList.First(teleport => teleport.CommandID == command);
|
||||||
|
|
||||||
|
if (AetheryteUnlocked(teleportInfo.Aetherite, out var targetAetheriteEntry))
|
||||||
|
{
|
||||||
|
Teleport(targetAetheriteEntry!);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PluginLog.Error("User attempted to teleport to an aetheryte that is not unlocked");
|
||||||
|
UserError(Strings.Teleport_NotUnlocked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DalamudLinkPayload GetPayload(Enum targetLocation)
|
||||||
|
{
|
||||||
|
return ChatLinkPayloads.First(payload => Equals(payload.Location, targetLocation)).Payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Teleport(AetheryteEntry aetheryte)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var didTeleport = teleportIpc.InvokeFunc(aetheryte.AetheryteId, aetheryte.SubIndex);
|
||||||
|
var showMessage = showChatMessageIpc.InvokeFunc();
|
||||||
|
|
||||||
|
if (!didTeleport)
|
||||||
|
{
|
||||||
|
UserError(Strings.Teleport_BadSituation);
|
||||||
|
}
|
||||||
|
else if (showMessage)
|
||||||
|
{
|
||||||
|
Chat.Print(Strings.Teleport_Label, string.Format(Strings.Teleport_TeleportingTo, GetAetheryteName(aetheryte)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IpcNotReadyError)
|
||||||
|
{
|
||||||
|
PluginLog.Error("Teleport IPC not found");
|
||||||
|
UserError(Strings.Teleport_InstallTeleporter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UserError(string error)
|
||||||
|
{
|
||||||
|
Service.Chat.PrintError(error);
|
||||||
|
Service.Toast.ShowError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetAetheryteName(AetheryteEntry aetheryte)
|
||||||
|
{
|
||||||
|
var gameData = aetheryte.AetheryteData.GameData;
|
||||||
|
var placeName = gameData?.PlaceName.Value;
|
||||||
|
|
||||||
|
return placeName == null ? "[Name Lookup Failed]" : placeName.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool AetheryteUnlocked(ExcelRow aetheryte, out AetheryteEntry? entry)
|
||||||
|
{
|
||||||
|
if (Service.AetheryteList.Any(entry => entry.AetheryteId == aetheryte.RowId))
|
||||||
|
{
|
||||||
|
entry = Service.AetheryteList.First(entry => entry.AetheryteId == aetheryte.RowId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entry = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
61
KamiLib/UserInterface/GameUserInterface.cs
Normal file
61
KamiLib/UserInterface/GameUserInterface.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
using Dalamud.Game;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
// ReSharper disable ConditionIsAlwaysTrueOrFalse
|
||||||
|
|
||||||
|
namespace KamiLib.UserInterface;
|
||||||
|
|
||||||
|
public unsafe class GameUserInterface : IDisposable
|
||||||
|
{
|
||||||
|
public event EventHandler? UiHidden;
|
||||||
|
public event EventHandler? UiShown;
|
||||||
|
|
||||||
|
private static GameUserInterface? _instance;
|
||||||
|
public static GameUserInterface Instance => _instance ??= new GameUserInterface();
|
||||||
|
|
||||||
|
public bool IsVisible => !lastState;
|
||||||
|
private bool lastState;
|
||||||
|
|
||||||
|
private GameUserInterface()
|
||||||
|
{
|
||||||
|
Service.Framework.Update += FrameworkUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cleanup()
|
||||||
|
{
|
||||||
|
_instance?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Service.Framework.Update -= FrameworkUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FrameworkUpdate(IFramework framework)
|
||||||
|
{
|
||||||
|
var partyList = (AtkUnitBase*) Service.GameGui.GetAddonByName("_PartyList", 1);
|
||||||
|
var todoList = (AtkUnitBase*) Service.GameGui.GetAddonByName("_ToDoList", 1);
|
||||||
|
var enemyList = (AtkUnitBase*) Service.GameGui.GetAddonByName("_EnemyList", 1);
|
||||||
|
|
||||||
|
var partyListVisible = partyList != null && partyList->IsVisible;
|
||||||
|
var todoListVisible = todoList != null && todoList->IsVisible;
|
||||||
|
var enemyListVisible = enemyList != null && enemyList->IsVisible;
|
||||||
|
|
||||||
|
var shouldHideUi = !partyListVisible && !todoListVisible && !enemyListVisible;
|
||||||
|
|
||||||
|
if (lastState != shouldHideUi)
|
||||||
|
{
|
||||||
|
if (shouldHideUi)
|
||||||
|
{
|
||||||
|
UiHidden?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UiShown?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastState = shouldHideUi;
|
||||||
|
}
|
||||||
|
}
|
19
KamiLib/Windows/DrawFlags.cs
Normal file
19
KamiLib/Windows/DrawFlags.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using ImGuiNET;
|
||||||
|
|
||||||
|
namespace KamiLib.Windows;
|
||||||
|
|
||||||
|
public static class DrawFlags
|
||||||
|
{
|
||||||
|
public const ImGuiWindowFlags AutoResize = ImGuiWindowFlags.NoFocusOnAppearing |
|
||||||
|
ImGuiWindowFlags.NoTitleBar |
|
||||||
|
ImGuiWindowFlags.NoScrollbar |
|
||||||
|
ImGuiWindowFlags.NoCollapse |
|
||||||
|
ImGuiWindowFlags.AlwaysAutoResize;
|
||||||
|
|
||||||
|
public const ImGuiWindowFlags ManualSize = ImGuiWindowFlags.NoFocusOnAppearing |
|
||||||
|
ImGuiWindowFlags.NoTitleBar |
|
||||||
|
ImGuiWindowFlags.NoCollapse;
|
||||||
|
|
||||||
|
public const ImGuiWindowFlags LockPosition = ImGuiWindowFlags.NoMove |
|
||||||
|
ImGuiWindowFlags.NoResize;
|
||||||
|
}
|
67
KamiLib/Windows/SelectionList.cs
Normal file
67
KamiLib/Windows/SelectionList.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
using ImGuiNET;
|
||||||
|
using KamiLib.Interfaces;
|
||||||
|
using KamiLib.Localization;
|
||||||
|
|
||||||
|
namespace KamiLib.Windows;
|
||||||
|
|
||||||
|
public class SelectionList
|
||||||
|
{
|
||||||
|
private ISelectable? Selected { get; set; }
|
||||||
|
|
||||||
|
public void Draw(IEnumerable<ISelectable> selectables)
|
||||||
|
{
|
||||||
|
var frameBgColor = ImGui.GetStyle().Colors[(int)ImGuiCol.FrameBg];
|
||||||
|
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.FrameBg, frameBgColor with { W = 0.05f });
|
||||||
|
ImGui.PushStyleVar(ImGuiStyleVar.ScrollbarSize, 0.0f);
|
||||||
|
var listBoxValid = ImGui.BeginListBox("", new Vector2(-1, -1));
|
||||||
|
ImGui.PopStyleVar();
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
|
||||||
|
if (listBoxValid)
|
||||||
|
{
|
||||||
|
foreach (var item in selectables)
|
||||||
|
{
|
||||||
|
var headerHoveredColor = ImGui.GetStyle().Colors[(int)ImGuiCol.HeaderHovered];
|
||||||
|
var textSelectedColor = ImGui.GetStyle().Colors[(int)ImGuiCol.Header];
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.HeaderHovered, headerHoveredColor with { W = 0.1f });
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Header, textSelectedColor with { W = 0.1f });
|
||||||
|
|
||||||
|
if (ImGui.Selectable($"##SelectableID{item.ID}", Selected?.ID == item.ID))
|
||||||
|
{
|
||||||
|
Selected = Selected == item ? null : item;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
|
||||||
|
ImGui.SameLine(3.0f);
|
||||||
|
|
||||||
|
item.DrawLabel();
|
||||||
|
|
||||||
|
ImGui.Spacing();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndListBox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawSelected()
|
||||||
|
{
|
||||||
|
if (Selected is null)
|
||||||
|
{
|
||||||
|
var available = ImGui.GetContentRegionAvail() / 2.0f;
|
||||||
|
var textSize = ImGui.CalcTextSize(Strings.Selection_NoItemSelected) / 2.0f;
|
||||||
|
var center = new Vector2(available.X - textSize.X, available.Y - textSize.Y);
|
||||||
|
|
||||||
|
ImGui.SetCursorPos(center);
|
||||||
|
ImGui.TextWrapped(Strings.Selection_NoItemSelected);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Selected.Contents.Draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
KamiLib/Windows/SelectionWindow.cs
Normal file
87
KamiLib/Windows/SelectionWindow.cs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
|
using Dalamud.Interface.Windowing;
|
||||||
|
using ImGuiNET;
|
||||||
|
using KamiLib.Drawing;
|
||||||
|
using KamiLib.Interfaces;
|
||||||
|
|
||||||
|
namespace KamiLib.Windows;
|
||||||
|
|
||||||
|
public abstract class SelectionWindow : Window, IDrawable
|
||||||
|
{
|
||||||
|
private readonly float horizontalWeight;
|
||||||
|
private readonly float verticalHeight;
|
||||||
|
private const bool ShowBorders = false;
|
||||||
|
|
||||||
|
private readonly SelectionList selectionList = new();
|
||||||
|
|
||||||
|
protected abstract IEnumerable<ISelectable> GetSelectables();
|
||||||
|
protected bool ShowScrollBar = true;
|
||||||
|
|
||||||
|
protected SelectionWindow(string windowName, float xPercent, float height) : base(windowName)
|
||||||
|
{
|
||||||
|
horizontalWeight = xPercent;
|
||||||
|
verticalHeight = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Draw()
|
||||||
|
{
|
||||||
|
var region = ImGui.GetContentRegionAvail();
|
||||||
|
var itemSpacing = ImGui.GetStyle().ItemSpacing;
|
||||||
|
|
||||||
|
var leftSideWidth = region.X * horizontalWeight - itemSpacing.X / 2.0f;
|
||||||
|
var topLeftSideHeight = region.Y - verticalHeight * ImGuiHelpers.GlobalScale - itemSpacing.Y / 2.0f;
|
||||||
|
|
||||||
|
if(ImGui.BeginChild($"###{KamiCommon.PluginName}LeftSide", new Vector2( leftSideWidth, topLeftSideHeight), ShowBorders, ImGuiWindowFlags.NoDecoration))
|
||||||
|
{
|
||||||
|
selectionList.Draw(GetSelectables());
|
||||||
|
}
|
||||||
|
ImGui.EndChild();
|
||||||
|
|
||||||
|
var bottomLeftChildPosition = ImGui.GetCursorPos();
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
DrawVerticalLine();
|
||||||
|
|
||||||
|
var rightSideWidth = region.X * (1.0f - horizontalWeight) - itemSpacing.X / 2.0f;
|
||||||
|
|
||||||
|
if(ImGui.BeginChild($"###{KamiCommon.PluginName}RightSide", new Vector2(rightSideWidth, 0), ShowBorders, (ShowScrollBar ? ImGuiWindowFlags.AlwaysVerticalScrollbar : ImGuiWindowFlags.None) | ImGuiWindowFlags.NoDecoration))
|
||||||
|
{
|
||||||
|
selectionList.DrawSelected();
|
||||||
|
}
|
||||||
|
ImGui.EndChild();
|
||||||
|
|
||||||
|
ImGui.SetCursorPos(bottomLeftChildPosition);
|
||||||
|
|
||||||
|
if(ImGui.BeginChild($"###{KamiCommon.PluginName}BottomLeftSide", new Vector2(leftSideWidth, verticalHeight * ImGuiHelpers.GlobalScale), ShowBorders, ImGuiWindowFlags.NoDecoration))
|
||||||
|
{
|
||||||
|
DrawExtras();
|
||||||
|
}
|
||||||
|
ImGui.EndChild();
|
||||||
|
|
||||||
|
DrawSpecial();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void DrawExtras()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void DrawSpecial()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DrawVerticalLine()
|
||||||
|
{
|
||||||
|
var contentArea = ImGui.GetContentRegionAvail();
|
||||||
|
var itemSpacing = ImGui.GetStyle().ItemSpacing;
|
||||||
|
var cursor = new Vector2(ImGui.GetCursorScreenPos().X - itemSpacing.X / 2.0f, ImGui.GetCursorScreenPos().Y );
|
||||||
|
var drawList = ImGui.GetWindowDrawList();
|
||||||
|
var color = ImGui.GetColorU32(Colors.White);
|
||||||
|
|
||||||
|
drawList.AddLine(cursor, cursor with {Y = cursor.Y + contentArea.Y}, color, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
62
KamiLib/Windows/WindowManager.cs
Normal file
62
KamiLib/Windows/WindowManager.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Dalamud.Interface.Windowing;
|
||||||
|
using KamiLib.ChatCommands;
|
||||||
|
|
||||||
|
namespace KamiLib.Windows;
|
||||||
|
|
||||||
|
public class WindowManager : IDisposable
|
||||||
|
{
|
||||||
|
private readonly WindowSystem windowSystem;
|
||||||
|
|
||||||
|
private readonly List<Window> windows = new();
|
||||||
|
|
||||||
|
public WindowManager()
|
||||||
|
{
|
||||||
|
windowSystem = new WindowSystem(KamiCommon.PluginName);
|
||||||
|
|
||||||
|
windows.ForEach(window => windowSystem.AddWindow(window));
|
||||||
|
|
||||||
|
Service.PluginInterface.UiBuilder.Draw += DrawUI;
|
||||||
|
Service.PluginInterface.UiBuilder.OpenConfigUi += DrawConfigUI;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Service.PluginInterface.UiBuilder.Draw -= DrawUI;
|
||||||
|
Service.PluginInterface.UiBuilder.OpenConfigUi -= DrawConfigUI;
|
||||||
|
|
||||||
|
windowSystem.RemoveAllWindows();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddWindow(Window newWindow)
|
||||||
|
{
|
||||||
|
if (windowSystem.Windows.All(w => w.WindowName != newWindow.WindowName))
|
||||||
|
{
|
||||||
|
windows.Add(newWindow);
|
||||||
|
windowSystem.AddWindow(newWindow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddConfigurationWindow<T>(T configWindow) where T : Window
|
||||||
|
{
|
||||||
|
windows.Add(configWindow);
|
||||||
|
windowSystem.AddWindow(configWindow);
|
||||||
|
|
||||||
|
KamiCommon.CommandManager.AddCommand(new OpenWindowCommand<T>(null, false, "Configuration"));
|
||||||
|
KamiCommon.CommandManager.AddCommand(new OpenWindowCommand<T>("silent", true, "Configuration"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveWindow(Window window)
|
||||||
|
{
|
||||||
|
windows.Remove(window);
|
||||||
|
windowSystem.RemoveWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyCollection<Window> GetWindows() => windows;
|
||||||
|
|
||||||
|
public T? GetWindowOfType<T>() => windows.OfType<T>().FirstOrDefault();
|
||||||
|
private void DrawUI() => windowSystem.Draw();
|
||||||
|
private void DrawConfigUI() => KamiCommon.CommandManager.OnCommand($"{KamiCommon.PluginName}", "silent");
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user