Skip to content

Commit

Permalink
mount & fly to autofollow
Browse files Browse the repository at this point in the history
  • Loading branch information
Jaksuhn committed Jan 10, 2024
1 parent 0438706 commit aa9f36d
Show file tree
Hide file tree
Showing 9 changed files with 268 additions and 558 deletions.
48 changes: 44 additions & 4 deletions Automaton/Features/Actions/AutoFollow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Interface.Components;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using Dalamud.Game.ClientState.Conditions;

namespace Automaton.Features.Actions
{
Expand All @@ -27,24 +29,29 @@ public unsafe class AutoFollow : Feature
public Configs Config { get; private set; }
public class Configs : FeatureConfig
{
[FeatureConfigOption("Distance to Keep", "", 1, IntMin = 0, IntMax = 30, EditorSize = 300)]
[FeatureConfigOption("Distance to Keep", "", 1)]
public int distanceToKeep = 3;

[FeatureConfigOption("Don't follow if further than this (yalms)", "", 2, IntMin = 0, IntMax = 30, EditorSize = 300, HelpText = "Set to 0 to disable")]
public int disableIfFurtherThan = 0;

[FeatureConfigOption("Function only in duty", "", 3, IntMin = 0, IntMax = 30, EditorSize = 300)]
[FeatureConfigOption("Function only in duty", "", 3)]
public bool OnlyInDuty = false;

[FeatureConfigOption("Change master on chat message", "", 3, IntMin = 0, IntMax = 30, EditorSize = 300, HelpText = "If a party chat message contains \"autofollow\", the current master will be switched to them.")]
[FeatureConfigOption("Change master on chat message", "", 4, IntMin = 0, IntMax = 30, EditorSize = 300, HelpText = "If a party chat message contains \"autofollow\", the current master will be switched to them.")]
public bool changeMasterOnChat = false;

[FeatureConfigOption("Mount & Fly (Experimental)", "", 5)]
public bool MountAndFly = true;
}

protected override DrawConfigDelegate DrawConfigTree => (ref bool hasChanged) =>
{
if (ImGui.Checkbox("Function Only in Duty", ref Config.OnlyInDuty)) hasChanged = true;
if (ImGui.Checkbox("Change master on chat message", ref Config.changeMasterOnChat)) hasChanged = true;
ImGuiComponents.HelpMarker("If a party chat message contains \"autofollow\", the current master will be switched to them.");
if (ImGui.Checkbox("Mount & Fly", ref Config.MountAndFly)) hasChanged = true;

ImGui.PushItemWidth(300);
if (ImGui.SliderInt("Distance to Keep (yalms)", ref Config.distanceToKeep, 0, 30)) hasChanged = true;
ImGui.PushItemWidth(300);
Expand Down Expand Up @@ -148,14 +155,47 @@ private void Follow(IFramework framework)
master = Svc.Objects.FirstOrDefault(x => x.ObjectId == masterObjectID);

if (master == null) { movement.Enabled = false; return; }
if (Vector3.Distance(Svc.ClientState.LocalPlayer.Position, master.Position) <= Config.distanceToKeep) { movement.Enabled = false; return; }
if (Config.disableIfFurtherThan > 0 && Vector3.Distance(Svc.ClientState.LocalPlayer.Position, master.Position) > Config.disableIfFurtherThan) { movement.Enabled = false; return; }
if (Config.OnlyInDuty && GameMain.Instance()->CurrentContentFinderConditionId == 0) { movement.Enabled = false; return; }
if (Svc.Condition[ConditionFlag.InFlight]) { TaskManager.Abort(); }

if (master.ObjectKind == Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player)
{
if (((Character*)master.Address)->IsMounted() && CanMount())
{
movement.Enabled = false;
ActionManager.Instance()->UseAction(ActionType.GeneralAction, 9);
return;
}

if (Config.MountAndFly && ((Structs.Character*)master.Address)->IsFlying != 0 && !Svc.Condition[ConditionFlag.InFlight] && Svc.Condition[ConditionFlag.Mounted])
{
movement.Enabled = false;
TaskManager.Enqueue(() => ActionManager.Instance()->UseAction(ActionType.GeneralAction, 2));
TaskManager.DelayNext(50);
TaskManager.Enqueue(() => ActionManager.Instance()->UseAction(ActionType.GeneralAction, 2));
return;
}

if (!((Character*)master.Address)->IsMounted() && Svc.Condition[ConditionFlag.Mounted])
{
movement.Enabled = false;
((BattleChara*)master.Address)->GetStatusManager->RemoveStatus(10);
ActionManager.Instance()->UseAction(ActionType.GeneralAction, 9);
return;
}
}

// set dismount logic here

if (Vector3.Distance(Svc.ClientState.LocalPlayer.Position, master.Position) <= Config.distanceToKeep) { movement.Enabled = false; return; }

movement.Enabled = true;
movement.DesiredPosition = master.Position;
}

private static bool CanMount() => !Svc.Condition[ConditionFlag.Mounted] && !Svc.Condition[ConditionFlag.Mounting] && !Svc.Condition[ConditionFlag.InCombat] && !Svc.Condition[ConditionFlag.Casting];

private void OnChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled)
{
if (type != XivChatType.Party) return;
Expand Down
47 changes: 47 additions & 0 deletions Automaton/Features/Commands/ClickToTP.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using ECommons.DalamudServices;
using Automaton.FeaturesSetup;
using System.Collections.Generic;
using Automaton.Features.Debugging;
using ImGuiNET;

namespace Automaton.Features.Commands
{
public unsafe class ClickToTP : CommandFeature
{
public override string Name => "Click to TP";
public override string Command { get; set; } = "/tpclick";
public override string[] Alias => new string[] { "/tpc" };
public override string Description => "";
public override List<string> Parameters => new() { "" };
public override bool isDebug => true;

public override FeatureType FeatureType => FeatureType.Disabled;

private bool active;

protected override void OnCommand(List<string> args)
{
if (!active)
{
active = true;
Svc.Framework.Update += ModifyPOS;
Svc.Log.Info($"Enabling {nameof(ClickToTP)}");
}
else
{
active = false;
Svc.Framework.Update -= ModifyPOS;
Svc.Log.Info($"Disabling {nameof(ClickToTP)}");
}

}

private void ModifyPOS(IFramework framework)
{
if (!active) return;

if (ImGui.IsMouseClicked(ImGuiMouseButton.Left))
PositionDebug.SetPosToMouse();
}
}
}
31 changes: 16 additions & 15 deletions Automaton/Features/Commands/Telewalk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
using System.Collections.Generic;
using System.Numerics;
using System;
using static Automaton.Helpers.Structs;
using FFXIVClientStructs.FFXIV.Client.Game.Control;
using Automaton.Features.Debugging;
using Automaton.Helpers;

namespace Automaton.Features.Commands
{
Expand All @@ -15,7 +15,7 @@ public unsafe class Telewalk : CommandFeature
public override string Name => "Telewalk";
public override string Command { get; set; } = "/telewalk";
public override string[] Alias => new string[] { "/tw" };
public override string Description => "";
public override string Description => "Replaces regular movement with teleporting. Works relative to your camera facing like normal movement.";
public override List<string> Parameters => new() { "<displacement factor>" };
public override bool isDebug => true;

Expand All @@ -27,6 +27,7 @@ public unsafe class Telewalk : CommandFeature
protected override void OnCommand(List<string> args)
{
float.TryParse(args[0], out displacementFactor);
displacementFactor = displacementFactor == 0 ? 0.10f : displacementFactor;
if (!active)
{
active = true;
Expand All @@ -45,27 +46,27 @@ private void ModifyPOS(IFramework framework)
{
if (!active) return;

var camera = (CameraEx*)CameraManager.Instance()->GetActiveCamera();
var camera = (Structs.CameraEx*)CameraManager.Instance()->GetActiveCamera();
var xDisp = -Math.Sin(camera->DirH);
var zDisp = -Math.Cos(camera->DirH);
var yDisp = Math.Sin(camera->DirV);

if (Svc.ClientState.LocalPlayer != null)
{
var curPos = Svc.ClientState.LocalPlayer.Position;
var newPos = Vector3.Multiply(displacementFactor, new Vector3((float)xDisp, (float)yDisp, (float)zDisp));
if (Svc.KeyState[VirtualKey.W])
{
Svc.Log.Info("telewalking forwards");
PositionDebug.SetPos(curPos + newPos);
}
//if (Svc.KeyState[VirtualKey.SPACE])
//{
// if (!Svc.KeyState[VirtualKey.SHIFT])
// PositionDebug.SetPos(curPos + new Vector3(0, Svc.ClientState.LocalPlayer.Position.Y * displacementFactor, 0));
// else
// PositionDebug.SetPos(curPos + new Vector3(0, Svc.ClientState.LocalPlayer.Position.Y * -displacementFactor, 0));
//}
PositionDebug.SetPos(curPos + Vector3.Multiply(displacementFactor, new Vector3((float)xDisp, 0, (float)zDisp)));
if (Svc.KeyState[VirtualKey.A])
PositionDebug.SetPos(curPos + Vector3.Multiply(displacementFactor, new Vector3((float)xDisp, 0, (float)zDisp)));
if (Svc.KeyState[VirtualKey.S])
PositionDebug.SetPos(curPos + Vector3.Multiply(displacementFactor, new Vector3((float)xDisp, 0, (float)zDisp)));
if (Svc.KeyState[VirtualKey.D])
PositionDebug.SetPos(curPos + -Vector3.Multiply(displacementFactor, new Vector3(-(float)xDisp, 0, -(float)zDisp)));

if (Svc.KeyState[VirtualKey.SPACE] && !Svc.KeyState[VirtualKey.LSHIFT])
PositionDebug.SetPos(curPos + new Vector3(0, displacementFactor, 0));
if (Svc.KeyState[VirtualKey.SPACE] && Svc.KeyState[VirtualKey.LSHIFT])
PositionDebug.SetPos(curPos + new Vector3(0, -displacementFactor, 0));
}
}
}
Expand Down
146 changes: 146 additions & 0 deletions Automaton/Features/Debugging/HousingDebug.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
using Automaton.Debugging;
using ImGuiNET;
using ECommons.DalamudServices;
using Dalamud.Game;
using System;
using static Automaton.Features.Debugging.HousingDebug;

namespace Automaton.Features.Debugging;

public unsafe class HousingDebug : DebugHelper
{
public override string Name => $"{nameof(HousingDebug).Replace("Debug", "")} Debugging";

public const string PositionInfo = "40 ?? 48 83 ?? ?? 33 DB 48 39 ?? ?? ?? ?? ?? 75 ?? 45";

public override void Draw()
{
ImGui.Text($"{Name}");
ImGui.Separator();

var pia = new PositionInfoAddress(Svc.SigScanner);
ImGui.Text($"District: {pia.Zone}");
ImGui.Text($"Ward: {pia.Ward}");
ImGui.Text($"House: {pia.House}");
ImGui.Text($"Subdivision: {pia.Subdivision}");
ImGui.Text($"Plot: {pia.Plot}");
ImGui.Text($"Floor: {pia.Floor}");
}

public enum HousingZone : byte
{
Unknown = 0,
Mist = 83,
Goblet = 85,
LavenderBeds = 84,
Shirogane = 129,
Firmament = 211,
}

public enum Floor : byte
{
Unknown = 0xFF,
Ground = 0,
First = 1,
Cellar = 0x0A,
}

public class SeAddressBase
{
public readonly IntPtr Address;

public SeAddressBase(ISigScanner sigScanner, string signature, int offset = 0)
{
Address = sigScanner.GetStaticAddressFromSig(signature);
if (Address != IntPtr.Zero)
Address += offset;
var baseOffset = (ulong)Address.ToInt64() - (ulong)sigScanner.Module.BaseAddress.ToInt64();
Svc.Log.Debug($"{GetType().Name} address 0x{Address.ToInt64():X16}, baseOffset 0x{baseOffset:X16}.");
}
}

public sealed class PositionInfoAddress(ISigScanner sigScanner) : SeAddressBase(sigScanner, "40 ?? 48 83 ?? ?? 33 DB 48 39 ?? ?? ?? ?? ?? 75 ?? 45")
{
private readonly unsafe struct PositionInfo
{
private readonly byte* address;

private PositionInfo(byte* address)
=> this.address = address;

public static implicit operator PositionInfo(IntPtr ptr)
=> new((byte*)ptr);

public static implicit operator PositionInfo(byte* ptr)
=> new(ptr);

public static implicit operator bool(PositionInfo ptr)
=> ptr.address != null;

public ushort House
=> (ushort)(address == null || !InHouse ? 0 : *(ushort*)(address + 0x96A0) + 1);

public ushort Ward
=> (ushort)(address == null ? 0 : *(ushort*)(address + 0x96A2) + 1);

public bool Subdivision
=> address != null && *(address + 0x96A9) == 2;

public HousingZone Zone
=> address == null ? HousingZone.Unknown : *(HousingZone*)(address + 0x96A4);

public byte Plot
=> (byte)(address == null || InHouse ? 0 : *(address + 0x96A8) + 1);

public Floor Floor
=> address == null ? Floor.Unknown : *(Floor*)(address + 0x9704);

private bool InHouse
=> *(address + 0x96A9) == 0;
}

private unsafe PositionInfo Info
{
get
{
var intermediate = *(byte***)Address;
return intermediate == null ? null : *intermediate;
}
}

public ushort Ward
=> Info.Ward;

public HousingZone Zone
=> Info.Zone;

public ushort House
=> Info.House;

public bool Subdivision
=> Info.Subdivision;

public byte Plot
=> Info.Plot;

public Floor Floor
=> Info.Floor;
}
}

public static class HousingZoneExtensions
{
public static string ToName(this HousingZone z)
{
return z switch
{
HousingZone.Unknown => "Unknown",
HousingZone.Mist => "Mist",
HousingZone.Goblet => "The Goblet",
HousingZone.LavenderBeds => "Lavender Beds",
HousingZone.Shirogane => "Shirogane",
HousingZone.Firmament => "Firmament",
_ => throw new ArgumentOutOfRangeException(nameof(z), z, null)
};
}
}
2 changes: 2 additions & 0 deletions Automaton/Features/Debugging/IslandDebug.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ public override void Draw()
ImGui.Text($"{Name}");
ImGui.Separator();

ImGui.Text($"OnIsland State: {MJIManager.Instance()->IsPlayerInSanctuary}");
ImGui.Text($"Current Rank: {MJIManager.Instance()->IslandState.CurrentRank}");
ImGui.Text($"Total Farm Slots: {MJIManager.Instance()->GetFarmSlotCount()}");
ImGui.Text($"Total Pasture Slots: {MJIManager.Instance()->GetPastureSlotCount()}");
ImGui.Text($"Current Mode: {MJIManager.Instance()->CurrentMode}");

ImGui.Separator();

Expand Down
10 changes: 7 additions & 3 deletions Automaton/Features/Debugging/PositionDebug.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,19 @@ public override void Draw()
var targetPos = Svc.Targets.Target != null ? Svc.Targets.Target.Position : Svc.Targets.PreviousTarget.Position;
var str = Svc.Targets.Target != null ? "Target" : "Last Target";

ImGui.Text($"{str} Position: x: {targetPos.X:f3}, y: {targetPos.Y:f3}, z: {targetPos.Z:f3}");
ImGui.Text($"{str} Position: {targetPos:f3}");
if (ImGui.Button($"TP to {str}")) SetPos(targetPos);
ImGui.Text($"Distance to {str}: {Vector3.Distance(Svc.ClientState.LocalPlayer.Position, targetPos)}");

try
{
ImGui.Text($"IsFlying: {((Character*)Svc.Targets.Target.Address)->IsFlying}");
}
catch { }
ImGui.Separator();
}

Svc.GameGui.ScreenToWorld(ImGui.GetIO().MousePos, out var pos, 100000f);
ImGui.Text($"Mouse Position: x: {pos.X:f3}, y: {pos.Y:f3}, z: {pos.Z:f3}");
ImGui.Text($"Mouse Position: {pos:f3}");

ImGui.Separator();

Expand Down
Loading

0 comments on commit aa9f36d

Please sign in to comment.