339 lines
9.9 KiB
Lua
339 lines
9.9 KiB
Lua
-- Node Color Mapping System for Luanti
|
|
-- Dynamically generates colors based on node properties, keywords, and groups
|
|
|
|
local nodecolors = {}
|
|
|
|
-- ============================================================================
|
|
-- COLOR PALETTE - 16 base colors for all terrain types
|
|
-- ============================================================================
|
|
local PALETTE = {
|
|
GRASS_GREEN = {95, 159, 53},
|
|
DIRT_BROWN = {134, 96, 67},
|
|
STONE_GRAY = {128, 128, 128},
|
|
SAND_TAN = {194, 178, 128},
|
|
DESERT_SAND = {210, 180, 140},
|
|
WATER_BLUE = {38, 92, 255},
|
|
SNOW_WHITE = {240, 240, 240},
|
|
ICE_BLUE = {175, 210, 255},
|
|
TREE_BROWN = {101, 84, 50},
|
|
LEAVES_GREEN = {60, 100, 30},
|
|
LAVA_ORANGE = {255, 100, 0},
|
|
COAL_BLACK = {64, 64, 64},
|
|
IRON_GRAY = {140, 120, 110},
|
|
GOLD_YELLOW = {220, 180, 50},
|
|
GRAVEL_GRAY = {136, 126, 126},
|
|
DEFAULT_GRAY = {100, 100, 100}
|
|
}
|
|
|
|
-- ============================================================================
|
|
-- MANUAL OVERRIDES - Highest priority, exact node name matches
|
|
-- ============================================================================
|
|
local manual_overrides = {
|
|
-- Special cases that don't fit auto-detection well
|
|
["default:apple"] = PALETTE.GOLD_YELLOW,
|
|
["mcl_core:obsidian"] = {20, 10, 30},
|
|
["mcl_core:bedrock"] = {40, 40, 40},
|
|
["mcl_nether:netherrack"] = {100, 50, 50},
|
|
["mcl_nether:soul_sand"] = {80, 70, 60},
|
|
["mcl_end:end_stone"] = {220, 220, 180},
|
|
["nc_fire:ash"] = {80, 80, 80},
|
|
["nc_concrete:concrete"] = {160, 160, 160},
|
|
}
|
|
|
|
-- ============================================================================
|
|
-- KEYWORD DETECTION - Pattern matching in node names
|
|
-- ============================================================================
|
|
local keyword_colors = {
|
|
-- Grass and vegetation
|
|
{pattern = "grass", color = PALETTE.GRASS_GREEN},
|
|
{pattern = "turf", color = PALETTE.GRASS_GREEN},
|
|
{pattern = "tallgrass", color = PALETTE.GRASS_GREEN},
|
|
{pattern = "sedge", color = PALETTE.GRASS_GREEN},
|
|
-- Dirt and soil
|
|
{pattern = "dirt", color = PALETTE.DIRT_BROWN},
|
|
{pattern = "soil", color = PALETTE.DIRT_BROWN},
|
|
{pattern = "podzol", color = {90, 70, 50}},
|
|
{pattern = "coarse_dirt", color = {120, 85, 60}},
|
|
{pattern = "mycelium", color = {110, 90, 110}},
|
|
{pattern = "clay", color = {160, 160, 180}},
|
|
|
|
-- Stone types
|
|
{pattern = "stone", color = PALETTE.STONE_GRAY},
|
|
{pattern = "cobble", color = PALETTE.DEFAULT_GRAY},
|
|
{pattern = "mossycobble", color = {80, 120, 80}},
|
|
{pattern = "granite", color = {150, 100, 80}},
|
|
{pattern = "andesite", color = {130, 130, 130}},
|
|
{pattern = "diorite", color = {180, 180, 180}},
|
|
{pattern = "annealed", color = {150, 150, 150}},
|
|
{pattern = "pumice", color = {200, 190, 180}},
|
|
{pattern = "lode", color = {110, 110, 110}},
|
|
|
|
-- Sand and desert
|
|
{pattern = "sand", color = PALETTE.SAND_TAN},
|
|
{pattern = "redsand", color = PALETTE.DESERT_SAND},
|
|
{pattern = "desert", color = PALETTE.DESERT_SAND},
|
|
|
|
-- Water
|
|
{pattern = "water", color = PALETTE.WATER_BLUE},
|
|
{pattern = "river_water", color = {20, 100, 200}},
|
|
|
|
-- Snow and ice
|
|
{pattern = "snow", color = PALETTE.SNOW_WHITE},
|
|
{pattern = "ice", color = PALETTE.ICE_BLUE},
|
|
{pattern = "packed_ice", color = {160, 200, 255}},
|
|
|
|
-- Trees and wood
|
|
{pattern = "tree", color = PALETTE.TREE_BROWN},
|
|
{pattern = "trunk", color = PALETTE.TREE_BROWN},
|
|
{pattern = "bark", color = {90, 70, 45}},
|
|
{pattern = "root", color = {80, 60, 40}},
|
|
{pattern = "log", color = PALETTE.TREE_BROWN},
|
|
{pattern = "wood", color = PALETTE.TREE_BROWN},
|
|
|
|
-- Specific tree types
|
|
{pattern = "pine", color = {85, 70, 45}},
|
|
{pattern = "spruce", color = {85, 70, 45}},
|
|
{pattern = "jungle", color = {120, 90, 50}},
|
|
{pattern = "birch", color = {220, 220, 180}},
|
|
{pattern = "acacia", color = {160, 100, 60}},
|
|
{pattern = "dark", color = {60, 40, 20}},
|
|
|
|
-- Leaves
|
|
{pattern = "leaves", color = PALETTE.LEAVES_GREEN},
|
|
{pattern = "needles", color = {45, 80, 25}},
|
|
{pattern = "jungleleaves", color = {50, 90, 30}},
|
|
{pattern = "birchleaves", color = {80, 120, 50}},
|
|
{pattern = "acacialeaves", color = {90, 110, 40}},
|
|
{pattern = "darkleaves", color = {40, 70, 20}},
|
|
|
|
-- Ores
|
|
{pattern = "coal", color = PALETTE.COAL_BLACK},
|
|
{pattern = "iron", color = PALETTE.IRON_GRAY},
|
|
{pattern = "copper", color = {180, 120, 80}},
|
|
{pattern = "gold", color = PALETTE.GOLD_YELLOW},
|
|
{pattern = "diamond", color = {100, 200, 255}},
|
|
{pattern = "emerald", color = {50, 200, 100}},
|
|
{pattern = "lapis", color = {50, 100, 200}},
|
|
{pattern = "redstone", color = {200, 50, 50}},
|
|
|
|
-- Lava and gravel
|
|
{pattern = "lava", color = PALETTE.LAVA_ORANGE},
|
|
{pattern = "gravel", color = PALETTE.GRAVEL_GRAY},
|
|
|
|
-- Flora
|
|
{pattern = "flower", color = {200, 100, 150}},
|
|
{pattern = "junglegrass", color = {40, 80, 20}},
|
|
|
|
-- Farmland
|
|
{pattern = "farmland", color = {120, 80, 50}},
|
|
{pattern = "grass_path", color = {140, 120, 80}},
|
|
}
|
|
|
|
-- ============================================================================
|
|
-- GROUP-BASED DETECTION - Fallback based on node groups
|
|
-- ============================================================================
|
|
local group_colors = {
|
|
soil = PALETTE.DIRT_BROWN,
|
|
sand = PALETTE.SAND_TAN,
|
|
stone = PALETTE.STONE_GRAY,
|
|
tree = PALETTE.TREE_BROWN,
|
|
leaves = PALETTE.LEAVES_GREEN,
|
|
water = PALETTE.WATER_BLUE,
|
|
lava = PALETTE.LAVA_ORANGE,
|
|
ice = PALETTE.ICE_BLUE,
|
|
snow = PALETTE.SNOW_WHITE,
|
|
}
|
|
|
|
-- ============================================================================
|
|
-- COLOR CACHE - Store computed colors to avoid recalculation
|
|
-- ============================================================================
|
|
local color_cache = {}
|
|
|
|
-- ============================================================================
|
|
-- HELPER FUNCTIONS
|
|
-- ============================================================================
|
|
|
|
-- Check if a string contains a pattern (case-insensitive)
|
|
local function contains_pattern(str, pattern)
|
|
return str:lower():find(pattern:lower(), 1, true) ~= nil
|
|
end
|
|
|
|
-- Detect color based on keywords in node name
|
|
local function detect_color_from_keywords(nodename)
|
|
for _, entry in ipairs(keyword_colors) do
|
|
if contains_pattern(nodename, entry.pattern) then
|
|
return entry.color
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- Detect color based on node groups
|
|
local function detect_color_from_groups(nodename)
|
|
local node_def = minetest.registered_nodes[nodename]
|
|
if not node_def or not node_def.groups then
|
|
return nil
|
|
end
|
|
|
|
-- Check each group that has a color mapping
|
|
for group, color in pairs(group_colors) do
|
|
if node_def.groups[group] and node_def.groups[group] > 0 then
|
|
return color
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
-- ============================================================================
|
|
-- PUBLIC API
|
|
-- ============================================================================
|
|
|
|
-- Get color for a node (main function)
|
|
function nodecolors.get_color(nodename)
|
|
-- Return from cache if available
|
|
if color_cache[nodename] then
|
|
return color_cache[nodename]
|
|
end
|
|
|
|
local color = nil
|
|
|
|
-- Priority 1: Manual overrides
|
|
if manual_overrides[nodename] then
|
|
color = manual_overrides[nodename]
|
|
end
|
|
|
|
-- Priority 2: Keyword detection
|
|
if not color then
|
|
color = detect_color_from_keywords(nodename)
|
|
end
|
|
|
|
-- Priority 3: Group-based detection
|
|
if not color then
|
|
color = detect_color_from_groups(nodename)
|
|
end
|
|
|
|
-- Priority 4: Default color
|
|
if not color then
|
|
color = PALETTE.DEFAULT_GRAY
|
|
end
|
|
|
|
-- Cache the result
|
|
color_cache[nodename] = color
|
|
|
|
return color
|
|
end
|
|
|
|
-- Set a manual override color for a specific node
|
|
function nodecolors.set_color(nodename, color)
|
|
manual_overrides[nodename] = color
|
|
color_cache[nodename] = color
|
|
end
|
|
|
|
-- Check if a node has a defined color (not default)
|
|
function nodecolors.has_color(nodename)
|
|
local color = nodecolors.get_color(nodename)
|
|
return color ~= PALETTE.DEFAULT_GRAY
|
|
end
|
|
|
|
-- Add a new keyword pattern and color
|
|
function nodecolors.add_keyword(pattern, color)
|
|
table.insert(keyword_colors, {pattern = pattern, color = color})
|
|
end
|
|
|
|
-- Add a new group color mapping
|
|
function nodecolors.add_group_color(group, color)
|
|
group_colors[group] = color
|
|
end
|
|
|
|
-- Get the color palette (for external customization)
|
|
function nodecolors.get_palette()
|
|
return PALETTE
|
|
end
|
|
|
|
-- Clear the color cache (useful after bulk changes)
|
|
function nodecolors.clear_cache()
|
|
color_cache = {}
|
|
end
|
|
|
|
-- Get statistics about color detection
|
|
function nodecolors.get_stats()
|
|
local stats = {
|
|
manual_overrides = 0,
|
|
keyword_patterns = 0,
|
|
group_mappings = 0,
|
|
cached_colors = 0
|
|
}
|
|
|
|
for _ in pairs(manual_overrides) do
|
|
stats.manual_overrides = stats.manual_overrides + 1
|
|
end
|
|
|
|
stats.keyword_patterns = #keyword_colors
|
|
|
|
for _ in pairs(group_colors) do
|
|
stats.group_mappings = stats.group_mappings + 1
|
|
end
|
|
|
|
for _ in pairs(color_cache) do
|
|
stats.cached_colors = stats.cached_colors + 1
|
|
end
|
|
|
|
return stats
|
|
end
|
|
|
|
-- Debug function: show how a color was determined
|
|
function nodecolors.debug_color(nodename)
|
|
local info = {
|
|
nodename = nodename,
|
|
color = nil,
|
|
method = "none",
|
|
details = ""
|
|
}
|
|
|
|
-- Check manual override
|
|
if manual_overrides[nodename] then
|
|
info.color = manual_overrides[nodename]
|
|
info.method = "manual_override"
|
|
return info
|
|
end
|
|
|
|
-- Check keywords
|
|
local keyword_color = detect_color_from_keywords(nodename)
|
|
if keyword_color then
|
|
info.color = keyword_color
|
|
info.method = "keyword"
|
|
for _, entry in ipairs(keyword_colors) do
|
|
if contains_pattern(nodename, entry.pattern) then
|
|
info.details = "matched pattern: " .. entry.pattern
|
|
break
|
|
end
|
|
end
|
|
return info
|
|
end
|
|
|
|
-- Check groups
|
|
local group_color = detect_color_from_groups(nodename)
|
|
if group_color then
|
|
info.color = group_color
|
|
info.method = "group"
|
|
local node_def = minetest.registered_nodes[nodename]
|
|
if node_def and node_def.groups then
|
|
for group, color in pairs(group_colors) do
|
|
if node_def.groups[group] and node_def.groups[group] > 0 then
|
|
info.details = "matched group: " .. group
|
|
break
|
|
end
|
|
end
|
|
end
|
|
return info
|
|
end
|
|
|
|
-- Default
|
|
info.color = PALETTE.DEFAULT_GRAY
|
|
info.method = "default"
|
|
return info
|
|
end
|
|
|
|
return nodecolors
|