mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2026-08-15 13:04:36 +00:00
191 lines
7.8 KiB
C#
191 lines
7.8 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// Maps block Materials to minimap colors using data extracted from Minecraft's
|
|
/// official MapColor table. Colors are loaded from the embedded MinimapBlockColors.json
|
|
/// resource generated by tools/gen_block_color_map.py.
|
|
/// </summary>
|
|
public static class MinimapColorMap
|
|
{
|
|
public static readonly Color WaterColor = Color.FromRgb(64, 64, 255);
|
|
public static readonly Color IceColor = Color.FromRgb(160, 160, 255);
|
|
public static readonly Color LavaColor = Color.FromRgb(255, 100, 0);
|
|
public static readonly Color DefaultColor = Color.FromRgb(60, 60, 60);
|
|
public static readonly Color VoidColor = Color.FromRgb(0, 0, 0);
|
|
public static readonly Color CaveBorderColor = Color.FromRgb(16, 16, 16);
|
|
public static readonly Color CaveSolidColor = Color.FromRgb(24, 20, 18);
|
|
|
|
private static readonly FrozenDictionary<Material, Color> ColorTable;
|
|
private static readonly FrozenSet<Material> FullyTransparentMats;
|
|
private static readonly FrozenSet<Material> WaterMats;
|
|
private static readonly FrozenSet<Material> IceMats;
|
|
|
|
static MinimapColorMap()
|
|
{
|
|
var colors = new Dictionary<Material, Color>();
|
|
var transparent = new HashSet<Material>();
|
|
var water = new HashSet<Material>();
|
|
var ice = new HashSet<Material>();
|
|
|
|
try
|
|
{
|
|
using var stream = Assembly.GetExecutingAssembly()
|
|
.GetManifestResourceStream("MinimapBlockColors.json");
|
|
if (stream is not null)
|
|
{
|
|
using var doc = JsonDocument.Parse(stream);
|
|
var root = doc.RootElement;
|
|
|
|
if (root.TryGetProperty("colors", out var colorsEl))
|
|
{
|
|
foreach (var prop in colorsEl.EnumerateObject())
|
|
{
|
|
if (!Enum.TryParse<Material>(prop.Name, out var mat))
|
|
continue;
|
|
var arr = prop.Value;
|
|
if (arr.GetArrayLength() < 3) continue;
|
|
byte r = (byte)arr[0].GetInt32();
|
|
byte g = (byte)arr[1].GetInt32();
|
|
byte b = (byte)arr[2].GetInt32();
|
|
colors[mat] = Color.FromRgb(r, g, b);
|
|
}
|
|
}
|
|
|
|
if (root.TryGetProperty("transparent", out var transEl))
|
|
{
|
|
foreach (var item in transEl.EnumerateArray())
|
|
{
|
|
if (Enum.TryParse<Material>(item.GetString(), out var mat))
|
|
transparent.Add(mat);
|
|
}
|
|
}
|
|
|
|
if (root.TryGetProperty("water", out var waterEl))
|
|
{
|
|
foreach (var item in waterEl.EnumerateArray())
|
|
{
|
|
if (Enum.TryParse<Material>(item.GetString(), out var mat))
|
|
water.Add(mat);
|
|
}
|
|
}
|
|
|
|
if (root.TryGetProperty("ice", out var iceEl))
|
|
{
|
|
foreach (var item in iceEl.EnumerateArray())
|
|
{
|
|
if (Enum.TryParse<Material>(item.GetString(), out var mat))
|
|
ice.Add(mat);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ConsoleIO.WriteLineFormatted($"\u00a7e[Minimap] Failed to load color data: {ex.Message}");
|
|
}
|
|
|
|
if (transparent.Count == 0)
|
|
{
|
|
transparent.Add(Material.Air);
|
|
transparent.Add(Material.CaveAir);
|
|
transparent.Add(Material.VoidAir);
|
|
}
|
|
if (water.Count == 0)
|
|
water.Add(Material.Water);
|
|
if (ice.Count == 0)
|
|
{
|
|
ice.Add(Material.Ice);
|
|
ice.Add(Material.PackedIce);
|
|
ice.Add(Material.BlueIce);
|
|
ice.Add(Material.FrostedIce);
|
|
}
|
|
|
|
ColorTable = colors.ToFrozenDictionary();
|
|
FullyTransparentMats = transparent.ToFrozenSet();
|
|
WaterMats = water.ToFrozenSet();
|
|
IceMats = ice.ToFrozenSet();
|
|
}
|
|
|
|
public static bool IsFullyTransparent(Material m) => FullyTransparentMats.Contains(m);
|
|
|
|
/// <summary>
|
|
/// Returns true for materials that block light propagation (solid, liquids),
|
|
/// used by cave mode to find the surface from the player's Y level.
|
|
/// Mirrors VoxelMap's lightDampening > 0 check.
|
|
/// </summary>
|
|
public static bool IsLightBlocking(Material m)
|
|
=> (m == Material.Lava) || (!FullyTransparentMats.Contains(m) && m.IsSolid());
|
|
|
|
public static bool IsWater(Material m) => WaterMats.Contains(m);
|
|
|
|
public static bool IsIce(Material m) => IceMats.Contains(m);
|
|
|
|
public static Color GetBaseColor(Material m)
|
|
{
|
|
if (m == Material.Lava)
|
|
return LavaColor;
|
|
return ColorTable.GetValueOrDefault(m, DefaultColor);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Apply Minecraft-style height shading. The shade multiplier depends on
|
|
/// the height difference between the current block and the block to its north.
|
|
/// Vanilla maps use four brightness levels: LOW (180/255), NORMAL (220/255),
|
|
/// HIGH (255/255), and LOWEST (135/255). We use NORMAL as baseline and shift
|
|
/// up/down based on delta.
|
|
/// </summary>
|
|
public static Color ApplyHeightShade(Color baseColor, int heightDelta)
|
|
{
|
|
int multiplier = heightDelta switch
|
|
{
|
|
> 0 => 255, // higher than neighbor: brightest
|
|
0 => 220, // same height: normal
|
|
_ => 180, // lower than neighbor: darker
|
|
};
|
|
byte r = (byte)(baseColor.R * multiplier / 255);
|
|
byte g = (byte)(baseColor.G * multiplier / 255);
|
|
byte b = (byte)(baseColor.B * multiplier / 255);
|
|
return Color.FromRgb(r, g, b);
|
|
}
|
|
|
|
public static Color BlendWaterColor(Color bottomColor, int waterDepth)
|
|
{
|
|
double alpha = Math.Min(0.85, 0.35 + waterDepth * 0.08);
|
|
return Blend(WaterColor, bottomColor, alpha);
|
|
}
|
|
|
|
public static Color BlendIceColor(Color bottomColor)
|
|
{
|
|
return Blend(IceColor, bottomColor, 0.35);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Darken a color to simulate underground lighting. Cave floors receive
|
|
/// a minimum brightness of ~32/255 for non-solid blocks (matching VoxelMap),
|
|
/// while solid/unreachable columns render as near-black.
|
|
/// </summary>
|
|
public static Color ApplyCaveDarkening(Color baseColor, double factor = 0.55)
|
|
{
|
|
byte r = (byte)(baseColor.R * factor);
|
|
byte g = (byte)(baseColor.G * factor);
|
|
byte b = (byte)(baseColor.B * factor);
|
|
return Color.FromRgb(r, g, b);
|
|
}
|
|
|
|
private static Color Blend(Color top, Color bottom, double topAlpha)
|
|
{
|
|
byte r = (byte)(top.R * topAlpha + bottom.R * (1.0 - topAlpha));
|
|
byte g = (byte)(top.G * topAlpha + bottom.G * (1.0 - topAlpha));
|
|
byte b = (byte)(top.B * topAlpha + bottom.B * (1.0 - topAlpha));
|
|
return Color.FromRgb(r, g, b);
|
|
}
|
|
}
|
|
}
|