Skip to content

Commit

Permalink
Update for Dawntrail
Browse files Browse the repository at this point in the history
  • Loading branch information
Caraxi committed Jul 17, 2024
1 parent 00b8871 commit 5edb83f
Show file tree
Hide file tree
Showing 13 changed files with 79 additions and 78 deletions.
29 changes: 15 additions & 14 deletions ApiProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
using System.Numerics;
using System.Threading;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin.Ipc;

namespace SimpleHeels;

public static class ApiProvider {
private const int ApiVersionMajor = 1;
private const int ApiVersionMajor = 2;
private const int ApiVersionMinor = 1;

public const string ApiVersionIdentifier = "SimpleHeels.ApiVersion";
Expand All @@ -23,8 +22,8 @@ public static class ApiProvider {
private static ICallGateProvider<(int, int)>? _apiVersion;
private static ICallGateProvider<string>? _getLocalPlayer;
private static ICallGateProvider<string, object?>? _localChanged;
private static ICallGateProvider<GameObject, string, object?>? _registerPlayer;
private static ICallGateProvider<GameObject, object?>? _unregisterPlayer;
private static ICallGateProvider<int, string, object?>? _registerPlayer;
private static ICallGateProvider<int, object?>? _unregisterPlayer;

private static IpcCharacterConfig? _lastReported;
private static Vector3? _lastReportedOffset;
Expand All @@ -44,28 +43,30 @@ public static void Init(Plugin plugin) {
_apiVersion.RegisterFunc(() => (ApiVersionMajor, ApiVersionMinor));
_getLocalPlayer = pluginInterface.GetIpcProvider<string>(GetLocalPlayerIdentifier);
_localChanged = pluginInterface.GetIpcProvider<string, object?>(LocalChangedIdentifier);
_registerPlayer = pluginInterface.GetIpcProvider<GameObject, string, object?>(RegisterPlayerIdentifier);
_unregisterPlayer = pluginInterface.GetIpcProvider<GameObject, object?>(UnregisterPlayerIdentifier);
_registerPlayer = pluginInterface.GetIpcProvider<int, string, object?>(RegisterPlayerIdentifier);
_unregisterPlayer = pluginInterface.GetIpcProvider<int, object?>(UnregisterPlayerIdentifier);

_apiVersion.RegisterFunc(() => (ApiVersionMajor, ApiVersionMinor));

_registerPlayer.RegisterAction((gameObject, data) => {
if (gameObject is not PlayerCharacter playerCharacter) return;
_registerPlayer.RegisterAction((gameObjectIndex, data) => {
var gameObject = gameObjectIndex >= 0 && gameObjectIndex < PluginService.Objects.Length ? PluginService.Objects[gameObjectIndex] : null;
if (gameObject is not IPlayerCharacter playerCharacter) return;
if (string.IsNullOrWhiteSpace(data)) {
Plugin.IpcAssignedData.Remove(playerCharacter.ObjectId);
Plugin.IpcAssignedData.Remove(playerCharacter.EntityId);
return;
}

var assigned = IpcCharacterConfig.FromString(data);
if (assigned == null) return;
Plugin.IpcAssignedData.Remove(playerCharacter.ObjectId);
Plugin.IpcAssignedData.Add(playerCharacter.ObjectId, assigned);
Plugin.IpcAssignedData.Remove(playerCharacter.EntityId);
Plugin.IpcAssignedData.Add(playerCharacter.EntityId, assigned);
Plugin.RequestUpdateAll();
});

_unregisterPlayer.RegisterAction(gameObject => {
if (gameObject is not PlayerCharacter playerCharacter) return;
Plugin.IpcAssignedData.Remove(playerCharacter.ObjectId);
_unregisterPlayer.RegisterAction(gameObjectIndex => {
var gameObject = gameObjectIndex >= 0 && gameObjectIndex < PluginService.Objects.Length ? PluginService.Objects[gameObjectIndex] : null;
if (gameObject is not IPlayerCharacter playerCharacter) return;
Plugin.IpcAssignedData.Remove(playerCharacter.EntityId);
Plugin.RequestUpdateAll();
});

Expand Down
1 change: 1 addition & 0 deletions Changelog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public static class Changelog {
private static bool _isOldExpanded;

private static void Changelogs() {
ChangelogFor(10.0f, "0.10.0.0", "Updated for Dawntrail");
ChangelogFor(9.35f, "0.9.3.5", "Fix support for new worlds.");
ChangelogFor(9.34f, "0.9.3.4", "Fixed issue causing other players to appear to teleport for a brief moment when using emotes with precise positioning.");
ChangelogFor(9.31f, "0.9.3.1", () => {
Expand Down
2 changes: 1 addition & 1 deletion CharacterConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public unsafe bool TryGetFirstMatch(GameObject* character, [NotNullWhen(true)] o
return offsetProvider != null;
}

public unsafe IOffsetProvider? GetFirstMatch(PlayerCharacter playerCharacter, bool checkEmote = true) {
public unsafe IOffsetProvider? GetFirstMatch(IPlayerCharacter playerCharacter, bool checkEmote = true) {
var character = (Character*)playerCharacter.Address;
if (character == null) return null;
return GetFirstMatch(character, checkEmote);
Expand Down
28 changes: 14 additions & 14 deletions ConfigWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Numerics;
using System.Threading;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Interface;
Expand All @@ -16,7 +17,6 @@
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing;
using Dalamud.Memory;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Game.Object;
Expand Down Expand Up @@ -183,7 +183,7 @@ public unsafe void DrawCharacterList() {
var ipcAssignedCharacter = (Character*)ipcAssignedObject;
if (ipcAssignedCharacter->HomeWorld == ushort.MaxValue) continue;

var name = MemoryHelper.ReadSeString((nint)ipcAssignedObject->Name, 64).TextValue;
var name = SeString.Parse(ipcAssignedObject->Name).TextValue;
var worldId = ipcAssignedCharacter->HomeWorld;

var world = PluginService.Data.GetExcelSheet<World>()?.GetRow(worldId);
Expand Down Expand Up @@ -264,9 +264,9 @@ public unsafe void DrawCharacterList() {
private void ShowDebugInfo() {
if (Plugin.IsDebug && ImGui.TreeNode("DEBUG INFO")) {
try {
var activePlayer = PluginService.Objects.FirstOrDefault(t => t is PlayerCharacter playerCharacter && playerCharacter.Name.TextValue == selectedName && playerCharacter.HomeWorld.Id == selectedWorld);
var activePlayer = PluginService.Objects.FirstOrDefault(t => t is IPlayerCharacter playerCharacter && playerCharacter.Name.TextValue == selectedName && playerCharacter.HomeWorld.Id == selectedWorld);

if (activePlayer is not PlayerCharacter pc) {
if (activePlayer is not IPlayerCharacter pc) {
ImGui.TextDisabled("Character is not currently in world.");
return;
}
Expand Down Expand Up @@ -377,7 +377,7 @@ public override void Draw() {

ImGui.SameLine();
if (ImGuiComponents.IconButton(FontAwesomeIcon.DotCircle)) {
if (PluginService.Targets.Target is PlayerCharacter pc) {
if (PluginService.Targets.Target is IPlayerCharacter pc) {
config.TryAddCharacter(pc.Name.TextValue, pc.HomeWorld.Id);
}
}
Expand Down Expand Up @@ -587,7 +587,7 @@ void World(string name, uint worldId, WorldDCGroupType? dc = null) {
if (ImGuiComponents.IconButton(FontAwesomeIcon.DotCircle)) {
var target = PluginService.Targets.SoftTarget ?? PluginService.Targets.Target;
if (target != null) {
var c = new GroupCharacter { Name = target.Name.TextValue, World = target is PlayerCharacter pc ? pc.HomeWorld.Id : ushort.MaxValue };
var c = new GroupCharacter { Name = target.Name.TextValue, World = target is IPlayerCharacter pc ? pc.HomeWorld.Id : ushort.MaxValue };
if (!selectedGroup.Characters.Any(ec => ec.Name == c.Name && ec.World == c.World)) {
selectedGroup.Characters.Add(c);
}
Expand Down Expand Up @@ -853,12 +853,12 @@ private unsafe void DrawCharacterView(CharacterConfig? characterConfig) {
IOffsetProvider? activeHeelConfig = null;

if (characterConfig is GroupConfig gc) {
var target = new[] { PluginService.Targets.SoftTarget, PluginService.Targets.Target, PluginService.ClientState.LocalPlayer }.FirstOrDefault(t => t is Dalamud.Game.ClientState.Objects.Types.Character character && gc.Matches(((GameObject*)character.Address)->DrawObject, character.Name.TextValue, (character is PlayerCharacter pc) ? pc.HomeWorld.Id : ushort.MaxValue));
if (target is Dalamud.Game.ClientState.Objects.Types.Character) {
var target = new[] { PluginService.Targets.SoftTarget, PluginService.Targets.Target, PluginService.ClientState.LocalPlayer }.FirstOrDefault(t => t is ICharacter character && gc.Matches(((GameObject*)character.Address)->DrawObject, character.Name.TextValue, (character is IPlayerCharacter pc) ? pc.HomeWorld.Id : ushort.MaxValue));
if (target is ICharacter) {
activeCharacter = (GameObject*)target.Address;
activeCharacterAsCharacter = (Character*)activeCharacter;
activeHeelConfig = characterConfig.GetFirstMatch(activeCharacterAsCharacter);
if (target is PlayerCharacter pc) {
if (target is IPlayerCharacter pc) {
ImGui.TextDisabled($"Preview displays based on {target.Name.TextValue} ({pc.HomeWorld?.GameData?.Name.RawString})");
} else {
ImGui.TextDisabled($"Preview displays based on {target.Name.TextValue} (NPC)");
Expand All @@ -867,16 +867,16 @@ private unsafe void DrawCharacterView(CharacterConfig? characterConfig) {
Plugin.RequestUpdateAll();
}
} else {
var player = PluginService.Objects.FirstOrDefault(t => t is PlayerCharacter playerCharacter && playerCharacter.Name.TextValue == selectedName && playerCharacter.HomeWorld.Id == selectedWorld);
if (player is PlayerCharacter) {
var player = PluginService.Objects.FirstOrDefault(t => t is IPlayerCharacter playerCharacter && playerCharacter.Name.TextValue == selectedName && playerCharacter.HomeWorld.Id == selectedWorld);
if (player is IPlayerCharacter) {
activeCharacter = (GameObject*)player.Address;
activeCharacterAsCharacter = (Character*)activeCharacter;
activeHeelConfig = characterConfig.GetFirstMatch(activeCharacterAsCharacter);
Plugin.NeedsUpdate[activeCharacter->ObjectIndex] = true;
}
}

if (activeCharacter != null && Plugin.IpcAssignedData.TryGetValue(activeCharacter->ObjectID, out var ipcCharacterConfig)) {
if (activeCharacter != null && Plugin.IpcAssignedData.TryGetValue(activeCharacter->EntityId, out var ipcCharacterConfig)) {
characterConfig = ipcCharacterConfig;
}

Expand All @@ -885,7 +885,7 @@ private unsafe void DrawCharacterView(CharacterConfig? characterConfig) {
if (Plugin.IsDebug && activeCharacter != null) {
ImGui.SameLine();
if (ImGui.SmallButton("Clear IPC")) {
Plugin.IpcAssignedData.Remove(activeCharacter->ObjectID);
Plugin.IpcAssignedData.Remove(activeCharacter->EntityId);
selectedCharacter = null;
selectedWorld = 0;
selectedName = string.Empty;
Expand Down Expand Up @@ -1688,7 +1688,7 @@ void ShowAddPathButton(string? path, ModelSlot slot) {

if (Plugin.IsDebug) {
if (characterConfig is IpcCharacterConfig ipcCharacter && ImGui.TreeNode("IPC Data")) {
if (ipcCharacter.EmotePosition != null && activeCharacterAsCharacter->Mode is Character.CharacterModes.EmoteLoop or Character.CharacterModes.InPositionLoop) {
if (ipcCharacter.EmotePosition != null && activeCharacterAsCharacter->Mode is CharacterModes.EmoteLoop or CharacterModes.InPositionLoop) {
ImGui.Text("Position Error:");
var pos = (Vector3) activeCharacter->Position;
var emotePos = ipcCharacter.EmotePosition.GetOffset();
Expand Down
2 changes: 1 addition & 1 deletion EmoteIdentifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public uint Icon {

public static EmoteIdentifier? Get(Character* character) {
if (character == null) return null;
if (character->Mode is not (Character.CharacterModes.InPositionLoop or Character.CharacterModes.EmoteLoop)) return null;
if (character->Mode is not (CharacterModes.InPositionLoop or CharacterModes.EmoteLoop)) return null;
return new EmoteIdentifier(character->ModeParam, character->EmoteController.CPoseState);
}

Expand Down
20 changes: 9 additions & 11 deletions ExtraDebug.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Reflection;
using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing;
Expand Down Expand Up @@ -63,17 +61,17 @@ private void TabBaseOffsets() {

private Vector4[] minionPositions = new Vector4[Constants.ObjectLimit];
private void TabStaticMinions() {
foreach (var c in PluginService.Objects.Where(o => o is PlayerCharacter).Cast<PlayerCharacter>()) {
foreach (var c in PluginService.Objects.Where(o => o is IPlayerCharacter).Cast<IPlayerCharacter>()) {
if (c == null) continue;
var chr = (Character*)c.Address;
if (chr->Companion.CompanionObject == null) continue;
var companionId = chr->Companion.CompanionObject->Character.GameObject.DataID;
if (chr->CompanionData.CompanionObject == null) continue;
var companionId = chr->CompanionData.CompanionObject->Character.GameObject.BaseId;
var companion = PluginService.Data.GetExcelSheet<Companion>()?.GetRow(companionId);
if (companion == null) continue;
if (companion.Behavior.Row != 3) continue;
using (ImRaii.PushId($"chr_{c.ObjectId:X}")) {
using (ImRaii.PushId($"chr_{c.EntityId:X}")) {
ImGui.Separator();
var go = &chr->Companion.CompanionObject->Character.GameObject;
var go = &chr->CompanionData.CompanionObject->Character.GameObject;
if (minionPositions[go->ObjectIndex] == default) minionPositions[go->ObjectIndex] = new Vector4(go->Position, go->Rotation);
if (ImGui.DragFloat4($"{c.Name.TextValue}'s {companion.Singular.ToDalamudString().TextValue}", ref minionPositions[go->ObjectIndex], 0.01f)) {
go->DrawObject->Object.Position.X = minionPositions[go->ObjectIndex].X;
Expand All @@ -83,14 +81,14 @@ private void TabStaticMinions() {
}

ImGui.SameLine();
ImGui.Text($"{go->ObjectID:X}");
ImGui.Text($"{go->EntityId:X}");
}
}
}

private void TabObjects() {
foreach (var actor in PluginService.Objects) {
if (actor is not PlayerCharacter pc) continue;
if (actor is not IPlayerCharacter pc) continue;

if (ImGui.TreeNode($"[{actor.ObjectIndex} ({actor.GetType().Name})] {actor.ObjectKind}.{actor.SubKind} - {actor.Name}")) {
var obj = (Character*)pc.Address;
Expand All @@ -104,7 +102,7 @@ private void TabObjects() {
ImGui.Text($"Mode: {obj->Mode}");
ImGui.Text($"ModeParam: {obj->ModeParam}");

ImGui.Text($"Feet Model: {obj->DrawData.Feet.Id}");
ImGui.Text($"Feet Model: {obj->DrawData.Equipment(DrawDataContainer.EquipmentSlot.Feet).Id}");

ImGui.Text($"Draw Offset: {obj->GameObject.DrawOffset}");
ImGui.Text($"Height: {obj->GameObject.Height}");
Expand Down
2 changes: 1 addition & 1 deletion ImGuiExt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static bool IconTextFrame(uint previewIcon, string previewText, bool hove
using (ImRaii.PushColor(ImGuiCol.FrameBg, ImGui.GetColorU32(ImGuiCol.FrameBgHovered), hoverColor && ImGui.IsMouseHoveringRect(pos, pos + frameSize))) {
if (ImGui.BeginChildFrame(ImGui.GetID($"iconTextFrame_{previewIcon}_{previewText}"), frameSize)) {
var dl = ImGui.GetWindowDrawList();
var icon = PluginService.TextureProvider.GetIcon(previewIcon);
var icon = PluginService.TextureProvider.GetFromGameIcon(previewIcon).GetWrapOrDefault();
if (icon != null) dl.AddImage(icon.ImGuiHandle, pos, pos + new Vector2(size.Y));
var textSize = ImGui.CalcTextSize(previewText);
dl.AddText(pos + new Vector2(size.Y + ImGui.GetStyle().FramePadding.X, size.Y / 2f - textSize.Y / 2f), ImGui.GetColorU32(ImGuiCol.Text), previewText);
Expand Down
8 changes: 4 additions & 4 deletions IpcCharacterConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class IpcCharacterConfig : CharacterConfig {
public string PluginVersion = string.Empty;


public unsafe IpcCharacterConfig(Plugin plugin, PlayerCharacter player) {
public unsafe IpcCharacterConfig(Plugin plugin, IPlayerCharacter player) {
if (player == null) throw new Exception("No Player");

if (plugin.TryGetCharacterConfig(player, out var characterConfig, false) && characterConfig != null) {
Expand All @@ -34,16 +34,16 @@ public unsafe IpcCharacterConfig(Plugin plugin, PlayerCharacter player) {
var chr = (Character*)player.Address;
if (Plugin.Config.ApplyStaticMinionPositions) {

if (chr->Companion.CompanionObject != null && Utils.StaticMinions.Value.Contains(chr->Companion.CompanionObject->Character.GameObject.DataID)) {
var drawObj = chr->Companion.CompanionObject->Character.GameObject.DrawObject;
if (chr->CompanionData.CompanionObject != null && Utils.StaticMinions.Value.Contains(chr->CompanionData.CompanionObject->Character.GameObject.BaseId)) {
var drawObj = chr->CompanionData.CompanionObject->Character.GameObject.DrawObject;
if (drawObj != null) {
var p = drawObj->Object.Position;
MinionPosition = new TempOffset(p.X, p.Y, p.Z, drawObj->Object.Rotation.EulerAngles.Y * MathF.PI / 180f);
}
}
}

if (chr->Mode is Character.CharacterModes.EmoteLoop or Character.CharacterModes.InPositionLoop) {
if (chr->Mode is CharacterModes.EmoteLoop or CharacterModes.InPositionLoop) {
// Precise Positioning
var p = chr->GameObject.Position;
EmotePosition = new TempOffset(p.X, p.Y, p.Z, chr->GameObject.Rotation);
Expand Down
Loading

0 comments on commit 5edb83f

Please sign in to comment.