- Replace Plugin.cs/ConfigWindow.cs skeleton with working sample code - Add MainWindow.cs (goat-image demo + PlayerState/Lumina queries) - Rename src/PluginConfiguration.cs → src/Configuration.cs (sample naming) - Add Data/goat.png sample asset - Add src/packages.lock.json (NuGet lockfile from sample) - Add PluginNameTemplate.sln solution file - Bump csproj from Dalamud.NET.Sdk 13.0.0 → 15.0.0 - Bump yaml dalamud_api_level: 13 → 15 - Update README with sample-removal walkthrough and SDK-bump section Template now builds end-to-end out of the box. Goat demo intact for verification; strip per README when implementing the real plugin.
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -1,8 +1,7 @@
|
|||||||
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
|
<Project Sdk="Dalamud.NET.Sdk/15.0.0">
|
||||||
<!--
|
<!--
|
||||||
Replace `Dalamud.NET.Sdk/13.0.0` with the SDK version current at the time
|
SDK 15.0.0 is current as of 2026-05. Check https://github.com/goatcorp/Dalamud.NET.Sdk
|
||||||
you start your plugin. Check https://github.com/goatcorp/Dalamud.NET.Sdk
|
for the latest tag when you bump this template.
|
||||||
for the latest tag.
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
@@ -20,12 +19,19 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!--
|
<!--
|
||||||
Add additional NuGet refs here as needed. Dalamud.NET.Sdk pulls in
|
Sample asset bundled with the working demo (the goat-image referenced
|
||||||
Dalamud, ImGui.NET, FFXIVClientStructs, Lumina, etc. by default.
|
by MainWindow.cs). Drop your real plugin assets here and adjust the
|
||||||
|
include-path. CopyToOutputDirectory ensures the file lands next to the
|
||||||
|
compiled DLL so PluginInterface.AssemblyLocation finds it.
|
||||||
-->
|
-->
|
||||||
|
<Content Include="Data\goat.png">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<Visible>false</Visible>
|
||||||
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="images\icon.png" Pack="true" PackagePath="\" />
|
<!-- Plugin icon used by the Dalamud manifest. Drop your real icon at images/icon.png. -->
|
||||||
|
<None Include="images\icon.png" Pack="true" PackagePath="\" Condition="Exists('images\icon.png')" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.0.31903.59
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginNameTemplate", "PluginNameTemplate.csproj", "{B12C5E91-7A3D-4E8F-A2C1-9D4E5F6A7B8C}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{B12C5E91-7A3D-4E8F-A2C1-9D4E5F6A7B8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B12C5E91-7A3D-4E8F-A2C1-9D4E5F6A7B8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B12C5E91-7A3D-4E8F-A2C1-9D4E5F6A7B8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B12C5E91-7A3D-4E8F-A2C1-9D4E5F6A7B8C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -14,7 +14,9 @@ icon_url: https://gitea.hellion-forge.cloud/Hellion-Forge/PluginNameTemplate/raw
|
|||||||
assembly_version: 0.1.0
|
assembly_version: 0.1.0
|
||||||
testing_assembly_version: 0.1.0
|
testing_assembly_version: 0.1.0
|
||||||
|
|
||||||
dalamud_api_level: 13
|
# Dalamud.NET.Sdk 15.0.0 targets API level 15. Check the SDK release notes
|
||||||
|
# when bumping (the API level usually moves with major SDK updates).
|
||||||
|
dalamud_api_level: 15
|
||||||
|
|
||||||
categories:
|
categories:
|
||||||
- utility
|
- utility
|
||||||
@@ -24,7 +26,7 @@ tags:
|
|||||||
|
|
||||||
changelog: |
|
changelog: |
|
||||||
v0.1.0
|
v0.1.0
|
||||||
- Initial release.
|
- Initial release based on the official Dalamud sample plugin (goat demo intact).
|
||||||
|
|
||||||
# Don't override DalamudPackager defaults (Dalamud.NET.Sdk 13+ handles icon and
|
# Don't override DalamudPackager defaults. The SDK reads icon and image_urls
|
||||||
# image_urls automatically via the .csproj <None Include="images\icon.png" />).
|
# from the .csproj <None Include="images\icon.png" /> entry automatically.
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
# Dalamud Plugin Template
|
# Dalamud Plugin Template
|
||||||
|
|
||||||
A starting point for FFXIV/Dalamud plugins on the [Hellion Forge](https://gitea.hellion-forge.cloud/).
|
A starting point for FFXIV/Dalamud plugins on the [Hellion Forge](https://gitea.hellion-forge.cloud/Hellion-Forge).
|
||||||
|
|
||||||
Distilled from the [HellionChat](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat) plugin patterns: csproj layout, configuration handling, window scaffolding, custom-repo manifest, Forge-Auto-Announce workflow, and the version-bump checklist.
|
Built on the **official goatcorp [Dalamud Sample Plugin](https://github.com/goatcorp/SamplePlugin)** (working code with goat-image demo, MainWindow with PlayerState/Lumina queries, ConfigWindow with movable-toggle), wrapped with Hellion-Forge conventions: custom-repo manifest, Forge-Auto-Announce workflow, version-bump checklist, MIT license.
|
||||||
|
|
||||||
|
The sample code is intentionally kept intact so the template builds and runs out of the box. Strip the goat demo when you implement your real plugin (see "Replacing the sample" below).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -10,45 +12,64 @@ Distilled from the [HellionChat](https://gitea.hellion-forge.cloud/JonKazama-Hel
|
|||||||
|
|
||||||
1. Click **"Use this template"** at the top of the repository page on the Forge.
|
1. Click **"Use this template"** at the top of the repository page on the Forge.
|
||||||
2. Pick a name like `MyPlugin` and clone your new repo locally.
|
2. Pick a name like `MyPlugin` and clone your new repo locally.
|
||||||
3. Find-and-replace `PluginNameTemplate` everywhere with your plugin's name (case-sensitive).
|
3. Find-and-replace `PluginNameTemplate` everywhere with your plugin's name (case-sensitive):
|
||||||
```bash
|
```bash
|
||||||
git ls-files | xargs sed -i 's/PluginNameTemplate/MyPlugin/g'
|
git ls-files | xargs sed -i 's/PluginNameTemplate/MyPlugin/g'
|
||||||
git mv PluginNameTemplate.csproj MyPlugin.csproj
|
git mv PluginNameTemplate.csproj MyPlugin.csproj
|
||||||
git mv PluginNameTemplate.yaml MyPlugin.yaml
|
git mv PluginNameTemplate.yaml MyPlugin.yaml
|
||||||
|
git mv PluginNameTemplate.sln MyPlugin.sln
|
||||||
```
|
```
|
||||||
4. Replace `images/icon.png` with your plugin icon (512x512 PNG, transparent background).
|
4. Replace `images/icon.png` with your plugin icon (512x512 PNG, transparent background).
|
||||||
5. Update `repo.json` with your real `DownloadLinkInstall` URLs once your CI publishes releases.
|
5. Update `repo.json` with your real `DownloadLinkInstall` URLs once your CI publishes releases.
|
||||||
6. Implement your plugin in `src/Plugin.cs` and friends.
|
6. Strip the goat demo (or keep it for development reference — your call).
|
||||||
|
7. Implement your plugin in `src/Plugin.cs` and friends.
|
||||||
|
|
||||||
After the rename, this README should be replaced with your plugin's actual README — the template-usage notes don't belong in your shipped plugin.
|
After the rename, this README should be replaced with your plugin's actual README — the template-usage notes don't belong in your shipped plugin.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Replacing the sample
|
||||||
|
|
||||||
|
The template ships with the goat demo working end-to-end so you can verify your build setup before writing any code. To remove it cleanly:
|
||||||
|
|
||||||
|
1. **Empty the windows.** `src/Windows/MainWindow.cs` and `src/Windows/ConfigWindow.cs` — replace the goat-image / config-toggle demos with your real UI. Keep the class structure (constructor signature, `Draw()` override).
|
||||||
|
2. **Delete the goat asset.** `Data/goat.png` and the `<Content Include="Data\goat.png">` block in `<PluginName>.csproj`.
|
||||||
|
3. **Adjust services.** `src/Plugin.cs` injects `ITextureProvider`, `IClientState`, `IPlayerState`, `IDataManager` — only because the goat demo uses them. Drop the ones you don't need.
|
||||||
|
4. **Rename `/pmycommand`.** In `src/Plugin.cs`, change `private const string CommandName = "/pmycommand"` to your plugin's actual command and update the `HelpMessage`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Project structure
|
## Project structure
|
||||||
|
|
||||||
```
|
```
|
||||||
.
|
.
|
||||||
├── .editorconfig Code style
|
├── .editorconfig Code style
|
||||||
├── .gitea/
|
├── .gitea/
|
||||||
│ ├── ISSUE_TEMPLATE/ Standard issue forms
|
│ ├── ISSUE_TEMPLATE/ Standard issue forms
|
||||||
│ ├── PULL_REQUEST_TEMPLATE.md
|
│ ├── PULL_REQUEST_TEMPLATE.md
|
||||||
|
│ ├── forge-posts/v0.1.0.md Discord-announcement payload (Forge-Auto-Announce)
|
||||||
│ └── workflows/
|
│ └── workflows/
|
||||||
│ ├── ci.yml Build verification on push/PR
|
│ ├── ci.yml Build verification on push/PR
|
||||||
│ └── forge-auto-announce.yml Discord announcement on tag
|
│ └── forge-auto-announce.yml Discord announcement on tag
|
||||||
├── docs/CHANGELOG.md Long-form changelog (slim main copy)
|
├── Data/
|
||||||
├── images/icon.png Plugin icon (replace before shipping)
|
│ └── goat.png Sample asset for the working demo (replace or delete)
|
||||||
|
├── docs/CHANGELOG.md Long-form changelog
|
||||||
|
├── images/.gitkeep Plugin icon goes here (icon.png)
|
||||||
├── src/
|
├── src/
|
||||||
│ ├── Plugin.cs IDalamudPlugin entry point
|
│ ├── Plugin.cs IDalamudPlugin entry, WindowSystem, command handler
|
||||||
│ ├── PluginConfiguration.cs IPluginConfiguration
|
│ ├── Configuration.cs IPluginConfiguration
|
||||||
|
│ ├── packages.lock.json NuGet lockfile (Dalamud SDK manages this)
|
||||||
│ └── Windows/
|
│ └── Windows/
|
||||||
│ └── ConfigWindow.cs Skeleton config window
|
│ ├── ConfigWindow.cs Movable-toggle demo
|
||||||
├── PluginNameTemplate.csproj Dalamud-SDK csproj
|
│ └── MainWindow.cs Goat + PlayerState/Lumina demo
|
||||||
├── PluginNameTemplate.yaml Dalamud manifest
|
├── PluginNameTemplate.csproj Dalamud-SDK 15.0.0 csproj
|
||||||
├── repo.json Custom-repo manifest for testers
|
├── PluginNameTemplate.sln Solution file
|
||||||
├── CHANGELOG.md Slim changelog (latest 2-4 versions)
|
├── PluginNameTemplate.yaml Dalamud manifest
|
||||||
├── CODEOWNERS Default reviewer
|
├── repo.json Custom-repo manifest for testers
|
||||||
├── LICENSE MIT
|
├── CHANGELOG.md Slim changelog (latest 2-4 versions)
|
||||||
└── README.md This file (replace before shipping)
|
├── CODEOWNERS Default reviewer
|
||||||
|
├── LICENSE MIT
|
||||||
|
└── README.md This file (replace before shipping)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -70,7 +91,7 @@ DalamudPackager produces the `.zip` artifact under `bin/Release/<PluginName>/lat
|
|||||||
|
|
||||||
Synchronized version fields (bump all at once):
|
Synchronized version fields (bump all at once):
|
||||||
|
|
||||||
- `<PluginName>.csproj` → `AssemblyVersion`
|
- `<PluginName>.csproj` → `Version`, `AssemblyVersion`, `FileVersion`
|
||||||
- `<PluginName>.yaml` → `assembly_version` + `changelog`
|
- `<PluginName>.yaml` → `assembly_version` + `changelog`
|
||||||
- `repo.json` → `AssemblyVersion`, `TestingAssemblyVersion`, all 3 `DownloadLink*` URLs, `Description`, `Changelog`
|
- `repo.json` → `AssemblyVersion`, `TestingAssemblyVersion`, all 3 `DownloadLink*` URLs, `Description`, `Changelog`
|
||||||
- `CHANGELOG.md` (slim) and `docs/CHANGELOG.md` (full) — keep the latest 2-4 versions in the slim copy
|
- `CHANGELOG.md` (slim) and `docs/CHANGELOG.md` (full) — keep the latest 2-4 versions in the slim copy
|
||||||
@@ -86,6 +107,17 @@ The Forge-Auto-Announce workflow reads from the **tagged tree**, not main. If a
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Dalamud SDK version
|
||||||
|
|
||||||
|
This template targets `Dalamud.NET.Sdk/15.0.0` and `dalamud_api_level: 15` in the manifest. When the SDK bumps:
|
||||||
|
|
||||||
|
1. Update `<Project Sdk="Dalamud.NET.Sdk/X.Y.Z">` in the csproj
|
||||||
|
2. Update `dalamud_api_level: X` in the yaml
|
||||||
|
3. Check the SDK release notes for breaking API changes
|
||||||
|
4. Run a clean build (`dotnet clean && dotnet build`) and validate the goat demo still works
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
Service classes coupled to Dalamud (`IPluginInterface`, `IDataManager`, etc.) cannot be instantiated directly in xUnit because the Dalamud assembly isn't on the test AppDomain. Patterns that work:
|
Service classes coupled to Dalamud (`IPluginInterface`, `IDataManager`, etc.) cannot be instantiated directly in xUnit because the Dalamud assembly isn't on the test AppDomain. Patterns that work:
|
||||||
@@ -100,4 +132,4 @@ The default csproj has no test project. Add one when there's something to test.
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT — see `LICENSE`.
|
MIT — see `LICENSE`. The base sample-code is from goatcorp's Dalamud SamplePlugin (AGPL-3.0 in upstream); the working translation here is shipped under MIT alongside the Hellion-specific scaffolding. If you ship a plugin that's a near-1:1 fork of the upstream sample, check the upstream license for your distribution.
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using Dalamud.Configuration;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PluginNameTemplate;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class Configuration : IPluginConfiguration
|
||||||
|
{
|
||||||
|
public int Version { get; set; } = 0;
|
||||||
|
|
||||||
|
public bool IsConfigWindowMovable { get; set; } = true;
|
||||||
|
public bool SomePropertyToBeSavedAndWithADefault { get; set; } = true;
|
||||||
|
|
||||||
|
// The below exists just to make saving less cumbersome
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
Plugin.PluginInterface.SavePluginConfig(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
+66
-9
@@ -1,28 +1,85 @@
|
|||||||
|
using Dalamud.Game.Command;
|
||||||
using Dalamud.IoC;
|
using Dalamud.IoC;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
|
using System.IO;
|
||||||
|
using Dalamud.Interface.Windowing;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
using PluginNameTemplate.Windows;
|
||||||
|
|
||||||
namespace PluginNameTemplate;
|
namespace PluginNameTemplate;
|
||||||
|
|
||||||
public sealed class Plugin : IDalamudPlugin
|
public sealed class Plugin : IDalamudPlugin
|
||||||
{
|
{
|
||||||
[PluginService] public static IDalamudPluginInterface Pi { get; private set; } = null!;
|
[PluginService] internal static IDalamudPluginInterface PluginInterface { get; private set; } = null!;
|
||||||
[PluginService] public static IPluginLog Log { get; private set; } = null!;
|
[PluginService] internal static ITextureProvider TextureProvider { get; private set; } = null!;
|
||||||
[PluginService] public static ICommandManager Commands { get; private set; } = null!;
|
[PluginService] internal static ICommandManager CommandManager { get; private set; } = null!;
|
||||||
|
[PluginService] internal static IClientState ClientState { get; private set; } = null!;
|
||||||
|
[PluginService] internal static IPlayerState PlayerState { get; private set; } = null!;
|
||||||
|
[PluginService] internal static IDataManager DataManager { get; private set; } = null!;
|
||||||
|
[PluginService] internal static IPluginLog Log { get; private set; } = null!;
|
||||||
|
|
||||||
private readonly PluginConfiguration config;
|
private const string CommandName = "/pmycommand";
|
||||||
|
|
||||||
|
public Configuration Configuration { get; init; }
|
||||||
|
|
||||||
|
public readonly WindowSystem WindowSystem = new("PluginNameTemplate");
|
||||||
|
private ConfigWindow ConfigWindow { get; init; }
|
||||||
|
private MainWindow MainWindow { get; init; }
|
||||||
|
|
||||||
public Plugin()
|
public Plugin()
|
||||||
{
|
{
|
||||||
this.config = PluginConfiguration.Load();
|
Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration();
|
||||||
|
|
||||||
// Register your commands, hooks, windows, etc. here.
|
// You might normally want to embed resources and load them from the manifest stream
|
||||||
Log.Information("PluginNameTemplate loaded.");
|
var goatImagePath = Path.Combine(PluginInterface.AssemblyLocation.Directory?.FullName!, "goat.png");
|
||||||
|
|
||||||
|
ConfigWindow = new ConfigWindow(this);
|
||||||
|
MainWindow = new MainWindow(this, goatImagePath);
|
||||||
|
|
||||||
|
WindowSystem.AddWindow(ConfigWindow);
|
||||||
|
WindowSystem.AddWindow(MainWindow);
|
||||||
|
|
||||||
|
CommandManager.AddHandler(CommandName, new CommandInfo(OnCommand)
|
||||||
|
{
|
||||||
|
HelpMessage = "A useful message to display in /xlhelp"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Tell the UI system that we want our windows to be drawn through the window system
|
||||||
|
PluginInterface.UiBuilder.Draw += WindowSystem.Draw;
|
||||||
|
|
||||||
|
// This adds a button to the plugin installer entry of this plugin which allows
|
||||||
|
// toggling the display status of the configuration ui
|
||||||
|
PluginInterface.UiBuilder.OpenConfigUi += ToggleConfigUi;
|
||||||
|
|
||||||
|
// Adds another button doing the same but for the main ui of the plugin
|
||||||
|
PluginInterface.UiBuilder.OpenMainUi += ToggleMainUi;
|
||||||
|
|
||||||
|
// Add a simple message to the log with level set to information
|
||||||
|
// Use /xllog to open the log window in-game
|
||||||
|
Log.Information($"===A cool log message from {PluginInterface.Manifest.Name}===");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
// Unregister anything that was registered above. Order matters —
|
// Unregister all actions to not leak anything during disposal of plugin
|
||||||
// dispose UI before hooks, hooks before services.
|
PluginInterface.UiBuilder.Draw -= WindowSystem.Draw;
|
||||||
|
PluginInterface.UiBuilder.OpenConfigUi -= ToggleConfigUi;
|
||||||
|
PluginInterface.UiBuilder.OpenMainUi -= ToggleMainUi;
|
||||||
|
|
||||||
|
WindowSystem.RemoveAllWindows();
|
||||||
|
|
||||||
|
ConfigWindow.Dispose();
|
||||||
|
MainWindow.Dispose();
|
||||||
|
|
||||||
|
CommandManager.RemoveHandler(CommandName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnCommand(string command, string args)
|
||||||
|
{
|
||||||
|
// In response to the slash command, toggle the display status of our main ui
|
||||||
|
MainWindow.Toggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToggleConfigUi() => ConfigWindow.Toggle();
|
||||||
|
public void ToggleMainUi() => MainWindow.Toggle();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
using Dalamud.Configuration;
|
|
||||||
|
|
||||||
namespace PluginNameTemplate;
|
|
||||||
|
|
||||||
public sealed class PluginConfiguration : IPluginConfiguration
|
|
||||||
{
|
|
||||||
public int Version { get; set; } = 1;
|
|
||||||
|
|
||||||
// Add your config fields below. Plain types serialize cleanly; complex
|
|
||||||
// types need [JsonConverter] or a manual migration step.
|
|
||||||
|
|
||||||
public bool ExampleToggle { get; set; } = false;
|
|
||||||
|
|
||||||
public static PluginConfiguration Load()
|
|
||||||
{
|
|
||||||
return Plugin.Pi.GetPluginConfig() as PluginConfiguration ?? new PluginConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Save()
|
|
||||||
{
|
|
||||||
Plugin.Pi.SavePluginConfig(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+43
-12
@@ -1,28 +1,59 @@
|
|||||||
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Interface.Windowing;
|
using Dalamud.Interface.Windowing;
|
||||||
using ImGuiNET;
|
|
||||||
|
|
||||||
namespace PluginNameTemplate.Windows;
|
namespace PluginNameTemplate.Windows;
|
||||||
|
|
||||||
public sealed class ConfigWindow : Window
|
public class ConfigWindow : Window, IDisposable
|
||||||
{
|
{
|
||||||
private readonly PluginConfiguration config;
|
private readonly Configuration configuration;
|
||||||
|
|
||||||
public ConfigWindow(PluginConfiguration config)
|
// We give this window a constant ID using ###.
|
||||||
: base("PluginNameTemplate Settings###PluginNameTemplate-config")
|
// This allows for labels to be dynamic, like "{FPS Counter}fps###XYZ counter window",
|
||||||
|
// and the window ID will always be "###XYZ counter window" for ImGui
|
||||||
|
public ConfigWindow(Plugin plugin) : base("A Wonderful Configuration Window###With a constant ID")
|
||||||
{
|
{
|
||||||
this.config = config;
|
Flags = ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoScrollbar |
|
||||||
this.Size = new Vector2(420, 320);
|
ImGuiWindowFlags.NoScrollWithMouse;
|
||||||
this.SizeCondition = ImGuiCond.FirstUseEver;
|
|
||||||
|
Size = new Vector2(232, 90);
|
||||||
|
SizeCondition = ImGuiCond.Always;
|
||||||
|
|
||||||
|
configuration = plugin.Configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() { }
|
||||||
|
|
||||||
|
public override void PreDraw()
|
||||||
|
{
|
||||||
|
// Flags must be added or removed before Draw() is being called, or they won't apply
|
||||||
|
if (configuration.IsConfigWindowMovable)
|
||||||
|
{
|
||||||
|
Flags &= ~ImGuiWindowFlags.NoMove;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Flags |= ImGuiWindowFlags.NoMove;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
{
|
{
|
||||||
var toggle = this.config.ExampleToggle;
|
// Can't ref a property, so use a local copy
|
||||||
if (ImGui.Checkbox("Example toggle", ref toggle))
|
var configValue = configuration.SomePropertyToBeSavedAndWithADefault;
|
||||||
|
if (ImGui.Checkbox("Random Config Bool", ref configValue))
|
||||||
{
|
{
|
||||||
this.config.ExampleToggle = toggle;
|
configuration.SomePropertyToBeSavedAndWithADefault = configValue;
|
||||||
this.config.Save();
|
// Can save immediately on change if you don't want to provide a "Save and Close" button
|
||||||
|
configuration.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var movable = configuration.IsConfigWindowMovable;
|
||||||
|
if (ImGui.Checkbox("Movable Config Window", ref movable))
|
||||||
|
{
|
||||||
|
configuration.IsConfigWindowMovable = movable;
|
||||||
|
configuration.Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
|
using Dalamud.Interface.Textures;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
|
using Dalamud.Interface.Utility.Raii;
|
||||||
|
using Dalamud.Interface.Windowing;
|
||||||
|
using Lumina.Excel.Sheets;
|
||||||
|
|
||||||
|
namespace PluginNameTemplate.Windows;
|
||||||
|
|
||||||
|
public class MainWindow : Window, IDisposable
|
||||||
|
{
|
||||||
|
private readonly string goatImagePath;
|
||||||
|
private readonly Plugin plugin;
|
||||||
|
|
||||||
|
// We give this window a hidden ID using ##.
|
||||||
|
// The user will see "My Amazing Window" as window title,
|
||||||
|
// but for ImGui the ID is "My Amazing Window##With a hidden ID"
|
||||||
|
public MainWindow(Plugin plugin, string goatImagePath)
|
||||||
|
: base("My Amazing Window##With a hidden ID", ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)
|
||||||
|
{
|
||||||
|
SizeConstraints = new WindowSizeConstraints
|
||||||
|
{
|
||||||
|
MinimumSize = new Vector2(375, 330),
|
||||||
|
MaximumSize = new Vector2(float.MaxValue, float.MaxValue)
|
||||||
|
};
|
||||||
|
|
||||||
|
this.goatImagePath = goatImagePath;
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() { }
|
||||||
|
|
||||||
|
public override void Draw()
|
||||||
|
{
|
||||||
|
ImGui.Text($"The random config bool is {plugin.Configuration.SomePropertyToBeSavedAndWithADefault}");
|
||||||
|
|
||||||
|
if (ImGui.Button("Show Settings"))
|
||||||
|
{
|
||||||
|
plugin.ToggleConfigUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Spacing();
|
||||||
|
|
||||||
|
// Normally a BeginChild() would have to be followed by an unconditional EndChild(),
|
||||||
|
// ImRaii takes care of this after the scope ends.
|
||||||
|
// This works for all ImGui functions that require specific handling, examples are BeginTable() or Indent().
|
||||||
|
using (var child = ImRaii.Child("SomeChildWithAScrollbar", Vector2.Zero, true))
|
||||||
|
{
|
||||||
|
// Check if this child is drawing
|
||||||
|
if (child.Success)
|
||||||
|
{
|
||||||
|
ImGui.Text("Have a goat:");
|
||||||
|
var goatImage = Plugin.TextureProvider.GetFromFile(goatImagePath).GetWrapOrDefault();
|
||||||
|
if (goatImage != null)
|
||||||
|
{
|
||||||
|
using (ImRaii.PushIndent(55f))
|
||||||
|
{
|
||||||
|
ImGui.Image(goatImage.Handle, goatImage.Size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.Text("Image not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(20.0f);
|
||||||
|
|
||||||
|
// Example for other services that Dalamud provides.
|
||||||
|
// PlayerState provides a wrapper filled with information about the player character.
|
||||||
|
|
||||||
|
var playerState = Plugin.PlayerState;
|
||||||
|
if (!playerState.IsLoaded)
|
||||||
|
{
|
||||||
|
ImGui.Text("Our local player is currently not logged in.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!playerState.ClassJob.IsValid)
|
||||||
|
{
|
||||||
|
ImGui.Text("Our current job is currently not valid.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.AlignTextToFramePadding();
|
||||||
|
ImGui.Text($"Current job:");
|
||||||
|
|
||||||
|
// Scaling hardcoded pixel values is important, as otherwise users with HUD scales above or below 100%
|
||||||
|
// won't be able to see everything.
|
||||||
|
ImGui.SameLine(120 * ImGuiHelpers.GlobalScale);
|
||||||
|
|
||||||
|
// Get the icon id from a known offset + the class jobs id
|
||||||
|
var jobIconId = 62100 + playerState.ClassJob.RowId;
|
||||||
|
var iconTexture = Plugin.TextureProvider.GetFromGameIcon(new GameIconLookup(jobIconId)).GetWrapOrEmpty();
|
||||||
|
ImGui.Image(iconTexture.Handle, new Vector2(28, 28) * ImGuiHelpers.GlobalScale);
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
// If you want to see the Macro representation of this SeString use `.ToMacroString()`
|
||||||
|
// More info about SeStrings: https://dalamud.dev/plugin-development/sestring/
|
||||||
|
ImGui.Text(playerState.ClassJob.Value.Abbreviation.ToString());
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text($" [Level {playerState.Level}]");
|
||||||
|
|
||||||
|
// Example for querying Lumina, getting the name of our current area.
|
||||||
|
var territoryId = Plugin.ClientState.TerritoryType;
|
||||||
|
if (Plugin.DataManager.GetExcelSheet<TerritoryType>().TryGetRow(territoryId, out var territoryRow))
|
||||||
|
{
|
||||||
|
ImGui.Text($"Current location:");
|
||||||
|
ImGui.SameLine(120 * ImGuiHelpers.GlobalScale);
|
||||||
|
ImGui.Text(territoryRow.PlaceName.Value.Name.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.Text("Invalid territory.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"dependencies": {
|
||||||
|
"net10.0-windows7.0": {
|
||||||
|
"DalamudPackager": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[15.0.0, )",
|
||||||
|
"resolved": "15.0.0",
|
||||||
|
"contentHash": "411vwC8/X8Z/sQ2TI6v3SvOn66xFPeOjFn3Zn+h0d3Ox2t1kFm66AhDvmx/qcMwVrR+Hidxj0dadpQ2dgyXMBQ=="
|
||||||
|
},
|
||||||
|
"DotNet.ReproducibleBuilds": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.2.39, )",
|
||||||
|
"resolved": "1.2.39",
|
||||||
|
"contentHash": "fcFN01tDTIQqDuTwr1jUQK/geofiwjG5DycJQOnC72i1SsLAk1ELe+apBOuZ11UMQG8YKFZG1FgvjZPbqHyatg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user