Merge pull request #477 from daemitus/misc

This commit is contained in:
goaaats 2021-08-19 16:59:46 +02:00 committed by GitHub
commit 8d5d290656
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 279 additions and 324 deletions

View file

@ -64,6 +64,21 @@ dotnet_style_predefined_type_for_member_access = true:suggestion
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
dotnet_style_parentheses_in_other_operators=always_for_clarity:silent
dotnet_style_object_initializer = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_empty_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_before_open_square_brackets = false
csharp_space_before_comma = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_comma = true
csharp_space_after_cast = false
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = none
csharp_space_between_square_brackets = false
# ReSharper properties
resharper_align_linq_query = true

View file

@ -61,8 +61,6 @@ namespace Dalamud.Injector
var process = GetProcess(args.ElementAtOrDefault(1));
var startInfo = GetStartInfo(args.ElementAtOrDefault(2), process);
startInfo.WorkingDirectory = Directory.GetCurrentDirectory();
// This seems to help with the STATUS_INTERNAL_ERROR condition
Thread.Sleep(1000);
@ -245,7 +243,7 @@ namespace Dalamud.Injector
startInfo = new DalamudStartInfo
{
WorkingDirectory = null,
WorkingDirectory = Directory.GetCurrentDirectory(),
ConfigurationPath = Path.Combine(xivlauncherDir, "dalamudConfig.json"),
PluginDirectory = Path.Combine(xivlauncherDir, "installedPlugins"),
DefaultPluginDirectory = Path.Combine(xivlauncherDir, "devPlugins"),

View file

@ -35,9 +35,7 @@ namespace Dalamud
#region Internals
private readonly ManualResetEvent unloadSignal;
private readonly ManualResetEvent finishUnloadSignal;
private bool hasDisposedPlugins = false;
#endregion
@ -237,6 +235,7 @@ namespace Dalamud
// Initialize FFXIVClientStructs function resolver
FFXIVClientStructs.Resolver.Initialize();
Log.Information("[T1] FFXIVClientStructs initialized!");
}
catch (Exception ex)

View file

@ -9,47 +9,47 @@ namespace Dalamud
/// Struct containing information needed to initialize Dalamud.
/// </summary>
[Serializable]
public struct DalamudStartInfo
public record DalamudStartInfo
{
/// <summary>
/// The working directory of the XIVLauncher installations.
/// Gets the working directory of the XIVLauncher installations.
/// </summary>
public string WorkingDirectory;
public string WorkingDirectory { get; init; }
/// <summary>
/// The path to the configuration file.
/// Gets the path to the configuration file.
/// </summary>
public string ConfigurationPath;
public string ConfigurationPath { get; init; }
/// <summary>
/// The path to the directory for installed plugins.
/// Gets the path to the directory for installed plugins.
/// </summary>
public string PluginDirectory;
public string PluginDirectory { get; init; }
/// <summary>
/// The path to the directory for developer plugins.
/// Gets the path to the directory for developer plugins.
/// </summary>
public string DefaultPluginDirectory;
public string DefaultPluginDirectory { get; init; }
/// <summary>
/// The path to core Dalamud assets.
/// Gets the path to core Dalamud assets.
/// </summary>
public string AssetDirectory;
public string AssetDirectory { get; init; }
/// <summary>
/// The language of the game client.
/// Gets the language of the game client.
/// </summary>
public ClientLanguage Language;
public ClientLanguage Language { get; init; }
/// <summary>
/// The current game version code.
/// Gets the current game version code.
/// </summary>
[JsonConverter(typeof(GameVersionConverter))]
public GameVersion GameVersion;
public GameVersion GameVersion { get; init; }
/// <summary>
/// Whether or not market board information should be uploaded by default.
/// Gets a value indicating whether or not market board information should be uploaded by default.
/// </summary>
public bool OptOutMbCollection;
public bool OptOutMbCollection { get; init; }
}
}

View file

@ -31,21 +31,14 @@ namespace Dalamud.Game.Command
{
this.dalamud = dalamud;
switch (language)
this.currentLangCommandRegex = language switch
{
case ClientLanguage.Japanese:
this.currentLangCommandRegex = this.commandRegexJp;
break;
case ClientLanguage.English:
this.currentLangCommandRegex = this.commandRegexEn;
break;
case ClientLanguage.German:
this.currentLangCommandRegex = this.commandRegexDe;
break;
case ClientLanguage.French:
this.currentLangCommandRegex = this.commandRegexFr;
break;
}
ClientLanguage.Japanese => this.commandRegexJp,
ClientLanguage.English => this.commandRegexEn,
ClientLanguage.German => this.commandRegexDe,
ClientLanguage.French => this.commandRegexFr,
_ => this.currentLangCommandRegex,
};
dalamud.Framework.Gui.Chat.CheckMessageHandled += this.OnCheckMessageHandled;
}

View file

@ -1,63 +0,0 @@
using System;
using Dalamud.Memory;
namespace Dalamud.Game.Gui.Addons
{
/// <summary>
/// This class represents an in-game UI "Addon".
/// </summary>
public unsafe class Addon
{
/// <summary>
/// Initializes a new instance of the <see cref="Addon"/> class.
/// </summary>
/// <param name="address">The address of the addon.</param>
public Addon(IntPtr address)
{
this.Address = address;
}
/// <summary>
/// Gets the address of the addon.
/// </summary>
public IntPtr Address { get; }
/// <summary>
/// Gets the name of the addon.
/// </summary>
public string Name => MemoryHelper.ReadString((IntPtr)this.Struct->Name, 0x20);
/// <summary>
/// Gets the X position of the addon on screen.
/// </summary>
public short X => this.Struct->X;
/// <summary>
/// Gets the Y position of the addon on screen.
/// </summary>
public short Y => this.Struct->Y;
/// <summary>
/// Gets the scale of the addon.
/// </summary>
public float Scale => this.Struct->Scale;
/// <summary>
/// Gets the width of the addon. This may include non-visible parts.
/// </summary>
public unsafe float Width => this.Struct->RootNode->Width * this.Scale;
/// <summary>
/// Gets the height of the addon. This may include non-visible parts.
/// </summary>
public unsafe float Height => this.Struct->RootNode->Height * this.Scale;
/// <summary>
/// Gets a value indicating whether the addon is visible.
/// </summary>
public bool Visible => this.Struct->IsVisible;
private FFXIVClientStructs.FFXIV.Component.GUI.AtkUnitBase* Struct => (FFXIVClientStructs.FFXIV.Component.GUI.AtkUnitBase*)this.Address;
}
}

View file

@ -70,7 +70,7 @@ namespace Dalamud.Game.Gui.FlyText
/// </summary>
private delegate IntPtr CreateFlyTextDelegate(
IntPtr addonFlyText,
int kind,
FlyTextKind kind,
int val1,
int val2,
IntPtr text2,
@ -126,14 +126,14 @@ namespace Dalamud.Game.Gui.FlyText
public unsafe void AddFlyText(FlyTextKind kind, uint actorIndex, uint val1, uint val2, SeString text1, SeString text2, uint color, uint icon)
{
// Known valid flytext region within the atk arrays
int numIndex = 28;
int strIndex = 25;
uint numOffset = 147;
uint strOffset = 28;
var numIndex = 28;
var strIndex = 25;
var numOffset = 147u;
var strOffset = 28u;
// Get the UI module and flytext addon pointers
var ui = (UIModule*)this.Dalamud.Framework.Gui.GetUIModule();
var flytext = this.Dalamud.Framework.Gui.GetUiObjectByName("_FlyText", 1);
var flytext = this.Dalamud.Framework.Gui.GetAddonByName("_FlyText", 1);
if (ui == null || flytext == IntPtr.Zero)
return;
@ -195,7 +195,7 @@ namespace Dalamud.Game.Gui.FlyText
private IntPtr CreateFlyTextDetour(
IntPtr addonFlyText,
int kind,
FlyTextKind kind,
int val1,
int val2,
IntPtr text2,
@ -211,7 +211,7 @@ namespace Dalamud.Game.Gui.FlyText
var handled = false;
var tmpKind = (FlyTextKind)kind;
var tmpKind = kind;
var tmpVal1 = val1;
var tmpVal2 = val2;
var tmpText1 = MemoryHelper.ReadSeStringNullTerminated(text1);
@ -224,7 +224,7 @@ namespace Dalamud.Game.Gui.FlyText
var cmpText2 = tmpText2.ToString();
Log.Verbose($"[FlyText] Called with addonFlyText({addonFlyText.ToInt64():X}) " +
$"kind({((FlyTextKind)kind).ToString()}) val1({val1}) val2({val2}) " +
$"kind({kind}) val1({val1}) val2({val2}) " +
$"text1({text1.ToInt64():X}, \"{tmpText1}\") text2({text2.ToInt64():X}, \"{tmpText2}\") " +
$"color({color:X}) icon({icon}) yOffset({yOffset})");
Log.Verbose("[FlyText] Calling flytext events!");
@ -250,14 +250,14 @@ namespace Dalamud.Game.Gui.FlyText
}
// Check if any values have changed
var dirty = tmpKind != (FlyTextKind)kind ||
tmpVal1 != val1 ||
tmpVal2 != val2 ||
tmpText1.ToString() != cmpText1 ||
tmpText2.ToString() != cmpText2 ||
tmpColor != color ||
tmpIcon != icon ||
Math.Abs(tmpYOffset - yOffset) > float.Epsilon;
var dirty = tmpKind != kind ||
tmpVal1 != val1 ||
tmpVal2 != val2 ||
tmpText1.ToString() != cmpText1 ||
tmpText2.ToString() != cmpText2 ||
tmpColor != color ||
tmpIcon != icon ||
Math.Abs(tmpYOffset - yOffset) > float.Epsilon;
// If not dirty, make the original call
if (!dirty)
@ -276,7 +276,7 @@ namespace Dalamud.Game.Gui.FlyText
retVal = this.createFlyTextHook.Original(
addonFlyText,
(int)tmpKind,
tmpKind,
tmpVal1,
tmpVal2,
pText2,

View file

@ -4,7 +4,7 @@ namespace Dalamud.Game.Gui.FlyText
/// Enum of FlyTextKind values. Members suffixed with
/// a number seem to be a duplicate, or perform duplicate behavior.
/// </summary>
public enum FlyTextKind
public enum FlyTextKind : int
{
/// <summary>
/// Val1 in serif font, Text2 in sans-serif as subtitle.
@ -19,8 +19,8 @@ namespace Dalamud.Game.Gui.FlyText
DirectHit = 1,
/// <summary>
/// Val1 in larger serif font with exclamation, with Text2
/// in sans-serif as subtitle. Does a bigger bounce effect on appearance.
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle.
/// Does a bigger bounce effect on appearance.
/// </summary>
CriticalHit = 2,
@ -75,6 +75,10 @@ namespace Dalamud.Game.Gui.FlyText
/// Icon next to sans-serif Text1.
/// </summary>
NamedIcon = 12,
/// <summary>
/// Icon next to sans-serif Text1 (2).
/// </summary>
NamedIcon2 = 13,
/// <summary>
@ -92,8 +96,19 @@ namespace Dalamud.Game.Gui.FlyText
/// </summary>
NamedTp = 16,
/// <summary>
/// AutoAttack with sans-serif Text1 to the left of the Val1 (2).
/// </summary>
NamedAttack2 = 17,
/// <summary>
/// Sans-serif Text1 next to serif Val1 with all caps condensed font MP with Text2 in sans-serif as subtitle (2).
/// </summary>
NamedMp2 = 18,
/// <summary>
/// Sans-serif Text1 next to serif Val1 with all caps condensed font TP with Text2 in sans-serif as subtitle (2).
/// </summary>
NamedTp2 = 19,
/// <summary>
@ -122,9 +137,25 @@ namespace Dalamud.Game.Gui.FlyText
/// AutoAttack with no Text2.
/// </summary>
AutoAttackNoText = 24,
/// <summary>
/// AutoAttack with no Text2 (2).
/// </summary>
AutoAttackNoText2 = 25,
/// <summary>
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle. Does a bigger bounce effect on appearance (2).
/// </summary>
CriticalHit2 = 26,
/// <summary>
/// AutoAttack with no Text2 (3).
/// </summary>
AutoAttackNoText3 = 27,
/// <summary>
/// CriticalHit with sans-serif Text1 to the left of the Val1 (2).
/// </summary>
NamedCriticalHit2 = 28,
/// <summary>
@ -148,6 +179,11 @@ namespace Dalamud.Game.Gui.FlyText
/// Same as NamedIcon but Text1 is slightly faded. Used for buff expiration.
/// </summary>
NamedIconFaded = 32,
/// <summary>
/// Same as NamedIcon but Text1 is slightly faded (2).
/// Used for buff expiration.
/// </summary>
NamedIconFaded2 = 33,
/// <summary>
@ -175,8 +211,19 @@ namespace Dalamud.Game.Gui.FlyText
/// </summary>
NamedHasNoEffect = 38,
/// <summary>
/// AutoAttack with sans-serif Text1 to the left of the Val1 (3).
/// </summary>
NamedAttack3 = 39,
/// <summary>
/// Sans-serif Text1 next to serif Val1 with all caps condensed font MP with Text2 in sans-serif as subtitle (3).
/// </summary>
NamedMp3 = 40,
/// <summary>
/// Sans-serif Text1 next to serif Val1 with all caps condensed font TP with Text2 in sans-serif as subtitle (3).
/// </summary>
NamedTp3 = 41,
/// <summary>
@ -194,7 +241,15 @@ namespace Dalamud.Game.Gui.FlyText
/// </summary>
NamedIconWithItemOutline = 44,
/// <summary>
/// AutoAttack with no Text2 (4).
/// </summary>
AutoAttackNoText4 = 45,
/// <summary>
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle (3).
/// Does a bigger bounce effect on appearance.
/// </summary>
CriticalHit3 = 46,
/// <summary>
@ -207,8 +262,22 @@ namespace Dalamud.Game.Gui.FlyText
/// </summary>
Reflected = 48,
/// <summary>
/// Val1 in serif font, Text2 in sans-serif as subtitle (2).
/// Does a bounce effect on appearance.
/// </summary>
DirectHit2 = 49,
CriticalHit5 = 50,
/// <summary>
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle (4).
/// Does a bigger bounce effect on appearance.
/// </summary>
CriticalHit4 = 50,
/// <summary>
/// Val1 in even larger serif font with 2 exclamations, Text2 in sans-serif as subtitle (2).
/// Does a large bounce effect on appearance. Does not scroll up or down the screen.
/// </summary>
CriticalDirectHit2 = 51,
}
}

View file

@ -2,9 +2,9 @@ using System;
using System.Numerics;
using System.Runtime.InteropServices;
using Dalamud.Game.Gui.Addons;
using Dalamud.Game.Gui.FlyText;
using Dalamud.Game.Gui.PartyFinder;
using Dalamud.Game.Gui.Toast;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Hooking;
using Dalamud.Interface;
@ -23,10 +23,7 @@ namespace Dalamud.Game.Gui
private readonly GameGuiAddressResolver address;
private readonly GetMatrixSingletonDelegate getMatrixSingleton;
private readonly GetUIObjectDelegate getUIObject;
private readonly ScreenToWorldNativeDelegate screenToWorldNative;
private readonly GetUIObjectByNameDelegate getUIObjectByName;
private readonly GetUiModuleDelegate getUiModule;
private readonly GetAgentModuleDelegate getAgentModule;
private readonly Hook<SetGlobalBgmDelegate> setGlobalBgmHook;
@ -61,7 +58,6 @@ namespace Dalamud.Game.Gui
Log.Verbose($"HandleItemHover address 0x{this.address.HandleItemHover.ToInt64():X}");
Log.Verbose($"HandleItemOut address 0x{this.address.HandleItemOut.ToInt64():X}");
Log.Verbose($"HandleImm address 0x{this.address.HandleImm.ToInt64():X}");
Log.Verbose($"GetUIObject address 0x{this.address.GetUIObject.ToInt64():X}");
Log.Verbose($"GetAgentModule address 0x{this.address.GetAgentModule.ToInt64():X}");
this.Chat = new ChatGui(this.address.ChatManager, scanner, dalamud);
@ -79,44 +75,23 @@ namespace Dalamud.Game.Gui
this.handleImmHook = new Hook<HandleImmDelegate>(this.address.HandleImm, this.HandleImmDetour);
this.getUIObject = Marshal.GetDelegateForFunctionPointer<GetUIObjectDelegate>(this.address.GetUIObject);
this.getMatrixSingleton = Marshal.GetDelegateForFunctionPointer<GetMatrixSingletonDelegate>(this.address.GetMatrixSingleton);
this.screenToWorldNative = Marshal.GetDelegateForFunctionPointer<ScreenToWorldNativeDelegate>(this.address.ScreenToWorld);
this.toggleUiHideHook = new Hook<ToggleUiHideDelegate>(this.address.ToggleUiHide, this.ToggleUiHideDetour);
this.GetBaseUIObject = Marshal.GetDelegateForFunctionPointer<GetBaseUIObjectDelegate>(this.address.GetBaseUIObject);
this.getUIObjectByName = Marshal.GetDelegateForFunctionPointer<GetUIObjectByNameDelegate>(this.address.GetUIObjectByName);
this.getUiModule = Marshal.GetDelegateForFunctionPointer<GetUiModuleDelegate>(this.address.GetUIModule);
this.getAgentModule = Marshal.GetDelegateForFunctionPointer<GetAgentModuleDelegate>(this.address.GetAgentModule);
}
// Marshaled delegates
/// <summary>
/// The delegate type of the native method that gets the Client::UI::UIModule address.
/// </summary>
/// <returns>The Client::UI::UIModule address.</returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate IntPtr GetBaseUIObjectDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate IntPtr GetMatrixSingletonDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate IntPtr GetUIObjectDelegate();
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private unsafe delegate bool ScreenToWorldNativeDelegate(float* camPos, float* clipPos, float rayDistance, float* worldPos, int* unknown);
[UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Ansi)]
private delegate IntPtr GetUIObjectByNameDelegate(IntPtr thisPtr, string uiName, int index);
private delegate IntPtr GetUiModuleDelegate(IntPtr basePtr);
private delegate IntPtr GetAgentModuleDelegate(IntPtr uiModule);
// Hooked delegates
@ -153,12 +128,6 @@ namespace Dalamud.Game.Gui
/// </summary>
public event EventHandler<bool> OnUiHideToggled;
/// <summary>
/// Gets a callable delegate for the GetBaseUIObject game method.
/// </summary>
/// <returns>The Client::UI::UIModule address.</returns>
public GetBaseUIObjectDelegate GetBaseUIObject { get; }
/// <summary>
/// Gets the <see cref="Chat"/> instance.
/// </summary>
@ -212,19 +181,19 @@ namespace Dalamud.Game.Gui
/// <returns>True if there were no errors and it could open the map.</returns>
public bool OpenMapWithMapLink(MapLinkPayload mapLink)
{
var uiObjectPtr = this.getUIObject();
var uiModule = this.GetUIModule();
if (uiObjectPtr.Equals(IntPtr.Zero))
if (uiModule == IntPtr.Zero)
{
Log.Error("OpenMapWithMapLink: Null pointer returned from getUIObject()");
return false;
}
this.getUIMapObject = this.address.GetVirtualFunction<GetUIMapObjectDelegate>(uiObjectPtr, 0, 8);
this.getUIMapObject = this.address.GetVirtualFunction<GetUIMapObjectDelegate>(uiModule, 0, 8);
var uiMapObjectPtr = this.getUIMapObject(uiObjectPtr);
var uiMapObjectPtr = this.getUIMapObject(uiModule);
if (uiMapObjectPtr.Equals(IntPtr.Zero))
if (uiMapObjectPtr == IntPtr.Zero)
{
Log.Error("OpenMapWithMapLink: Null pointer returned from GetUIMapObject()");
return false;
@ -407,37 +376,40 @@ namespace Dalamud.Game.Gui
/// Gets a pointer to the game's UI module.
/// </summary>
/// <returns>IntPtr pointing to UI module.</returns>
public IntPtr GetUIModule() => this.getUiModule(this.dalamud.Framework.Address.BaseAddress);
/// <summary>
/// Gets the pointer to the UI Object with the given name and index.
/// </summary>
/// <param name="name">Name of UI to find.</param>
/// <param name="index">Index of UI to find (1-indexed).</param>
/// <returns>IntPtr.Zero if unable to find UI, otherwise IntPtr pointing to the start of the UI Object.</returns>
public IntPtr GetUiObjectByName(string name, int index)
public unsafe IntPtr GetUIModule()
{
var baseUi = this.GetBaseUIObject();
if (baseUi == IntPtr.Zero) return IntPtr.Zero;
var baseUiProperties = Marshal.ReadIntPtr(baseUi, 0x20);
if (baseUiProperties == IntPtr.Zero) return IntPtr.Zero;
return this.getUIObjectByName(baseUiProperties, name, index);
var framework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework.Instance();
if (framework == null)
return IntPtr.Zero;
var uiModule = framework->GetUiModule();
if (uiModule == null)
return IntPtr.Zero;
return (IntPtr)uiModule;
}
/// <summary>
/// Gets an Addon by it's internal name.
/// Gets the pointer to the Addon with the given name and index.
/// </summary>
/// <param name="name">The addon name.</param>
/// <param name="index">The index of the addon, starting at 1.</param>
/// <returns>The native memory representation of the addon, if it exists.</returns>
public Addon GetAddonByName(string name, int index)
/// <param name="name">Name of addon to find.</param>
/// <param name="index">Index of addon to find (1-indexed).</param>
/// <returns>IntPtr.Zero if unable to find UI, otherwise IntPtr pointing to the start of the addon.</returns>
public unsafe IntPtr GetAddonByName(string name, int index)
{
var address = this.GetUiObjectByName(name, index);
var atkStage = FFXIVClientStructs.FFXIV.Component.GUI.AtkStage.GetSingleton();
if (atkStage == null)
return IntPtr.Zero;
if (address == IntPtr.Zero)
return null;
var unitMgr = atkStage->RaptureAtkUnitManager;
if (unitMgr == null)
return IntPtr.Zero;
return new Addon(address);
var addon = unitMgr->GetAddonByName(name, index);
if (addon == null)
return IntPtr.Zero;
return (IntPtr)addon;
}
/// <summary>
@ -447,7 +419,7 @@ namespace Dalamud.Game.Gui
/// <returns>A pointer to the agent interface.</returns>
public IntPtr FindAgentInterface(string addonName)
{
var addon = this.dalamud.Framework.Gui.GetUiObjectByName(addonName, 1);
var addon = this.GetAddonByName(addonName, 1);
return this.FindAgentInterface(addon);
}
@ -456,7 +428,14 @@ namespace Dalamud.Game.Gui
/// </summary>
/// <param name="addon">The addon address.</param>
/// <returns>A pointer to the agent interface.</returns>
public IntPtr FindAgentInterface(IntPtr addon)
public unsafe IntPtr FindAgentInterface(void* addon) => this.FindAgentInterface((IntPtr)addon);
/// <summary>
/// Find the agent associated with an addon, if possible.
/// </summary>
/// <param name="addon">The addon address.</param>
/// <returns>A pointer to the agent interface.</returns>
public unsafe IntPtr FindAgentInterface(IntPtr addon)
{
if (addon == IntPtr.Zero)
return IntPtr.Zero;
@ -473,9 +452,10 @@ namespace Dalamud.Game.Gui
return IntPtr.Zero;
}
var id = Marshal.ReadInt16(addon, 0x1CE);
var unitBase = (FFXIVClientStructs.FFXIV.Component.GUI.AtkUnitBase*)addon;
var id = unitBase->ParentID;
if (id == 0)
id = Marshal.ReadInt16(addon, 0x1CC);
id = unitBase->ID;
if (id == 0)
return IntPtr.Zero;

View file

@ -57,11 +57,6 @@ namespace Dalamud.Game.Gui
/// </summary>
public IntPtr HandleImm { get; private set; }
/// <summary>
/// Gets the address of the native GetUIObject method.
/// </summary>
public IntPtr GetUIObject { get; private set; }
/// <summary>
/// Gets the address of the native GetMatrixSingleton method.
/// </summary>
@ -77,21 +72,6 @@ namespace Dalamud.Game.Gui
/// </summary>
public IntPtr ToggleUiHide { get; private set; }
/// <summary>
/// Gets the address of the native Client::UI::UIModule getter method.
/// </summary>
public IntPtr GetBaseUIObject { get; private set; }
/// <summary>
/// Gets the address of the native GetUIObjectByName method.
/// </summary>
public IntPtr GetUIObjectByName { get; private set; }
/// <summary>
/// Gets the address of the native GetUIModule method.
/// </summary>
public IntPtr GetUIModule { get; private set; }
/// <summary>
/// Gets the address of the native GetAgentModule method.
/// </summary>
@ -106,13 +86,9 @@ namespace Dalamud.Game.Gui
this.HandleActionHover = sig.ScanText("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 83 F8 0F");
this.HandleActionOut = sig.ScanText("48 89 5C 24 ?? 57 48 83 EC 20 48 8B DA 48 8B F9 4D 85 C0 74 1F");
this.HandleImm = sig.ScanText("E8 ?? ?? ?? ?? 84 C0 75 10 48 83 FF 09");
this.GetUIObject = sig.ScanText("E8 ?? ?? ?? ?? 48 8B C8 48 8B 10 FF 52 40 80 88 ?? ?? ?? ?? 01 E9");
this.GetMatrixSingleton = sig.ScanText("E8 ?? ?? ?? ?? 48 8D 4C 24 ?? 48 89 4c 24 ?? 4C 8D 4D ?? 4C 8D 44 24 ??");
this.ScreenToWorld = sig.ScanText("48 83 EC 48 48 8B 05 ?? ?? ?? ?? 4D 8B D1");
this.ToggleUiHide = sig.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 0F B6 B9 ?? ?? ?? ?? B8 ?? ?? ?? ??");
this.GetBaseUIObject = sig.ScanText("E8 ?? ?? ?? ?? 41 B8 01 00 00 00 48 8D 15 ?? ?? ?? ?? 48 8B 48 20 E8 ?? ?? ?? ?? 48 8B CF");
this.GetUIObjectByName = sig.ScanText("E8 ?? ?? ?? ?? 48 8B CF 48 89 87 ?? ?? 00 00 E8 ?? ?? ?? ?? 41 B8 01 00 00 00");
this.GetUIModule = sig.ScanText("E8 ?? ?? ?? ?? 48 8B C8 48 85 C0 75 2D");
var uiModuleVtableSig = sig.GetStaticAddressFromSig("48 8D 05 ?? ?? ?? ?? 4C 89 61 28");
this.GetAgentModule = Marshal.ReadIntPtr(uiModuleVtableSig, 34 * IntPtr.Size);

View file

@ -2,11 +2,10 @@ using System;
using System.Collections.Generic;
using System.Text;
using Dalamud.Game.Gui.Toast;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Hooking;
namespace Dalamud.Game.Gui
namespace Dalamud.Game.Gui.Toast
{
/// <summary>
/// This class facilitates interacting with and creating native toast windows.

View file

@ -1,8 +1,6 @@
using System;
using Dalamud.Game.Internal;
namespace Dalamud.Game.Gui
namespace Dalamud.Game.Gui.Toast
{
/// <summary>
/// An address resolver for the <see cref="ToastGui"/> class.

View file

@ -160,27 +160,25 @@ namespace Dalamud.Game.Network
return this.processZonePacketUpHook.Original(a1, dataPtr, a3, a4);
}
#if DEBUG
private void InjectZoneProtoPacket(byte[] data)
{
this.zoneInjectQueue.Enqueue(data);
}
// private void InjectZoneProtoPacket(byte[] data)
// {
// this.zoneInjectQueue.Enqueue(data);
// }
private void InjectActorControl(short cat, int param1)
{
var packetData = new byte[]
{
0x14, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x17, 0x7C, 0xC5, 0x5D, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x48, 0xB2, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x43, 0x7F, 0x00, 0x00,
};
BitConverter.GetBytes((short)cat).CopyTo(packetData, 0x10);
BitConverter.GetBytes((uint)param1).CopyTo(packetData, 0x14);
this.InjectZoneProtoPacket(packetData);
}
#endif
// private void InjectActorControl(short cat, int param1)
// {
// var packetData = new byte[]
// {
// 0x14, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x17, 0x7C, 0xC5, 0x5D, 0x00, 0x00, 0x00, 0x00,
// 0x05, 0x00, 0x48, 0xB2, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x43, 0x7F, 0x00, 0x00,
// };
//
// BitConverter.GetBytes((short)cat).CopyTo(packetData, 0x10);
//
// BitConverter.GetBytes((uint)param1).CopyTo(packetData, 0x14);
//
// this.InjectZoneProtoPacket(packetData);
// }
}
}

View file

@ -17,6 +17,15 @@ namespace Dalamud.Game
private IntPtr moduleCopyPtr;
private long moduleCopyOffset;
/// <summary>
/// Initializes a new instance of the <see cref="SigScanner"/> class using the main module of the current process.
/// </summary>
/// <param name="doCopy">Whether or not to copy the module upon initialization for search operations to use, as to not get disturbed by possible hooks.</param>
public SigScanner(bool doCopy = false)
: this(Process.GetCurrentProcess().MainModule!, doCopy)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SigScanner"/> class.
/// </summary>

View file

@ -84,31 +84,16 @@ namespace Dalamud.Game.Text.Sanitizer
};
}
private static IEnumerable<string> SanitizeByLanguage(
IEnumerable<string> unsanitizedStrings, ClientLanguage clientLanguage)
private static IEnumerable<string> SanitizeByLanguage(IEnumerable<string> unsanitizedStrings, ClientLanguage clientLanguage)
{
var sanitizedStrings = new List<string>();
switch (clientLanguage)
return clientLanguage switch
{
case ClientLanguage.Japanese:
case ClientLanguage.English:
sanitizedStrings.AddRange(unsanitizedStrings.Select(FilterUnprintableCharacters));
return sanitizedStrings;
case ClientLanguage.German:
sanitizedStrings.AddRange(
unsanitizedStrings.Select(
unsanitizedString =>
FilterByDict(FilterUnprintableCharacters(unsanitizedString), DESanitizationDict)));
return sanitizedStrings;
case ClientLanguage.French:
sanitizedStrings.AddRange(
unsanitizedStrings.Select(
unsanitizedString =>
FilterByDict(FilterUnprintableCharacters(unsanitizedString), FRSanitizationDict)));
return sanitizedStrings;
default:
throw new ArgumentOutOfRangeException(nameof(clientLanguage), clientLanguage, null);
}
ClientLanguage.Japanese => unsanitizedStrings.Select(FilterUnprintableCharacters),
ClientLanguage.English => unsanitizedStrings.Select(FilterUnprintableCharacters),
ClientLanguage.German => unsanitizedStrings.Select(original => FilterByDict(FilterUnprintableCharacters(original), DESanitizationDict)),
ClientLanguage.French => unsanitizedStrings.Select(original => FilterByDict(FilterUnprintableCharacters(original), FRSanitizationDict)),
_ => throw new ArgumentOutOfRangeException(nameof(clientLanguage), clientLanguage, null),
};
}
private static string FilterUnprintableCharacters(string str)

View file

@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.IO;

View file

@ -4,7 +4,6 @@ using System.Linq;
using Dalamud.Plugin;
using ImGuiNET;
using Lumina.Excel.GeneratedSheets;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using Serilog;
@ -65,10 +64,10 @@ namespace Dalamud.Interface.Internal.Scratchpad
var options = ScriptOptions.Default
.AddReferences(typeof(ImGui).Assembly)
.AddReferences(typeof(Dalamud).Assembly)
.AddReferences(typeof(FFXIVClientStructs.Attributes.Addon).Assembly) // FFXIVClientStructs
.AddReferences(typeof(FFXIVClientStructs.Resolver).Assembly) // FFXIVClientStructs
.AddReferences(typeof(Lumina.GameData).Assembly) // Lumina
.AddReferences(typeof(TerritoryType).Assembly) // Lumina.Excel
// .WithReferences(MetadataReference.CreateFromFile(typeof(ScratchExecutionManager).Assembly.Location))
.AddReferences(typeof(Lumina.Excel.GeneratedSheets.TerritoryType).Assembly) // Lumina.Excel
// .WithReferences(MetadataReference.CreateFromFile(typeof(ScratchExecutionManager).Assembly.Location))
.AddImports("System")
.AddImports("System.IO")
.AddImports("System.Reflection")

View file

@ -11,11 +11,11 @@ using Dalamud.Game.ClientState.JobGauge.Enums;
using Dalamud.Game.ClientState.JobGauge.Types;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Gui.Addons;
using Dalamud.Game.Gui.FlyText;
using Dalamud.Game.Gui.Toast;
using Dalamud.Game.Text;
using Dalamud.Interface.Windowing;
using Dalamud.Memory;
using Dalamud.Plugin;
using Dalamud.Utility;
using ImGuiNET;
@ -45,7 +45,6 @@ namespace Dalamud.Interface.Internal.Windows
private string inputAddonName = string.Empty;
private int inputAddonIndex;
private Addon resultAddon;
private IntPtr findAgentInterfacePtr;
@ -130,7 +129,6 @@ namespace Dalamud.Interface.Internal.Windows
/// <inheritdoc/>
public override void OnClose()
{
this.resultAddon = null;
}
/// <summary>
@ -843,22 +841,31 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.Text($"{command.Key}\n -> {command.Value.HelpMessage}\n -> In help: {command.Value.ShowInHelp}\n\n");
}
private void DrawAddon()
private unsafe void DrawAddon()
{
var gameGui = this.dalamud.Framework.Gui;
ImGui.InputText("Addon name", ref this.inputAddonName, 256);
ImGui.InputInt("Addon Index", ref this.inputAddonIndex);
if (ImGui.Button("Get Addon"))
if (this.inputAddonName.IsNullOrEmpty())
return;
var address = gameGui.GetAddonByName(this.inputAddonName, this.inputAddonIndex);
if (address == IntPtr.Zero)
{
this.resultAddon = this.dalamud.Framework.Gui.GetAddonByName(this.inputAddonName, this.inputAddonIndex);
ImGui.Text("Null");
return;
}
if (ImGui.Button("Find Agent"))
this.findAgentInterfacePtr = this.dalamud.Framework.Gui.FindAgentInterface(this.inputAddonName);
var addon = (FFXIVClientStructs.FFXIV.Component.GUI.AtkUnitBase*)address;
var name = MemoryHelper.ReadStringNullTerminated((IntPtr)addon->Name);
ImGui.TextUnformatted($"{name} - 0x{address.ToInt64():x}\n v:{addon->IsVisible} x:{addon->X} y:{addon->Y} s:{addon->Scale}, w:{addon->RootNode->Width}, h:{addon->RootNode->Height}");
if (this.resultAddon != null)
if (ImGui.Button("Find Agent"))
{
ImGui.TextUnformatted($"{this.resultAddon.Name} - 0x{this.resultAddon.Address.ToInt64():x}\n v:{this.resultAddon.Visible} x:{this.resultAddon.X} y:{this.resultAddon.Y} s:{this.resultAddon.Scale}, w:{this.resultAddon.Width}, h:{this.resultAddon.Height}");
this.findAgentInterfacePtr = gameGui.FindAgentInterface(address);
}
if (this.findAgentInterfacePtr != IntPtr.Zero)
@ -869,13 +876,6 @@ namespace Dalamud.Interface.Internal.Windows
if (ImGui.Button("C"))
ImGui.SetClipboardText(this.findAgentInterfacePtr.ToInt64().ToString("x"));
}
if (ImGui.Button("Get Base UI object"))
{
var addr = this.dalamud.Framework.Gui.GetBaseUIObject().ToInt64().ToString("x");
Log.Information("{0}", addr);
ImGui.SetClipboardText(addr);
}
}
private void DrawAddonInspector()
@ -977,7 +977,7 @@ namespace Dalamud.Interface.Internal.Windows
if (ImGui.BeginCombo("Kind", this.flyKind.ToString()))
{
var names = Enum.GetNames(typeof(FlyTextKind));
for (int i = 0; i < names.Length; i++)
for (var i = 0; i < names.Length; i++)
{
if (ImGui.Selectable($"{names[i]} ({i})"))
this.flyKind = (FlyTextKind)i;

View file

@ -1,5 +1,4 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
@ -20,7 +19,6 @@ namespace Dalamud.Memory
public static unsafe class MemoryHelper
{
private static SeStringManager seStringManager;
private static IntPtr handle;
#region Read
@ -174,8 +172,23 @@ namespace Dalamud.Memory
/// </remarks>
/// <param name="memoryAddress">The memory address to read from.</param>
/// <returns>The read in string.</returns>
public static string ReadString(IntPtr memoryAddress)
=> ReadString(memoryAddress, 256);
public static string ReadStringNullTerminated(IntPtr memoryAddress)
=> ReadStringNullTerminated(memoryAddress, Encoding.UTF8);
/// <summary>
/// Read a string with the given encoding from a specified memory address.
/// </summary>
/// <remarks>
/// Attention! If this is an SeString, use the <see cref="SeStringManager"/> to decode or the applicable helper method.
/// </remarks>
/// <param name="memoryAddress">The memory address to read from.</param>
/// <param name="encoding">The encoding to use to decode the string.</param>
/// <returns>The read in string.</returns>
public static string ReadStringNullTerminated(IntPtr memoryAddress, Encoding encoding)
{
var buffer = ReadRawNullTerminated(memoryAddress);
return encoding.GetString(buffer);
}
/// <summary>
/// Read a UTF-8 encoded string from a specified memory address.
@ -189,18 +202,6 @@ namespace Dalamud.Memory
public static string ReadString(IntPtr memoryAddress, int maxLength)
=> ReadString(memoryAddress, Encoding.UTF8, maxLength);
/// <summary>
/// Read a string with the given encoding from a specified memory address.
/// </summary>
/// <remarks>
/// Attention! If this is an SeString, use the <see cref="SeStringManager"/> to decode or the applicable helper method.
/// </remarks>
/// <param name="memoryAddress">The memory address to read from.</param>
/// <param name="encoding">The encoding to use to decode the string.</param>
/// <returns>The read in string.</returns>
public static string ReadString(IntPtr memoryAddress, Encoding encoding)
=> ReadString(memoryAddress, encoding, 256);
/// <summary>
/// Read a string with the given encoding from a specified memory address.
/// </summary>
@ -288,8 +289,20 @@ namespace Dalamud.Memory
/// </remarks>
/// <param name="memoryAddress">The memory address to read from.</param>
/// <param name="value">The read in string.</param>
public static void ReadString(IntPtr memoryAddress, out string value)
=> value = ReadString(memoryAddress);
public static void ReadStringNullTerminated(IntPtr memoryAddress, out string value)
=> value = ReadStringNullTerminated(memoryAddress);
/// <summary>
/// Read a string with the given encoding from a specified memory address.
/// </summary>
/// <remarks>
/// Attention! If this is an SeString, use the <see cref="SeStringManager"/> to decode or the applicable helper method.
/// </remarks>
/// <param name="memoryAddress">The memory address to read from.</param>
/// <param name="encoding">The encoding to use to decode the string.</param>
/// <param name="value">The read in string.</param>
public static void ReadStringNullTerminated(IntPtr memoryAddress, Encoding encoding, out string value)
=> value = ReadStringNullTerminated(memoryAddress, encoding);
/// <summary>
/// Read a UTF-8 encoded string from a specified memory address.
@ -303,18 +316,6 @@ namespace Dalamud.Memory
public static void ReadString(IntPtr memoryAddress, out string value, int maxLength)
=> value = ReadString(memoryAddress, maxLength);
/// <summary>
/// Read a string with the given encoding from a specified memory address.
/// </summary>
/// <remarks>
/// Attention! If this is an SeString, use the <see cref="SeStringManager"/> to decode or the applicable helper method.
/// </remarks>
/// <param name="memoryAddress">The memory address to read from.</param>
/// <param name="encoding">The encoding to use to decode the string.</param>
/// <param name="value">The read in string.</param>
public static void ReadString(IntPtr memoryAddress, Encoding encoding, out string value)
=> value = ReadString(memoryAddress, encoding);
/// <summary>
/// Read a string with the given encoding from a specified memory address.
/// </summary>
@ -584,7 +585,7 @@ namespace Dalamud.Memory
public static void ReadProcessMemory(IntPtr memoryAddress, ref byte[] value)
{
var length = value.Length;
var result = NativeFunctions.ReadProcessMemory(handle, memoryAddress, value, length, out _);
var result = NativeFunctions.ReadProcessMemory((IntPtr)0xFFFFFFFF, memoryAddress, value, length, out _);
if (!result)
throw new MemoryReadException($"Unable to read memory at 0x{memoryAddress.ToInt64():X} of length {length} (result={result})");
@ -603,7 +604,7 @@ namespace Dalamud.Memory
public static void WriteProcessMemory(IntPtr memoryAddress, byte[] data)
{
var length = data.Length;
var result = NativeFunctions.WriteProcessMemory(handle, memoryAddress, data, length, out _);
var result = NativeFunctions.WriteProcessMemory((IntPtr)0xFFFFFFFF, memoryAddress, data, length, out _);
if (!result)
throw new MemoryWriteException($"Unable to write memory at 0x{memoryAddress.ToInt64():X} of length {length} (result={result})");
@ -662,7 +663,6 @@ namespace Dalamud.Memory
internal static void Initialize(Dalamud dalamud)
{
seStringManager = dalamud.SeStringManager;
handle = Process.GetCurrentProcess().Handle;
}
}
}

View file

@ -1,5 +1,4 @@
#define WIN32_LEAN_AND_MEAN
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <filesystem>
@ -36,12 +35,20 @@ int InitializeClrAndGetEntryPoint(
CoreCLR clr;
SetEnvironmentVariable(L"DOTNET_MULTILEVEL_LOOKUP", L"0");
char* env_path = std::getenv("DALAMUD_RUNTIME");
wchar_t* dotnet_path;
wchar_t* _appdata;
if (!env_path)
std::wstring buffer;
buffer.resize(0);
result = GetEnvironmentVariableW(L"DALAMUD_RUNTIME", &buffer[0], 0);
if (result)
{
buffer.resize(result); // The first pass returns the required length
result = GetEnvironmentVariableW(L"DALAMUD_RUNTIME", &buffer[0], result);
dotnet_path = _wcsdup(buffer.c_str());
}
else
{
result = SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DEFAULT, nullptr, &_appdata);
@ -54,12 +61,6 @@ int InitializeClrAndGetEntryPoint(
std::filesystem::path fs_app_data(_appdata);
dotnet_path = _wcsdup(fs_app_data.append("XIVLauncher").append("runtime").c_str());
}
else
{
const size_t cSize = strlen(env_path)+1;
dotnet_path = new wchar_t[cSize];
mbstowcs (dotnet_path, env_path, cSize);
}
// =========================================================================== //