qstbak/Questionable/Questionable.Controller.GameUi/ChocoboNameHandler.cs
2026-01-19 08:31:23 +10:00

149 lines
4.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Dalamud.Game.Addon.Lifecycle;
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Component.GUI;
using LLib.GameUI;
using Microsoft.Extensions.Logging;
using Questionable.Model.Questing;
namespace Questionable.Controller.GameUi;
internal sealed class ChocoboNameHandler : IDisposable
{
private static readonly HashSet<ElementId> ChocoboQuestIds = new HashSet<ElementId>
{
new QuestId(700),
new QuestId(701),
new QuestId(702)
};
private readonly QuestController _questController;
private readonly Configuration _configuration;
private readonly IAddonLifecycle _addonLifecycle;
private readonly ILogger<ChocoboNameHandler> _logger;
private bool _awaitingConfirmation;
public ChocoboNameHandler(QuestController questController, Configuration configuration, IAddonLifecycle addonLifecycle, ILogger<ChocoboNameHandler> logger)
{
_questController = questController;
_configuration = configuration;
_addonLifecycle = addonLifecycle;
_logger = logger;
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "InputString", OnInputStringSetup);
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "SelectYesno", OnSelectYesNoSetup);
}
public void Dispose()
{
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "SelectYesno", OnSelectYesNoSetup);
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "InputString", OnInputStringSetup);
}
private bool IsChocoboQuestActive()
{
QuestController.QuestProgress currentQuest = _questController.CurrentQuest;
if (currentQuest != null)
{
return ChocoboQuestIds.Contains(currentQuest.Quest.Id);
}
return false;
}
private unsafe void OnInputStringSetup(AddonEvent type, AddonArgs args)
{
if (_questController.IsRunning && IsChocoboQuestActive())
{
AtkUnitBase* address = (AtkUnitBase*)args.Addon.Address;
if (LAddon.IsAddonReady(address))
{
string validatedChocoboName = GetValidatedChocoboName(_configuration.Advanced.ChocoboName);
_logger.LogInformation("Entering chocobo name: {Name}", validatedChocoboName);
FireInputStringCallback(address, validatedChocoboName);
_awaitingConfirmation = true;
}
}
}
private unsafe void OnSelectYesNoSetup(AddonEvent type, AddonArgs args)
{
if (_questController.IsRunning && _awaitingConfirmation)
{
AtkUnitBase* address = (AtkUnitBase*)args.Addon.Address;
if (LAddon.IsAddonReady(address))
{
_logger.LogInformation("Confirming chocobo name");
ClickYes(address);
_awaitingConfirmation = false;
}
}
}
private static string GetValidatedChocoboName(string? configuredName)
{
if (string.IsNullOrWhiteSpace(configuredName))
{
return "Kweh";
}
string text = configuredName.Trim();
if (text.Length < 2 || text.Length > 20)
{
return "Kweh";
}
string text2 = text.Substring(0, 1).ToUpperInvariant();
string text3;
if (text.Length <= 1)
{
text3 = string.Empty;
}
else
{
string text4 = text;
text3 = text4.Substring(1, text4.Length - 1).ToLowerInvariant();
}
return text2 + text3;
}
private unsafe void FireInputStringCallback(AtkUnitBase* addon, string text)
{
AtkComponentNode* componentNodeById = addon->GetComponentNodeById(9u);
if (componentNodeById == null)
{
_logger.LogWarning("Could not find text input node in InputString addon");
return;
}
AtkComponentTextInput* asAtkComponentTextInput = componentNodeById->GetAsAtkComponentTextInput();
if (asAtkComponentTextInput == null)
{
_logger.LogWarning("Node is not a text input component");
return;
}
asAtkComponentTextInput->SetText(text);
AtkValue* ptr = stackalloc AtkValue[2];
ptr->Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Int;
ptr->Int = 0;
byte[] bytes = Encoding.UTF8.GetBytes(text);
nint num = Marshal.AllocHGlobal(bytes.Length + 1);
Marshal.Copy(bytes, 0, num, bytes.Length);
Marshal.WriteByte(num + bytes.Length, 0);
ptr[1].Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.String;
ptr[1].String = (byte*)num;
addon->FireCallback(2u, ptr);
Marshal.FreeHGlobal(num);
}
private unsafe static void ClickYes(AtkUnitBase* addon)
{
AtkValue* ptr = stackalloc AtkValue[1];
ptr->Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Int;
ptr->Int = 0;
addon->FireCallback(1u, ptr);
}
}