From 8bd1b3dc28afdeaeb53281eaa398089827418a91 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:15:25 -0700 Subject: [PATCH] fix: AddonGenerator produces broken/incomplete addon output (#2517) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary `[AddonGen` currently produces addon scripts that **do not compile**, plus a few gather-logic and UI bugs. This fixes all of them. ## Compile-breaking (verified) Every generated addon failed to build because of the item-component emission path: - **Trailing comma + missing semicolon.** Items were emitted as a multi-line `AddComponent(\n … ,\n)` — a trailing comma in the argument list and no terminating `;`, i.e. `CS1525: Invalid expression term ')'` and `CS1002: ; expected`. - **`Deed` missing `new`.** The template emitted `public override BaseAddonDeed Deed => {name}AddonDeed();` — invoking the type as a method (`CS1955: Non-invocable member … cannot be used like a method`). Both are now fixed; components are emitted on a single line matching the existing static-tile path: ```csharp AddComponent(new AddonComponent(3215) { Light = LightType.Circle300, Hue = 5 }, 2, 3, 5); ``` **Verification:** compiled the generator's *output* (a representative two-component addon — one plain, one hued + light-source) before and after the change against minimal `BaseAddon`/`AddonComponent` stubs: - Before: `CS1525` + `CS1002` (item path), and `CS1955` in isolation for the `Deed` line. - After: **Build succeeded.** `Projects/UOContent` also builds clean with the source change. ## Gather-logic + UI (reasoned from the code, not runtime-tested) - **Inverted Z-range guards.** The tile/item scan used `if (range && …)`, so with the range filter off (the default) map tiles and items were never captured — inconsistent with the Static pass's `if (!range || …)`. Corrected to match. - **"Export Items" was dead unless "Export Statics" was also checked** — the items scan was nested inside `if (statics)`. Items now scan independently. Placed `Static` items are skipped in this path because they're already captured (with hue/light) by the `GetItemsInBounds` pass, which also removes a pre-existing double-count. - **Swapped gump Min/Max labels** — the "Max" label sat over the Min entry and vice versa. ## Notes The three gather/UI fixes are reasoned from the code rather than exercised through the in-game gump, so they're worth a close look in review. The compile fixes are the headline and are output-verified. --- Projects/UOContent/Commands/AddonGenerator.cs | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/Projects/UOContent/Commands/AddonGenerator.cs b/Projects/UOContent/Commands/AddonGenerator.cs index ddb805361..f8b8020a6 100644 --- a/Projects/UOContent/Commands/AddonGenerator.cs +++ b/Projects/UOContent/Commands/AddonGenerator.cs @@ -36,7 +36,7 @@ public class AddonGenerator [SerializationGenerator(0)] public class {name}Addon : BaseAddon { - public override BaseAddonDeed Deed => {name}AddonDeed(); + public override BaseAddonDeed Deed => new {name}AddonDeed(); [Constructible] public {name}Addon() @@ -180,7 +180,7 @@ public class AddonGenerator var tiles = new Dictionary>(); - if (statics) + if (statics || items) { for (var x = start.X; x <= end.X; x++) { @@ -193,18 +193,28 @@ public class AddonGenerator { foreach (var item in map.GetItemsAt(x, y)) { - if (range && item.Z >= min && item.Z <= max) + // Placed Static items are captured (with hue/light) by the + // GetItemsInBounds pass below; skip them here to avoid duplicates. + if (item is Static) + { + continue; + } + + if (!range || item.Z >= min && item.Z <= max) { list.Add(new StaticTile((ushort)item.ItemID, (sbyte)item.Z)); } } } - foreach (var staticTile in tileMatrix.GetStaticTiles(x, y)) + if (statics) { - if (range && staticTile.Z >= min && staticTile.Z <= max) + foreach (var staticTile in tileMatrix.GetStaticTiles(x, y)) { - list.Add(staticTile); + if (!range || staticTile.Z >= min && staticTile.Z <= max) + { + list.Add(staticTile); + } } } @@ -294,29 +304,25 @@ public class AddonGenerator var light = (item.ItemData.Flags & TileFlag.LightSource) == TileFlag.LightSource ? item.Light : LightType.Empty; var hue = item.Hue; - sb.Append(" AddComponent(\n"); + sb.Append($" AddComponent(new AddonComponent({item.ItemID})"); if (hue != 0 || light != LightType.Empty) { - sb.Append($" new AddonComponent({item.ItemID})\n"); - sb.Append(" {\n"); + sb.Append(" {"); if (light != LightType.Empty) { - sb.Append($" Light = LightType.{light},\n"); + sb.Append($" Light = LightType.{light}"); + if (hue != 0) + { + sb.Append($", Hue = {hue}"); + } } - if (hue != 0) + else { - sb.Append($" Hue = {hue},\n"); + sb.Append($" Hue = {hue}"); } - sb.Append(" },\n"); + sb.Append(" }"); } - else - { - sb.Append($" new AddonComponent({item.ItemID}),\n"); - } - sb.Append($" {xOffset},\n"); - sb.Append($" {yOffset},\n"); - sb.Append($" {zOffset},\n"); - sb.Append(" )\n"); + sb.Append($", {xOffset}, {yOffset}, {zOffset});\n"); } // Only pull in Server.Items when the generated addon lives in a different namespace. @@ -387,11 +393,11 @@ public class AddonGenerator AddCheck(20, 135, 2510, 2511, _state.Range, 2); AddLabel(40, 135, LabelHue, "Specify Z Range"); - AddLabel(50, 160, LabelHue, "Max"); + AddLabel(50, 160, LabelHue, "Min"); AddImageTiled(85, 175, 60, 1, 9304); AddTextEntry(85, 155, 60, 20, LabelHue, 2, _state.Min.ToString()); - AddLabel(160, 160, LabelHue, "Min"); + AddLabel(160, 160, LabelHue, "Max"); AddImageTiled(200, 175, 60, 1, 9304); AddTextEntry(200, 155, 60, 20, LabelHue, 3, _state.Max.ToString());