/// <summary> /// 設定を読み込みます。 /// </summary> private void LoadConfig() { var found = true; try { Config = PluginConfig.LoadJson(GetConfigPath()); } catch (FileNotFoundException) { Config = null; found = false; } catch (Exception e) { Config = null; Logger.Log(LogLevel.Error, "LoadConfig: {0}", e); } if (!found) { try { Config = PluginConfig.LoadXml(PluginDirectory, GetConfigPath(true)); } catch (Exception e) { // 設定ファイルが存在しない、もしくは破損している場合は作り直す Logger.Log(LogLevel.Warning, "LoadConfig: {0}", e); Config = null; } } if (Config == null) { Logger.Log(LogLevel.Info, "LoadConfig: Creating new configuration."); Config = new PluginConfig(); Config.SetDefaultOverlayConfigs(PluginDirectory); } Registry.Register(Config); Registry.Register <IPluginConfig>(Config); foreach (var es in Registry.EventSources) { es.LoadConfig(Config); es.Start(); } }
/// <summary> /// プラグインが有効化されたときに呼び出されます。 /// </summary> /// <param name="pluginScreenSpace"></param> /// <param name="pluginStatusText"></param> public void InitPlugin(TabPage pluginScreenSpace, Label pluginStatusText) { try { this.tabPage = pluginScreenSpace; this.label = pluginStatusText; #if DEBUG Logger.Log(LogLevel.Warning, "##################################"); Logger.Log(LogLevel.Warning, " THIS IS THE DEBUG BUILD"); Logger.Log(LogLevel.Warning, "##################################"); #endif Logger.Log(LogLevel.Info, "InitPlugin: PluginDirectory = {0}", PluginDirectory); #if DEBUG Stopwatch watch = new Stopwatch(); watch.Start(); #endif // ** Init phase 1 // Only init stuff here that works without the FFXIV plugin or addons (event sources, overlays). // Everything else should be initialized in the second phase. NativeMethods.Init(); FFXIVExportVariables.Init(); EventDispatcher.Init(); Registry.Register(new KeyboardHook()); LoadConfig(); #if DEBUG Logger.Log(LogLevel.Debug, "Component init and config load took {0}s.", watch.Elapsed.TotalSeconds); watch.Reset(); #endif try { Renderer.Initialize(PluginDirectory, ActGlobals.oFormActMain.AppDataFolder.FullName, Config.ErrorReports); } catch (Exception e) { Logger.Log(LogLevel.Error, "InitPlugin: {0}", e); } #if DEBUG Logger.Log(LogLevel.Debug, "CEF init took {0}s.", watch.Elapsed.TotalSeconds); watch.Reset(); #endif // プラグイン間のメッセージ関連 OverlayApi.BroadcastMessage += (o, e) => { Task.Run(() => { foreach (var overlay in this.Overlays) { overlay.SendMessage(e.Message); } }); }; OverlayApi.SendMessage += (o, e) => { Task.Run(() => { var targetOverlay = this.Overlays.FirstOrDefault(x => x.Name == e.Target); if (targetOverlay != null) { targetOverlay.SendMessage(e.Message); } }); }; OverlayApi.OverlayMessage += (o, e) => { Task.Run(() => { var targetOverlay = this.Overlays.FirstOrDefault(x => x.Name == e.Target); if (targetOverlay != null) { targetOverlay.OverlayMessage(e.Message); } }); }; #if DEBUG watch.Reset(); #endif // コンフィグUI系初期化 this.controlPanel = new ControlPanel(this, this.Config); this.controlPanel.Dock = DockStyle.Fill; this.tabPage.Controls.Add(this.controlPanel); this.tabPage.Name = "OverlayPlugin"; this.wsConfigPanel = new WSConfigPanel(this.Config); this.wsConfigPanel.Dock = DockStyle.Fill; this.wsTabPage = new TabPage("OverlayPlugin WSServer"); this.wsTabPage.Controls.Add(wsConfigPanel); ((TabControl)this.tabPage.Parent).TabPages.Add(this.wsTabPage); Logger.Log(LogLevel.Info, "InitPlugin: Initialized."); this.label.Text = "Initialized."; if (Config.UpdateCheck) { Updater.Updater.PerformUpdateIfNecessary(PluginDirectory); } initTimer = new Timer(); initTimer.Interval = 300; initTimer.Tick += async(o, e) => { if (ActGlobals.oFormActMain == null) { // Something went really wrong. initTimer.Stop(); } else if (ActGlobals.oFormActMain.InitActDone && ActGlobals.oFormActMain.Handle != IntPtr.Zero) { try { initTimer.Stop(); // ** Init phase 2 // Initialize the parser in the second phase since it needs the FFXIV plugin. // If OverlayPlugin is placed above the FFXIV plugin, it won't be available in the first // phase but it'll be loaded by the time we enter the second phase. NetworkParser.Init(); TriggIntegration.Init(); // This timer runs on the UI thread (it has to since we create UI controls) but LoadAddons() // can block for some time. We run it on the background thread to avoid blocking the UI. // We can't run LoadAddons() in the first init phase since it checks other ACT plugins for // addons. Plugins below OverlayPlugin wouldn't have been loaded in the first init phase. // However, in the second phase all plugins have been loaded which means we can look for addons // in that list. await Task.Run(LoadAddons); ActGlobals.oFormActMain.Invoke((Action)(() => { // Now that addons have been loaded, we can finish the overlay setup. InitializeOverlays(); controlPanel.InitializeOverlayConfigTabs(); OverlayHider.Init(); OverlayZCorrector.Init(); // WSServer has to start after the LoadAddons() call because clients can connect immediately // after it's initialized and that requires the event sources to be initialized. if (Config.WSServerRunning) { WSServer.Init(); } })); } catch (Exception ex) { Logger.Log(LogLevel.Error, "InitPlugin: {0}", ex); } } }; initTimer.Start(); } catch (Exception e) { Logger.Log(LogLevel.Error, "InitPlugin: {0}", e.ToString()); MessageBox.Show(e.ToString()); throw; } }
public Logger() { this.Logs = new BindingList <LogEntry>(); Registry.Register <ILogger>(this); }
/// <summary> /// アドオンを読み込みます。 /// </summary> private void LoadAddons() { try { // <プラグイン本体があるディレクトリ>\plugins\*.dll を検索する var directory = Path.Combine(PluginDirectory, "addons"); if (!Directory.Exists(directory)) { try { Directory.CreateDirectory(directory); } catch (Exception e) { Logger.Log(LogLevel.Error, "LoadAddons: {0}", e); } } Registry.Register(BuiltinEventConfig.LoadConfig(Config)); // Make sure the event sources are ready before we load any overlays. Registry.RegisterEventSource <MiniParseEventSource>(); Registry.RegisterEventSource <EnmityEventSource>(); Registry.StartEventSources(); Registry.RegisterOverlay <MiniParseOverlay>(); Registry.RegisterOverlay <SpellTimerOverlay>(); Registry.RegisterOverlay <LabelOverlay>(); var version = typeof(PluginMain).Assembly.GetName().Version; var Addons = new List <IOverlayAddonV2>(); foreach (var plugin in ActGlobals.oFormActMain.ActPlugins) { if (plugin.pluginObj == null) { continue; } try { if (plugin.pluginObj.GetType().GetInterface(typeof(IOverlayAddonV2).FullName) != null) { try { // プラグインのインスタンスを生成し、アドオンリストに追加する var addon = (IOverlayAddonV2)plugin.pluginObj; addon.Init(); Logger.Log(LogLevel.Info, "LoadAddons: {0}: Initialized", plugin.lblPluginTitle.Text); } catch (Exception e) { Logger.Log(LogLevel.Error, "LoadAddons: {0}: {1}", plugin.lblPluginTitle.Text, e); } } } catch (Exception e) { Logger.Log(LogLevel.Error, "LoadAddons: {0}: {1}", plugin.lblPluginTitle.Text, e); } } foreach (var pluginFile in Directory.GetFiles(directory, "*.dll")) { try { Logger.Log(LogLevel.Info, "LoadAddons: {0}", pluginFile); // アセンブリが見つかったら読み込む var asm = Assembly.LoadFrom(pluginFile); var incompatible = asm.GetReferencedAssemblies().Where(a => a.FullName != null && a.FullName.StartsWith("Xilium.CefGlue")).Count() > 0; if (incompatible) { Logger.Log(LogLevel.Error, "LoadAddons: Skipped {0} because it's incompatible with this version of OverlayPlugin.", asm.FullName); continue; } // アセンブリから IOverlayAddon を実装した public クラスを列挙し... var types = asm.GetExportedTypes().Where(t => t.GetInterface(typeof(IOverlayAddonV2).FullName) != null && t.IsClass); foreach (var type in types) { try { // プラグインのインスタンスを生成し、アドオンリストに追加する var addon = (IOverlayAddonV2)asm.CreateInstance(type.FullName); addon.Init(); Logger.Log(LogLevel.Info, "LoadAddons: {0}: Initialized", type.FullName); } catch (Exception e) { Logger.Log(LogLevel.Error, "LoadAddons: {0}: {1}", type.FullName, e); } } } catch (Exception e) { Logger.Log(LogLevel.Error, "LoadAddons: {0}: {1}", pluginFile, e); } } } catch (Exception e) { Logger.Log(LogLevel.Error, "LoadAddons: {0}", e); } }
/// <summary> /// コンフィグのオーバーレイ設定を基に、オーバーレイを初期化・登録します。 /// </summary> private void InitializeOverlays() { Registry.Register(new KeyboardHook()); // オーバーレイ初期化 this.Overlays = new List <IOverlay>(); foreach (var overlayConfig in this.Config.Overlays) { var parameters = new NamedParameterOverloads(); parameters["config"] = overlayConfig; parameters["name"] = overlayConfig.Name; var overlay = (IOverlay)Registry.Container.Resolve(overlayConfig.OverlayType, parameters); if (overlay != null) { RegisterOverlay(overlay); } else { Logger.Log(LogLevel.Error, "InitPlugin: Could not find addon for {0}.", overlayConfig.Name); } } var gameActive = true; var inCutscene = false; NativeMethods.ActiveWindowChanged += (sender, hWndFg) => { if (!Config.HideOverlaysWhenNotActive || hWndFg == IntPtr.Zero) { return; } try { try { NativeMethods.GetWindowThreadProcessId(hWndFg, out uint pid); if (pid == 0) { return; } var exePath = Process.GetProcessById((int)pid).MainModule.FileName; var fileName = Path.GetFileName(exePath.ToString()); gameActive = (fileName == "ffxiv.exe" || fileName == "ffxiv_dx11.exe" || exePath.ToString() == Process.GetCurrentProcess().MainModule.FileName); } catch (System.ComponentModel.Win32Exception ex) { // Ignore access denied errors. Those usually happen if the foreground window is running with // admin permissions but we are not. if (ex.ErrorCode == -2147467259) // 0x80004005 { gameActive = false; } else { Logger.Log(LogLevel.Error, "XivWindowWatcher: {0}", ex.ToString()); } } foreach (var overlay in this.Overlays) { if (overlay.Config.IsVisible) { overlay.Visible = gameActive && !inCutscene; } } } catch (Exception ex) { Logger.Log(LogLevel.Error, "XivWindowWatcher: {0}", ex.ToString()); } }; NetworkParser.OnOnlineStatusChanged += (o, e) => { if (!Config.HideOverlayDuringCutscene || e.Target != FFXIVRepository.GetPlayerID()) { return; } inCutscene = e.Status == 15; foreach (var overlay in Overlays) { if (overlay.Config.IsVisible) { overlay.Visible = gameActive && !inCutscene; } } }; }
/// <summary> /// プラグインが有効化されたときに呼び出されます。 /// </summary> /// <param name="pluginScreenSpace"></param> /// <param name="pluginStatusText"></param> public void InitPlugin(TabPage pluginScreenSpace, Label pluginStatusText) { try { this.tabPage = pluginScreenSpace; this.label = pluginStatusText; #if DEBUG Logger.Log(LogLevel.Warning, "##################################"); Logger.Log(LogLevel.Warning, " THIS IS THE DEBUG BUILD"); Logger.Log(LogLevel.Warning, "##################################"); #endif Logger.Log(LogLevel.Info, "InitPlugin: PluginDirectory = {0}", PluginDirectory); #if DEBUG Stopwatch watch = new Stopwatch(); watch.Start(); #endif FFXIVExportVariables.Init(); NetworkParser.Init(); EventDispatcher.Init(); // LoadAddons(); LoadConfig(); #if DEBUG Logger.Log(LogLevel.Debug, "Component init and config load took {0}s.", watch.Elapsed.TotalSeconds); watch.Reset(); #endif try { Renderer.Initialize(PluginDirectory, ActGlobals.oFormActMain.AppDataFolder.FullName, Config.ErrorReports); } catch (Exception e) { Logger.Log(LogLevel.Error, "InitPlugin: {0}", e); } #if DEBUG Logger.Log(LogLevel.Debug, "CEF init took {0}s.", watch.Elapsed.TotalSeconds); watch.Reset(); #endif // プラグイン間のメッセージ関連 OverlayApi.BroadcastMessage += (o, e) => { Task.Run(() => { foreach (var overlay in this.Overlays) { overlay.SendMessage(e.Message); } }); }; OverlayApi.SendMessage += (o, e) => { Task.Run(() => { var targetOverlay = this.Overlays.FirstOrDefault(x => x.Name == e.Target); if (targetOverlay != null) { targetOverlay.SendMessage(e.Message); } }); }; OverlayApi.OverlayMessage += (o, e) => { Task.Run(() => { var targetOverlay = this.Overlays.FirstOrDefault(x => x.Name == e.Target); if (targetOverlay != null) { targetOverlay.OverlayMessage(e.Message); } }); }; #if DEBUG watch.Reset(); #endif // コンフィグUI系初期化 this.controlPanel = new ControlPanel(this, this.Config); this.controlPanel.Dock = DockStyle.Fill; this.tabPage.Controls.Add(this.controlPanel); this.tabPage.Name = "OverlayPlugin"; this.wsConfigPanel = new WSConfigPanel(this.Config); this.wsConfigPanel.Dock = DockStyle.Fill; this.wsTabPage = new TabPage("OverlayPlugin WSServer"); this.wsTabPage.Controls.Add(wsConfigPanel); ((TabControl)this.tabPage.Parent).TabPages.Add(this.wsTabPage); Logger.Log(LogLevel.Info, "InitPlugin: Initialized."); this.label.Text = "Initialized."; if (Config.UpdateCheck) { Updater.Updater.PerformUpdateIfNecessary(controlPanel, PluginDirectory); } initTimer = new Timer(); initTimer.Interval = 300; initTimer.Tick += (o, e) => { if (ActGlobals.oFormActMain.InitActDone && ActGlobals.oFormActMain.Handle != IntPtr.Zero) { initTimer.Stop(); Registry.Register(new KeyboardHook()); LoadAddons(); InitializeOverlays(); controlPanel.InitializeOverlayConfigTabs(); OverlayHider.Initialize(); if (Config.WSServerRunning) { try { WSServer.Initialize(); } catch (Exception ex) { Logger.Log(LogLevel.Error, "InitPlugin: {0}", ex); } } } }; initTimer.Start(); } catch (Exception e) { Logger.Log(LogLevel.Error, "InitPlugin: {0}", e.ToString()); MessageBox.Show(e.ToString()); throw; } }