Merge branch 'master' into master

This commit is contained in:
goaaats 2020-04-22 21:04:21 +02:00 committed by GitHub
commit 2a9e395805
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 716 additions and 1223 deletions

View file

@ -14,10 +14,10 @@
</PropertyGroup>
<PropertyGroup Label="Feature">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AssemblyVersion>4.8.5.0</AssemblyVersion>
<FileVersion>4.8.5.0</FileVersion>
<AssemblyVersion>4.8.8.0</AssemblyVersion>
<FileVersion>4.8.8.0</FileVersion>
<Description>XIVLauncher addon injection</Description>
<Version>4.8.5.0</Version>
<Version>4.8.8.0</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DocumentationFile></DocumentationFile>

View file

@ -13,6 +13,8 @@ using Newtonsoft.Json;
namespace Dalamud.Injector {
internal static class Program {
static private Process process = null;
private static void Main(string[] args) {
#if !DEBUG
AppDomain.CurrentDomain.UnhandledException += delegate(object sender, UnhandledExceptionEventArgs eventArgs)
@ -25,9 +27,10 @@ namespace Dalamud.Injector {
};
#endif
var pid = int.Parse(args[0]);
Process process = null;
var pid = -1;
if (args.Length == 1) {
pid = int.Parse(args[0]);
}
switch (pid) {
case -1:
@ -45,10 +48,12 @@ namespace Dalamud.Injector {
}
DalamudStartInfo startInfo;
if (args.Length == 1) {
if (args.Length <= 1) {
startInfo = GetDefaultStartInfo();
Console.WriteLine("\nA Dalamud start info was not found in the program arguments. One has been generated for you.");
Console.WriteLine("\nCopy the following contents into the program arguments:");
Console.WriteLine();
Console.WriteLine(Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(startInfo))));
} else {
startInfo = JsonConvert.DeserializeObject<DalamudStartInfo>(Encoding.UTF8.GetString(Convert.FromBase64String(args[1])));
}
@ -80,6 +85,7 @@ namespace Dalamud.Injector {
}
private static DalamudStartInfo GetDefaultStartInfo() {
var ffxivDir = Path.GetDirectoryName(process.MainModule.FileName);
var startInfo = new DalamudStartInfo {
WorkingDirectory = null,
ConfigurationPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
@ -89,7 +95,7 @@ namespace Dalamud.Injector {
DefaultPluginDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
@"\XIVLauncher\devPlugins",
GameVersion = File.ReadAllText(@"C:\Program Files (x86)\SquareEnix\FINAL FANTASY XIV - A Realm Reborn\game\ffxivgame.ver"),
GameVersion = File.ReadAllText(Path.Combine(ffxivDir, "ffxivgame.ver")),
Language = ClientLanguage.English
};

View file

@ -27,14 +27,25 @@ namespace Dalamud
public Dictionary<int, PreferredRole> PreferredRoleReminders { get; set; }
public string LanguageOverride { get; set; }
public string LastVersion { get; set; }
[JsonIgnore]
public string ConfigPath;
public static DalamudConfiguration Load(string path) {
return JsonConvert.DeserializeObject<DalamudConfiguration>(File.ReadAllText(path));
var deserialized = JsonConvert.DeserializeObject<DalamudConfiguration>(File.ReadAllText(path));
deserialized.ConfigPath = path;
return deserialized;
}
public void Save(string path) {
File.WriteAllText(path, JsonConvert.SerializeObject(this, Formatting.Indented));
/// <summary>
/// Save the configuration at the path it was loaded from.
/// </summary>
public void Save() {
File.WriteAllText(this.ConfigPath, JsonConvert.SerializeObject(this, Formatting.Indented));
}
}
}

View file

@ -22,7 +22,10 @@ using Dalamud.Game.Network;
using Dalamud.Interface;
using Dalamud.Plugin;
using ImGuiNET;
using Newtonsoft.Json;
using Serilog;
using Serilog.Core;
using Serilog.Events;
namespace Dalamud {
public sealed class Dalamud : IDisposable {
@ -36,13 +39,13 @@ namespace Dalamud {
public readonly Framework Framework;
public readonly CommandManager CommandManager;
public CommandManager CommandManager { get; private set; }
public readonly ChatHandlers ChatHandlers;
public ChatHandlers ChatHandlers { get; private set; }
public readonly NetworkHandlers NetworkHandlers;
public NetworkHandlers NetworkHandlers { get; private set; }
public readonly DiscordBotManager BotManager;
public DiscordBotManager BotManager { get; private set; }
public PluginManager PluginManager { get; private set; }
public PluginRepository PluginRepository { get; private set; }
@ -50,31 +53,29 @@ namespace Dalamud {
public readonly ClientState ClientState;
public readonly DalamudStartInfo StartInfo;
private readonly LoggingLevelSwitch loggingLevelSwitch;
public readonly DalamudConfiguration Configuration;
private readonly WinSockHandlers WinSock2;
public readonly InterfaceManager InterfaceManager;
public InterfaceManager InterfaceManager { get; private set; }
public readonly DataManager Data;
private AntiDebug antiDebug;
public DataManager Data { get; private set; }
private Localization localizationMgr;
public bool IsReady { get; private set; }
private readonly string assemblyVersion = Assembly.GetAssembly(typeof(ChatHandlers)).GetName().Version.ToString();
public Dalamud(DalamudStartInfo info) {
public Dalamud(DalamudStartInfo info, LoggingLevelSwitch loggingLevelSwitch) {
this.StartInfo = info;
this.localizationMgr = new Localization(this.StartInfo.WorkingDirectory);
this.localizationMgr.SetupWithUiCulture();
this.loggingLevelSwitch = loggingLevelSwitch;
this.Configuration = DalamudConfiguration.Load(info.ConfigurationPath);
this.baseDirectory = info.WorkingDirectory;
this.unloadSignal = new ManualResetEvent(false);
@ -86,50 +87,61 @@ namespace Dalamud {
// Initialize game subsystem
this.Framework = new Framework(this.SigScanner, this);
// Initialize managers. Basically handlers for the logic
this.CommandManager = new CommandManager(this, info.Language);
SetupCommands();
this.ChatHandlers = new ChatHandlers(this);
this.NetworkHandlers = new NetworkHandlers(this, this.Configuration.OptOutMbCollection);
this.Data = new DataManager(this.StartInfo.Language);
this.Data.Initialize();
this.ClientState = new ClientState(this, info, this.SigScanner);
this.BotManager = new DiscordBotManager(this, this.Configuration.DiscordFeatureConfig);
this.WinSock2 = new WinSockHandlers();
try {
this.InterfaceManager = new InterfaceManager(this, this.SigScanner);
this.InterfaceManager.OnDraw += BuildDalamudUi;
} catch (Exception e) {
Log.Information(e, "Could not init interface.");
}
AssetManager.EnsureAssets(this.baseDirectory).ContinueWith(async task => {
this.localizationMgr = new Localization(this.StartInfo.WorkingDirectory);
if (!string.IsNullOrEmpty(this.Configuration.LanguageOverride)) {
this.localizationMgr.SetupWithLangCode(this.Configuration.LanguageOverride);
} else {
this.localizationMgr.SetupWithUiCulture();
}
try {
this.InterfaceManager = new InterfaceManager(this, this.SigScanner);
this.InterfaceManager.OnDraw += BuildDalamudUi;
this.InterfaceManager.Enable();
} catch (Exception e) {
Log.Information(e, "Could not init interface.");
}
this.Data = new DataManager(this.StartInfo.Language);
await this.Data.Initialize(this.baseDirectory);
this.NetworkHandlers = new NetworkHandlers(this, this.Configuration.OptOutMbCollection);
// Initialize managers. Basically handlers for the logic
this.CommandManager = new CommandManager(this, info.Language);
SetupCommands();
this.ChatHandlers = new ChatHandlers(this);
// Discord Bot Manager
this.BotManager = new DiscordBotManager(this, this.Configuration.DiscordFeatureConfig);
this.BotManager.Start();
try
{
this.PluginManager = new PluginManager(this, this.StartInfo.PluginDirectory, this.StartInfo.DefaultPluginDirectory);
this.PluginManager.LoadPlugins();
this.PluginRepository = new PluginRepository(PluginManager, this.StartInfo.PluginDirectory, this.StartInfo.GameVersion);
}
catch (Exception ex)
{
Log.Error(ex, "Plugin load failed.");
}
IsReady = true;
});
}
public void Start() {
try {
this.InterfaceManager?.Enable();
} catch (Exception e) {
Log.Information("Could not enable interface.");
}
this.Framework.Enable();
this.ClientState.Enable();
this.BotManager.Start();
try {
this.PluginManager = new PluginManager(this, this.StartInfo.PluginDirectory, this.StartInfo.DefaultPluginDirectory);
this.PluginManager.LoadPlugins();
PluginRepository = new PluginRepository(PluginManager, this.StartInfo.PluginDirectory, this.StartInfo.GameVersion);
} catch (Exception ex) {
Log.Error(ex, "Plugin load failed.");
}
}
public void Unload() {
@ -145,7 +157,7 @@ namespace Dalamud {
// due to rendering happening on another thread, where a plugin might receive
// a render call after it has been disposed, which can crash if it attempts to
// use any resources that it freed in its own Dispose method
this.InterfaceManager.Dispose();
this.InterfaceManager?.Dispose();
try
{
@ -166,8 +178,6 @@ namespace Dalamud {
this.WinSock2.Dispose();
this.SigScanner.Dispose();
this.antiDebug?.Dispose();
}
#region Interface
@ -180,8 +190,6 @@ namespace Dalamud {
private bool isImguiDrawDevMenu = false;
#endif
private bool isAntiDebugEnabled = false;
private bool isImguiDrawLogWindow = false;
private bool isImguiDrawDataWindow = false;
private bool isImguiDrawPluginWindow = false;
@ -207,6 +215,18 @@ namespace Dalamud {
this.logWindow = new DalamudLogWindow();
this.isImguiDrawLogWindow = true;
}
if (ImGui.BeginMenu("Set log level..."))
{
foreach (var logLevel in Enum.GetValues(typeof(LogEventLevel)).Cast<LogEventLevel>()) {
if (ImGui.MenuItem(logLevel + "##logLevelSwitch", "", this.loggingLevelSwitch.MinimumLevel == logLevel))
{
this.loggingLevelSwitch.MinimumLevel = logLevel;
}
}
ImGui.EndMenu();
}
ImGui.Separator();
if (ImGui.MenuItem("Open Data window"))
{
this.dataWindow = new DalamudDataWindow(this);
@ -220,15 +240,8 @@ namespace Dalamud {
this.isImguiDrawCreditsWindow = true;
}
ImGui.MenuItem("Draw ImGui demo", "", ref this.isImguiDrawDemoWindow);
ImGui.Separator();
if (ImGui.MenuItem("Enable AntiDebug", "", ref this.isAntiDebugEnabled)) {
if (this.isAntiDebugEnabled) {
this.antiDebug = new AntiDebug();
this.antiDebug.Enable();
} else {
this.antiDebug?.Dispose();
}
}
if (ImGui.MenuItem("Dump ImGui info"))
OnDebugImInfoCommand(null, null);
ImGui.Separator();
if (ImGui.MenuItem("Unload Dalamud"))
{
@ -395,7 +408,7 @@ namespace Dalamud {
CommandManager.AddHandler("/xlitem", new CommandInfo(OnItemLinkCommand)
{
HelpMessage = Loc.Localize("DalamudItemLinkHelp", "Link an item by name. Usage: /xlitem <Item name>. For matching an item exactly, use /xlitem +<Item name>")
HelpMessage = Loc.Localize("DalamudItemLinkHelp", "Open a window you can use to link any specific item to chat.")
});
#if DEBUG
@ -424,6 +437,17 @@ namespace Dalamud {
this.CommandManager.AddHandler("/xlcredits", new CommandInfo(OnOpenCreditsCommand) {
HelpMessage = Loc.Localize("DalamudCreditsHelp", "Opens the credits for dalamud.")
});
this.CommandManager.AddHandler("/xllanguage", new CommandInfo(OnSetLanguageCommand)
{
HelpMessage = Loc.Localize("DalamudLanguageHelp", "Set the language for the in-game addon and plugins that support it.")
});
this.CommandManager.AddHandler("/imdebug", new CommandInfo(OnDebugImInfoCommand)
{
HelpMessage = "ImGui DEBUG",
ShowInHelp = false
});
}
private void OnUnloadCommand(string command, string arguments) {
@ -476,7 +500,7 @@ namespace Dalamud {
this.Configuration.BadWords.Add(arguments);
this.Configuration.Save(this.StartInfo.ConfigurationPath);
this.Configuration.Save();
Framework.Gui.Chat.Print(string.Format(Loc.Localize("DalamudMuted", "Muted \"{0}\"."), arguments));
}
@ -490,7 +514,7 @@ namespace Dalamud {
return;
}
this.Configuration.Save(this.StartInfo.ConfigurationPath);
this.Configuration.Save();
foreach (var word in this.Configuration.BadWords) Framework.Gui.Chat.Print($"\"{word}\"");
}
@ -501,7 +525,7 @@ namespace Dalamud {
this.Configuration.BadWords.RemoveAll(x => x == arguments);
this.Configuration.Save(this.StartInfo.ConfigurationPath);
this.Configuration.Save();
Framework.Gui.Chat.Print(string.Format(Loc.Localize("DalamudUnmuted", "Unmuted \"{0}\"."), arguments));
}
@ -534,7 +558,7 @@ namespace Dalamud {
private bool isImguiDrawItemSearchWindow;
private void OnItemLinkCommand(string command, string arguments) {
this.itemSearchCommandWindow = new ItemSearchWindow(this.Data, new UiBuilder(this.InterfaceManager, "ItemSearcher"));
this.itemSearchCommandWindow = new ItemSearchWindow(this.Data, new UiBuilder(this.InterfaceManager, "ItemSearcher"), false);
this.itemSearchCommandWindow.OnItemChosen += (sender, item) => {
var hexData = new byte[] {
0x02, 0x13, 0x06, 0xFE, 0xFF, 0xF3, 0xF3, 0xF3, 0x03, 0x02, 0x27, 0x07, 0x03, 0xF2, 0x3A, 0x2F,
@ -597,7 +621,7 @@ namespace Dalamud {
Framework.Gui.Chat.Print($"Set bonus notifications for {argParts[0]}({rouletteIndex}) to {role}");
Framework.Gui.Chat.Print(string.Format(Loc.Localize("DalamudBonusSet", "Set bonus notifications for {0}({1}) to {2}"), argParts[0], rouletteIndex, role));
this.Configuration.Save(this.StartInfo.ConfigurationPath);
this.Configuration.Save();
return;
@ -610,6 +634,28 @@ namespace Dalamud {
this.isImguiDrawDevMenu = true;
}
private void OnDebugImInfoCommand(string command, string arguments) {
var io = this.InterfaceManager.LastImGuiIoPtr;
var info = $"WantCaptureKeyboard: {io.WantCaptureKeyboard}\n";
info += $"WantCaptureMouse: {io.WantCaptureMouse}\n";
info += $"WantSetMousePos: {io.WantSetMousePos}\n";
info += $"WantTextInput: {io.WantTextInput}\n";
info += $"WantSaveIniSettings: {io.WantSaveIniSettings}\n";
info += $"BackendFlags: {(int) io.BackendFlags}\n";
info += $"DeltaTime: {io.DeltaTime}\n";
info += $"DisplaySize: {io.DisplaySize.X} {io.DisplaySize.Y}\n";
info += $"Framerate: {io.Framerate}\n";
info += $"MetricsActiveWindows: {io.MetricsActiveWindows}\n";
info += $"MetricsRenderWindows: {io.MetricsRenderWindows}\n";
info += $"MousePos: {io.MousePos.X} {io.MousePos.Y}\n";
info += $"MouseClicked: {io.MouseClicked}\n";
info += $"MouseDown: {io.MouseDown}\n";
info += $"NavActive: {io.NavActive}\n";
info += $"NavVisible: {io.NavVisible}\n";
Log.Information(info);
}
private void OnOpenInstallerCommand(string command, string arguments) {
this.pluginWindow = new PluginInstallerWindow(this.PluginManager, PluginRepository, this.StartInfo.GameVersion);
this.isImguiDrawPluginWindow = true;
@ -624,6 +670,19 @@ namespace Dalamud {
this.isImguiDrawCreditsWindow = true;
}
private void OnSetLanguageCommand(string command, string arguments)
{
if (Localization.ApplicableLangCodes.Contains(arguments.ToLower())) {
this.localizationMgr.SetupWithLangCode(arguments.ToLower());
this.Configuration.LanguageOverride = arguments.ToLower();
} else {
this.localizationMgr.SetupWithUiCulture();
this.Configuration.LanguageOverride = null;
}
this.Configuration.Save();
}
private int RouletteSlugToKey(string slug) => slug.ToLower() switch {
"leveling" => 1,
"506070" => 2,

View file

@ -14,9 +14,9 @@
</PropertyGroup>
<PropertyGroup Label="Feature">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AssemblyVersion>4.8.5.0</AssemblyVersion>
<Version>4.8.5.0</Version>
<FileVersion>4.8.5.0</FileVersion>
<AssemblyVersion>4.8.8.0</AssemblyVersion>
<Version>4.8.8.0</Version>
<FileVersion>4.8.8.0</FileVersion>
</PropertyGroup>
<ItemGroup Label="Resources">
<None Include="$(SolutionDir)/Resources/**/*" CopyToOutputDirectory="PreserveNewest" Visible="false" />
@ -79,26 +79,5 @@
<None Update="NotoSansCJKjp-Medium.otf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="UIRes\loc\dalamud\dalamud_de.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="UIRes\loc\dalamud\dalamud_es.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="UIRes\loc\dalamud\dalamud_fr.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="UIRes\loc\dalamud\dalamud_it.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="UIRes\loc\dalamud\dalamud_ja.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="UIRes\logo.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="UIRes\NotoSansCJKjp-Medium.otf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View file

@ -22,8 +22,6 @@ namespace Dalamud.Data
/// This class provides data for Dalamud-internal features, but can also be used by plugins if needed.
/// </summary>
public class DataManager {
private const string DataBaseUrl = "https://goaaats.github.io/ffxiv/tools/launcher/addons/Hooks/Data/";
public ReadOnlyDictionary<string, ushort> ServerOpCodes { get; private set; }
/// <summary>
@ -53,20 +51,14 @@ namespace Dalamud.Data
this.language = language;
}
public async Task Initialize()
public async Task Initialize(string baseDir)
{
try
{
Log.Verbose("Starting data download...");
using var client = new HttpClient()
{
BaseAddress = new Uri(DataBaseUrl)
};
var opCodeDict =
JsonConvert.DeserializeObject<Dictionary<string, ushort>>(
await client.GetStringAsync(DataBaseUrl + "serveropcode.json"));
JsonConvert.DeserializeObject<Dictionary<string, ushort>>(File.ReadAllText(Path.Combine(baseDir, "UIRes", "serveropcode.json")));
this.ServerOpCodes = new ReadOnlyDictionary<string, ushort>(opCodeDict);
Log.Verbose("Loaded {0} ServerOpCodes.", opCodeDict.Count);

View file

@ -6,6 +6,7 @@ using Dalamud.Interface;
using EasyHook;
using Serilog;
using Serilog.Core;
using Serilog.Events;
namespace Dalamud {
public sealed class EntryPoint : IEntryPoint {
@ -15,7 +16,8 @@ namespace Dalamud {
public void Run(RemoteHooking.IContext ctx, DalamudStartInfo info) {
// Setup logger
Log.Logger = NewLogger(info.WorkingDirectory);
var (logger, levelSwitch) = NewLogger(info.WorkingDirectory);
Log.Logger = logger;
try {
Log.Information("Initializing a session..");
@ -28,7 +30,7 @@ namespace Dalamud {
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
using var dalamud = new Dalamud(info);
using var dalamud = new Dalamud(info, levelSwitch);
Log.Information("Starting a session..");
// Run session
@ -44,18 +46,24 @@ namespace Dalamud {
}
}
private Logger NewLogger(string baseDirectory) {
private (Logger logger, LoggingLevelSwitch levelSwitch) NewLogger(string baseDirectory) {
var logPath = Path.Combine(baseDirectory, "dalamud.txt");
return new LoggerConfiguration()
var levelSwitch = new LoggingLevelSwitch();
#if DEBUG
levelSwitch.MinimumLevel = LogEventLevel.Verbose;
#else
levelSwitch.MinimumLevel = LogEventLevel.Information;
#endif
var newLogger = new LoggerConfiguration()
.WriteTo.Async(a => a.File(logPath))
.WriteTo.EventSink()
#if DEBUG
.MinimumLevel.Verbose()
#else
.MinimumLevel.Information()
#endif
.MinimumLevel.ControlledBy(levelSwitch)
.CreateLogger();
return (newLogger, levelSwitch);
}
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs arg) {

View file

@ -0,0 +1,181 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Dalamud.Game.Chat
{
/// <summary>
/// Special unicode characters with game-related symbols that work both in-game and in any dalamud window.
/// </summary>
public enum SeIconChar {
BotanistSprout = 0xE034,
ItemLevel = 0xE033,
AutoTranslateOpen = 0xE040,
AutoTranslateClose = 0xE041,
HighQuality = 0xE03C,
Clock = 0xE031,
Gil = 0xE049,
Hyadelyn = 0xE048,
MouseNoClick = 0xE050,
MouseLeftClick = 0xE051,
MouseRightClick = 0xE052,
MouseBothClick = 0xE053,
MouseWheel = 0xE054,
Mouse1 = 0xE055,
Mouse2 = 0xE056,
Mouse3 = 0xE057,
Mouse4 = 0xE058,
Mouse5 = 0xE059,
LevelEn = 0xE06A,
LevelDe = 0xE06B,
LevelFr = 0xE06C,
Experience = 0xE0BC,
ExperienceFilled = 0xE0BD,
TimeAm = 0xE06D,
TimePm = 0xE06E,
ArrowRight = 0xE06F,
ArrowDown = 0xE035,
Number0 = 0xE060,
Number1 = 0xE061,
Number2 = 0xE062,
Number3 = 0xE063,
Number4 = 0xE064,
Number5 = 0xE065,
Number6 = 0xE066,
Number7 = 0xE067,
Number8 = 0xE068,
Number9 = 0xE069,
BoxedNumber0 = 0xE08F,
BoxedNumber1 = 0xE090,
BoxedNumber2 = 0xE091,
BoxedNumber3 = 0xE092,
BoxedNumber4 = 0xE093,
BoxedNumber5 = 0xE094,
BoxedNumber6 = 0xE095,
BoxedNumber7 = 0xE096,
BoxedNumber8 = 0xE097,
BoxedNumber9 = 0xE098,
BoxedNumber10 = 0xE099,
BoxedNumber11 = 0xE09A,
BoxedNumber12 = 0xE09B,
BoxedNumber13 = 0xE09C,
BoxedNumber14 = 0xE09D,
BoxedNumber15 = 0xE09E,
BoxedNumber16 = 0xE09F,
BoxedNumber17 = 0xE0A0,
BoxedNumber18 = 0xE0A1,
BoxedNumber19 = 0xE0A2,
BoxedNumber20 = 0xE0A3,
BoxedNumber21 = 0xE0A4,
BoxedNumber22 = 0xE0A5,
BoxedNumber23 = 0xE0A6,
BoxedNumber24 = 0xE0A7,
BoxedNumber25 = 0xE0A8,
BoxedNumber26 = 0xE0A9,
BoxedNumber27 = 0xE0AA,
BoxedNumber28 = 0xE0AB,
BoxedNumber29 = 0xE0AC,
BoxedNumber30 = 0xE0AD,
BoxedNumber31 = 0xE0AE,
BoxedPlus = 0xE0AF,
BoxedQuestionMark = 0xE070,
BoxedStar = 0xE0C0,
BoxedRoman1 = 0xE0C1,
BoxedRoman2 = 0xE0C2,
BoxedRoman3 = 0xE0C3,
BoxedRoman4 = 0xE0C4,
BoxedRoman5 = 0xE0C5,
BoxedRoman6 = 0xE0C6,
BoxedLetterA = 0xE071,
BoxedLetterB = 0xE072,
BoxedLetterC = 0xE073,
BoxedLetterD = 0xE074,
BoxedLetterE = 0xE075,
BoxedLetterF = 0xE076,
BoxedLetterG = 0xE077,
BoxedLetterH = 0xE078,
BoxedLetterI = 0xE079,
BoxedLetterJ = 0xE07A,
BoxedLetterK = 0xE07B,
BoxedLetterL = 0xE07C,
BoxedLetterM = 0xE07D,
BoxedLetterN = 0xE07E,
BoxedLetterO = 0xE07F,
BoxedLetterP = 0xE080,
BoxedLetterQ = 0xE081,
BoxedLetterR = 0xE082,
BoxedLetterS = 0xE083,
BoxedLetterT = 0xE084,
BoxedLetterU = 0xE085,
BoxedLetterV = 0xE086,
BoxedLetterW = 0xE087,
BoxedLetterX = 0xE088,
BoxedLetterY = 0xE089,
BoxedLetterZ = 0xE08A,
Circle = 0xE04A,
Square = 0xE04B,
Cross = 0xE04C,
Triangle = 0xE04D,
Hexagon = 0xE042,
Prohibited = 0xE043,
Dice = 0xE03E,
Debuff = 0xE05B,
Buff = 0xE05C,
CrossWorld = 0xE05D,
EurekaLevel = 0xE03A,
LinkMarker = 0xE0BB,
Glamoured = 0xE03B,
GlamouredDyed = 0xE04E,
QuestSync = 0xE0BE,
QuestRepeatable = 0xE0BF,
ImeHiragana = 0xE020,
ImeKatakana = 0xE021,
ImeAlphanumeric = 0xE022,
ImeKatakanaHalfWidth = 0xE023,
ImeAlphanumericHalfWidth = 0xE024,
Instance1 = 0xE0B1,
Instance2 = 0xE0B2,
Instance3 = 0xE0B3,
Instance4 = 0xE0B4,
Instance5 = 0xE0B5,
Instance6 = 0xE0B6,
Instance7 = 0xE0B7,
Instance8 = 0xE0B8,
Instance9 = 0xE0B9,
InstanceMerged = 0xE0BA,
LocalTimeEn = 0xE0D0,
ServerTimeEn = 0xE0D1,
EorzeaTimeEn = 0xE0D2,
LocalTimeDe = 0xE0D3,
ServerTimeDe = 0xE0D4,
EorzeaTimeDe = 0xE0D5,
LocalTimeFr = 0xE0D6,
ServerTimeFr = 0xE0D7,
EorzeaTimeFr = 0xE0D8,
LocalTimeJa = 0xE0D9,
ServerTimeJa = 0xE0DA,
EorzeaTimeJa = 0xE0DB,
}
}

View file

@ -5,6 +5,13 @@ using System.Linq;
using Dalamud.Game.Chat.SeStringHandling.Payloads;
using Serilog;
// TODOs:
// - refactor integer handling now that we have multiple packed types
// - common construction/property design for subclasses
// - lumina DI
// - design for handling raw values vs resolved values, both for input and output
// - wrapper class(es) for handling of composite links in chat (item, map etc) and formatting operations
namespace Dalamud.Game.Chat.SeStringHandling
{
/// <summary>
@ -148,6 +155,7 @@ namespace Dalamud.Game.Chat.SeStringHandling
Int16 = 0xF2,
Int16Packed = 0xF4, // seen in map links, seemingly 2 8-bit values packed into 2 bytes with only one marker
Int24Special = 0xF6, // unsure how different form Int24 - used for hq items that add 1 million, also used for normal 24-bit values in map links
Int24Packed = 0xFC, // used in map links- sometimes short+byte, sometimes... not??
Int24 = 0xFA,
Int32 = 0xFE
}
@ -189,6 +197,8 @@ namespace Dalamud.Game.Chat.SeStringHandling
case IntegerType.Int24Special:
// Fallthrough - same logic
case IntegerType.Int24Packed:
// fallthrough again
case IntegerType.Int24:
{
var v = 0;
@ -267,6 +277,7 @@ namespace Dalamud.Game.Chat.SeStringHandling
var type = bytes.Length switch
{
4 => IntegerType.Int32,
3 => IntegerType.Int24Packed,
2 => IntegerType.Int16Packed,
_ => throw new NotSupportedException()
};
@ -276,17 +287,32 @@ namespace Dalamud.Game.Chat.SeStringHandling
protected (uint, uint) GetPackedIntegers(BinaryReader input)
{
// HACK - this was already a hack, but the addition of Int24Packed made it even worse
// All of this should be redone/removed at some point
var marker = (IntegerType)input.ReadByte();
input.BaseStream.Position--;
var value = GetInteger(input);
if (value > 0xFFFF)
if (marker == IntegerType.Int24Packed)
{
return ((uint)((value & 0xFFFF0000) >> 16), (uint)(value & 0xFFFF));
return ((uint)((value & 0xFFFF00) >> 8), (uint)(value & 0xFF));
}
else if (value > 0xFF)
// this used to be the catchall before Int24Packed; leave it for now to ensure we handle all encodings
else // if (marker == IntegerType.Int16Packed || marker == IntegerType.Int32)
{
return ((uint)((value & 0xFF00) >> 8), (uint)(value & 0xFF));
if (value > 0xFFFF)
{
return ((uint)((value & 0xFFFF0000) >> 16), (uint)(value & 0xFFFF));
}
else if (value > 0xFF)
{
return ((uint)((value & 0xFF00) >> 8), (uint)(value & 0xFF));
}
}
// unsure if there are other cases, like "odd" pairings of 2+1 bytes etc
// unsure if there are other cases
throw new NotSupportedException();
}

View file

@ -65,15 +65,34 @@ namespace Dalamud.Game.Chat.SeStringHandling.Payloads
//}
}
public override string ToString()
{
return $"{Type} - TerritoryTypeId: {TerritoryTypeId}, MapId: {MapId}, RawX: {RawX}, RawY: {RawY}";
}
protected override void ProcessChunkImpl(BinaryReader reader, long endOfStream)
{
(TerritoryTypeId, MapId) = GetPackedIntegers(reader);
RawX = (uint)GetInteger(reader);
RawY = (uint)GetInteger(reader);
// the Z coordinate is never in this chunk, just the text (if applicable)
// for debugging for now
var oldPos = reader.BaseStream.Position;
var bytes = reader.ReadBytes((int)(endOfStream - reader.BaseStream.Position));
reader.BaseStream.Position = oldPos;
// seems to always be FF 01
reader.ReadBytes(2);
try
{
(TerritoryTypeId, MapId) = GetPackedIntegers(reader);
RawX = (uint)GetInteger(reader);
RawY = (uint)GetInteger(reader);
// the Z coordinate is never in this chunk, just the text (if applicable)
// seems to always be FF 01
reader.ReadBytes(2);
}
catch (NotSupportedException)
{
Serilog.Log.Information($"Unsupported map bytes {BitConverter.ToString(bytes).Replace("-", " ")}");
// we still want to break here for now, or we'd just throw again later
throw;
}
}
#region ugliness

View file

@ -119,7 +119,7 @@ namespace Dalamud.Game {
});
this.dalamud.Configuration.LastVersion = assemblyVersion;
this.dalamud.Configuration.Save(this.dalamud.StartInfo.ConfigurationPath);
this.dalamud.Configuration.Save();
}
try {

View file

@ -1,5 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Dalamud.Game.ClientState.Actors.Types;
@ -11,9 +12,10 @@ namespace Dalamud.Game.ClientState.Actors {
/// <summary>
/// This collection represents the currently spawned FFXIV actors.
/// </summary>
public class ActorTable : ICollection, IDisposable {
public class ActorTable : IReadOnlyCollection<Actor>, ICollection, IDisposable {
#region temporary imports for crash workaround
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadProcessMemory(
IntPtr hProcess,
@ -21,6 +23,7 @@ namespace Dalamud.Game.ClientState.Actors {
IntPtr lpBuffer,
int dwSize,
out IntPtr lpNumberOfBytesRead);
#endregion
private ClientStateAddressResolver Address { get; }
@ -42,7 +45,8 @@ namespace Dalamud.Game.ClientState.Actors {
Address = addressResolver;
this.dalamud = dalamud;
this.someActorTableAccessHook = new Hook<SomeActorTableAccessDelegate>(Address.SomeActorTableAccess, new SomeActorTableAccessDelegate(SomeActorTableAccessDetour), this);
this.someActorTableAccessHook = new Hook<SomeActorTableAccessDelegate>(
Address.SomeActorTableAccess, new SomeActorTableAccessDelegate(SomeActorTableAccessDetour), this);
Log.Verbose("Actor table address {ActorTable}", Address.ViewportActorTable);
}
@ -74,15 +78,14 @@ namespace Dalamud.Game.ClientState.Actors {
if (!this.isReady)
return null;
if (this.someActorTableAccessHook != null)
{
if (this.someActorTableAccessHook != null) {
this.someActorTableAccessHook.Dispose();
this.someActorTableAccessHook = null;
}
if (index >= Length)
return null;
var tblIndex = this.realActorTablePtr + 8 + index * 8;
var offset = Marshal.ReadIntPtr(tblIndex);
@ -94,9 +97,8 @@ namespace Dalamud.Game.ClientState.Actors {
// FIXME: hack workaround for trying to access the player on logout, after the main object has been deleted
var sz = Marshal.SizeOf(typeof(Structs.Actor));
var actorMem = Marshal.AllocHGlobal(sz); // we arguably could just reuse this
if (!ReadProcessMemory(Process.GetCurrentProcess().Handle, offset, actorMem, sz, out _))
{
var actorMem = Marshal.AllocHGlobal(sz); // we arguably could just reuse this
if (!ReadProcessMemory(Process.GetCurrentProcess().Handle, offset, actorMem, sz, out _)) {
Log.Debug("ActorTable - ReadProcessMemory failed: likely player deletion during logout");
return null;
}
@ -106,17 +108,16 @@ namespace Dalamud.Game.ClientState.Actors {
//Log.Debug("ActorTable[{0}]: {1} - {2} - {3}", index, tblIndex.ToString("X"), offset.ToString("X"),
// actorStruct.ObjectKind.ToString());
switch (actorStruct.ObjectKind)
{
case ObjectKind.Player: return new PlayerCharacter(actorStruct, this.dalamud);
case ObjectKind.BattleNpc: return new BattleNpc(actorStruct, this.dalamud);
default: return new Actor(actorStruct, this.dalamud);
switch (actorStruct.ObjectKind) {
case ObjectKind.Player: return new PlayerCharacter(offset, actorStruct, this.dalamud);
case ObjectKind.BattleNpc: return new BattleNpc(offset, actorStruct, this.dalamud);
default: return new Actor(offset, actorStruct, this.dalamud);
}
}
}
private class ActorTableEnumerator : IEnumerator {
private class ActorTableEnumerator : IEnumerator<Actor> {
private readonly ActorTable table;
private int currentIndex;
@ -134,18 +135,29 @@ namespace Dalamud.Game.ClientState.Actors {
this.currentIndex = 0;
}
public object Current => this.table[this.currentIndex];
public Actor Current => this.table[this.currentIndex];
object IEnumerator.Current => Current;
// Required by IEnumerator<T> even though we have nothing we want to dispose here.
public void Dispose() {}
}
public IEnumerator GetEnumerator() {
public IEnumerator<Actor> GetEnumerator() {
return new ActorTableEnumerator(this);
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
/// <summary>
/// The amount of currently spawned actors.
/// </summary>
public int Length => !this.isReady ? 0 : Marshal.ReadInt32(this.realActorTablePtr);
int IReadOnlyCollection<Actor>.Count => Length;
int ICollection.Count => Length;
bool ICollection.IsSynchronized => false;

View file

@ -1,3 +1,5 @@
using System;
namespace Dalamud.Game.ClientState.Actors.Types {
/// <summary>
/// This class represents a basic FFXIV actor.
@ -10,14 +12,21 @@ namespace Dalamud.Game.ClientState.Actors.Types {
protected Dalamud dalamud;
/// <summary>
/// The address of this actor in memory.
/// </summary>
public readonly IntPtr Address;
/// <summary>
/// Initialize a representation of a basic FFXIV actor.
/// </summary>
/// <param name="actorStruct">The memory representation of the base actor.</param>
/// <param name="dalamud">A dalamud reference needed to access game data in Resolvers.</param>
public Actor(Structs.Actor actorStruct, Dalamud dalamud) {
/// <param name="address">The address of this actor in memory.</param>
public Actor(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud) {
this.actorStruct = actorStruct;
this.dalamud = dalamud;
this.Address = address;
}
/// <summary>

View file

@ -1,3 +1,4 @@
using System;
using Dalamud.Game.ClientState.Actors.Resolvers;
namespace Dalamud.Game.ClientState.Actors.Types {
@ -10,7 +11,8 @@ namespace Dalamud.Game.ClientState.Actors.Types {
/// </summary>
/// <param name="actorStruct">The memory representation of the base actor.</param>
/// <param name="dalamud">A dalamud reference needed to access game data in Resolvers.</param>
protected Chara(Structs.Actor actorStruct, Dalamud dalamud) : base(actorStruct, dalamud) { }
/// <param name="address">The address of this actor in memory.</param>
protected Chara(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud) : base(address, actorStruct, dalamud) { }
/// <summary>
/// The level of this Chara.

View file

@ -1,3 +1,5 @@
using System;
namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer {
/// <summary>
/// This class represents a battle NPC.
@ -8,7 +10,8 @@ namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer {
/// </summary>
/// <param name="actorStruct">The memory representation of the base actor.</param>
/// <param name="dalamud">A dalamud reference needed to access game data in Resolvers.</param>
public BattleNpc(Structs.Actor actorStruct, Dalamud dalamud) : base(actorStruct, dalamud) { }
/// <param name="address">The address of this actor in memory.</param>
public BattleNpc(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud) : base(address, actorStruct, dalamud) { }
/// <summary>
/// The BattleNpc <see cref="BattleNpcSubKind" /> of this BattleNpc.

View file

@ -1,3 +1,5 @@
using System;
namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer {
/// <summary>
/// This class represents a NPC.
@ -8,11 +10,17 @@ namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer {
/// </summary>
/// <param name="actorStruct">The memory representation of the base actor.</param>
/// <param name="dalamud">A dalamud reference needed to access game data in Resolvers.</param>
protected Npc(Structs.Actor actorStruct, Dalamud dalamud) : base(actorStruct, dalamud) { }
/// <param name="address">The address of this actor in memory.</param>
protected Npc(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud) : base(address, actorStruct, dalamud) { }
/// <summary>
/// The data ID of the NPC linking to their respective game data.
/// </summary>
public int DataId => this.actorStruct.DataId;
/// <summary>
/// The name ID of the NPC linking to their respective game data.
/// </summary>
public int NameId => this.actorStruct.NameId;
}
}

View file

@ -1,3 +1,4 @@
using System;
using Dalamud.Game.ClientState.Actors.Resolvers;
using SharpDX.Text;
@ -11,7 +12,8 @@ namespace Dalamud.Game.ClientState.Actors.Types {
/// </summary>
/// <param name="actorStruct">The memory representation of the base actor.</param>
/// <param name="dalamud">A dalamud reference needed to access game data in Resolvers.</param>
public PlayerCharacter(Structs.Actor actorStruct, Dalamud dalamud) : base(actorStruct, dalamud) { }
/// <param name="address">The address of this actor in memory.</param>
public PlayerCharacter(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud) : base(address, actorStruct, dalamud) { }
/// <summary>
/// The current <see cref="World">world</see> of the character.

View file

@ -24,10 +24,10 @@ namespace Dalamud.Game.ClientState.Structs
[FieldOffset(145)] public byte PlayerTargetStatus; // This is some kind of enum
[FieldOffset(146)] public byte YalmDistanceFromPlayer2; // and the other is z distance
[FieldOffset(160)] public Position3 Position;
[FieldOffset(0x17F8)] public int TargetActorId;
// This field can't be correctly aligned, so we have to cut it manually.
[FieldOffset(0x17d0)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] public byte[] CompanyTag;
[FieldOffset(0x17F8)] public int TargetActorId;
[FieldOffset(0x1868)] public int NameId;
[FieldOffset(0x1884)] public byte CurrentWorld;
[FieldOffset(0x1886)] public byte HomeWorld;
[FieldOffset(6328)] public int CurrentHp;

View file

@ -11,6 +11,7 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
public struct BRDGauge {
[FieldOffset(0)] public short SongTimer;
[FieldOffset(2)] public byte NumSongStacks;
[FieldOffset(3)] public byte SoulVoiceValue;
[FieldOffset(4)] public CurrentSong ActiveSong;
}
}

View file

@ -1,39 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Dalamud.Hooking;
using EasyHook;
using Serilog;
namespace Dalamud.Game.Internal
{
class AntiDebug : IDisposable
{
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate bool IsDebuggerPresentDelegate();
private Hook<IsDebuggerPresentDelegate> debuggerPresentHook;
public AntiDebug() {
this.debuggerPresentHook = new Hook<IsDebuggerPresentDelegate>(LocalHook.GetProcAddress("Kernel32", "IsDebuggerPresent"),
new IsDebuggerPresentDelegate(IsDebuggerPresentDetour));
Log.Verbose("IsDebuggerPresent address {IsDebuggerPresent}", this.debuggerPresentHook.Address);
}
public void Enable() {
this.debuggerPresentHook.Enable();
}
public void Dispose() {
this.debuggerPresentHook.Disable();
}
private bool IsDebuggerPresentDetour() {
return false;
}
}
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Runtime.InteropServices;
namespace Dalamud.Game.Internal {
@ -35,7 +35,7 @@ namespace Dalamud.Game.Internal {
// Do nothing
}
protected T GetVirtualFunction<T>(IntPtr address, int vtableOffset, int count) where T : class {
public T GetVirtualFunction<T>(IntPtr address, int vtableOffset, int count) where T : class {
// Get vtable
var vtable = Marshal.ReadIntPtr(address, vtableOffset);

View file

@ -1,6 +1,6 @@
using System;
using System.Runtime.InteropServices;
using Dalamud.Game.Chat;
using Dalamud.Game.Chat.SeStringHandling.Payloads;
using Dalamud.Hooking;
using Serilog;
@ -22,6 +22,18 @@ namespace Dalamud.Game.Internal.Gui {
private delegate IntPtr HandleItemOutDelegate(IntPtr hoverState, IntPtr a2, IntPtr a3, ulong a4);
private readonly Hook<HandleItemOutDelegate> handleItemOutHook;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate IntPtr GetUIObjectDelegate();
private readonly GetUIObjectDelegate getUIObject;
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate IntPtr GetUIMapObjectDelegate(IntPtr UIObject);
private GetUIMapObjectDelegate getUIMapObject;
[UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Ansi)]
private delegate bool OpenMapWithFlagDelegate(IntPtr UIMapObject, string flag);
private OpenMapWithFlagDelegate openMapWithFlag;
/// <summary>
/// The item ID that is currently hovered by the player. 0 when no item is hovered.
/// If > 1.000.000, subtract 1.000.000 and treat it as HQ
@ -43,6 +55,7 @@ namespace Dalamud.Game.Internal.Gui {
Log.Verbose("SetGlobalBgm address {Address}", Address.SetGlobalBgm);
Log.Verbose("HandleItemHover address {Address}", Address.HandleItemHover);
Log.Verbose("HandleItemOut address {Address}", Address.HandleItemOut);
Log.Verbose("GetUIObject address {Address}", Address.GetUIObject);
Chat = new ChatGui(Address.ChatManager, scanner, dalamud);
@ -59,6 +72,8 @@ namespace Dalamud.Game.Internal.Gui {
new Hook<HandleItemOutDelegate>(Address.HandleItemOut,
new HandleItemOutDelegate(HandleItemOutDetour),
this);
this.getUIObject = Marshal.GetDelegateForFunctionPointer<GetUIObjectDelegate>(Address.GetUIObject);
}
private IntPtr HandleSetGlobalBgmDetour(UInt16 bgmKey, byte a2, UInt32 a3, UInt32 a4, UInt32 a5, byte a6) {
@ -111,6 +126,39 @@ namespace Dalamud.Game.Internal.Gui {
return retVal;
}
public bool OpenMapWithMapLink(MapLinkPayload mapLink)
{
var uiObjectPtr = getUIObject();
if (uiObjectPtr.Equals(IntPtr.Zero))
{
Log.Error("OpenMapWithMapLink: Null pointer returned from getUIObject()");
return false;
}
getUIMapObject =
Address.GetVirtualFunction<GetUIMapObjectDelegate>(uiObjectPtr, 0, 8);
var uiMapObjectPtr = this.getUIMapObject(uiObjectPtr);
if (uiMapObjectPtr.Equals(IntPtr.Zero))
{
Log.Error("OpenMapWithMapLink: Null pointer returned from GetUIMapObject()");
return false;
}
openMapWithFlag =
Address.GetVirtualFunction<OpenMapWithFlagDelegate>(uiMapObjectPtr, 0, 63);
var mapLinkString =
$"m:{mapLink.TerritoryTypeId},{mapLink.MapId},{unchecked((int)mapLink.RawX)},{unchecked((int)mapLink.RawY)}";
Log.Debug($"OpenMapWithMapLink: Opening Map Link: {mapLinkString}");
return this.openMapWithFlag(uiMapObjectPtr, mapLinkString);
}
public void SetBgm(ushort bgmKey) => this.setGlobalBgmHook.Original(bgmKey, 0, 0, 0, 0, 0);
public void Enable() {

View file

@ -11,6 +11,7 @@ namespace Dalamud.Game.Internal.Gui {
public IntPtr SetGlobalBgm { get; private set; }
public IntPtr HandleItemHover { get; set; }
public IntPtr HandleItemOut { get; set; }
public IntPtr GetUIObject { get; private set; }
public GameGuiAddressResolver(IntPtr baseAddress) {
BaseAddress = baseAddress;
@ -29,6 +30,7 @@ namespace Dalamud.Game.Internal.Gui {
SetGlobalBgm = sig.ScanText("4C 8B 15 ?? ?? ?? ?? 4D 85 D2 74 58");
HandleItemHover = sig.ScanText("E8 ?? ?? ?? ?? 48 8B 5C 24 ?? 48 89 AE ?? ?? ?? ??");
HandleItemOut = sig.ScanText("48 89 5C 24 ?? 57 48 83 EC 20 48 8B FA 48 8B D9 4D");
GetUIObject = sig.ScanText("E8 ?? ?? ?? ?? 48 8B C8 48 8B 10 FF 52 40 80 88 ?? ?? ?? ?? 01 E9");
}
}
}

View file

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Serilog;
namespace Dalamud.Interface
{
class AssetManager {
private const string AssetStoreUrl = "https://goatcorp.github.io/DalamudAssets/";
private static readonly Dictionary<string, string> AssetDictionary = new Dictionary<string, string> {
{AssetStoreUrl + "UIRes/serveropcode.json", "UIRes/serveropcode.json" },
{AssetStoreUrl + "UIRes/NotoSansCJKjp-Medium.otf", "UIRes/NotoSansCJKjp-Medium.otf" },
{AssetStoreUrl + "UIRes/logo.png", "UIRes/logo.png" },
{AssetStoreUrl + "UIRes/loc/dalamud/dalamud_de.json", "UIRes/loc/dalamud/dalamud_de.json" },
{AssetStoreUrl + "UIRes/loc/dalamud/dalamud_es.json", "UIRes/loc/dalamud/dalamud_es.json" },
{AssetStoreUrl + "UIRes/loc/dalamud/dalamud_fr.json", "UIRes/loc/dalamud/dalamud_fr.json" },
{AssetStoreUrl + "UIRes/loc/dalamud/dalamud_it.json", "UIRes/loc/dalamud/dalamud_it.json" },
{AssetStoreUrl + "UIRes/loc/dalamud/dalamud_ja.json", "UIRes/loc/dalamud/dalamud_ja.json" },
{"https://img.finalfantasyxiv.com/lds/pc/global/fonts/FFXIV_Lodestone_SSF.ttf", "UIRes/gamesym.ttf" }
};
public static async Task EnsureAssets(string baseDir) {
using var client = new HttpClient();
var assetVerRemote = await client.GetStringAsync(AssetStoreUrl + "version");
var assetVerPath = Path.Combine(baseDir, "assetver");
var assetVerLocal = "0";
if (File.Exists(assetVerPath))
assetVerLocal = File.ReadAllText(assetVerPath);
var forceRedownload = assetVerLocal != assetVerRemote;
if (forceRedownload)
Log.Information("Assets need redownload");
Log.Verbose("Starting asset download");
foreach (var entry in AssetDictionary) {
var filePath = Path.Combine(baseDir, entry.Value);
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
if (!File.Exists(filePath) || forceRedownload) {
Log.Verbose("Downloading {0} to {1}...", entry.Key, entry.Value);
try {
File.WriteAllBytes(filePath, await client.GetByteArrayAsync(entry.Key));
} catch (Exception ex) {
// If another game is running, we don't want to just fail in here
Log.Error(ex, "Could not download asset.");
}
}
}
try {
File.WriteAllText(assetVerPath, assetVerRemote);
} catch (Exception ex) {
Log.Error(ex, "Could not write asset version.");
}
}
}
}

View file

@ -22,6 +22,7 @@ attick
Aida-Enna
perchbird
Wintermute
fmauNeko

View file

@ -1,4 +1,5 @@
using System.Numerics;
using Dalamud.Game.Chat;
using Dalamud.Game.ClientState.Actors.Types;
using Dalamud.Game.ClientState.Actors.Types.NonPlayer;
using ImGuiNET;
@ -45,8 +46,8 @@ namespace Dalamud.Interface
ImGui.SameLine();
var copy = ImGui.Button("Copy all");
ImGui.SameLine();
ImGui.Combo("Data kind", ref this.currentKind, new[] {"ServerOpCode", "ContentFinderCondition", "State"},
3);
ImGui.Combo("Data kind", ref this.currentKind, new[] {"ServerOpCode", "ContentFinderCondition", "State", "Font Test"},
4);
ImGui.BeginChild("scrolling", new Vector2(0, 0), false, ImGuiWindowFlags.HorizontalScrollbar);
@ -81,16 +82,16 @@ namespace Dalamud.Interface
stateString += $"HomeWorldName: {this.dalamud.ClientState.LocalPlayer.HomeWorld.GameData.Name}\n";
stateString += $"LocalCID: {this.dalamud.ClientState.LocalContentId:X}\n";
stateString += $"LastLinkedItem: {this.dalamud.Framework.Gui.Chat.LastLinkedItemId.ToString()}\n";
stateString += $"TerritoryType: {this.dalamud.ClientState.TerritoryType}\n";
stateString += $"TerritoryType: {this.dalamud.ClientState.TerritoryType}\n\n";
for (var i = 0; i < this.dalamud.ClientState.Actors.Length; i++) {
var actor = this.dalamud.ClientState.Actors[i];
stateString +=
$" -> {i} - {actor.Name} - {actor.Position.X} {actor.Position.Y} {actor.Position.Z}\n";
$"{actor.Address.ToInt64():X}:{actor.ActorId:X}[{i}] - {actor.ObjectKind} - {actor.Name} - {actor.Position.X} {actor.Position.Y} {actor.Position.Z}\n";
if (actor is Npc npc)
stateString += $" DataId: {npc.DataId}\n";
stateString += $" DataId: {npc.DataId} NameId:{npc.NameId}\n";
if (actor is Chara chara)
stateString +=
@ -105,6 +106,14 @@ namespace Dalamud.Interface
ImGui.TextUnformatted(stateString);
}
break;
case 3:
var specialChars = string.Empty;
for (var i = 0xE020; i <= 0xE0DB; i++) {
specialChars += $"0x{i:X} - {(SeIconChar) i} - {(char) i}\n";
}
ImGui.TextUnformatted(specialChars);
break;
}
else
ImGui.TextUnformatted("Data not ready.");

View file

@ -52,6 +52,8 @@ namespace Dalamud.Interface
private delegate void InstallRTSSHook();
private string rtssPath;
public ImGuiIOPtr LastImGuiIoPtr;
/// <summary>
/// This event gets called by a plugin UiBuilder when read
/// </summary>
@ -198,7 +200,7 @@ namespace Dalamud.Interface
return null;
}
private IntPtr PresentDetour(IntPtr swapChain, uint syncInterval, uint presentFlags)
private unsafe IntPtr PresentDetour(IntPtr swapChain, uint syncInterval, uint presentFlags)
{
if (this.scene == null)
{
@ -207,11 +209,31 @@ namespace Dalamud.Interface
this.scene.OnBuildUI += Display;
this.scene.OnNewInputFrame += OnNewInputFrame;
ImFontConfigPtr fontConfig = ImGuiNative.ImFontConfig_ImFontConfig();
fontConfig.MergeMode = true;
fontConfig.PixelSnapH = true;
var fontPathJp = Path.Combine(this.dalamud.StartInfo.WorkingDirectory, "UIRes", "NotoSansCJKjp-Medium.otf");
ImGui.GetIO().Fonts.AddFontFromFileTTF(fontPathJp, 17.0f, null, ImGui.GetIO().Fonts.GetGlyphRangesJapanese());
var fontPathGame = Path.Combine(this.dalamud.StartInfo.WorkingDirectory, "UIRes", "gamesym.ttf");
Log.Verbose(fontPathGame);
var rangeHandle = GCHandle.Alloc(new ushort[]
{
0xE020,
0xE0DB,
0
}, GCHandleType.Pinned);
ImGui.GetIO().Fonts.AddFontFromFileTTF(fontPathGame, 17.0f, fontConfig, rangeHandle.AddrOfPinnedObject());
ImGui.GetIO().Fonts.Build();
fontConfig.Destroy();
rangeHandle.Free();
ImGui.GetStyle().GrabRounding = 3f;
ImGui.GetStyle().FrameRounding = 4f;
ImGui.GetStyle().WindowRounding = 4f;
@ -297,7 +319,8 @@ namespace Dalamud.Interface
// they will see both cursors.
// Doing this here because it's somewhat application-specific behavior
//ImGui.GetIO().MouseDrawCursor = ImGui.GetIO().WantCaptureMouse;
this.lastWantCapture = ImGui.GetIO().WantCaptureMouse;
this.LastImGuiIoPtr = ImGui.GetIO();
this.lastWantCapture = this.LastImGuiIoPtr.WantCaptureMouse;
OnDraw?.Invoke();
}

View file

@ -24,6 +24,7 @@ namespace Dalamud.Interface
{
private readonly DataManager data;
private readonly UiBuilder builder;
private readonly bool closeOnChoose;
private string lastSearchText = string.Empty;
private string searchText = string.Empty;
@ -40,14 +41,16 @@ namespace Dalamud.Interface
public event EventHandler<Item> OnItemChosen;
public ItemSearchWindow(DataManager data, UiBuilder builder) {
public ItemSearchWindow(DataManager data, UiBuilder builder, bool closeOnChoose = true) {
this.data = data;
this.builder = builder;
this.closeOnChoose = closeOnChoose;
while (!data.IsDataReady)
Thread.Sleep(1);
this.luminaItems = this.data.GetExcelSheet<Item>().GetRows();
Task.Run(() => this.data.GetExcelSheet<Item>().GetRows()).ContinueWith(t => this.luminaItems = t.Result);
}
public bool Draw() {
@ -95,56 +98,69 @@ namespace Dalamud.Interface
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(0, 0));
if (!string.IsNullOrEmpty(this.searchText) || this.currentKind != 0) {
if (this.lastSearchText != this.searchText || this.lastKind != this.currentKind) {
this.lastSearchText = this.searchText;
this.lastKind = this.currentKind;
if (this.luminaItems != null) {
if (!string.IsNullOrEmpty(this.searchText) || this.currentKind != 0)
{
if (this.lastSearchText != this.searchText || this.lastKind != this.currentKind)
{
this.lastSearchText = this.searchText;
this.lastKind = this.currentKind;
this.searchCancelTokenSource?.Cancel();
this.searchCancelTokenSource?.Cancel();
this.searchCancelTokenSource = new CancellationTokenSource();
this.searchCancelTokenSource = new CancellationTokenSource();
var asyncEnum = this.luminaItems.ToAsyncEnumerable();
var asyncEnum = this.luminaItems.ToAsyncEnumerable();
if (!string.IsNullOrEmpty(this.searchText)) {
Log.Debug("Searching for " + this.searchText);
asyncEnum = asyncEnum.Where(
x => (x.Name.ToLower().Contains(this.searchText.ToLower()) ||
int.TryParse(this.searchText, out var parsedId) &&
parsedId == x.RowId));
if (!string.IsNullOrEmpty(this.searchText))
{
Log.Debug("Searching for " + this.searchText);
asyncEnum = asyncEnum.Where(
x => (x.Name.ToLower().Contains(this.searchText.ToLower()) ||
int.TryParse(this.searchText, out var parsedId) &&
parsedId == x.RowId));
}
if (this.currentKind != 0)
{
Log.Debug("Searching for C" + this.currentKind);
asyncEnum = asyncEnum.Where(x => x.ItemSearchCategory == this.currentKind);
}
this.selectedItemIndex = -1;
this.selectedItemTex?.Dispose();
this.selectedItemTex = null;
this.searchTask = asyncEnum.ToListAsync(this.searchCancelTokenSource.Token);
}
if (this.currentKind != 0) {
Log.Debug("Searching for C" + this.currentKind);
asyncEnum = asyncEnum.Where(x => x.ItemSearchCategory == this.currentKind);
if (this.searchTask.IsCompletedSuccessfully)
{
for (var i = 0; i < this.searchTask.Result.Count; i++)
{
if (ImGui.Selectable(this.searchTask.Result[i].Name, this.selectedItemIndex == i))
{
this.selectedItemIndex = i;
var iconTex = this.data.GetIcon(this.searchTask.Result[i].Icon);
this.selectedItemTex?.Dispose();
this.selectedItemTex =
this.builder.LoadImageRaw(iconTex.GetRgbaImageData(), iconTex.Header.Width,
iconTex.Header.Height, 4);
}
}
}
}
else
{
ImGui.TextColored(new Vector4(0.86f, 0.86f, 0.86f, 1.00f), Loc.Localize("DalamudItemSelectHint", "Type to start searching..."));
this.selectedItemIndex = -1;
this.selectedItemTex?.Dispose();
this.selectedItemTex = null;
this.searchTask = asyncEnum.ToListAsync(this.searchCancelTokenSource.Token);
}
if (this.searchTask.IsCompletedSuccessfully) {
for (var i = 0; i < this.searchTask.Result.Count; i++) {
if (ImGui.Selectable(this.searchTask.Result[i].Name, this.selectedItemIndex == i)) {
this.selectedItemIndex = i;
var iconTex = this.data.GetIcon(this.searchTask.Result[i].Icon);
this.selectedItemTex?.Dispose();
this.selectedItemTex =
this.builder.LoadImageRaw(iconTex.GetRgbaImageData(), iconTex.Header.Width,
iconTex.Header.Height, 4);
}
}
}
} else {
ImGui.TextColored(new Vector4(0.86f, 0.86f, 0.86f, 1.00f), Loc.Localize("DalamudItemSelectHint", "Type to start searching..."));
this.selectedItemIndex = -1;
this.selectedItemTex?.Dispose();
this.selectedItemTex = null;
ImGui.TextColored(new Vector4(0.86f, 0.86f, 0.86f, 1.00f), Loc.Localize("DalamudItemSelectLoading", "Loading item list..."));
}
ImGui.PopStyleVar();
@ -153,8 +169,20 @@ namespace Dalamud.Interface
if (ImGui.Button(Loc.Localize("Choose", "Choose"))) {
OnItemChosen?.Invoke(this, this.searchTask.Result[this.selectedItemIndex]);
this.selectedItemTex?.Dispose();
isOpen = false;
if (this.closeOnChoose) {
this.selectedItemTex?.Dispose();
isOpen = false;
}
}
if (!this.closeOnChoose) {
ImGui.SameLine();
if (ImGui.Button(Loc.Localize("Close", "Close")))
{
this.selectedItemTex?.Dispose();
isOpen = false;
}
}
ImGui.End();

View file

@ -95,7 +95,7 @@ namespace Dalamud.Interface
try {
OnBuildUi?.Invoke();
} catch (Exception ex) {
Log.Error("[{0}] UiBuilder OnBuildUi caught exception");
Log.Error(ex, "[{0}] UiBuilder OnBuildUi caught exception", this.namespaceName);
OnBuildUi = null;
OnOpenConfigUi = null;

View file

@ -39,6 +39,11 @@ namespace Dalamud
}
public void SetupWithLangCode(string langCode) {
if (langCode.ToLower() == "en") {
Loc.SetupWithFallbacks();
return;
}
Loc.Setup(File.ReadAllText(Path.Combine(this.workingDirectory, "UIRes", "loc", "dalamud", $"dalamud_{langCode}.json")));
}
}

View file

@ -14,7 +14,7 @@ namespace Dalamud.Plugin
{
public class PluginRepository
{
private const string PluginRepoBaseUrl = "https://goaaats.github.io/DalamudPlugins/";
private const string PluginRepoBaseUrl = "https://goatcorp.github.io/DalamudPlugins/";
private PluginManager manager;
private string pluginDirectory;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

View file

@ -1,194 +0,0 @@
{
"DalamudUnloadHelp": {
"message": "Entläd das XIVLauncher In-Game-Addon.",
"description": "Dalamud.SetupCommands"
},
"DalamudPluginReloadHelp": {
"message": "Läd alle Plugins neu.",
"description": "Dalamud.SetupCommands"
},
"DalamudPrintChatHelp": {
"message": "Gibt eine Nachricht im Chat aus.",
"description": "Dalamud.SetupCommands"
},
"DalamudCmdInfoHelp": {
"message": "Zeigt eine Liste aller verfügbaren Textkommandos an.",
"description": "Dalamud.SetupCommands"
},
"DalamudMuteHelp": {
"message": "Gib ein Wort oder einen Satz ein, der nicht im Chat auftauchen soll. Nutzung: /xlmute <word or sentence>",
"description": "Dalamud.SetupCommands"
},
"DalamudMuteListHelp": {
"message": "Listet stummgeschaltete Worte oder Sätze auf.",
"description": "Dalamud.SetupCommands"
},
"DalamudUnmuteHelp": {
"message": "Löscht ein Wort oder einen Satz von der Liste der stummgeschalteten Worte. Nutzung: /xlunmute <word or sentence>",
"description": "Dalamud.SetupCommands"
},
"DalamudLastLinkHelp": {
"message": "Öffnet den zuletzt im Chat geposteten Link in deinem Browser.",
"description": "Dalamud.SetupCommands"
},
"DalamudBotJoinHelp": {
"message": "Füge den XIVLauncher Discord-Bot zu einem deiner Server hinzu.",
"description": "Dalamud.SetupCommands"
},
"DalamudBgmSetHelp": {
"message": "Setzt die Hintergrundmusik im Spiel. Nutzung: /xlbgmset <BGM ID>",
"description": "Dalamud.SetupCommands"
},
"DalamudItemLinkHelp": {
"message": "Verlinkt den angegebenen Gegenstand. Nutzung: /xlitem <Item name>. Um den exakten Namen anzugeben, nutze /xlitem +<Item name>",
"description": "Dalamud.SetupCommands"
},
"DalamudBonusHelp": {
"message": "Sende eine Benachrichtigung, wenn ein Zufallsinhalt einen Bonus für die Rolle hast, die du angibst. Nutzung: /xlbonus <roulette name> <role name>",
"description": "Dalamud.SetupCommands"
},
"DalamudDevMenuHelp": {
"message": "Öffne das dev-Menü DEBUG",
"description": "Dalamud.SetupCommands"
},
"DalamudInstallerHelp": {
"message": "Öffnet den Plugin-Installer",
"description": "Dalamud.SetupCommands"
},
"DalamudCreditsHelp": {
"message": "Öffnet die Liste der Mitwirkenden",
"description": "Dalamud.SetupCommands"
},
"DalamudCmdHelpAvailable": {
"message": "Verfügbare Kommandos:",
"description": "Dalamud.OnHelpCommand"
},
"DalamudMuted": {
"message": "\"{0}\" stummgeschaltet.",
"description": "Dalamud.OnBadWordsAddCommand"
},
"DalamudNoneMuted": {
"message": "Keine stummgeschalteten Wörte oder Sätze.",
"description": "Dalamud.OnBadWordsListCommand"
},
"DalamudUnmuted": {
"message": "\"{0}\" freigegeben.",
"description": "Dalamud.OnBadWordsRemoveCommand"
},
"DalamudNoLastLink": {
"message": "Keinen Link gefunden...",
"description": "Dalamud.OnLastLinkCommand"
},
"DalamudOpeningLink": {
"message": "{0} wird geöffnet",
"description": "Dalamud.OnLastLinkCommand"
},
"DalamudBotNotSetup": {
"message": "Der XIVLauncher Discord-Bot wurde nicht korrekt eingestellt. Bitte prüfe die Einstellungen und unser FAQ.",
"description": "Dalamud.OnBotJoinCommand"
},
"DalamudChannelNotSetup": {
"message": "Du hast keinen Discord-Kanal für diese Notifikationen eingestellt - du wirst sie also nur im Chat erhalten.\nUm einen Kanal einzustellen, nutze bitte die XIVLauncher-Einstellungen.",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudBonusSet": {
"message": "Bonus-Notifikationen für {0}({1}) auf {2} gesetzt",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudInvalidArguments": {
"message": "Parameter nicht erkannt.",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudBonusPossibleValues": {
"message": "Mögliche Werte für Zufallsinhalte: leveling, 506070, msq, guildhests, expert, trials, mentor, alliance, normal\nMögliche Werte für Rollen: tank, dps, healer, all, none/reset",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudItemNotFound": {
"message": "Gegenstand konnte nicht gefunden werden.",
"description": "<<OnItemLinkCommand>b__0>d.MoveNext"
},
"InstallerHeader": {
"message": "Plugin-Installer",
"description": "PluginInstallerWindow.Draw"
},
"InstallerHint": {
"message": "Dieses Fenster erlaubt es dir, Plugins zu installieren.\nSie werden von Drittanbietern entwickelt.",
"description": "PluginInstallerWindow.Draw"
},
"InstallerLoading": {
"message": "Plugins werden geladen...",
"description": "PluginInstallerWindow.Draw"
},
"InstallerDownloadFailed": {
"message": "Download fehlgeschlagen.",
"description": "PluginInstallerWindow.Draw"
},
"InstallerInstalled": {
"message": " (installiert)",
"description": "PluginInstallerWindow.Draw"
},
"InstallerInProgress": {
"message": "Wird installiert...",
"description": "PluginInstallerWindow.Draw"
},
"InstallerDisable": {
"message": "Deaktivieren",
"description": "PluginInstallerWindow.Draw"
},
"InstallerOpenConfig": {
"message": "Einstellungen öffnen",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdating": {
"message": "Wird aktualisiert...",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdateComplete": {
"message": "{0} Plugins aktualisiert!",
"description": "PluginInstallerWindow.Draw"
},
"InstallerNoUpdates": {
"message": "Keine Aktualisierungen gefunden!",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdatePlugins": {
"message": "Plugins aktualisieren",
"description": "PluginInstallerWindow.Draw"
},
"Close": {
"message": "Schließen",
"description": "PluginInstallerWindow.Draw"
},
"InstallerError": {
"message": "Installation fehlgeschlagen",
"description": "PluginInstallerWindow.Draw"
},
"InstallerErrorHint": {
"message": "Der Plugin-Installer konnte die Operation nicht erfolgreich beenden.\nBitte starte das Spiel neu und melde diesen Fehler auf unserem Discord-Server.",
"description": "PluginInstallerWindow.Draw"
},
"OK": {
"message": "OK",
"description": "PluginInstallerWindow.Draw"
},
"DalamudWelcome": {
"message": "XIVLauncher In-Game-Addon v{0} geladen.",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginLoaded": {
"message": " 》 {0} v{1} geladen.",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudUpdated": {
"message": "Das In-Game-Addon wurde aktualisiert oder neu installiert. Bitte prüfe unseren Discord-Server für weitere Informationen!",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginUpdateRequired": {
"message": "Eines oder mehrere deiner Plugins müssen aktualisiert werden. Bitte nutze das /xlplugins-Kommando, um sie zu aktualisieren.",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginUpdateCheckFail": {
"message": "Konnte nicht auf Plugin-Aktualisierungen prüfen.",
"description": "ChatHandlers.OnChatMessage"
}
}

View file

@ -1,194 +0,0 @@
{
"DalamudUnloadHelp": {
"message": "Decarga el extra In-Game de XIVLauncher.",
"description": "Dalamud.SetupCommands"
},
"DalamudPluginReloadHelp": {
"message": "Recarga todos de los plugins.",
"description": "Dalamud.SetupCommands"
},
"DalamudPrintChatHelp": {
"message": "Publica al chat.",
"description": "Dalamud.SetupCommands"
},
"DalamudCmdInfoHelp": {
"message": "Muestre la lista de los comandos disponibles.",
"description": "Dalamud.SetupCommands"
},
"DalamudMuteHelp": {
"message": "Bloquea una palabra u oración que aperecer en el chat. Uso: /xlmute <palabra u oración>",
"description": "Dalamud.SetupCommands"
},
"DalamudMuteListHelp": {
"message": "Enumera las palabras u oraciónes qué están bloqueadas.",
"description": "Dalamud.SetupCommands"
},
"DalamudUnmuteHelp": {
"message": "Desbloquea una palabra u oración. Uso: /xlunmute <palabra u oración>",
"description": "Dalamud.SetupCommands"
},
"DalamudLastLinkHelp": {
"message": "Abre el enlace anterior en su navegador por defecto.",
"description": "Dalamud.SetupCommands"
},
"DalamudBotJoinHelp": {
"message": "Agrega el bot Discord de XIVLauncher que ha configurado a su servidor.",
"description": "Dalamud.SetupCommands"
},
"DalamudBgmSetHelp": {
"message": "Configura la música ambiental del juego. Uso: /xlbgmset <BGM ID>",
"description": "Dalamud.SetupCommands"
},
"DalamudItemLinkHelp": {
"message": "Enlaza un artículo por nombre. Uso: /xlitem <nombre del artículo>. Para emperejando un artículo exactamente, utiliza /xlitem +<nombre del artículo>",
"description": "Dalamud.SetupCommands"
},
"DalamudBonusHelp": {
"message": "Notifícase cuando una ruleta tenga un extra que usted especifica. Ejecútalo sin parametres para más información. Uso: /xlbonus <nombre de ruleta> <nombre del papel>",
"description": "Dalamud.SetupCommands"
},
"DalamudDevMenuHelp": {
"message": "Dibuja el menú dev DEBUG",
"description": "Dalamud.SetupCommands"
},
"DalamudInstallerHelp": {
"message": "Abre el instalador de plugins",
"description": "Dalamud.SetupCommands"
},
"DalamudCreditsHelp": {
"message": "Abra los méritos de Dalamud.",
"description": "Dalamud.SetupCommands"
},
"DalamudCmdHelpAvailable": {
"message": "Comandos disponibles:",
"description": "Dalamud.OnHelpCommand"
},
"DalamudMuted": {
"message": "Ha bloqueado \"{0}\".",
"description": "Dalamud.OnBadWordsAddCommand"
},
"DalamudNoneMuted": {
"message": "No hay palabras u oraciónes qué están bloqueadas.",
"description": "Dalamud.OnBadWordsListCommand"
},
"DalamudUnmuted": {
"message": "Ha desbloqueado \"{0}\".",
"description": "Dalamud.OnBadWordsRemoveCommand"
},
"DalamudNoLastLink": {
"message": "No hay un enlace anterior...",
"description": "Dalamud.OnLastLinkCommand"
},
"DalamudOpeningLink": {
"message": "Está abriendo {0}",
"description": "Dalamud.OnLastLinkCommand"
},
"DalamudBotNotSetup": {
"message": "El bot Discord de XIVLauncher no configuría corecto o no pudo conectar a Discord. Por favor revisa los ajustes y el FAQ.",
"description": "Dalamud.OnBotJoinCommand"
},
"DalamudChannelNotSetup": {
"message": "No configuría un canal Discord para estos notificaciónes - solo recibirá en el chat. Para que lo configura, por favor utiliza los ajustes de XIVLauncher en el juego.",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudBonusSet": {
"message": "Configura notificaciónes bonus para {0}({1}) a {2}",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudInvalidArguments": {
"message": "Hay argumentes que no reconocido.",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudBonusPossibleValues": {
"message": "Valores posibles para ruleta: leveling, 506070, msq, guildhests, expert, trials, mentor, alliance, normal\nValores posibles para rol: tank, dps, healer, all, none/reset",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudItemNotFound": {
"message": "No pudo encuentra el artículo.",
"description": "<<OnItemLinkCommand>b__0>d.MoveNext"
},
"InstallerHeader": {
"message": "Instalador de Plugins",
"description": "PluginInstallerWindow.Draw"
},
"InstallerHint": {
"message": "Esta ventana permite que instalar y elimnar los plugins en el juego.\nFueron hechos por desarrolladores terceros.",
"description": "PluginInstallerWindow.Draw"
},
"InstallerLoading": {
"message": "Está cargando los plugins...",
"description": "PluginInstallerWindow.Draw"
},
"InstallerDownloadFailed": {
"message": "La descarga falló.",
"description": "PluginInstallerWindow.Draw"
},
"InstallerInstalled": {
"message": " (instalado)",
"description": "PluginInstallerWindow.Draw"
},
"InstallerInProgress": {
"message": "Instalación en curso...",
"description": "PluginInstallerWindow.Draw"
},
"InstallerDisable": {
"message": "Desactiva",
"description": "PluginInstallerWindow.Draw"
},
"InstallerOpenConfig": {
"message": "Abre Configuración",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdating": {
"message": "Actualizando...",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdateComplete": {
"message": "¡{0} plugins han actualizado!",
"description": "PluginInstallerWindow.Draw"
},
"InstallerNoUpdates": {
"message": "¡No hay actualizaciónes!",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdatePlugins": {
"message": "Actualiza plugins",
"description": "PluginInstallerWindow.Draw"
},
"Close": {
"message": "Cierra",
"description": "PluginInstallerWindow.Draw"
},
"InstallerError": {
"message": "El instalador falló",
"description": "PluginInstallerWindow.Draw"
},
"InstallerErrorHint": {
"message": "El instalador de plugins corrió a una problema, o el plugin está incompatible.\nPor favor reinicia el juego y informa el error en neustro Discord.",
"description": "PluginInstallerWindow.Draw"
},
"OK": {
"message": "OK",
"description": "PluginInstallerWindow.Draw"
},
"DalamudWelcome": {
"message": "El extra In-Game v{0} de XIVLauncher ha cargado.",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginLoaded": {
"message": " 》 {0} v{1} ha cargado.",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudUpdated": {
"message": "¡El extra In-Game había actualizado o reinstalado con éxito! Por favor comproba el Discord para un changelog completo.",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginUpdateRequired": {
"message": "Uno o más de sus plugins deben habar actualizado. ¡Por favor utiliza el comando /xlplugins para los actualizan!",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginUpdateCheckFail": {
"message": "No pudo buscar para actualizaciónes de los plugins.",
"description": "ChatHandlers.OnChatMessage"
}
}

View file

@ -1,194 +0,0 @@
{
"DalamudUnloadHelp": {
"message": "Désactive l'addon in-game de XIVLauncher.",
"description": "Dalamud.SetupCommands"
},
"DalamudPluginReloadHelp": {
"message": "Recharge tous les plugins.",
"description": "Dalamud.SetupCommands"
},
"DalamudPrintChatHelp": {
"message": "Afficher dans le chat.",
"description": "Dalamud.SetupCommands"
},
"DalamudCmdInfoHelp": {
"message": "Montre la liste des commandes disponibles.",
"description": "Dalamud.SetupCommands"
},
"DalamudMuteHelp": {
"message": "Met en sourdine un mot ou une phrase dans le chat. Utilisation: /xlmute <mot ou phrase>",
"description": "Dalamud.SetupCommands"
},
"DalamudMuteListHelp": {
"message": "Liste les mots ou phrases en sourdine.",
"description": "Dalamud.SetupCommands"
},
"DalamudUnmuteHelp": {
"message": "Ré-affiche un mot ou une phrase. Utilisation: /xlunmute <mot ou phrase>",
"description": "Dalamud.SetupCommands"
},
"DalamudLastLinkHelp": {
"message": "Ouvre le dernier lien affiché dans le chat dans votre navigateur par défaut.",
"description": "Dalamud.SetupCommands"
},
"DalamudBotJoinHelp": {
"message": "Ajoute le bot discord XIVLauncher que vous avez configuré à votre serveur.",
"description": "Dalamud.SetupCommands"
},
"DalamudBgmSetHelp": {
"message": "Définit la musique de fond. Utilisation: /xlbgmset <BGM ID>",
"description": "Dalamud.SetupCommands"
},
"DalamudItemLinkHelp": {
"message": "Envoie le lien d'un objet grâce à son nom. Utilisation: /xlitem <Nom de l'objet>. Pour trouver un objet précis, utilisez /xlitem +<Nom de l'objet>",
"description": "Dalamud.SetupCommands"
},
"DalamudBonusHelp": {
"message": "Informe lorsque une mission aléatoire possède le bonus spécifié. Exécuter sans paramètres pour plus d'infos. Utilisation: /xlbonus <nom de la mission aléatoire> <nom du rôle>",
"description": "Dalamud.SetupCommands"
},
"DalamudDevMenuHelp": {
"message": "Fait sortir le menu dev DEBUG",
"description": "Dalamud.SetupCommands"
},
"DalamudInstallerHelp": {
"message": "Ouvrir linstallateur de plugins",
"description": "Dalamud.SetupCommands"
},
"DalamudCreditsHelp": {
"message": "Ouvre la liste des participants.",
"description": "Dalamud.SetupCommands"
},
"DalamudCmdHelpAvailable": {
"message": "Commandes disponibles:",
"description": "Dalamud.OnHelpCommand"
},
"DalamudMuted": {
"message": "\"{0}\" est mis en sourdine.",
"description": "Dalamud.OnBadWordsAddCommand"
},
"DalamudNoneMuted": {
"message": "Pas de mots ou phrases en sourdine.",
"description": "Dalamud.OnBadWordsListCommand"
},
"DalamudUnmuted": {
"message": "\"{0}\" est de nouveau visible.",
"description": "Dalamud.OnBadWordsRemoveCommand"
},
"DalamudNoLastLink": {
"message": "Il n'y a pas de lien...",
"description": "Dalamud.OnLastLinkCommand"
},
"DalamudOpeningLink": {
"message": "Ouverture de {0}",
"description": "Dalamud.OnLastLinkCommand"
},
"DalamudBotNotSetup": {
"message": "Le bot discord XIVLauncher n'a pas été configuré correctement ou ne peut pas se connecter à discord. Veuillez vérifier les paramètres et la FAQ.",
"description": "Dalamud.OnBotJoinCommand"
},
"DalamudChannelNotSetup": {
"message": "Vous n'avez pas configuré de canal discord pour ces notifications - vous les recevrez uniquement dans le chat. Pour ce faire, veuillez utiliser les paramètres \"In-game\" dans XIVLauncher.",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudBonusSet": {
"message": "Définit les notifications de bonus pour {0}({1}) à {2}",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudInvalidArguments": {
"message": "Arguments non-reconnus.",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudBonusPossibleValues": {
"message": "Valeurs possibles pour mission aléatoire: leveling, 506070, msq, guildhests, expert, trials, mentor, alliance, normal\nValeurs possibles pour rôle: tank, dps, healer, all, none/reset",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudItemNotFound": {
"message": "L'objet n'a pas pu être trouvé.",
"description": "<<OnItemLinkCommand>b__0>d.MoveNext"
},
"InstallerHeader": {
"message": "Installateur de Plugin",
"description": "PluginInstallerWindow.Draw"
},
"InstallerHint": {
"message": "Cette fenêtre vous autorise à installer ou retirer des plugins en jeu.\nIls sont créés par des développeurs tiers.",
"description": "PluginInstallerWindow.Draw"
},
"InstallerLoading": {
"message": "Chargement des plugins...",
"description": "PluginInstallerWindow.Draw"
},
"InstallerDownloadFailed": {
"message": "Le téléchargement a échoué.",
"description": "PluginInstallerWindow.Draw"
},
"InstallerInstalled": {
"message": " (installé)",
"description": "PluginInstallerWindow.Draw"
},
"InstallerInProgress": {
"message": "Installation en cours...",
"description": "PluginInstallerWindow.Draw"
},
"InstallerDisable": {
"message": "Désactiver",
"description": "PluginInstallerWindow.Draw"
},
"InstallerOpenConfig": {
"message": "Ouvrir la configuration",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdating": {
"message": "Mise à jour...",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdateComplete": {
"message": "{0} plugin(s) mis à jour!",
"description": "PluginInstallerWindow.Draw"
},
"InstallerNoUpdates": {
"message": "Pas de mise à jour trouvée!",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdatePlugins": {
"message": "Mettre à jour les plugins",
"description": "PluginInstallerWindow.Draw"
},
"Close": {
"message": "Fermer",
"description": "PluginInstallerWindow.Draw"
},
"InstallerError": {
"message": "Échec de l'installation",
"description": "PluginInstallerWindow.Draw"
},
"InstallerErrorHint": {
"message": "L'installateur de plugins a rencontré un problème ou le plugin est incompatible.\nVeuillez redémarrer le jeu et rapporter cette erreur sur notre discord.",
"description": "PluginInstallerWindow.Draw"
},
"OK": {
"message": "OK",
"description": "PluginInstallerWindow.Draw"
},
"DalamudWelcome": {
"message": "Addon en jeu XIVLauncher v{0} chargé.",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginLoaded": {
"message": " 》 {0} v{1} chargé.",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudUpdated": {
"message": "L'addon en jeu à été mis à jour ou réinstallé avec succès! Veuillez consulter le discord pour plus d'informations.",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginUpdateRequired": {
"message": "Un ou plusieurs plugins ne sont plus à jour. Veuillez utiliser la commande en jeu /xlplugins pour les mettre à jour!",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginUpdateCheckFail": {
"message": "Impossible de vérifier les mises à jour des plugins.",
"description": "ChatHandlers.OnChatMessage"
}
}

View file

@ -1,194 +0,0 @@
{
"DalamudUnloadHelp": {
"message": "Disattiva l'addon in gioco di XIVLauncher.",
"description": "Dalamud.SetupCommands"
},
"DalamudPluginReloadHelp": {
"message": "Ricarica tutti i plugin.",
"description": "Dalamud.SetupCommands"
},
"DalamudPrintChatHelp": {
"message": "Stampa in chat.",
"description": "Dalamud.SetupCommands"
},
"DalamudCmdInfoHelp": {
"message": "Mostra lista dei comandi disponibili.",
"description": "Dalamud.SetupCommands"
},
"DalamudMuteHelp": {
"message": "Proibisci a una parola o a una frase di apparire in chat. Uso: /xlmute <parola o frase>",
"description": "Dalamud.SetupCommands"
},
"DalamudMuteListHelp": {
"message": "Elenca parole e frasi proibite.",
"description": "Dalamud.SetupCommands"
},
"DalamudUnmuteHelp": {
"message": "Permetti a una parola o a una frase di apparire in chat. Uso: /xlunmute <parola o frase>",
"description": "Dalamud.SetupCommands"
},
"DalamudLastLinkHelp": {
"message": "Apri il link piú recente della chat nel tuo browser predefinito.",
"description": "Dalamud.SetupCommands"
},
"DalamudBotJoinHelp": {
"message": "Aggiungi al tuo server il bot Discord di XIVLauncher che hai impostato.",
"description": "Dalamud.SetupCommands"
},
"DalamudBgmSetHelp": {
"message": "Imposta la musica di sottofondo del gioco. Uso: /xlbgmset <ID Musica>",
"description": "Dalamud.SetupCommands"
},
"DalamudItemLinkHelp": {
"message": "Linka un oggetto per nome. Uso: /xlitem <Nome oggetto>. Per abbinare un oggetto specifico, usa /xlitem +<Nome oggetto>",
"description": "Dalamud.SetupCommands"
},
"DalamudBonusHelp": {
"message": "Notificami quando una roulette contiene un bonus specifico. Esegui senza parametri aggiuntivi per maggiori informazioni. Uso: /xlbonus <Nome roulette> <Nome ruolo>",
"description": "Dalamud.SetupCommands"
},
"DalamudDevMenuHelp": {
"message": "Mostra menu sviluppatore DEBUG",
"description": "Dalamud.SetupCommands"
},
"DalamudInstallerHelp": {
"message": "Apri l'installatore dei plugin",
"description": "Dalamud.SetupCommands"
},
"DalamudCreditsHelp": {
"message": "Apri i titoli di coda per dalamud.",
"description": "Dalamud.SetupCommands"
},
"DalamudCmdHelpAvailable": {
"message": "Comandi disponibili:",
"description": "Dalamud.OnHelpCommand"
},
"DalamudMuted": {
"message": "Silenziato \"{0}\".",
"description": "Dalamud.OnBadWordsAddCommand"
},
"DalamudNoneMuted": {
"message": "Nessuna parola o frase proibita.",
"description": "Dalamud.OnBadWordsListCommand"
},
"DalamudUnmuted": {
"message": "Riattivato \"{0}\".",
"description": "Dalamud.OnBadWordsRemoveCommand"
},
"DalamudNoLastLink": {
"message": "Nessun link recente...",
"description": "Dalamud.OnLastLinkCommand"
},
"DalamudOpeningLink": {
"message": "Aprendo {0}",
"description": "Dalamud.OnLastLinkCommand"
},
"DalamudBotNotSetup": {
"message": "Il bot Discord di XIVLauncher non è stato impostato correttamente o non ha potuto connettersi a Discord. Per favore controlla le impostazioni e le FAQ.",
"description": "Dalamud.OnBotJoinCommand"
},
"DalamudChannelNotSetup": {
"message": "Non hai impostato un canale Discord per queste notifiche - Per fare ció, utilizza le impostazioni di gioco di XIVLauncher. Al momento, riceverai le notifiche solo nella chat.",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudBonusSet": {
"message": "Impostate notifiche bonus per {0}({1} a {2})",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudInvalidArguments": {
"message": "Argomenti non risconosciuti.",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudBonusPossibleValues": {
"message": "Possibili valori per la roulette: leveling, 506070, msq, guildhests, expert, trials, mentor, alliance, normal\nPossibili valori per i ruoli: tank, dps, healer, all, none/reset",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudItemNotFound": {
"message": "Oggetto non trovato.",
"description": "<<OnItemLinkCommand>b__0>d.MoveNext"
},
"InstallerHeader": {
"message": "Installatore Plugin",
"description": "PluginInstallerWindow.Draw"
},
"InstallerHint": {
"message": "Questa finestra ti permette di installare e rimuovere i plugin di gioco.\nSono sviluppati da terze parti.",
"description": "PluginInstallerWindow.Draw"
},
"InstallerLoading": {
"message": "Caricamento plugins...",
"description": "PluginInstallerWindow.Draw"
},
"InstallerDownloadFailed": {
"message": "Download fallito.",
"description": "PluginInstallerWindow.Draw"
},
"InstallerInstalled": {
"message": " (installato)",
"description": "PluginInstallerWindow.Draw"
},
"InstallerInProgress": {
"message": "Installazione in corso...",
"description": "PluginInstallerWindow.Draw"
},
"InstallerDisable": {
"message": "Disabilita",
"description": "PluginInstallerWindow.Draw"
},
"InstallerOpenConfig": {
"message": "Apri configurazione",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdating": {
"message": "Aggiornamento...",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdateComplete": {
"message": "{0} plugins aggiornati!",
"description": "PluginInstallerWindow.Draw"
},
"InstallerNoUpdates": {
"message": "Nessun aggiornamento trovato!",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdatePlugins": {
"message": "Aggiorna plugins",
"description": "PluginInstallerWindow.Draw"
},
"Close": {
"message": "Chiudi",
"description": "PluginInstallerWindow.Draw"
},
"InstallerError": {
"message": "Installazione fallita",
"description": "PluginInstallerWindow.Draw"
},
"InstallerErrorHint": {
"message": "L'installatore ha riscontrato dei problemi o il plugin é incompatibile.\nRiavvia il gioco e segnalaci questo errore sul nostro Discord.",
"description": "PluginInstallerWindow.Draw"
},
"OK": {
"message": "OK",
"description": "PluginInstallerWindow.Draw"
},
"DalamudWelcome": {
"message": "XIVLauncher addon in gioco v{0} caricato.",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginLoaded": {
"message": " 》 {0} v{1} caricato.",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudUpdated": {
"message": "L'addon in gioco è stato aggiornato o reinstallato con successo! Controlla su Discord per un changelog completo.",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginUpdateRequired": {
"message": "Uno o piú dei tuoi plugins necessita un aggiornamento. Usa il comando /xlplugins in gioco per aggiornarli!",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginUpdateCheckFail": {
"message": "Non è stato possibile controllare gli aggiornamenti dei plugin.",
"description": "ChatHandlers.OnChatMessage"
}
}

View file

@ -1,194 +0,0 @@
{
"DalamudUnloadHelp": {
"message": "XIVLauncher In-Game アドオンをアンロードします。",
"description": "Dalamud.SetupCommands"
},
"DalamudPluginReloadHelp": {
"message": "全てのプラグインをリロードします。",
"description": "Dalamud.SetupCommands"
},
"DalamudPrintChatHelp": {
"message": "チャットに出力する。",
"description": "Dalamud.SetupCommands"
},
"DalamudCmdInfoHelp": {
"message": "利用可能なコマンド一覧を表示します。",
"description": "Dalamud.SetupCommands"
},
"DalamudMuteHelp": {
"message": "チャットに表示される単語や文章をミュートします。 利用法: /xlmute <単語 または、文章>",
"description": "Dalamud.SetupCommands"
},
"DalamudMuteListHelp": {
"message": "ミュートされた単語または文章の一覧を表示します。",
"description": "Dalamud.SetupCommands"
},
"DalamudUnmuteHelp": {
"message": "単語または文章のミュートを解除します。利用法: /xlunmute <単語 または、文章>",
"description": "Dalamud.SetupCommands"
},
"DalamudLastLinkHelp": {
"message": "デフォルトブラウザで直前に投稿したリンクを開きます。",
"description": "Dalamud.SetupCommands"
},
"DalamudBotJoinHelp": {
"message": "設定した XIVLauncher の Discord ボットを自分のサーバーへ追加します。",
"description": "Dalamud.SetupCommands"
},
"DalamudBgmSetHelp": {
"message": "ゲームBGMを設定します。利用法: /xlbgmset <BGM ID>",
"description": "Dalamud.SetupCommands"
},
"DalamudItemLinkHelp": {
"message": "アイテムを名前でリンクします。使用法: /xlitem <アイテム名> アイテム名を完全一致したい場合: /xlitem +<アイテム名>",
"description": "Dalamud.SetupCommands"
},
"DalamudBonusHelp": {
"message": "ルーレットに指定したボーナスがある場合に通知します。詳細はパラメータなしで実行してください。使用法: /xlbonus <ルーレット名> <ロール名>",
"description": "Dalamud.SetupCommands"
},
"DalamudDevMenuHelp": {
"message": "DEBUG 開発メニューを表示します。",
"description": "Dalamud.SetupCommands"
},
"DalamudInstallerHelp": {
"message": "プラグインインストーラを開きます",
"description": "Dalamud.SetupCommands"
},
"DalamudCreditsHelp": {
"message": "Dalamud のクレジットを開きます。",
"description": "Dalamud.SetupCommands"
},
"DalamudCmdHelpAvailable": {
"message": "利用可能なコマンド:",
"description": "Dalamud.OnHelpCommand"
},
"DalamudMuted": {
"message": "\"{0}\" をミュートしました。",
"description": "Dalamud.OnBadWordsAddCommand"
},
"DalamudNoneMuted": {
"message": "ミュートされている単語または、文章はありません。",
"description": "Dalamud.OnBadWordsListCommand"
},
"DalamudUnmuted": {
"message": "\"{0}\" のミュートを解除しました。",
"description": "Dalamud.OnBadWordsRemoveCommand"
},
"DalamudNoLastLink": {
"message": "直前のリンクがありません……",
"description": "Dalamud.OnLastLinkCommand"
},
"DalamudOpeningLink": {
"message": "{0} を開いています。",
"description": "Dalamud.OnLastLinkCommand"
},
"DalamudBotNotSetup": {
"message": "XIVLauncher の Discordボットが正しく設定されていないか、Discord に接続できませんでした。設定やFAQをご確認ください。",
"description": "Dalamud.OnBotJoinCommand"
},
"DalamudChannelNotSetup": {
"message": "通知用の Discord チャンネルを設定していません (チャットでのみ受信できます)。Discord で通知を受け取るには、XIVLauncher の In-Game 設定をしてください。",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudBonusSet": {
"message": "{0}({1}) のボーナス通知を {2} に設定します",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudInvalidArguments": {
"message": "認識できないパラメータです。",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudBonusPossibleValues": {
"message": "ルーレットの可能な入力leveling, 506070, msq, guildhests, expert, trials, mentor, alliance, normal\nロールの可能な入力tank, dps, healer, all, none/reset",
"description": "Dalamud.OnRouletteBonusNotifyCommand"
},
"DalamudItemNotFound": {
"message": "アイテムを見つけられませんでした。",
"description": "<<OnItemLinkCommand>b__0>d.MoveNext"
},
"InstallerHeader": {
"message": "プラグインインストーラ",
"description": "PluginInstallerWindow.Draw"
},
"InstallerHint": {
"message": "このウィンドウでは、In-Game プラグインのインストールと削除を行うことができます。\nこれらはサードパーティの開発者によって作られたものです。",
"description": "PluginInstallerWindow.Draw"
},
"InstallerLoading": {
"message": "プラグインをロード中……",
"description": "PluginInstallerWindow.Draw"
},
"InstallerDownloadFailed": {
"message": "ダウンロードが失敗しました。",
"description": "PluginInstallerWindow.Draw"
},
"InstallerInstalled": {
"message": " (導入済み)",
"description": "PluginInstallerWindow.Draw"
},
"InstallerInProgress": {
"message": "インストール中……",
"description": "PluginInstallerWindow.Draw"
},
"InstallerDisable": {
"message": "無効化",
"description": "PluginInstallerWindow.Draw"
},
"InstallerOpenConfig": {
"message": "設定を開く",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdating": {
"message": "アップデートしています……",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdateComplete": {
"message": "{0} のプラグインが更新されました!",
"description": "PluginInstallerWindow.Draw"
},
"InstallerNoUpdates": {
"message": "アップデートが見つかりませんでした!",
"description": "PluginInstallerWindow.Draw"
},
"InstallerUpdatePlugins": {
"message": "プラグインをアップデートする",
"description": "PluginInstallerWindow.Draw"
},
"Close": {
"message": "閉じる",
"description": "PluginInstallerWindow.Draw"
},
"InstallerError": {
"message": "インストールが失敗しました",
"description": "PluginInstallerWindow.Draw"
},
"InstallerErrorHint": {
"message": "プラグインのインストーラに問題が発生したか、プラグインとの互換性がありません。\nゲームを再起動して、このエラーを私たちのディスコードで報告してください。",
"description": "PluginInstallerWindow.Draw"
},
"OK": {
"message": "OK",
"description": "PluginInstallerWindow.Draw"
},
"DalamudWelcome": {
"message": "XIVLauncher In-Game アドオン v{0} がロードされました.",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginLoaded": {
"message": " 》 {0} v{1} がロードされました。",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudUpdated": {
"message": "In-Game アドオンの更新または、再インストールに成功しました。詳細な変更履歴はDiscordで確認してください。",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginUpdateRequired": {
"message": "いくつかのプラグインで更新が必要です。/xlplugins コマンドを使用して、プラグインを更新してください。",
"description": "ChatHandlers.OnChatMessage"
},
"DalamudPluginUpdateCheckFail": {
"message": "プラグインの更新を確認できませんでした。",
"description": "ChatHandlers.OnChatMessage"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 KiB

View file

@ -6,11 +6,11 @@
Dalamud is a plugin development framework for FINAL FANTASY XIV that provides access to game data and native interoperability with the game itself to add functionality and quality-of-life.
It is meant to be used in conjunction with [FFXIVQuickLauncher](https://github.com/goaaats/FFXIVQuickLauncher).
It is meant to be used in conjunction with [FFXIVQuickLauncher](https://github.com/goatcorp/FFXIVQuickLauncher).
## Plugin development
Dalamud features a growing API for in-game plugin development with game data and chat access and overlays.
Please see the [API documentation](https://goaaats.github.io/Dalamud/api/index.html) for more details.
Please see the [API documentation](https://goatcorp.github.io/Dalamud/api/index.html) for more details.
If you need any support regarding the API or usage of Dalamud, please [join our discord server](https://discord.gg/3NMcUV5).

@ -1 +1 @@
Subproject commit b096e5b2e9826525394a0c00b987aad1f2c4eccb
Subproject commit aaa037938d6fe835a15542a3451d12108e3f83b6