using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using Dalamud.Configuration;
using Dalamud.Configuration.Internal;
using Dalamud.Data;
using Dalamud.Game.Gui;
using Dalamud.Game.Text;
using Dalamud.Game.Text.Sanitizer;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Interface;
using Dalamud.Interface.Internal;
using Dalamud.Plugin.Internal;
namespace Dalamud.Plugin
{
///
/// This class acts as an interface to various objects needed to interact with Dalamud and the game.
///
public sealed class DalamudPluginInterface : IDisposable
{
private readonly string pluginName;
private readonly PluginConfigurations configs;
///
/// Initializes a new instance of the class.
/// Set up the interface and populate all fields needed.
///
/// The internal name of the plugin.
/// The reason the plugin was loaded.
internal DalamudPluginInterface(string pluginName, PluginLoadReason reason)
{
var configuration = Service.Get();
var dataManager = Service.Get();
var localization = Service.Get();
this.UiBuilder = new UiBuilder(pluginName);
this.pluginName = pluginName;
this.configs = Service.Get().PluginConfigs;
this.Reason = reason;
this.GeneralChatType = configuration.GeneralChatType;
this.Sanitizer = new Sanitizer(dataManager.Language);
if (configuration.LanguageOverride != null)
{
this.UiLanguage = configuration.LanguageOverride;
}
else
{
var currentUiLang = CultureInfo.CurrentUICulture;
if (Localization.ApplicableLangCodes.Any(langCode => currentUiLang.TwoLetterISOLanguageName == langCode))
this.UiLanguage = currentUiLang.TwoLetterISOLanguageName;
else
this.UiLanguage = "en";
}
localization.OnLocalizationChanged += this.OnLocalizationChanged;
configuration.OnDalamudConfigurationSaved += this.OnDalamudConfigurationSaved;
}
///
/// Delegate for localization change with two-letter iso lang code.
///
/// The new language code.
public delegate void LanguageChangedDelegate(string langCode);
///
/// Event that gets fired when loc is changed
///
public event LanguageChangedDelegate OnLanguageChanged;
///
/// Gets the reason this plugin was loaded.
///
public PluginLoadReason Reason { get; }
///
/// Gets the directory Dalamud assets are stored in.
///
public DirectoryInfo DalamudAssetDirectory => Service.Get().AssetDirectory;
///
/// Gets the directory your plugin configurations are stored in.
///
public DirectoryInfo ConfigDirectory => new(this.GetPluginConfigDirectory());
///
/// Gets the config file of your plugin.
///
public FileInfo ConfigFile => this.configs.GetConfigFile(this.pluginName);
///
/// Gets the instance which allows you to draw UI into the game via ImGui draw calls.
///
public UiBuilder UiBuilder { get; private set; }
///
/// Gets a value indicating whether Dalamud is running in Debug mode or the /xldev menu is open. This can occur on release builds.
///
#if DEBUG
public bool IsDebugging => true;
#else
public bool IsDebugging => Service.Get().IsDevMenuOpen;
#endif
///
/// Gets the current UI language in two-letter iso format.
///
public string UiLanguage { get; private set; }
///
/// Gets serializer class with functions to remove special characters from strings.
///
public ISanitizer Sanitizer { get; }
///
/// Gets the chat type used by default for plugin messages.
///
public XivChatType GeneralChatType { get; private set; }
#region Configuration
///
/// Save a plugin configuration(inheriting IPluginConfiguration).
///
/// The current configuration.
public void SavePluginConfig(IPluginConfiguration currentConfig)
{
if (currentConfig == null)
return;
this.configs.Save(currentConfig, this.pluginName);
}
///
/// Get a previously saved plugin configuration or null if none was saved before.
///
/// A previously saved config or null if none was saved before.
public IPluginConfiguration GetPluginConfig()
{
// This is done to support json deserialization of plugin configurations
// even after running an in-game update of plugins, where the assembly version
// changes.
// Eventually it might make sense to have a separate method on this class
// T GetPluginConfig() where T : IPluginConfiguration
// that can invoke LoadForType() directly instead of via reflection
// This is here for now to support the current plugin API
foreach (var type in Assembly.GetCallingAssembly().GetTypes())
{
if (type.IsAssignableTo(typeof(IPluginConfiguration)))
{
var mi = this.configs.GetType().GetMethod("LoadForType");
var fn = mi.MakeGenericMethod(type);
return (IPluginConfiguration)fn.Invoke(this.configs, new object[] { this.pluginName });
}
}
// this shouldn't be a thing, I think, but just in case
return this.configs.Load(this.pluginName);
}
///
/// Get the config directory.
///
/// directory with path of AppData/XIVLauncher/pluginConfig/PluginInternalName.
public string GetPluginConfigDirectory() => this.configs.GetDirectory(this.pluginName);
///
/// Get the loc directory.
///
/// directory with path of AppData/XIVLauncher/pluginConfig/PluginInternalName/loc.
public string GetPluginLocDirectory() => this.configs.GetDirectory(Path.Combine(this.pluginName, "loc"));
#endregion
#region Chat Links
///
/// Register a chat link handler.
///
/// The ID of the command.
/// The action to be executed.
/// Returns an SeString payload for the link.
public DalamudLinkPayload AddChatLinkHandler(uint commandId, Action commandAction)
{
return Service.Get().AddChatLinkHandler(this.pluginName, commandId, commandAction);
}
///
/// Remove a chat link handler.
///
/// The ID of the command.
public void RemoveChatLinkHandler(uint commandId)
{
Service.Get().RemoveChatLinkHandler(this.pluginName, commandId);
}
///
/// Removes all chat link handlers registered by the plugin.
///
public void RemoveChatLinkHandler()
{
Service.Get().RemoveChatLinkHandler(this.pluginName);
}
#endregion
///
/// Unregister your plugin and dispose all references. You have to call this when your IDalamudPlugin is disposed.
///
public void Dispose()
{
this.UiBuilder.Dispose();
Service.Get().RemoveChatLinkHandler(this.pluginName);
Service.Get().OnLocalizationChanged -= this.OnLocalizationChanged;
Service.Get().OnDalamudConfigurationSaved -= this.OnDalamudConfigurationSaved;
}
private void OnLocalizationChanged(string langCode)
{
this.UiLanguage = langCode;
this.OnLanguageChanged?.Invoke(langCode);
}
private void OnDalamudConfigurationSaved(DalamudConfiguration dalamudConfiguration)
{
this.GeneralChatType = dalamudConfiguration.GeneralChatType;
}
}
}