cleanup and reformatting
This commit is contained in:
@@ -15,3 +15,8 @@ description: |-
|
|||||||
- Screenshot mode (obfuscate names)
|
- Screenshot mode (obfuscate names)
|
||||||
repo_url: https://github.com/Infiziert90/ChatTwo
|
repo_url: https://github.com/Infiziert90/ChatTwo
|
||||||
accepts_feedback: true
|
accepts_feedback: true
|
||||||
|
tags:
|
||||||
|
- Social
|
||||||
|
- UI
|
||||||
|
- Chat
|
||||||
|
- Replacement
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ using LiteDB;
|
|||||||
|
|
||||||
namespace ChatTwo.Code;
|
namespace ChatTwo.Code;
|
||||||
|
|
||||||
internal class ChatCode {
|
internal class ChatCode
|
||||||
|
{
|
||||||
private const ushort Clear7 = ~(~0 << 7);
|
private const ushort Clear7 = ~(~0 << 7);
|
||||||
|
|
||||||
internal ushort Raw { get; }
|
internal ushort Raw { get; }
|
||||||
@@ -12,7 +13,8 @@ internal class ChatCode {
|
|||||||
internal ChatSource Target { get; }
|
internal ChatSource Target { get; }
|
||||||
private ChatSource SourceFrom(ushort shift) => (ChatSource) (1 << ((Raw >> shift) & 0xF));
|
private ChatSource SourceFrom(ushort shift) => (ChatSource) (1 << ((Raw >> shift) & 0xF));
|
||||||
|
|
||||||
internal ChatCode(ushort raw) {
|
internal ChatCode(ushort raw)
|
||||||
|
{
|
||||||
Raw = raw;
|
Raw = raw;
|
||||||
Type = (ChatType) (Raw & Clear7);
|
Type = (ChatType) (Raw & Clear7);
|
||||||
Source = SourceFrom(11);
|
Source = SourceFrom(11);
|
||||||
@@ -20,14 +22,16 @@ internal class ChatCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BsonCtor]
|
[BsonCtor]
|
||||||
public ChatCode(ushort raw, ChatType type, ChatSource source, ChatSource target) {
|
public ChatCode(ushort raw, ChatType type, ChatSource source, ChatSource target)
|
||||||
|
{
|
||||||
Raw = raw;
|
Raw = raw;
|
||||||
Type = type;
|
Type = type;
|
||||||
Source = source;
|
Source = source;
|
||||||
Target = target;
|
Target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ChatType Parent() => Type switch {
|
internal ChatType Parent() => Type switch
|
||||||
|
{
|
||||||
ChatType.Say => ChatType.Say,
|
ChatType.Say => ChatType.Say,
|
||||||
ChatType.GmSay => ChatType.Say,
|
ChatType.GmSay => ChatType.Say,
|
||||||
ChatType.Shout => ChatType.Shout,
|
ChatType.Shout => ChatType.Shout,
|
||||||
@@ -84,8 +88,10 @@ internal class ChatCode {
|
|||||||
_ => Type,
|
_ => Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
internal bool IsBattle() {
|
internal bool IsBattle()
|
||||||
switch (Type) {
|
{
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
case ChatType.Damage:
|
case ChatType.Damage:
|
||||||
case ChatType.Miss:
|
case ChatType.Miss:
|
||||||
case ChatType.Action:
|
case ChatType.Action:
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ namespace ChatTwo.Code;
|
|||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1028:Enum Storage should be Int32")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1028:Enum Storage should be Int32")]
|
||||||
[Flags]
|
[Flags]
|
||||||
internal enum ChatSource : ushort {
|
internal enum ChatSource : ushort
|
||||||
|
{
|
||||||
Self = 2,
|
Self = 2,
|
||||||
PartyMember = 4,
|
PartyMember = 4,
|
||||||
AllianceMember = 8,
|
AllianceMember = 8,
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ using ChatTwo.Resources;
|
|||||||
|
|
||||||
namespace ChatTwo.Code;
|
namespace ChatTwo.Code;
|
||||||
|
|
||||||
internal static class ChatSourceExt {
|
internal static class ChatSourceExt
|
||||||
|
{
|
||||||
internal const ChatSource All =
|
internal const ChatSource All =
|
||||||
ChatSource.Self
|
ChatSource.Self
|
||||||
| ChatSource.PartyMember
|
| ChatSource.PartyMember
|
||||||
@@ -16,7 +17,8 @@ internal static class ChatSourceExt {
|
|||||||
| ChatSource.AlliancePet
|
| ChatSource.AlliancePet
|
||||||
| ChatSource.OtherPet;
|
| ChatSource.OtherPet;
|
||||||
|
|
||||||
internal static string Name(this ChatSource source) => source switch {
|
internal static string Name(this ChatSource source) => source switch
|
||||||
|
{
|
||||||
ChatSource.Self => Language.ChatSource_Self,
|
ChatSource.Self => Language.ChatSource_Self,
|
||||||
ChatSource.PartyMember => Language.ChatSource_PartyMember,
|
ChatSource.PartyMember => Language.ChatSource_PartyMember,
|
||||||
ChatSource.AllianceMember => Language.ChatSource_AllianceMember,
|
ChatSource.AllianceMember => Language.ChatSource_AllianceMember,
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
namespace ChatTwo.Code;
|
namespace ChatTwo.Code;
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1028:Enum Storage should be Int32")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1028:Enum Storage should be Int32")]
|
||||||
internal enum ChatType : ushort {
|
internal enum ChatType : ushort
|
||||||
|
{
|
||||||
Debug = 1,
|
Debug = 1,
|
||||||
Urgent = 2,
|
Urgent = 2,
|
||||||
Notice = 3,
|
Notice = 3,
|
||||||
|
|||||||
+33
-17
@@ -3,14 +3,19 @@ using ChatTwo.Util;
|
|||||||
|
|
||||||
namespace ChatTwo.Code;
|
namespace ChatTwo.Code;
|
||||||
|
|
||||||
internal static class ChatTypeExt {
|
internal static class ChatTypeExt
|
||||||
internal static IEnumerable<(string, ChatType[])> SortOrder => new[] {
|
{
|
||||||
(Language.Options_Tabs_ChannelTypes_Special, new[] {
|
internal static IEnumerable<(string, ChatType[])> SortOrder => new[]
|
||||||
|
{
|
||||||
|
(Language.Options_Tabs_ChannelTypes_Special,
|
||||||
|
[
|
||||||
ChatType.Debug,
|
ChatType.Debug,
|
||||||
ChatType.Urgent,
|
ChatType.Urgent,
|
||||||
ChatType.Notice,
|
ChatType.Notice
|
||||||
}),
|
]),
|
||||||
(Language.Options_Tabs_ChannelTypes_Chat, new[] {
|
|
||||||
|
(Language.Options_Tabs_ChannelTypes_Chat,
|
||||||
|
[
|
||||||
ChatType.Say,
|
ChatType.Say,
|
||||||
ChatType.Yell,
|
ChatType.Yell,
|
||||||
ChatType.Shout,
|
ChatType.Shout,
|
||||||
@@ -39,9 +44,11 @@ internal static class ChatTypeExt {
|
|||||||
ChatType.Linkshell8,
|
ChatType.Linkshell8,
|
||||||
ChatType.NoviceNetwork,
|
ChatType.NoviceNetwork,
|
||||||
ChatType.StandardEmote,
|
ChatType.StandardEmote,
|
||||||
ChatType.CustomEmote,
|
ChatType.CustomEmote
|
||||||
}),
|
]),
|
||||||
(Language.Options_Tabs_ChannelTypes_Battle, new[] {
|
|
||||||
|
(Language.Options_Tabs_ChannelTypes_Battle, new[]
|
||||||
|
{
|
||||||
ChatType.Damage,
|
ChatType.Damage,
|
||||||
ChatType.Miss,
|
ChatType.Miss,
|
||||||
ChatType.Action,
|
ChatType.Action,
|
||||||
@@ -52,7 +59,9 @@ internal static class ChatTypeExt {
|
|||||||
ChatType.GainDebuff,
|
ChatType.GainDebuff,
|
||||||
ChatType.LoseDebuff,
|
ChatType.LoseDebuff,
|
||||||
}),
|
}),
|
||||||
(Language.Options_Tabs_ChannelTypes_Announcements, new[] {
|
|
||||||
|
(Language.Options_Tabs_ChannelTypes_Announcements, new[]
|
||||||
|
{
|
||||||
ChatType.System,
|
ChatType.System,
|
||||||
ChatType.BattleSystem,
|
ChatType.BattleSystem,
|
||||||
ChatType.GatheringSystem,
|
ChatType.GatheringSystem,
|
||||||
@@ -80,8 +89,10 @@ internal static class ChatTypeExt {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
internal static string Name(this ChatType type) {
|
internal static string Name(this ChatType type)
|
||||||
return type switch {
|
{
|
||||||
|
return type switch
|
||||||
|
{
|
||||||
ChatType.Debug => Language.ChatType_Debug,
|
ChatType.Debug => Language.ChatType_Debug,
|
||||||
ChatType.Urgent => Language.ChatType_Urgent,
|
ChatType.Urgent => Language.ChatType_Urgent,
|
||||||
ChatType.Notice => Language.ChatType_Notice,
|
ChatType.Notice => Language.ChatType_Notice,
|
||||||
@@ -174,8 +185,10 @@ internal static class ChatTypeExt {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static uint? DefaultColour(this ChatType type) {
|
internal static uint? DefaultColour(this ChatType type)
|
||||||
switch (type) {
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
case ChatType.Debug:
|
case ChatType.Debug:
|
||||||
return ColourUtil.ComponentsToRgba(204, 204, 204);
|
return ColourUtil.ComponentsToRgba(204, 204, 204);
|
||||||
case ChatType.Urgent:
|
case ChatType.Urgent:
|
||||||
@@ -292,7 +305,8 @@ internal static class ChatTypeExt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static InputChannel? ToInputChannel(this ChatType type) => type switch {
|
internal static InputChannel? ToInputChannel(this ChatType type) => type switch
|
||||||
|
{
|
||||||
ChatType.TellOutgoing => InputChannel.Tell,
|
ChatType.TellOutgoing => InputChannel.Tell,
|
||||||
ChatType.Say => InputChannel.Say,
|
ChatType.Say => InputChannel.Say,
|
||||||
ChatType.Party => InputChannel.Party,
|
ChatType.Party => InputChannel.Party,
|
||||||
@@ -321,7 +335,8 @@ internal static class ChatTypeExt {
|
|||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
internal static bool IsGm(this ChatType type) => type switch {
|
internal static bool IsGm(this ChatType type) => type switch
|
||||||
|
{
|
||||||
ChatType.GmTell => true,
|
ChatType.GmTell => true,
|
||||||
ChatType.GmSay => true,
|
ChatType.GmSay => true,
|
||||||
ChatType.GmShout => true,
|
ChatType.GmShout => true,
|
||||||
@@ -340,7 +355,8 @@ internal static class ChatTypeExt {
|
|||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
internal static bool HasSource(this ChatType type) => type switch {
|
internal static bool HasSource(this ChatType type) => type switch
|
||||||
|
{
|
||||||
// Battle
|
// Battle
|
||||||
ChatType.Damage => true,
|
ChatType.Damage => true,
|
||||||
ChatType.Miss => true,
|
ChatType.Miss => true,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
namespace ChatTwo.Code;
|
namespace ChatTwo.Code;
|
||||||
|
|
||||||
internal enum InputChannel : uint {
|
internal enum InputChannel : uint
|
||||||
|
{
|
||||||
Tell = 0,
|
Tell = 0,
|
||||||
Say = 1,
|
Say = 1,
|
||||||
Party = 2,
|
Party = 2,
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ using Lumina.Excel.GeneratedSheets;
|
|||||||
|
|
||||||
namespace ChatTwo.Code;
|
namespace ChatTwo.Code;
|
||||||
|
|
||||||
internal static class InputChannelExt {
|
internal static class InputChannelExt
|
||||||
internal static ChatType ToChatType(this InputChannel input) => input switch {
|
{
|
||||||
|
internal static ChatType ToChatType(this InputChannel input) => input switch
|
||||||
|
{
|
||||||
InputChannel.Tell => ChatType.TellOutgoing,
|
InputChannel.Tell => ChatType.TellOutgoing,
|
||||||
InputChannel.Say => ChatType.Say,
|
InputChannel.Say => ChatType.Say,
|
||||||
InputChannel.Party => ChatType.Party,
|
InputChannel.Party => ChatType.Party,
|
||||||
@@ -41,7 +43,8 @@ internal static class InputChannelExt {
|
|||||||
_ => throw new ArgumentOutOfRangeException(nameof(input), input, null),
|
_ => throw new ArgumentOutOfRangeException(nameof(input), input, null),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static uint LinkshellIndex(this InputChannel channel) => channel switch {
|
public static uint LinkshellIndex(this InputChannel channel) => channel switch
|
||||||
|
{
|
||||||
InputChannel.Linkshell1 => 0,
|
InputChannel.Linkshell1 => 0,
|
||||||
InputChannel.Linkshell2 => 1,
|
InputChannel.Linkshell2 => 1,
|
||||||
InputChannel.Linkshell3 => 2,
|
InputChannel.Linkshell3 => 2,
|
||||||
@@ -69,7 +72,8 @@ internal static class InputChannelExt {
|
|||||||
_ => uint.MaxValue,
|
_ => uint.MaxValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
public static string Prefix(this InputChannel channel) => channel switch {
|
public static string Prefix(this InputChannel channel) => channel switch
|
||||||
|
{
|
||||||
InputChannel.Tell => "/tell",
|
InputChannel.Tell => "/tell",
|
||||||
InputChannel.Say => "/say",
|
InputChannel.Say => "/say",
|
||||||
InputChannel.Party => "/party",
|
InputChannel.Party => "/party",
|
||||||
@@ -106,52 +110,47 @@ internal static class InputChannelExt {
|
|||||||
_ => "",
|
_ => "",
|
||||||
};
|
};
|
||||||
|
|
||||||
public static IEnumerable<TextCommand>? TextCommands(this InputChannel channel, IDataManager data) {
|
public static IEnumerable<TextCommand>? TextCommands(this InputChannel channel, IDataManager data)
|
||||||
var ids = channel switch {
|
{
|
||||||
InputChannel.Tell => new uint[] { 104, 118 },
|
var ids = channel switch
|
||||||
InputChannel.Say => new uint[] { 102 },
|
{
|
||||||
InputChannel.Party => new uint[] { 105 },
|
InputChannel.Tell => [104, 118],
|
||||||
InputChannel.Alliance => new uint[] { 119 },
|
InputChannel.Say => [102],
|
||||||
InputChannel.Yell => new uint[] { 117 },
|
InputChannel.Party => [105],
|
||||||
InputChannel.Shout => new uint[] { 103 },
|
InputChannel.Alliance => [119],
|
||||||
InputChannel.FreeCompany => new uint[] { 115 },
|
InputChannel.Yell => [117],
|
||||||
InputChannel.PvpTeam => new uint[] { 91 },
|
InputChannel.Shout => [103],
|
||||||
InputChannel.NoviceNetwork => new uint[] { 101 },
|
InputChannel.FreeCompany => [115],
|
||||||
InputChannel.CrossLinkshell1 => new uint[] { 13 },
|
InputChannel.PvpTeam => [91],
|
||||||
InputChannel.CrossLinkshell2 => new uint[] { 14 },
|
InputChannel.NoviceNetwork => [101],
|
||||||
InputChannel.CrossLinkshell3 => new uint[] { 15 },
|
InputChannel.CrossLinkshell1 => [13],
|
||||||
InputChannel.CrossLinkshell4 => new uint[] { 16 },
|
InputChannel.CrossLinkshell2 => [14],
|
||||||
InputChannel.CrossLinkshell5 => new uint[] { 17 },
|
InputChannel.CrossLinkshell3 => [15],
|
||||||
InputChannel.CrossLinkshell6 => new uint[] { 18 },
|
InputChannel.CrossLinkshell4 => [16],
|
||||||
InputChannel.CrossLinkshell7 => new uint[] { 19 },
|
InputChannel.CrossLinkshell5 => [17],
|
||||||
InputChannel.CrossLinkshell8 => new uint[] { 20 },
|
InputChannel.CrossLinkshell6 => [18],
|
||||||
InputChannel.Linkshell1 => new uint[] { 107 },
|
InputChannel.CrossLinkshell7 => [19],
|
||||||
InputChannel.Linkshell2 => new uint[] { 108 },
|
InputChannel.CrossLinkshell8 => [20],
|
||||||
InputChannel.Linkshell3 => new uint[] { 109 },
|
InputChannel.Linkshell1 => [107],
|
||||||
InputChannel.Linkshell4 => new uint[] { 110 },
|
InputChannel.Linkshell2 => [108],
|
||||||
InputChannel.Linkshell5 => new uint[] { 111 },
|
InputChannel.Linkshell3 => [109],
|
||||||
InputChannel.Linkshell6 => new uint[] { 112 },
|
InputChannel.Linkshell4 => [110],
|
||||||
InputChannel.Linkshell7 => new uint[] { 113 },
|
InputChannel.Linkshell5 => [111],
|
||||||
InputChannel.Linkshell8 => new uint[] { 114 },
|
InputChannel.Linkshell6 => [112],
|
||||||
|
InputChannel.Linkshell7 => [113],
|
||||||
|
InputChannel.Linkshell8 => [114],
|
||||||
_ => Array.Empty<uint>(),
|
_ => Array.Empty<uint>(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ids.Length == 0) {
|
if (ids.Length == 0)
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
var cmds = data.GetExcelSheet<TextCommand>();
|
var cmds = data.GetExcelSheet<TextCommand>();
|
||||||
if (cmds == null) {
|
return cmds == null ? null : ids.Select(id => cmds.GetRow(id)).Where(id => id != null).Cast<TextCommand>();
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ids
|
internal static bool IsLinkshell(this InputChannel channel) => channel switch
|
||||||
.Select(id => cmds.GetRow(id))
|
{
|
||||||
.Where(id => id != null)
|
|
||||||
.Cast<TextCommand>();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static bool IsLinkshell(this InputChannel channel) => channel switch {
|
|
||||||
InputChannel.Linkshell1 => true,
|
InputChannel.Linkshell1 => true,
|
||||||
InputChannel.Linkshell2 => true,
|
InputChannel.Linkshell2 => true,
|
||||||
InputChannel.Linkshell3 => true,
|
InputChannel.Linkshell3 => true,
|
||||||
@@ -163,7 +162,8 @@ internal static class InputChannelExt {
|
|||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
internal static bool IsCrossLinkshell(this InputChannel channel) => channel switch {
|
internal static bool IsCrossLinkshell(this InputChannel channel) => channel switch
|
||||||
|
{
|
||||||
InputChannel.CrossLinkshell1 => true,
|
InputChannel.CrossLinkshell1 => true,
|
||||||
InputChannel.CrossLinkshell2 => true,
|
InputChannel.CrossLinkshell2 => true,
|
||||||
InputChannel.CrossLinkshell3 => true,
|
InputChannel.CrossLinkshell3 => true,
|
||||||
@@ -175,7 +175,8 @@ internal static class InputChannelExt {
|
|||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
internal static bool IsExtraChatLinkshell(this InputChannel channel) => channel switch {
|
internal static bool IsExtraChatLinkshell(this InputChannel channel) => channel switch
|
||||||
|
{
|
||||||
InputChannel.ExtraChatLinkshell1 => true,
|
InputChannel.ExtraChatLinkshell1 => true,
|
||||||
InputChannel.ExtraChatLinkshell2 => true,
|
InputChannel.ExtraChatLinkshell2 => true,
|
||||||
InputChannel.ExtraChatLinkshell3 => true,
|
InputChannel.ExtraChatLinkshell3 => true,
|
||||||
|
|||||||
+130
-122
@@ -36,9 +36,6 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
[Signature("E8 ?? ?? ?? ?? 48 8D 4D A0 8B F8")]
|
[Signature("E8 ?? ?? ?? ?? 48 8D 4D A0 8B F8")]
|
||||||
private readonly delegate* unmanaged<IntPtr, Utf8String*, IntPtr, uint> GetKeybindNative = null!;
|
private readonly delegate* unmanaged<IntPtr, Utf8String*, IntPtr, uint> GetKeybindNative = null!;
|
||||||
|
|
||||||
[Signature("E8 ?? ?? ?? ?? 48 3B F0 74 35")]
|
|
||||||
private readonly delegate* unmanaged<AtkStage*, IntPtr> GetFocus = null!;
|
|
||||||
|
|
||||||
[Signature("44 8B 89 ?? ?? ?? ?? 4C 8B C1 45 85 C9")]
|
[Signature("44 8B 89 ?? ?? ?? ?? 4C 8B C1 45 85 C9")]
|
||||||
private readonly delegate* unmanaged<void*, int, IntPtr> GetTellHistory = null!;
|
private readonly delegate* unmanaged<void*, int, IntPtr> GetTellHistory = null!;
|
||||||
|
|
||||||
@@ -72,6 +69,10 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
[Signature("E8 ?? ?? ?? ?? EB 0A 48 8D 4C 24 ?? E8 ?? ?? ?? ?? 48 8D 8D")]
|
[Signature("E8 ?? ?? ?? ?? EB 0A 48 8D 4C 24 ?? E8 ?? ?? ?? ?? 48 8D 8D")]
|
||||||
private readonly delegate* unmanaged<Utf8String*, int, IntPtr, void> SanitiseString = null!;
|
private readonly delegate* unmanaged<Utf8String*, int, IntPtr, void> SanitiseString = null!;
|
||||||
|
|
||||||
|
// Currently Unused
|
||||||
|
[Signature("E8 ?? ?? ?? ?? 48 3B F0 74 35")]
|
||||||
|
private readonly delegate* unmanaged<AtkStage*, IntPtr> GetFocus = null!;
|
||||||
|
|
||||||
// Hooks
|
// Hooks
|
||||||
|
|
||||||
private delegate byte ChatLogRefreshDelegate(IntPtr log, ushort eventId, AtkValue* value);
|
private delegate byte ChatLogRefreshDelegate(IntPtr log, ushort eventId, AtkValue* value);
|
||||||
@@ -155,7 +156,8 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
internal bool UsesTellTempChannel { get; set; }
|
internal bool UsesTellTempChannel { get; set; }
|
||||||
internal InputChannel? PreviousChannel { get; private set; }
|
internal InputChannel? PreviousChannel { get; private set; }
|
||||||
|
|
||||||
internal Chat(Plugin plugin) {
|
internal Chat(Plugin plugin)
|
||||||
|
{
|
||||||
Plugin = plugin;
|
Plugin = plugin;
|
||||||
Plugin.GameInteropProvider.InitializeFromAttributes(this);
|
Plugin.GameInteropProvider.InitializeFromAttributes(this);
|
||||||
|
|
||||||
@@ -203,21 +205,21 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal string? GetCrossLinkshellName(uint idx) {
|
internal string? GetCrossLinkshellName(uint idx) {
|
||||||
if (CrossLinkshellInfoProxyIdx is not { } proxyIdx) {
|
if (CrossLinkshellInfoProxyIdx is not { } proxyIdx)
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
var infoProxy = Plugin.Functions.GetInfoProxyByIndex(proxyIdx);
|
var infoProxy = Plugin.Functions.GetInfoProxyByIndex(proxyIdx);
|
||||||
if (infoProxy == IntPtr.Zero) {
|
if (infoProxy == IntPtr.Zero)
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
var utf = GetCrossLinkshellNameNative(infoProxy, idx);
|
var utf = GetCrossLinkshellNameNative(infoProxy, idx);
|
||||||
return utf == null ? null : utf->ToString();
|
return utf == null ? null : utf->ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ulong RotateLinkshellHistory(RotateMode mode) {
|
internal ulong RotateLinkshellHistory(RotateMode mode)
|
||||||
if (mode == RotateMode.None && LinkshellCycleOffset != null) {
|
{
|
||||||
|
if (mode == RotateMode.None && LinkshellCycleOffset != null)
|
||||||
|
{
|
||||||
// for the branch at 6.08: 5E1680
|
// for the branch at 6.08: 5E1680
|
||||||
var uiModule = (IntPtr) Framework.Instance()->GetUiModule();
|
var uiModule = (IntPtr) Framework.Instance()->GetUiModule();
|
||||||
*(int*) (uiModule + LinkshellCycleOffset.Value) = -1;
|
*(int*) (uiModule + LinkshellCycleOffset.Value) = -1;
|
||||||
@@ -230,11 +232,11 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
|
|
||||||
private static ulong RotateLinkshellHistoryInternal(delegate* unmanaged<UIModule*, int, ulong> func, RotateMode mode) {
|
private static ulong RotateLinkshellHistoryInternal(delegate* unmanaged<UIModule*, int, ulong> func, RotateMode mode) {
|
||||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||||
if (func == null) {
|
if (func == null)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
var idx = mode switch {
|
var idx = mode switch
|
||||||
|
{
|
||||||
RotateMode.Forward => 1,
|
RotateMode.Forward => 1,
|
||||||
RotateMode.Reverse => -1,
|
RotateMode.Reverse => -1,
|
||||||
_ => 0,
|
_ => 0,
|
||||||
@@ -248,9 +250,8 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
//
|
//
|
||||||
// If this function would ever return 0, it returns null instead.
|
// If this function would ever return 0, it returns null instead.
|
||||||
internal uint? GetChannelColour(ChatType type) {
|
internal uint? GetChannelColour(ChatType type) {
|
||||||
if (GetColourInfo == null || ColourLookup == IntPtr.Zero) {
|
if (GetColourInfo == null || ColourLookup == IntPtr.Zero)
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
// Colours are retrieved by looking up their code in a lookup table. Some codes share a colour, so they're lumped into a parent code here.
|
// Colours are retrieved by looking up their code in a lookup table. Some codes share a colour, so they're lumped into a parent code here.
|
||||||
// Only codes >= 10 (say) have configurable colours.
|
// Only codes >= 10 (say) have configurable colours.
|
||||||
@@ -272,9 +273,8 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
var info = GetColourInfo(framework + 16, lookupResult);
|
var info = GetColourInfo(framework + 16, lookupResult);
|
||||||
var rgb = *(uint*) (info + 32) & 0xFFFFFF;
|
var rgb = *(uint*) (info + 32) & 0xFFFFFF;
|
||||||
|
|
||||||
if (rgb == 0) {
|
if (rgb == 0)
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
return 0xFF | (rgb << 8);
|
return 0xFF | (rgb << 8);
|
||||||
}
|
}
|
||||||
@@ -350,154 +350,161 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
private int _graceFrames;
|
private int _graceFrames;
|
||||||
|
|
||||||
|
|
||||||
private void CheckFocus() {
|
private void CheckFocus()
|
||||||
void Decrement() {
|
{
|
||||||
if (_graceFrames > 0) {
|
void Decrement()
|
||||||
|
{
|
||||||
|
if (_graceFrames > 0)
|
||||||
_graceFrames -= 1;
|
_graceFrames -= 1;
|
||||||
} else {
|
else
|
||||||
_inputFocused = false;
|
_inputFocused = false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 6.08: CB8F27
|
// 6.08: CB8F27
|
||||||
var isTextInputActivePtr = *(bool**) ((IntPtr) AtkStage.GetSingleton() + 0x28) + 0x188E;
|
var isTextInputActivePtr = *(bool**) ((IntPtr) AtkStage.GetSingleton() + 0x28) + 0x188E;
|
||||||
if (isTextInputActivePtr == null) {
|
if (isTextInputActivePtr == null)
|
||||||
|
{
|
||||||
Decrement();
|
Decrement();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*isTextInputActivePtr) {
|
if (*isTextInputActivePtr)
|
||||||
|
{
|
||||||
_inputFocused = true;
|
_inputFocused = true;
|
||||||
_graceFrames = 60;
|
_graceFrames = 60;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Decrement();
|
Decrement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateKeybinds() {
|
private void UpdateKeybinds()
|
||||||
foreach (var name in KeybindsToIntercept.Keys) {
|
{
|
||||||
|
foreach (var name in KeybindsToIntercept.Keys)
|
||||||
|
{
|
||||||
var keybind = GetKeybind(name);
|
var keybind = GetKeybind(name);
|
||||||
if (keybind is null) {
|
if (keybind is null)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
_keybinds[name] = keybind;
|
_keybinds[name] = keybind;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InterceptKeybinds(IFramework framework1) {
|
private void InterceptKeybinds(IFramework framework1)
|
||||||
|
{
|
||||||
CheckFocus();
|
CheckFocus();
|
||||||
UpdateKeybinds();
|
UpdateKeybinds();
|
||||||
|
|
||||||
if (_inputFocused) {
|
if (_inputFocused)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
var modifierState = (ModifierFlag) 0;
|
var modifierState = (ModifierFlag) 0;
|
||||||
foreach (var modifier in Enum.GetValues<ModifierFlag>()) {
|
foreach (var modifier in Enum.GetValues<ModifierFlag>())
|
||||||
|
{
|
||||||
var modifierKey = GetKeyForModifier(modifier);
|
var modifierKey = GetKeyForModifier(modifier);
|
||||||
if (modifierKey != VirtualKey.NO_KEY && Plugin.KeyState[modifierKey]) {
|
if (modifierKey != VirtualKey.NO_KEY && Plugin.KeyState[modifierKey])
|
||||||
modifierState |= modifier;
|
modifierState |= modifier;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var turnedOff = new Dictionary<VirtualKey, (uint, string)>();
|
var turnedOff = new Dictionary<VirtualKey, (uint, string)>();
|
||||||
foreach (var toIntercept in KeybindsToIntercept.Keys) {
|
foreach (var toIntercept in KeybindsToIntercept.Keys)
|
||||||
if (!Keybinds.TryGetValue(toIntercept, out var keybind)) {
|
{
|
||||||
|
if (!Keybinds.TryGetValue(toIntercept, out var keybind))
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
void Intercept(VirtualKey key, ModifierFlag modifier) {
|
void Intercept(VirtualKey key, ModifierFlag modifier)
|
||||||
if (!Plugin.KeyState.IsVirtualKeyValid(key)) {
|
{
|
||||||
|
if (!Plugin.KeyState.IsVirtualKeyValid(key))
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
var modifierPressed = Plugin.Config.KeybindMode switch {
|
var modifierPressed = Plugin.Config.KeybindMode switch
|
||||||
|
{
|
||||||
KeybindMode.Strict => modifier == modifierState,
|
KeybindMode.Strict => modifier == modifierState,
|
||||||
KeybindMode.Flexible => modifierState.HasFlag(modifier),
|
KeybindMode.Flexible => modifierState.HasFlag(modifier),
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if (!modifierPressed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Plugin.KeyState[key]) {
|
if (!modifierPressed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!Plugin.KeyState[key])
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
var bits = BitOperations.PopCount((uint) modifier);
|
var bits = BitOperations.PopCount((uint) modifier);
|
||||||
if (!turnedOff.TryGetValue(key, out var previousBits) || previousBits.Item1 < bits) {
|
if (!turnedOff.TryGetValue(key, out var previousBits) || previousBits.Item1 < bits)
|
||||||
turnedOff[key] = ((uint) bits, toIntercept);
|
turnedOff[key] = ((uint) bits, toIntercept);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Intercept(keybind.Key1, keybind.Modifier1);
|
Intercept(keybind.Key1, keybind.Modifier1);
|
||||||
Intercept(keybind.Key2, keybind.Modifier2);
|
Intercept(keybind.Key2, keybind.Modifier2);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (key, (_, keybind)) in turnedOff) {
|
foreach (var (key, (_, keybind)) in turnedOff)
|
||||||
|
{
|
||||||
Plugin.KeyState[key] = false;
|
Plugin.KeyState[key] = false;
|
||||||
|
if (!KeybindsToIntercept.TryGetValue(keybind, out var info))
|
||||||
if (!KeybindsToIntercept.TryGetValue(keybind, out var info)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try
|
||||||
Activated?.Invoke(new ChatActivatedArgs(info) {
|
{
|
||||||
TellReason = TellReason.Reply,
|
Activated?.Invoke(new ChatActivatedArgs(info) { TellReason = TellReason.Reply, });
|
||||||
});
|
}
|
||||||
} catch (Exception ex) {
|
catch (Exception ex)
|
||||||
|
{
|
||||||
Plugin.Log.Error(ex, "Error in chat Activated event");
|
Plugin.Log.Error(ex, "Error in chat Activated event");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Login() {
|
private void Login() {
|
||||||
if (ChangeChannelNameHook == null) {
|
if (ChangeChannelNameHook == null)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
var agent = Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.ChatLog);
|
var agent = Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.ChatLog);
|
||||||
if (agent == null) {
|
if (agent == null)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
ChangeChannelNameDetour((IntPtr) agent);
|
ChangeChannelNameDetour((IntPtr) agent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte ChatLogRefreshDetour(IntPtr log, ushort eventId, AtkValue* value) {
|
private byte ChatLogRefreshDetour(IntPtr log, ushort eventId, AtkValue* value)
|
||||||
if (eventId != 0x31 || value == null || value->UInt is not (0x05 or 0x0C)) {
|
{
|
||||||
|
if (eventId != 0x31 || value == null || value->UInt is not (0x05 or 0x0C))
|
||||||
return ChatLogRefreshHook!.Original(log, eventId, value);
|
return ChatLogRefreshHook!.Original(log, eventId, value);
|
||||||
}
|
|
||||||
|
|
||||||
string? input = null;
|
string? input = null;
|
||||||
if (Plugin.GameConfig.TryGet(UiControlOption.DirectChat, out bool option) && option) {
|
if (Plugin.GameConfig.TryGet(UiControlOption.DirectChat, out bool option) && option)
|
||||||
if (CurrentCharacter != null) {
|
{
|
||||||
|
if (CurrentCharacter != null)
|
||||||
|
{
|
||||||
// FIXME: this whole system sucks
|
// FIXME: this whole system sucks
|
||||||
var c = *CurrentCharacter;
|
var c = *CurrentCharacter;
|
||||||
if (c != '\0' && !char.IsControl(c)) {
|
if (c != '\0' && !char.IsControl(c))
|
||||||
input = c.ToString();
|
input = c.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
string? addIfNotPresent = null;
|
string? addIfNotPresent = null;
|
||||||
|
|
||||||
var str = value + 2;
|
var str = value + 2;
|
||||||
if (str != null && ((int) str->Type & 0xF) == (int) ValueType.String && str->String != null) {
|
if (str != null && ((int) str->Type & 0xF) == (int) ValueType.String && str->String != null)
|
||||||
|
{
|
||||||
var add = MemoryHelper.ReadStringNullTerminated((IntPtr) str->String);
|
var add = MemoryHelper.ReadStringNullTerminated((IntPtr) str->String);
|
||||||
if (add.Length > 0) {
|
if (add.Length > 0)
|
||||||
addIfNotPresent = add;
|
addIfNotPresent = add;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
var args = new ChatActivatedArgs(new ChannelSwitchInfo(null)) {
|
var args = new ChatActivatedArgs(new ChannelSwitchInfo(null)) {
|
||||||
AddIfNotPresent = addIfNotPresent,
|
AddIfNotPresent = addIfNotPresent,
|
||||||
Input = input,
|
Input = input,
|
||||||
};
|
};
|
||||||
Activated?.Invoke(args);
|
Activated?.Invoke(args);
|
||||||
} catch (Exception ex) {
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
Plugin.Log.Error(ex, "Error in chat Activated event");
|
Plugin.Log.Error(ex, "Error in chat Activated event");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,66 +512,60 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntPtr ChangeChannelNameDetour(IntPtr agent) {
|
private IntPtr ChangeChannelNameDetour(IntPtr agent)
|
||||||
|
{
|
||||||
// Last ShB patch
|
// Last ShB patch
|
||||||
// +0x40 = chat channel (byte or uint?)
|
// +0x40 = chat channel (byte or uint?)
|
||||||
// channel is 17 (maybe 18?) for tells
|
// channel is 17 (maybe 18?) for tells
|
||||||
// +0x48 = pointer to channel name string
|
// +0x48 = pointer to channel name string
|
||||||
var ret = ChangeChannelNameHook!.Original(agent);
|
var ret = ChangeChannelNameHook!.Original(agent);
|
||||||
if (agent == IntPtr.Zero) {
|
if (agent == IntPtr.Zero)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
// E8 ?? ?? ?? ?? 8D 48 F7
|
// E8 ?? ?? ?? ?? 8D 48 F7
|
||||||
// RaptureShellModule + 0xFD0
|
// RaptureShellModule + 0xFD0
|
||||||
var shellModule = (IntPtr) Framework.Instance()->GetUiModule()->GetRaptureShellModule();
|
var shellModule = (IntPtr) Framework.Instance()->GetUiModule()->GetRaptureShellModule();
|
||||||
if (shellModule == IntPtr.Zero) {
|
if (shellModule == IntPtr.Zero)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
var channel = 0u;
|
var channel = 0u;
|
||||||
if (ShellChannelOffset != null) {
|
if (ShellChannelOffset != null)
|
||||||
channel = *(uint*) (shellModule + ShellChannelOffset.Value);
|
channel = *(uint*) (shellModule + ShellChannelOffset.Value);
|
||||||
}
|
|
||||||
|
|
||||||
// var channel = *(uint*) (agent + 0x40);
|
// var channel = *(uint*) (agent + 0x40);
|
||||||
if (channel is 17 or 18) {
|
if (channel is 17 or 18)
|
||||||
channel = 0;
|
channel = 0;
|
||||||
}
|
|
||||||
|
|
||||||
SeString? name = null;
|
SeString? name = null;
|
||||||
var namePtrPtr = (byte**) (agent + 0x48);
|
var namePtrPtr = (byte**) (agent + 0x48);
|
||||||
if (namePtrPtr != null) {
|
if (namePtrPtr != null)
|
||||||
|
{
|
||||||
var namePtr = *namePtrPtr;
|
var namePtr = *namePtrPtr;
|
||||||
name = MemoryHelper.ReadSeStringNullTerminated((IntPtr) namePtr);
|
name = MemoryHelper.ReadSeStringNullTerminated((IntPtr) namePtr);
|
||||||
if (name.Payloads.Count == 0) {
|
if (name.Payloads.Count == 0)
|
||||||
name = null;
|
name = null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (name == null) {
|
if (name == null)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
var nameChunks = ChunkUtil.ToChunks(name, ChunkSource.None, null).ToList();
|
var nameChunks = ChunkUtil.ToChunks(name, ChunkSource.None, null).ToList();
|
||||||
if (nameChunks.Count > 0 && nameChunks[0] is TextChunk text) {
|
if (nameChunks.Count > 0 && nameChunks[0] is TextChunk text)
|
||||||
text.Content = text.Content.TrimStart('\uE01E').TrimStart();
|
text.Content = text.Content.TrimStart('\uE01E').TrimStart();
|
||||||
}
|
|
||||||
|
|
||||||
Channel = ((InputChannel) channel, nameChunks);
|
Channel = ((InputChannel) channel, nameChunks);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReplyInSelectedChatModeDetour(AgentInterface* agent) {
|
private void ReplyInSelectedChatModeDetour(AgentInterface* agent)
|
||||||
if (ReplyChannelOffset == null) {
|
{
|
||||||
|
if (ReplyChannelOffset == null)
|
||||||
goto Original;
|
goto Original;
|
||||||
}
|
|
||||||
|
|
||||||
var replyMode = *(int*) ((IntPtr) agent + ReplyChannelOffset.Value);
|
var replyMode = *(int*) ((IntPtr) agent + ReplyChannelOffset.Value);
|
||||||
if (replyMode == -2) {
|
if (replyMode == -2)
|
||||||
goto Original;
|
goto Original;
|
||||||
}
|
|
||||||
|
|
||||||
SetChannel((InputChannel) replyMode);
|
SetChannel((InputChannel) replyMode);
|
||||||
|
|
||||||
@@ -572,15 +573,21 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
ReplyInSelectedChatModeHook!.Original(agent);
|
ReplyInSelectedChatModeHook!.Original(agent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte SetChatLogTellTargetDetour(IntPtr a1, Utf8String* name, Utf8String* a3, ushort world, ulong contentId, ushort reason, byte a7) {
|
private byte SetChatLogTellTargetDetour(IntPtr a1, Utf8String* name, Utf8String* a3, ushort world, ulong contentId, ushort reason, byte a7)
|
||||||
if (name != null) {
|
{
|
||||||
try {
|
if (name != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
var target = new TellTarget(name->ToString(), world, contentId, (TellReason) reason);
|
var target = new TellTarget(name->ToString(), world, contentId, (TellReason) reason);
|
||||||
Activated?.Invoke(new ChatActivatedArgs(new ChannelSwitchInfo(InputChannel.Tell)) {
|
Activated?.Invoke(new ChatActivatedArgs(new ChannelSwitchInfo(InputChannel.Tell))
|
||||||
|
{
|
||||||
TellReason = (TellReason) reason,
|
TellReason = (TellReason) reason,
|
||||||
TellTarget = target,
|
TellTarget = target,
|
||||||
});
|
});
|
||||||
} catch (Exception ex) {
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
Plugin.Log.Error(ex, "Error in chat Activated event");
|
Plugin.Log.Error(ex, "Error in chat Activated event");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -602,15 +609,16 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
EurekaContextMenuTellHook!.Original(param1, playerName, worldName, world, id, param6);
|
EurekaContextMenuTellHook!.Original(param1, playerName, worldName, world, id, param6);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ulong? GetContentIdForEntry(uint index) {
|
internal ulong? GetContentIdForEntry(uint index)
|
||||||
if (GetContentIdForChatEntry == null) {
|
{
|
||||||
|
if (GetContentIdForChatEntry == null)
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
return GetContentIdForChatEntry(Framework.Instance()->GetUiModule()->GetRaptureLogModule(), index);
|
return GetContentIdForChatEntry(Framework.Instance()->GetUiModule()->GetRaptureLogModule(), index);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SetChannel(InputChannel channel, string? tellTarget = null) {
|
internal void SetChannel(InputChannel channel, string? tellTarget = null)
|
||||||
|
{
|
||||||
// ExtraChat linkshells aren't supported in game so we never want to
|
// ExtraChat linkshells aren't supported in game so we never want to
|
||||||
// call the ChangeChatChannel function with them.
|
// call the ChangeChatChannel function with them.
|
||||||
//
|
//
|
||||||
@@ -651,23 +659,23 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
utfWorld->Dtor(true);
|
utfWorld->Dtor(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static VirtualKey GetKeyForModifier(ModifierFlag modifierFlag) => modifierFlag switch {
|
private static VirtualKey GetKeyForModifier(ModifierFlag modifierFlag) => modifierFlag switch
|
||||||
|
{
|
||||||
ModifierFlag.Shift => VirtualKey.SHIFT,
|
ModifierFlag.Shift => VirtualKey.SHIFT,
|
||||||
ModifierFlag.Ctrl => VirtualKey.CONTROL,
|
ModifierFlag.Ctrl => VirtualKey.CONTROL,
|
||||||
ModifierFlag.Alt => VirtualKey.MENU,
|
ModifierFlag.Alt => VirtualKey.MENU,
|
||||||
_ => VirtualKey.NO_KEY,
|
_ => VirtualKey.NO_KEY,
|
||||||
};
|
};
|
||||||
|
|
||||||
private Keybind? GetKeybind(string id) {
|
private Keybind? GetKeybind(string id)
|
||||||
|
{
|
||||||
var agent = (IntPtr) Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.Configkey);
|
var agent = (IntPtr) Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.Configkey);
|
||||||
if (agent == IntPtr.Zero) {
|
if (agent == IntPtr.Zero)
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
var a1 = *(void**) (agent + 0x78);
|
var a1 = *(void**) (agent + 0x78);
|
||||||
if (a1 == null) {
|
if (a1 == null)
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
var outData = stackalloc byte[32];
|
var outData = stackalloc byte[32];
|
||||||
var idString = Utf8String.FromString(id);
|
var idString = Utf8String.FromString(id);
|
||||||
@@ -675,16 +683,15 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
idString->Dtor(true);
|
idString->Dtor(true);
|
||||||
|
|
||||||
var key1 = (VirtualKey) outData[0];
|
var key1 = (VirtualKey) outData[0];
|
||||||
if (key1 is VirtualKey.F23) {
|
if (key1 is VirtualKey.F23)
|
||||||
key1 = VirtualKey.OEM_2;
|
key1 = VirtualKey.OEM_2;
|
||||||
}
|
|
||||||
|
|
||||||
var key2 = (VirtualKey) outData[2];
|
var key2 = (VirtualKey) outData[2];
|
||||||
if (key2 is VirtualKey.F23) {
|
if (key2 is VirtualKey.F23)
|
||||||
key2 = VirtualKey.OEM_2;
|
key2 = VirtualKey.OEM_2;
|
||||||
}
|
|
||||||
|
|
||||||
return new Keybind {
|
return new Keybind
|
||||||
|
{
|
||||||
Key1 = key1,
|
Key1 = key1,
|
||||||
Modifier1 = (ModifierFlag) outData[1],
|
Modifier1 = (ModifierFlag) outData[1],
|
||||||
Key2 = key2,
|
Key2 = key2,
|
||||||
@@ -692,16 +699,15 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
internal TellHistoryInfo? GetTellHistoryInfo(int index) {
|
internal TellHistoryInfo? GetTellHistoryInfo(int index)
|
||||||
|
{
|
||||||
var acquaintanceModule = Framework.Instance()->GetUiModule()->GetAcquaintanceModule();
|
var acquaintanceModule = Framework.Instance()->GetUiModule()->GetAcquaintanceModule();
|
||||||
if (acquaintanceModule == null) {
|
if (acquaintanceModule == null)
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
var ptr = GetTellHistory(acquaintanceModule, index);
|
var ptr = GetTellHistory(acquaintanceModule, index);
|
||||||
if (ptr == IntPtr.Zero) {
|
if (ptr == IntPtr.Zero)
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
var name = MemoryHelper.ReadStringNullTerminated(*(IntPtr*) ptr);
|
var name = MemoryHelper.ReadStringNullTerminated(*(IntPtr*) ptr);
|
||||||
var world = *(ushort*) (ptr + 0xD0);
|
var world = *(ushort*) (ptr + 0xD0);
|
||||||
@@ -710,7 +716,8 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
return new TellHistoryInfo(name, world, contentId);
|
return new TellHistoryInfo(name, world, contentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SendTell(TellReason reason, ulong contentId, string name, ushort homeWorld, byte[] message) {
|
internal void SendTell(TellReason reason, ulong contentId, string name, ushort homeWorld, byte[] message)
|
||||||
|
{
|
||||||
var uName = Utf8String.FromString(name);
|
var uName = Utf8String.FromString(name);
|
||||||
var uMessage = Utf8String.FromSequence(message);
|
var uMessage = Utf8String.FromSequence(message);
|
||||||
|
|
||||||
@@ -725,7 +732,8 @@ internal sealed unsafe class Chat : IDisposable {
|
|||||||
uMessage->Dtor(true);
|
uMessage->Dtor(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool IsCharValid(char c) {
|
internal bool IsCharValid(char c)
|
||||||
|
{
|
||||||
var uC = Utf8String.FromString(c.ToString());
|
var uC = Utf8String.FromString(c.ToString());
|
||||||
|
|
||||||
SanitiseString(uC, 0x27F, IntPtr.Zero);
|
SanitiseString(uC, 0x27F, IntPtr.Zero);
|
||||||
|
|||||||
Reference in New Issue
Block a user