This commit is contained in:
goat 2020-08-03 19:49:51 +02:00
commit 74d9e25c39
8 changed files with 143 additions and 56 deletions

View file

@ -169,12 +169,9 @@ namespace Dalamud.Injector {
var ffxivDir = Path.GetDirectoryName(process.MainModule.FileName); var ffxivDir = Path.GetDirectoryName(process.MainModule.FileName);
var startInfo = new DalamudStartInfo { var startInfo = new DalamudStartInfo {
WorkingDirectory = null, WorkingDirectory = null,
ConfigurationPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + ConfigurationPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "XIVLauncher", "dalamudConfig.json"),
@"\XIVLauncher\dalamudConfig.json", PluginDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "XIVLauncher", "installedPlugins"),
PluginDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + DefaultPluginDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "XIVLauncher", "devPlugins"),
@"\XIVLauncher\installedPlugins",
DefaultPluginDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
@"\XIVLauncher\devPlugins",
GameVersion = File.ReadAllText(Path.Combine(ffxivDir, "ffxivgame.ver")), GameVersion = File.ReadAllText(Path.Combine(ffxivDir, "ffxivgame.ver")),
Language = ClientLanguage.English Language = ClientLanguage.English

View file

@ -5,6 +5,7 @@ using Dalamud.Configuration;
using Dalamud.DiscordBot; using Dalamud.DiscordBot;
using Dalamud.Game.Chat; using Dalamud.Game.Chat;
using Newtonsoft.Json; using Newtonsoft.Json;
using Serilog;
namespace Dalamud namespace Dalamud
{ {
@ -43,7 +44,17 @@ namespace Dalamud
public string ConfigPath; public string ConfigPath;
public static DalamudConfiguration Load(string path) { public static DalamudConfiguration Load(string path) {
var deserialized = JsonConvert.DeserializeObject<DalamudConfiguration>(File.ReadAllText(path)); DalamudConfiguration deserialized;
try
{
deserialized = JsonConvert.DeserializeObject<DalamudConfiguration>(File.ReadAllText(path));
}
catch (Exception ex)
{
Log.Warning(ex, "Failed to load DalamudConfiguration at {0}", path);
deserialized = new DalamudConfiguration();
}
deserialized.ConfigPath = path; deserialized.ConfigPath = path;
return deserialized; return deserialized;

View file

@ -424,12 +424,12 @@ namespace Dalamud {
CommandManager.AddHandler("/xldreloadplugins", new CommandInfo(OnPluginReloadCommand) { CommandManager.AddHandler("/xldreloadplugins", new CommandInfo(OnPluginReloadCommand) {
HelpMessage = Loc.Localize("DalamudPluginReloadHelp", "Reloads all plugins."), HelpMessage = Loc.Localize("DalamudPluginReloadHelp", "Reloads all plugins."),
ShowInHelp = false ShowInHelp = false
}); });
CommandManager.AddHandler("/xldsay", new CommandInfo(OnCommandDebugSay) { CommandManager.AddHandler("/xldsay", new CommandInfo(OnCommandDebugSay) {
HelpMessage = Loc.Localize("DalamudPrintChatHelp", "Print to chat."), HelpMessage = Loc.Localize("DalamudPrintChatHelp", "Print to chat."),
ShowInHelp = false ShowInHelp = false
}); });
CommandManager.AddHandler("/xlhelp", new CommandInfo(OnHelpCommand) { CommandManager.AddHandler("/xlhelp", new CommandInfo(OnHelpCommand) {
@ -456,57 +456,48 @@ namespace Dalamud {
HelpMessage = Loc.Localize("DalamudBotJoinHelp", "Add the XIVLauncher discord bot you set up to your server.") HelpMessage = Loc.Localize("DalamudBotJoinHelp", "Add the XIVLauncher discord bot you set up to your server.")
}); });
CommandManager.AddHandler("/xlbgmset", new CommandInfo(OnBgmSetCommand) CommandManager.AddHandler("/xlbgmset", new CommandInfo(OnBgmSetCommand) {
{
HelpMessage = Loc.Localize("DalamudBgmSetHelp", "Set the Game background music. Usage: /xlbgmset <BGM ID>") HelpMessage = Loc.Localize("DalamudBgmSetHelp", "Set the Game background music. Usage: /xlbgmset <BGM ID>")
}); });
#if DEBUG #if DEBUG
CommandManager.AddHandler("/xldzpi", new CommandInfo(OnDebugZoneDownInjectCommand) CommandManager.AddHandler("/xldzpi", new CommandInfo(OnDebugZoneDownInjectCommand) {
{
HelpMessage = "Inject zone down channel", HelpMessage = "Inject zone down channel",
ShowInHelp = false ShowInHelp = false
}); });
#endif #endif
CommandManager.AddHandler("/xlbonus", new CommandInfo(OnRouletteBonusNotifyCommand) CommandManager.AddHandler("/xlbonus", new CommandInfo(OnRouletteBonusNotifyCommand) {
{
HelpMessage = Loc.Localize("DalamudBonusHelp", "Notify when a roulette has a bonus you specified. Run without parameters for more info. Usage: /xlbonus <roulette name> <role name>") HelpMessage = Loc.Localize("DalamudBonusHelp", "Notify when a roulette has a bonus you specified. Run without parameters for more info. Usage: /xlbonus <roulette name> <role name>")
}); });
CommandManager.AddHandler("/xldev", new CommandInfo(OnDebugDrawDevMenu) { CommandManager.AddHandler("/xldev", new CommandInfo(OnDebugDrawDevMenu) {
HelpMessage = Loc.Localize("DalamudDevMenuHelp", "Draw dev menu DEBUG"), HelpMessage = Loc.Localize("DalamudDevMenuHelp", "Draw dev menu DEBUG"),
ShowInHelp = false ShowInHelp = false
}); });
CommandManager.AddHandler("/xlplugins", new CommandInfo(OnOpenInstallerCommand) CommandManager.AddHandler("/xlplugins", new CommandInfo(OnOpenInstallerCommand) {
{
HelpMessage = Loc.Localize("DalamudInstallerHelp", "Open the plugin installer") HelpMessage = Loc.Localize("DalamudInstallerHelp", "Open the plugin installer")
}); });
this.CommandManager.AddHandler("/xlcredits", new CommandInfo(OnOpenCreditsCommand) { CommandManager.AddHandler("/xlcredits", new CommandInfo(OnOpenCreditsCommand) {
HelpMessage = Loc.Localize("DalamudCreditsHelp", "Opens the credits for dalamud.") HelpMessage = Loc.Localize("DalamudCreditsHelp", "Opens the credits for dalamud.")
}); });
this.CommandManager.AddHandler("/xllanguage", new CommandInfo(OnSetLanguageCommand) CommandManager.AddHandler("/xllanguage", new CommandInfo(OnSetLanguageCommand) {
{
HelpMessage = Loc.Localize("DalamudLanguageHelp", "Set the language for the in-game addon and plugins that support it. Available languages: ") + Localization.ApplicableLangCodes.Aggregate("en", (current, code) => current + ", " + code) HelpMessage = Loc.Localize("DalamudLanguageHelp", "Set the language for the in-game addon and plugins that support it. Available languages: ") + Localization.ApplicableLangCodes.Aggregate("en", (current, code) => current + ", " + code)
}); });
this.CommandManager.AddHandler("/xlsettings", new CommandInfo(OnOpenSettingsCommand) CommandManager.AddHandler("/xlsettings", new CommandInfo(OnOpenSettingsCommand) {
{
HelpMessage = Loc.Localize("DalamudSettingsHelp", "Change various In-Game-Addon settings like chat channels and the discord bot setup.") HelpMessage = Loc.Localize("DalamudSettingsHelp", "Change various In-Game-Addon settings like chat channels and the discord bot setup.")
}); });
this.CommandManager.AddHandler("/xlbugreport", new CommandInfo(OnBugReportCommand) CommandManager.AddHandler("/xlbugreport", new CommandInfo(OnBugReportCommand) {
{
HelpMessage = Loc.Localize("DalamudBugReport", "Upload a log to be analyzed by our professional development team."), HelpMessage = Loc.Localize("DalamudBugReport", "Upload a log to be analyzed by our professional development team."),
ShowInHelp = false ShowInHelp = false
}); });
CommandManager.AddHandler("/imdebug", new CommandInfo(OnDebugImInfoCommand) {
this.CommandManager.AddHandler("/imdebug", new CommandInfo(OnDebugImInfoCommand)
{
HelpMessage = "ImGui DEBUG", HelpMessage = "ImGui DEBUG",
ShowInHelp = false ShowInHelp = false
}); });
@ -671,7 +662,7 @@ namespace Dalamud {
} }
private void OnDebugDrawDevMenu(string command, string arguments) { private void OnDebugDrawDevMenu(string command, string arguments) {
this.isImguiDrawDevMenu = true; this.isImguiDrawDevMenu = !this.isImguiDrawDevMenu;
} }
private void OnDebugImInfoCommand(string command, string arguments) { private void OnDebugImInfoCommand(string command, string arguments) {

View file

@ -77,7 +77,7 @@ namespace Dalamud.Game.ClientState.Actors {
get => ActorsCache[index]; get => ActorsCache[index];
} }
private Actor ReadActorFromMemory(IntPtr offset) internal Actor ReadActorFromMemory(IntPtr offset)
{ {
try { try {
// FIXME: hack workaround for trying to access the player on logout, after the main object has been deleted // FIXME: hack workaround for trying to access the player on logout, after the main object has been deleted

View file

@ -0,0 +1,48 @@
using System;
using System.Runtime.InteropServices;
using Dalamud.Game.ClientState.Actors.Types;
namespace Dalamud.Game.ClientState.Actors {
public static class TargetOffsets {
public const int CurrentTarget = 0x80;
public const int MouseOverTarget = 0xD0;
public const int FocusTarget = 0xF8;
public const int PreviousTarget = 0x110;
}
public sealed class Targets {
private ClientStateAddressResolver Address { get; }
private Dalamud dalamud;
public Actor CurrentTarget => GetActorByOffset(TargetOffsets.CurrentTarget);
public Actor MouseOverTarget => GetActorByOffset(TargetOffsets.MouseOverTarget);
public Actor FocusTarget => GetActorByOffset(TargetOffsets.FocusTarget);
public Actor PreviousTarget => GetActorByOffset(TargetOffsets.PreviousTarget);
internal Targets(Dalamud dalamud, ClientStateAddressResolver addressResolver) {
this.dalamud = dalamud;
Address = addressResolver;
}
public void SetCurrentTarget(Actor actor) => SetTarget(actor?.Address ?? IntPtr.Zero, TargetOffsets.CurrentTarget);
public void SetCurrentTarget(IntPtr actorAddress) => SetTarget(actorAddress, TargetOffsets.CurrentTarget);
public void SetFocusTarget(Actor actor) => SetTarget(actor?.Address ?? IntPtr.Zero, TargetOffsets.FocusTarget);
public void SetFocusTarget(IntPtr actorAddress) => SetTarget(actorAddress, TargetOffsets.FocusTarget);
public void ClearCurrentTarget() => SetCurrentTarget(IntPtr.Zero);
public void ClearFocusTarget() => SetFocusTarget(IntPtr.Zero);
private void SetTarget(IntPtr actorAddress, int offset) {
if (Address.TargetManager == IntPtr.Zero) return;
Marshal.WriteIntPtr(Address.TargetManager, offset, actorAddress);
}
private Actor GetActorByOffset(int offset) {
if (Address.TargetManager == IntPtr.Zero) return null;
var actorAddress = Marshal.ReadIntPtr(Address.TargetManager + offset);
if (actorAddress == IntPtr.Zero) return null;
return this.dalamud.ClientState.Actors.ReadActorFromMemory(actorAddress);
}
}
}

View file

@ -97,6 +97,11 @@ namespace Dalamud.Game.ClientState
/// </summary> /// </summary>
public Condition Condition; public Condition Condition;
/// <summary>
/// The class facilitating target data access
/// </summary>
public Targets Targets;
/// <summary> /// <summary>
/// Set up client state access. /// Set up client state access.
/// </summary> /// </summary>
@ -121,6 +126,8 @@ namespace Dalamud.Game.ClientState
this.Condition = new Condition( Address ); this.Condition = new Condition( Address );
this.Targets = new Targets(dalamud, Address);
Log.Verbose("SetupTerritoryType address {SetupTerritoryType}", Address.SetupTerritoryType); Log.Verbose("SetupTerritoryType address {SetupTerritoryType}", Address.SetupTerritoryType);
this.setupTerritoryTypeHook = new Hook<SetupTerritoryTypeDelegate>(Address.SetupTerritoryType, this.setupTerritoryTypeHook = new Hook<SetupTerritoryTypeDelegate>(Address.SetupTerritoryType,

View file

@ -10,6 +10,7 @@ namespace Dalamud.Game.ClientState
public IntPtr LocalContentId { get; private set; } public IntPtr LocalContentId { get; private set; }
public IntPtr JobGaugeData { get; private set; } public IntPtr JobGaugeData { get; private set; }
public IntPtr KeyboardState { get; private set; } public IntPtr KeyboardState { get; private set; }
public IntPtr TargetManager { get; private set; }
// Functions // Functions
public IntPtr SetupTerritoryType { get; private set; } public IntPtr SetupTerritoryType { get; private set; }
@ -35,6 +36,8 @@ namespace Dalamud.Game.ClientState
PartyListUpdate = sig.ScanText("E8 ?? ?? ?? ?? 49 8B D4 4C 8D 87 ?? ?? ?? ??"); PartyListUpdate = sig.ScanText("E8 ?? ?? ?? ?? 49 8B D4 4C 8D 87 ?? ?? ?? ??");
ConditionFlags = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? BA ?? ?? ?? ?? 45 33 C0"); ConditionFlags = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? BA ?? ?? ?? ?? 45 33 C0");
TargetManager = sig.GetStaticAddressFromSig("48 8B 05 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? FF 50 ?? 48 85 DB", 3);
} }
} }
} }

View file

@ -8,48 +8,78 @@ using Dalamud.Game.ClientState.Actors;
namespace Dalamud.Game.ClientState.Structs namespace Dalamud.Game.ClientState.Structs
{ {
public class ActorOffsets
{
public const int Name = 0x30;
public const int ActorId = 116;
public const int DataId = 128;
public const int OwnerId = 132;
public const int ObjectKind = 140;
public const int SubKind = 141;
public const int IsFriendly = 142;
public const int YalmDistanceFromPlayerX = 144;
public const int PlayerTargetStatus = 145;
public const int YalmDistanceFromPlayerY = 146;
public const int Position = 160;
public const int Rotation = 176;
public const int Customize = 0x17B8;
public const int PlayerCharacterTargetActorId = 0x1F0;
public const int BattleNpcTargetActorId = 0x17F8;
public const int CompanyTag = 0x17D0;
public const int NameId = 0x1868;
public const int CurrentWorld = 0x1884;
public const int HomeWorld = 0x1886;
public const int CurrentHp = 0x1898;
public const int MaxHp = 0x189C;
public const int CurrentMp = 0x18A0;
public const int MaxMp = 0x18AA;
public const int ClassJob = 6358;
public const int Level = 6360;
public const int UIStatusEffects = 0x1958;
}
/// <summary> /// <summary>
/// Native memory representation of a FFXIV actor. /// Native memory representation of a FFXIV actor.
/// </summary> /// </summary>
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct Actor { public struct Actor {
[FieldOffset(0x30)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)] [FieldOffset(ActorOffsets.Name)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)]
public string Name; public string Name;
[FieldOffset(116)] public int ActorId; [FieldOffset(ActorOffsets.ActorId)] public int ActorId;
[FieldOffset(128)] public int DataId; [FieldOffset(ActorOffsets.DataId)] public int DataId;
[FieldOffset(132)] public int OwnerId; [FieldOffset(ActorOffsets.OwnerId)] public int OwnerId;
[FieldOffset(140)] public ObjectKind ObjectKind; [FieldOffset(ActorOffsets.ObjectKind)] public ObjectKind ObjectKind;
[FieldOffset(141)] public byte SubKind; [FieldOffset(ActorOffsets.SubKind)] public byte SubKind;
[FieldOffset(142)] public bool IsFriendly; [FieldOffset(ActorOffsets.IsFriendly)] public bool IsFriendly;
[FieldOffset(144)] public byte YalmDistanceFromPlayerX; // Demo says one of these is x distance [FieldOffset(ActorOffsets.YalmDistanceFromPlayerX)] public byte YalmDistanceFromPlayerX; // Demo says one of these is x distance
[FieldOffset(145)] public byte PlayerTargetStatus; // This is some kind of enum [FieldOffset(ActorOffsets.PlayerTargetStatus)] public byte PlayerTargetStatus; // This is some kind of enum
[FieldOffset(146)] public byte YalmDistanceFromPlayerY; // and the other is z distance [FieldOffset(ActorOffsets.YalmDistanceFromPlayerY)] public byte YalmDistanceFromPlayerY; // and the other is z distance
[FieldOffset(160)] public Position3 Position; [FieldOffset(ActorOffsets.Position)] public Position3 Position;
[FieldOffset(176)] public float Rotation; // Rotation around the vertical axis (yaw), from -pi to pi radians [FieldOffset(ActorOffsets.Rotation)] public float Rotation; // Rotation around the vertical axis (yaw), from -pi to pi radians
[FieldOffset(0x17B8)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)] public byte[] Customize; [FieldOffset(ActorOffsets.Customize)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)] public byte[] Customize;
[FieldOffset(0x1F0)] public int PlayerCharacterTargetActorId; [FieldOffset(ActorOffsets.PlayerCharacterTargetActorId)] public int PlayerCharacterTargetActorId;
[FieldOffset(0x17F8)] public int BattleNpcTargetActorId; [FieldOffset(ActorOffsets.BattleNpcTargetActorId)] public int BattleNpcTargetActorId;
// This field can't be correctly aligned, so we have to cut it manually. // This field can't be correctly aligned, so we have to cut it manually.
[FieldOffset(0x17d0)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] [FieldOffset(ActorOffsets.CompanyTag)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
public byte[] CompanyTag; public byte[] CompanyTag;
[FieldOffset(0x1868)] public int NameId; [FieldOffset(ActorOffsets.NameId)] public int NameId;
[FieldOffset(0x1884)] public byte CurrentWorld; [FieldOffset(ActorOffsets.CurrentWorld)] public byte CurrentWorld;
[FieldOffset(0x1886)] public byte HomeWorld; [FieldOffset(ActorOffsets.HomeWorld)] public byte HomeWorld;
[FieldOffset(0x1898)] public int CurrentHp; [FieldOffset(ActorOffsets.CurrentHp)] public int CurrentHp;
[FieldOffset(0x189C)] public int MaxHp; [FieldOffset(ActorOffsets.MaxHp)] public int MaxHp;
[FieldOffset(0x18A0)] public int CurrentMp; [FieldOffset(ActorOffsets.CurrentMp)] public int CurrentMp;
// This value is weird. It seems to change semi-randomly between 0 and 10k, definitely // This value is weird. It seems to change semi-randomly between 0 and 10k, definitely
// in response to mp-using events, but it doesn't often have a value and the changing seems // in response to mp-using events, but it doesn't often have a value and the changing seems
// somewhat arbitrary. // somewhat arbitrary.
[FieldOffset(0x18AA)] public int MaxMp; [FieldOffset(ActorOffsets.MaxMp)] public int MaxMp;
[FieldOffset(6358)] public byte ClassJob; [FieldOffset(ActorOffsets.ClassJob)] public byte ClassJob;
[FieldOffset(6360)] public byte Level; [FieldOffset(ActorOffsets.Level)] public byte Level;
[FieldOffset(0x1958)][MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public StatusEffect[] UIStatusEffects; [FieldOffset(ActorOffsets.UIStatusEffects)][MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public StatusEffect[] UIStatusEffects;
} }
} }