From 72f85fd952c8e53230c968ef9a433644dae90254 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Tue, 27 Aug 2024 22:21:18 -0700 Subject: Initial Version 1.0.0.0 --- Malmstone.sln | 25 +++++ Malmstone/Configuration.cs | 19 ++++ Malmstone/Dalamud.Plugin.Bootstrap.targets | 11 +++ Malmstone/Malmstone.csproj | 12 +++ Malmstone/Malmstone.json | 13 +++ Malmstone/Plugin.cs | 63 ++++++++++++ Malmstone/Services/PVPService.cs | 32 ++++++ Malmstone/Utils/MalmstoneXPCalculator.cs | 107 ++++++++++++++++++++ Malmstone/Windows/ConfigWindow.cs | 44 +++++++++ Malmstone/Windows/MainWindow.cs | 136 ++++++++++++++++++++++++++ Malmstone/packages.lock.json | 13 +++ README.md | 78 +-------------- SamplePlugin.sln | 29 ------ SamplePlugin/Configuration.cs | 20 ---- SamplePlugin/Dalamud.Plugin.Bootstrap.targets | 11 --- SamplePlugin/Plugin.cs | 73 -------------- SamplePlugin/SamplePlugin.csproj | 19 ---- SamplePlugin/SamplePlugin.json | 12 --- SamplePlugin/Windows/ConfigWindow.cs | 59 ----------- SamplePlugin/Windows/MainWindow.cs | 58 ----------- SamplePlugin/packages.lock.json | 13 --- 21 files changed, 478 insertions(+), 369 deletions(-) create mode 100644 Malmstone.sln create mode 100644 Malmstone/Configuration.cs create mode 100644 Malmstone/Dalamud.Plugin.Bootstrap.targets create mode 100644 Malmstone/Malmstone.csproj create mode 100644 Malmstone/Malmstone.json create mode 100644 Malmstone/Plugin.cs create mode 100644 Malmstone/Services/PVPService.cs create mode 100644 Malmstone/Utils/MalmstoneXPCalculator.cs create mode 100644 Malmstone/Windows/ConfigWindow.cs create mode 100644 Malmstone/Windows/MainWindow.cs create mode 100644 Malmstone/packages.lock.json delete mode 100644 SamplePlugin.sln delete mode 100644 SamplePlugin/Configuration.cs delete mode 100644 SamplePlugin/Dalamud.Plugin.Bootstrap.targets delete mode 100644 SamplePlugin/Plugin.cs delete mode 100644 SamplePlugin/SamplePlugin.csproj delete mode 100644 SamplePlugin/SamplePlugin.json delete mode 100644 SamplePlugin/Windows/ConfigWindow.cs delete mode 100644 SamplePlugin/Windows/MainWindow.cs delete mode 100644 SamplePlugin/packages.lock.json diff --git a/Malmstone.sln b/Malmstone.sln new file mode 100644 index 0000000..abbe892 --- /dev/null +++ b/Malmstone.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35219.272 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Malmstone", "Malmstone\Malmstone.csproj", "{13C812E9-0D42-4B95-8646-40EEBF30636F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.ActiveCfg = Debug|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.Build.0 = Debug|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.ActiveCfg = Release|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B17E85B1-5F60-4440-9F9A-3DDE877E8CDF} + EndGlobalSection +EndGlobal diff --git a/Malmstone/Configuration.cs b/Malmstone/Configuration.cs new file mode 100644 index 0000000..e0d5a3c --- /dev/null +++ b/Malmstone/Configuration.cs @@ -0,0 +1,19 @@ +using Dalamud.Configuration; +using Dalamud.Plugin; +using System; + +namespace Malmstone; + +[Serializable] +public class Configuration : IPluginConfiguration +{ + public int Version { get; set; } = 0; + + public int DefaultTargetRankProperty { get; set; } = 1; + + // the below exist just to make saving less cumbersome + public void Save() + { + Plugin.PluginInterface.SavePluginConfig(this); + } +} diff --git a/Malmstone/Dalamud.Plugin.Bootstrap.targets b/Malmstone/Dalamud.Plugin.Bootstrap.targets new file mode 100644 index 0000000..11eec9c --- /dev/null +++ b/Malmstone/Dalamud.Plugin.Bootstrap.targets @@ -0,0 +1,11 @@ + + + + $(appdata)\XIVLauncher\addon\Hooks\dev\ + $(HOME)/.xlcore/dalamud/Hooks/dev/ + $(HOME)/Library/Application Support/XIV on Mac/dalamud/Hooks/dev/ + $(DALAMUD_HOME)/ + + + + diff --git a/Malmstone/Malmstone.csproj b/Malmstone/Malmstone.csproj new file mode 100644 index 0000000..dbc432f --- /dev/null +++ b/Malmstone/Malmstone.csproj @@ -0,0 +1,12 @@ + + + + + + 1.0.0.0 + A PVP Series Malmstones Experience Calculator + https://github.com/goatcorp/Malmstone + AGPL-3.0-or-later + false + + diff --git a/Malmstone/Malmstone.json b/Malmstone/Malmstone.json new file mode 100644 index 0000000..d93fcd7 --- /dev/null +++ b/Malmstone/Malmstone.json @@ -0,0 +1,13 @@ +{ + "Author": "pinapelz", + "Name": "Malmstone Calculator", + "Punchline": "A PVP Series Malmstones Experience Calculator", + "Description": "Calculate how much more PVP you have to play before reaching a certain rank in the current PVP Series", + "ApplicableVersion": "any", + "Tags": [ + "pvp", + "malmstone", + "series", + "calculator" + ] +} diff --git a/Malmstone/Plugin.cs b/Malmstone/Plugin.cs new file mode 100644 index 0000000..0455792 --- /dev/null +++ b/Malmstone/Plugin.cs @@ -0,0 +1,63 @@ +using Dalamud.Game.Command; +using Dalamud.IoC; +using Dalamud.Plugin; +using Dalamud.Interface.Windowing; +using Dalamud.Plugin.Services; +using Malmstone.Windows; + +namespace Malmstone; + +public sealed class Plugin : IDalamudPlugin +{ + [PluginService] internal static IDalamudPluginInterface PluginInterface { get; private set; } = null!; + [PluginService] internal static ITextureProvider TextureProvider { get; private set; } = null!; + [PluginService] internal static ICommandManager CommandManager { get; private set; } = null!; + + private const string CommandName = "/pmalm"; + + public Configuration Configuration { get; init; } + + public readonly WindowSystem WindowSystem = new("Malmstone"); + private ConfigWindow ConfigWindow { get; init; } + private MainWindow MainWindow { get; init; } + + public Plugin() + { + Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration(); + + ConfigWindow = new ConfigWindow(this); + MainWindow = new MainWindow(this); + + WindowSystem.AddWindow(ConfigWindow); + WindowSystem.AddWindow(MainWindow); + + CommandManager.AddHandler(CommandName, new CommandInfo(OnCommand) + { + HelpMessage = "Open the Malmstone calculator main window" + }); + + PluginInterface.UiBuilder.Draw += DrawUI; + PluginInterface.UiBuilder.OpenConfigUi += ToggleConfigUI; + PluginInterface.UiBuilder.OpenMainUi += ToggleMainUI; + } + + public void Dispose() + { + WindowSystem.RemoveAllWindows(); + + ConfigWindow.Dispose(); + MainWindow.Dispose(); + + CommandManager.RemoveHandler(CommandName); + } + + private void OnCommand(string command, string args) + { + ToggleMainUI(); + } + + private void DrawUI() => WindowSystem.Draw(); + + public void ToggleConfigUI() => ConfigWindow.Toggle(); + public void ToggleMainUI() => MainWindow.Toggle(); +} diff --git a/Malmstone/Services/PVPService.cs b/Malmstone/Services/PVPService.cs new file mode 100644 index 0000000..cf08fea --- /dev/null +++ b/Malmstone/Services/PVPService.cs @@ -0,0 +1,32 @@ +using FFXIVClientStructs.FFXIV.Client.Game.UI; + +namespace Malmstone.Services +{ + public class PvPService + { + public PvPSeriesInfo? GetPvPSeriesInfo() + { + unsafe + { + var pvpProfile = PvPProfile.Instance(); + if (pvpProfile != null && pvpProfile->IsLoaded != 0) + { + return new PvPSeriesInfo + { + CurrentSeriesRank = pvpProfile->GetSeriesCurrentRank(), + ClaimedSeriesRank = pvpProfile->GetSeriesClaimedRank(), + SeriesExperience = pvpProfile->GetSeriesExperience() + }; + } + return null; + } + } + } + + public class PvPSeriesInfo + { + public byte CurrentSeriesRank { get; set; } + public byte ClaimedSeriesRank { get; set; } + public ushort SeriesExperience { get; set; } + } +} diff --git a/Malmstone/Utils/MalmstoneXPCalculator.cs b/Malmstone/Utils/MalmstoneXPCalculator.cs new file mode 100644 index 0000000..4834def --- /dev/null +++ b/Malmstone/Utils/MalmstoneXPCalculator.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; + +namespace Malmstone.Utils +{ + public static class MalmstoneXPCalculator + { + private static readonly int[] PvpLevels = { + 0, 2000, 2000, 2000, 2000, 3000, 3000, 3000, 3000, 3000, 4000, 4000, 4000, 4000, 4000, 5500, 5500, 5500, 5500, 5500, + 7500, 7500, 7500, 7500, 7500, 10000, 10000, 10000, 10000, 10000, 20000, 20000 + }; + + private const int InfinityLevelExp = 20000; + private const int FrontlineWinExp = 1500; + private const int FrontlineLose2Exp = 1250; + private const int FrontlineLoseExp = 1000; + private const int FrontlineDailyWinExp = 3000; + private const int FrontlineDailyLose2Exp = 2750; + private const int FrontlineDailyLoseExp = 2500; + private const int CrystallineWinExp = 900; + private const int CrystallineLoseExp = 700; + private const int RivalWingsWinExp = 1250; + private const int RivalWingsLoseExp = 750; + + public class XpCalculationResult + { + public int RemainingXp { get; set; } + public int TargetLevel { get; set; } + public Dictionary ActivityCounts { get; set; } = new(); + } + + public static XpCalculationResult CalculateXp(int currentLevel, int goalLevel, int currentProgress) + { + if (currentLevel < 1 || goalLevel < 1) + { + throw new ArgumentOutOfRangeException(nameof(currentLevel), "Levels must be greater than 0."); + } + + int remainingXp = 0; + + if (currentLevel <= PvpLevels.Length && goalLevel <= PvpLevels.Length) + { + remainingXp = CalculateRemainingXp(currentLevel, goalLevel, currentProgress); + } + else + { + remainingXp = CalculateRemainingXpBeyondChart(currentLevel, goalLevel, currentProgress); + } + + if (remainingXp <= 0) + { + return new XpCalculationResult { RemainingXp = 0, TargetLevel = goalLevel }; + } + + var result = new XpCalculationResult + { + RemainingXp = remainingXp, + TargetLevel = goalLevel, + }; + + result.ActivityCounts["Crystalline Conflict Win"] = CalculateActivityCount(remainingXp, CrystallineWinExp); + result.ActivityCounts["Crystalline Conflict Lose"] = CalculateActivityCount(remainingXp, CrystallineLoseExp); + result.ActivityCounts["Frontline Win"] = CalculateActivityCount(remainingXp, FrontlineWinExp); + result.ActivityCounts["Frontline Lose 2nd"] = CalculateActivityCount(remainingXp, FrontlineLose2Exp); + result.ActivityCounts["Frontline Lose 3rd"] = CalculateActivityCount(remainingXp, FrontlineLoseExp); + result.ActivityCounts["Frontline Daily Win"] = CalculateActivityCount(remainingXp, FrontlineDailyWinExp); + result.ActivityCounts["Frontline Daily Lose 2nd"] = CalculateActivityCount(remainingXp, FrontlineDailyLose2Exp); + result.ActivityCounts["Frontline Daily Lose 3rd"] = CalculateActivityCount(remainingXp, FrontlineDailyLoseExp); + result.ActivityCounts["Rival Wings Win"] = CalculateActivityCount(remainingXp, RivalWingsWinExp); + result.ActivityCounts["Rival Wings Lose"] = CalculateActivityCount(remainingXp, RivalWingsLoseExp); + + return result; + } + + private static int CalculateRemainingXp(int currentLevel, int goalLevel, int currentProgress) + { + int remainingXp = 0; + + for (int level = currentLevel; level < goalLevel; level++) + { + remainingXp += PvpLevels[level]; + } + + return remainingXp - currentProgress; + } + + private static int CalculateRemainingXpBeyondChart(int currentLevel, int goalLevel, int currentProgress) + { + int remainingXp = 0; + + if (currentLevel <= PvpLevels.Length) + { + remainingXp = CalculateRemainingXp(currentLevel, PvpLevels.Length, currentProgress); + currentLevel = PvpLevels.Length; + } + + remainingXp += (goalLevel - currentLevel) * InfinityLevelExp; + + return remainingXp; + } + + private static int CalculateActivityCount(int remainingXp, int activityXp) + { + return (int)Math.Ceiling((double)remainingXp / activityXp); + } + } +} diff --git a/Malmstone/Windows/ConfigWindow.cs b/Malmstone/Windows/ConfigWindow.cs new file mode 100644 index 0000000..8fbe9ba --- /dev/null +++ b/Malmstone/Windows/ConfigWindow.cs @@ -0,0 +1,44 @@ +using System; +using System.Numerics; +using Dalamud.Interface.Windowing; +using ImGuiNET; + +namespace Malmstone.Windows; + +public class ConfigWindow : Window, IDisposable +{ + private Configuration Configuration; + + public ConfigWindow(Plugin plugin) : base("Malmstone Config") + { + Flags = ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoScrollbar | + ImGuiWindowFlags.NoScrollWithMouse; + + Size = new Vector2(232, 150); + Configuration = plugin.Configuration; + } + + public void Dispose() { } + + public override void PreDraw() + { + } + + public override void Draw() + { + ImGui.Text("Default Series Rank"); + var savedTargetSeriesRank = Configuration.DefaultTargetRankProperty; + if (ImGui.InputInt("##SavedTargetSeriesRank", ref savedTargetSeriesRank, 1)) + { + Configuration.DefaultTargetRankProperty = savedTargetSeriesRank; + } + + ImGui.Spacing(); + + if (ImGui.Button("Save and Close")) + { + Configuration.Save(); + IsOpen = false; + } + } +} diff --git a/Malmstone/Windows/MainWindow.cs b/Malmstone/Windows/MainWindow.cs new file mode 100644 index 0000000..917dd64 --- /dev/null +++ b/Malmstone/Windows/MainWindow.cs @@ -0,0 +1,136 @@ +using System; +using System.Numerics; +using Dalamud.Interface.Windowing; +using ImGuiNET; +using Malmstone.Services; +using Malmstone.Utils; + +namespace Malmstone.Windows +{ + public class MainWindow : Window, IDisposable + { + private Plugin Plugin; + private PvPService PvPService; + private int TargetSeriesRank; + + public MainWindow(Plugin plugin) + : base("Malmstone", ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse) + { + SizeConstraints = new WindowSizeConstraints + { + MinimumSize = new Vector2(375, 310), + MaximumSize = new Vector2(float.MaxValue, float.MaxValue) + }; + + Plugin = plugin; + PvPService = new PvPService(); + TargetSeriesRank = Plugin.Configuration.DefaultTargetRankProperty; + } + + public void Dispose() { } + + public override void Draw() + { + var pvpInfo = PvPService.GetPvPSeriesInfo(); + if (pvpInfo != null) + { + ImGui.Text($"Current Series Rank: {pvpInfo.CurrentSeriesRank}"); + ImGui.Text($"Current Rank Series Experience: {pvpInfo.SeriesExperience}"); + if (pvpInfo.CurrentSeriesRank != pvpInfo.ClaimedSeriesRank) + { + ImGui.Text("Don't forget to claim your rank rewards!"); + + } + ImGui.Spacing(); + + ImGui.Text("Target Rank:"); + ImGui.InputInt("##TargetSeriesRank", ref TargetSeriesRank, 1); + } + else + { + ImGui.Text("PvP Profile is not loaded."); + } + + if (TargetSeriesRank < 1) TargetSeriesRank = 1; + + ImGui.Spacing(); + ImGui.Separator(); + + if (pvpInfo != null) + { + var xpResult = MalmstoneXPCalculator.CalculateXp(pvpInfo.CurrentSeriesRank, TargetSeriesRank, pvpInfo.SeriesExperience); + + ImGui.Spacing(); + ImGui.Text($"You have {xpResult.RemainingXp} remaining series EXP to go until you reach rank {xpResult.TargetLevel}"); + + ImGui.Spacing(); + ImGui.Separator(); + + // Crystalline Conflict Section + ImGui.TextColored(new Vector4(0.6f, 0.8f, 1f, 1f), "Crystalline Conflict"); + ImGui.Spacing(); + if (xpResult.ActivityCounts.ContainsKey("Crystalline Conflict Win")) + { + ImGui.BulletText($"Win: {xpResult.ActivityCounts["Crystalline Conflict Win"]} times"); + } + if (xpResult.ActivityCounts.ContainsKey("Crystalline Conflict Lose")) + { + ImGui.BulletText($"Lose: {xpResult.ActivityCounts["Crystalline Conflict Lose"]} times"); + } + + ImGui.Spacing(); + ImGui.Separator(); + + // Frontlines Section + ImGui.TextColored(new Vector4(0.8f, 0.6f, 0.6f, 1f), "Frontlines"); + ImGui.Spacing(); + if (xpResult.ActivityCounts.ContainsKey("Frontline Win")) + { + ImGui.BulletText($"Take 1st Place: {xpResult.ActivityCounts["Frontline Win"]} times"); + } + if (xpResult.ActivityCounts.ContainsKey("Frontline Lose 2nd")) + { + ImGui.BulletText($"Take 2nd Place: {xpResult.ActivityCounts["Frontline Lose 2nd"]} times"); + } + if (xpResult.ActivityCounts.ContainsKey("Frontline Lose 3rd")) + { + ImGui.BulletText($"Take 3rd Place: {xpResult.ActivityCounts["Frontline Lose 3rd"]} times"); + } + + // Frontlines Section + ImGui.TextColored(new Vector4(0.8f, 0.6f, 0.6f, 1f), "Frontlines (Roulette)"); + ImGui.Spacing(); + if (xpResult.ActivityCounts.ContainsKey("Frontline Daily Win")) + { + ImGui.BulletText($"Take 1st Place: {xpResult.ActivityCounts["Frontline Daily Win"]} times"); + } + if (xpResult.ActivityCounts.ContainsKey("Frontline Daily Lose 2nd")) + { + ImGui.BulletText($"Take 2nd Place: {xpResult.ActivityCounts["Frontline Daily Lose 2nd"]} times"); + } + if (xpResult.ActivityCounts.ContainsKey("Frontline Daily Lose 3rd")) + { + ImGui.BulletText($"Take 3rd Place: {xpResult.ActivityCounts["Frontline Daily Lose 3rd"]} times"); + } + + ImGui.Spacing(); + ImGui.Separator(); + + // Rival Wings Section + ImGui.TextColored(new Vector4(0.6f, 0.8f, 0.6f, 1f), "Rival Wings"); + ImGui.Spacing(); + if (xpResult.ActivityCounts.ContainsKey("Rival Wings Win")) + { + ImGui.BulletText($"Win: {xpResult.ActivityCounts["Rival Wings Win"]} times"); + } + if (xpResult.ActivityCounts.ContainsKey("Rival Wings Lose")) + { + ImGui.BulletText($"Lose: {xpResult.ActivityCounts["Rival Wings Lose"]} times"); + } + + ImGui.Spacing(); + ImGui.Separator(); + } + } + } +} diff --git a/Malmstone/packages.lock.json b/Malmstone/packages.lock.json new file mode 100644 index 0000000..19fcea9 --- /dev/null +++ b/Malmstone/packages.lock.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "dependencies": { + "net8.0-windows7.0": { + "DalamudPackager": { + "type": "Direct", + "requested": "[2.1.13, )", + "resolved": "2.1.13", + "contentHash": "rMN1omGe8536f4xLMvx9NwfvpAc9YFFfeXJ1t4P4PE6Gu8WCIoFliR1sh07hM+bfODmesk/dvMbji7vNI+B/pQ==" + } + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 8419402..c5729a9 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,4 @@ -> ⚠️ **Don't click Fork!** -> -> This is a GitHub Template repo. If you want to use this for a plugin, just [use this template][new-repo] to make a new repo! -> -> ![image](https://github.com/goatcorp/SamplePlugin/assets/16760685/d9732094-e1ed-4769-a70b-58ed2b92580c) +# Malmstone Calculator +A Dalamud plugin that calculates how much more PVP you have to play to reach your target Malmstone Series Rank. -# SamplePlugin - -[![Use This Template badge](https://img.shields.io/badge/Use%20This%20Template-0?logo=github&labelColor=grey)][new-repo] - - -Simple example plugin for Dalamud. - -This is not designed to be the simplest possible example, but it is also not designed to cover everything you might want to do. For more detailed questions, come ask in [the Discord](https://discord.gg/holdshift). - -## Main Points - -* Simple functional plugin - * Slash command - * Main UI - * Settings UI - * Image loading - * Plugin json -* Simple, slightly-improved plugin configuration handling -* Project organization - * Copies all necessary plugin files to the output directory - * Does not copy dependencies that are provided by dalamud - * Output directory can be zipped directly and have exactly what is required - * Hides data files from visual studio to reduce clutter - * Also allows having data files in different paths than VS would usually allow if done in the IDE directly - - -The intention is less that any of this is used directly in other projects, and more to show how similar things can be done. - -## How To Use - -### Getting Started - -To begin, [clone this template repository][new-repo] to your own GitHub account. This will automatically bring in everything you need to get a jumpstart on development. You do not need to fork this repository unless you intend to contribute modifications to it. - -Be sure to also check out the [Dalamud Developer Docs][dalamud-docs] for helpful information about building your own plugin. The Developer Docs includes helpful information about all sorts of things, including [how to submit][submit] your newly-created plugin to the official repository. Assuming you use this template repository, the provided project build configuration and license are already chosen to make everything a breeze. - -[new-repo]: https://github.com/new?template_name=SamplePlugin&template_owner=goatcorp -[dalamud-docs]: https://dalamud.dev -[submit]: https://dalamud.dev/plugin-development/plugin-submission - -### Prerequisites - -SamplePlugin assumes all the following prerequisites are met: - -* XIVLauncher, FINAL FANTASY XIV, and Dalamud have all been installed and the game has been run with Dalamud at least once. -* XIVLauncher is installed to its default directories and configurations. - * If a custom path is required for Dalamud's dev directory, it must be set with the `DALAMUD_HOME` environment variable. -* A .NET Core 8 SDK has been installed and configured, or is otherwise available. (In most cases, the IDE will take care of this.) - -### Building - -1. Open up `SamplePlugin.sln` in your C# editor of choice (likely [Visual Studio 2022](https://visualstudio.microsoft.com) or [JetBrains Rider](https://www.jetbrains.com/rider/)). -2. Build the solution. By default, this will build a `Debug` build, but you can switch to `Release` in your IDE. -3. The resulting plugin can be found at `SamplePlugin/bin/x64/Debug/SamplePlugin.dll` (or `Release` if appropriate.) - -### Activating in-game - -1. Launch the game and use `/xlsettings` in chat or `xlsettings` in the Dalamud Console to open up the Dalamud settings. - * In here, go to `Experimental`, and add the full path to the `SamplePlugin.dll` to the list of Dev Plugin Locations. -2. Next, use `/xlplugins` (chat) or `xlplugins` (console) to open up the Plugin Installer. - * In here, go to `Dev Tools > Installed Dev Plugins`, and the `SamplePlugin` should be visible. Enable it. -3. You should now be able to use `/pmycommand` (chat) or `pmycommand` (console)! - -Note that you only need to add it to the Dev Plugin Locations once (Step 1); it is preserved afterwards. You can disable, enable, or load your plugin on startup through the Plugin Installer. - -### Reconfiguring for your own uses - -Basically, just replace all references to `SamplePlugin` in all of the files and filenames with your desired name, then start building the plugin of your dreams. You'll figure it out 😁 - -Dalamud will load the JSON file (by default, `SamplePlugin/SamplePlugin.json`) next to your DLL and use it for metadata, including the description for your plugin in the Plugin Installer. Make sure to update this with information relevant to _your_ plugin! +![Screenshot of Malmstone Calculator Plugin Main Window](https://github.com/user-attachments/assets/3df4e459-9c18-4f69-b85a-0a022e399788) diff --git a/SamplePlugin.sln b/SamplePlugin.sln deleted file mode 100644 index 31c0066..0000000 --- a/SamplePlugin.sln +++ /dev/null @@ -1,29 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29709.97 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamplePlugin", "SamplePlugin\SamplePlugin.csproj", "{13C812E9-0D42-4B95-8646-40EEBF30636F}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.ActiveCfg = Debug|x64 - {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.Build.0 = Debug|x64 - {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.ActiveCfg = Release|x64 - {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.Build.0 = Release|x64 - {4FEC9558-EB25-419F-B86E-51B8CFDA32B7}.Debug|x64.ActiveCfg = Debug|x64 - {4FEC9558-EB25-419F-B86E-51B8CFDA32B7}.Debug|x64.Build.0 = Debug|x64 - {4FEC9558-EB25-419F-B86E-51B8CFDA32B7}.Release|x64.ActiveCfg = Release|x64 - {4FEC9558-EB25-419F-B86E-51B8CFDA32B7}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {B17E85B1-5F60-4440-9F9A-3DDE877E8CDF} - EndGlobalSection -EndGlobal diff --git a/SamplePlugin/Configuration.cs b/SamplePlugin/Configuration.cs deleted file mode 100644 index 4cdc476..0000000 --- a/SamplePlugin/Configuration.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Dalamud.Configuration; -using Dalamud.Plugin; -using System; - -namespace SamplePlugin; - -[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 exist just to make saving less cumbersome - public void Save() - { - Plugin.PluginInterface.SavePluginConfig(this); - } -} diff --git a/SamplePlugin/Dalamud.Plugin.Bootstrap.targets b/SamplePlugin/Dalamud.Plugin.Bootstrap.targets deleted file mode 100644 index 11eec9c..0000000 --- a/SamplePlugin/Dalamud.Plugin.Bootstrap.targets +++ /dev/null @@ -1,11 +0,0 @@ - - - - $(appdata)\XIVLauncher\addon\Hooks\dev\ - $(HOME)/.xlcore/dalamud/Hooks/dev/ - $(HOME)/Library/Application Support/XIV on Mac/dalamud/Hooks/dev/ - $(DALAMUD_HOME)/ - - - - diff --git a/SamplePlugin/Plugin.cs b/SamplePlugin/Plugin.cs deleted file mode 100644 index b8e859b..0000000 --- a/SamplePlugin/Plugin.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Dalamud.Game.Command; -using Dalamud.IoC; -using Dalamud.Plugin; -using System.IO; -using Dalamud.Interface.Windowing; -using Dalamud.Plugin.Services; -using SamplePlugin.Windows; - -namespace SamplePlugin; - -public sealed class Plugin : IDalamudPlugin -{ - [PluginService] internal static IDalamudPluginInterface PluginInterface { get; private set; } = null!; - [PluginService] internal static ITextureProvider TextureProvider { get; private set; } = null!; - [PluginService] internal static ICommandManager CommandManager { get; private set; } = null!; - - private const string CommandName = "/pmycommand"; - - public Configuration Configuration { get; init; } - - public readonly WindowSystem WindowSystem = new("SamplePlugin"); - private ConfigWindow ConfigWindow { get; init; } - private MainWindow MainWindow { get; init; } - - public Plugin() - { - Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration(); - - // you might normally want to embed resources and load them from the manifest stream - 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" - }); - - PluginInterface.UiBuilder.Draw += DrawUI; - - // This adds a button to the plugin installer entry of this plugin which allows - // to toggle the display status of the configuration ui - PluginInterface.UiBuilder.OpenConfigUi += ToggleConfigUI; - - // Adds another button that is doing the same but for the main ui of the plugin - PluginInterface.UiBuilder.OpenMainUi += ToggleMainUI; - } - - public void Dispose() - { - WindowSystem.RemoveAllWindows(); - - ConfigWindow.Dispose(); - MainWindow.Dispose(); - - CommandManager.RemoveHandler(CommandName); - } - - private void OnCommand(string command, string args) - { - // in response to the slash command, just toggle the display status of our main ui - ToggleMainUI(); - } - - private void DrawUI() => WindowSystem.Draw(); - - public void ToggleConfigUI() => ConfigWindow.Toggle(); - public void ToggleMainUI() => MainWindow.Toggle(); -} diff --git a/SamplePlugin/SamplePlugin.csproj b/SamplePlugin/SamplePlugin.csproj deleted file mode 100644 index e952b44..0000000 --- a/SamplePlugin/SamplePlugin.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - 0.0.0.1 - A sample plugin. - https://github.com/goatcorp/SamplePlugin - AGPL-3.0-or-later - false - - - - - PreserveNewest - false - - - diff --git a/SamplePlugin/SamplePlugin.json b/SamplePlugin/SamplePlugin.json deleted file mode 100644 index c806554..0000000 --- a/SamplePlugin/SamplePlugin.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Author": "your name here", - "Name": "Sample Plugin", - "Punchline": "A short one-liner that shows up in /xlplugins.", - "Description": "A description that shows up in /xlplugins. List any major slash-command(s).", - "ApplicableVersion": "any", - "Tags": [ - "sample", - "plugin", - "goats" - ] -} diff --git a/SamplePlugin/Windows/ConfigWindow.cs b/SamplePlugin/Windows/ConfigWindow.cs deleted file mode 100644 index 0a0af98..0000000 --- a/SamplePlugin/Windows/ConfigWindow.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Numerics; -using Dalamud.Interface.Windowing; -using ImGuiNET; - -namespace SamplePlugin.Windows; - -public class ConfigWindow : Window, IDisposable -{ - private Configuration Configuration; - - // We give this window a constant ID using ### - // This allows for labels being 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") - { - Flags = ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoScrollbar | - ImGuiWindowFlags.NoScrollWithMouse; - - 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() - { - // can't ref a property, so use a local copy - var configValue = Configuration.SomePropertyToBeSavedAndWithADefault; - if (ImGui.Checkbox("Random Config Bool", ref configValue)) - { - Configuration.SomePropertyToBeSavedAndWithADefault = configValue; - // 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(); - } - } -} diff --git a/SamplePlugin/Windows/MainWindow.cs b/SamplePlugin/Windows/MainWindow.cs deleted file mode 100644 index 9ac6a4d..0000000 --- a/SamplePlugin/Windows/MainWindow.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Numerics; -using Dalamud.Interface.Internal; -using Dalamud.Interface.Utility; -using Dalamud.Interface.Windowing; -using Dalamud.Plugin.Services; -using ImGuiNET; - -namespace SamplePlugin.Windows; - -public class MainWindow : Window, IDisposable -{ - private string GoatImagePath; - private Plugin Plugin; - - // We give this window a hidden ID using ## - // So that 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) - }; - - GoatImagePath = goatImagePath; - 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(); - - ImGui.Text("Have a goat:"); - var goatImage = Plugin.TextureProvider.GetFromFile(GoatImagePath).GetWrapOrDefault(); - if (goatImage != null) - { - ImGuiHelpers.ScaledIndent(55f); - ImGui.Image(goatImage.ImGuiHandle, new Vector2(goatImage.Width, goatImage.Height)); - ImGuiHelpers.ScaledIndent(-55f); - } - else - { - ImGui.Text("Image not found."); - } - } -} diff --git a/SamplePlugin/packages.lock.json b/SamplePlugin/packages.lock.json deleted file mode 100644 index 19fcea9..0000000 --- a/SamplePlugin/packages.lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "version": 1, - "dependencies": { - "net8.0-windows7.0": { - "DalamudPackager": { - "type": "Direct", - "requested": "[2.1.13, )", - "resolved": "2.1.13", - "contentHash": "rMN1omGe8536f4xLMvx9NwfvpAc9YFFfeXJ1t4P4PE6Gu8WCIoFliR1sh07hM+bfODmesk/dvMbji7vNI+B/pQ==" - } - } - } -} \ No newline at end of file -- cgit v1.2.3