Update to API 9 without the Kami touch
This commit is contained in:
parent
32f251720c
commit
2cf6ded1cd
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
.vs/
|
||||
obj/
|
||||
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"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<AssemblyName>CurrencyAlertClassic</AssemblyName>
|
||||
<Version>0.5.0.1</Version>
|
||||
<Description>Currency Alert</Description>
|
||||
<PackageProjectUrl>https://github.com/Lharz/xiv-currency-alert</PackageProjectUrl>
|
||||
@ -26,7 +27,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.10" />
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.12" />
|
||||
<Reference Include="FFXIVClientStructs">
|
||||
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"Author": "Lharz",
|
||||
"Name": "CurrencyAlert",
|
||||
"Name": "CurrencyAlert Classic",
|
||||
"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.",
|
||||
"Tags": [
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Dalamud.Interface.Internal;
|
||||
using Dalamud.Utility;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using ImGuiScene;
|
||||
@ -13,7 +14,7 @@ public class CurrencyInfo : IDisposable
|
||||
public uint ItemID { get; }
|
||||
public string ItemName { get; } = string.Empty;
|
||||
public uint IconID { get; }
|
||||
public TextureWrap? IconTexture { get; }
|
||||
public IDalamudTextureWrap? IconTexture { get; }
|
||||
|
||||
public CurrencyInfo(CurrencyName currency)
|
||||
{
|
||||
@ -81,4 +82,4 @@ public class CurrencyInfo : IDisposable
|
||||
.First()
|
||||
.Item.Row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,15 +3,16 @@ using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
|
||||
namespace CurrencyAlert;
|
||||
|
||||
public class Service
|
||||
{
|
||||
[PluginService] public static DalamudPluginInterface PluginInterface { get; private set; } = null!;
|
||||
[PluginService] public static Framework Framework { get; private set; } = null!;
|
||||
[PluginService] public static ClientState ClientState { get; private set; } = null!;
|
||||
[PluginService] public static IFramework Framework { get; private set; } = null!;
|
||||
[PluginService] public static IClientState ClientState { get; private set; } = null!;
|
||||
|
||||
public static Configuration Configuration { 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 (Condition.IsBoundByDuty()) return;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using CurrencyAlert.DataModels;
|
||||
using CurrencyAlert.Localization;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using ImGuiNET;
|
||||
using KamiLib.Drawing;
|
||||
using KamiLib.Interfaces;
|
||||
@ -45,4 +46,4 @@ public class GeneralSettingsSelectable : ISelectable, IDrawable
|
||||
.AddConfigColor(Strings.TextColor, Strings.Default, DisplaySettings.TextColor, Colors.White)
|
||||
.Draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
using CurrencyAlert.DataModels;
|
||||
using CurrencyAlert.Localization;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using ImGuiNET;
|
||||
using KamiLib.Drawing;
|
||||
using KamiLib.Interfaces;
|
||||
@ -43,4 +44,4 @@ public class TrackedCurrencySelectable : ISelectable, IDrawable
|
||||
.AddInputInt(Strings.Threshold, currency.Threshold, 0, 100000, 0, 0, innerWidth / 2.0f)
|
||||
.Draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ using System.Numerics;
|
||||
using System.Reflection;
|
||||
using CurrencyAlert.Windows.Components;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using ImGuiNET;
|
||||
using KamiLib.Drawing;
|
||||
using KamiLib.Interfaces;
|
||||
|
@ -4,9 +4,9 @@
|
||||
"net7.0-windows7.0": {
|
||||
"DalamudPackager": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.1.10, )",
|
||||
"resolved": "2.1.10",
|
||||
"contentHash": "S6NrvvOnLgT4GDdgwuKVJjbFo+8ZEj+JsEYk9ojjOR/MMfv1dIFpT8aRJQfI24rtDcw1uF+GnSSMN4WW1yt7fw=="
|
||||
"requested": "[2.1.12, )",
|
||||
"resolved": "2.1.12",
|
||||
"contentHash": "Sc0PVxvgg4NQjcI8n10/VfUQBAS4O+Fw2pZrAqBdRMbthYGeogzu5+xmIGCGmsEZ/ukMOBuAqiNiB5qA3MRalg=="
|
||||
},
|
||||
"kamilib": {
|
||||
"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