Initial commit: HSPosition plugin and plugin-repo for Gitea
Made-with: Cursor
This commit is contained in:
+18
@@ -0,0 +1,18 @@
|
|||||||
|
# Build
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
*.user
|
||||||
|
*.suo
|
||||||
|
packages/
|
||||||
|
*.dll
|
||||||
|
*.pdb
|
||||||
|
*.zip
|
||||||
|
!plugin-repo/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.csproj.user
|
||||||
|
|
||||||
|
# Keep plugin-repo (manifest)
|
||||||
|
# packages.lock.json
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
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}") = "HSPosition", "HSPosition\HSPosition.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
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using Dalamud.Configuration;
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace HSPosition;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class Configuration : IPluginConfiguration
|
||||||
|
{
|
||||||
|
public int Version { get; set; } = 1;
|
||||||
|
|
||||||
|
public bool Enabled { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>Radius in yalms. Game target ring is ~2–2.5; use MatchGameRingSize in UI to sync.</summary>
|
||||||
|
public float RingRadius { get; set; } = 2.5f;
|
||||||
|
public float RingThickness { get; set; } = 3f;
|
||||||
|
public int RingSegments { get; set; } = 64;
|
||||||
|
|
||||||
|
/// <summary>Degrees added to relative angle before classifying (0–360). Use to align with game if ring color is offset.</summary>
|
||||||
|
public float AngleOffsetDegrees { get; set; } = 0f;
|
||||||
|
/// <summary>If true, flip the angle (use when ring positionals are mirrored).</summary>
|
||||||
|
public bool InvertAngle { get; set; } = false;
|
||||||
|
|
||||||
|
// Colors as RGBA (0-1)
|
||||||
|
public Vector4 ColorFront { get; set; } = new(0.2f, 0.8f, 0.2f, 0.85f); // Green
|
||||||
|
public Vector4 ColorFlank { get; set; } = new(0.9f, 0.7f, 0.1f, 0.85f); // Amber
|
||||||
|
public Vector4 ColorRear { get; set; } = new(0.9f, 0.2f, 0.2f, 0.85f); // Red
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project Sdk="Dalamud.NET.Sdk/14.0.2">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Version>0.0.0.1</Version>
|
||||||
|
<PackageProjectUrl>https://brassnet.ddns.net:33983/Dawnsorrow/HSPosition</PackageProjectUrl>
|
||||||
|
<PackageLicenseExpression>AGPL-3.0-or-later</PackageLicenseExpression>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<Name>HSPosition</Name>
|
||||||
|
<Author>HSPosition</Author>
|
||||||
|
<Description>Shows a colored ground ring under your target based on your positional (front, flank, or rear) so you can easily tell if you need to move for abilities.</Description>
|
||||||
|
<Punchline>Ground ring color shows front, flank, or rear for positionals.</Punchline>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="plugin.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<Visible>false</Visible>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using Dalamud.Game.Command;
|
||||||
|
using Dalamud.Interface.Windowing;
|
||||||
|
using Dalamud.IoC;
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
using HSPosition.Windows;
|
||||||
|
|
||||||
|
namespace HSPosition;
|
||||||
|
|
||||||
|
public sealed class Plugin : IDalamudPlugin
|
||||||
|
{
|
||||||
|
[PluginService] internal static IDalamudPluginInterface PluginInterface { get; private set; } = null!;
|
||||||
|
[PluginService] internal static ICommandManager CommandManager { get; private set; } = null!;
|
||||||
|
[PluginService] internal static ITargetManager TargetManager { get; private set; } = null!;
|
||||||
|
[PluginService] internal static IObjectTable ObjectTable { get; private set; } = null!;
|
||||||
|
[PluginService] internal static IGameGui GameGui { get; private set; } = null!;
|
||||||
|
[PluginService] internal static IClientState ClientState { get; private set; } = null!;
|
||||||
|
[PluginService] internal static IPluginLog Log { get; private set; } = null!;
|
||||||
|
|
||||||
|
private const string CommandName = "/hspos";
|
||||||
|
|
||||||
|
public Configuration Configuration { get; }
|
||||||
|
|
||||||
|
private readonly WindowSystem WindowSystem = new("HSPosition");
|
||||||
|
private ConfigWindow ConfigWindow { get; }
|
||||||
|
|
||||||
|
private PositionalOverlay Overlay { get; }
|
||||||
|
|
||||||
|
public Plugin()
|
||||||
|
{
|
||||||
|
Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration();
|
||||||
|
|
||||||
|
ConfigWindow = new ConfigWindow(this);
|
||||||
|
Overlay = new PositionalOverlay(this);
|
||||||
|
|
||||||
|
WindowSystem.AddWindow(ConfigWindow);
|
||||||
|
|
||||||
|
CommandManager.AddHandler(CommandName, new CommandInfo(OnCommand)
|
||||||
|
{
|
||||||
|
HelpMessage = "Open HSPosition configure (ring color, placement, thickness)"
|
||||||
|
});
|
||||||
|
|
||||||
|
PluginInterface.UiBuilder.Draw += OnDraw;
|
||||||
|
PluginInterface.UiBuilder.OpenConfigUi += () => ConfigWindow.Toggle();
|
||||||
|
|
||||||
|
Log.Information("HSPosition loaded: target ground ring shows front/flank/rear position.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
PluginInterface.UiBuilder.Draw -= OnDraw;
|
||||||
|
PluginInterface.UiBuilder.OpenConfigUi -= () => { };
|
||||||
|
|
||||||
|
WindowSystem.RemoveAllWindows();
|
||||||
|
CommandManager.RemoveHandler(CommandName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCommand(string command, string args) => ConfigWindow.Toggle();
|
||||||
|
|
||||||
|
private void OnDraw()
|
||||||
|
{
|
||||||
|
Overlay.Draw();
|
||||||
|
WindowSystem.Draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
|
|
||||||
|
namespace HSPosition;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// FFXIV target ring: front = 180° (half circle in front of target), rear = 90° gap at back, flank = sides of back half.
|
||||||
|
/// We use: Front ±90°, Flank 90°–135° and -90° to -135°, Rear 135°–180° and -135° to -180°.
|
||||||
|
/// </summary>
|
||||||
|
public enum Positional
|
||||||
|
{
|
||||||
|
Front,
|
||||||
|
Flank,
|
||||||
|
Rear
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PositionalOverlay
|
||||||
|
{
|
||||||
|
private readonly Plugin plugin;
|
||||||
|
|
||||||
|
public PositionalOverlay(Plugin plugin)
|
||||||
|
{
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw()
|
||||||
|
{
|
||||||
|
if (!plugin.Configuration.Enabled) return;
|
||||||
|
|
||||||
|
var target = Plugin.TargetManager.Target;
|
||||||
|
if (target == null || target.Address == nint.Zero) return;
|
||||||
|
|
||||||
|
var player = Plugin.ObjectTable.LocalPlayer;
|
||||||
|
if (player == null || player.Address == nint.Zero) return;
|
||||||
|
|
||||||
|
var targetPos = target.Position;
|
||||||
|
var targetRot = target.Rotation;
|
||||||
|
var playerPos = player.Position;
|
||||||
|
|
||||||
|
var positional = GetPositional(targetPos, targetRot, playerPos);
|
||||||
|
var color = GetColor(positional);
|
||||||
|
|
||||||
|
DrawGroundRing(targetPos, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the player's positional relative to the target.
|
||||||
|
/// Game: front = 180° half-circle, rear = 90° gap at back, flank = sides (90°–135° from center).
|
||||||
|
/// Target rotation in radians (-π to π). Uses config AngleOffsetDegrees and InvertAngle for alignment.
|
||||||
|
/// </summary>
|
||||||
|
private Positional GetPositional(Vector3 targetPos, float targetRot, Vector3 playerPos)
|
||||||
|
{
|
||||||
|
float dx = playerPos.X - targetPos.X;
|
||||||
|
float dz = playerPos.Z - targetPos.Z;
|
||||||
|
|
||||||
|
if (MathF.Abs(dx) < 1e-5f && MathF.Abs(dz) < 1e-5f)
|
||||||
|
return Positional.Front;
|
||||||
|
|
||||||
|
float angleToPlayer = MathF.Atan2(dx, dz);
|
||||||
|
float relative = angleToPlayer - targetRot;
|
||||||
|
|
||||||
|
if (plugin.Configuration.InvertAngle)
|
||||||
|
relative = -relative;
|
||||||
|
|
||||||
|
relative += plugin.Configuration.AngleOffsetDegrees * (MathF.PI / 180f);
|
||||||
|
|
||||||
|
while (relative > MathF.PI) relative -= 2f * MathF.PI;
|
||||||
|
while (relative < -MathF.PI) relative += 2f * MathF.PI;
|
||||||
|
|
||||||
|
float deg = MathF.Abs(relative * (180f / MathF.PI));
|
||||||
|
|
||||||
|
// Game-style: front = 180° (±90°), flank = sides of back half (90°–135°), rear = back center (135°–180°)
|
||||||
|
if (deg <= 90f) return Positional.Front;
|
||||||
|
if (deg <= 135f) return Positional.Flank;
|
||||||
|
return Positional.Rear;
|
||||||
|
}
|
||||||
|
|
||||||
|
private uint GetColor(Positional p)
|
||||||
|
{
|
||||||
|
var v = p switch
|
||||||
|
{
|
||||||
|
Positional.Front => plugin.Configuration.ColorFront,
|
||||||
|
Positional.Flank => plugin.Configuration.ColorFlank,
|
||||||
|
Positional.Rear => plugin.Configuration.ColorRear,
|
||||||
|
_ => plugin.Configuration.ColorFront
|
||||||
|
};
|
||||||
|
return ImGui.ColorConvertFloat4ToU32(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawGroundRing(Vector3 worldCenter, uint color)
|
||||||
|
{
|
||||||
|
var gui = Plugin.GameGui;
|
||||||
|
float r = plugin.Configuration.RingRadius;
|
||||||
|
int segments = Math.Clamp(plugin.Configuration.RingSegments, 8, 128);
|
||||||
|
float thickness = MathF.Max(1f, plugin.Configuration.RingThickness);
|
||||||
|
|
||||||
|
for (int i = 0; i < segments; i++)
|
||||||
|
{
|
||||||
|
float t0 = (float)i / segments * 2f * MathF.PI;
|
||||||
|
float t1 = (float)(i + 1) / segments * 2f * MathF.PI;
|
||||||
|
|
||||||
|
var p0 = worldCenter + new Vector3(r * MathF.Sin(t0), 0, r * MathF.Cos(t0));
|
||||||
|
var p1 = worldCenter + new Vector3(r * MathF.Sin(t1), 0, r * MathF.Cos(t1));
|
||||||
|
|
||||||
|
if (!gui.WorldToScreen(p0, out var s0)) continue;
|
||||||
|
if (!gui.WorldToScreen(p1, out var s1)) continue;
|
||||||
|
|
||||||
|
var drawList = ImGui.GetBackgroundDrawList();
|
||||||
|
drawList.AddLine(s0, s1, color, thickness);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
|
using Dalamud.Interface.Windowing;
|
||||||
|
|
||||||
|
namespace HSPosition.Windows;
|
||||||
|
|
||||||
|
public class ConfigWindow : Window
|
||||||
|
{
|
||||||
|
private readonly Plugin plugin;
|
||||||
|
|
||||||
|
public ConfigWindow(Plugin plugin) : base("HSPosition Configure", ImGuiWindowFlags.AlwaysAutoResize)
|
||||||
|
{
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Draw()
|
||||||
|
{
|
||||||
|
var cfg = plugin.Configuration;
|
||||||
|
|
||||||
|
var enabled = cfg.Enabled;
|
||||||
|
if (ImGui.Checkbox("Enable ground ring", ref enabled))
|
||||||
|
{
|
||||||
|
cfg.Enabled = enabled;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
ImGui.Text("Ring placement and thickness");
|
||||||
|
ImGui.Spacing();
|
||||||
|
ImGui.TextWrapped("The game's target ring cannot be recolored by plugins. We draw a colored ring on top of it.");
|
||||||
|
if (ImGui.Button("Match game ring size"))
|
||||||
|
{
|
||||||
|
cfg.RingRadius = 2.4f;
|
||||||
|
cfg.RingThickness = 2.5f;
|
||||||
|
cfg.RingSegments = 64;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
ImGui.Spacing();
|
||||||
|
|
||||||
|
var ringRadius = cfg.RingRadius;
|
||||||
|
if (ImGui.SliderFloat("Ring radius (yalms)", ref ringRadius, 1f, 8f, "%.1f"))
|
||||||
|
{
|
||||||
|
cfg.RingRadius = ringRadius;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
var ringThickness = cfg.RingThickness;
|
||||||
|
if (ImGui.SliderFloat("Ring line thickness", ref ringThickness, 1f, 12f, "%.0f"))
|
||||||
|
{
|
||||||
|
cfg.RingThickness = ringThickness;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
var ringSegments = cfg.RingSegments;
|
||||||
|
if (ImGui.SliderInt("Ring segments", ref ringSegments, 16, 128))
|
||||||
|
{
|
||||||
|
cfg.RingSegments = ringSegments;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
ImGui.Text("Positional angle (if colors feel offset)");
|
||||||
|
ImGui.Spacing();
|
||||||
|
|
||||||
|
var angleOffset = cfg.AngleOffsetDegrees;
|
||||||
|
if (ImGui.SliderFloat("Angle offset (degrees)", ref angleOffset, 0f, 360f, "%.0f"))
|
||||||
|
{
|
||||||
|
cfg.AngleOffsetDegrees = angleOffset;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
var invertAngle = cfg.InvertAngle;
|
||||||
|
if (ImGui.Checkbox("Invert angle (mirror front/rear)", ref invertAngle))
|
||||||
|
{
|
||||||
|
cfg.InvertAngle = invertAngle;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
ImGui.Text("Ring colors (Front / Flank / Rear)");
|
||||||
|
ImGui.Spacing();
|
||||||
|
|
||||||
|
var colorFront = cfg.ColorFront;
|
||||||
|
if (ImGui.ColorEdit4("Front", ref colorFront, ImGuiColorEditFlags.AlphaBar))
|
||||||
|
{
|
||||||
|
cfg.ColorFront = colorFront;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
var colorFlank = cfg.ColorFlank;
|
||||||
|
if (ImGui.ColorEdit4("Flank", ref colorFlank, ImGuiColorEditFlags.AlphaBar))
|
||||||
|
{
|
||||||
|
cfg.ColorFlank = colorFlank;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
var colorRear = cfg.ColorRear;
|
||||||
|
if (ImGui.ColorEdit4("Rear", ref colorRear, ImGuiColorEditFlags.AlphaBar))
|
||||||
|
{
|
||||||
|
cfg.ColorRear = colorRear;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
ImGui.TextWrapped("Our ring is drawn on top of the game's target ring and changes color by your positional (Front / Flank / Rear). Use 'Match game ring size' so they align.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Save()
|
||||||
|
{
|
||||||
|
Plugin.PluginInterface.SavePluginConfig(plugin.Configuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"dependencies": {
|
||||||
|
"net10.0-windows7.0": {
|
||||||
|
"DalamudPackager": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[14.0.2, )",
|
||||||
|
"resolved": "14.0.2",
|
||||||
|
"contentHash": "dQJeq+8eyHzra4Cg5eZ/3LAeS3/UpvvLriYJGSncMK9LqJ7Q4B6jwcOsxo3PfxVd15xj+IzVFxkPqIBmPQu8/w=="
|
||||||
|
},
|
||||||
|
"DotNet.ReproducibleBuilds": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.2.39, )",
|
||||||
|
"resolved": "1.2.39",
|
||||||
|
"contentHash": "fcFN01tDTIQqDuTwr1jUQK/geofiwjG5DycJQOnC72i1SsLAk1ELe+apBOuZ11UMQG8YKFZG1FgvjZPbqHyatg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"Name": "HSPosition",
|
||||||
|
"Author": "HSPosition",
|
||||||
|
"Description": "Shows a colored ground ring under your target based on your positional (front, flank, or rear) so you can easily tell if you need to move for abilities.",
|
||||||
|
"Punchline": "Ground ring color shows front, flank, or rear for positionals.",
|
||||||
|
"InternalName": "HSPosition",
|
||||||
|
"AssemblyVersion": "0.0.0.1",
|
||||||
|
"RepoUrl": "https://brassnet.ddns.net:33983/Dawnsorrow/HSPosition",
|
||||||
|
"ApplicableVersion": "any",
|
||||||
|
"DalamudApiLevel": 11,
|
||||||
|
"LoadPriority": 0
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# HSPosition
|
||||||
|
|
||||||
|
A Dalamud plugin for FFXIV that draws a **colored ground ring** under your current target.
|
||||||
|
|
||||||
|
**Publishing to your own repo:** See the `plugin-repo/` folder for a single-repo setup (pluginmaster + README) you can push to Gitea so others can add one URL and get all your plugins. The color reflects your positional:
|
||||||
|
|
||||||
|
- **Green** = Front
|
||||||
|
- **Amber** = Flank
|
||||||
|
- **Red** = Rear
|
||||||
|
|
||||||
|
So you can see at a glance whether you need to move for positional abilities.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
- .NET 10 SDK and Dalamud dev install (e.g. XIVLauncher with Dalamud, run game once).
|
||||||
|
- Build: `dotnet build HSPosition.sln -c Debug` (or Release).
|
||||||
|
- Output: `HSPosition/bin/x64/Debug/` (or `Release/`).
|
||||||
|
|
||||||
|
## Install (dev)
|
||||||
|
|
||||||
|
1. **xlsettings** → Experimental → add the full path to `HSPosition.dll` to **Dev Plugin Locations**.
|
||||||
|
2. **xlplugins** → Dev Tools → Installed Dev Plugins → enable **HSPosition**.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
- Target something; a ring appears under it. Color = your current positional (front/flank/rear).
|
||||||
|
- **/hspos** — open configure menu (or use the **Configure** button on the plugin in the installer).
|
||||||
|
- Configure: enable/disable, ring radius, line thickness, segments, angle offset/invert, and colors for front/flank/rear.
|
||||||
|
|
||||||
|
## Positional angles
|
||||||
|
|
||||||
|
- **Front**: ±45° in front of the target.
|
||||||
|
- **Flank**: 45°–135° to the left or right.
|
||||||
|
- **Rear**: 135°–180° behind the target.
|
||||||
|
|
||||||
|
Matches FFXIV’s usual ~90° cones for positionals.
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# My Dalamud Plugin Repository
|
||||||
|
|
||||||
|
This repo is a **single custom repository** for Dalamud. Users add one URL and see all your plugins in the installer.
|
||||||
|
|
||||||
|
## What users add in Dalamud
|
||||||
|
|
||||||
|
1. Open **xlsettings** (or Dalamud Settings).
|
||||||
|
2. Go to **Experimental** → **Custom Plugin Repositories**.
|
||||||
|
3. Add this URL (use the **raw** URL to `pluginmaster.json` on your Gitea):
|
||||||
|
|
||||||
|
```
|
||||||
|
https://brassnet.ddns.net:33983/Dawnsorrow/DalamudPlugins/raw/main/pluginmaster.json
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Save. In **xlplugins**, your repo will appear and list all plugins in `pluginmaster.json`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Repo layout
|
||||||
|
|
||||||
|
- **pluginmaster.json** – List of all your plugins. This file’s raw URL is the “repo link” users add.
|
||||||
|
- **releases/** – Optional: put `latest.zip` builds here and use raw URLs in pluginmaster (see below).
|
||||||
|
- Or use **Gitea Releases** on this repo for each plugin (recommended).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Adding a new plugin to the repo
|
||||||
|
|
||||||
|
1. **Edit `pluginmaster.json`** and add a new object to the array (copy an existing entry and change fields):
|
||||||
|
|
||||||
|
- `Author`, `Name`, `Description`, `Punchline`, `InternalName`
|
||||||
|
- `AssemblyVersion` (e.g. `"0.0.0.1"`)
|
||||||
|
- `RepoUrl` – link to the plugin’s source (can be another Gitea repo or same repo folder)
|
||||||
|
- `ApplicableVersion`: `"any"`
|
||||||
|
- `DalamudApiLevel`: e.g. `14`
|
||||||
|
- `LastUpdate`: Unix timestamp (seconds), e.g. `1730000000`
|
||||||
|
- `DownloadLinkInstall` and `DownloadLinkUpdate`: URL to the plugin’s **zip** (see below)
|
||||||
|
|
||||||
|
2. **Host the plugin zip** in one of these ways:
|
||||||
|
|
||||||
|
**Option A – Releases on this repo (recommended)**
|
||||||
|
- Create a release (e.g. tag `HSPosition-0.0.0.1` or `v0.0.0.1`).
|
||||||
|
- Upload the plugin zip as `latest.zip`.
|
||||||
|
- Use the release download URL in pluginmaster, e.g.
|
||||||
|
`https://brassnet.ddns.net:33983/Dawnsorrow/DalamudPlugins/releases/download/HSPosition-0.0.0.1/latest.zip`
|
||||||
|
|
||||||
|
**Option B – Raw file in repo**
|
||||||
|
- Put `HSPosition-0.0.0.1.zip` in a `releases/` folder and commit.
|
||||||
|
- Use the raw file URL:
|
||||||
|
`https://brassnet.ddns.net:33983/Dawnsorrow/DalamudPlugins/raw/main/releases/HSPosition-0.0.0.1.zip`
|
||||||
|
|
||||||
|
**Option C – Separate repo per plugin**
|
||||||
|
- Build and release each plugin in its own Gitea repo.
|
||||||
|
- In pluginmaster, set `DownloadLinkInstall` / `DownloadLinkUpdate` to that repo’s release zip URL.
|
||||||
|
|
||||||
|
3. This repo is configured for **brassnet.ddns.net:33983** and user **Dawnsorrow**. For new plugins, set download URLs to `https://brassnet.ddns.net:33983/Dawnsorrow/DalamudPlugins/...` (releases or raw).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Building and packaging HSPosition (or any plugin)
|
||||||
|
|
||||||
|
1. From the plugin project directory, build in **Release** so the packager produces a zip:
|
||||||
|
```bash
|
||||||
|
dotnet build HSPosition.sln -c Release
|
||||||
|
```
|
||||||
|
2. The zip is at:
|
||||||
|
`HSPosition/bin/x64/Release/HSPosition/latest.zip`
|
||||||
|
3. Upload that zip to a Gitea Release (e.g. create release tag `HSPosition-0.0.0.1`, attach `latest.zip`), or put it in `releases/` and use the raw URL.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Updating a plugin
|
||||||
|
|
||||||
|
1. Bump the plugin’s version (e.g. in `.csproj` and `plugin.json`).
|
||||||
|
2. Build in Release and upload the new zip (new release or replace file in `releases/`).
|
||||||
|
3. In `pluginmaster.json` update:
|
||||||
|
- `AssemblyVersion` (and tag/release name if you use it in the URL).
|
||||||
|
- `LastUpdate` (current Unix timestamp: `date +%s`).
|
||||||
|
- `DownloadLinkInstall` and `DownloadLinkUpdate` if the zip URL changed (e.g. new release tag).
|
||||||
|
4. Commit and push. Users will get the update when they check for updates in the plugin installer.
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"Author": "HSPosition",
|
||||||
|
"Name": "HSPosition",
|
||||||
|
"Punchline": "Ground ring color shows front, flank, or rear for positionals.",
|
||||||
|
"Description": "Shows a colored ground ring under your target based on your positional (front, flank, or rear) so you can easily tell if you need to move for abilities.",
|
||||||
|
"Changelog": "Initial release.",
|
||||||
|
"IsHide": false,
|
||||||
|
"InternalName": "HSPosition",
|
||||||
|
"AssemblyVersion": "0.0.0.1",
|
||||||
|
"TestingAssemblyVersion": null,
|
||||||
|
"IsTestingExclusive": false,
|
||||||
|
"RepoUrl": "https://brassnet.ddns.net:33983/Dawnsorrow/HSPosition",
|
||||||
|
"ApplicableVersion": "any",
|
||||||
|
"DalamudApiLevel": 14,
|
||||||
|
"DownloadCount": 0,
|
||||||
|
"LastUpdate": 1730000000,
|
||||||
|
"DownloadLinkInstall": "https://brassnet.ddns.net:33983/Dawnsorrow/HSPosition/releases/download/HSPosition-0.0.0.1/latest.zip",
|
||||||
|
"DownloadLinkUpdate": "https://brassnet.ddns.net:33983/Dawnsorrow/HSPosition/releases/download/HSPosition-0.0.0.1/latest.zip",
|
||||||
|
"DownloadLinkTesting": null
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user