/** * We use reflection to calculate the field offsets since there's no public Machina DLL we could link * against. I want to avoid copying the relevant structures so reflection is the last option left. * * IMPORTANT: Remove the parsing code, once the parser parses the network packet and provides * an event or log line for it. */ public static void Init() { try { var mach = Assembly.Load("Machina.FFXIV"); MessageType = mach.GetType("Machina.FFXIV.Headers.Server_MessageType"); var ActorControl142 = mach.GetType("Machina.FFXIV.Headers.Server_ActorControl142"); ActorControl142_Size = Marshal.SizeOf(ActorControl142); var headerOffset = GetOffset(ActorControl142, "MessageHeader"); var msgHeader = ActorControl142.GetField("MessageHeader").FieldType; MessageType_Offset = headerOffset + GetOffset(msgHeader, "MessageType"); ActorID_Offset = headerOffset + GetOffset(msgHeader, "ActorID"); Category_Offset = GetOffset(ActorControl142, "category"); Param1_Offset = GetOffset(ActorControl142, "param1"); ActorControl142_Opcode = GetOpcode("ActorControl142"); #if DEBUG Registry.Resolve <ILogger>().Log(LogLevel.Debug, $"ActorControl142 = {ActorControl142_Opcode.ToString("x")}"); #endif FFXIVRepository.RegisterNetworkParser(Parse); } catch (Exception e) { Registry.Resolve <ILogger>().Log(LogLevel.Error, Resources.NetworkParserInitException, e); } }
public OverlayHider(TinyIoCContainer container) { this.config = container.Resolve <IPluginConfig>(); this.logger = container.Resolve <ILogger>(); this.main = container.Resolve <PluginMain>(); this.repository = container.Resolve <FFXIVRepository>(); container.Resolve <NativeMethods>().ActiveWindowChanged += ActiveWindowChangedHandler; container.Resolve <NetworkParser>().OnOnlineStatusChanged += OnlineStatusChanged; container.Resolve <EventSources.EnmityEventSource>().CombatStatusChanged += CombatStatusChanged; try { repository.RegisterProcessChangedHandler(UpdateFFXIVProcess); } catch (Exception ex) { logger.Log(LogLevel.Error, "Failed to register process watcher for FFXIV; this is only an issue if you're playing FFXIV. As a consequence, OverlayPlugin won't be able to hide overlays if you're not in-game."); logger.Log(LogLevel.Error, "Details: " + ex.ToString()); } focusTimer = new Timer(); focusTimer.Tick += (o, e) => ActiveWindowChangedHandler(this, IntPtr.Zero); focusTimer.Interval = 10000; // 10 seconds focusTimer.Start(); }
/** * We use reflection to calculate the field offsets since there's no public Machina DLL we could link * against. I want to avoid copying the relevant structures so reflection is the last option left. * * IMPORTANT: Remove the parsing code, once the parser parses the network packet and provides * an event or log line for it. */ public static void Init() { try { var mach = Assembly.Load("Machina.FFXIV"); var ActorControl142 = mach.GetType("Machina.FFXIV.Headers.Server_ActorControl142"); ActorControl142_Size = Marshal.SizeOf(ActorControl142); var headerOffset = GetOffset(ActorControl142, "MessageHeader"); var msgHeader = ActorControl142.GetField("MessageHeader").FieldType; MessageType_Offset = headerOffset + GetOffset(msgHeader, "MessageType"); ActorID_Offset = headerOffset + GetOffset(msgHeader, "ActorID"); Category_Offset = GetOffset(ActorControl142, "category"); Param1_Offset = GetOffset(ActorControl142, "param1"); ActorControl142_Type = (ushort)GetEnumValue(msgHeader.GetField("MessageType").FieldType, "ActorControl142"); FFXIVRepository.RegisterNetworkParser(Parse); } catch (Exception e) { Registry.Resolve <ILogger>().Log(LogLevel.Error, Resources.NetworkParserInitException, e); } }
public OverlayZCorrector(TinyIoCContainer container) { main = container.Resolve <PluginMain>(); logger = container.Resolve <ILogger>(); repository = container.Resolve <FFXIVRepository>(); var span = TimeSpan.FromSeconds(3); timer = new Timer(EnsureOverlaysAreOverGame, null, span, span); }
static void OnlineStatusChanged(object sender, OnlineStatusChangedArgs e) { if (!config.HideOverlayDuringCutscene || e.Target != FFXIVRepository.GetPlayerID()) { return; } inCutscene = e.Status == 15; UpdateOverlays(); }
public OverlayHider(TinyIoCContainer container) { this.config = container.Resolve <IPluginConfig>(); this.logger = container.Resolve <ILogger>(); this.main = container.Resolve <PluginMain>(); this.repository = container.Resolve <FFXIVRepository>(); container.Resolve <NativeMethods>().ActiveWindowChanged += ActiveWindowChangedHandler; container.Resolve <NetworkParser>().OnOnlineStatusChanged += OnlineStatusChanged; }
public OverlayHider(TinyIoCContainer container) { this.config = container.Resolve <IPluginConfig>(); this.logger = container.Resolve <ILogger>(); this.main = container.Resolve <PluginMain>(); this.repository = container.Resolve <FFXIVRepository>(); container.Resolve <NativeMethods>().ActiveWindowChanged += ActiveWindowChangedHandler; container.Resolve <NetworkParser>().OnOnlineStatusChanged += OnlineStatusChanged; repository.RegisterProcessChangedHandler(UpdateFFXIVProcess); focusTimer = new Timer(); focusTimer.Tick += (o, e) => ActiveWindowChangedHandler(this, IntPtr.Zero); focusTimer.Interval = 10000; // 10 seconds focusTimer.Start(); }
protected override void OnOpen() { base.OnOpen(); EventDispatcher.Subscribe("CombatData", this); EventDispatcher.Subscribe("LogLine", this); EventDispatcher.Subscribe("ChangeZone", this); EventDispatcher.Subscribe("ChangePrimaryPlayer", this); Send(JsonConvert.SerializeObject(new { type = "broadcast", msgtype = "SendCharName", msg = new { charName = FFXIVRepository.GetPlayerName() ?? "YOU", charID = FFXIVRepository.GetPlayerID() } })); }
private static void EnsureOverlaysAreOverGame(object _) { var watch = new Stopwatch(); watch.Start(); var xivProc = FFXIVRepository.GetCurrentFFXIVProcess(); if (xivProc == null || xivProc.HasExited) { return; } var xivHandle = xivProc.MainWindowHandle; var overlayWindows = new List <IntPtr>(); var handle = xivHandle; while (handle != IntPtr.Zero) { handle = NativeMethods.GetWindow(handle, NativeMethods.GW_HWNDPREV); overlayWindows.Add(handle); } foreach (var overlay in main.Overlays) { if (!overlayWindows.Contains(overlay.Handle)) { // The overlay is behind the game. Let's fix that. NativeMethods.SetWindowPos( overlay.Handle, NativeMethods.HWND_TOPMOST, 0, 0, 0, 0, NativeMethods.SWP_NOSIZE | NativeMethods.SWP_NOMOVE | NativeMethods.SWP_NOACTIVATE); logger.Log(LogLevel.Info, $"ZReorder: Fixed {overlay.Name}."); } } // logger.Log(LogLevel.Debug, $"ZReorder: Took {watch.Elapsed.TotalSeconds}s."); }
public LegacyHandler(TinyIoCContainer container, IWebSocketConnection conn, WSServer server) : base() { _logger = container.Resolve <ILogger>(); _dispatcher = container.Resolve <EventDispatcher>(); _repository = container.Resolve <FFXIVRepository>(); _conn = conn; conn.OnOpen = OnOpen; conn.OnMessage = OnMessage; conn.OnClose = () => { try { _dispatcher.UnsubscribeAll(this); server._connections.Remove(this); } catch (Exception ex) { _logger.Log(LogLevel.Error, $"Failed to unsubscribe WebSocket connection: {ex}"); } }; }
public LegacyHandler(TinyIoCContainer container, IWebSocketConnection conn, WSServer server) : base() { _logger = container.Resolve <ILogger>(); _dispatcher = container.Resolve <EventDispatcher>(); _repository = container.Resolve <FFXIVRepository>(); _conn = conn; var open = true; conn.OnOpen = OnOpen; conn.OnMessage = OnMessage; conn.OnClose = () => { if (!open) { return; } open = false; try { _dispatcher.UnsubscribeAll(this); server._connections.Remove(this); } catch (Exception ex) { _logger.Log(LogLevel.Error, $"Failed to unsubscribe WebSocket connection: {ex}"); } }; conn.OnError = (ex) => { // Fleck will close the connection; make sure we always clean up even if Fleck doesn't call OnClose(). conn.OnClose(); _logger.Log(LogLevel.Info, $"WebSocket connection was closed with error: {ex}"); }; }
/// <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; } } }; }
public LegacyHandler(TinyIoCContainer container) : base() { _logger = container.Resolve <ILogger>(); _dispatcher = container.Resolve <EventDispatcher>(); _repository = container.Resolve <FFXIVRepository>(); }