Compare commits

...

No commits in common. "v1.18.0" and "main" have entirely different histories.

55 changed files with 3754 additions and 8050 deletions

View File

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<Version>1.18.0</Version> <Version>1.18.10</Version>
<TargetFramework>net6.0-windows</TargetFramework> <TargetFramework>net7.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@ -39,10 +39,6 @@
<HintPath>$(DalamudLibPath)\ImGui.NET.dll</HintPath> <HintPath>$(DalamudLibPath)\ImGui.NET.dll</HintPath>
<Private>false</Private> <Private>false</Private>
</Reference> </Reference>
<Reference Include="ImGuiScene">
<HintPath>$(DalamudLibPath)\ImGuiScene.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Lumina"> <Reference Include="Lumina">
<HintPath>$(DalamudLibPath)\Lumina.dll</HintPath> <HintPath>$(DalamudLibPath)\Lumina.dll</HintPath>
<Private>false</Private> <Private>false</Private>
@ -54,11 +50,11 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DalamudPackager" Version="2.1.8"/> <PackageReference Include="DalamudPackager" Version="2.1.12"/>
<PackageReference Include="LiteDB" Version="5.0.12"/> <PackageReference Include="LiteDB" Version="5.0.17"/>
<PackageReference Include="Pidgin" Version="3.2.0"/> <PackageReference Include="Pidgin" Version="3.2.2"/>
<PackageReference Include="SharpDX.Direct2D1" Version="4.2.0"/> <PackageReference Include="SharpDX.Direct2D1" Version="4.2.0"/>
<PackageReference Include="XivCommon" Version="6.0.1"/> <PackageReference Include="XivCommon" Version="9.0.0"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,5 +1,5 @@
name: Chat 2 name: Chat 2
author: ascclemens author: Anna
punchline: Electric Boogaloo - ♪ A whole new chat, a new fantastic chat window ♪ punchline: Electric Boogaloo - ♪ A whole new chat, a new fantastic chat window ♪
description: |- description: |-
Chat 2 is a complete rewrite of the in-game chat window as a plugin. It Chat 2 is a complete rewrite of the in-game chat window as a plugin. It
@ -13,6 +13,6 @@ description: |-
- Sidebar tabs - Sidebar tabs
- Unread counts - Unread counts
- Screenshot mode (obfuscate names) - Screenshot mode (obfuscate names)
repo_url: https://git.annaclemens.io/ascclemens/ChatTwo repo_url: https://git.anna.lgbt/anna/ChatTwo
accepts_feedback: false accepts_feedback: false
feedback_message: Submit only bugs to https://github.com/ascclemens/plugin-issues feedback_message: Submit only bugs to https://github.com/anna/plugin-issues

View File

@ -1,4 +1,4 @@
using Dalamud.Data; using Dalamud.Plugin.Services;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
namespace ChatTwo.Code; namespace ChatTwo.Code;
@ -82,7 +82,7 @@ internal static class InputChannelExt {
_ => "", _ => "",
}; };
public static IEnumerable<TextCommand>? TextCommands(this InputChannel channel, DataManager data) { public static IEnumerable<TextCommand>? TextCommands(this InputChannel channel, IDataManager data) {
var ids = channel switch { var ids = channel switch {
InputChannel.Tell => new uint[] { 104, 118 }, InputChannel.Tell => new uint[] { 104, 118 },
InputChannel.Say => new uint[] { 102 }, InputChannel.Say => new uint[] { 102 },

View File

@ -1,5 +1,4 @@
using Dalamud.Game.Command; using Dalamud.Game.Command;
using Dalamud.Logging;
namespace ChatTwo; namespace ChatTwo;
@ -45,14 +44,14 @@ internal sealed class Commands : IDisposable {
private void Invoke(string command, string arguments) { private void Invoke(string command, string arguments) {
if (!this.Registered.TryGetValue(command, out var wrapper)) { if (!this.Registered.TryGetValue(command, out var wrapper)) {
PluginLog.Warning($"Missing registration for command {command}"); Plugin.Log.Warning($"Missing registration for command {command}");
return; return;
} }
try { try {
wrapper.Invoke(command, arguments); wrapper.Invoke(command, arguments);
} catch (Exception ex) { } catch (Exception ex) {
PluginLog.Error(ex, $"Error while executing command {command}"); Plugin.Log.Error(ex, $"Error while executing command {command}");
} }
} }
} }

View File

@ -2,8 +2,6 @@ using ChatTwo.Code;
using ChatTwo.Resources; using ChatTwo.Resources;
using ChatTwo.Ui; using ChatTwo.Ui;
using Dalamud.Configuration; using Dalamud.Configuration;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Logging;
using ImGuiNET; using ImGuiNET;
namespace ChatTwo; namespace ChatTwo;
@ -11,6 +9,7 @@ namespace ChatTwo;
[Serializable] [Serializable]
internal class Configuration : IPluginConfiguration { internal class Configuration : IPluginConfiguration {
private const int LatestVersion = 5; private const int LatestVersion = 5;
internal const int LatestDbVersion = 1;
public int Version { get; set; } = LatestVersion; public int Version { get; set; } = LatestVersion;
@ -50,6 +49,8 @@ internal class Configuration : IPluginConfiguration {
public Dictionary<ChatType, uint> ChatColours = new(); public Dictionary<ChatType, uint> ChatColours = new();
public List<Tab> Tabs = new(); public List<Tab> Tabs = new();
public uint DatabaseMigration = LatestDbVersion;
internal void UpdateFrom(Configuration other) { internal void UpdateFrom(Configuration other) {
this.HideChat = other.HideChat; this.HideChat = other.HideChat;
this.HideDuringCutscenes = other.HideDuringCutscenes; this.HideDuringCutscenes = other.HideDuringCutscenes;
@ -84,6 +85,7 @@ internal class Configuration : IPluginConfiguration {
this.WindowAlpha = other.WindowAlpha; this.WindowAlpha = other.WindowAlpha;
this.ChatColours = other.ChatColours.ToDictionary(entry => entry.Key, entry => entry.Value); this.ChatColours = other.ChatColours.ToDictionary(entry => entry.Key, entry => entry.Value);
this.Tabs = other.Tabs.Select(t => t.Clone()).ToList(); this.Tabs = other.Tabs.Select(t => t.Clone()).ToList();
this.DatabaseMigration = other.DatabaseMigration;
} }
public void Migrate() { public void Migrate() {
@ -121,7 +123,7 @@ internal class Configuration : IPluginConfiguration {
break; break;
default: default:
PluginLog.Warning($"Couldn't migrate config version {this.Version}"); Plugin.Log.Warning($"Couldn't migrate config version {this.Version}");
loop = false; loop = false;
break; break;
} }
@ -173,7 +175,7 @@ internal class Tab {
public uint Unread; public uint Unread;
[NonSerialized] [NonSerialized]
public Mutex MessagesMutex = new(); public SemaphoreSlim MessagesMutex = new(1, 1);
[NonSerialized] [NonSerialized]
public List<Message> Messages = new(); public List<Message> Messages = new();
@ -183,13 +185,8 @@ internal class Tab {
} }
internal bool Matches(Message message) { internal bool Matches(Message message) {
if (message.ContentSource.Payloads.Count > 0 && message.ContentSource.Payloads[0] is RawPayload raw) { if (message.ExtraChatChannel != Guid.Empty) {
// this does an encode and clone every time it's accessed, so cache return this.ExtraChatAll || this.ExtraChatChannels.Contains(message.ExtraChatChannel);
var data = raw.Data;
if (data[1] == 0x27 && data[2] == 18 && data[3] == 0x20) {
var extraChatChannel = new Guid(data[4..^1]);
return this.ExtraChatAll || this.ExtraChatChannels.Contains(extraChatChannel);
}
} }
return message.Code.Type.IsGm() return message.Code.Type.IsGm()
@ -197,13 +194,13 @@ internal class Tab {
} }
internal void AddMessage(Message message, bool unread = true) { internal void AddMessage(Message message, bool unread = true) {
this.MessagesMutex.WaitOne(); this.MessagesMutex.Wait();
this.Messages.Add(message); this.Messages.Add(message);
while (this.Messages.Count > Store.MessagesLimit) { while (this.Messages.Count > Store.MessagesLimit) {
this.Messages.RemoveAt(0); this.Messages.RemoveAt(0);
} }
this.MessagesMutex.ReleaseMutex(); this.MessagesMutex.Release();
if (unread) { if (unread) {
this.Unread += 1; this.Unread += 1;
@ -211,9 +208,9 @@ internal class Tab {
} }
internal void Clear() { internal void Clear() {
this.MessagesMutex.WaitOne(); this.MessagesMutex.Wait();
this.Messages.Clear(); this.Messages.Clear();
this.MessagesMutex.ReleaseMutex(); this.MessagesMutex.Release();
} }
internal Tab Clone() { internal Tab Clone() {

View File

@ -3,10 +3,11 @@ using ChatTwo.Code;
using ChatTwo.GameFunctions.Types; using ChatTwo.GameFunctions.Types;
using ChatTwo.Util; using ChatTwo.Util;
using Dalamud.Game.ClientState.Keys; using Dalamud.Game.ClientState.Keys;
using Dalamud.Game.Config;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Hooking; using Dalamud.Hooking;
using Dalamud.Logging;
using Dalamud.Memory; using Dalamud.Memory;
using Dalamud.Plugin.Services;
using Dalamud.Utility.Signatures; using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.System.Framework; using FFXIVClientStructs.FFXIV.Client.System.Framework;
using FFXIVClientStructs.FFXIV.Client.System.Memory; using FFXIVClientStructs.FFXIV.Client.System.Memory;
@ -38,7 +39,7 @@ internal sealed unsafe class Chat : IDisposable {
[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!;
[Signature("E8 ?? ?? ?? ?? B8 ?? ?? ?? ?? 48 8D 4D 50")] [Signature("E8 ?? ?? ?? ?? 48 8D 4D 50 E8 ?? ?? ?? ?? 48 8B 17")]
private readonly delegate* unmanaged<RaptureLogModule*, ushort, Utf8String*, Utf8String*, ulong, ushort, byte, int, byte, void> _printTell = null!; private readonly delegate* unmanaged<RaptureLogModule*, ushort, Utf8String*, Utf8String*, ulong, ushort, byte, int, byte, void> _printTell = null!;
[Signature("E8 ?? ?? ?? ?? 48 8D 4C 24 ?? E8 ?? ?? ?? ?? 48 8D 8C 24 ?? ?? ?? ?? E8 ?? ?? ?? ?? B0 01")] [Signature("E8 ?? ?? ?? ?? 48 8D 4C 24 ?? E8 ?? ?? ?? ?? 48 8D 8C 24 ?? ?? ?? ?? E8 ?? ?? ?? ?? B0 01")]
@ -53,7 +54,7 @@ internal sealed unsafe class Chat : IDisposable {
[Signature("3B 51 10 73 0F 8B C2 48 83 C0 0B")] [Signature("3B 51 10 73 0F 8B C2 48 83 C0 0B")]
private readonly delegate* unmanaged<IntPtr, uint, ulong*> _getLinkshellInfo = null!; private readonly delegate* unmanaged<IntPtr, uint, ulong*> _getLinkshellInfo = null!;
[Signature("E8 ?? ?? ?? ?? 4C 8B C0 FF C3")] [Signature("E8 ?? ?? ?? ?? 4C 8B C8 44 8D 47 01")]
private readonly delegate* unmanaged<IntPtr, ulong, byte*> _getLinkshellName = null!; private readonly delegate* unmanaged<IntPtr, ulong, byte*> _getLinkshellName = null!;
[Signature("40 56 41 54 41 55 41 57 48 83 EC 28 48 8B 01", Fallibility = Fallibility.Fallible)] [Signature("40 56 41 54 41 55 41 57 48 83 EC 28 48 8B 01", Fallibility = Fallibility.Fallible)]
@ -142,7 +143,7 @@ internal sealed unsafe class Chat : IDisposable {
internal Chat(Plugin plugin) { internal Chat(Plugin plugin) {
this.Plugin = plugin; this.Plugin = plugin;
SignatureHelper.Initialise(this); this.Plugin.GameInteropProvider.InitializeFromAttributes(this);
this.ChatLogRefreshHook?.Enable(); this.ChatLogRefreshHook?.Enable();
this.ChangeChannelNameHook?.Enable(); this.ChangeChannelNameHook?.Enable();
@ -151,7 +152,7 @@ internal sealed unsafe class Chat : IDisposable {
this.Plugin.Framework.Update += this.InterceptKeybinds; this.Plugin.Framework.Update += this.InterceptKeybinds;
this.Plugin.ClientState.Login += this.Login; this.Plugin.ClientState.Login += this.Login;
this.Login(null, null); this.Login();
} }
public void Dispose() { public void Dispose() {
@ -368,7 +369,7 @@ internal sealed unsafe class Chat : IDisposable {
} }
} }
private void InterceptKeybinds(Dalamud.Game.Framework framework) { private void InterceptKeybinds(IFramework framework1) {
this.CheckFocus(); this.CheckFocus();
this.UpdateKeybinds(); this.UpdateKeybinds();
@ -430,12 +431,12 @@ internal sealed unsafe class Chat : IDisposable {
TellReason = TellReason.Reply, TellReason = TellReason.Reply,
}); });
} catch (Exception ex) { } catch (Exception ex) {
PluginLog.LogError(ex, "Error in chat Activated event"); Plugin.Log.Error(ex, "Error in chat Activated event");
} }
} }
} }
private void Login(object? sender, EventArgs? e) { private void Login() {
if (this.ChangeChannelNameHook == null) { if (this.ChangeChannelNameHook == null) {
return; return;
} }
@ -454,10 +455,8 @@ internal sealed unsafe class Chat : IDisposable {
} }
string? input = null; string? input = null;
var option = Framework.Instance()->GetUiModule()->GetConfigModule()->GetValue(ConfigOption.DirectChat); if (this.Plugin.GameConfig.TryGet(UiControlOption.DirectChat, out bool option) && option) {
if (option != null) { if (this._currentCharacter != null) {
var directChat = option->Int > 0;
if (directChat && this._currentCharacter != null) {
// FIXME: this whole system sucks // FIXME: this whole system sucks
var c = *this._currentCharacter; var c = *this._currentCharacter;
if (c != '\0' && !char.IsControl(c)) { if (c != '\0' && !char.IsControl(c)) {
@ -483,7 +482,7 @@ internal sealed unsafe class Chat : IDisposable {
}; };
this.Activated?.Invoke(args); this.Activated?.Invoke(args);
} catch (Exception ex) { } catch (Exception ex) {
PluginLog.LogError(ex, "Error in chat Activated event"); Plugin.Log.Error(ex, "Error in chat Activated event");
} }
// prevent the game from focusing the chat log // prevent the game from focusing the chat log
@ -566,7 +565,7 @@ internal sealed unsafe class Chat : IDisposable {
TellTarget = target, TellTarget = target,
}); });
} catch (Exception ex) { } catch (Exception ex) {
PluginLog.LogError(ex, "Error in chat Activated event"); Plugin.Log.Error(ex, "Error in chat Activated event");
} }
} }
@ -592,7 +591,7 @@ internal sealed unsafe class Chat : IDisposable {
idx = 0; idx = 0;
} }
this._changeChatChannel(RaptureShellModule.Instance, (int) channel, idx, target, 1); this._changeChatChannel(RaptureShellModule.Instance(), (int) channel, idx, target, 1);
target->Dtor(); target->Dtor();
IMemorySpace.Free(target); IMemorySpace.Free(target);
} }

View File

@ -20,7 +20,7 @@ internal sealed unsafe class Context {
[Signature("E8 ?? ?? ?? ?? EB 3F 83 F8 FE", Fallibility = Fallibility.Fallible)] [Signature("E8 ?? ?? ?? ?? EB 3F 83 F8 FE", Fallibility = Fallibility.Fallible)]
private readonly delegate* unmanaged<AgentInterface*, ushort, uint, byte, void> _itemComparison = null!; private readonly delegate* unmanaged<AgentInterface*, ushort, uint, byte, void> _itemComparison = null!;
[Signature("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 41 B4 01", Fallibility = Fallibility.Fallible)] [Signature("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 48 83 F8 0F", Fallibility = Fallibility.Fallible)]
private readonly delegate* unmanaged<IntPtr, uint, void> _searchForRecipesUsingItem = null!; private readonly delegate* unmanaged<IntPtr, uint, void> _searchForRecipesUsingItem = null!;
[Signature("E8 ?? ?? ?? ?? EB 45 45 33 C9", Fallibility = Fallibility.Fallible)] [Signature("E8 ?? ?? ?? ?? EB 45 45 33 C9", Fallibility = Fallibility.Fallible)]
@ -29,7 +29,7 @@ internal sealed unsafe class Context {
#region Offsets #region Offsets
[Signature( [Signature(
"FF 90 ?? ?? ?? ?? 8B 93 ?? ?? ?? ?? 48 8B C8 E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 41 B4 01", "FF 90 ?? ?? ?? ?? 8B 93 ?? ?? ?? ?? 48 8B C8 E8 ?? ?? ?? ?? 41 0F B6 D4 48 8B CB E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 48 81 FF ?? ?? ?? ?? 0F 85",
Offset = 2 Offset = 2
)] )]
private readonly int? _searchForRecipesUsingItemVfunc; private readonly int? _searchForRecipesUsingItemVfunc;
@ -40,7 +40,7 @@ internal sealed unsafe class Context {
internal Context(Plugin plugin) { internal Context(Plugin plugin) {
this.Plugin = plugin; this.Plugin = plugin;
SignatureHelper.Initialise(this); this.Plugin.GameInteropProvider.InitializeFromAttributes(this);
} }
internal void InviteToNoviceNetwork(string name, ushort world) { internal void InviteToNoviceNetwork(string name, ushort world) {
@ -48,7 +48,7 @@ internal sealed unsafe class Context {
return; return;
} }
// 6.05: 20E4CB // 6.3: 221EFD
var a1 = this.Plugin.Functions.GetInfoProxyByIndex(0x14); var a1 = this.Plugin.Functions.GetInfoProxyByIndex(0x14);
fixed (byte* namePtr = name.ToTerminatedBytes()) { fixed (byte* namePtr = name.ToTerminatedBytes()) {

View File

@ -71,7 +71,7 @@ internal unsafe class GameFunctions : IDisposable {
this.Chat = new Chat(this.Plugin); this.Chat = new Chat(this.Plugin);
this.Context = new Context(this.Plugin); this.Context = new Context(this.Plugin);
SignatureHelper.Initialise(this); this.Plugin.GameInteropProvider.InitializeFromAttributes(this);
this.ResolveTextCommandPlaceholderHook?.Enable(); this.ResolveTextCommandPlaceholderHook?.Enable();
} }
@ -207,7 +207,7 @@ internal unsafe class GameFunctions : IDisposable {
// hide addon first to prevent the "addon close" sound // hide addon first to prevent the "addon close" sound
var addon = AtkStage.GetSingleton()->RaptureAtkUnitManager->GetAddonByName("ItemDetail"); var addon = AtkStage.GetSingleton()->RaptureAtkUnitManager->GetAddonByName("ItemDetail");
if (addon != null) { if (addon != null) {
addon->Hide(true); addon->Hide(true, false, 0);
} }
var agent = Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.ItemDetail); var agent = Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.ItemDetail);
@ -227,7 +227,7 @@ internal unsafe class GameFunctions : IDisposable {
vf27(atkModule, addonId, 1); vf27(atkModule, addonId, 1);
} else { } else {
// 6.05: 8443DD // 6.05: 8443DD
if (*(uint*) ((IntPtr) lfg + 0x2AB8) > 0) { if (*(uint*) ((IntPtr) lfg + 0x2C20) > 0) {
lfg->Hide(); lfg->Hide();
} else { } else {
lfg->Show(); lfg->Show();

View File

@ -26,7 +26,7 @@ internal sealed unsafe class Party {
internal Party(Plugin plugin) { internal Party(Plugin plugin) {
this.Plugin = plugin; this.Plugin = plugin;
SignatureHelper.Initialise(this); this.Plugin.GameInteropProvider.InitializeFromAttributes(this);
} }
internal void InviteSameWorld(string name, ushort world, ulong contentId) { internal void InviteSameWorld(string name, ushort world, ulong contentId) {

View File

@ -1,5 +1,6 @@
using ChatTwo.Code; using ChatTwo.Code;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using LiteDB; using LiteDB;
namespace ChatTwo; namespace ChatTwo;
@ -60,6 +61,7 @@ internal class Message {
internal SeString ContentSource { get; } internal SeString ContentSource { get; }
internal SortCode SortCode { get; } internal SortCode SortCode { get; }
internal Guid ExtraChatChannel { get; }
internal int Hash { get; } internal int Hash { get; }
@ -72,6 +74,7 @@ internal class Message {
this.SenderSource = senderSource; this.SenderSource = senderSource;
this.ContentSource = contentSource; this.ContentSource = contentSource;
this.SortCode = new SortCode(this.Code.Type, this.Code.Source); this.SortCode = new SortCode(this.Code.Type, this.Code.Source);
this.ExtraChatChannel = this.ExtractExtraChatChannel();
this.Hash = this.GenerateHash(); this.Hash = this.GenerateHash();
foreach (var chunk in sender.Concat(content)) { foreach (var chunk in sender.Concat(content)) {
@ -90,6 +93,26 @@ internal class Message {
this.SenderSource = BsonMapper.Global.Deserialize<SeString>(senderSource); this.SenderSource = BsonMapper.Global.Deserialize<SeString>(senderSource);
this.ContentSource = BsonMapper.Global.Deserialize<SeString>(contentSource); this.ContentSource = BsonMapper.Global.Deserialize<SeString>(contentSource);
this.SortCode = BsonMapper.Global.ToObject<SortCode>(sortCode); this.SortCode = BsonMapper.Global.ToObject<SortCode>(sortCode);
this.ExtraChatChannel = this.ExtractExtraChatChannel();
this.Hash = this.GenerateHash();
foreach (var chunk in this.Sender.Concat(this.Content)) {
chunk.Message = this;
}
}
internal Message(ObjectId id, ulong receiver, ulong contentId, DateTime date, BsonDocument code, BsonArray sender, BsonArray content, BsonValue senderSource, BsonValue contentSource, BsonDocument sortCode, BsonValue extraChatChannel) {
this.Id = id;
this.Receiver = receiver;
this.ContentId = contentId;
this.Date = date;
this.Code = BsonMapper.Global.ToObject<ChatCode>(code);
this.Sender = BsonMapper.Global.Deserialize<List<Chunk>>(sender);
this.Content = BsonMapper.Global.Deserialize<List<Chunk>>(content);
this.SenderSource = BsonMapper.Global.Deserialize<SeString>(senderSource);
this.ContentSource = BsonMapper.Global.Deserialize<SeString>(contentSource);
this.SortCode = BsonMapper.Global.ToObject<SortCode>(sortCode);
this.ExtraChatChannel = BsonMapper.Global.Deserialize<Guid>(extraChatChannel);
this.Hash = this.GenerateHash(); this.Hash = this.GenerateHash();
foreach (var chunk in this.Sender.Concat(this.Content)) { foreach (var chunk in this.Sender.Concat(this.Content)) {
@ -99,7 +122,20 @@ internal class Message {
private int GenerateHash() { private int GenerateHash() {
return this.SortCode.GetHashCode() return this.SortCode.GetHashCode()
^ this.ExtraChatChannel.GetHashCode()
^ string.Join("", this.Sender.Select(c => c.StringValue())).GetHashCode() ^ string.Join("", this.Sender.Select(c => c.StringValue())).GetHashCode()
^ string.Join("", this.Content.Select(c => c.StringValue())).GetHashCode(); ^ string.Join("", this.Content.Select(c => c.StringValue())).GetHashCode();
} }
private Guid ExtractExtraChatChannel() {
if (this.ContentSource.Payloads.Count > 0 && this.ContentSource.Payloads[0] is RawPayload raw) {
// this does an encode and clone every time it's accessed, so cache
var data = raw.Data;
if (data[1] == 0x27 && data[2] == 18 && data[3] == 0x20) {
return new Guid(data[4..^1]);
}
}
return Guid.Empty;
}
} }

View File

@ -7,13 +7,14 @@ using ChatTwo.Util;
using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Interface; using Dalamud.Interface.Internal;
using Dalamud.Logging; using Dalamud.Interface.Utility;
using Dalamud.Utility; using Dalamud.Utility;
using ImGuiNET; using ImGuiNET;
using ImGuiScene;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using Action = System.Action; using Action = System.Action;
using DalamudPartyFinderPayload = Dalamud.Game.Text.SeStringHandling.Payloads.PartyFinderPayload;
using ChatTwoPartyFinderPayload = ChatTwo.Util.PartyFinderPayload;
namespace ChatTwo; namespace ChatTwo;
@ -99,7 +100,7 @@ internal sealed class PayloadHandler {
try { try {
this.Ui.Plugin.Ipc.Invoke(id, sender, contentId, payload, chunk.Message?.SenderSource, chunk.Message?.ContentSource); this.Ui.Plugin.Ipc.Invoke(id, sender, contentId, payload, chunk.Message?.SenderSource, chunk.Message?.ContentSource);
} catch (Exception ex) { } catch (Exception ex) {
PluginLog.Error(ex, "Error executing integration"); Plugin.Log.Error(ex, "Error executing integration");
} }
} }
@ -118,7 +119,7 @@ internal sealed class PayloadHandler {
ImGui.Separator(); ImGui.Separator();
} }
if (!ImGui.BeginMenu(this.Ui.Plugin.Name)) { if (!ImGui.BeginMenu(Plugin.Name)) {
return; return;
} }
@ -214,7 +215,7 @@ internal sealed class PayloadHandler {
} }
} }
private static void InlineIcon(TextureWrap icon) { private static void InlineIcon(IDalamudTextureWrap icon) {
var lineHeight = ImGui.CalcTextSize("A").Y; var lineHeight = ImGui.CalcTextSize("A").Y;
var cursor = ImGui.GetCursorPos(); var cursor = ImGui.GetCursorPos();
@ -294,7 +295,16 @@ internal sealed class PayloadHandler {
this.ClickLinkPayload(chunk, payload, link); this.ClickLinkPayload(chunk, payload, link);
break; break;
} }
case PartyFinderPayload pf: { case DalamudPartyFinderPayload pf: {
if (pf.LinkType == DalamudPartyFinderPayload.PartyFinderLinkType.PartyFinderNotification) {
GameFunctions.GameFunctions.OpenPartyFinder();
} else {
this.Ui.Plugin.Functions.OpenPartyFinder(pf.ListingId);
}
break;
}
case ChatTwoPartyFinderPayload pf: {
this.Ui.Plugin.Functions.OpenPartyFinder(pf.Id); this.Ui.Plugin.Functions.OpenPartyFinder(pf.Id);
break; break;
} }
@ -325,16 +335,25 @@ internal sealed class PayloadHandler {
var payloads = source.Payloads.Skip(start).Take(end - start + 1).ToList(); var payloads = source.Payloads.Skip(start).Take(end - start + 1).ToList();
var chatGui = this.Ui.Plugin.ChatGui; var chatGuiScoped = this.Ui.Plugin.ChatGui;
var field = chatGui.GetType().GetField("dalamudLinkHandlers", BindingFlags.Instance | BindingFlags.NonPublic); var chatGuiService = chatGuiScoped.GetType()
if (field == null || field.GetValue(chatGui) is not Dictionary<(string PluginName, uint CommandId), Action<uint, SeString>> dict || !dict.TryGetValue((link.Plugin, link.CommandId), out var action)) { .GetField("chatGuiService", BindingFlags.Instance | BindingFlags.NonPublic)!
.GetValue(chatGuiScoped);
if (chatGuiService == null) {
Plugin.Log.Warning("could not find chatGuiService");
return;
}
var field = chatGuiService.GetType().GetField("dalamudLinkHandlers", BindingFlags.Instance | BindingFlags.NonPublic);
if (field == null || field.GetValue(chatGuiService) is not Dictionary<(string PluginName, uint CommandId), Action<uint, SeString>> dict || !dict.TryGetValue((link.Plugin, link.CommandId), out var action)) {
Plugin.Log.Warning("could not find dalamudLinkHandlers");
return; return;
} }
try { try {
action(link.CommandId, new SeString(payloads)); action(link.CommandId, new SeString(payloads));
} catch (Exception ex) { } catch (Exception ex) {
PluginLog.LogError(ex, "Error executing DalamudLinkPayload handler"); Plugin.Log.Error(ex, "Error executing DalamudLinkPayload handler");
} }
} }
@ -520,7 +539,7 @@ internal sealed class PayloadHandler {
} }
if (ImGui.Selectable(Language.Context_Target) && this.FindCharacterForPayload(player) is { } obj) { if (ImGui.Selectable(Language.Context_Target) && this.FindCharacterForPayload(player) is { } obj) {
this.Ui.Plugin.TargetManager.SetTarget(obj); this.Ui.Plugin.TargetManager.Target = obj;
} }
// View Party Finder 0x2E // View Party Finder 0x2E

View File

@ -3,17 +3,10 @@ using System.Globalization;
using ChatTwo.Ipc; using ChatTwo.Ipc;
using ChatTwo.Resources; using ChatTwo.Resources;
using ChatTwo.Util; using ChatTwo.Util;
using Dalamud.Data;
using Dalamud.Game;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Game.ClientState.Objects; using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Party;
using Dalamud.Game.Command;
using Dalamud.Game.Gui;
using Dalamud.IoC; using Dalamud.IoC;
using Dalamud.Plugin; using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using XivCommon; using XivCommon;
namespace ChatTwo; namespace ChatTwo;
@ -22,43 +15,55 @@ namespace ChatTwo;
public sealed class Plugin : IDalamudPlugin { public sealed class Plugin : IDalamudPlugin {
internal const string PluginName = "Chat 2"; internal const string PluginName = "Chat 2";
public string Name => PluginName; internal static string Name => PluginName;
[PluginService]
internal static IPluginLog Log { get; private set; }
[PluginService] [PluginService]
internal DalamudPluginInterface Interface { get; init; } internal DalamudPluginInterface Interface { get; init; }
[PluginService] [PluginService]
internal ChatGui ChatGui { get; init; } internal IChatGui ChatGui { get; init; }
[PluginService] [PluginService]
internal ClientState ClientState { get; init; } internal IClientState ClientState { get; init; }
[PluginService] [PluginService]
internal CommandManager CommandManager { get; init; } internal ICommandManager CommandManager { get; init; }
[PluginService] [PluginService]
internal Condition Condition { get; init; } internal ICondition Condition { get; init; }
[PluginService] [PluginService]
internal DataManager DataManager { get; init; } internal IDataManager DataManager { get; init; }
[PluginService] [PluginService]
internal Framework Framework { get; init; } internal IFramework Framework { get; init; }
[PluginService] [PluginService]
internal GameGui GameGui { get; init; } internal IGameGui GameGui { get; init; }
[PluginService] [PluginService]
internal KeyState KeyState { get; init; } internal IKeyState KeyState { get; init; }
[PluginService] [PluginService]
internal ObjectTable ObjectTable { get; init; } internal IObjectTable ObjectTable { get; init; }
[PluginService] [PluginService]
internal PartyList PartyList { get; init; } internal IPartyList PartyList { get; init; }
[PluginService] [PluginService]
internal TargetManager TargetManager { get; init; } internal ITargetManager TargetManager { get; init; }
[PluginService]
internal ITextureProvider TextureProvider { get; init; }
[PluginService]
internal IGameInteropProvider GameInteropProvider { get; init; }
[PluginService]
internal IGameConfig GameConfig { get; init; }
internal Configuration Config { get; } internal Configuration Config { get; }
internal Commands Commands { get; } internal Commands Commands { get; }
@ -88,8 +93,8 @@ public sealed class Plugin : IDalamudPlugin {
this.LanguageChanged(this.Interface.UiLanguage); this.LanguageChanged(this.Interface.UiLanguage);
this.Commands = new Commands(this); this.Commands = new Commands(this);
this.Common = new XivCommonBase(); this.Common = new XivCommonBase(this.Interface);
this.TextureCache = new TextureCache(this.DataManager!); this.TextureCache = new TextureCache(this.TextureProvider!);
this.Functions = new GameFunctions.GameFunctions(this); this.Functions = new GameFunctions.GameFunctions(this);
this.Store = new Store(this); this.Store = new Store(this);
this.Ipc = new IpcManager(this.Interface); this.Ipc = new IpcManager(this.Interface);
@ -143,7 +148,7 @@ public sealed class Plugin : IDalamudPlugin {
"ChatLogPanel_3", "ChatLogPanel_3",
}; };
private void FrameworkUpdate(Framework framework) { private void FrameworkUpdate(IFramework framework) {
if (this.DeferredSaveFrames >= 0 && this.DeferredSaveFrames-- == 0) { if (this.DeferredSaveFrames >= 0 && this.DeferredSaveFrames-- == 0) {
this.SaveConfig(); this.SaveConfig();
} }

View File

@ -3,7 +3,6 @@ using System.Runtime.InteropServices;
using ChatTwo.Ui; using ChatTwo.Ui;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.GameFonts; using Dalamud.Interface.GameFonts;
using Dalamud.Logging;
using ImGuiNET; using ImGuiNET;
namespace ChatTwo; namespace ChatTwo;
@ -130,6 +129,10 @@ internal sealed class PluginUi : IDisposable {
} }
private void Draw() { private void Draw() {
if (this.Plugin.Config.DatabaseMigration != Configuration.LatestDbVersion) {
return;
}
this.Plugin.Interface.UiBuilder.DisableUserUiHide = !this.Plugin.Config.HideWhenUiHidden; this.Plugin.Interface.UiBuilder.DisableUserUiHide = !this.Plugin.Config.HideWhenUiHidden;
this.DefaultText = ImGui.GetStyle().Colors[(int) ImGuiCol.Text]; this.DefaultText = ImGui.GetStyle().Colors[(int) ImGuiCol.Text];
@ -147,7 +150,7 @@ internal sealed class PluginUi : IDisposable {
try { try {
component.Draw(); component.Draw();
} catch (Exception ex) { } catch (Exception ex) {
PluginLog.LogError(ex, "Error drawing component"); Plugin.Log.Error(ex, "Error drawing component");
} }
} }

View File

@ -1502,5 +1502,29 @@ namespace ChatTwo.Resources {
return ResourceManager.GetString("Options_Tabs_ExtraChatAll", resourceCulture); return ResourceManager.GetString("Options_Tabs_ExtraChatAll", resourceCulture);
} }
} }
internal static string Migration_Line1 {
get {
return ResourceManager.GetString("Migration_Line1", resourceCulture);
}
}
internal static string Migration_Line2 {
get {
return ResourceManager.GetString("Migration_Line2", resourceCulture);
}
}
internal static string Migration_Line3 {
get {
return ResourceManager.GetString("Migration_Line3", resourceCulture);
}
}
internal static string Migration_Line4 {
get {
return ResourceManager.GetString("Migration_Line4", resourceCulture);
}
}
} }
} }

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

File diff suppressed because it is too large Load Diff

View File

@ -121,279 +121,55 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
<data name="Options_HideChat_Name" xml:space="preserve"> <data name="Options_HideChat_Name">
<value>Απόκρυψη αρχικού παραθύρου συνομιλιών</value> <value>Απόκρυψη αρχικού παραθύρου συνομιλιών</value>
</data> </data>
<data name="Options_HideChat_Description" xml:space="preserve"> <data name="Options_HideChat_Description">
<value>Απόκρυψη αρχικού παραθύρου συνομιλιών όταν το plugin είναι ενεργό.</value> <value>Απόκρυψη αρχικού παραθύρου συνομιλιών όταν το plugin είναι ενεργό.</value>
</data> </data>
<data name="Options_SidebarTabView_Name">
<value>Εμφάνιση καρτελών σε πλαϊνή μπάρα</value>
</data>
<data name="Options_SidebarTabView_Description">
<data name="Options_SidebarTabView_Name" xml:space="preserve"> <value>Εμφάνιση καρτελών στο {0} ως πλαϊνή μπάρα αντί για μια μπάρα στην κορυφή.</value>
<value>Εμφάνιση καρτελών σε πλαϊνή μπάρα</value> </data>
</data> <data name="Options_PrettierTimestamps_Name">
<data name="Options_SidebarTabView_Description" xml:space="preserve">
<value>Εμφάνιση καρτελών στο {0} ως πλαϊνή μπάρα αντί για μια μπάρα στην κορυφή.</value>
</data>
<data name="Options_PrettierTimestamps_Name" xml:space="preserve">
<value>Χρήση σύγχρονης διάταξης</value> <value>Χρήση σύγχρονης διάταξης</value>
</data> </data>
<data name="Options_PrettierTimestamps_Description" xml:space="preserve"> <data name="Options_PrettierTimestamps_Description">
<value>Εμφάνιση μηνυμάτων σε πιο μοντέρνο στυλ.</value> <value>Εμφάνιση μηνυμάτων σε πιο μοντέρνο στυλ.</value>
</data> </data>
<data name="Options_MoreCompactPretty_Name" xml:space="preserve"> <data name="Options_MoreCompactPretty_Name">
<value>Πιο συμπαγής μοντέρνα διάταξη</value> <value>Πιο συμπαγής μοντέρνα διάταξη</value>
</data> </data>
<data name="Options_MoreCompactPretty_Description" xml:space="preserve"> <data name="Options_MoreCompactPretty_Description">
<value>Μείωση της απόστασης μεταξύ μηνυμάτων.</value> <value>Μείωση της απόστασης μεταξύ μηνυμάτων.</value>
</data> </data>
<data name="Options_ShowNoviceNetwork_Name" xml:space="preserve"> <data name="Options_ShowNoviceNetwork_Name">
<value>Εμφάνιση κουμπιού σύνδεσης στο Δίκτυο Αρχαρίων</value> <value>Εμφάνιση κουμπιού σύνδεσης στο Δίκτυο Αρχαρίων</value>
</data> </data>
<data name="Options_ShowNoviceNetwork_Description" xml:space="preserve"> <data name="Options_ShowNoviceNetwork_Description">
<value>Εμφάνιση του κουμπιού σύνδεσης στο Δίκτυο Αρχαρίων δίπλα στο κουμπί ρυθμίσεων, εάν συνδέεστε ως μέντορας.</value> <value>Εμφάνιση του κουμπιού σύνδεσης στο Δίκτυο Αρχαρίων δίπλα στο κουμπί ρυθμίσεων, εάν συνδέεστε ως μέντορας.</value>
</data> </data>
<data name="Options_FontSize_Name" xml:space="preserve"> <data name="Options_FontSize_Name">
<value>Μέγεθος γραμματοσειράς</value> <value>Μέγεθος γραμματοσειράς</value>
</data> </data>
<data name="Options_WindowOpacity_Name" xml:space="preserve"> <data name="Options_WindowOpacity_Name">
<value>Διαφάνεια παραθύρου</value> <value>Διαφάνεια παραθύρου</value>
</data> </data>
<data name="Options_CanMove_Name" xml:space="preserve"> <data name="Options_CanMove_Name">
<value>Να επιτρέπεται η μετακίνηση του παραθύρου συνομιλιών</value> <value>Να επιτρέπεται η μετακίνηση του παραθύρου συνομιλιών</value>
</data> </data>
<data name="Options_CanResize_Name" xml:space="preserve"> <data name="Options_CanResize_Name">
<value>Να επιτρέπεται η αλλαγή μεγέθους του παραθύρου συνομιλιών</value> <value>Να επιτρέπεται η αλλαγή μεγέθους του παραθύρου συνομιλιών</value>
</data> </data>
<data name="Options_ShowTitleBar_Name" xml:space="preserve"> <data name="Options_ShowTitleBar_Name">
<value>Να εμφανίζεται η γραμμή τίτλου του παραθύρου συνομιλιών</value> <value>Να εμφανίζεται η γραμμή τίτλου του παραθύρου συνομιλιών</value>
</data> </data>
<data name="Options_Display_Tab" xml:space="preserve"> <data name="Options_Display_Tab">
<value>Εμφάνιση</value> <value>Εμφάνιση</value>
</data> </data>
<data name="Options_ChatColours_Tab" xml:space="preserve"> <data name="Options_ChatColours_Tab">
<value>Χρώματα παραθύρου συνομιλιών</value> <value>Χρώματα παραθύρου συνομιλιών</value>
</data> </data>
</root> </root>

File diff suppressed because it is too large Load Diff

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

File diff suppressed because it is too large Load Diff

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

View File

@ -121,339 +121,145 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
<data name="Context_HideChat">
<data name="Context_HideChat" xml:space="preserve">
<value>ログウィンドウを隠す</value> <value>ログウィンドウを隠す</value>
</data> </data>
<data name="Context_Copy" xml:space="preserve"> <data name="Context_Copy">
<value>コピーする</value> <value>コピーする</value>
</data> </data>
<data name="Context_TryOn" xml:space="preserve"> <data name="Context_TryOn">
<value>装備試着</value> <value>装備試着</value>
</data> </data>
<data name="Context_ItemComparison" xml:space="preserve"> <data name="Context_ItemComparison">
<value>装備詳細を比較</value> <value>装備詳細を比較</value>
</data> </data>
<data name="Context_SearchRecipes" xml:space="preserve"> <data name="Context_SearchRecipes">
<value>この素材から作れるものを確認</value> <value>この素材から作れるものを確認</value>
</data> </data>
<data name="Context_SearchForItem" xml:space="preserve"> <data name="Context_SearchForItem">
<value>所持状況を確認</value> <value>所持状況を確認</value>
</data> </data>
<data name="Context_Link" xml:space="preserve"> <data name="Context_Link">
<value>基本性能を伝える</value> <value>基本性能を伝える</value>
</data> </data>
<data name="Context_CopyItemName" xml:space="preserve"> <data name="Context_CopyItemName">
<value>アイテム名をコピーする</value> <value>アイテム名をコピーする</value>
</data> </data>
<data name="Context_SendTell" xml:space="preserve"> <data name="Context_SendTell">
<value>Tellする</value> <value>Tellする</value>
</data> </data>
<data name="Context_InviteToParty" xml:space="preserve"> <data name="Context_InviteToParty">
<value>パーティに誘う</value> <value>パーティに誘う</value>
</data> </data>
<data name="Context_Promote">
<data name="Context_Promote" xml:space="preserve">
<value>パーティリーダーを委譲する</value> <value>パーティリーダーを委譲する</value>
</data> </data>
<data name="Context_KickFromParty" xml:space="preserve"> <data name="Context_KickFromParty">
<value>パーティから除外する</value> <value>パーティから除外する</value>
</data> </data>
<data name="Context_SendFriendRequest" xml:space="preserve"> <data name="Context_SendFriendRequest">
<value>フレンド申請をする</value> <value>フレンド申請をする</value>
</data> </data>
<data name="Context_AddToBlacklist" xml:space="preserve"> <data name="Context_AddToBlacklist">
<value>ブラックリストに登録する</value> <value>ブラックリストに登録する</value>
</data> </data>
<data name="Context_InviteToNoviceNetwork" xml:space="preserve"> <data name="Context_InviteToNoviceNetwork">
<value>ビギナーチャンネルに招待する</value> <value>ビギナーチャンネルに招待する</value>
</data> </data>
<data name="Context_ReplyInSelectedChatMode" xml:space="preserve"> <data name="Context_ReplyInSelectedChatMode">
<value>選択した会話モードに返信する</value> <value>選択した会話モードに返信する</value>
</data> </data>
<data name="Context_Target" xml:space="preserve"> <data name="Context_Target">
<value>ターゲットする</value> <value>ターゲットする</value>
</data> </data>
<data name="ChatType_Alliance">
<data name="ChatType_Alliance" xml:space="preserve">
<value>アライアンス</value> <value>アライアンス</value>
</data> </data>
<data name="ChatType_Linkshell1" xml:space="preserve"> <data name="ChatType_Linkshell1">
<value>Linkshell[1]</value> <value>Linkshell[1]</value>
</data> </data>
<data name="ChatType_Linkshell2" xml:space="preserve"> <data name="ChatType_Linkshell2">
<value>Linkshell[2]</value> <value>Linkshell[2]</value>
</data> </data>
<data name="ChatType_Linkshell3" xml:space="preserve"> <data name="ChatType_Linkshell3">
<value>Linkshell[3]</value> <value>Linkshell[3]</value>
</data> </data>
<data name="ChatType_Linkshell4" xml:space="preserve"> <data name="ChatType_Linkshell4">
<value>Linkshell[4]</value> <value>Linkshell[4]</value>
</data> </data>
<data name="ChatType_Linkshell5" xml:space="preserve"> <data name="ChatType_Linkshell5">
<value>Linkshell[5]</value> <value>Linkshell[5]</value>
</data> </data>
<data name="ChatType_Linkshell6" xml:space="preserve"> <data name="ChatType_Linkshell6">
<value>Linkshell[6]</value> <value>Linkshell[6]</value>
</data> </data>
<data name="ChatType_Linkshell7" xml:space="preserve"> <data name="ChatType_Linkshell7">
<value>Linkshell[7]</value> <value>Linkshell[7]</value>
</data> </data>
<data name="ChatType_Linkshell8" xml:space="preserve"> <data name="ChatType_Linkshell8">
<value>Linkshell[8]</value> <value>Linkshell[8]</value>
</data> </data>
<data name="ChatType_FreeCompany" xml:space="preserve"> <data name="ChatType_FreeCompany">
<value>フリーカンパニー</value> <value>フリーカンパニー</value>
</data> </data>
<data name="ChatType_NoviceNetwork" xml:space="preserve"> <data name="ChatType_NoviceNetwork">
<value>ビギナーチャンネル</value> <value>ビギナーチャンネル</value>
</data> </data>
<data name="ChatType_PvpTeam">
<data name="ChatType_PvpTeam" xml:space="preserve">
<value>PvPチーム</value> <value>PvPチーム</value>
</data> </data>
<data name="ChatType_CrossLinkshell1" xml:space="preserve"> <data name="ChatType_CrossLinkshell1">
<value>クロスワールドリンクシェルチャンネル1</value> <value>クロスワールドリンクシェルチャンネル1</value>
</data> </data>
<data name="ChatType_CrossLinkshell2" xml:space="preserve"> <data name="ChatType_CrossLinkshell2">
<value>クロスワールドリンクシェルチャンネル2</value> <value>クロスワールドリンクシェルチャンネル2</value>
</data> </data>
<data name="ChatType_CrossLinkshell3" xml:space="preserve"> <data name="ChatType_CrossLinkshell3">
<value>クロスワールドリンクシェルチャンネル3</value> <value>クロスワールドリンクシェルチャンネル3</value>
</data> </data>
<data name="ChatType_CrossLinkshell4" xml:space="preserve"> <data name="ChatType_CrossLinkshell4">
<value>クロスワールドリンクシェルチャンネル4</value> <value>クロスワールドリンクシェルチャンネル4</value>
</data> </data>
<data name="ChatType_CrossLinkshell5" xml:space="preserve"> <data name="ChatType_CrossLinkshell5">
<value>クロスワールドリンクシェルチャンネル5</value> <value>クロスワールドリンクシェルチャンネル5</value>
</data> </data>
<data name="ChatType_CrossLinkshell6" xml:space="preserve"> <data name="ChatType_CrossLinkshell6">
<value>クロスワールドリンクシェルチャンネル6</value> <value>クロスワールドリンクシェルチャンネル6</value>
</data> </data>
<data name="ChatType_CrossLinkshell7" xml:space="preserve"> <data name="ChatType_CrossLinkshell7">
<value>クロスワールドリンクシェルチャンネル7</value> <value>クロスワールドリンクシェルチャンネル7</value>
</data> </data>
<data name="ChatType_CrossLinkshell8" xml:space="preserve"> <data name="ChatType_CrossLinkshell8">
<value>クロスワールドリンクシェルチャンネル8</value> <value>クロスワールドリンクシェルチャンネル8</value>
</data> </data>
<data name="ChatType_Damage" xml:space="preserve"> <data name="ChatType_Damage">
<value>ダメージを与えた</value> <value>ダメージを与えた</value>
</data> </data>
<data name="ChatType_Echo">
<data name="ChatType_Echo" xml:space="preserve">
<value>/echoで出力するテキスト</value> <value>/echoで出力するテキスト</value>
</data> </data>
<data name="ChatType_System" xml:space="preserve"> <data name="ChatType_System">
<value>システムメッセージ</value> <value>システムメッセージ</value>
</data> </data>
<data name="ChatType_BattleSystem" xml:space="preserve"> <data name="ChatType_BattleSystem">
<value>戦闘に関するシステムメッセージ</value> <value>戦闘に関するシステムメッセージ</value>
</data> </data>
<data name="ChatType_GatheringSystem" xml:space="preserve"> <data name="ChatType_GatheringSystem">
<value>採集に関するシステムメッセージ</value> <value>採集に関するシステムメッセージ</value>
</data> </data>
<data name="ChatType_Error" xml:space="preserve"> <data name="ChatType_Error">
<value>エラーメッセージ</value> <value>エラーメッセージ</value>
</data> </data>
<data name="ChatType_NpcDialogue" xml:space="preserve"> <data name="ChatType_NpcDialogue">
<value>NPC会話</value> <value>NPC会話</value>
</data> </data>
<data name="ChatType_FreeCompanyAnnouncement">
<data name="ChatType_FreeCompanyAnnouncement" xml:space="preserve">
<value>フリーカンパニーアナウンス</value> <value>フリーカンパニーアナウンス</value>
</data> </data>
<data name="ChatType_NoviceNetworkSystem">
<data name="ChatType_NoviceNetworkSystem" xml:space="preserve">
<value>ビギナーチャンネルアナウンス</value> <value>ビギナーチャンネルアナウンス</value>
</data> </data>
<data name="ChatType_PvpTeamAnnouncement">
<data name="ChatType_PvpTeamAnnouncement" xml:space="preserve">
<value>PvPチームアナウンス</value> <value>PvPチームアナウンス</value>
</data> </data>
</root> </root>

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

File diff suppressed because it is too large Load Diff

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

File diff suppressed because it is too large Load Diff

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

File diff suppressed because it is too large Load Diff

View File

@ -121,521 +121,418 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
<data name="Options_HideChat_Name" xml:space="preserve"> <data name="Options_HideChat_Name">
<value>Ascunde chat-ul normal</value> <value>Ascunde chat-ul normal</value>
</data> </data>
<data name="Options_HideChat_Description" xml:space="preserve"> <data name="Options_HideChat_Description">
<value>Ascunde fereastra de chat a jocului atunci când pluginul este activ.</value> <value>Ascunde fereastra de chat a jocului atunci când pluginul este activ.</value>
</data> </data>
<data name="Options_HideDuringCutscenes_Name" xml:space="preserve"> <data name="Options_HideDuringCutscenes_Name">
<value>Ascunde chat-ul pe durata cinematic-urilor</value> <value>Ascunde chat-ul pe durata cinematic-urilor</value>
</data> </data>
<data name="Options_HideDuringCutscenes_Description" xml:space="preserve"> <data name="Options_HideDuringCutscenes_Description">
<value>Ascunde {0} pe durata cinematic-urilor.</value> <value>Ascunde {0} pe durata cinematic-urilor.</value>
</data> </data>
<data name="Options_NativeItemTooltips_Name" xml:space="preserve"> <data name="Options_NativeItemTooltips_Name">
<value>Afișează descrierea nativa a item-urilor</value> <value>Afișează descrierea nativa a item-urilor</value>
</data> </data>
<data name="Options_NativeItemTooltips_Description" xml:space="preserve"> <data name="Options_NativeItemTooltips_Description">
<value>Afișează descrierea item-urilor din joc când cursorul este peste un item in {0}.</value> <value>Afișează descrierea item-urilor din joc când cursorul este peste un item in {0}.</value>
</data> </data>
<data name="Options_SidebarTabView_Name" xml:space="preserve"> <data name="Options_SidebarTabView_Name">
<value>Afișează taburi într-o bara laterala</value> <value>Afișează taburi într-o bara laterala</value>
</data> </data>
<data name="Options_SidebarTabView_Description" xml:space="preserve"> <data name="Options_SidebarTabView_Description">
<value>Afișează taburi in {0} ca o bara laterala in loc de o bara deasupra ferestrei.</value> <value>Afișează taburi in {0} ca o bara laterala in loc de o bara deasupra ferestrei.</value>
</data> </data>
<data name="Options_PrettierTimestamps_Name" xml:space="preserve"> <data name="Options_PrettierTimestamps_Name">
<value>Folosește aspectul modern</value> <value>Folosește aspectul modern</value>
</data> </data>
<data name="Options_PrettierTimestamps_Description" xml:space="preserve"> <data name="Options_PrettierTimestamps_Description">
<value>Afișează mesajele într-un stil modern.</value> <value>Afișează mesajele într-un stil modern.</value>
</data> </data>
<data name="Options_MoreCompactPretty_Name" xml:space="preserve"> <data name="Options_MoreCompactPretty_Name">
<value>Aspect modern mai compact</value> <value>Aspect modern mai compact</value>
</data> </data>
<data name="Options_MoreCompactPretty_Description" xml:space="preserve"> <data name="Options_MoreCompactPretty_Description">
<value>Reduce spațiul dintre mesaje.</value> <value>Reduce spațiul dintre mesaje.</value>
</data> </data>
<data name="Options_ShowNoviceNetwork_Name" xml:space="preserve"> <data name="Options_ShowNoviceNetwork_Name">
<value>Afișează butonul de alăturare la Novice Network</value> <value>Afișează butonul de alăturare la Novice Network</value>
</data> </data>
<data name="Options_ShowNoviceNetwork_Description" xml:space="preserve"> <data name="Options_ShowNoviceNetwork_Description">
<value>Afișează butonul de alăturare la Novice Network lângă butonul de setări daca ești conectat ca un mentor.</value> <value>Afișează butonul de alăturare la Novice Network lângă butonul de setări daca ești conectat ca un mentor.</value>
</data> </data>
<data name="Options_FontSize_Name" xml:space="preserve"> <data name="Options_FontSize_Name">
<value>Dimensiunea textului</value> <value>Dimensiunea textului</value>
</data> </data>
<data name="Options_WindowOpacity_Name" xml:space="preserve"> <data name="Options_WindowOpacity_Name">
<value>Opacitatea ferestrei</value> <value>Opacitatea ferestrei</value>
</data> </data>
<data name="Options_CanMove_Name" xml:space="preserve"> <data name="Options_CanMove_Name">
<value>Permite mutarea chat-ului</value> <value>Permite mutarea chat-ului</value>
</data> </data>
<data name="Options_CanResize_Name" xml:space="preserve"> <data name="Options_CanResize_Name">
<value>Permite redimensionarea chat-ului</value> <value>Permite redimensionarea chat-ului</value>
</data> </data>
<data name="Options_ShowTitleBar_Name" xml:space="preserve"> <data name="Options_ShowTitleBar_Name">
<value>Afișează bara de titlu pentru chat</value> <value>Afișează bara de titlu pentru chat</value>
</data> </data>
<data name="Options_Display_Tab" xml:space="preserve"> <data name="Options_Display_Tab">
<value>Afișaj</value> <value>Afișaj</value>
</data> </data>
<data name="Options_ChatColours_Tab" xml:space="preserve"> <data name="Options_ChatColours_Tab">
<value>Culori în chat</value> <value>Culori în chat</value>
</data> </data>
<data name="Options_ChatColours_Reset" xml:space="preserve"> <data name="Options_ChatColours_Reset">
<value>Resetează la valorile implicite</value> <value>Resetează la valorile implicite</value>
</data> </data>
<data name="Options_ChatColours_Import" xml:space="preserve"> <data name="Options_ChatColours_Import">
<value>Importă din joc</value> <value>Importă din joc</value>
</data> </data>
<data name="Options_Tabs_Tab" xml:space="preserve"> <data name="Options_Tabs_Tab">
<value>Taburi</value> <value>Taburi</value>
</data> </data>
<data name="Options_Tabs_Add" xml:space="preserve"> <data name="Options_Tabs_Add">
<value>Adaugă</value> <value>Adaugă</value>
</data> </data>
<data name="Options_Tabs_Delete" xml:space="preserve"> <data name="Options_Tabs_Delete">
<value>Șterge</value> <value>Șterge</value>
</data> </data>
<data name="Options_Tabs_MoveUp" xml:space="preserve"> <data name="Options_Tabs_MoveUp">
<value>Mută în sus</value> <value>Mută în sus</value>
</data> </data>
<data name="Options_Tabs_MoveDown" xml:space="preserve"> <data name="Options_Tabs_MoveDown">
<value>Mută în jos</value> <value>Mută în jos</value>
</data> </data>
<data name="Options_Tabs_Name" xml:space="preserve"> <data name="Options_Tabs_Name">
<value>Nume</value> <value>Nume</value>
</data> </data>
<data name="Options_Tabs_ShowTimestamps" xml:space="preserve"> <data name="Options_Tabs_ShowTimestamps">
<value>Afișează marcajele de timp</value> <value>Afișează marcajele de timp</value>
</data> </data>
<data name="Options_Tabs_UnreadMode" xml:space="preserve"> <data name="Options_Tabs_UnreadMode">
<value>Modul necitit</value> <value>Modul necitit</value>
</data> </data>
<data name="Options_Tabs_NoInputChannel" xml:space="preserve"> <data name="Options_Tabs_NoInputChannel">
<value>&lt;Nimic&gt;</value> <value>&lt;Nimic&gt;</value>
</data> </data>
<data name="Options_Tabs_InputChannel" xml:space="preserve"> <data name="Options_Tabs_InputChannel">
<value>Canalul de comunicare</value> <value>Canalul de comunicare</value>
</data> </data>
<data name="Options_Tabs_Channels" xml:space="preserve"> <data name="Options_Tabs_Channels">
<value>Canale</value> <value>Canale</value>
</data> </data>
<data name="UnreadMode_All_Tooltip" xml:space="preserve"> <data name="UnreadMode_All_Tooltip">
<value>Afișează întotdeauna indicatorii pentru mesajele necitite.</value> <value>Afișează întotdeauna indicatorii pentru mesajele necitite.</value>
</data> </data>
<data name="UnreadMode_Unseen_Tooltip" xml:space="preserve"> <data name="UnreadMode_Unseen_Tooltip">
<value>Afișează indicatorii pentru mesajele necitite doar pentru mesajele pe care nu le-ai văzut.</value> <value>Afișează indicatorii pentru mesajele necitite doar pentru mesajele pe care nu le-ai văzut.</value>
</data> </data>
<data name="UnreadMode_None_Tooltip" xml:space="preserve"> <data name="UnreadMode_None_Tooltip">
<value>Nu arată indicatori pentru mesajele necitite.</value> <value>Nu arată indicatori pentru mesajele necitite.</value>
</data> </data>
<data name="Tab_DefaultName" xml:space="preserve"> <data name="Tab_DefaultName">
<value>Tab nou</value> <value>Tab nou</value>
</data> </data>
<data name="Settings_Kofi" xml:space="preserve"> <data name="Settings_Kofi">
<value>Suportă {0} pe Ko-fi</value> <value>Suportă {0} pe Ko-fi</value>
</data> </data>
<data name="Settings_SaveAndClose" xml:space="preserve"> <data name="Settings_SaveAndClose">
<value>Salvează si închide</value> <value>Salvează si închide</value>
</data> </data>
<data name="Settings_Save" xml:space="preserve"> <data name="Settings_Save">
<value>Salvează</value> <value>Salvează</value>
</data> </data>
<data name="Settings_Discard" xml:space="preserve"> <data name="Settings_Discard">
<value>Anulează</value> <value>Anulează</value>
</data> </data>
<data name="Settings_Title" xml:space="preserve"> <data name="Settings_Title">
<value>Setări {0}</value> <value>Setări {0}</value>
</data> </data>
<data name="ChatLog_SwitcherDisabled" xml:space="preserve"> <data name="ChatLog_SwitcherDisabled">
<value>Dezactivat pentru acest tab.</value> <value>Dezactivat pentru acest tab.</value>
</data> </data>
<data name="ChatLog_HideChat" xml:space="preserve"> <data name="ChatLog_HideChat">
<value>Ascunde chat-ul</value> <value>Ascunde chat-ul</value>
</data> </data>
<data name="ChatLog_Tabs_MoveUp" xml:space="preserve"> <data name="ChatLog_Tabs_MoveUp">
<value>Mută în sus</value> <value>Mută în sus</value>
</data> </data>
<data name="ChatLog_Tabs_MoveLeft" xml:space="preserve"> <data name="ChatLog_Tabs_MoveLeft">
<value>Mută în stânga</value> <value>Mută în stânga</value>
</data> </data>
<data name="ChatLog_Tabs_MoveDown" xml:space="preserve"> <data name="ChatLog_Tabs_MoveDown">
<value>Mută în jos</value> <value>Mută în jos</value>
</data> </data>
<data name="ChatLog_Tabs_MoveRight" xml:space="preserve"> <data name="ChatLog_Tabs_MoveRight">
<value>Mută în dreapta</value> <value>Mută în dreapta</value>
</data> </data>
<data name="Options_Tabs_ChannelTypes_Chat" xml:space="preserve"> <data name="Options_Tabs_ChannelTypes_Chat">
<value>Conversație</value> <value>Conversație</value>
</data> </data>
<data name="Options_Tabs_ChannelTypes_Battle" xml:space="preserve"> <data name="Options_Tabs_ChannelTypes_Battle">
<value>Luptă</value> <value>Luptă</value>
</data> </data>
<data name="Options_Tabs_ChannelTypes_Announcements" xml:space="preserve"> <data name="Options_Tabs_ChannelTypes_Announcements">
<value>Anunțuri</value> <value>Anunțuri</value>
</data> </data>
<data name="UnreadMode_All" xml:space="preserve"> <data name="UnreadMode_All">
<value>Toate</value> <value>Toate</value>
</data> </data>
<data name="UnreadMode_Unseen" xml:space="preserve"> <data name="UnreadMode_Unseen">
<value>Nevăzut</value> <value>Nevăzut</value>
</data> </data>
<data name="UnreadMode_None" xml:space="preserve"> <data name="UnreadMode_None">
<value>Niciunul</value> <value>Niciunul</value>
</data> </data>
<data name="ChatSource_Self" xml:space="preserve"> <data name="ChatSource_Self">
<value>Propriu</value> <value>Propriu</value>
</data> </data>
<data name="ChatSource_PartyMember" xml:space="preserve"> <data name="ChatSource_PartyMember">
<value>Membru al grupului</value> <value>Membru al grupului</value>
</data> </data>
<data name="ChatSource_AllianceMember" xml:space="preserve"> <data name="ChatSource_AllianceMember">
<value>Membru al alianței</value> <value>Membru al alianței</value>
</data> </data>
<data name="ChatSource_Other" xml:space="preserve"> <data name="ChatSource_Other">
<value>Altele</value> <value>Altele</value>
</data> </data>
<data name="ChatSource_EngagedEnemy" xml:space="preserve"> <data name="ChatSource_EngagedEnemy">
<value>Inamic atacat</value> <value>Inamic atacat</value>
</data> </data>
<data name="ChatSource_UnengagedEnemy" xml:space="preserve"> <data name="ChatSource_UnengagedEnemy">
<value>Inamic neatacat</value> <value>Inamic neatacat</value>
</data> </data>
<data name="ChatSource_FriendlyNpc" xml:space="preserve"> <data name="ChatSource_FriendlyNpc">
<value>NPC prietenos</value> <value>NPC prietenos</value>
</data> </data>
<data name="ChatSource_SelfPet" xml:space="preserve"> <data name="ChatSource_SelfPet">
<value>Pet (Propriu)</value> <value>Pet (Propriu)</value>
</data> </data>
<data name="ChatSource_PartyPet" xml:space="preserve"> <data name="ChatSource_PartyPet">
<value>Pet (Grup)</value> <value>Pet (Grup)</value>
</data> </data>
<data name="ChatSource_AlliancePet" xml:space="preserve"> <data name="ChatSource_AlliancePet">
<value>Pet (Membru al alianței)</value> <value>Pet (Membru al alianței)</value>
</data> </data>
<data name="ChatSource_OtherPet" xml:space="preserve"> <data name="ChatSource_OtherPet">
<value>Pet (Altele)</value> <value>Pet (Altele)</value>
</data> </data>
<data name="Options_Font_Name" xml:space="preserve"> <data name="Options_Font_Name">
<value>Font</value> <value>Font</value>
</data> </data>
<data name="Options_JapaneseFont_Name" xml:space="preserve"> <data name="Options_JapaneseFont_Name">
<value>Font japonez</value> <value>Font japonez</value>
</data> </data>
<data name="Options_Font_Description" xml:space="preserve"> <data name="Options_Font_Description">
<value>Fontul pe care {0} îl va folosii sa afișeze text non-japonez.</value> <value>Fontul pe care {0} îl va folosii sa afișeze text non-japonez.</value>
</data> </data>
<data name="Options_Font_Warning" xml:space="preserve"> <data name="Options_Font_Warning">
<value>Folosirea anumitor fonturi de sistem vă poate închide jocul. Ați fost avertizat.</value> <value>Folosirea anumitor fonturi de sistem vă poate închide jocul. Ați fost avertizat.</value>
</data> </data>
<data name="Options_JapaneseFont_Description" xml:space="preserve"> <data name="Options_JapaneseFont_Description">
<value>Fontul care va fi folosit pentru a afișa textul japonez in {0}.</value> <value>Fontul care va fi folosit pentru a afișa textul japonez in {0}.</value>
</data> </data>
<data name="Options_Tabs_ChannelTypes_Special" xml:space="preserve"> <data name="Options_Tabs_ChannelTypes_Special">
<value>Special</value> <value>Special</value>
</data> </data>
<data name="Options_Fonts_Tab" xml:space="preserve"> <data name="Options_Fonts_Tab">
<value>Fonturi</value> <value>Fonturi</value>
</data> </data>
<data name="Options_SymbolsFontSize_Name" xml:space="preserve"> <data name="Options_SymbolsFontSize_Name">
<value>Dimensiunea fontului simbolurilor</value> <value>Dimensiunea fontului simbolurilor</value>
</data> </data>
<data name="Options_JapaneseFontSize_Name" xml:space="preserve"> <data name="Options_JapaneseFontSize_Name">
<value>Dimensiunea fontului japonez</value> <value>Dimensiunea fontului japonez</value>
</data> </data>
<data name="Options_SymbolsFontSize_Description" xml:space="preserve"> <data name="Options_SymbolsFontSize_Description">
<value>Dimensiunea fontului care va fi folosită pentru simbolurile jocului.</value> <value>Dimensiunea fontului care va fi folosită pentru simbolurile jocului.</value>
</data> </data>
<data name="ChatLog_Tabs_Delete" xml:space="preserve"> <data name="ChatLog_Tabs_Delete">
<value>Șterge tabul</value> <value>Șterge tabul</value>
</data> </data>
<data name="Options_HideWhenNotLoggedIn_Name" xml:space="preserve"> <data name="Options_HideWhenNotLoggedIn_Name">
<value>Ascunde când nu ești autentificat</value> <value>Ascunde când nu ești autentificat</value>
</data> </data>
<data name="Options_HideWhenNotLoggedIn_Description" xml:space="preserve"> <data name="Options_HideWhenNotLoggedIn_Description">
<value>Ascunde {0} când nu ești conectat la un caracter.</value> <value>Ascunde {0} când nu ești conectat la un caracter.</value>
</data> </data>
<data name="Tabs_Presets_General" xml:space="preserve"> <data name="Tabs_Presets_General">
<value>General</value> <value>General</value>
</data> </data>
<data name="Options_Tabs_Preset" xml:space="preserve"> <data name="Options_Tabs_Preset">
<value>Presetare: {0}</value> <value>Presetare: {0}</value>
</data> </data>
<data name="Tabs_Presets_Event" xml:space="preserve"> <data name="Tabs_Presets_Event">
<value>Eveniment</value> <value>Eveniment</value>
</data> </data>
<data name="Options_Tabs_NewTab" xml:space="preserve"> <data name="Options_Tabs_NewTab">
<value>Tab nou</value> <value>Tab nou</value>
</data> </data>
<data name="Options_About_Tab" xml:space="preserve"> <data name="Options_About_Tab">
<value>Despre</value> <value>Despre</value>
</data> </data>
<data name="Options_About_Opening" xml:space="preserve"> <data name="Options_About_Opening">
<value>{0} este un proiect care recreează complet chat-ul din joc si îl îmbunătățește.</value> <value>{0} este un proiect care recreează complet chat-ul din joc si îl îmbunătățește.</value>
</data> </data>
<data name="Options_About_ClickUp" xml:space="preserve"> <data name="Options_About_ClickUp">
<value>Apasă butonul din stânga pentru a vedea ce este in lucru si ce urmează.</value> <value>Apasă butonul din stânga pentru a vedea ce este in lucru si ce urmează.</value>
</data> </data>
<data name="Options_About_CrowdIn" xml:space="preserve"> <data name="Options_About_CrowdIn">
<value>Apasă butonul din stânga pentru a contribui la traducerea {0}.</value> <value>Apasă butonul din stânga pentru a contribui la traducerea {0}.</value>
</data> </data>
<data name="Options_About_Translators" xml:space="preserve"> <data name="Options_About_Translators">
<value>Traducători</value> <value>Traducători</value>
</data> </data>
<data name="CommandHelpSide_None" xml:space="preserve"> <data name="CommandHelpSide_None">
<value>Niciunul</value> <value>Niciunul</value>
</data> </data>
<data name="CommandHelpSide_Left" xml:space="preserve"> <data name="CommandHelpSide_Left">
<value>Stânga</value> <value>Stânga</value>
</data> </data>
<data name="CommandHelpSide_Right" xml:space="preserve"> <data name="CommandHelpSide_Right">
<value>Dreapta</value> <value>Dreapta</value>
</data> </data>
<data name="Options_CommandHelpSide_Name" xml:space="preserve"> <data name="Options_CommandHelpSide_Name">
<value>Partea pentru ajutor la comenzi</value> <value>Partea pentru ajutor la comenzi</value>
</data> </data>
<data name="Options_CommandHelpSide_Description" xml:space="preserve"> <data name="Options_CommandHelpSide_Description">
<value>Partea {0}-ului de afișare a ajutorului pentru comenzi.</value> <value>Partea {0}-ului de afișare a ajutorului pentru comenzi.</value>
</data> </data>
<data name="Options_HideWhenUiHidden_Name" xml:space="preserve"> <data name="Options_HideWhenUiHidden_Name">
<value>Ascunde când interfața jocului este ascunsă</value> <value>Ascunde când interfața jocului este ascunsă</value>
</data> </data>
<data name="Options_HideWhenUiHidden_Description" xml:space="preserve"> <data name="Options_HideWhenUiHidden_Description">
<value>Ascunde {0} atunci când interfața jocului este ascunsă.</value> <value>Ascunde {0} atunci când interfața jocului este ascunsă.</value>
</data> </data>
<data name="Options_KeybindMode_Name" xml:space="preserve"> <data name="Options_KeybindMode_Name">
<value>Modul scurtăturilor</value> <value>Modul scurtăturilor</value>
</data> </data>
<data name="Options_KeybindMode_Description" xml:space="preserve"> <data name="Options_KeybindMode_Description">
<value>Modul în care {0} ar trebui să se ocupe de scurtături.</value> <value>Modul în care {0} ar trebui să se ocupe de scurtături.</value>
</data> </data>
<data name="Options_Miscellaneous_Tab" xml:space="preserve"> <data name="Options_Miscellaneous_Tab">
<value>Diverse</value> <value>Diverse</value>
</data> </data>
<data name="LanguageOverride_None" xml:space="preserve"> <data name="LanguageOverride_None">
<value>Folosește limba implicită a lui Dalamud</value> <value>Folosește limba implicită a lui Dalamud</value>
</data> </data>
<data name="KeybindMode_Flexible_Name" xml:space="preserve"> <data name="KeybindMode_Flexible_Name">
<value>Flexibil</value> <value>Flexibil</value>
</data> </data>
<data name="KeybindMode_Strict_Name" xml:space="preserve"> <data name="KeybindMode_Strict_Name">
<value>Strict</value> <value>Strict</value>
</data> </data>
<data name="KeybindMode_Flexible_Tooltip" xml:space="preserve"> <data name="KeybindMode_Flexible_Tooltip">
<value>Procesează funcția tastelor cu modificatori, chiar dacă sunt apăsați alți modificatori.</value> <value>Procesează funcția tastelor cu modificatori, chiar dacă sunt apăsați alți modificatori.</value>
</data> </data>
<data name="KeybindMode_Strict_Tooltip" xml:space="preserve"> <data name="KeybindMode_Strict_Tooltip">
<value>Procesează tastele cu modificatori doar daca alți modificatori nu sunt apăsați.</value> <value>Procesează tastele cu modificatori doar daca alți modificatori nu sunt apăsați.</value>
</data> </data>
<data name="Options_Language_Name" xml:space="preserve"> <data name="Options_Language_Name">
<value>Limbă</value> <value>Limbă</value>
</data> </data>
<data name="Options_Language_Description" xml:space="preserve"> <data name="Options_Language_Description">
<value>Limba în care se afișează {0}.</value> <value>Limba în care se afișează {0}.</value>
</data> </data>
<data name="Options_DatabaseBattleMessages_Name" xml:space="preserve"> <data name="Options_DatabaseBattleMessages_Name">
<value>Salvează mesajele de luptă în baza de date</value> <value>Salvează mesajele de luptă în baza de date</value>
</data> </data>
<data name="Options_DatabaseBattleMessages_Description" xml:space="preserve"> <data name="Options_DatabaseBattleMessages_Description">
<value>Daca mesajele de lupta sunt salvate in baza de date, dimensiunea bazei de date va creste mult mai repede, și va exista o întârziere vizibilă la salvarea setărilor. Este recomandat să lăsați aceasta opțiune dezactivată.</value> <value>Daca mesajele de lupta sunt salvate in baza de date, dimensiunea bazei de date va creste mult mai repede, și va exista o întârziere vizibilă la salvarea setărilor. Este recomandat să lăsați aceasta opțiune dezactivată.</value>
</data> </data>
<data name="Options_LoadPreviousSession_Name" xml:space="preserve"> <data name="Options_LoadPreviousSession_Name">
<value>Afișează sesiunea anterioară a chat-ului la autentificare</value> <value>Afișează sesiunea anterioară a chat-ului la autentificare</value>
</data> </data>
<data name="Options_LoadPreviousSession_Description" xml:space="preserve"> <data name="Options_LoadPreviousSession_Description">
<value>După autentificare, populează chat-ul cu mesajele de când te-ai deconectat ultima dată.</value> <value>După autentificare, populează chat-ul cu mesajele de când te-ai deconectat ultima dată.</value>
</data> </data>
<data name="Options_Database_Tab" xml:space="preserve"> <data name="Options_Database_Tab">
<value>Bază de date</value> <value>Bază de date</value>
</data> </data>
<data name="Options_FilterIncludePreviousSessions_Name" xml:space="preserve"> <data name="Options_FilterIncludePreviousSessions_Name">
<value>Include sesiunile anterioare la popularea taburilor</value> <value>Include sesiunile anterioare la popularea taburilor</value>
</data> </data>
<data name="Options_FilterIncludePreviousSessions_Description" xml:space="preserve"> <data name="Options_FilterIncludePreviousSessions_Description">
<value>Include mesaje de dinaintea lansării jocului atunci când se populează taburile. Taburile sunt populate atunci când setările sunt salvate.</value> <value>Include mesaje de dinaintea lansării jocului atunci când se populează taburile. Taburile sunt populate atunci când setările sunt salvate.</value>
</data> </data>
<data name="Options_Database_Advanced_Warning" xml:space="preserve"> <data name="Options_Database_Advanced_Warning">
<value>Nu apasă butoanele astea daca nu știi ce faci.</value> <value>Nu apasă butoanele astea daca nu știi ce faci.</value>
</data> </data>
<data name="Options_Database_Advanced" xml:space="preserve"> <data name="Options_Database_Advanced">
<value>Avansat</value> <value>Avansat</value>
</data> </data>
<data name="Options_SharedMode_Name" xml:space="preserve"> <data name="Options_SharedMode_Name">
<value>Activează modul instanțelor multiple</value> <value>Activează modul instanțelor multiple</value>
</data> </data>
<data name="Options_SharedMode_Description" xml:space="preserve"> <data name="Options_SharedMode_Description">
<value>Permite mai multor instanțe sa folosească {0} simultan, folosind aceeași data de baze.</value> <value>Permite mai multor instanțe sa folosească {0} simultan, folosind aceeași data de baze.</value>
</data> </data>
<data name="Options_SharedMode_Warning" xml:space="preserve"> <data name="Options_SharedMode_Warning">
<value>Această opțiune nu este recomandată. Dacă o activați nu veți primi niciun suport. Această opțiune va afecta performanța {0}-ului.</value> <value>Această opțiune nu este recomandată. Dacă o activați nu veți primi niciun suport. Această opțiune va afecta performanța {0}-ului.</value>
</data> </data>
<data name="ChatLog_Tabs_PopOut" xml:space="preserve"> <data name="ChatLog_Tabs_PopOut">
<value>Mută tabul într-o fereastra noua</value> <value>Mută tabul într-o fereastra noua</value>
</data> </data>
<data name="Options_HideSameTimestamps_Name" xml:space="preserve"> <data name="Options_HideSameTimestamps_Name">
<value>Ascunde marcajele de timp când nu sunt necesare</value> <value>Ascunde marcajele de timp când nu sunt necesare</value>
</data> </data>
<data name="Options_HideSameTimestamps_Description" xml:space="preserve"> <data name="Options_HideSameTimestamps_Description">
<value>Ascunde marcajele de timp atunci când mesajele anterioare au aceeași marcă de timp.</value> <value>Ascunde marcajele de timp atunci când mesajele anterioare au aceeași marcă de timp.</value>
</data> </data>
<data name="Options_ShowPopOutTitleBar_Name" xml:space="preserve"> <data name="Options_ShowPopOutTitleBar_Name">
<value>Arată bara de titlu pentru tab-urile in ferestre diferite</value> <value>Arată bara de titlu pentru tab-urile in ferestre diferite</value>
</data> </data>
<data name="Options_Tabs_PopOut" xml:space="preserve"> <data name="Options_Tabs_PopOut">
<value>Afișează într-o fereastră separată</value> <value>Afișează într-o fereastră separată</value>
</data> </data>
<data name="Options_Tabs_IndependentOpacity" xml:space="preserve"> <data name="Options_Tabs_IndependentOpacity">
<value>Folosește o transparentă diferită de fereastra principală</value> <value>Folosește o transparentă diferită de fereastra principală</value>
</data> </data>
<data name="Options_Tabs_Opacity" xml:space="preserve"> <data name="Options_Tabs_Opacity">
<value>Transparență</value> <value>Transparență</value>
</data> </data>
<data name="Options_FontsEnabled" xml:space="preserve"> <data name="Options_FontsEnabled">
<value>Activează fonturi personalizate</value> <value>Activează fonturi personalizate</value>
</data> </data>
<data name="AutoTranslate_Search_Hint" xml:space="preserve"> <data name="AutoTranslate_Search_Hint">
<value>Caută traducere automată...</value> <value>Caută traducere automată...</value>
</data> </data>
<data name="Options_SortAutoTranslate_Name" xml:space="preserve"> <data name="Options_SortAutoTranslate_Name">
<value>Sortează lista de traduceri automate</value> <value>Sortează lista de traduceri automate</value>
</data> </data>
<data name="Options_SortAutoTranslate_Description" xml:space="preserve"> <data name="Options_SortAutoTranslate_Description">
<value>Dacă această opțiune este activată, lista de traduceri automate va fi sortată alfabetic.</value> <value>Dacă această opțiune este activată, lista de traduceri automate va fi sortată alfabetic.</value>
</data> </data>
<data name="AutoTranslate_Completion_Key" xml:space="preserve"> <data name="AutoTranslate_Completion_Key">
<value>Ctrl + {0}</value> <value>Ctrl + {0}</value>
</data> </data>
<data name="Options_ExtraGlyphs_Name" xml:space="preserve"> <data name="Options_ExtraGlyphs_Name">
<value>Caractere suplimentare</value> <value>Caractere suplimentare</value>
</data> </data>
<data name="Options_ExtraGlyphs_Description" xml:space="preserve"> <data name="Options_ExtraGlyphs_Description">
<value>Pot fi adăugate mai multe caractere la fontul global al {0} prin activarea opțiunilor de mai jos. Este posibil să fie necesară creșterea dimensiunilor fontului din Dalamud.</value> <value>Pot fi adăugate mai multe caractere la fontul global al {0} prin activarea opțiunilor de mai jos. Este posibil să fie necesară creșterea dimensiunilor fontului din Dalamud.</value>
</data> </data>
<data name="ExtraGlyphRanges_ChineseFull_Name" xml:space="preserve"> <data name="ExtraGlyphRanges_ChineseFull_Name">
<value>Chineză (completă)</value> <value>Chineză (completă)</value>
</data> </data>
<data name="ExtraGlyphRanges_ChineseSimplifiedCommon_Name" xml:space="preserve"> <data name="ExtraGlyphRanges_ChineseSimplifiedCommon_Name">
<value>Chineză (simplificată)</value> <value>Chineză (simplificată)</value>
</data> </data>
<data name="ExtraGlyphRanges_Cyrillic_Name" xml:space="preserve"> <data name="ExtraGlyphRanges_Cyrillic_Name">
<value>Chirilică</value> <value>Chirilică</value>
</data> </data>
<data name="ExtraGlyphRanges_Japanese_Name" xml:space="preserve"> <data name="ExtraGlyphRanges_Japanese_Name">
<value>Japoneză</value> <value>Japoneză</value>
</data> </data>
<data name="ExtraGlyphRanges_Korean_Name" xml:space="preserve"> <data name="ExtraGlyphRanges_Korean_Name">
<value>Coreeană</value> <value>Coreeană</value>
</data> </data>
<data name="ExtraGlyphRanges_Thai_Name" xml:space="preserve"> <data name="ExtraGlyphRanges_Thai_Name">
<value>Tailandeză</value> <value>Tailandeză</value>
</data> </data>
<data name="ExtraGlyphRanges_Vietnamese_Name" xml:space="preserve"> <data name="ExtraGlyphRanges_Vietnamese_Name">
<value>Vietnameză</value> <value>Vietnameză</value>
</data> </data>
</root> </root>

File diff suppressed because it is too large Load Diff

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

File diff suppressed because it is too large Load Diff

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

View File

@ -121,245 +121,4 @@
PublicKeyToken=b77a5c561934e089 PublicKeyToken=b77a5c561934e089
</value> </value>
</resheader> </resheader>
</root> </root>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,13 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Diagnostics; using System.Diagnostics;
using System.Numerics;
using ChatTwo.Code; using ChatTwo.Code;
using ChatTwo.Resources;
using ChatTwo.Util; using ChatTwo.Util;
using Dalamud.Game;
using Dalamud.Game.Text; using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Plugin.Services;
using ImGuiNET;
using LiteDB; using LiteDB;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
@ -39,20 +42,40 @@ internal class Store : IDisposable {
TrimWhitespace = false, TrimWhitespace = false,
// EnumAsInteger = true, // EnumAsInteger = true,
}; };
BsonMapper.Global.Entity<Message>()
.Id(msg => msg.Id) if (this.Plugin.Config.DatabaseMigration == 0) {
.Ctor(doc => new Message( BsonMapper.Global.Entity<Message>()
doc["_id"].AsObjectId, .Id(msg => msg.Id)
(ulong) doc["Receiver"].AsInt64, .Ctor(doc => new Message(
(ulong) doc["ContentId"].AsInt64, doc["_id"].AsObjectId,
DateTime.UnixEpoch.AddMilliseconds(doc["Date"].AsInt64), (ulong) doc["Receiver"].AsInt64,
doc["Code"].AsDocument, (ulong) doc["ContentId"].AsInt64,
doc["Sender"].AsArray, DateTime.UnixEpoch.AddMilliseconds(doc["Date"].AsInt64),
doc["Content"].AsArray, doc["Code"].AsDocument,
doc["SenderSource"], doc["Sender"].AsArray,
doc["ContentSource"], doc["Content"].AsArray,
doc["SortCode"].AsDocument doc["SenderSource"],
)); doc["ContentSource"],
doc["SortCode"].AsDocument
));
} else {
BsonMapper.Global.Entity<Message>()
.Id(msg => msg.Id)
.Ctor(doc => new Message(
doc["_id"].AsObjectId,
(ulong) doc["Receiver"].AsInt64,
(ulong) doc["ContentId"].AsInt64,
DateTime.UnixEpoch.AddMilliseconds(doc["Date"].AsInt64),
doc["Code"].AsDocument,
doc["Sender"].AsArray,
doc["Content"].AsArray,
doc["SenderSource"],
doc["ContentSource"],
doc["SortCode"].AsDocument,
doc["ExtraChatChannel"]
));
}
BsonMapper.Global.RegisterType<Payload?>( BsonMapper.Global.RegisterType<Payload?>(
payload => { payload => {
switch (payload) { switch (payload) {
@ -116,6 +139,9 @@ internal class Store : IDisposable {
this.Database = this.Connect(); this.Database = this.Connect();
this.Messages.EnsureIndex(msg => msg.Date); this.Messages.EnsureIndex(msg => msg.Date);
this.Messages.EnsureIndex(msg => msg.SortCode); this.Messages.EnsureIndex(msg => msg.SortCode);
this.Messages.EnsureIndex(msg => msg.ExtraChatChannel);
this.MigrateWrapper();
this.Plugin.ChatGui.ChatMessageUnhandled += this.ChatMessage; this.Plugin.ChatGui.ChatMessageUnhandled += this.ChatMessage;
this.Plugin.Framework.Update += this.GetMessageInfo; this.Plugin.Framework.Update += this.GetMessageInfo;
@ -150,18 +176,18 @@ internal class Store : IDisposable {
this.Database = this.Connect(); this.Database = this.Connect();
} }
private void Logout(object? sender, EventArgs eventArgs) { private void Logout() {
this.LastContentId = 0; this.LastContentId = 0;
} }
private void UpdateReceiver(Framework framework) { private void UpdateReceiver(IFramework framework) {
var contentId = this.Plugin.ClientState.LocalContentId; var contentId = this.Plugin.ClientState.LocalContentId;
if (contentId != 0) { if (contentId != 0) {
this.LastContentId = contentId; this.LastContentId = contentId;
} }
} }
private void GetMessageInfo(Framework framework) { private void GetMessageInfo(IFramework framework) {
if (this.CheckpointTimer.Elapsed > TimeSpan.FromMinutes(5)) { if (this.CheckpointTimer.Elapsed > TimeSpan.FromMinutes(5)) {
this.CheckpointTimer.Restart(); this.CheckpointTimer.Restart();
new Thread(() => this.Database.Checkpoint()).Start(); new Thread(() => this.Database.Checkpoint()).Start();
@ -178,6 +204,87 @@ internal class Store : IDisposable {
} }
} }
private long _migrateCurrent;
private long _migrateMax;
private void MigrateDraw() {
ImGui.SetNextWindowSizeConstraints(new Vector2(450, 0), new Vector2(450, float.MaxValue));
if (!ImGui.Begin($"{Plugin.Name}##migration-window", ImGuiWindowFlags.AlwaysAutoResize)) {
ImGui.End();
return;
}
ImGui.PushTextWrapPos();
ImGui.TextUnformatted(string.Format(Language.Migration_Line1, Plugin.PluginName));
ImGui.TextUnformatted(string.Format(Language.Migration_Line2, Plugin.PluginName));
ImGui.TextUnformatted(Language.Migration_Line3);
ImGui.TextUnformatted(Language.Migration_Line4);
ImGui.PopTextWrapPos();
ImGui.Spacing();
ImGui.ProgressBar((float) this._migrateCurrent / this._migrateMax, new Vector2(-1, 0), $"{this._migrateCurrent} / {this._migrateMax}");
ImGui.End();
}
internal void MigrateWrapper() {
if (this.Plugin.Config.DatabaseMigration < Configuration.LatestDbVersion) {
this.Plugin.Interface.UiBuilder.Draw += this.MigrateDraw;
}
try {
this.Migrate();
} finally {
this.Plugin.Interface.UiBuilder.Draw -= this.MigrateDraw;
}
}
internal void Migrate() {
// re-save all messages, which will add the ExtraChat channel
if (this.Plugin.Config.DatabaseMigration == 0) {
var total = (float) this.Messages.LongCount() / 10_000.0;
var rounds = (long) Math.Ceiling(total);
this._migrateMax = rounds;
var lastId = ObjectId.Empty;
for (var i = 0; i < rounds; i++) {
this._migrateCurrent = i + 1;
Plugin.Log.Info($"Update round {i + 1}/{rounds}");
var messages = this.Messages.Query()
.OrderBy(msg => msg.Id)
.Where(msg => msg.Id > lastId)
.Limit(10_000)
.ToArray();
foreach (var message in messages) {
this.Messages.Update(message);
lastId = message.Id;
}
}
this.Database.Checkpoint();
BsonMapper.Global.Entity<Message>()
.Id(msg => msg.Id)
.Ctor(doc => new Message(
doc["_id"].AsObjectId,
(ulong) doc["Receiver"].AsInt64,
(ulong) doc["ContentId"].AsInt64,
DateTime.UnixEpoch.AddMilliseconds(doc["Date"].AsInt64),
doc["Code"].AsDocument,
doc["Sender"].AsArray,
doc["Content"].AsArray,
doc["SenderSource"],
doc["ContentSource"],
doc["SortCode"].AsDocument,
doc["ExtraChatChannel"]
));
this.Plugin.Config.DatabaseMigration = 1;
this.Plugin.SaveConfig();
}
}
internal void AddMessage(Message message, Tab? currentTab) { internal void AddMessage(Message message, Tab? currentTab) {
if (this.Plugin.Config.DatabaseBattleMessages || !message.Code.IsBattle()) { if (this.Plugin.Config.DatabaseBattleMessages || !message.Code.IsBattle()) {
this.Messages.Insert(message); this.Messages.Insert(message);
@ -218,7 +325,7 @@ internal class Store : IDisposable {
var query = this.Messages var query = this.Messages
.Query() .Query()
.OrderByDescending(msg => msg.Date) .OrderByDescending(msg => msg.Date)
.Where(msg => sortCodes.Contains(msg.SortCode)) .Where(msg => sortCodes.Contains(msg.SortCode) || msg.ExtraChatChannel != Guid.Empty)
.Where(msg => msg.Receiver == this.CurrentContentId); .Where(msg => msg.Receiver == this.CurrentContentId);
if (!this.Plugin.Config.FilterIncludePreviousSessions) { if (!this.Plugin.Config.FilterIncludePreviousSessions) {
query = query.Where(msg => msg.Date >= this.Plugin.GameStarted); query = query.Where(msg => msg.Date >= this.Plugin.GameStarted);

View File

@ -1,22 +1,22 @@
using Dalamud.Data; using Dalamud.Interface.Internal;
using ImGuiScene; using Dalamud.Plugin.Services;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
namespace ChatTwo; namespace ChatTwo;
internal class TextureCache : IDisposable { internal class TextureCache : IDisposable {
private DataManager Data { get; } private ITextureProvider TextureProvider { get; }
private readonly Dictionary<(uint, bool), TextureWrap> _itemIcons = new(); private readonly Dictionary<(uint, bool), IDalamudTextureWrap> _itemIcons = new();
private readonly Dictionary<(uint, bool), TextureWrap> _statusIcons = new(); private readonly Dictionary<(uint, bool), IDalamudTextureWrap> _statusIcons = new();
private readonly Dictionary<(uint, bool), TextureWrap> _eventItemIcons = new(); private readonly Dictionary<(uint, bool), IDalamudTextureWrap> _eventItemIcons = new();
internal IReadOnlyDictionary<(uint, bool), TextureWrap> ItemIcons => this._itemIcons; internal IReadOnlyDictionary<(uint, bool), IDalamudTextureWrap> ItemIcons => this._itemIcons;
internal IReadOnlyDictionary<(uint, bool), TextureWrap> StatusIcons => this._statusIcons; internal IReadOnlyDictionary<(uint, bool), IDalamudTextureWrap> StatusIcons => this._statusIcons;
internal IReadOnlyDictionary<(uint, bool), TextureWrap> EventItemIcons => this._eventItemIcons; internal IReadOnlyDictionary<(uint, bool), IDalamudTextureWrap> EventItemIcons => this._eventItemIcons;
internal TextureCache(DataManager data) { internal TextureCache(ITextureProvider textureProvider) {
this.Data = data; this.TextureProvider = textureProvider;
} }
public void Dispose() { public void Dispose() {
@ -28,14 +28,14 @@ internal class TextureCache : IDisposable {
} }
} }
private void AddIcon(IDictionary<(uint, bool), TextureWrap> dict, uint icon, bool hq = false) { private void AddIcon(IDictionary<(uint, bool), IDalamudTextureWrap> dict, uint icon, bool hq = false) {
if (dict.ContainsKey((icon, hq))) { if (dict.ContainsKey((icon, hq))) {
return; return;
} }
var tex = hq var tex = hq
? this.Data.GetImGuiTextureHqIcon(icon) ? this.TextureProvider.GetIcon(icon, ITextureProvider.IconFlags.ItemHighQuality)
: this.Data.GetImGuiTextureIcon(icon); : this.TextureProvider.GetIcon(icon);
if (tex != null) { if (tex != null) {
dict[(icon, hq)] = tex; dict[(icon, hq)] = tex;
} }
@ -53,19 +53,19 @@ internal class TextureCache : IDisposable {
this.AddIcon(this._eventItemIcons, item.Icon); this.AddIcon(this._eventItemIcons, item.Icon);
} }
internal TextureWrap? GetItem(Item item, bool hq = false) { internal IDalamudTextureWrap? GetItem(Item item, bool hq = false) {
this.AddItem(item, hq); this.AddItem(item, hq);
this.ItemIcons.TryGetValue((item.Icon, hq), out var icon); this.ItemIcons.TryGetValue((item.Icon, hq), out var icon);
return icon; return icon;
} }
internal TextureWrap? GetStatus(Status status) { internal IDalamudTextureWrap? GetStatus(Status status) {
this.AddStatus(status); this.AddStatus(status);
this.StatusIcons.TryGetValue((status.Icon, false), out var icon); this.StatusIcons.TryGetValue((status.Icon, false), out var icon);
return icon; return icon;
} }
internal TextureWrap? GetEventItem(EventItem item) { internal IDalamudTextureWrap? GetEventItem(EventItem item) {
this.AddEventItem(item); this.AddEventItem(item);
this.EventItemIcons.TryGetValue((item.Icon, false), out var icon); this.EventItemIcons.TryGetValue((item.Icon, false), out var icon);
return icon; return icon;

View File

@ -11,10 +11,10 @@ using Dalamud.Game.ClientState.Keys;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Logging; using Dalamud.Interface.Internal;
using Dalamud.Interface.Utility;
using Dalamud.Memory; using Dalamud.Memory;
using ImGuiNET; using ImGuiNET;
using ImGuiScene;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
namespace ChatTwo.Ui; namespace ChatTwo.Ui;
@ -28,7 +28,7 @@ internal sealed class ChatLog : IUiComponent {
internal bool Activate; internal bool Activate;
private int _activatePos = -1; private int _activatePos = -1;
internal string Chat = string.Empty; internal string Chat = string.Empty;
private readonly TextureWrap? _fontIcon; private readonly IDalamudTextureWrap? _fontIcon;
private readonly List<string> _inputBacklog = new(); private readonly List<string> _inputBacklog = new();
private int _inputBacklogIdx = -1; private int _inputBacklogIdx = -1;
internal int LastTab { get; private set; } internal int LastTab { get; private set; }
@ -62,7 +62,7 @@ internal sealed class ChatLog : IUiComponent {
this.Ui.Plugin.Commands.Register("/clearlog2", "Clear the Chat 2 chat log").Execute += this.ClearLog; this.Ui.Plugin.Commands.Register("/clearlog2", "Clear the Chat 2 chat log").Execute += this.ClearLog;
this.Ui.Plugin.Commands.Register("/chat2").Execute += this.ToggleChat; this.Ui.Plugin.Commands.Register("/chat2").Execute += this.ToggleChat;
this._fontIcon = this.Ui.Plugin.DataManager.GetImGuiTexture("common/font/fonticon_ps5.tex"); this._fontIcon = this.Ui.Plugin.TextureProvider.GetTextureFromGame("common/font/fonticon_ps5.tex");
this.Ui.Plugin.Functions.Chat.Activated += this.Activated; this.Ui.Plugin.Functions.Chat.Activated += this.Activated;
this.Ui.Plugin.ClientState.Login += this.Login; this.Ui.Plugin.ClientState.Login += this.Login;
@ -78,13 +78,13 @@ internal sealed class ChatLog : IUiComponent {
this.Ui.Plugin.Commands.Register("/clearlog2").Execute -= this.ClearLog; this.Ui.Plugin.Commands.Register("/clearlog2").Execute -= this.ClearLog;
} }
private void Logout(object? sender, EventArgs e) { private void Logout() {
foreach (var tab in this.Ui.Plugin.Config.Tabs) { foreach (var tab in this.Ui.Plugin.Config.Tabs) {
tab.Clear(); tab.Clear();
} }
} }
private void Login(object? sender, EventArgs e) { private void Login() {
this.Ui.Plugin.Store.FilterAllTabs(false); this.Ui.Plugin.Store.FilterAllTabs(false);
} }
@ -327,7 +327,7 @@ internal sealed class ChatLog : IUiComponent {
TellReason = reason, TellReason = reason,
}); });
} catch (Exception ex) { } catch (Exception ex) {
PluginLog.LogError(ex, "Error in chat Activated event"); Plugin.Log.Error(ex, "Error in chat Activated event");
} }
} }
} }
@ -415,7 +415,7 @@ internal sealed class ChatLog : IUiComponent {
ImGui.SetNextWindowSize(new Vector2(500, 250) * ImGuiHelpers.GlobalScale, ImGuiCond.FirstUseEver); ImGui.SetNextWindowSize(new Vector2(500, 250) * ImGuiHelpers.GlobalScale, ImGuiCond.FirstUseEver);
if (!ImGui.Begin($"{this.Ui.Plugin.Name}###chat2", flags)) { if (!ImGui.Begin($"{Plugin.Name}###chat2", flags)) {
this._lastViewport = ImGui.GetWindowViewport().NativePtr; this._lastViewport = ImGui.GetWindowViewport().NativePtr;
this._wasDocked = ImGui.IsWindowDocked(); this._wasDocked = ImGui.IsWindowDocked();
ImGui.End(); ImGui.End();
@ -707,7 +707,7 @@ internal sealed class ChatLog : IUiComponent {
} }
try { try {
tab.MessagesMutex.WaitOne(); tab.MessagesMutex.Wait();
var reset = false; var reset = false;
if (this._lastResize.IsRunning && this._lastResize.Elapsed.TotalSeconds > 0.25) { if (this._lastResize.IsRunning && this._lastResize.Elapsed.TotalSeconds > 0.25) {
@ -820,7 +820,12 @@ internal sealed class ChatLog : IUiComponent {
ImGui.SameLine(); ImGui.SameLine();
} }
this.DrawChunks(message.Content, true, handler, lineWidth); if (message.Content.Count == 0) {
this.DrawChunks(new[] { new TextChunk(ChunkSource.Content, null, " ") }, true, handler, lineWidth);
} else {
this.DrawChunks(message.Content, true, handler, lineWidth);
}
var afterDraw = ImGui.GetCursorScreenPos(); var afterDraw = ImGui.GetCursorScreenPos();
message.Height = ImGui.GetCursorPosY() - lastPos; message.Height = ImGui.GetCursorPosY() - lastPos;
@ -836,7 +841,7 @@ internal sealed class ChatLog : IUiComponent {
lastPos = ImGui.GetCursorPosY(); lastPos = ImGui.GetCursorPosY();
} }
} finally { } finally {
tab.MessagesMutex.ReleaseMutex(); tab.MessagesMutex.Release();
ImGui.PopStyleVar(this.Ui.Plugin.Config.PrettierTimestamps && this.Ui.Plugin.Config.MoreCompactPretty ? 2 : 1); ImGui.PopStyleVar(this.Ui.Plugin.Config.PrettierTimestamps && this.Ui.Plugin.Config.MoreCompactPretty ? 2 : 1);
} }

View File

@ -1,6 +1,6 @@
using System.Numerics; using System.Numerics;
using ChatTwo.Util; using ChatTwo.Util;
using Dalamud.Interface; using Dalamud.Interface.Utility;
using Dalamud.Utility; using Dalamud.Utility;
using ImGuiNET; using ImGuiNET;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;

View File

@ -3,7 +3,7 @@ using System.Numerics;
using ChatTwo.Resources; using ChatTwo.Resources;
using ChatTwo.Ui.SettingsTabs; using ChatTwo.Ui.SettingsTabs;
using ChatTwo.Util; using ChatTwo.Util;
using Dalamud.Interface; using Dalamud.Interface.Utility;
using ImGuiNET; using ImGuiNET;
namespace ChatTwo.Ui; namespace ChatTwo.Ui;
@ -13,7 +13,6 @@ internal sealed class Settings : IUiComponent {
private Configuration Mutable { get; } private Configuration Mutable { get; }
private List<ISettingsTab> Tabs { get; } private List<ISettingsTab> Tabs { get; }
private int _currentTab; private int _currentTab;
internal Settings(PluginUi ui) { internal Settings(PluginUi ui) {
@ -62,7 +61,7 @@ internal sealed class Settings : IUiComponent {
ImGui.SetNextWindowSize(new Vector2(475, 600) * ImGuiHelpers.GlobalScale, ImGuiCond.FirstUseEver); ImGui.SetNextWindowSize(new Vector2(475, 600) * ImGuiHelpers.GlobalScale, ImGuiCond.FirstUseEver);
var name = string.Format(Language.Settings_Title, this.Ui.Plugin.Name); var name = string.Format(Language.Settings_Title, Plugin.Name);
if (!ImGui.Begin($"{name}###chat2-settings", ref this.Ui.SettingsVisible, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)) { if (!ImGui.Begin($"{name}###chat2-settings", ref this.Ui.SettingsVisible, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)) {
ImGui.End(); ImGui.End();
return; return;
@ -118,7 +117,7 @@ internal sealed class Settings : IUiComponent {
this.Ui.SettingsVisible = false; this.Ui.SettingsVisible = false;
} }
var buttonLabel = string.Format(Language.Settings_Kofi, this.Ui.Plugin.Name); var buttonLabel = string.Format(Language.Settings_Kofi, Plugin.Name);
ImGui.PushStyleColor(ImGuiCol.Button, ColourUtil.RgbaToAbgr(0xFF5E5BFF)); ImGui.PushStyleColor(ImGuiCol.Button, ColourUtil.RgbaToAbgr(0xFF5E5BFF));
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, ColourUtil.RgbaToAbgr(0xFF7775FF)); ImGui.PushStyleColor(ImGuiCol.ButtonHovered, ColourUtil.RgbaToAbgr(0xFF7775FF));
@ -130,7 +129,7 @@ internal sealed class Settings : IUiComponent {
ImGui.SameLine(ImGui.GetContentRegionAvail().X - buttonWidth); ImGui.SameLine(ImGui.GetContentRegionAvail().X - buttonWidth);
if (ImGui.Button(buttonLabel)) { if (ImGui.Button(buttonLabel)) {
Process.Start(new ProcessStartInfo("https://ko-fi.com/ascclemens") { Process.Start(new ProcessStartInfo("https://ko-fi.com/lojewalo") {
UseShellExecute = true, UseShellExecute = true,
}); });
} }

View File

@ -23,10 +23,10 @@ internal sealed class ChatColours : ISettingsTab {
.ToHashSet(); .ToHashSet();
var total = Enum.GetValues<ChatType>().Where(type => !type.IsGm()).ToHashSet(); var total = Enum.GetValues<ChatType>().Where(type => !type.IsGm()).ToHashSet();
if (sortable.Count != total.Count) { if (sortable.Count != total.Count) {
Dalamud.Logging.PluginLog.Warning($"There are {sortable.Count} sortable channels, but there are {total.Count} total channels."); Dalamud.Logging.Plugin.Log.Warning($"There are {sortable.Count} sortable channels, but there are {total.Count} total channels.");
total.ExceptWith(sortable); total.ExceptWith(sortable);
foreach (var missing in total) { foreach (var missing in total) {
Dalamud.Logging.PluginLog.Log($"Missing {missing}"); Dalamud.Logging.Plugin.Log.Log($"Missing {missing}");
} }
} }
#endif #endif

View File

@ -1,9 +1,9 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using Dalamud; using Dalamud;
using Dalamud.Data;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Plugin.Services;
using Dalamud.Utility; using Dalamud.Utility;
using Lumina.Excel; using Lumina.Excel;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
@ -89,7 +89,7 @@ internal static class AutoTranslate {
return string.Join("", payloads); return string.Join("", payloads);
} }
private static List<AutoTranslateEntry> AllEntries(DataManager data) { private static List<AutoTranslateEntry> AllEntries(IDataManager data) {
if (Entries.TryGetValue(data.Language, out var entries)) { if (Entries.TryGetValue(data.Language, out var entries)) {
return entries; return entries;
} }
@ -197,7 +197,7 @@ internal static class AutoTranslate {
return list; return list;
} }
internal static List<AutoTranslateEntry> Matching(DataManager data, string prefix, bool sort) { internal static List<AutoTranslateEntry> Matching(IDataManager data, string prefix, bool sort) {
var wholeMatches = new List<AutoTranslateEntry>(); var wholeMatches = new List<AutoTranslateEntry>();
var prefixMatches = new List<AutoTranslateEntry>(); var prefixMatches = new List<AutoTranslateEntry>();
var otherMatches = new List<AutoTranslateEntry>(); var otherMatches = new List<AutoTranslateEntry>();
@ -227,7 +227,7 @@ internal static class AutoTranslate {
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)] [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int memcmp(byte[] b1, byte[] b2, UIntPtr count); private static extern int memcmp(byte[] b1, byte[] b2, UIntPtr count);
internal static void ReplaceWithPayload(DataManager data, ref byte[] bytes) { internal static void ReplaceWithPayload(IDataManager data, ref byte[] bytes) {
var search = Encoding.UTF8.GetBytes("<at:"); var search = Encoding.UTF8.GetBytes("<at:");
if (bytes.Length <= search.Length) { if (bytes.Length <= search.Length) {
return; return;

View File

@ -63,11 +63,19 @@ internal static class ChunkUtil {
case PayloadType.Player: case PayloadType.Player:
link = payload; link = payload;
break; break;
case PayloadType.PartyFinder:
link = payload;
break;
case PayloadType.Unknown: case PayloadType.Unknown:
var rawPayload = (RawPayload) payload; var rawPayload = (RawPayload) payload;
if (rawPayload.Data.Length > 1 && rawPayload.Data[1] == 0x13) { if (rawPayload.Data.Length > 1 && rawPayload.Data[1] == 0x13) {
foreground.Pop(); if (foreground.Count > 0) {
glow.Pop(); foreground.Pop();
}
if (glow.Count > 0) {
glow.Pop();
}
} else if (rawPayload.Data.Length > 7 && rawPayload.Data[1] == 0x27 && rawPayload.Data[3] == 0x0A) { } else if (rawPayload.Data.Length > 7 && rawPayload.Data[1] == 0x27 && rawPayload.Data[3] == 0x0A) {
// pf payload // pf payload
var reader = new BinaryReader(new MemoryStream(rawPayload.Data[4..])); var reader = new BinaryReader(new MemoryStream(rawPayload.Data[4..]));
@ -80,8 +88,6 @@ internal static class ChunkUtil {
link = new AchievementPayload(id); link = new AchievementPayload(id);
} else if (Equals(rawPayload, RawPayload.LinkTerminator)) { } else if (Equals(rawPayload, RawPayload.LinkTerminator)) {
link = null; link = null;
} else if (Equals(rawPayload, PeriodicRecruitmentLink)) {
link = rawPayload;
} }
break; break;

View File

@ -4,6 +4,7 @@ using Dalamud.Game.ClientState.Keys;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.Style; using Dalamud.Interface.Style;
using Dalamud.Interface.Utility;
using ImGuiNET; using ImGuiNET;
namespace ChatTwo.Util; namespace ChatTwo.Util;

26
ChatTwo/packages.lock.json Executable file → Normal file
View File

@ -1,24 +1,24 @@
{ {
"version": 1, "version": 1,
"dependencies": { "dependencies": {
"net6.0-windows7.0": { "net7.0-windows7.0": {
"DalamudPackager": { "DalamudPackager": {
"type": "Direct", "type": "Direct",
"requested": "[2.1.8, )", "requested": "[2.1.12, )",
"resolved": "2.1.8", "resolved": "2.1.12",
"contentHash": "YqagNXs9InxmqkXzq7kLveImxnodkBEicAhydMXVp7dFjC7xb76U6zGgAax4/BWIWfZeWzr5DJyQSev31kj81A==" "contentHash": "Sc0PVxvgg4NQjcI8n10/VfUQBAS4O+Fw2pZrAqBdRMbthYGeogzu5+xmIGCGmsEZ/ukMOBuAqiNiB5qA3MRalg=="
}, },
"LiteDB": { "LiteDB": {
"type": "Direct", "type": "Direct",
"requested": "[5.0.12, )", "requested": "[5.0.17, )",
"resolved": "5.0.12", "resolved": "5.0.17",
"contentHash": "HaOjSIGS9BRm7dw42qcHd5NGYl5wdjsFB31pImt3QQNLKUNEmRAr7ADos5VsujwBc9c4otJgb+G6NA4MlzKyAw==" "contentHash": "cKPvkdlzIts3ZKu/BzoIc/Y71e4VFKlij4LyioPFATZMot+wB7EAm1FFbZSJez6coJmQUoIg/3yHE1MMU+zOdg=="
}, },
"Pidgin": { "Pidgin": {
"type": "Direct", "type": "Direct",
"requested": "[3.2.0, )", "requested": "[3.2.2, )",
"resolved": "3.2.0", "resolved": "3.2.2",
"contentHash": "pUm2B95hRRvcPO50mCMUST2B3/M6b99CUHaZOIpFJpnD2twgKea83ZqYyllvwxr64EIhch9o/xy02zfbisg1Kw==" "contentHash": "imvuRt8fzxJCJs9kCk7s418NRyEdP6aDtz2qL9XYcn1ywTkpnrSq4IORVTQ879HNoTfJkyGkFadmEoCZEsebGg=="
}, },
"SharpDX.Direct2D1": { "SharpDX.Direct2D1": {
"type": "Direct", "type": "Direct",
@ -33,9 +33,9 @@
}, },
"XivCommon": { "XivCommon": {
"type": "Direct", "type": "Direct",
"requested": "[6.0.1, )", "requested": "[9.0.0, )",
"resolved": "6.0.1", "resolved": "9.0.0",
"contentHash": "X58/iHscbwzF9JziooBKYE4S0XDYuGYI7Eg5Er1LhdQSjGwMLes0whRdKtH591wIhefFiS5G14W6EEL3Qt76wg==" "contentHash": "avaBp3FmSCi/PiQhntCeBDYOHejdyTWmFtz4pRBVQQ8vHkmRx+YTk1la9dkYBMlXxRXKckEdH1iI1Fu61JlE7w=="
}, },
"Microsoft.NETCore.Platforms": { "Microsoft.NETCore.Platforms": {
"type": "Transitive", "type": "Transitive",

6
fix_resources.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
for f in ChatTwo/Resources/Language.resx ChatTwo/Resources/Language.*.resx; do
sed -i 's/ xml:space="preserve"//g' "$f"
xmlstarlet fo -e utf-8 -s 4 "$f" | sponge "$f"
done