Minecraft-Console-Client/MinecraftClient/Tui/MinimapEntityClassifier.cs

179 lines
5.8 KiB
C#
Raw Normal View History

2026-03-29 18:47:40 +08:00
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,
};
}
/// <summary>
/// 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.
/// </summary>
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<EntityType, MobCategory> CategoryTable;
static MinimapEntityClassifier()
{
var table = new Dictionary<EntityType, MobCategory>();
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<EntityType, MobCategory> 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<EntityType>(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);
}
}
}