### Load and Display Textures with ITextureProvider Source: https://context7.com/goatcorp/dalamud/llms.txt Demonstrates loading textures from game files, local files, and raw image data. Includes asynchronous loading and drawing textures in ImGui. Requires setup with IDalamudPluginInterface and ITextureProvider. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Services; using Dalamud.Interface.Textures; using Dalamud.Interface.Textures.TextureWraps; using ImGuiNET; public class MyPlugin : IDalamudPlugin { private readonly ITextureProvider textureProvider; private readonly IDalamudPluginInterface pluginInterface; private ISharedImmediateTexture? gameIcon; private IDalamudTextureWrap? localTexture; public MyPlugin(ITextureProvider textureProvider, IDalamudPluginInterface pluginInterface) { this.textureProvider = textureProvider; this.pluginInterface = pluginInterface; // Load game icon (lazy loading) this.gameIcon = textureProvider.GetFromGameIcon(new GameIconLookup(62001)); // Sprout icon // Load from game path var gameTexture = textureProvider.GetFromGame("ui/icon/000000/000001.tex"); // Load from local file var localPath = Path.Combine(pluginInterface.AssemblyLocation.DirectoryName!, "images", "logo.png"); var fileTexture = textureProvider.GetFromFile(localPath); // Register draw handler pluginInterface.UiBuilder.Draw += OnDraw; // Load texture asynchronously LoadTextureAsync(); } private async void LoadTextureAsync() { var imagePath = Path.Combine(this.pluginInterface.AssemblyLocation.DirectoryName!, "image.png"); if (File.Exists(imagePath)) { var bytes = await File.ReadAllBytesAsync(imagePath); this.localTexture = await this.textureProvider.CreateFromImageAsync(bytes); } } private void OnDraw() { if (ImGui.Begin("Texture Demo")) { // Draw game icon if (this.gameIcon != null && this.gameIcon.TryGetWrap(out var iconWrap, out _)) { ImGui.Image(iconWrap.ImGuiHandle, new System.Numerics.Vector2(64, 64)); ImGui.SameLine(); ImGui.Text("Game Icon"); } // Draw local texture if (this.localTexture != null) { ImGui.Image(this.localTexture.ImGuiHandle, new System.Numerics.Vector2(this.localTexture.Width, this.localTexture.Height)); } } ImGui.End(); } public void Dispose() { this.pluginInterface.UiBuilder.Draw -= OnDraw; this.localTexture?.Dispose(); } } ``` -------------------------------- ### Manage Player Targets with ITargetManager Source: https://context7.com/goatcorp/dalamud/llms.txt Use ITargetManager to get and set various targeting states like current target, focus target, mouseover target, and soft target. Requires Dalamud.Plugin and Dalamud.Plugin.Services. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Services; public class MyPlugin : IDalamudPlugin { private readonly ITargetManager targetManager; private readonly IFramework framework; private readonly IChatGui chatGui; public MyPlugin(ITargetManager targetManager, IFramework framework, IChatGui chatGui) { this.targetManager = targetManager; this.framework = framework; this.chatGui = chatGui; this.framework.Update += OnUpdate; } private void OnUpdate(IFramework framework) { // Get current target var target = this.targetManager.Target; if (target != null) { // Target exists } // Get focus target var focusTarget = this.targetManager.FocusTarget; // Get mouseover target var mouseOver = this.targetManager.MouseOverTarget; // Get soft target (controller/gamepad) var softTarget = this.targetManager.SoftTarget; } public void ClearTarget() { this.targetManager.Target = null; } public void SetFocusTarget(IGameObject obj) { this.targetManager.FocusTarget = obj; } public void Dispose() { this.framework.Update -= OnUpdate; } } ``` -------------------------------- ### Register Slash Commands with ICommandManager Source: https://context7.com/goatcorp/dalamud/llms.txt Register custom slash commands, including aliases and help messages. Commands must start with a forward slash. Ensure commands are removed on disposal. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Services; using Dalamud.Game.Command; public class MyPlugin : IDalamudPlugin { private readonly ICommandManager commandManager; private readonly IChatGui chatGui; private const string CommandName = "/myplugin"; private const string AltCommand = "/mp"; public MyPlugin(ICommandManager commandManager, IChatGui chatGui) { this.commandManager = commandManager; this.chatGui = chatGui; // Register main command var mainCommand = new CommandInfo(OnMainCommand) { HelpMessage = "Opens the main plugin window\n" + "/myplugin config - Opens configuration\n" + "/myplugin search - Searches for items", ShowInHelp = true, DisplayOrder = 1, }; this.commandManager.AddHandler(CommandName, mainCommand); // Register alias (hidden from help) var aliasCommand = new CommandInfo(OnMainCommand) { ShowInHelp = false }; this.commandManager.AddHandler(AltCommand, aliasCommand); } private void OnMainCommand(string command, string args) { var argList = args.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (argList.Length == 0) { this.chatGui.Print("Opening main window..."); return; } switch (argList[0].ToLower()) { case "config": this.chatGui.Print("Opening config..."); break; case "search" when argList.Length > 1: var searchTerm = string.Join(" ", argList.Skip(1)); this.chatGui.Print($"Searching for: {searchTerm}"); break; default: this.chatGui.PrintError($"Unknown subcommand: {argList[0]}"); break; } } public void Dispose() { this.commandManager.RemoveHandler(CommandName); this.commandManager.RemoveHandler(AltCommand); } } ``` -------------------------------- ### Subscribe to Addon Lifecycle Events Source: https://context7.com/goatcorp/dalamud/llms.txt Listen to specific UI addon lifecycle events like PostSetup or PreFinalize. You can register listeners for individual addons, multiple addons, or all addons of a specific event type. Remember to unregister listeners in the Dispose method. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Services; using Dalamud.Game.Addon.Lifecycle; using Dalamud.Game.Addon.Lifecycle.AddonArgTypes; using FFXIVClientStructs.FFXIV.Component.GUI; public unsafe class MyPlugin : IDalamudPlugin { private readonly IAddonLifecycle addonLifecycle; private readonly IChatGui chatGui; public MyPlugin(IAddonLifecycle addonLifecycle, IChatGui chatGui) { this.addonLifecycle = addonLifecycle; this.chatGui = chatGui; // Listen for specific addon events addonLifecycle.RegisterListener(AddonEvent.PostSetup, "CharacterStatus", OnCharacterStatusSetup); addonLifecycle.RegisterListener(AddonEvent.PreFinalize, "CharacterStatus", OnCharacterStatusClose); // Listen to multiple addons addonLifecycle.RegisterListener(AddonEvent.PostSetup, new[] { "Inventory", "InventoryLarge", "InventoryExpansion" }, OnInventoryOpen); // Listen to all addons of an event type addonLifecycle.RegisterListener(AddonEvent.PostOpen, OnAnyAddonOpen); } private void OnCharacterStatusSetup(AddonEvent type, AddonArgs args) { var addon = (AtkUnitBase*)args.Addon; this.chatGui.Print($"Character status opened! Addon: {addon->NameString}"); // Access addon nodes var textNode = addon->GetTextNodeById(10); if (textNode != null) { // Modify text textNode->SetText("Modified!"); } } private void OnCharacterStatusClose(AddonEvent type, AddonArgs args) { this.chatGui.Print("Character status closing!"); } private void OnInventoryOpen(AddonEvent type, AddonArgs args) { this.chatGui.Print($"Inventory addon opened: {args.AddonName}"); } private void OnAnyAddonOpen(AddonEvent type, AddonArgs args) { // Called for every addon that opens } public void Dispose() { addonLifecycle.UnregisterListener(OnCharacterStatusSetup); addonLifecycle.UnregisterListener(OnCharacterStatusClose); addonLifecycle.UnregisterListener(OnInventoryOpen); addonLifecycle.UnregisterListener(OnAnyAddonOpen); } } ``` -------------------------------- ### Create IPC Channels for Plugin Communication Source: https://context7.com/goatcorp/dalamud/llms.txt Use ICallGateProvider to expose functionality and ICallGateSubscriber to consume it from other plugins. Ensure proper unregistration in Dispose. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Ipc; public class MyPlugin : IDalamudPlugin { private readonly IDalamudPluginInterface pluginInterface; // Provider (server) side private readonly ICallGateProvider myFunctionProvider; private readonly ICallGateProvider myNotificationProvider; // Subscriber (client) side private readonly ICallGateSubscriber otherPluginFunction; public MyPlugin(IDalamudPluginInterface pluginInterface) { this.pluginInterface = pluginInterface; // Create IPC provider - expose a function to other plugins this.myFunctionProvider = pluginInterface.GetIpcProvider("MyPlugin.GetLength"); this.myFunctionProvider.RegisterFunc(GetStringLength); // Create notification channel this.myNotificationProvider = pluginInterface.GetIpcProvider("MyPlugin.OnSomethingHappened"); // Subscribe to another plugin's IPC this.otherPluginFunction = pluginInterface.GetIpcSubscriber("OtherPlugin.GetItemName"); // Subscribe to notifications from another plugin var otherPluginEvent = pluginInterface.GetIpcSubscriber("OtherPlugin.OnEvent"); otherPluginEvent.Subscribe(OnOtherPluginEvent); } private int GetStringLength(string input) { return input?.Length ?? 0; } public void NotifyOtherPlugins(string message) { this.myNotificationProvider.SendMessage(message); } public string? CallOtherPlugin(uint itemId) { try { return this.otherPluginFunction.InvokeFunc(itemId); } catch { return null; // Other plugin not available } } private void OnOtherPluginEvent(string eventData) { // Handle event from other plugin } public void Dispose() { this.myFunctionProvider.UnregisterFunc(); } } ``` -------------------------------- ### Draw Custom ImGui UI with IUiBuilder Source: https://context7.com/goatcorp/dalamud/llms.txt Implement custom UIs using ImGui by registering draw handlers with pluginInterface.UiBuilder.Draw. Requires Dalamud.Plugin, Dalamud.Plugin.Services, Dalamud.Interface, and ImGuiNET. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Services; using Dalamud.Interface; using Dalamud.Interface.Windowing; using ImGuiNET; using System.Numerics; public class MyPlugin : IDalamudPlugin { private readonly IDalamudPluginInterface pluginInterface; private readonly WindowSystem windowSystem; private readonly MainWindow mainWindow; public MyPlugin(IDalamudPluginInterface pluginInterface) { this.pluginInterface = pluginInterface; this.windowSystem = new WindowSystem("MyPlugin"); this.mainWindow = new MainWindow(); this.windowSystem.AddWindow(this.mainWindow); // Register draw event pluginInterface.UiBuilder.Draw += OnDraw; pluginInterface.UiBuilder.OpenMainUi += () => this.mainWindow.IsOpen = true; pluginInterface.UiBuilder.OpenConfigUi += () => this.mainWindow.IsOpen = true; } private void OnDraw() { this.windowSystem.Draw(); } public void Dispose() { this.pluginInterface.UiBuilder.Draw -= OnDraw; this.windowSystem.RemoveAllWindows(); } } public class MainWindow : Window { private string inputText = ""; private bool checkboxValue = false; private int sliderValue = 50; public MainWindow() : base("My Plugin Window", ImGuiWindowFlags.NoScrollbar) { this.Size = new Vector2(400, 300); this.SizeCondition = ImGuiCond.FirstUseEver; } public override void Draw() { ImGui.Text("Welcome to my plugin!"); ImGui.Separator(); // Text input ImGui.InputText("Name", ref inputText, 100); // Checkbox ImGui.Checkbox("Enable feature", ref checkboxValue); // Slider ImGui.SliderInt("Value", ref sliderValue, 0, 100); // Button if (ImGui.Button("Click me!")) { // Button clicked } ImGui.SameLine(); // Colored button ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.2f, 0.7f, 0.2f, 1.0f)); if (ImGui.Button("Green Button")) { // Green button clicked } ImGui.PopStyleColor(); // Collapsing header if (ImGui.CollapsingHeader("Advanced Settings")) { ImGui.Text("Hidden content here"); } } } ``` -------------------------------- ### Implement Basic Dalamud Plugin Interface Source: https://context7.com/goatcorp/dalamud/llms.txt Implement the IDalamudPlugin interface to create a basic Dalamud plugin. Services like ICommandManager and IChatGui are injected via the constructor. Remember to clean up handlers in the Dispose method. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Services; using Dalamud.Game.Command; public class MyPlugin : IDalamudPlugin { private readonly ICommandManager commandManager; private readonly IChatGui chatGui; public MyPlugin(ICommandManager commandManager, IChatGui chatGui) { this.commandManager = commandManager; this.chatGui = chatGui; // Register a slash command this.commandManager.AddHandler("/mycommand", new CommandInfo(OnCommand) { HelpMessage = "My plugin command", ShowInHelp = true, }); this.chatGui.Print("MyPlugin loaded!"); } private void OnCommand(string command, string args) { this.chatGui.Print($"Command executed with args: {args}"); } public void Dispose() { this.commandManager.RemoveHandler("/mycommand"); } } ``` -------------------------------- ### Interact with Game Chat using IChatGui Source: https://context7.com/goatcorp/dalamud/llms.txt Use IChatGui to print messages, subscribe to chat events, and create clickable chat links. Ensure you unsubscribe from events in Dispose. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Services; using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling.Payloads; public class MyPlugin : IDalamudPlugin { private readonly IChatGui chatGui; public MyPlugin(IChatGui chatGui) { this.chatGui = chatGui; // Subscribe to chat messages this.chatGui.ChatMessage += OnChatMessage; // Print simple messages this.chatGui.Print("Hello from my plugin!"); this.chatGui.Print("Tagged message", "MyPlugin", 45); // With colored tag this.chatGui.PrintError("Something went wrong!"); // Print formatted SeString with clickable link var linkPayload = this.chatGui.AddChatLinkHandler(1, OnLinkClicked); var message = new SeStringBuilder() .AddUiForeground(60) // Yellow color .AddText("[MyPlugin] ") .AddUiForegroundOff() .Add(linkPayload) .AddUiForeground(500) // Clickable color .AddText("Click here for more info") .AddUiForegroundOff() .Add(RawPayload.LinkTerminator) .Build(); this.chatGui.Print(new XivChatEntry { Message = message }); } private void OnChatMessage(XivChatType type, int timestamp, ref SeString sender, ref SeString message, ref bool isHandled) { // Intercept and modify messages if (message.TextValue.Contains("secret")) { message = new SeStringBuilder() .AddText("[REDACTED]") .Build(); } // Block certain messages if (type == XivChatType.Shout && message.TextValue.Contains("spam")) { isHandled = true; // Prevents message from showing } } private void OnLinkClicked(uint commandId, SeString message) { this.chatGui.Print($"Link clicked! Command ID: {commandId}"); } public void Dispose() { this.chatGui.ChatMessage -= OnChatMessage; this.chatGui.RemoveChatLinkHandler(1); } } ``` -------------------------------- ### Interact with Game UI and Convert Coordinates Source: https://context7.com/goatcorp/dalamud/llms.txt Utilize IGameGui to interact with the game's UI, convert world positions to screen coordinates, and subscribe to UI events. Remember to unsubscribe from events in Dispose. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Services; using System.Numerics; public class MyPlugin : IDalamudPlugin { private readonly IGameGui gameGui; private readonly IObjectTable objectTable; private readonly IDalamudPluginInterface pluginInterface; public MyPlugin(IGameGui gameGui, IObjectTable objectTable, IDalamudPluginInterface pluginInterface) { this.gameGui = gameGui; this.objectTable = objectTable; this.pluginInterface = pluginInterface; // Subscribe to UI hide toggle gameGui.UiHideToggled += OnUiHideToggled; // Register draw for overlay pluginInterface.UiBuilder.Draw += DrawOverlay; } private void OnUiHideToggled(object? sender, bool isHidden) { // UI visibility changed } private void DrawOverlay() { if (this.gameGui.GameUiHidden) return; // Draw markers over game objects foreach (var obj in this.objectTable) { if (obj == null) continue; // Convert world position to screen position if (this.gameGui.WorldToScreen(obj.Position, out var screenPos)) { // Draw at screenPos using ImGui var drawList = ImGuiNET.ImGui.GetBackgroundDrawList(); drawList.AddCircleFilled(screenPos, 5f, 0xFF00FF00); // Green circle drawList.AddText(screenPos + new Vector2(10, -10), 0xFFFFFFFF, obj.Name.ToString()); } } } public void Dispose() { this.gameGui.UiHideToggled -= OnUiHideToggled; this.pluginInterface.UiBuilder.Draw -= DrawOverlay; } } ``` -------------------------------- ### Access Game Client State with IClientState Source: https://context7.com/goatcorp/dalamud/llms.txt Subscribe to game client events like login, logout, and territory changes. Check the current login status, territory, and client language. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Services; public class MyPlugin : IDalamudPlugin { private readonly IClientState clientState; private readonly IChatGui chatGui; public MyPlugin(IClientState clientState, IChatGui chatGui) { this.clientState = clientState; this.chatGui = chatGui; // Subscribe to events this.clientState.Login += OnLogin; this.clientState.Logout += OnLogout; this.clientState.TerritoryChanged += OnTerritoryChanged; this.clientState.ClassJobChanged += OnClassJobChanged; // Check current state if (this.clientState.IsLoggedIn) { var territory = this.clientState.TerritoryType; var isPvP = this.clientState.IsPvP; var language = this.clientState.ClientLanguage; this.chatGui.Print($"Currently in territory {territory}, PvP: {isPvP}"); } } private void OnLogin() => this.chatGui.Print("Logged in!"); private void OnLogout(int type, int code) => this.chatGui.Print("Logged out!"); private void OnTerritoryChanged(ushort territoryId) => this.chatGui.Print($"Zone: {territoryId}"); private void OnClassJobChanged(uint classJobId) => this.chatGui.Print($"Job changed: {classJobId}"); public void Dispose() { this.clientState.Login -= OnLogin; this.clientState.Logout -= OnLogout; this.clientState.TerritoryChanged -= OnTerritoryChanged; this.clientState.ClassJobChanged -= OnClassJobChanged; } } ``` -------------------------------- ### Access Plugin Interface Services and Configuration Source: https://context7.com/goatcorp/dalamud/llms.txt Utilize IDalamudPluginInterface to manage plugin configuration, access plugin metadata, and hook into UI events. Ensure proper cleanup of UI event subscriptions in the Dispose method. ```csharp using Dalamud.Plugin; using Dalamud.Configuration; public class MyConfig : IPluginConfiguration { public int Version { get; set; } = 1; public bool EnableFeature { get; set; } = true; public string CustomMessage { get; set; } = "Hello!"; } public class MyPlugin : IDalamudPlugin { private readonly IDalamudPluginInterface pluginInterface; private MyConfig config; public MyPlugin(IDalamudPluginInterface pluginInterface) { this.pluginInterface = pluginInterface; // Load configuration this.config = pluginInterface.GetPluginConfig() as MyConfig ?? new MyConfig(); // Access plugin information var pluginName = pluginInterface.InternalName; var configDir = pluginInterface.GetPluginConfigDirectory(); var assemblyPath = pluginInterface.AssemblyLocation.FullName; // Register UI events pluginInterface.UiBuilder.Draw += OnDraw; pluginInterface.UiBuilder.OpenConfigUi += OnOpenConfigUi; } private void OnDraw() { /* ImGui drawing code */ } private void OnOpenConfigUi() { /* Open settings window */ } public void SaveConfig() { this.pluginInterface.SavePluginConfig(this.config); } public void Dispose() { this.pluginInterface.UiBuilder.Draw -= OnDraw; this.pluginInterface.UiBuilder.OpenConfigUi -= OnOpenConfigUi; } } ``` -------------------------------- ### Access Game Data with IDataManager Source: https://context7.com/goatcorp/dalamud/llms.txt Use IDataManager to access game data, including Excel sheets and raw files. Ensure Lumina library is available for Excel sheet access. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Services; using Lumina.Excel.Sheets; public class MyPlugin : IDalamudPlugin { private readonly IDataManager dataManager; private readonly IChatGui chatGui; public MyPlugin(IDataManager dataManager, IChatGui chatGui) { this.dataManager = dataManager; this.chatGui = chatGui; // Get an Excel sheet var itemSheet = dataManager.GetExcelSheet(); // Look up a specific item by row ID var potion = itemSheet.GetRow(4554); // Potion if (potion != null) { this.chatGui.Print($"Item: {potion.Name}, IL: {potion.LevelItem.RowId}"); } // Search for items foreach (var item in itemSheet) { if (item.Name.ToString().Contains("Ironworks") && item.LevelItem.RowId >= 130) { this.chatGui.Print($"Found: {item.Name} (IL{item.LevelItem.RowId})"); } } // Access other sheets var territorySheet = dataManager.GetExcelSheet(); var actionSheet = dataManager.GetExcelSheet(); var classJobSheet = dataManager.GetExcelSheet(); // Load a game file directly var texFile = dataManager.GetFile("ui/icon/000000/000001.tex"); if (texFile != null) { this.chatGui.Print($"Texture loaded: {texFile.Header.Width}x{texFile.Header.Height}"); } // Check if file exists if (dataManager.FileExists("exd/item.exh")) { this.chatGui.Print("Item sheet exists!"); } } public void Dispose() { } } ``` -------------------------------- ### Subscribe to Framework Update Event Source: https://context7.com/goatcorp/dalamud/llms.txt Subscribe to the IFramework.Update event to execute code on every game frame. Ensure to unsubscribe in Dispose. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Services; public class MyPlugin : IDalamudPlugin { private readonly IFramework framework; private readonly IChatGui chatGui; private int updateCount = 0; public MyPlugin(IFramework framework, IChatGui chatGui) { this.framework = framework; this.chatGui = chatGui; // Subscribe to the update event (runs every frame) this.framework.Update += OnFrameworkUpdate; // Run code on the framework thread (thread-safe) this.framework.RunOnFrameworkThread(() => { // This code runs on the main game thread this.chatGui.Print("Running on framework thread!"); }); // Run with a delay _ = this.framework.RunOnTick(() => { this.chatGui.Print("Delayed execution after 5 seconds"); }, delay: TimeSpan.FromSeconds(5)); // Run after specific number of ticks _ = this.framework.RunOnTick(() => { this.chatGui.Print("Executed after 60 ticks"); }, delayTicks: 60); } private void OnFrameworkUpdate(IFramework framework) { this.updateCount++; // Do something every 600 frames (~10 seconds at 60fps) if (this.updateCount % 600 == 0) { var delta = framework.UpdateDelta; this.chatGui.Print($"10 seconds passed, delta: {delta.TotalMilliseconds}ms"); } } public async Task DoAsyncWork() { // Async method that needs framework thread access await this.framework.Run(async () => { // First part on framework thread this.chatGui.Print("Starting async work..."); // Can safely await here and continue on framework thread await Task.Delay(1000); this.chatGui.Print("Async work complete!"); }); } public void Dispose() { this.framework.Update -= OnFrameworkUpdate; } } ``` -------------------------------- ### Display Toast Notifications with INotificationManager Source: https://context7.com/goatcorp/dalamud/llms.txt Shows how to add various types of toast notifications (success, error, info) to the user interface. Supports setting titles, content, types, durations, and progress. Notifications can be updated after creation. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Services; using Dalamud.Interface.ImGuiNotification; public class MyPlugin : IDalamudPlugin { private readonly INotificationManager notificationManager; public MyPlugin(INotificationManager notificationManager) { this.notificationManager = notificationManager; // Simple notification notificationManager.AddNotification(new Notification { Title = "Plugin Loaded", Content = "My plugin has been loaded successfully!", Type = NotificationType.Success, InitialDuration = TimeSpan.FromSeconds(5), }); // Error notification notificationManager.AddNotification(new Notification { Title = "Error", Content = "Something went wrong!", Type = NotificationType.Error, MinimizedText = "Error occurred", }); // Progress notification var progressNotification = notificationManager.AddNotification(new Notification { Title = "Processing", Content = "Working on it...", Type = NotificationType.Info, Progress = 0.5f, ShowIndeterminateIfNoExpiry = false, }); // Update progress later progressNotification.Progress = 0.75f; progressNotification.Content = "Almost done..."; } public void Dispose() { } } ``` -------------------------------- ### Access Local Player and Game Objects Source: https://context7.com/goatcorp/dalamud/llms.txt Retrieve the local player object and iterate through all spawned game objects. Filter objects by type and proximity to the local player. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Services; using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Enums; using System.Numerics; public class MyPlugin : IDalamudPlugin { private readonly IObjectTable objectTable; private readonly IChatGui chatGui; public MyPlugin(IObjectTable objectTable, IChatGui chatGui) { this.objectTable = objectTable; this.chatGui = chatGui; // Get local player var localPlayer = objectTable.LocalPlayer; if (localPlayer != null) { this.chatGui.Print($"Player: {localPlayer.Name}, HP: {localPlayer.CurrentHp}/{localPlayer.MaxHp}"); this.chatGui.Print($"Position: {localPlayer.Position}"); } // Iterate all objects foreach (var obj in objectTable) { if (obj == null) continue; // Filter by object kind if (obj.ObjectKind == ObjectKind.BattleNpc) { var npc = obj as IBattleNpc; if (npc != null && npc.BattleNpcKind == BattleNpcSubKind.Enemy) { var distance = Vector3.Distance(localPlayer!.Position, npc.Position); if (distance < 30) { this.chatGui.Print($"Enemy nearby: {npc.Name} at {distance:F1}y"); } } } } // Search by ID var targetObj = objectTable.SearchByEntityId(0x12345678); // Get object at specific index var objAtIndex = objectTable[0]; // Index 0 is usually the local player // Iterate only player characters foreach (var player in objectTable.PlayerObjects) { this.chatGui.Print($"Player in zone: {player.Name}"); } } public void Dispose() { } } ``` -------------------------------- ### Hook Game Function by Signature Source: https://context7.com/goatcorp/dalamud/llms.txt Intercept game function calls by providing a signature. Ensure the delegate matches the function signature. Hooks must be enabled after creation and disposed when no longer needed. ```csharp using Dalamud.Plugin; using Dalamud.Plugin.Services; using Dalamud.Hooking; using System.Runtime.InteropServices; public class MyPlugin : IDalamudPlugin { private readonly IGameInteropProvider gameInterop; private readonly IChatGui chatGui; // Delegate matching the function signature private delegate void ProcessChatDelegate(nint uiModule, nint message, nint unk1, nint unk2); private readonly Hook? processChatHook; public MyPlugin(IGameInteropProvider gameInterop, ISigScanner sigScanner, IChatGui chatGui) { this.gameInterop = gameInterop; this.chatGui = chatGui; // Method 1: Hook from signature var processChatSig = "48 89 5C 24 ?? 57 48 83 EC 20 48 8B FA 48 8B D9 45 84 C9"; this.processChatHook = gameInterop.HookFromSignature( processChatSig, ProcessChatDetour ); this.processChatHook.Enable(); // Method 2: Hook from address // var address = sigScanner.ScanText("48 89 5C 24 ..."); // var hook = gameInterop.HookFromAddress(address, Detour); // Method 3: Initialize hooks from attributes // gameInterop.InitializeFromAttributes(this); } private void ProcessChatDetour(nint uiModule, nint message, nint unk1, nint unk2) { // Read the message var text = Marshal.PtrToStringUTF8(message); this.chatGui.Print($"[Hook] Processing: {text}"); // Call original function this.processChatHook!.Original(uiModule, message, unk1, unk2); } public void Dispose() { this.processChatHook?.Dispose(); } } ```