using System; using System.Collections.Frozen; using System.Collections.Generic; using System.Reflection; using System.Text.Json; using Avalonia.Media; using MinecraftClient.Mapping; namespace MinecraftClient.Tui { public enum MobCategory { Hostile, Passive, Neutral, Player, NonLiving, } public enum MinimapPosition { top_left, top_right, center, bottom_left, bottom_right, } public sealed class NameDisplayConfig { public volatile bool Players = false; public volatile bool Hostile = false; public volatile bool Neutral = false; public volatile bool Passive = false; public bool AnyEnabled => Players || Hostile || Neutral || Passive; public void SetAll(bool value) { Players = value; Hostile = value; Neutral = value; Passive = value; } public bool ShouldShowName(MobCategory category) => category switch { MobCategory.Player => Players, MobCategory.Hostile => Hostile, MobCategory.Neutral => Neutral, MobCategory.Passive => Passive, _ => false, }; } /// /// Classifies entities into minimap categories using data extracted from /// Minecraft's MobCategory assignments. Categories are loaded from the /// embedded MinimapEntityCategories.json resource generated by /// tools/gen_entity_category_map.py. /// public static class MinimapEntityClassifier { public static readonly Color HostileColor = Color.FromRgb(255, 68, 68); public static readonly Color PassiveColor = Color.FromRgb(68, 255, 68); public static readonly Color NeutralColor = Color.FromRgb(255, 170, 0); public static readonly Color PlayerColor = Color.FromRgb(255, 255, 255); public static readonly Color FadedGray = Color.FromRgb(100, 100, 100); private static readonly FrozenDictionary CategoryTable; static MinimapEntityClassifier() { var table = new Dictionary(); try { using var stream = Assembly.GetExecutingAssembly() .GetManifestResourceStream("MinimapEntityCategories.json"); if (stream is not null) { using var doc = JsonDocument.Parse(stream); var root = doc.RootElement; LoadCategory(root, "hostile", MobCategory.Hostile, table); LoadCategory(root, "passive", MobCategory.Passive, table); LoadCategory(root, "neutral", MobCategory.Neutral, table); LoadCategory(root, "non_living", MobCategory.NonLiving, table); } } catch (Exception ex) { ConsoleIO.WriteLogLine($"[Minimap] Failed to load entity categories: {ex.Message}"); } CategoryTable = table.ToFrozenDictionary(); } private static void LoadCategory(JsonElement root, string key, MobCategory category, Dictionary table) { if (!root.TryGetProperty(key, out var arr)) return; foreach (var el in arr.EnumerateArray()) { var name = el.GetString(); if (name is not null && Enum.TryParse(name, out var et)) table.TryAdd(et, category); } } public static MobCategory Classify(EntityType type) { if (type == EntityType.Player) return MobCategory.Player; return CategoryTable.GetValueOrDefault(type, MobCategory.NonLiving); } public static Color GetBaseColor(MobCategory category) => category switch { MobCategory.Hostile => HostileColor, MobCategory.Passive => PassiveColor, MobCategory.Neutral => NeutralColor, MobCategory.Player => PlayerColor, _ => FadedGray, }; public static Color ApplyDepthFade(Color baseColor, double playerY, double entityY) { double depth = playerY - entityY; if (depth <= 5.0) return baseColor; if (depth >= 15.0) return FadedGray; double t = (depth - 5.0) / 10.0; return Lerp(baseColor, FadedGray, t); } public static bool ShouldDisplay(MobCategory category, double playerY, double entityY) { if (category == MobCategory.Player) return true; if (entityY >= playerY) return true; return playerY - entityY <= 15.0; } public static int GetPriority(MobCategory category) => category switch { MobCategory.Hostile => 4, MobCategory.Player => 3, MobCategory.Neutral => 2, MobCategory.Passive => 1, _ => 0, }; public static string GetCategoryLabel(MobCategory category) => category switch { MobCategory.Hostile => Translations.tui_minimap_legend_hostile, MobCategory.Passive => Translations.tui_minimap_legend_passive, MobCategory.Neutral => Translations.tui_minimap_legend_neutral, MobCategory.Player => Translations.tui_minimap_legend_player, _ => "?", }; private static Color Lerp(Color a, Color b, double t) { byte r = (byte)(a.R + (b.R - a.R) * t); byte g = (byte)(a.G + (b.G - a.G) * t); byte bl = (byte)(a.B + (b.B - a.B) * t); return Color.FromRgb(r, g, bl); } } }