From 5c25e4c19e89acd66cffd8728b24d4672287c4f2 Mon Sep 17 00:00:00 2001 From: HandyS11 Date: Sat, 11 Jul 2026 20:57:00 +0200 Subject: [PATCH 1/9] feat(map): composite event icons with correctly-placed rotors Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Assets/MapIcons.cs | 23 +++-- .../Assets/MarkerIconComposer.cs | 87 ++++++++++++++++++ .../Assets/icons/blade.png | Bin 0 -> 4228 bytes .../Assets/icons/ch47.png | Bin 1727 -> 0 bytes .../Assets/icons/chinook.png | Bin 0 -> 2828 bytes .../Assets/icons/heli.png | Bin 0 -> 2742 bytes .../Assets/icons/patrol.png | Bin 7075 -> 0 bytes .../Assets/icons/vendor.png | Bin 172022 -> 6871 bytes .../MarkerIconComposerTests.cs | 59 ++++++++++++ 9 files changed, 162 insertions(+), 7 deletions(-) create mode 100644 src/RustPlusBot.Features.Map/Assets/MarkerIconComposer.cs create mode 100644 src/RustPlusBot.Features.Map/Assets/icons/blade.png delete mode 100644 src/RustPlusBot.Features.Map/Assets/icons/ch47.png create mode 100644 src/RustPlusBot.Features.Map/Assets/icons/chinook.png create mode 100644 src/RustPlusBot.Features.Map/Assets/icons/heli.png delete mode 100644 src/RustPlusBot.Features.Map/Assets/icons/patrol.png create mode 100644 tests/RustPlusBot.Features.Map.Tests/MarkerIconComposerTests.cs diff --git a/src/RustPlusBot.Features.Map/Assets/MapIcons.cs b/src/RustPlusBot.Features.Map/Assets/MapIcons.cs index 4111c26c..ad853dbe 100644 --- a/src/RustPlusBot.Features.Map/Assets/MapIcons.cs +++ b/src/RustPlusBot.Features.Map/Assets/MapIcons.cs @@ -27,7 +27,7 @@ public static class MapIcons public static Image? Marker(MarkerKind kind) { var key = KeyFor(kind); - return key is null ? null : Load(key); + return key is null ? null : Native(key); } /// Gets the marker icon scaled to fit a square box, or null when the kind has no icon. @@ -38,11 +38,11 @@ public static class MapIcons /// Gets the travelling vendor icon. /// The cached vendor icon image, or null. - public static Image? Vendor() => Load("vendor"); + public static Image? Vendor() => Native("vendor"); /// Gets the player position icon, or null when the asset is missing. /// The player icon, or null. - public static Image? Player() => Load("player"); + public static Image? Player() => Native("player"); /// Gets the player icon scaled to fit a square box, or null when the asset is missing. /// The box edge length in pixels. @@ -58,18 +58,27 @@ public static class MapIcons _ => null, }; - private static Image? Load(string key) => Cache.GetOrAdd(key, static k => + private static Image? Native(string? key) => key is null + ? null + : Cache.GetOrAdd(key, static k => k switch + { + "patrol" => MarkerIconComposer.Heli(), + "ch47" => MarkerIconComposer.Chinook(), + _ => LoadPng(k), + }); + + private static Image? LoadPng(string key) { var asm = typeof(MapIcons).Assembly; - using var stream = asm.GetManifestResourceStream(ResourcePrefix + k + ".png"); + using var stream = asm.GetManifestResourceStream(ResourcePrefix + key + ".png"); return stream is null ? null : Image.Load(stream); - }); + } private static Image? Scaled(string? key, int size) => key is null ? null : Cache.GetOrAdd($"{key}@{size}", _ => { - var native = Load(key); + var native = Native(key); return native?.Clone(ctx => ctx.Resize(new ResizeOptions { Mode = ResizeMode.Max, Size = new Size(size, size), diff --git a/src/RustPlusBot.Features.Map/Assets/MarkerIconComposer.cs b/src/RustPlusBot.Features.Map/Assets/MarkerIconComposer.cs new file mode 100644 index 00000000..86fe98df --- /dev/null +++ b/src/RustPlusBot.Features.Map/Assets/MarkerIconComposer.cs @@ -0,0 +1,87 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; + +namespace RustPlusBot.Features.Map.Assets; + +/// +/// Builds the patrol-heli and CH47 marker icons by compositing a grey body with rotor blade(s): +/// the heli gets one blade on its hub, the CH47 gets two at its tandem-rotor positions. Blades are +/// drawn into a copy of the body canvas, so the composite keeps the body's dimensions and rotates +/// cleanly about its centre in . Offsets/scale are tuned against the +/// reference art (verify visually on a rendered tile). +/// +internal static class MarkerIconComposer +{ + private const string ResourcePrefix = "RustPlusBot.Features.Map.Assets.icons."; + + /// Main-rotor blade edge as a fraction of the body's shorter edge; spans past the fuselage. + private const float HeliBladeScale = 1.15f; + + /// Each tandem-rotor blade edge as a fraction of the body's shorter edge; smaller than the body. + private const float ChinookBladeScale = 0.62f; + + /// The single main-rotor hub offset, in body pixels (populated on first access). + internal static IReadOnlyList HeliRotorOffsets { get; } = HeliOffsets(); + + /// The two tandem-rotor offsets (front, rear), in body pixels. + internal static IReadOnlyList ChinookRotorOffsets { get; } = ChinookOffsets(); + + /// Builds the patrol-heli composite (body + one rotor blade on the hub). + /// The composited heli icon; caller owns disposal. + internal static Image Heli() => + Compose("heli", HeliRotorOffsets, HeliBladeScale); + + /// Builds the CH47 composite (body + two rotor blades at the tandem positions). + /// The composited chinook icon; caller owns disposal. + internal static Image Chinook() => + Compose("chinook", ChinookRotorOffsets, ChinookBladeScale); + + private static IReadOnlyList HeliOffsets() + { + using var body = Load("heli"); + + // Hub sits slightly forward of centre. + return [new PointF(body.Width / 2f, body.Height * 0.44f)]; + } + + private static IReadOnlyList ChinookOffsets() + { + using var body = Load("chinook"); + var cx = body.Width / 2f; + return + [ + new PointF(cx, body.Height * 0.20f), // front rotor + new PointF(cx, body.Height * 0.80f), // rear rotor + ]; + } + + private static Image Compose(string bodyKey, IReadOnlyList offsets, float bladeScale) + { + var canvas = Load(bodyKey); // returned to caller (cached by MapIcons); not disposed here + using var blade = Load("blade"); + var edge = (int)(Math.Min(canvas.Width, canvas.Height) * bladeScale); + using var scaledBlade = blade.Clone(c => c.Resize(edge, edge)); + + canvas.Mutate(ctx => + { + foreach (var offset in offsets) + { + var topLeft = new Point( + (int)(offset.X - (scaledBlade.Width / 2f)), + (int)(offset.Y - (scaledBlade.Height / 2f))); + ctx.DrawImage(scaledBlade, topLeft, 1f); + } + }); + + return canvas; + } + + private static Image Load(string key) + { + var asm = typeof(MarkerIconComposer).Assembly; + using var stream = asm.GetManifestResourceStream(ResourcePrefix + key + ".png") + ?? throw new InvalidOperationException($"Embedded marker asset '{key}.png' not found."); + return Image.Load(stream); + } +} diff --git a/src/RustPlusBot.Features.Map/Assets/icons/blade.png b/src/RustPlusBot.Features.Map/Assets/icons/blade.png new file mode 100644 index 0000000000000000000000000000000000000000..95b9687729c4d57c13390307dde78f76188e44a0 GIT binary patch literal 4228 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 F{{dbn?{)wH literal 0 HcmV?d00001 diff --git a/src/RustPlusBot.Features.Map/Assets/icons/ch47.png b/src/RustPlusBot.Features.Map/Assets/icons/ch47.png deleted file mode 100644 index 4af5d18ba55878efd9a3b8aceefb64e41e3c2f38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1727 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 diff --git a/src/RustPlusBot.Features.Map/Assets/icons/vendor.png b/src/RustPlusBot.Features.Map/Assets/icons/vendor.png index 1556ad97ea834687993f7f5c5c515441dd497b81..676be5a25d206ad5298255a729f590e136eba488 100644 GIT binary patch literal 6871 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 K)v8n+BK`}j^H_8M literal 172022 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 z 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 0 && heli.Height > 0); + } + + [Fact] + public void Chinook_has_two_rotors_placed_apart() + { + Assert.Equal(2, MarkerIconComposer.ChinookRotorOffsets.Count); + using var chinook = MarkerIconComposer.Chinook(); + + // One rotor in the top half of the body, one in the bottom half (tandem placement). + var midY = chinook.Height / 2f; + Assert.Contains(MarkerIconComposer.ChinookRotorOffsets, p => p.Y < midY); + Assert.Contains(MarkerIconComposer.ChinookRotorOffsets, p => p.Y > midY); + } + + [Fact] + public void Composited_chinook_adds_blade_pixels_to_the_bare_body() + { + // The composite must differ from the bare body β€” proving blades were actually drawn on. + using var composite = MarkerIconComposer.Chinook(); + using var body = LoadEmbedded("chinook"); + + Assert.Equal(body.Width, composite.Width); + Assert.Equal(body.Height, composite.Height); + var changed = 0; + for (var y = 0; y < body.Height; y++) + { + for (var x = 0; x < body.Width; x++) + { + if (body[x, y] != composite[x, y]) + { + changed++; + } + } + } + + Assert.True(changed > 0, "composite identical to bare body β€” no blades drawn"); + } + + private static Image LoadEmbedded(string key) + { + var asm = typeof(MarkerIconComposer).Assembly; + using var stream = asm.GetManifestResourceStream($"RustPlusBot.Features.Map.Assets.icons.{key}.png")!; + return Image.Load(stream); + } +} From 4f90a50765a9f39af3789617cf6c7ebbd78ffa16 Mon Sep 17 00:00:00 2001 From: HandyS11 Date: Sat, 11 Jul 2026 21:05:27 +0200 Subject: [PATCH 2/9] feat(map): soften motion trails to a faint dashed hint Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Rendering/MapRenderStyle.cs | 10 ++++++++-- src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs | 10 ++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/RustPlusBot.Features.Map/Rendering/MapRenderStyle.cs b/src/RustPlusBot.Features.Map/Rendering/MapRenderStyle.cs index 6a985cb7..b7c72780 100644 --- a/src/RustPlusBot.Features.Map/Rendering/MapRenderStyle.cs +++ b/src/RustPlusBot.Features.Map/Rendering/MapRenderStyle.cs @@ -18,12 +18,18 @@ public static class MapRenderStyle ///

Player icon box edge, in output pixels. public const int PlayerIconSize = 20; - /// Trail polyline stroke width, in output pixels. - public const float TrailWidth = 2f; + /// Trail polyline stroke width, in output pixels (thin, so it reads as a faint hint). + public const float TrailWidth = 1.25f; + + /// Opacity ceiling for the newest trail segment (older segments fade below this). + public const float TrailMaxAlpha = 0.4f; /// Grid cell label font size, in points. public const float GridLabelFontSize = 10f; + /// Dash pattern (on, off, on, off …) for the trail, in multiples of the pen width. + public static float[] TrailDash { get; } = [3f, 3f]; + /// Gets the icon box edge for a marker kind. /// The marker kind. /// The box edge length in output pixels. diff --git a/src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs b/src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs index 56b5a03e..01e8815a 100644 --- a/src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs +++ b/src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs @@ -173,10 +173,12 @@ private static void DrawTrails(Image image, IReadOnlyList Date: Sat, 11 Jul 2026 21:19:14 +0200 Subject: [PATCH 3/9] feat(map): persist a Tunnels layer toggle (defaults on) Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Map/ServerMapSettings.cs | 3 + .../Modules/MapComponentModule.cs | 1 + src/RustPlusBot.Persistence/Map/MapLayer.cs | 5 + .../Map/MapSettingsStore.cs | 5 +- ...20260711191524_MapTunnelsLayer.Designer.cs | 729 ++++++++++++++++++ .../20260711191524_MapTunnelsLayer.cs | 29 + .../Migrations/BotDbContextModelSnapshot.cs | 3 + .../Map/MapSettingsStoreTests.cs | 15 + .../Map/ServerMapSettingsSchemaTests.cs | 1 + 9 files changed, 790 insertions(+), 1 deletion(-) create mode 100644 src/RustPlusBot.Persistence/Migrations/20260711191524_MapTunnelsLayer.Designer.cs create mode 100644 src/RustPlusBot.Persistence/Migrations/20260711191524_MapTunnelsLayer.cs diff --git a/src/RustPlusBot.Domain/Map/ServerMapSettings.cs b/src/RustPlusBot.Domain/Map/ServerMapSettings.cs index f6e44ee9..ce16aa7d 100644 --- a/src/RustPlusBot.Domain/Map/ServerMapSettings.cs +++ b/src/RustPlusBot.Domain/Map/ServerMapSettings.cs @@ -29,6 +29,9 @@ public sealed class ServerMapSettings /// Whether oil rigs are styled by activation state. public bool ShowRigs { get; set; } = true; + /// Whether train-tunnel entrance icons are drawn (separate from monuments). + public bool ShowTunnels { get; set; } = true; + /// Which grid convention the rendered map and event grid references use. public MapGridStyle GridStyle { get; set; } = MapGridStyle.InGame; } diff --git a/src/RustPlusBot.Features.Workspace/Modules/MapComponentModule.cs b/src/RustPlusBot.Features.Workspace/Modules/MapComponentModule.cs index 76d0f810..c3dc2261 100644 --- a/src/RustPlusBot.Features.Workspace/Modules/MapComponentModule.cs +++ b/src/RustPlusBot.Features.Workspace/Modules/MapComponentModule.cs @@ -113,6 +113,7 @@ public async Task SetGridStyleAsync(string tail) MapLayer.Vendor => settings.Vendor, MapLayer.Players => settings.Players, MapLayer.Rigs => settings.Rigs, + MapLayer.Tunnels => settings.Tunnels, _ => true, }; } diff --git a/src/RustPlusBot.Persistence/Map/MapLayer.cs b/src/RustPlusBot.Persistence/Map/MapLayer.cs index 06e650fa..b92c1bc8 100644 --- a/src/RustPlusBot.Persistence/Map/MapLayer.cs +++ b/src/RustPlusBot.Persistence/Map/MapLayer.cs @@ -22,6 +22,9 @@ public enum MapLayer /// The oil-rig activation-styling layer. Rigs = 5, + + /// The train-tunnel entrance layer. + Tunnels = 6, } /// The resolved per-server layer toggles (all-on when no row is stored). @@ -31,6 +34,7 @@ public enum MapLayer /// Travelling vendor. /// Teammate positions. /// Oil-rig activation styling. +/// Train-tunnel entrance icons. /// Which grid convention the render and event grid references use. public sealed record MapLayerSettings( bool Grid, @@ -39,6 +43,7 @@ public sealed record MapLayerSettings( bool Vendor, bool Players, bool Rigs, + bool Tunnels = true, MapGridStyle GridStyle = MapGridStyle.InGame) { /// All layers enabled β€” the default when no settings row exists. diff --git a/src/RustPlusBot.Persistence/Map/MapSettingsStore.cs b/src/RustPlusBot.Persistence/Map/MapSettingsStore.cs index d6e96b79..d35a6089 100644 --- a/src/RustPlusBot.Persistence/Map/MapSettingsStore.cs +++ b/src/RustPlusBot.Persistence/Map/MapSettingsStore.cs @@ -19,7 +19,7 @@ public async Task GetAsync(ulong guildId, return row is null ? MapLayerSettings.AllOn : new MapLayerSettings(row.ShowGrid, row.ShowMarkers, row.ShowMonuments, row.ShowVendor, - row.ShowPlayers, row.ShowRigs, row.GridStyle); + row.ShowPlayers, row.ShowRigs, row.ShowTunnels, row.GridStyle); } /// @@ -57,6 +57,9 @@ public async Task SetLayerAsync(ulong guildId, case MapLayer.Rigs: row.ShowRigs = enabled; break; + case MapLayer.Tunnels: + row.ShowTunnels = enabled; + break; default: throw new ArgumentOutOfRangeException(nameof(layer), layer, "Unknown map layer."); } diff --git a/src/RustPlusBot.Persistence/Migrations/20260711191524_MapTunnelsLayer.Designer.cs b/src/RustPlusBot.Persistence/Migrations/20260711191524_MapTunnelsLayer.Designer.cs new file mode 100644 index 00000000..98fc0697 --- /dev/null +++ b/src/RustPlusBot.Persistence/Migrations/20260711191524_MapTunnelsLayer.Designer.cs @@ -0,0 +1,729 @@ +ο»Ώ// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using RustPlusBot.Persistence; + +#nullable disable + +namespace RustPlusBot.Persistence.Migrations +{ + [DbContext(typeof(BotDbContext))] + [Migration("20260711191524_MapTunnelsLayer")] + partial class MapTunnelsLayer + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "10.0.9"); + + modelBuilder.Entity("Persistord.Core.Entities.ChannelEntity", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId"); + + b.HasIndex("ParentId"); + + b.ToTable("Channels"); + }); + + modelBuilder.Entity("Persistord.Core.Entities.GuildEntity", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Guilds"); + }); + + modelBuilder.Entity("Persistord.Core.Entities.MemberEntity", b => + { + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("JoinedAt") + .HasColumnType("TEXT"); + + b.Property("Nickname") + .HasColumnType("TEXT"); + + b.HasKey("GuildId", "UserId"); + + b.ToTable("Members"); + }); + + modelBuilder.Entity("Persistord.Core.Entities.RoleEntity", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("Color") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Permissions") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId"); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Persistord.Core.Entities.UserEntity", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("GlobalName") + .HasColumnType("TEXT"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Alarms.SmartAlarm", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedUtc") + .HasColumnType("TEXT"); + + b.Property("EntityId") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("LastIsActive") + .HasColumnType("INTEGER"); + + b.Property("LastTriggeredUtc") + .HasColumnType("TEXT"); + + b.Property("MessageId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("PairedByUserId") + .HasColumnType("INTEGER"); + + b.Property("PingEveryone") + .HasColumnType("INTEGER"); + + b.Property("Reachability") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("RelayToTeamChat") + .HasColumnType("INTEGER"); + + b.Property("ServerId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ServerId"); + + b.HasIndex("GuildId", "ServerId", "EntityId") + .IsUnique(); + + b.ToTable("SmartAlarms"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Commands.ServerCommandSettings", b => + { + b.Property("ServerId") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Muted") + .HasColumnType("INTEGER"); + + b.Property("Prefix") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("TEXT"); + + b.HasKey("ServerId"); + + b.ToTable("ServerCommandSettings"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Connections.ConnectionState", b => + { + b.Property("RustServerId") + .HasColumnType("TEXT"); + + b.Property("ActiveCredentialId") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("PlayerCount") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasColumnType("INTEGER"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("RustServerId"); + + b.ToTable("ConnectionStates"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Credentials.FcmRegistration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("OwnerUserId") + .HasColumnType("INTEGER"); + + b.Property("ProtectedFcmCredentials") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("INTEGER"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "OwnerUserId") + .IsUnique(); + + b.ToTable("FcmRegistrations"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Credentials.PlayerCredential", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("OwnerUserId") + .HasColumnType("INTEGER"); + + b.Property("ProtectedPlayerToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RustServerId") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("INTEGER"); + + b.Property("SteamId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RustServerId"); + + b.HasIndex("GuildId", "RustServerId", "OwnerUserId") + .IsUnique(); + + b.ToTable("PlayerCredentials"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Entities.PairedEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EntityId") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("RustServerId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RustServerId"); + + b.ToTable("PairedEntities"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Events.EventSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("EventKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("RustServerId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RustServerId"); + + b.ToTable("EventSubscriptions"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Guilds.GuildSettings", b => + { + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Culture") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("TEXT"); + + b.HasKey("GuildId"); + + b.ToTable("GuildSettings"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Map.ServerMapSettings", b => + { + b.Property("ServerId") + .HasColumnType("TEXT"); + + b.Property("GridStyle") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("ShowGrid") + .HasColumnType("INTEGER"); + + b.Property("ShowMarkers") + .HasColumnType("INTEGER"); + + b.Property("ShowMonuments") + .HasColumnType("INTEGER"); + + b.Property("ShowPlayers") + .HasColumnType("INTEGER"); + + b.Property("ShowRigs") + .HasColumnType("INTEGER"); + + b.Property("ShowTunnels") + .HasColumnType("INTEGER"); + + b.Property("ShowVendor") + .HasColumnType("INTEGER"); + + b.HasKey("ServerId"); + + b.ToTable("ServerMapSettings"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Servers.RustServer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AddedByUserId") + .HasColumnType("INTEGER"); + + b.Property("FacepunchServerId") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Ip") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("FacepunchServerId"); + + b.HasIndex("GuildId"); + + b.HasIndex("GuildId", "Ip", "Port") + .IsUnique(); + + b.ToTable("RustServers"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.StorageMonitors.SmartStorageMonitor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedUtc") + .HasColumnType("TEXT"); + + b.Property("EntityId") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("MessageId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("PairedByUserId") + .HasColumnType("INTEGER"); + + b.Property("Reachability") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("ServerId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ServerId"); + + b.HasIndex("GuildId", "ServerId", "EntityId") + .IsUnique(); + + b.ToTable("SmartStorageMonitors"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Switches.SmartSwitch", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedUtc") + .HasColumnType("TEXT"); + + b.Property("EntityId") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("LastIsActive") + .HasColumnType("INTEGER"); + + b.Property("MessageId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("PairedByUserId") + .HasColumnType("INTEGER"); + + b.Property("Reachability") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("ServerId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ServerId"); + + b.HasIndex("GuildId", "ServerId", "EntityId") + .IsUnique(); + + b.ToTable("SmartSwitches"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Workspace.ProvisionedCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("DiscordCategoryId") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("RustServerId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RustServerId"); + + b.HasIndex("GuildId", "RustServerId") + .IsUnique(); + + b.ToTable("ProvisionedCategories"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Workspace.ProvisionedChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ChannelKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("DiscordChannelId") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("RustServerId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RustServerId"); + + b.HasIndex("GuildId", "RustServerId", "ChannelKey") + .IsUnique(); + + b.ToTable("ProvisionedChannels"); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Workspace.ProvisionedMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("DiscordChannelId") + .HasColumnType("INTEGER"); + + b.Property("DiscordMessageId") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("MessageKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("RustServerId") + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RustServerId"); + + b.HasIndex("GuildId", "RustServerId", "MessageKey") + .IsUnique(); + + b.ToTable("ProvisionedMessages"); + }); + + modelBuilder.Entity("Persistord.Core.Entities.ChannelEntity", b => + { + b.HasOne("Persistord.Core.Entities.ChannelEntity", null) + .WithMany() + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Alarms.SmartAlarm", b => + { + b.HasOne("RustPlusBot.Domain.Servers.RustServer", null) + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Commands.ServerCommandSettings", b => + { + b.HasOne("RustPlusBot.Domain.Servers.RustServer", null) + .WithOne() + .HasForeignKey("RustPlusBot.Domain.Commands.ServerCommandSettings", "ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Connections.ConnectionState", b => + { + b.HasOne("RustPlusBot.Domain.Servers.RustServer", null) + .WithOne() + .HasForeignKey("RustPlusBot.Domain.Connections.ConnectionState", "RustServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Credentials.PlayerCredential", b => + { + b.HasOne("RustPlusBot.Domain.Servers.RustServer", null) + .WithMany() + .HasForeignKey("RustServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Map.ServerMapSettings", b => + { + b.HasOne("RustPlusBot.Domain.Servers.RustServer", null) + .WithOne() + .HasForeignKey("RustPlusBot.Domain.Map.ServerMapSettings", "ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("RustPlusBot.Domain.StorageMonitors.SmartStorageMonitor", b => + { + b.HasOne("RustPlusBot.Domain.Servers.RustServer", null) + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Switches.SmartSwitch", b => + { + b.HasOne("RustPlusBot.Domain.Servers.RustServer", null) + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Workspace.ProvisionedCategory", b => + { + b.HasOne("RustPlusBot.Domain.Servers.RustServer", null) + .WithMany() + .HasForeignKey("RustServerId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Workspace.ProvisionedChannel", b => + { + b.HasOne("RustPlusBot.Domain.Servers.RustServer", null) + .WithMany() + .HasForeignKey("RustServerId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("RustPlusBot.Domain.Workspace.ProvisionedMessage", b => + { + b.HasOne("RustPlusBot.Domain.Servers.RustServer", null) + .WithMany() + .HasForeignKey("RustServerId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/RustPlusBot.Persistence/Migrations/20260711191524_MapTunnelsLayer.cs b/src/RustPlusBot.Persistence/Migrations/20260711191524_MapTunnelsLayer.cs new file mode 100644 index 00000000..1194967c --- /dev/null +++ b/src/RustPlusBot.Persistence/Migrations/20260711191524_MapTunnelsLayer.cs @@ -0,0 +1,29 @@ +ο»Ώusing Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace RustPlusBot.Persistence.Migrations +{ + /// + public partial class MapTunnelsLayer : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ShowTunnels", + table: "ServerMapSettings", + type: "INTEGER", + nullable: false, + defaultValue: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ShowTunnels", + table: "ServerMapSettings"); + } + } +} diff --git a/src/RustPlusBot.Persistence/Migrations/BotDbContextModelSnapshot.cs b/src/RustPlusBot.Persistence/Migrations/BotDbContextModelSnapshot.cs index 21b0ed21..e441cd7f 100644 --- a/src/RustPlusBot.Persistence/Migrations/BotDbContextModelSnapshot.cs +++ b/src/RustPlusBot.Persistence/Migrations/BotDbContextModelSnapshot.cs @@ -384,6 +384,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ShowRigs") .HasColumnType("INTEGER"); + b.Property("ShowTunnels") + .HasColumnType("INTEGER"); + b.Property("ShowVendor") .HasColumnType("INTEGER"); diff --git a/tests/RustPlusBot.Persistence.Tests/Map/MapSettingsStoreTests.cs b/tests/RustPlusBot.Persistence.Tests/Map/MapSettingsStoreTests.cs index a5fea841..a5a38350 100644 --- a/tests/RustPlusBot.Persistence.Tests/Map/MapSettingsStoreTests.cs +++ b/tests/RustPlusBot.Persistence.Tests/Map/MapSettingsStoreTests.cs @@ -64,6 +64,21 @@ public async Task SetLayerAsync_updates_existing_row() Assert.True(result.Players); } + [Fact] + public async Task SetLayerAsync_can_disable_tunnels_only() + { + var (context, connection) = SqliteContextFixture.Create(); + await using var _ = context; + await using var __ = connection; + var server = SeedServer(context); + + await new MapSettingsStore(context).SetLayerAsync(1UL, server.Id, MapLayer.Tunnels, enabled: false); + var result = await new MapSettingsStore(context).GetAsync(1UL, server.Id); + + Assert.False(result.Tunnels); + Assert.True(result.Monuments); // other layers untouched + } + [Fact] public async Task GridStyle_defaults_to_in_game() { diff --git a/tests/RustPlusBot.Persistence.Tests/Map/ServerMapSettingsSchemaTests.cs b/tests/RustPlusBot.Persistence.Tests/Map/ServerMapSettingsSchemaTests.cs index 4354647c..b033d7e0 100644 --- a/tests/RustPlusBot.Persistence.Tests/Map/ServerMapSettingsSchemaTests.cs +++ b/tests/RustPlusBot.Persistence.Tests/Map/ServerMapSettingsSchemaTests.cs @@ -33,6 +33,7 @@ public async Task ServerMapSettings_persists_with_all_layers_on_by_default() Assert.True(read.ShowVendor); Assert.True(read.ShowPlayers); Assert.True(read.ShowRigs); + Assert.True(read.ShowTunnels); } [Fact] From 0c931e308c5102b050a73b5d8a3daa365dcb7d7a Mon Sep 17 00:00:00 2001 From: HandyS11 Date: Sat, 11 Jul 2026 21:31:10 +0200 Subject: [PATCH 4/9] feat(map): render train tunnels as a separate toggleable layer Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Assets/TunnelTokens.cs | 14 ++++++++ .../Composing/MapComposer.cs | 33 ++++++++++++++--- .../Rendering/MapLayerSet.cs | 12 +++++-- .../Rendering/MapRenderer.cs | 9 ++++- .../MapComposerTests.cs | 36 ++++++++++++++++++- .../MapLayerSetTests.cs | 1 + 6 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 src/RustPlusBot.Features.Map/Assets/TunnelTokens.cs diff --git a/src/RustPlusBot.Features.Map/Assets/TunnelTokens.cs b/src/RustPlusBot.Features.Map/Assets/TunnelTokens.cs new file mode 100644 index 00000000..6fc83d86 --- /dev/null +++ b/src/RustPlusBot.Features.Map/Assets/TunnelTokens.cs @@ -0,0 +1,14 @@ +namespace RustPlusBot.Features.Map.Assets; + +/// +/// The Rust+ monument tokens that belong to the separately-toggleable Tunnels layer rather than the +/// general Monuments layer. Trainyard and Military Tunnels stay ordinary monuments. +/// +public static class TunnelTokens +{ + /// The train-tunnel entrance and link tokens. + public static IReadOnlySet All { get; } = new HashSet(StringComparer.Ordinal) + { + "train_tunnel_display_name", "train_tunnel_link_display_name", + }; +} diff --git a/src/RustPlusBot.Features.Map/Composing/MapComposer.cs b/src/RustPlusBot.Features.Map/Composing/MapComposer.cs index a18e0de7..4ae8d104 100644 --- a/src/RustPlusBot.Features.Map/Composing/MapComposer.cs +++ b/src/RustPlusBot.Features.Map/Composing/MapComposer.cs @@ -2,6 +2,7 @@ using RustPlusBot.Abstractions.Connections; using RustPlusBot.Abstractions.Events; using RustPlusBot.Features.Events.State; +using RustPlusBot.Features.Map.Assets; using RustPlusBot.Features.Map.Rendering; using RustPlusBot.Persistence.Map; using SixLabors.ImageSharp; @@ -45,7 +46,7 @@ public sealed class MapComposer( } var layers = new MapLayerSet(settings.Grid, settings.Markers, settings.Monuments, - settings.Vendor, settings.Players, settings.Rigs); + settings.Vendor, settings.Players, settings.Rigs, settings.Tunnels); return await ComposeWithLayersAsync(guildId, serverId, layers, settings.GridStyle, cancellationToken) .ConfigureAwait(false); } @@ -80,20 +81,21 @@ public sealed class MapComposer( var markers = GatherMarkers(guildId, serverId, projection, layers); - // Monuments feed both the monuments layer and the rig-styling layer; fetch them once when either is on. + // Monuments feed the monuments, rig-styling, and tunnels layers; fetch them once when any is on. IReadOnlyList serverMonuments = []; - if (layers.Monuments || layers.Rigs) + if (layers.Monuments || layers.Rigs || layers.Tunnels) { serverMonuments = await query.GetMonumentsAsync(guildId, serverId, cancellationToken).ConfigureAwait(false); } var monuments = GatherMonuments(serverMonuments, projection, layers); + var tunnels = GatherTunnels(serverMonuments, projection, layers); var players = await GatherPlayersAsync(guildId, serverId, projection, layers, cancellationToken) .ConfigureAwait(false); var rigPlacements = GatherRigs(guildId, serverId, serverMonuments, projection, layers); return renderer.Render(baseImage.Bytes, projection, markers, monuments, players, rigPlacements, layers, - gridStyle); + gridStyle, tunnels); } private List GatherMarkers( @@ -151,6 +153,11 @@ private static List GatherMonuments( { foreach (var mon in serverMonuments) { + if (TunnelTokens.All.Contains(mon.Token)) + { + continue; // routed to the Tunnels layer instead + } + var (px, py) = projection.ToPixel(mon.X, mon.Y); monuments.Add(new MonumentPlacement(mon.Token, px, py)); } @@ -159,6 +166,24 @@ private static List GatherMonuments( return monuments; } + private static List GatherTunnels( + IReadOnlyList serverMonuments, + MapProjection projection, + MapLayerSet layers) + { + var tunnels = new List(); + if (layers.Tunnels) + { + foreach (var mon in serverMonuments.Where(m => TunnelTokens.All.Contains(m.Token))) + { + var (px, py) = projection.ToPixel(mon.X, mon.Y); + tunnels.Add(new MonumentPlacement(mon.Token, px, py)); + } + } + + return tunnels; + } + private async Task> GatherPlayersAsync( ulong guildId, Guid serverId, diff --git a/src/RustPlusBot.Features.Map/Rendering/MapLayerSet.cs b/src/RustPlusBot.Features.Map/Rendering/MapLayerSet.cs index 192cb97f..4ceefc42 100644 --- a/src/RustPlusBot.Features.Map/Rendering/MapLayerSet.cs +++ b/src/RustPlusBot.Features.Map/Rendering/MapLayerSet.cs @@ -7,8 +7,16 @@ namespace RustPlusBot.Features.Map.Rendering; /// Draw the travelling-vendor marker. /// Draw teammate position markers. /// Style oil rigs by activation state. -public sealed record MapLayerSet(bool Grid, bool Markers, bool Monuments, bool Vendor, bool Players, bool Rigs) +/// Draw train-tunnel entrance icons. +public sealed record MapLayerSet( + bool Grid, + bool Markers, + bool Monuments, + bool Vendor, + bool Players, + bool Rigs, + bool Tunnels = false) { /// All layers enabled β€” the defaults-on render. - public static MapLayerSet AllOn { get; } = new(true, true, true, true, true, true); + public static MapLayerSet AllOn { get; } = new(true, true, true, true, true, true, true); } diff --git a/src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs b/src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs index 01e8815a..02d96c6c 100644 --- a/src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs +++ b/src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs @@ -47,6 +47,7 @@ private static FontFamily LoadFamily() /// Oil-rig placements already projected to pixel coordinates. /// Which overlay layers to draw. /// Which grid convention to draw (in-game F1 map, or Rust+/RustMaps). + /// Train-tunnel placements already projected to pixel coordinates. /// PNG-encoded bytes of a square image with pixels on each side. public byte[] Render(byte[] baseJpeg, MapProjection projection, @@ -55,7 +56,8 @@ public byte[] Render(byte[] baseJpeg, IReadOnlyList players, IReadOnlyList rigs, MapLayerSet layers, - MapGridStyle gridStyle = MapGridStyle.InGame) + MapGridStyle gridStyle = MapGridStyle.InGame, + IReadOnlyList? tunnels = null) { ArgumentNullException.ThrowIfNull(baseJpeg); ArgumentNullException.ThrowIfNull(projection); @@ -78,6 +80,11 @@ public byte[] Render(byte[] baseJpeg, DrawMonuments(image, monuments); } + if (layers.Tunnels && tunnels is { Count: > 0 }) + { + DrawMonuments(image, tunnels); + } + if (layers.Markers || layers.Vendor) { DrawTrails(image, markers); diff --git a/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs b/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs index 20452f6b..7e95ad2c 100644 --- a/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs +++ b/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs @@ -129,7 +129,7 @@ public async Task ComposeAsync_renders_only_enabled_layers() var events = NewEvents(new ActiveMarker(1, MarkerKind.CargoShip, 2000f, 2000f, Dims, DateTimeOffset.UtcNow, [new TrailPoint(2000f, 2000f)], null)); var settings = NewSettings(new MapLayerSettings( - Grid: true, Markers: true, Monuments: false, Vendor: true, Players: true, Rigs: false)); + Grid: true, Markers: true, Monuments: false, Vendor: true, Players: true, Rigs: false, Tunnels: false)); var composer = Build(BaseJpeg(), Dims, query, events, NewRigs(), settings); @@ -142,6 +142,40 @@ public async Task ComposeAsync_renders_only_enabled_layers() await query.Received().GetTeamInfoAsync(Guild, Server, Arg.Any()); } + [Fact] + public async Task Tunnel_tokens_render_only_when_the_tunnels_layer_is_on() + { + // Two monuments at the same spot: a launchsite (ordinary) and a tunnel entrance. + var query = NewQuery(); + query.GetMonumentsAsync(Guild, Server, Arg.Any()) + .Returns([new MonumentSnapshot("train_tunnel_display_name", 2000f, 2000f)]); + var events = NewEvents(); + + // Monuments ON, Tunnels OFF -> the tunnel token must NOT draw (it belongs to the Tunnels layer). + var tunnelsOff = Build(BaseJpeg(), Dims, query, events, NewRigs(), + NewSettings(MapLayerSettings.AllOn with + { + Tunnels = false + })); + // Monuments OFF, Tunnels ON -> the tunnel token draws via the tunnels pass. + var query2 = NewQuery(); + query2.GetMonumentsAsync(Guild, Server, Arg.Any()) + .Returns([new MonumentSnapshot("train_tunnel_display_name", 2000f, 2000f)]); + var tunnelsOn = Build(BaseJpeg(), Dims, query2, events, NewRigs(), + NewSettings(new MapLayerSettings( + Grid: false, Markers: false, Monuments: false, Vendor: false, Players: false, Rigs: false, + Tunnels: true))); + + var off = await tunnelsOff.ComposeAsync(Guild, Server, CancellationToken.None); + var on = await tunnelsOn.ComposeAsync(Guild, Server, CancellationToken.None); + + Assert.NotNull(off); + Assert.NotNull(on); + // With Monuments on but Tunnels off, the tunnel token is excluded from the monuments pass, so the + // only difference from a Tunnels-on/Monuments-off render is whether the tunnel icon was painted. + Assert.False(off!.SequenceEqual(on!), "tunnel token must render under the Tunnels layer only"); + } + [Fact] public async Task ComposeAsync_uses_all_on_when_no_settings_row() { diff --git a/tests/RustPlusBot.Features.Map.Tests/MapLayerSetTests.cs b/tests/RustPlusBot.Features.Map.Tests/MapLayerSetTests.cs index 8d3a7f9d..9f364c11 100644 --- a/tests/RustPlusBot.Features.Map.Tests/MapLayerSetTests.cs +++ b/tests/RustPlusBot.Features.Map.Tests/MapLayerSetTests.cs @@ -15,5 +15,6 @@ public void AllOn_enables_every_layer() Assert.True(set.Vendor); Assert.True(set.Players); Assert.True(set.Rigs); + Assert.True(set.Tunnels); } } From 9f6f4c03b80f4361f2acbef45eef86089a06c4f2 Mon Sep 17 00:00:00 2001 From: HandyS11 Date: Sat, 11 Jul 2026 21:41:26 +0200 Subject: [PATCH 5/9] test(map): isolate the tunnel-routing composer test (fix confounded layers) Co-Authored-By: Claude Opus 4.8 (1M context) --- .../MapComposerTests.cs | 53 +++++++++---------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs b/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs index 7e95ad2c..b087b7e9 100644 --- a/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs +++ b/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs @@ -143,37 +143,36 @@ public async Task ComposeAsync_renders_only_enabled_layers() } [Fact] - public async Task Tunnel_tokens_render_only_when_the_tunnels_layer_is_on() + public async Task Tunnel_tokens_render_under_the_tunnels_layer_not_the_monuments_layer() + { + // A single tunnel-entrance monument. Every layer except Monuments/Tunnels is held OFF in all + // three configs, so any byte difference is attributable ONLY to the tunnel token's draw pass. + // - baseOnly: Monuments off, Tunnels off -> tunnel token never drawn (bare base render) + // - monumentsOnly: Monuments on, Tunnels off -> tunnel token EXCLUDED from the monuments pass + // - tunnelsOnly: Monuments off, Tunnels on -> tunnel token drawn via the tunnels pass + var basePng = await ComposeTunnelScenarioAsync(monuments: false, tunnels: false); + var monPng = await ComposeTunnelScenarioAsync(monuments: true, tunnels: false); + var tunPng = await ComposeTunnelScenarioAsync(monuments: false, tunnels: true); + + Assert.NotNull(basePng); + Assert.NotNull(monPng); + Assert.NotNull(tunPng); + // Monuments layer must NOT draw the tunnel token -> identical to the bare base render. + Assert.True(monPng!.SequenceEqual(basePng!), "tunnel token must be excluded from the Monuments pass"); + // Tunnels layer MUST draw the tunnel token -> differs from the bare base render. + Assert.False(tunPng!.SequenceEqual(basePng!), "tunnel token must render under the Tunnels layer"); + } + + private static async Task ComposeTunnelScenarioAsync(bool monuments, bool tunnels) { - // Two monuments at the same spot: a launchsite (ordinary) and a tunnel entrance. var query = NewQuery(); query.GetMonumentsAsync(Guild, Server, Arg.Any()) .Returns([new MonumentSnapshot("train_tunnel_display_name", 2000f, 2000f)]); - var events = NewEvents(); - - // Monuments ON, Tunnels OFF -> the tunnel token must NOT draw (it belongs to the Tunnels layer). - var tunnelsOff = Build(BaseJpeg(), Dims, query, events, NewRigs(), - NewSettings(MapLayerSettings.AllOn with - { - Tunnels = false - })); - // Monuments OFF, Tunnels ON -> the tunnel token draws via the tunnels pass. - var query2 = NewQuery(); - query2.GetMonumentsAsync(Guild, Server, Arg.Any()) - .Returns([new MonumentSnapshot("train_tunnel_display_name", 2000f, 2000f)]); - var tunnelsOn = Build(BaseJpeg(), Dims, query2, events, NewRigs(), - NewSettings(new MapLayerSettings( - Grid: false, Markers: false, Monuments: false, Vendor: false, Players: false, Rigs: false, - Tunnels: true))); - - var off = await tunnelsOff.ComposeAsync(Guild, Server, CancellationToken.None); - var on = await tunnelsOn.ComposeAsync(Guild, Server, CancellationToken.None); - - Assert.NotNull(off); - Assert.NotNull(on); - // With Monuments on but Tunnels off, the tunnel token is excluded from the monuments pass, so the - // only difference from a Tunnels-on/Monuments-off render is whether the tunnel icon was painted. - Assert.False(off!.SequenceEqual(on!), "tunnel token must render under the Tunnels layer only"); + var settings = new MapLayerSettings( + Grid: false, Markers: false, Monuments: monuments, Vendor: false, Players: false, Rigs: false, + Tunnels: tunnels); + var composer = Build(BaseJpeg(), Dims, query, NewEvents(), NewRigs(), NewSettings(settings)); + return await composer.ComposeAsync(Guild, Server, CancellationToken.None); } [Fact] From 28c771900d8864e7a114538befd279bc23e11fae Mon Sep 17 00:00:00 2001 From: HandyS11 Date: Sat, 11 Jul 2026 21:49:22 +0200 Subject: [PATCH 6/9] feat(map): add the Tunnels layer toggle button + localization Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Messages/MapControlMessageRenderer.cs | 6 ++++-- src/RustPlusBot.Localization/Strings.fr.resx | 3 +++ src/RustPlusBot.Localization/Strings.resx | 3 +++ .../Messages/MapControlMessageRendererTests.cs | 4 ++-- .../StringsResourceParityTests.cs | 2 +- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/RustPlusBot.Features.Workspace/Messages/MapControlMessageRenderer.cs b/src/RustPlusBot.Features.Workspace/Messages/MapControlMessageRenderer.cs index b69b0c79..fdc718a0 100644 --- a/src/RustPlusBot.Features.Workspace/Messages/MapControlMessageRenderer.cs +++ b/src/RustPlusBot.Features.Workspace/Messages/MapControlMessageRenderer.cs @@ -7,7 +7,7 @@ namespace RustPlusBot.Features.Workspace.Messages; -/// Renders the per-server #map control message: six ManageGuild layer-toggle buttons plus the +/// Renders the per-server #map control message: seven ManageGuild layer-toggle buttons plus the /// grid-style picker (in-game vs Rust+/RustMaps grid convention). /// Per-(guild, server) layer toggles. /// String resolution. @@ -31,7 +31,7 @@ public async ValueTask RenderAsync(MessageRenderContext context, var settings = await mapSettings.GetAsync(context.GuildId, serverId, cancellationToken).ConfigureAwait(false); var builder = new ComponentBuilder(); - // Discord caps an action row at five buttons, so split the six toggles across two rows. + // Discord caps an action row at five buttons, so split the seven toggles across two rows. AddToggle(builder, MapLayer.Grid, "map.layer.grid", settings.Grid, serverId, context.Culture, row: 0); AddToggle(builder, MapLayer.Markers, "map.layer.markers", settings.Markers, serverId, context.Culture, row: 0); AddToggle(builder, MapLayer.Monuments, "map.layer.monuments", settings.Monuments, serverId, context.Culture, @@ -39,6 +39,8 @@ public async ValueTask RenderAsync(MessageRenderContext context, AddToggle(builder, MapLayer.Vendor, "map.layer.vendor", settings.Vendor, serverId, context.Culture, row: 1); AddToggle(builder, MapLayer.Players, "map.layer.players", settings.Players, serverId, context.Culture, row: 1); AddToggle(builder, MapLayer.Rigs, "map.layer.rigs", settings.Rigs, serverId, context.Culture, row: 1); + AddToggle(builder, MapLayer.Tunnels, "map.layer.tunnels", settings.Tunnels, serverId, context.Culture, + row: 1); AddGridStyle(builder, MapGridStyle.InGame, "map.gridstyle.ingame", settings.GridStyle, serverId, context.Culture); AddGridStyle(builder, MapGridStyle.RustPlus, "map.gridstyle.rustplus", settings.GridStyle, serverId, diff --git a/src/RustPlusBot.Localization/Strings.fr.resx b/src/RustPlusBot.Localization/Strings.fr.resx index 7f16ea7f..facc37f4 100644 --- a/src/RustPlusBot.Localization/Strings.fr.resx +++ b/src/RustPlusBot.Localization/Strings.fr.resx @@ -573,6 +573,9 @@ Plateformes + + Tunnels + Marchand diff --git a/src/RustPlusBot.Localization/Strings.resx b/src/RustPlusBot.Localization/Strings.resx index 94b863a6..55063fce 100644 --- a/src/RustPlusBot.Localization/Strings.resx +++ b/src/RustPlusBot.Localization/Strings.resx @@ -573,6 +573,9 @@ Rigs + + Tunnels + Vendor diff --git a/tests/RustPlusBot.Features.Workspace.Tests/Messages/MapControlMessageRendererTests.cs b/tests/RustPlusBot.Features.Workspace.Tests/Messages/MapControlMessageRendererTests.cs index 8a8ba981..98cf0eeb 100644 --- a/tests/RustPlusBot.Features.Workspace.Tests/Messages/MapControlMessageRendererTests.cs +++ b/tests/RustPlusBot.Features.Workspace.Tests/Messages/MapControlMessageRendererTests.cs @@ -20,7 +20,7 @@ private static List Buttons(MessagePayload payload) => ]; [Fact] - public async Task Renders_six_toggle_buttons_reflecting_settings() + public async Task Renders_seven_toggle_buttons_reflecting_settings() { var serverId = Guid.NewGuid(); var settings = Substitute.For(); @@ -35,7 +35,7 @@ public async Task Renders_six_toggle_buttons_reflecting_settings() var toggles = Buttons(payload) .Where(b => b.CustomId!.StartsWith(WorkspaceComponentIds.MapTogglePrefix, StringComparison.Ordinal)) .ToList(); - Assert.Equal(6, toggles.Count); + Assert.Equal(7, toggles.Count); var monuments = toggles.Single(b => b.CustomId == $"workspace:map:toggle:{MapLayer.Monuments}:{serverId}"); diff --git a/tests/RustPlusBot.Localization.Tests/StringsResourceParityTests.cs b/tests/RustPlusBot.Localization.Tests/StringsResourceParityTests.cs index c19d6c47..7e051955 100644 --- a/tests/RustPlusBot.Localization.Tests/StringsResourceParityTests.cs +++ b/tests/RustPlusBot.Localization.Tests/StringsResourceParityTests.cs @@ -41,6 +41,6 @@ public void English_covers_every_french_key() [Fact] public void Catalog_has_expected_key_count() { - Assert.Equal(267, EnglishKeys().Count); + Assert.Equal(268, EnglishKeys().Count); } } From 0fe9133314627a557262e74d9393189cda8d1467 Mon Sep 17 00:00:00 2001 From: HandyS11 Date: Sat, 11 Jul 2026 21:57:48 +0200 Subject: [PATCH 7/9] feat(map): draw players as stable palette-colored crosses, drop name labels Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Assets/MapIcons.cs | 9 --- .../Assets/icons/player.png | Bin 4402 -> 0 bytes .../Composing/MapComposer.cs | 9 ++- .../Rendering/MapRenderStyle.cs | 13 ++++- .../Rendering/MapRenderer.cs | 51 +++++++---------- .../Rendering/PlayerPalette.cs | 35 ++++++++++++ .../Rendering/PlayerPlacement.cs | 9 ++- .../MapIconsTests.cs | 8 +-- .../MapRendererTests.cs | 54 +++++++++++++++++- .../PlayerPaletteTests.cs | 21 +++++++ 10 files changed, 158 insertions(+), 51 deletions(-) delete mode 100644 src/RustPlusBot.Features.Map/Assets/icons/player.png create mode 100644 src/RustPlusBot.Features.Map/Rendering/PlayerPalette.cs create mode 100644 tests/RustPlusBot.Features.Map.Tests/PlayerPaletteTests.cs diff --git a/src/RustPlusBot.Features.Map/Assets/MapIcons.cs b/src/RustPlusBot.Features.Map/Assets/MapIcons.cs index ad853dbe..6e1f500d 100644 --- a/src/RustPlusBot.Features.Map/Assets/MapIcons.cs +++ b/src/RustPlusBot.Features.Map/Assets/MapIcons.cs @@ -40,15 +40,6 @@ public static class MapIcons /// The cached vendor icon image, or null. public static Image? Vendor() => Native("vendor"); - /// Gets the player position icon, or null when the asset is missing. - /// The player icon, or null. - public static Image? Player() => Native("player"); - - /// Gets the player icon scaled to fit a square box, or null when the asset is missing. - /// The box edge length in pixels. - /// The cached scaled icon, or null. - public static Image? Player(int size) => Scaled("player", size); - private static string? KeyFor(MarkerKind kind) => kind switch { MarkerKind.CargoShip => "cargo", diff --git a/src/RustPlusBot.Features.Map/Assets/icons/player.png b/src/RustPlusBot.Features.Map/Assets/icons/player.png deleted file mode 100644 index 5c6c89398723b63478b2d896939a3c4c32911e9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4402 zcmV-25zX$2P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D5XVVGK~#8N?VSmb z6xA8Wzu9FE_JEybfn639SRf)GK~zvADoRXLR768Gf)FqoZ;h6blvRmZN=h^;@xCG& zPl6XB@j?L=0XYTb*n?wX4|Z|cgS{u;zo(~yOuz0oGd&$*c!h zn^^5EUyOyniNB3|z`ew4Y3eElvi`;@WEmO7N#UOEVc{MXHj=NZW8Vh z_lkSQy(_|`3u_u{3(M$1cLd?y@g4A86q2AWoyywAGJ2>TQTQ(SPOfVwxb23RkPNK{nU9``WQ$5rr$^Z3RTYS{i&`$L=ZB$#;N(akZ z=)j(4+PAZbO1C#sV?Ek?wy>IY6YCr8$_2Q^0nj)9J8Kpzta>vc(L?=)rqYOCWYW*Z zq|<;C(x_*@Wb#B<3%9rVsI0h|3fDK#_SJQ?`HNcGU)V%Gyw~9YZ+f0}CkrtLM{$D# zOkzFF%G0hwASoq*PB=4@#$K33BhSvHtX_6^{f(*Q(qa9_hv@5f57G}`*Hc?-Sl+Oo zbq(u%?aCpXbbvJ0Bdn{ns}LA4GL6oj)`L!)?4=BEqW-Bf94u?0Fptt7kr}dv4(m#=+ zmNlLAj&>CzV(kEE_}tHuYMKq_2HmuK^0`5Wahs0EmX&q1;OoNe6MP4)g3dgj*MwC*G6YT-2&sss#GM~!GdWf&h{ z1W_Fx| zuq@yFf>CL7+lvFJ=P}9pC-F_m=EL;x%wj4llIk|T&iWlIDozm165yY#-}_I+jK9oF zcf2xC3(o&%|y!q(AvMte`*Zs`zd$i(#*O2 zD6vZiZ|Q|Wa@PbpeTr9W8=yq600}23E>>z+HWCd7KtKN(me8u`+s~ZamoC1!cZYA~ zM*@OdC;hrRwKV!@+c)+4r$UhOwwd*Vc4ZTGI{+elD5``J8yNo&|2T$zIWtH9q;rE8 z0OJ{m9B%!xPXE*pyeddCL7?aWKClBj9RRWYPguylH3VOF)`R_M;tXZ{qZxL3CbcyA z=!aFNB|!@7EY`nRNK%a$J00M0*021h#!Q`)N0Y8cX12lzL_RUNRJ_r&O@Ia=9-=Ly zh;}&uhIHroPmRIo-L!l2^(%!DC?Q9k(~Sz(HBecxX%}%cYaMI5b`=43G{KO}f!sIY zc>d5+GwANO2T_+~JN{h!({QMb=A5(5YIqs>1PByGlvH9z$PEJ*LgORyb;}F=mGMIW zDQkaPFpyHxOwEI59`T@2q*VZB;UM5+XkE1UZ-03p9XqUJj^;T@_na=;%d_@F%vKXJ ziuGR>rm=-ZBqachj*K4R|8f4cy=cT4Qp5fV1J1mn2aTDOrC%9>Xa6WG?BX>N2fzRi zvUm;2D@dWKe+fCwPjLij6waR4&nip~8(0pui3qm}z#T1Q_0X=40ylo^3j?UnppKEj z<7QIR6Sz7^qBToQtAdfNCs`p67=>E`T*1P$YeU9O@oIfqg*_lg0;%pMz!sLHu1198 z0Qff;>@fsm`Ip~~+1d_*q4sFVAyA@Dzc1fvj>Df>A=@(?2SBtB^Y0BgcXp08A;VG7 zB#MR{Wbo*88f)GlgiTB%u||aB0GQfj22h4NC@UaQ7O-Sn#gz5k@Scd;5G08*c{}JO9ifA(F2GhYb*akL| zCKLxi*@N6PLq?z5U7LZch%T5Fg{g5Sz(&$7mQWnvB$lvvnWz#xVgh;u6K5EPUjo2J zNFkFV6bG2BAA{)8Cy9oS&(Nsv;NbjCVqb6dhLm@(29gVC5AhLt>WJAVYWZFNCDH)ytl+Q0f#rA9}*_1@S zis6*&IY<9#{D3tPOn|MVqH(egfIKwAR~+3wOzdzAIi4}}<;qP|R=<%N(>BqXZ`aeo z(p1Xw2>rK1GIByUvr-p7fXytCb%62uF$iR|x~2F}_4J~e>K3YREvLReKR`JJHPq*X zD%!ofjJnFb5FG|gr5kjj>5C_{*^$UP01`h888+TMgFZfAJ0&C}PNMsxUW4glF|8eG{R57KA4p3TF3-$8$rNR|`Xz%)-RJx%T6%^!C zJ?++iD}ESqis`e5%`C^`Wy)@(9U%iX2+VkWv1o)_3rJZ zmaau~z~`Ek*=z$#+RYk_$wER-WUcp~8Y5Ez2;ctxBf7fE_@L2OLA%-)QbO)#%IIHA z)u|uFrSSnWg)By1g|-VI;{b#7V-Ogea3?;h^A*z}-!`rms`Ss|lfLFQ5ZW$)j05!7 zk3k^sPvI=N15Irpv|Ruh2N2Hnb3E}wLA}fu)ezb)fQ$nO#~;0Uv00f@AqER-nP52) zQ^o->^~;cM*(&+NX}X!GjA!ddAu1a{X_ILnU}rZy1TE`W>!?A4D!9N25Q&aEQKSlB>ly8to{ zP@*4$C^uiqOc4XHrJV^v+XawufSvj=h|(R(0h|UKTbdxWT>u#ez>Zdigs>NmA__D& zwp%%X&~^c28~|IH8MZXAtf^`UI>)Z>4x0snU>M77=wuuKE@tRSSmAod8p~zQ6;Wcl z`Ll=3Op6B~;{aflehlLKuayHh#n!J(mzNjX>_}uCV1<4RVnb+~BPwj7wb@7CEjM)l zq0Np&)&Z8W3@e*`I~%FIMD+$@4R#nY3B|)!u$d*Y4zQ2)o&WTwpdDbbo~i}S}ehgyeLdUnk?^K}Wzv>-R2N2roXhLy-xAkKXMH?EZbcbbwQ(+U| zEw8oeeoJpa9f||2Wfl2Pe+sIBPhX1f88~hNdl8!e8?Eu5S`&%`pkeWE|7kE^yk4ym zL}EbIz7|@$)U?e78yPm(jR?g70CuY~v~q2AD}DZ|2g|6XNwo#+rlzu$mONFdUl{_Mz&0Tfjsw8D!riJWcQ;$z zs3HvBd|L@T!fs){~$-;@n3Q5qYo;R(Ss=51T!VRoV{?pJ1rwR!0 z25YtdG?>+kf26P8Rw3d@LC>miy=mqZ7C?e6!Xgp}KzVdCOIYtbf5%>`-mfx-!lh*M zVXf{rAz*{B``(c_06@~g^ZwId5FDC+O^J#Pgh69{J3TtPMB7r{gy&chErDjo3J)t; z(^-a#5uh!AHUXBDRmg#{l_##-MO(f!P5403fF=AR8iljN0dNCog$nnr+rGM<@(NPv znB&zR!ZN)3Xt_*R`bySD|7rNxwZ_Xf7FMLf%9Mtz|M(CMJuO46EM@^3&d=Sk$EsF; zmNn0R8X0yj@qmSE(JK(HPMMySNPm5Qu-Z*rz~(P%Y3^@}tRkt1zhFxkTP9^h+6X)n zqz5A|Ae@qn!HoMZ*=aSIp;Pkx*LC#Zm6pcGv&A#EZAOk=RX_j?RsF!ajAdB5G&Qu- zH}BQZ$O)O$y{C#4f-NiR_{}fWTK*>BhuE`OD%)2UyBz?)0Wf1xxK9hdDC)Z7#%6T- zt>zFgd+4fSnPi$dEOh&9B^nL@&^5#=mBQ`Inj3xe)uMyiTDSd%cFs1z2TxYe)3@xQ zR&jzy0Bj9^m;cmWqU8W!DQgI8gmz^B0z}{N8_?FmEyr;gIwXJt}qdNgmzdG;4J(fz+E(z?YG z{D*~|K%=%6Pqd#lDz-%|3>yne0#IJktYs7B4NRr{A#UA=AbjwqfA(?}&6{3C2lhy< ztnwNQ#t(UjHxy#=y1@xBrvN)kn{H`}9s(MNcuUYgjF+Wokt&C{{s&K0%GCGZ3D(uD zsJ;0CVpZPaTQ6ZD05E}NTG{X3+DMluP+XXDC(V;$rQfTU&JQ{nUmm7)thb{+$U&~&tqDAw{v^;)E z5ahw2n)Iw5J8M8vfR`tK)<1>bn(r-wS9`aB)hXjz#IQL8~**rE2v^uNGqrz zyo(5*<%%A5~l?XK-%980Q7n`zCG8f|9uj&JM9XBo%~ z0^|ADvfk6K9KtPSDY8eA);x<9a!n6s7&JPKMxND83n&$wm_{jG?QJkL9BQK-YwKz2 zmvyw^vsxt{V~6=;3b_MPv@r)% zAJ}6DKQ{vDS2dL_+UjSO+*dCvYSKn7k(;-dk6{}8NHAP}6DvM@XPyX<1l@PiiSP zHxsX|Qj8}f+zdy+7V6kV8)@svQbNoDyP+ZtDc~e9E(WTw_zwE!<*ZT`*4xLD>j=@p s_$r%Kp-?Ck3WY+UP$(1%MF)lGf7Qbh2OGm{`v3p{07*qoM6N<$g4qi<$^ZZW diff --git a/src/RustPlusBot.Features.Map/Composing/MapComposer.cs b/src/RustPlusBot.Features.Map/Composing/MapComposer.cs index 4ae8d104..426a00a2 100644 --- a/src/RustPlusBot.Features.Map/Composing/MapComposer.cs +++ b/src/RustPlusBot.Features.Map/Composing/MapComposer.cs @@ -195,10 +195,15 @@ private async Task> GatherPlayersAsync( if (layers.Players) { var team = await query.GetTeamInfoAsync(guildId, serverId, cancellationToken).ConfigureAwait(false); - foreach (var member in team?.Members ?? []) + // Stable color per player: order by SteamId, index into the palette. SteamId never changes, + // so a player keeps their color across refreshes regardless of online/offline ordering. + var ordered = (team?.Members ?? []).OrderBy(m => m.SteamId).ToList(); + for (var i = 0; i < ordered.Count; i++) { + var member = ordered[i]; var (px, py) = projection.ToPixel(member.X, member.Y); - players.Add(new PlayerPlacement(member.Name, px, py, member.IsAlive, member.IsOnline)); + players.Add(new PlayerPlacement(member.Name, px, py, member.IsAlive, member.IsOnline, + PlayerPalette.For(i).Rgba)); } } diff --git a/src/RustPlusBot.Features.Map/Rendering/MapRenderStyle.cs b/src/RustPlusBot.Features.Map/Rendering/MapRenderStyle.cs index b7c72780..36463341 100644 --- a/src/RustPlusBot.Features.Map/Rendering/MapRenderStyle.cs +++ b/src/RustPlusBot.Features.Map/Rendering/MapRenderStyle.cs @@ -15,8 +15,17 @@ public static class MapRenderStyle /// Cargo-ship icon box edge, in output pixels (slightly larger β€” it is a big target). public const int CargoIconSize = 40; - /// Player icon box edge, in output pixels. - public const int PlayerIconSize = 20; + /// Player cross half-arm length, in output pixels. + public const float PlayerCrossArm = 7f; + + /// Player cross colored-stroke width, in output pixels. + public const float PlayerCrossWidth = 2.5f; + + /// Player cross dark-halo stroke width (drawn under the color for contrast). + public const float PlayerCrossHaloWidth = 4.5f; + + /// Opacity for offline players' crosses. + public const float PlayerOfflineAlpha = 0.5f; /// Trail polyline stroke width, in output pixels (thin, so it reads as a faint hint). public const float TrailWidth = 1.25f; diff --git a/src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs b/src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs index 02d96c6c..6e3147b1 100644 --- a/src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs +++ b/src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs @@ -22,10 +22,8 @@ public sealed class MapRenderer(MonumentIconSource monumentIcons) private const float OutlinePenWidth = 1f; private const float ActiveRingWidth = 3f; - private const float PlayerLabelOffset = 12f; private static readonly FontFamily Family = LoadFamily(); - private static readonly Font Font = Family.CreateFont(12f); private static readonly Font GridLabelFont = Family.CreateFont(MapRenderStyle.GridLabelFontSize); private static FontFamily LoadFamily() @@ -262,43 +260,36 @@ private void DrawRigs(Image image, IReadOnlyList rigs) private static void DrawPlayers(Image image, IReadOnlyList players) { - var icon = MapIcons.Player(MapRenderStyle.PlayerIconSize); - image.Mutate(ctx => { foreach (var player in players) { - DrawPlayerIcon(ctx, player, icon); - DrawPlayerLabel(ctx, player); + DrawPlayerCross(ctx, player); } }); } - private static void DrawPlayerIcon(IImageProcessingContext ctx, PlayerPlacement player, Image? icon) + private static void DrawPlayerCross(IImageProcessingContext ctx, PlayerPlacement player) { - if (icon is null) - { - return; - } - - var isActive = player is { IsAlive: true, IsOnline: true }; - // Dead/offline teammates render dimmed so status reads at a glance (label adds the suffix). - ctx.DrawImage(icon, CenterAt(player.PixelX, player.PixelY, icon), isActive ? 1f : 0.45f); - } - - private static void DrawPlayerLabel(IImageProcessingContext ctx, PlayerPlacement player) - { - var isActive = player is { IsAlive: true, IsOnline: true }; - var suffix = player.IsAlive ? " (offline)" : " (dead)"; - var label = isActive ? player.Name : player.Name + suffix; - var labelColor = isActive ? Color.White : Color.Gray; - var textOptions = new RichTextOptions(Font) - { - Origin = new PointF(player.PixelX, player.PixelY + PlayerLabelOffset), - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Top, - }; - ctx.DrawText(textOptions, label, labelColor); + const float arm = MapRenderStyle.PlayerCrossArm; + var alpha = player.IsOnline ? 1f : MapRenderStyle.PlayerOfflineAlpha; + var color = player.CrossColor.WithAlpha(alpha); + var halo = Color.FromRgba(0, 0, 0, (byte)(180 * alpha)); + + // Alive = '+', dead = 'x'. + var (a1, a2, b1, b2) = player.IsAlive + ? (new PointF(player.PixelX - arm, player.PixelY), new PointF(player.PixelX + arm, player.PixelY), + new PointF(player.PixelX, player.PixelY - arm), new PointF(player.PixelX, player.PixelY + arm)) + : (new PointF(player.PixelX - arm, player.PixelY - arm), + new PointF(player.PixelX + arm, player.PixelY + arm), + new PointF(player.PixelX - arm, player.PixelY + arm), + new PointF(player.PixelX + arm, player.PixelY - arm)); + + // Halo first (wider, dark), then the colored strokes on top. + ctx.DrawLine(halo, MapRenderStyle.PlayerCrossHaloWidth, a1, a2); + ctx.DrawLine(halo, MapRenderStyle.PlayerCrossHaloWidth, b1, b2); + ctx.DrawLine(color, MapRenderStyle.PlayerCrossWidth, a1, a2); + ctx.DrawLine(color, MapRenderStyle.PlayerCrossWidth, b1, b2); } private static Point CenterAt(float x, float y, Image icon) => diff --git a/src/RustPlusBot.Features.Map/Rendering/PlayerPalette.cs b/src/RustPlusBot.Features.Map/Rendering/PlayerPalette.cs new file mode 100644 index 00000000..b28bcd44 --- /dev/null +++ b/src/RustPlusBot.Features.Map/Rendering/PlayerPalette.cs @@ -0,0 +1,35 @@ +using SixLabors.ImageSharp; + +namespace RustPlusBot.Features.Map.Rendering; + +/// One palette entry: the on-map cross color and the matching Discord legend square. +/// The cross color drawn on the map. +/// The colored-square emoji used for this color in the legend. +public readonly record struct PlayerColor(Color Rgba, string Emoji); + +/// +/// The fixed nine-color player palette. Each color's RGB matches its Discord colored-square emoji so +/// an on-map cross and its legend row read as the same color. Players are assigned by stable index +/// (see the composer), wrapping past nine. +/// +public static class PlayerPalette +{ + /// The palette, ordered for maximum distinctiveness in the first slots. + public static IReadOnlyList Entries { get; } = + [ + new(Color.ParseHex("E03131"), "πŸŸ₯"), // red + new(Color.ParseHex("1971C2"), "🟦"), // blue + new(Color.ParseHex("2F9E44"), "🟩"), // green + new(Color.ParseHex("F2CC0C"), "🟨"), // yellow + new(Color.ParseHex("9C36B5"), "πŸŸͺ"), // purple + new(Color.ParseHex("E8590C"), "🟧"), // orange + new(Color.ParseHex("8B5E34"), "🟫"), // brown + new(Color.ParseHex("212529"), "⬛"), // black + new(Color.ParseHex("F1F3F5"), "⬜"), // white + ]; + + /// Gets the palette entry for a zero-based player index, wrapping past the palette length. + /// The stable zero-based player index. + /// The palette entry. + public static PlayerColor For(int index) => Entries[((index % Entries.Count) + Entries.Count) % Entries.Count]; +} diff --git a/src/RustPlusBot.Features.Map/Rendering/PlayerPlacement.cs b/src/RustPlusBot.Features.Map/Rendering/PlayerPlacement.cs index 6a578f3a..40d47a81 100644 --- a/src/RustPlusBot.Features.Map/Rendering/PlayerPlacement.cs +++ b/src/RustPlusBot.Features.Map/Rendering/PlayerPlacement.cs @@ -8,7 +8,14 @@ namespace RustPlusBot.Features.Map.Rendering; /// Pixel Y on the rendered tile. /// Whether the player is alive (dead players are styled differently). /// Whether the player is online. -public sealed record PlayerPlacement(string Name, float PixelX, float PixelY, bool IsAlive, bool IsOnline); +/// The palette color the on-map cross is drawn in. +public sealed record PlayerPlacement( + string Name, + float PixelX, + float PixelY, + bool IsAlive, + bool IsOnline, + SixLabors.ImageSharp.Color CrossColor); /// One monument to draw, already projected to pixel coordinates. /// The monument protobuf token (selects the icon). diff --git a/tests/RustPlusBot.Features.Map.Tests/MapIconsTests.cs b/tests/RustPlusBot.Features.Map.Tests/MapIconsTests.cs index fc9cf2c8..0727162e 100644 --- a/tests/RustPlusBot.Features.Map.Tests/MapIconsTests.cs +++ b/tests/RustPlusBot.Features.Map.Tests/MapIconsTests.cs @@ -12,10 +12,6 @@ public sealed class MapIconsTests public void Marker_resolves_for_known_kinds(MarkerKind kind) => Assert.NotNull(MapIcons.Marker(kind)); - [Fact] - public void Player_resolves_to_vendored_icon() => - Assert.NotNull(MapIcons.Player()); - [Fact] public void Sized_marker_icon_fits_the_requested_box() { @@ -29,7 +25,7 @@ public void Sized_marker_icon_fits_the_requested_box() [Fact] public void Sized_icons_are_cached_per_size() { - Assert.Same(MapIcons.Player(20), MapIcons.Player(20)); - Assert.NotSame(MapIcons.Player(20), MapIcons.Player(24)); + Assert.Same(MapIcons.Marker(MarkerKind.CargoShip, 40), MapIcons.Marker(MarkerKind.CargoShip, 40)); + Assert.NotSame(MapIcons.Marker(MarkerKind.CargoShip, 40), MapIcons.Marker(MarkerKind.CargoShip, 44)); } } diff --git a/tests/RustPlusBot.Features.Map.Tests/MapRendererTests.cs b/tests/RustPlusBot.Features.Map.Tests/MapRendererTests.cs index 157d8bda..28933ef4 100644 --- a/tests/RustPlusBot.Features.Map.Tests/MapRendererTests.cs +++ b/tests/RustPlusBot.Features.Map.Tests/MapRendererTests.cs @@ -100,7 +100,8 @@ public void Render_with_all_layers_produces_valid_png() }; var players = new[] { - new PlayerPlacement("Alice", 300, 300, IsAlive: true, IsOnline: true) + new PlayerPlacement("Alice", 300, 300, IsAlive: true, IsOnline: true, + PlayerPalette.For(0).Rgba) }; var rigs = new[] { @@ -189,4 +190,55 @@ public void Rotation_changes_the_rendered_icon() Assert.False(unrotated.AsSpan().SequenceEqual(rotated)); } + + [Fact] + public void Player_cross_paints_in_the_assigned_color() + { + var renderer = CreateRenderer(); + var projection = new MapProjection(4000, 2000, 2000, 100, MapRenderer.OutputSize); + var baseJpeg = SolidJpeg(2000); + var (px, py) = projection.ToPixel(2000f, 2000f); + var layers = new MapLayerSet(false, false, false, false, true, false); + var red = SixLabors.ImageSharp.Color.ParseHex("E03131"); + + var without = renderer.Render(baseJpeg, projection, [], [], [], [], layers); + var with = renderer.Render(baseJpeg, projection, [], [], + [new PlayerPlacement("A", px, py, IsAlive: true, IsOnline: true, red)], [], layers); + + Assert.False(without.AsSpan().SequenceEqual(with)); + // A red-dominant pixel must appear where the cross was drawn. + using var img = SixLabors.ImageSharp.Image.Load(with); + var found = false; + for (var dy = -8; dy <= 8 && !found; dy++) + { + for (var dx = -8; dx <= 8 && !found; dx++) + { + var p = img[(int)px + dx, (int)py + dy]; + if (p.R > 150 && p.G < 120 && p.B < 120) + { + found = true; + } + } + } + + Assert.True(found, "no red cross pixel near the player position"); + } + + [Fact] + public void Alive_and_dead_players_render_differently() + { + var renderer = CreateRenderer(); + var projection = new MapProjection(4000, 2000, 2000, 100, MapRenderer.OutputSize); + var baseJpeg = SolidJpeg(2000); + var (px, py) = projection.ToPixel(2000f, 2000f); + var layers = new MapLayerSet(false, false, false, false, true, false); + var blue = SixLabors.ImageSharp.Color.ParseHex("1971C2"); + + var alive = renderer.Render(baseJpeg, projection, [], [], + [new PlayerPlacement("A", px, py, IsAlive: true, IsOnline: true, blue)], [], layers); + var dead = renderer.Render(baseJpeg, projection, [], [], + [new PlayerPlacement("A", px, py, IsAlive: false, IsOnline: true, blue)], [], layers); + + Assert.False(alive.AsSpan().SequenceEqual(dead)); // '+' vs 'x' + } } diff --git a/tests/RustPlusBot.Features.Map.Tests/PlayerPaletteTests.cs b/tests/RustPlusBot.Features.Map.Tests/PlayerPaletteTests.cs new file mode 100644 index 00000000..9a4b7fa2 --- /dev/null +++ b/tests/RustPlusBot.Features.Map.Tests/PlayerPaletteTests.cs @@ -0,0 +1,21 @@ +using RustPlusBot.Features.Map.Rendering; + +namespace RustPlusBot.Features.Map.Tests; + +public sealed class PlayerPaletteTests +{ + [Fact] + public void Has_nine_distinct_colors_with_emoji() + { + Assert.Equal(9, PlayerPalette.Entries.Count); + Assert.Equal(9, PlayerPalette.Entries.Select(e => e.Emoji).Distinct().Count()); + Assert.All(PlayerPalette.Entries, e => Assert.False(string.IsNullOrEmpty(e.Emoji))); + } + + [Fact] + public void For_wraps_past_the_palette_length() + { + Assert.Equal(PlayerPalette.For(0), PlayerPalette.For(9)); + Assert.Equal(PlayerPalette.For(1), PlayerPalette.For(10)); + } +} From a867dbc54c5814c1ca3d7754c750b5d14ba4bb14 Mon Sep 17 00:00:00 2001 From: HandyS11 Date: Sat, 11 Jul 2026 22:09:56 +0200 Subject: [PATCH 8/9] feat(map): build a player legend alongside the rendered PNG Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Composing/MapComposer.cs | 67 +++++++----- .../Composing/MapLegend.cs | 16 +++ .../Hosting/MapHostedService.cs | 6 +- .../MapComposerTests.cs | 101 ++++++++++++------ 4 files changed, 130 insertions(+), 60 deletions(-) create mode 100644 src/RustPlusBot.Features.Map/Composing/MapLegend.cs diff --git a/src/RustPlusBot.Features.Map/Composing/MapComposer.cs b/src/RustPlusBot.Features.Map/Composing/MapComposer.cs index 426a00a2..3ad82a97 100644 --- a/src/RustPlusBot.Features.Map/Composing/MapComposer.cs +++ b/src/RustPlusBot.Features.Map/Composing/MapComposer.cs @@ -32,8 +32,8 @@ public sealed class MapComposer( /// The owning guild snowflake. /// The target server id. /// A cancellation token. - /// PNG bytes, or null. - public async Task ComposeAsync(ulong guildId, Guid serverId, CancellationToken cancellationToken) + /// The rendered composition, or null when no base map is available yet. + public async Task ComposeAsync(ulong guildId, Guid serverId, CancellationToken cancellationToken) { // The settings store is scoped (EF context); this composer is a singleton, so we open a scope per // call to resolve it (mirroring MapHostedService.OnConnectionStatusAsync) β€” avoids a captive dependency. @@ -51,7 +51,7 @@ public sealed class MapComposer( .ConfigureAwait(false); } - private async Task ComposeWithLayersAsync( + private async Task ComposeWithLayersAsync( ulong guildId, Guid serverId, MapLayerSet layers, @@ -70,10 +70,12 @@ public sealed class MapComposer( if (dims is null || dims.WorldSize == 0) { // Dimensions unavailable: render the base tile only (every overlay needs worldβ†’pixel). - return renderer.Render(baseImage.Bytes, new MapProjection(0, 1, 1, 0, MapRenderer.OutputSize), - markers: [], monuments: [], players: [], rigs: [], - new MapLayerSet(Grid: false, Markers: false, Monuments: false, Vendor: false, Players: false, - Rigs: false)); + return new MapComposition( + renderer.Render(baseImage.Bytes, new MapProjection(0, 1, 1, 0, MapRenderer.OutputSize), + markers: [], monuments: [], players: [], rigs: [], + new MapLayerSet(Grid: false, Markers: false, Monuments: false, Vendor: false, Players: false, + Rigs: false, Tunnels: false)), + Legend: null); } var projection = new MapProjection(dims.WorldSize, baseImage.PixelWidth, baseImage.PixelHeight, @@ -90,12 +92,13 @@ public sealed class MapComposer( var monuments = GatherMonuments(serverMonuments, projection, layers); var tunnels = GatherTunnels(serverMonuments, projection, layers); - var players = await GatherPlayersAsync(guildId, serverId, projection, layers, cancellationToken) + var (players, legend) = await GatherPlayersAsync(guildId, serverId, projection, layers, cancellationToken) .ConfigureAwait(false); var rigPlacements = GatherRigs(guildId, serverId, serverMonuments, projection, layers); - return renderer.Render(baseImage.Bytes, projection, markers, monuments, players, rigPlacements, layers, + var png = renderer.Render(baseImage.Bytes, projection, markers, monuments, players, rigPlacements, layers, gridStyle, tunnels); + return new MapComposition(png, legend); } private List GatherMarkers( @@ -184,30 +187,46 @@ private static List GatherTunnels( return tunnels; } - private async Task> GatherPlayersAsync( + private async Task<(List Players, MapLegend? Legend)> GatherPlayersAsync( ulong guildId, Guid serverId, MapProjection projection, MapLayerSet layers, CancellationToken cancellationToken) { - var players = new List(); - if (layers.Players) + if (!layers.Players) { - var team = await query.GetTeamInfoAsync(guildId, serverId, cancellationToken).ConfigureAwait(false); - // Stable color per player: order by SteamId, index into the palette. SteamId never changes, - // so a player keeps their color across refreshes regardless of online/offline ordering. - var ordered = (team?.Members ?? []).OrderBy(m => m.SteamId).ToList(); - for (var i = 0; i < ordered.Count; i++) - { - var member = ordered[i]; - var (px, py) = projection.ToPixel(member.X, member.Y); - players.Add(new PlayerPlacement(member.Name, px, py, member.IsAlive, member.IsOnline, - PlayerPalette.For(i).Rgba)); - } + return ([], null); + } + + var team = await query.GetTeamInfoAsync(guildId, serverId, cancellationToken).ConfigureAwait(false); + // Stable color per player: order by SteamId, index into the palette. SteamId never changes, + // so a player keeps their color across refreshes regardless of online/offline ordering. The + // legend is built from the same index so a cross color and its legend row never drift. + var ordered = (team?.Members ?? []).OrderBy(m => m.SteamId).ToList(); + if (ordered.Count == 0) + { + return ([], null); } - return players; + var players = new List(ordered.Count); + var legend = new List(ordered.Count); + for (var i = 0; i < ordered.Count; i++) + { + var member = ordered[i]; + var color = PlayerPalette.For(i); + var (px, py) = projection.ToPixel(member.X, member.Y); + players.Add(new PlayerPlacement(member.Name, px, py, member.IsAlive, member.IsOnline, color.Rgba)); + legend.Add(new MapLegendEntry(color.Emoji, member.Name, StatusText(member))); + } + + return (players, new MapLegend(legend)); + } + + private static string StatusText(TeamMemberSnapshot member) + { + var presence = member.IsOnline ? "online" : "offline"; + return member.IsAlive ? presence : presence + ", dead"; } private List GatherRigs( diff --git a/src/RustPlusBot.Features.Map/Composing/MapLegend.cs b/src/RustPlusBot.Features.Map/Composing/MapLegend.cs new file mode 100644 index 00000000..89df17ef --- /dev/null +++ b/src/RustPlusBot.Features.Map/Composing/MapLegend.cs @@ -0,0 +1,16 @@ +namespace RustPlusBot.Features.Map.Composing; + +/// One legend row: a colored square, the player's name, and their status. +/// The colored-square emoji matching the player's on-map cross color. +/// The player's in-game display name. +/// Human-readable status, e.g. "online" or "offline, dead". +public sealed record MapLegendEntry(string Emoji, string Name, string Status); + +/// The player legend for a rendered map, one entry per teammate. +/// The legend rows, ordered as the crosses were assigned (by SteamId). +public sealed record MapLegend(IReadOnlyList Entries); + +/// A rendered map: the PNG plus its optional player legend. +/// The rendered PNG bytes. +/// The player legend, or null when the Players layer is off or the team is empty. +public sealed record MapComposition(byte[] Png, MapLegend? Legend); diff --git a/src/RustPlusBot.Features.Map/Hosting/MapHostedService.cs b/src/RustPlusBot.Features.Map/Hosting/MapHostedService.cs index 41c0c251..0932b0fb 100644 --- a/src/RustPlusBot.Features.Map/Hosting/MapHostedService.cs +++ b/src/RustPlusBot.Features.Map/Hosting/MapHostedService.cs @@ -191,13 +191,13 @@ private async Task RefreshAsync(ulong guildId, Guid serverId, CancellationToken return; } - var png = await _composer.ComposeAsync(guildId, serverId, cancellationToken).ConfigureAwait(false); - if (png is null) + var composition = await _composer.ComposeAsync(guildId, serverId, cancellationToken).ConfigureAwait(false); + if (composition is null) { return; } - await _poster.PostAsync(id, png, cancellationToken).ConfigureAwait(false); + await _poster.PostAsync(id, composition.Png, cancellationToken).ConfigureAwait(false); } private async Task ConsumeConnectionStatusEventsAsync(CancellationToken cancellationToken) diff --git a/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs b/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs index b087b7e9..fe84a1ee 100644 --- a/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs +++ b/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs @@ -83,9 +83,9 @@ public async Task ComposeAsync_returns_null_when_no_base_map() var composer = Build(baseImage: null, Dims, NewQuery(), NewEvents(), NewRigs(), NewSettings(MapLayerSettings.AllOn)); - var png = await composer.ComposeAsync(Guild, Server, CancellationToken.None); + var result = await composer.ComposeAsync(Guild, Server, CancellationToken.None); - Assert.Null(png); + Assert.Null(result); } [Fact] @@ -96,11 +96,11 @@ public async Task Renders_a_png_when_base_map_available() var composer = Build(BaseJpeg(), Dims, NewQuery(), NewEvents(marker), NewRigs(), NewSettings(MapLayerSettings.AllOn)); - var png = await composer.ComposeAsync(Guild, Server, CancellationToken.None); + var result = await composer.ComposeAsync(Guild, Server, CancellationToken.None); - Assert.NotNull(png); - using var result = Image.Load(png!); - Assert.Equal(MapRenderer.OutputSize, result.Width); + Assert.NotNull(result); + using var image = Image.Load(result!.Png); + Assert.Equal(MapRenderer.OutputSize, image.Width); } [Fact] @@ -111,11 +111,11 @@ public async Task Renders_base_only_when_dimensions_unavailable() [new TrailPoint(2000f, 2000f)], null)), NewRigs(), NewSettings(MapLayerSettings.AllOn)); - var png = await composer.ComposeAsync(Guild, Server, CancellationToken.None); + var result = await composer.ComposeAsync(Guild, Server, CancellationToken.None); - Assert.NotNull(png); - using var result = Image.Load(png!); - Assert.Equal(MapRenderer.OutputSize, result.Width); + Assert.NotNull(result); + using var image = Image.Load(result!.Png); + Assert.Equal(MapRenderer.OutputSize, image.Width); } [Fact] @@ -133,9 +133,9 @@ public async Task ComposeAsync_renders_only_enabled_layers() var composer = Build(BaseJpeg(), Dims, query, events, NewRigs(), settings); - var png = await composer.ComposeAsync(Guild, Server, CancellationToken.None); + var result = await composer.ComposeAsync(Guild, Server, CancellationToken.None); - Assert.NotNull(png); + Assert.NotNull(result); // Monuments + Rigs both disabled -> no monument round-trip at all. await query.DidNotReceive().GetMonumentsAsync(Guild, Server, Arg.Any()); // Players enabled -> the team seam was consulted. @@ -150,20 +150,21 @@ public async Task Tunnel_tokens_render_under_the_tunnels_layer_not_the_monuments // - baseOnly: Monuments off, Tunnels off -> tunnel token never drawn (bare base render) // - monumentsOnly: Monuments on, Tunnels off -> tunnel token EXCLUDED from the monuments pass // - tunnelsOnly: Monuments off, Tunnels on -> tunnel token drawn via the tunnels pass - var basePng = await ComposeTunnelScenarioAsync(monuments: false, tunnels: false); - var monPng = await ComposeTunnelScenarioAsync(monuments: true, tunnels: false); - var tunPng = await ComposeTunnelScenarioAsync(monuments: false, tunnels: true); + var baseResult = await ComposeTunnelScenarioAsync(monuments: false, tunnels: false); + var monResult = await ComposeTunnelScenarioAsync(monuments: true, tunnels: false); + var tunResult = await ComposeTunnelScenarioAsync(monuments: false, tunnels: true); - Assert.NotNull(basePng); - Assert.NotNull(monPng); - Assert.NotNull(tunPng); + Assert.NotNull(baseResult); + Assert.NotNull(monResult); + Assert.NotNull(tunResult); // Monuments layer must NOT draw the tunnel token -> identical to the bare base render. - Assert.True(monPng!.SequenceEqual(basePng!), "tunnel token must be excluded from the Monuments pass"); + Assert.True(monResult!.Png.SequenceEqual(baseResult!.Png), + "tunnel token must be excluded from the Monuments pass"); // Tunnels layer MUST draw the tunnel token -> differs from the bare base render. - Assert.False(tunPng!.SequenceEqual(basePng!), "tunnel token must render under the Tunnels layer"); + Assert.False(tunResult!.Png.SequenceEqual(baseResult!.Png), "tunnel token must render under the Tunnels layer"); } - private static async Task ComposeTunnelScenarioAsync(bool monuments, bool tunnels) + private static async Task ComposeTunnelScenarioAsync(bool monuments, bool tunnels) { var query = NewQuery(); query.GetMonumentsAsync(Guild, Server, Arg.Any()) @@ -190,9 +191,9 @@ public async Task ComposeAsync_uses_all_on_when_no_settings_row() var composer = Build(BaseJpeg(), Dims, query, events, NewRigs(), NewSettings(MapLayerSettings.AllOn)); - var png = await composer.ComposeAsync(Guild, Server, CancellationToken.None); + var result = await composer.ComposeAsync(Guild, Server, CancellationToken.None); - Assert.NotNull(png); + Assert.NotNull(result); await query.Received().GetMonumentsAsync(Guild, Server, Arg.Any()); await query.Received().GetTeamInfoAsync(Guild, Server, Arg.Any()); } @@ -212,13 +213,13 @@ public async Task Renders_the_grid_even_with_no_markers() NewSettings(new MapLayerSettings( Grid: false, Markers: true, Monuments: false, Vendor: false, Players: false, Rigs: false))); - var pngOn = await composerOn.ComposeAsync(Guild, Server, CancellationToken.None); - var pngOff = await composerOff.ComposeAsync(Guild, Server, CancellationToken.None); + var resultOn = await composerOn.ComposeAsync(Guild, Server, CancellationToken.None); + var resultOff = await composerOff.ComposeAsync(Guild, Server, CancellationToken.None); - Assert.NotNull(pngOn); - Assert.NotNull(pngOff); + Assert.NotNull(resultOn); + Assert.NotNull(resultOff); // The grid layer must have painted at least one pixel differently. - Assert.False(pngOn!.SequenceEqual(pngOff!), "Grid-on and grid-off renders must differ."); + Assert.False(resultOn!.Png.SequenceEqual(resultOff!.Png), "Grid-on and grid-off renders must differ."); } [Fact] @@ -239,17 +240,51 @@ public async Task ComposeAsync_forwards_vendor_marker_history_into_rendered_trai var composerNoTrail = Build(jpeg, Dims, NewQuery(), NewEvents(vendorNoTrail), NewRigs(), NewSettings(layers)); - var pngWithTrail = await composerWithTrail.ComposeAsync(Guild, Server, CancellationToken.None); - var pngNoTrail = await composerNoTrail.ComposeAsync(Guild, Server, CancellationToken.None); + var resultWithTrail = await composerWithTrail.ComposeAsync(Guild, Server, CancellationToken.None); + var resultNoTrail = await composerNoTrail.ComposeAsync(Guild, Server, CancellationToken.None); - Assert.NotNull(pngWithTrail); - Assert.NotNull(pngNoTrail); + Assert.NotNull(resultWithTrail); + Assert.NotNull(resultNoTrail); // MapRenderer.DrawTrails only paints when Trail.Count >= 2, so a 2-point History must render // differently from a 1-point History β€” proving the history ring made it through to the trail. - Assert.False(pngWithTrail!.SequenceEqual(pngNoTrail!), + Assert.False(resultWithTrail!.Png.SequenceEqual(resultNoTrail!.Png), "Vendor trail with 2-point history must render differently than a 1-point history."); } + [Fact] + public async Task ComposeAsync_builds_a_legend_entry_per_player() + { + var query = NewQuery(); + query.GetTeamInfoAsync(Guild, Server, Arg.Any()) + .Returns(new TeamInfoSnapshot(0, + [ + new TeamMemberSnapshot(20, "Bob", 2000f, 2000f, IsOnline: false, IsAlive: false, default, default), + new TeamMemberSnapshot(10, "Ada", 2000f, 2000f, IsOnline: true, IsAlive: true, default, default), + ])); + var composer = Build(BaseJpeg(), Dims, query, NewEvents(), NewRigs(), + NewSettings(MapLayerSettings.AllOn)); + + var result = await composer.ComposeAsync(Guild, Server, CancellationToken.None); + + Assert.NotNull(result); + Assert.NotNull(result!.Legend); + // Ordered by SteamId: Ada (10) first, Bob (20) second. + Assert.Collection(result.Legend!.Entries, + e => + { + Assert.Equal("Ada", e.Name); + Assert.Equal("online", e.Status); + }, + e => + { + Assert.Equal("Bob", e.Name); + Assert.Equal("offline, dead", e.Status); + }); + // Ada gets palette[0], Bob palette[1]. + Assert.Equal(PlayerPalette.For(0).Emoji, result.Legend.Entries[0].Emoji); + Assert.Equal(PlayerPalette.For(1).Emoji, result.Legend.Entries[1].Emoji); + } + private sealed class FakeSource(BaseMapImage? result) : IBaseMapSource { public Task GetAsync(ulong guildId, Guid serverId, CancellationToken cancellationToken) => From 73e1553d0490c041a47b1e1e29f6021e7233246f Mon Sep 17 00:00:00 2001 From: HandyS11 Date: Sat, 11 Jul 2026 22:19:05 +0200 Subject: [PATCH 9/9] feat(map): attach the player legend as an embed on the map image Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Hosting/MapHostedService.cs | 2 +- .../Posting/DiscordMapChannelPoster.cs | 10 ++++-- .../Posting/IMapChannelPoster.cs | 5 ++- .../Posting/MapLegendEmbed.cs | 32 +++++++++++++++++++ .../MapLegendEmbedTests.cs | 32 +++++++++++++++++++ 5 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 src/RustPlusBot.Features.Map/Posting/MapLegendEmbed.cs create mode 100644 tests/RustPlusBot.Features.Map.Tests/MapLegendEmbedTests.cs diff --git a/src/RustPlusBot.Features.Map/Hosting/MapHostedService.cs b/src/RustPlusBot.Features.Map/Hosting/MapHostedService.cs index 0932b0fb..949a0a01 100644 --- a/src/RustPlusBot.Features.Map/Hosting/MapHostedService.cs +++ b/src/RustPlusBot.Features.Map/Hosting/MapHostedService.cs @@ -197,7 +197,7 @@ private async Task RefreshAsync(ulong guildId, Guid serverId, CancellationToken return; } - await _poster.PostAsync(id, composition.Png, cancellationToken).ConfigureAwait(false); + await _poster.PostAsync(id, composition.Png, composition.Legend, cancellationToken).ConfigureAwait(false); } private async Task ConsumeConnectionStatusEventsAsync(CancellationToken cancellationToken) diff --git a/src/RustPlusBot.Features.Map/Posting/DiscordMapChannelPoster.cs b/src/RustPlusBot.Features.Map/Posting/DiscordMapChannelPoster.cs index 9af64031..85954eea 100644 --- a/src/RustPlusBot.Features.Map/Posting/DiscordMapChannelPoster.cs +++ b/src/RustPlusBot.Features.Map/Posting/DiscordMapChannelPoster.cs @@ -1,6 +1,7 @@ using Discord; using Discord.WebSocket; using Microsoft.Extensions.Logging; +using RustPlusBot.Features.Map.Composing; namespace RustPlusBot.Features.Map.Posting; @@ -15,7 +16,10 @@ internal sealed partial class DiscordMapChannelPoster( private const int RecentMessageScan = 10; /// - public async Task PostAsync(ulong channelId, byte[] pngBytes, CancellationToken cancellationToken) + public async Task PostAsync(ulong channelId, + byte[] pngBytes, + MapLegend? legend, + CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(pngBytes); try @@ -47,8 +51,8 @@ public async Task PostAsync(ulong channelId, byte[] pngBytes, CancellationToken var stream = new MemoryStream(pngBytes); await using (stream.ConfigureAwait(false)) { - await channel.SendFileAsync(stream, "map.png", options: options, allowedMentions: AllowedMentions.None) - .ConfigureAwait(false); + await channel.SendFileAsync(stream, "map.png", embed: MapLegendEmbed.Build(legend), + options: options, allowedMentions: AllowedMentions.None).ConfigureAwait(false); } } catch (OperationCanceledException) diff --git a/src/RustPlusBot.Features.Map/Posting/IMapChannelPoster.cs b/src/RustPlusBot.Features.Map/Posting/IMapChannelPoster.cs index 416e762d..1b19a242 100644 --- a/src/RustPlusBot.Features.Map/Posting/IMapChannelPoster.cs +++ b/src/RustPlusBot.Features.Map/Posting/IMapChannelPoster.cs @@ -1,3 +1,5 @@ +using RustPlusBot.Features.Map.Composing; + namespace RustPlusBot.Features.Map.Posting; /// Posts the rendered map image to a Discord channel, replacing the prior bot message. @@ -6,7 +8,8 @@ internal interface IMapChannelPoster /// Deletes the bot's prior map message (if any) and posts the new PNG. /// The #map channel id. /// The rendered PNG. + /// The player legend to attach as an embed, or null when there is none. /// A cancellation token. /// A task that completes when the post is issued. - Task PostAsync(ulong channelId, byte[] pngBytes, CancellationToken cancellationToken); + Task PostAsync(ulong channelId, byte[] pngBytes, MapLegend? legend, CancellationToken cancellationToken); } diff --git a/src/RustPlusBot.Features.Map/Posting/MapLegendEmbed.cs b/src/RustPlusBot.Features.Map/Posting/MapLegendEmbed.cs new file mode 100644 index 00000000..4de65afe --- /dev/null +++ b/src/RustPlusBot.Features.Map/Posting/MapLegendEmbed.cs @@ -0,0 +1,32 @@ +using System.Globalization; +using System.Text; +using Discord; +using RustPlusBot.Features.Map.Composing; + +namespace RustPlusBot.Features.Map.Posting; + +/// Builds the Discord legend embed for a rendered map's players (color square, name, status). +public static class MapLegendEmbed +{ + /// Builds the legend embed, or null when there is nothing to show. + /// The legend, or null. + /// An embed, or null when the legend is null or empty. + public static Embed? Build(MapLegend? legend) + { + if (legend is null || legend.Entries.Count == 0) + { + return null; + } + + var description = new StringBuilder(); + foreach (var entry in legend.Entries) + { + description.Append(CultureInfo.InvariantCulture, $"{entry.Emoji} **{entry.Name}** β€” {entry.Status}") + .Append('\n'); + } + + return new EmbedBuilder() + .WithDescription(description.ToString().TrimEnd('\n')) + .Build(); + } +} diff --git a/tests/RustPlusBot.Features.Map.Tests/MapLegendEmbedTests.cs b/tests/RustPlusBot.Features.Map.Tests/MapLegendEmbedTests.cs new file mode 100644 index 00000000..e1600058 --- /dev/null +++ b/tests/RustPlusBot.Features.Map.Tests/MapLegendEmbedTests.cs @@ -0,0 +1,32 @@ +using RustPlusBot.Features.Map.Composing; +using RustPlusBot.Features.Map.Posting; + +namespace RustPlusBot.Features.Map.Tests; + +public sealed class MapLegendEmbedTests +{ + [Fact] + public void Build_returns_null_for_no_legend() + { + Assert.Null(MapLegendEmbed.Build(null)); + Assert.Null(MapLegendEmbed.Build(new MapLegend([]))); + } + + [Fact] + public void Build_lists_one_line_per_player() + { + var legend = new MapLegend( + [ + new MapLegendEntry("πŸŸ₯", "Ada", "online"), + new MapLegendEntry("🟦", "Bob", "offline, dead"), + ]); + + var embed = MapLegendEmbed.Build(legend); + + Assert.NotNull(embed); + Assert.Contains("Ada", embed!.Description, StringComparison.Ordinal); + Assert.Contains("online", embed.Description, StringComparison.Ordinal); + Assert.Contains("Bob", embed.Description, StringComparison.Ordinal); + Assert.Contains("🟦", embed.Description, StringComparison.Ordinal); + } +}