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; } } }