Make IsMinILevel public

main
ilitirit 3 years ago
parent a2ebaf710b
commit 5f3d8dc894

@ -13,6 +13,6 @@ namespace Expedience.Models
public bool IsUnrestricted { get; set; }
public bool HasEcho { get; set; }
public bool IsNpcSupported { get; set; }
public bool IsMinILevel { get; internal set; }
public bool IsMinILevel { get; set; }
}
}

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 MgAl2O4
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -1,3 +0,0 @@
# Expedience
Dalamud plugin for recording and uploading duty completion times

@ -1,90 +0,0 @@
using Dalamud.Configuration;
using Dalamud.Plugin;
using System;
using System.Collections.Generic;
namespace Expedience
{
[Serializable]
public class EmoteDataConfig
{
public string OwnerName { get; set; }
public int EmoteId { get; set; } = 0;
public int Counter { get; set; } = 0;
public bool IsValid() { return !string.IsNullOrEmpty(OwnerName) && (EmoteId > 0) && (Counter > 0); }
}
[Serializable]
public class Configuration : IPluginConfiguration
{
private static int VersionLatest = 1;
public int Version { get; set; } = VersionLatest;
public Dictionary<string, int> mapPats { internal get; set; } = new();
public List<EmoteDataConfig> Emotes { get; set; } = new();
public bool showSpecialPats { get; set; } = true;
public bool showFlyText { get; set; } = true;
public bool showCounterUI { get; set; } = false;
public bool canTrackDotes { get; set; } = true;
[NonSerialized]
private DalamudPluginInterface pluginInterface;
public void Initialize(DalamudPluginInterface pluginInterface)
{
this.pluginInterface = pluginInterface;
switch (Version)
{
case 0:
MigrateVersion0();
break;
default: break;
}
Emotes.RemoveAll(x => !x.IsValid());
}
public void Save()
{
Emotes.RemoveAll(x => !x.IsValid());
pluginInterface.SavePluginConfig(this);
}
public EmoteDataConfig FindOrAddEmote(string ownerName, int emoteId)
{
if (string.IsNullOrEmpty(ownerName) || emoteId <= 0)
{
return null;
}
EmoteDataConfig emoteOb = Emotes.Find(x => (x.EmoteId == emoteId && x.OwnerName.Equals(ownerName, StringComparison.OrdinalIgnoreCase)));
if (emoteOb != null)
{
return emoteOb;
}
emoteOb = new EmoteDataConfig() { OwnerName = ownerName, EmoteId = emoteId };
Emotes.Add(emoteOb);
return emoteOb;
}
private void MigrateVersion0()
{
foreach (var kvp in mapPats)
{
var emoteConfig = new EmoteDataConfig() { OwnerName = kvp.Key, EmoteId = EmoteReaderHooks.petEmoteId, Counter = kvp.Value };
Emotes.Add(emoteConfig);
}
mapPats.Clear();
Version = VersionLatest;
}
}
}

@ -1,138 +0,0 @@
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Logging;
using System;
using System.Collections.Generic;
namespace Expedience
{
public class EmoteCounter
{
public Action<int> OnChanged;
public bool isActive = true;
public int counterEmoteId;
public int[] triggerEmoteIds;
public string counterDesc;
public string counterDescPlural;
public string uiDesc;
private Dictionary<string, int> mapEmotesInZone = new();
private string currentPlayerName;
public void OnEmote(GameObject instigator, ushort emoteId)
{
bool canUse = emoteId == counterEmoteId;
if (triggerEmoteIds != null)
{
canUse = Array.FindIndex(triggerEmoteIds, x => x == emoteId) >= 0;
}
if (canUse && isActive)
{
var canNotify = IncCounter();
if (canNotify)
{
var playerInstigator = instigator as PlayerCharacter;
uint instigatorWorld = (playerInstigator != null) ? playerInstigator.HomeWorld.Id : 0;
Service.counterBroadcast.SendMessage(counterDesc, emoteId, instigator.Name.ToString(), instigatorWorld);
}
var instigatorName = (instigator != null) ? instigator.Name.ToString() : "??";
if (mapEmotesInZone.TryGetValue(instigatorName, out int counter))
{
mapEmotesInZone[instigatorName] = counter + 1;
}
else
{
mapEmotesInZone.Add(instigatorName, 1);
}
}
}
public int GetCounter()
{
if (currentPlayerName == null)
{
currentPlayerName = GetCurrentPlayerName();
}
var emoteData = Service.pluginConfig.FindOrAddEmote(currentPlayerName, counterEmoteId);
if (emoteData != null)
{
return emoteData.Counter;
}
return 0;
}
public bool IncCounter()
{
if (currentPlayerName == null)
{
currentPlayerName = GetCurrentPlayerName();
}
var emoteData = Service.pluginConfig.FindOrAddEmote(currentPlayerName, counterEmoteId);
if (emoteData != null)
{
emoteData.Counter++;
Service.pluginConfig.Save();
OnChanged?.Invoke(emoteData.Counter);
return true;
}
return false;
}
public void OnLogout()
{
currentPlayerName = null;
}
public void OnTerritoryChanged()
{
mapEmotesInZone.Clear();
}
public (string, int) GetTopEmotesInZone()
{
string maxPatsPlayer = null;
int maxPats = 0;
foreach (var kvp in mapEmotesInZone)
{
if (kvp.Value > maxPats)
{
maxPats = kvp.Value;
maxPatsPlayer = kvp.Key;
}
}
return (maxPatsPlayer, maxPats);
}
public int GetEmotesInCurrentZone(string instigatorName)
{
if (mapEmotesInZone.TryGetValue(instigatorName, out int numPats))
{
return numPats;
}
return 0;
}
private string GetCurrentPlayerName()
{
if (Service.clientState == null || Service.clientState.LocalPlayer == null || Service.clientState.LocalPlayer.Name == null)
{
return null;
}
return Service.clientState.LocalPlayer.Name.TextValue;
}
}
}

@ -1,69 +0,0 @@
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Hooking;
using Dalamud.Logging;
using System;
using System.Linq;
namespace Expedience
{
public class EmoteReaderHooks : IDisposable
{
public static ushort petEmoteId = 105; // TODO: read from lumina?
public Action<GameObject, ushort> OnEmote;
public delegate void OnEmoteFuncDelegate(ulong unk, ulong instigatorAddr, ushort emoteId, ulong targetId, ulong unk2);
private readonly Hook<OnEmoteFuncDelegate> hookEmote;
public bool IsValid = false;
public EmoteReaderHooks()
{
try
{
var emoteFuncPtr = Service.sigScanner.ScanText("48 89 5c 24 08 48 89 6c 24 10 48 89 74 24 18 48 89 7c 24 20 41 56 48 83 ec 30 4c 8b 74 24 60 48 8b d9 48 81 c1 60 2f 00 00");
hookEmote = Hook<OnEmoteFuncDelegate>.FromAddress(emoteFuncPtr, OnEmoteDetour);
hookEmote.Enable();
IsValid = true;
}
catch (Exception ex)
{
PluginLog.Error(ex, "oh noes!");
}
}
public void Dispose()
{
hookEmote?.Dispose();
IsValid = false;
}
void OnEmoteDetour(ulong unk, ulong instigatorAddr, ushort emoteId, ulong targetId, ulong unk2)
{
// unk - some field of event framework singleton? doesn't matter here anyway
// PluginLog.Log($"Emote >> unk:{unk:X}, instigatorAddr:{instigatorAddr:X}, emoteId:{emoteId}, targetId:{targetId:X}, unk2:{unk2:X}");
if (Service.clientState.LocalPlayer != null)
{
if (targetId == Service.clientState.LocalPlayer.ObjectId)
{
var instigatorOb = Service.objectTable.FirstOrDefault(x => (ulong)x.Address == instigatorAddr);
if (instigatorOb != null)
{
bool canCount = (instigatorOb.ObjectId != targetId);
#if DEBUG
canCount = true;
#endif
if (canCount)
{
OnEmote?.Invoke(instigatorOb, emoteId);
}
}
}
}
hookEmote.Original(unk, instigatorAddr, emoteId, targetId, unk2);
}
}
}

@ -1,40 +0,0 @@
using Dalamud.Interface.Windowing;
using ImGuiNET;
using System;
namespace Expedience
{
public class PatCountUI : Window, IDisposable
{
public PatCountUI() : base("Pat Count")
{
IsOpen = false;
Flags = ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.AlwaysAutoResize;
RespectCloseHotkey = false;
}
public void Dispose()
{
}
public override void Draw()
{
int pats = Service.patCounter.GetCounter();
ImGui.Text($"{Service.patCounter.uiDesc}: {pats}");
// add more counters if they want to be there
foreach (var counter in Service.plugin.emoteCounters)
{
if (counter != null && counter != Service.patCounter && !string.IsNullOrEmpty(counter.uiDesc) && counter.isActive)
{
int numEmotes = counter.GetCounter();
if (numEmotes > 0)
{
ImGui.Text($"{counter.uiDesc}: {numEmotes}");
}
}
}
}
}
}

@ -1,264 +0,0 @@
using Dalamud.Data;
using Dalamud.Game;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.Gui.FlyText;
using Dalamud.Game.Gui.Toast;
using Dalamud.Interface.Windowing;
using Dalamud.Logging;
using Dalamud.Plugin;
using ImGuiScene;
using Lumina.Excel;
using Lumina.Excel.GeneratedSheets;
using System;
using System.Collections.Generic;
namespace Expedience
{
public class Plugin : IDalamudPlugin
{
public string Name => "Expedience";
private readonly WindowSystem windowSystem = new("Expedience");
private PluginUI pluginUI;
private EmoteReaderHooks emoteReader;
private UIReaderVoteMvp uiReaderVoteMvp;
private UIReaderBannerMIP uiReaderBannerMIP;
private PluginWindowConfig windowConfig;
private PatCountUI patCountUI;
public readonly List<EmoteCounter> emoteCounters = new();
private ExcelSheet<TerritoryType> _territories;
private Tuple<PlaceName, DateTime> _currentDuty;
public Plugin(DalamudPluginInterface pluginInterface)
{
pluginInterface.Create<Service>();
Service.plugin = this;
Service.pluginConfig = pluginInterface.GetPluginConfig() as Configuration ?? new Configuration();
Service.pluginConfig.Initialize(pluginInterface);
_territories = Service.DataManager.GetExcelSheet<TerritoryType>();
Service.patCounter = new EmoteCounter()
{
counterEmoteId = EmoteReaderHooks.petEmoteId,
counterDesc = "pat",
counterDescPlural = "pats",
uiDesc = "Head pats",
};
Service.DutyState.DutyStarted += (sender, args) =>
{
var territory = Service.ClientState.TerritoryType;
var player = Service.ClientState.LocalPlayer;
PlaceName place = _territories.GetRow(territory)?.PlaceName.Value;
foreach (var member in Service.PartyList)
{
}
};
Service.DutyState.DutyCompleted += (sender, args) =>
{
var territory = Service.ClientState.TerritoryType;
var place = _territories.GetRow(territory)?.PlaceName.Value;
};
Service.patCounter.OnChanged += (num) => OnEmoteReward(Service.patCounter, num);
emoteCounters.Add(Service.patCounter);
// two different emote ids?
Service.doteCounter = new EmoteCounter()
{
counterEmoteId = 146,
triggerEmoteIds = new int[] { 146, 147 },
counterDesc = "dote",
counterDescPlural = "dotes",
uiDesc = "Ranged pats",
};
Service.doteCounter.OnChanged += (num) => OnEmoteReward(Service.doteCounter, num);
Service.doteCounter.isActive = Service.pluginConfig.canTrackDotes;
emoteCounters.Add(Service.doteCounter);
pluginUI = new PluginUI();
pluginUI.overlayImage = LoadEmbeddedImage("fan-kit-lala.png");
uiReaderVoteMvp = new UIReaderVoteMvp();
uiReaderBannerMIP = new UIReaderBannerMIP();
windowConfig = new PluginWindowConfig();
windowSystem.AddWindow(windowConfig);
patCountUI = new PatCountUI();
windowSystem.AddWindow(patCountUI);
Service.commandManager.AddHandler("/Expedience", new(OnCommand) { HelpMessage = "Show pat counter" });
Service.commandManager.AddHandler("/patcount", new(OnCommand) { HelpMessage = "Show persistent pat counter" });
pluginInterface.UiBuilder.Draw += OnDraw;
pluginInterface.UiBuilder.OpenConfigUi += OnOpenConfig;
emoteReader = new EmoteReaderHooks();
emoteReader.OnEmote += (instigator, emoteId) => emoteCounters.ForEach(x => x.OnEmote(instigator, emoteId));
Service.framework.Update += Framework_Update;
Service.ClientState.TerritoryChanged += ClientState_TerritoryChanged;
Service.ClientState.Logout += ClientState_Logout;
if (Service.pluginConfig.showCounterUI)
{
patCountUI.IsOpen = true;
}
Service.counterBroadcast = pluginInterface.GetIpcProvider<string, ushort, string, uint, object>("ExpedienceEmoteCounter");
}
private void Framework_Update(Framework framework)
{
float deltaSeconds = (float)framework.UpdateDelta.TotalSeconds;
uiReaderVoteMvp.Tick(deltaSeconds);
uiReaderBannerMIP.Tick(deltaSeconds);
}
private void ClientState_TerritoryChanged(object sender, ushort e)
{
emoteCounters.ForEach(x => x.OnTerritoryChanged());
}
private void ClientState_Logout(object sender, EventArgs e)
{
emoteCounters.ForEach(x => x.OnLogout());
}
public void Dispose()
{
pluginUI.Dispose();
emoteReader.Dispose();
windowSystem.RemoveAllWindows();
Service.commandManager.RemoveHandler("/Expedience");
Service.commandManager.RemoveHandler("/patcount");
Service.framework.Update -= Framework_Update;
Service.ClientState.TerritoryChanged -= ClientState_TerritoryChanged;
Service.ClientState.Logout -= ClientState_Logout;
}
private void OnCommand(string command, string args)
{
if (command == "/Expedience")
{
DescribeCounter(Service.patCounter, false);
foreach (var counter in emoteCounters)
{
if (counter != Service.patCounter)
{
DescribeCounter(counter);
}
}
}
else if (command == "/patcount")
{
patCountUI.Toggle();
}
}
private void DescribeCounter(EmoteCounter counter, bool hideEmpty = true)
{
if (counter == null || string.IsNullOrEmpty(counter.counterDesc) || !counter.isActive)
{
return;
}
int numEmotes = counter.GetCounter();
if (numEmotes <= 0 && hideEmpty)
{
return;
}
var useName = counter.counterDesc[0].ToString().ToUpper() + counter.counterDesc.Substring(1);
Service.chatGui.Print($"{useName} counter: {numEmotes}");
var (maxPlayerName, maxCount) = counter.GetTopEmotesInZone();
if (maxCount > 0)
{
string countDesc = (maxCount == 1) ? counter.counterDesc : counter.counterDescPlural;
Service.chatGui.Print($"♥ {maxPlayerName}: {maxCount} {countDesc}");
}
}
private void OnDraw()
{
pluginUI.Draw();
windowSystem.Draw();
}
private void OnOpenConfig()
{
windowConfig.IsOpen = true;
}
public void OnShowCounterConfigChanged(bool wantsUI)
{
patCountUI.IsOpen = wantsUI;
}
private void OnEmoteReward(EmoteCounter counter, int numEmotes)
{
// thresholds on: 5, 15, 25, 50, 75, ...
bool isSpecial = (numEmotes < 25) ? (numEmotes == 5 || numEmotes == 15) : ((numEmotes % 25) == 0);
if (isSpecial && Service.pluginConfig.showSpecialPats)
{
// pats get special rewards.
if (counter == Service.patCounter)
{
pluginUI.Show();
}
var useDesc = counter.counterDescPlural.ToUpper();
Service.toastGui?.ShowQuest($"{numEmotes} {useDesc}!", new QuestToastOptions
{
Position = QuestToastPosition.Centre,
DisplayCheckmark = true,
IconId = 0,
PlaySound = true
});
}
else if (Service.pluginConfig.showFlyText)
{
var useDesc = counter.counterDesc.ToUpper();
Service.flyTextGui?.AddFlyText(FlyTextKind.NamedCriticalDirectHit, 0, (uint)numEmotes, 0, useDesc, " ", 0xff00ff00, 0, 0);
}
}
private TextureWrap LoadEmbeddedImage(string name)
{
TextureWrap resultImage = null;
try
{
var myAssembly = GetType().Assembly;
var myAssemblyName = myAssembly.GetName().Name;
var resourceName = $"{myAssemblyName}.assets.{name}";
var resStream = myAssembly.GetManifestResourceStream(resourceName);
if (resStream != null && resStream.Length > 0)
{
var contentBytes = new byte[(int)resStream.Length];
resStream.Read(contentBytes, 0, contentBytes.Length);
resultImage = Service.pluginInterface.UiBuilder.LoadImage(contentBytes);
resStream.Close();
}
}
catch (Exception ex)
{
PluginLog.Error(ex, "failed to load overlay image");
}
return resultImage;
}
}
}

@ -1,101 +0,0 @@
using ImGuiNET;
using ImGuiScene;
using System;
using System.Numerics;
namespace Expedience
{
public class PluginUI : IDisposable
{
private enum AnimPhase
{
None,
Appear,
Keep,
Disappear,
}
public TextureWrap overlayImage;
private AnimPhase anim = AnimPhase.None;
private static readonly float[] animDuration = new float[] { 0.0f, 1.0f, 1.0f, 1.0f };
private float animTimeRemaining = 0.0f;
public void Show()
{
SetAnim(AnimPhase.Appear);
}
public void Draw()
{
if (anim == AnimPhase.None || overlayImage == null)
{
return;
}
float animPct = 1.0f - Math.Max(0.0f, animTimeRemaining / animDuration[(int)anim]);
// draw image
{
var viewport = ImGui.GetMainViewport();
var viewportCenter = viewport.GetCenter();
var drawHalfSize = new Vector2(overlayImage.Width * 0.5f, overlayImage.Height * 0.5f);
if (drawHalfSize.X > viewportCenter.X || drawHalfSize.Y > viewportCenter.Y)
{
drawHalfSize.Y = viewportCenter.Y * 3 / 4;
drawHalfSize.X = overlayImage.Width * drawHalfSize.Y / overlayImage.Height;
}
if (anim == AnimPhase.Appear)
{
drawHalfSize *= AnimElastic(animPct);
}
var drawAlpha =
(anim == AnimPhase.Appear) ? 1 - Math.Pow(1 - animPct, 4) :
(anim == AnimPhase.Disappear) ? (1.0f - animPct) :
1.0f;
uint drawColor = 0xffffff | (uint)(drawAlpha * 255) << 24;
var drawList = ImGui.GetForegroundDrawList();
drawList.AddImage(overlayImage.ImGuiHandle, viewportCenter - drawHalfSize, viewportCenter + drawHalfSize, Vector2.Zero, Vector2.One, drawColor);
}
// state transitions
animTimeRemaining -= ImGui.GetIO().DeltaTime;
if (animTimeRemaining <= 0.0f)
{
if (anim == AnimPhase.Disappear)
{
SetAnim(AnimPhase.None);
}
else
{
SetAnim(anim + 1);
}
}
}
private float AnimElastic(float alpha)
{
const float c4 = (float)(2 * Math.PI) / 3.0f;
return (alpha == 0) ? 0.0f :
(alpha == 1) ? 1.0f :
(float)(Math.Pow(2, -10 * alpha) * Math.Sin((alpha * 10 - 0.75) * c4) + 1);
}
private void SetAnim(AnimPhase anim)
{
this.anim = anim;
animTimeRemaining = animDuration[(int)anim];
}
public void Dispose()
{
overlayImage.Dispose();
}
}
}

@ -1,55 +0,0 @@
using Dalamud.Interface.Windowing;
using ImGuiNET;
using System;
using System.Numerics;
namespace Expedience
{
public class PluginWindowConfig : Window, IDisposable
{
public PluginWindowConfig() : base("Pat Config")
{
IsOpen = false;
SizeConstraints = new WindowSizeConstraints() { MinimumSize = new Vector2(100, 0), MaximumSize = new Vector2(300, 3000) };
Flags = ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoScrollbar;
}
public void Dispose()
{
}
public override void Draw()
{
bool showSpecialPats = Service.pluginConfig.showSpecialPats;
bool showFlyText = Service.pluginConfig.showFlyText;
bool showCounterOnScreen = Service.pluginConfig.showCounterUI;
bool canTrackDotes = Service.pluginConfig.canTrackDotes;
bool hasChanges = false;
hasChanges = ImGui.Checkbox("Show notify on reaching pat goals", ref showSpecialPats) || hasChanges;
hasChanges = ImGui.Checkbox("Show fly text counter on each emote", ref showFlyText) || hasChanges;
hasChanges = ImGui.Checkbox("Show pat counter on screen", ref showCounterOnScreen) || hasChanges;
ImGui.Separator();
hasChanges = ImGui.Checkbox("Track emote: dote", ref canTrackDotes) || hasChanges;
if (showCounterOnScreen != Service.pluginConfig.showCounterUI)
{
Service.plugin.OnShowCounterConfigChanged(showCounterOnScreen);
}
if (hasChanges)
{
Service.pluginConfig.showSpecialPats = showSpecialPats;
Service.pluginConfig.showFlyText = showFlyText;
Service.pluginConfig.showCounterUI = showCounterOnScreen;
Service.pluginConfig.canTrackDotes = canTrackDotes;
Service.pluginConfig.Save();
Service.doteCounter.isActive = canTrackDotes;
}
}
}
}

@ -1,71 +0,0 @@
using Dalamud.Data;
using Dalamud.Game;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Party;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.Command;
using Dalamud.Game.DutyState;
using Dalamud.Game.Gui;
using Dalamud.Game.Gui.FlyText;
using Dalamud.Game.Gui.Toast;
using Dalamud.IoC;
using Dalamud.Plugin;
using Dalamud.Plugin.Ipc;
using Lumina.Excel.GeneratedSheets;
namespace Expedience
{
internal class Service
{
public static Plugin plugin;
public static Configuration pluginConfig;
public static EmoteCounter patCounter;
public static EmoteCounter doteCounter;
public static ICallGateProvider<string, ushort, string, uint, object> counterBroadcast;
[PluginService]
public static DalamudPluginInterface pluginInterface { get; private set; } = null!;
[PluginService]
public static CommandManager commandManager { get; private set; } = null!;
[PluginService]
public static FlyTextGui flyTextGui { get; private set; } = null!;
[PluginService]
public static ToastGui toastGui { get; private set; } = null!;
[PluginService]
public static ClientState ClientState { get; private set; } = null!;
[PluginService]
public static ChatGui chatGui { get; private set; } = null!;
[PluginService]
public static SigScanner sigScanner { get; private set; } = null!;
[PluginService]
public static ObjectTable objectTable { get; private set; } = null!;
[PluginService]
public static Framework framework { get; private set; } = null!;
[PluginService]
public static GameGui gameGui { get; private set; } = null!;
[PluginService]
public static DataManager DataManager { get; private set; } = null!;
[PluginService]
public static DutyState DutyState { get; private set; } = null!;
[PluginService]
public static PartyList PartyList { get; private set; } = null!;
[PluginService]
public static InstanceContent InstanceContent { get; private set; } = null!;
}
}

@ -1,107 +0,0 @@
using FFXIVClientStructs.FFXIV.Component.GUI;
using MgAl2O4.Utils;
using System;
using System.Collections.Generic;
namespace Expedience
{
public class UIReaderBannerMIP
{
public const float UpdateInterval = 0.5f;
private float updateTimeRemaining = 0.0f;
private IntPtr cachedAddonPtr;
private Dictionary<int, string> playerNames = new Dictionary<int, string>();
public void Tick(float deltaSeconds)
{
updateTimeRemaining -= deltaSeconds;
if (updateTimeRemaining < 0.0f)
{
updateTimeRemaining = UpdateInterval;
UpdateAddon();
}
}
private unsafe void UpdateAddon()
{
var addonPtr = Service.gameGui.GetAddonByName("BannerMIP", 1);
var addonBaseNode = (AtkUnitBase*)addonPtr;
if (addonBaseNode == null || addonBaseNode->RootNode == null || !addonBaseNode->RootNode->IsVisible)
{
// reset when closed
cachedAddonPtr = IntPtr.Zero;
playerNames.Clear();
return;
}
cachedAddonPtr = addonPtr;
var level0 = GUINodeUtils.GetImmediateChildNodes(addonBaseNode->RootNode);
var listRoot = GUINodeUtils.PickNode(level0, 2, 4);
var listNodes = GUINodeUtils.GetImmediateChildNodes(listRoot);
var collectsPlayerNames = playerNames.Count == 0;
if (listNodes != null)
{
for (int idx = 0; idx < listNodes.Length; idx++)
{
var innerList = GUINodeUtils.GetChildNode(listNodes[idx]);
if (innerList != null && innerList->IsVisible)
{
var nodeLastName = GUINodeUtils.PickChildNode(innerList, 20, 27);
var nodeFirstName = GUINodeUtils.PickChildNode(innerList, 21, 27);
var nodeCombined = GUINodeUtils.PickChildNode(innerList, 22, 27);
UpdatePlayerNames(idx, collectsPlayerNames, nodeLastName, nodeFirstName, nodeCombined);
}
}
}
}
private unsafe void UpdatePlayerNames(int entryIdx, bool collectsPlayerNames, AtkResNode* nodeLastName, AtkResNode* nodeFirstName, AtkResNode* nodeCombined)
{
if (nodeLastName == null || nodeFirstName == null || nodeCombined == null ||
nodeLastName->Type != NodeType.Text || nodeFirstName->Type != NodeType.Text || nodeCombined->Type != NodeType.Text)
{
return;
}
var lastName = GUINodeUtils.GetNodeText(nodeLastName);
if (lastName.Length == 0 || lastName.StartsWith("pats:"))
{
return;
}
var playerName = "";
if (collectsPlayerNames)
{
var firstName = GUINodeUtils.GetNodeText(nodeFirstName);
playerName = $"{firstName} {lastName}";
playerNames.Add(entryIdx, playerName);
}
else
{
playerNames.TryGetValue(entryIdx, out playerName);
}
if (playerName.Length <= 1) // include separator
{
return;
}
int numPats = Service.patCounter.GetEmotesInCurrentZone(playerName);
if (numPats > 0)
{
((AtkTextNode*)nodeLastName)->SetText($"pats: {numPats}");
nodeCombined->Flags &= ~0x10; // hide
nodeLastName->Flags |= 0x10; // show
nodeFirstName->Flags |= 0x10; // show
}
}
}
}

@ -1,74 +0,0 @@
using FFXIVClientStructs.FFXIV.Component.GUI;
using MgAl2O4.Utils;
using System;
namespace Expedience
{
public class UIReaderVoteMvp
{
public const float UpdateInterval = 0.5f;
private float updateTimeRemaining = 0.0f;
private IntPtr cachedAddonPtr;
public void Tick(float deltaSeconds)
{
updateTimeRemaining -= deltaSeconds;
if (updateTimeRemaining < 0.0f)
{
updateTimeRemaining = UpdateInterval;
UpdateAddon();
}
}
private unsafe void UpdateAddon()
{
var addonPtr = Service.gameGui.GetAddonByName("VoteMvp", 1);
var addonBaseNode = (AtkUnitBase*)addonPtr;
if (addonBaseNode == null || addonBaseNode->RootNode == null || !addonBaseNode->RootNode->IsVisible)
{
// reset when closed
cachedAddonPtr = IntPtr.Zero;
return;
}
// update once
if (cachedAddonPtr == addonPtr)
{
return;
}
cachedAddonPtr = addonPtr;
var childNodesL0 = GUINodeUtils.GetImmediateChildNodes(addonBaseNode->RootNode);
if (childNodesL0 != null)
{
foreach (var nodeL0 in childNodesL0)
{
var nodeL1 = GUINodeUtils.PickChildNode(nodeL0, 3, 7);
if (nodeL1 != null && nodeL1->Type == NodeType.Text)
{
var textNode = (AtkTextNode*)nodeL1;
var playerName = textNode->NodeText.ToString();
if (!playerName.Contains("pats ]") && !playerName.Contains("pat ]"))
{
int numPats = Service.patCounter.GetEmotesInCurrentZone(playerName);
if (numPats == 1)
{
playerName += " [ 1 pat ]";
textNode->SetText(playerName);
}
else if (numPats > 1)
{
playerName += $" [ {numPats} pats ]";
textNode->SetText(playerName);
}
}
}
}
}
}
}
}
Loading…
Cancel
Save