feat(plugin): add more block entity api stuff

This commit is contained in:
Alexander Medvedev
2026-08-14 11:32:50 +02:00
parent 00cb2f9240
commit e09e8c529a
21 changed files with 3703 additions and 165 deletions

1
assets/dye_colors.json Normal file
View File

@@ -0,0 +1 @@
[{"id":0,"name":"white","map_color_id":8,"terracotta_color_id":36,"texture_diffuse_color":16383998,"firework_color":15790320,"text_color":16777215},{"id":1,"name":"orange","map_color_id":15,"terracotta_color_id":37,"texture_diffuse_color":16351261,"firework_color":15435844,"text_color":16738335},{"id":2,"name":"magenta","map_color_id":16,"terracotta_color_id":38,"texture_diffuse_color":13061821,"firework_color":12801229,"text_color":16711935},{"id":3,"name":"light_blue","map_color_id":17,"terracotta_color_id":39,"texture_diffuse_color":3847130,"firework_color":6719955,"text_color":10141901},{"id":4,"name":"yellow","map_color_id":18,"terracotta_color_id":40,"texture_diffuse_color":16701501,"firework_color":14602026,"text_color":16776960},{"id":5,"name":"lime","map_color_id":19,"terracotta_color_id":41,"texture_diffuse_color":8439583,"firework_color":4312372,"text_color":12582656},{"id":6,"name":"pink","map_color_id":20,"terracotta_color_id":42,"texture_diffuse_color":15961002,"firework_color":14188952,"text_color":16738740},{"id":7,"name":"gray","map_color_id":21,"terracotta_color_id":43,"texture_diffuse_color":4673362,"firework_color":4408131,"text_color":8421504},{"id":8,"name":"light_gray","map_color_id":22,"terracotta_color_id":44,"texture_diffuse_color":10329495,"firework_color":11250603,"text_color":13882323},{"id":9,"name":"cyan","map_color_id":23,"terracotta_color_id":45,"texture_diffuse_color":1481884,"firework_color":2651799,"text_color":65535},{"id":10,"name":"purple","map_color_id":24,"terracotta_color_id":46,"texture_diffuse_color":8991416,"firework_color":8073150,"text_color":10494192},{"id":11,"name":"blue","map_color_id":25,"terracotta_color_id":47,"texture_diffuse_color":3949738,"firework_color":2437522,"text_color":255},{"id":12,"name":"brown","map_color_id":26,"terracotta_color_id":48,"texture_diffuse_color":8606770,"firework_color":5320730,"text_color":9127187},{"id":13,"name":"green","map_color_id":27,"terracotta_color_id":49,"texture_diffuse_color":6192150,"firework_color":3887386,"text_color":65280},{"id":14,"name":"red","map_color_id":28,"terracotta_color_id":50,"texture_diffuse_color":11546150,"firework_color":11743532,"text_color":16711680},{"id":15,"name":"black","map_color_id":29,"terracotta_color_id":51,"texture_diffuse_color":1908001,"firework_color":1973019,"text_color":0}]

1
assets/map_colors.json Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -49,9 +49,15 @@ default = [
"configured_feature",
"slot_ranges",
"bedrock_creative",
"bedrock_biome"
"bedrock_biome",
"map_color",
"map_decoration",
"dye_color"
]
map_color = []
map_decoration = []
dye_color = []
advancement = []
bedrock_creative = []
bedrock_biome = []

View File

@@ -0,0 +1,214 @@
/* This file is generated. Do not edit manually. */
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum DyeColor {
White,
Orange,
Magenta,
LightBlue,
Yellow,
Lime,
Pink,
Gray,
LightGray,
Cyan,
Purple,
Blue,
Brown,
Green,
Red,
#[default]
Black,
}
impl DyeColor {
#[must_use]
pub const fn id(&self) -> u8 {
match self {
Self::White => 0u8,
Self::Orange => 1u8,
Self::Magenta => 2u8,
Self::LightBlue => 3u8,
Self::Yellow => 4u8,
Self::Lime => 5u8,
Self::Pink => 6u8,
Self::Gray => 7u8,
Self::LightGray => 8u8,
Self::Cyan => 9u8,
Self::Purple => 10u8,
Self::Blue => 11u8,
Self::Brown => 12u8,
Self::Green => 13u8,
Self::Red => 14u8,
Self::Black => 15u8,
}
}
#[must_use]
pub const fn name(&self) -> &'static str {
match self {
Self::White => "white",
Self::Orange => "orange",
Self::Magenta => "magenta",
Self::LightBlue => "light_blue",
Self::Yellow => "yellow",
Self::Lime => "lime",
Self::Pink => "pink",
Self::Gray => "gray",
Self::LightGray => "light_gray",
Self::Cyan => "cyan",
Self::Purple => "purple",
Self::Blue => "blue",
Self::Brown => "brown",
Self::Green => "green",
Self::Red => "red",
Self::Black => "black",
}
}
#[must_use]
pub const fn map_color_id(&self) -> u8 {
match self {
Self::White => 8u8,
Self::Orange => 15u8,
Self::Magenta => 16u8,
Self::LightBlue => 17u8,
Self::Yellow => 18u8,
Self::Lime => 19u8,
Self::Pink => 20u8,
Self::Gray => 21u8,
Self::LightGray => 22u8,
Self::Cyan => 23u8,
Self::Purple => 24u8,
Self::Blue => 25u8,
Self::Brown => 26u8,
Self::Green => 27u8,
Self::Red => 28u8,
Self::Black => 29u8,
}
}
#[must_use]
pub const fn terracotta_color_id(&self) -> u8 {
match self {
Self::White => 36u8,
Self::Orange => 37u8,
Self::Magenta => 38u8,
Self::LightBlue => 39u8,
Self::Yellow => 40u8,
Self::Lime => 41u8,
Self::Pink => 42u8,
Self::Gray => 43u8,
Self::LightGray => 44u8,
Self::Cyan => 45u8,
Self::Purple => 46u8,
Self::Blue => 47u8,
Self::Brown => 48u8,
Self::Green => 49u8,
Self::Red => 50u8,
Self::Black => 51u8,
}
}
#[must_use]
pub const fn texture_diffuse_color(&self) -> u32 {
match self {
Self::White => 16383998u32,
Self::Orange => 16351261u32,
Self::Magenta => 13061821u32,
Self::LightBlue => 3847130u32,
Self::Yellow => 16701501u32,
Self::Lime => 8439583u32,
Self::Pink => 15961002u32,
Self::Gray => 4673362u32,
Self::LightGray => 10329495u32,
Self::Cyan => 1481884u32,
Self::Purple => 8991416u32,
Self::Blue => 3949738u32,
Self::Brown => 8606770u32,
Self::Green => 6192150u32,
Self::Red => 11546150u32,
Self::Black => 1908001u32,
}
}
#[must_use]
pub const fn firework_color(&self) -> u32 {
match self {
Self::White => 15790320u32,
Self::Orange => 15435844u32,
Self::Magenta => 12801229u32,
Self::LightBlue => 6719955u32,
Self::Yellow => 14602026u32,
Self::Lime => 4312372u32,
Self::Pink => 14188952u32,
Self::Gray => 4408131u32,
Self::LightGray => 11250603u32,
Self::Cyan => 2651799u32,
Self::Purple => 8073150u32,
Self::Blue => 2437522u32,
Self::Brown => 5320730u32,
Self::Green => 3887386u32,
Self::Red => 11743532u32,
Self::Black => 1973019u32,
}
}
#[must_use]
pub const fn text_color(&self) -> u32 {
match self {
Self::White => 16777215u32,
Self::Orange => 16738335u32,
Self::Magenta => 16711935u32,
Self::LightBlue => 10141901u32,
Self::Yellow => 16776960u32,
Self::Lime => 12582656u32,
Self::Pink => 16738740u32,
Self::Gray => 8421504u32,
Self::LightGray => 13882323u32,
Self::Cyan => 65535u32,
Self::Purple => 10494192u32,
Self::Blue => 255u32,
Self::Brown => 9127187u32,
Self::Green => 65280u32,
Self::Red => 16711680u32,
Self::Black => 0u32,
}
}
#[must_use]
pub const fn by_id(id: u8) -> Option<Self> {
match id {
0u8 => Some(Self::White),
1u8 => Some(Self::Orange),
2u8 => Some(Self::Magenta),
3u8 => Some(Self::LightBlue),
4u8 => Some(Self::Yellow),
5u8 => Some(Self::Lime),
6u8 => Some(Self::Pink),
7u8 => Some(Self::Gray),
8u8 => Some(Self::LightGray),
9u8 => Some(Self::Cyan),
10u8 => Some(Self::Purple),
11u8 => Some(Self::Blue),
12u8 => Some(Self::Brown),
13u8 => Some(Self::Green),
14u8 => Some(Self::Red),
15u8 => Some(Self::Black),
_ => None,
}
}
#[must_use]
pub fn by_name(name: &str) -> Option<Self> {
match name {
"white" => Some(Self::White),
"orange" => Some(Self::Orange),
"magenta" => Some(Self::Magenta),
"light_blue" => Some(Self::LightBlue),
"yellow" => Some(Self::Yellow),
"lime" => Some(Self::Lime),
"pink" => Some(Self::Pink),
"gray" => Some(Self::Gray),
"light_gray" => Some(Self::LightGray),
"cyan" => Some(Self::Cyan),
"purple" => Some(Self::Purple),
"blue" => Some(Self::Blue),
"brown" => Some(Self::Brown),
"green" => Some(Self::Green),
"red" => Some(Self::Red),
"black" => Some(Self::Black),
_ => None,
}
}
}

View File

@@ -0,0 +1,536 @@
/* This file is generated. Do not edit manually. */
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MapColor {
pub id: u8,
pub name: &'static str,
pub col: u32,
pub rgb: (u8, u8, u8),
}
impl MapColor {
pub const NONE_0: MapColor = MapColor {
id: 0u8,
name: "none",
col: 0u32,
rgb: (0u8, 0u8, 0u8),
};
pub const GRASS: MapColor = MapColor {
id: 1u8,
name: "grass",
col: 8368696u32,
rgb: (127u8, 178u8, 56u8),
};
pub const SAND: MapColor = MapColor {
id: 2u8,
name: "sand",
col: 16247203u32,
rgb: (247u8, 233u8, 163u8),
};
pub const WOOL: MapColor = MapColor {
id: 3u8,
name: "wool",
col: 13092807u32,
rgb: (199u8, 199u8, 199u8),
};
pub const FIRE: MapColor = MapColor {
id: 4u8,
name: "fire",
col: 16711680u32,
rgb: (255u8, 0u8, 0u8),
};
pub const ICE: MapColor = MapColor {
id: 5u8,
name: "ice",
col: 10526975u32,
rgb: (160u8, 160u8, 255u8),
};
pub const METAL: MapColor = MapColor {
id: 6u8,
name: "metal",
col: 10987431u32,
rgb: (167u8, 167u8, 167u8),
};
pub const PLANT: MapColor = MapColor {
id: 7u8,
name: "plant",
col: 31744u32,
rgb: (0u8, 124u8, 0u8),
};
pub const SNOW: MapColor = MapColor {
id: 8u8,
name: "snow",
col: 16777215u32,
rgb: (255u8, 255u8, 255u8),
};
pub const CLAY: MapColor = MapColor {
id: 9u8,
name: "clay",
col: 10791096u32,
rgb: (164u8, 168u8, 184u8),
};
pub const DIRT: MapColor = MapColor {
id: 10u8,
name: "dirt",
col: 9923917u32,
rgb: (151u8, 109u8, 77u8),
};
pub const STONE: MapColor = MapColor {
id: 11u8,
name: "stone",
col: 7368816u32,
rgb: (112u8, 112u8, 112u8),
};
pub const WATER: MapColor = MapColor {
id: 12u8,
name: "water",
col: 4210943u32,
rgb: (64u8, 64u8, 255u8),
};
pub const WOOD: MapColor = MapColor {
id: 13u8,
name: "wood",
col: 9402184u32,
rgb: (143u8, 119u8, 72u8),
};
pub const QUARTZ: MapColor = MapColor {
id: 14u8,
name: "quartz",
col: 16776437u32,
rgb: (255u8, 252u8, 245u8),
};
pub const COLOR_ORANGE: MapColor = MapColor {
id: 15u8,
name: "color_orange",
col: 14188339u32,
rgb: (216u8, 127u8, 51u8),
};
pub const COLOR_MAGENTA: MapColor = MapColor {
id: 16u8,
name: "color_magenta",
col: 11685080u32,
rgb: (178u8, 76u8, 216u8),
};
pub const COLOR_LIGHT_BLUE: MapColor = MapColor {
id: 17u8,
name: "color_light_blue",
col: 6724056u32,
rgb: (102u8, 153u8, 216u8),
};
pub const COLOR_YELLOW: MapColor = MapColor {
id: 18u8,
name: "color_yellow",
col: 15066419u32,
rgb: (229u8, 229u8, 51u8),
};
pub const COLOR_LIGHT_GREEN: MapColor = MapColor {
id: 19u8,
name: "color_light_green",
col: 8375321u32,
rgb: (127u8, 204u8, 25u8),
};
pub const COLOR_PINK: MapColor = MapColor {
id: 20u8,
name: "color_pink",
col: 15892389u32,
rgb: (242u8, 127u8, 165u8),
};
pub const COLOR_GRAY: MapColor = MapColor {
id: 21u8,
name: "color_gray",
col: 5000268u32,
rgb: (76u8, 76u8, 76u8),
};
pub const COLOR_LIGHT_GRAY: MapColor = MapColor {
id: 22u8,
name: "color_light_gray",
col: 10066329u32,
rgb: (153u8, 153u8, 153u8),
};
pub const COLOR_CYAN: MapColor = MapColor {
id: 23u8,
name: "color_cyan",
col: 5013401u32,
rgb: (76u8, 127u8, 153u8),
};
pub const COLOR_PURPLE: MapColor = MapColor {
id: 24u8,
name: "color_purple",
col: 8339378u32,
rgb: (127u8, 63u8, 178u8),
};
pub const COLOR_BLUE: MapColor = MapColor {
id: 25u8,
name: "color_blue",
col: 3361970u32,
rgb: (51u8, 76u8, 178u8),
};
pub const COLOR_BROWN: MapColor = MapColor {
id: 26u8,
name: "color_brown",
col: 6704179u32,
rgb: (102u8, 76u8, 51u8),
};
pub const COLOR_GREEN: MapColor = MapColor {
id: 27u8,
name: "color_green",
col: 6717235u32,
rgb: (102u8, 127u8, 51u8),
};
pub const COLOR_RED: MapColor = MapColor {
id: 28u8,
name: "color_red",
col: 10040115u32,
rgb: (153u8, 51u8, 51u8),
};
pub const COLOR_BLACK: MapColor = MapColor {
id: 29u8,
name: "color_black",
col: 1644825u32,
rgb: (25u8, 25u8, 25u8),
};
pub const GOLD: MapColor = MapColor {
id: 30u8,
name: "gold",
col: 16445005u32,
rgb: (250u8, 238u8, 77u8),
};
pub const DIAMOND: MapColor = MapColor {
id: 31u8,
name: "diamond",
col: 6085589u32,
rgb: (92u8, 219u8, 213u8),
};
pub const LAPIS: MapColor = MapColor {
id: 32u8,
name: "lapis",
col: 4882687u32,
rgb: (74u8, 128u8, 255u8),
};
pub const EMERALD: MapColor = MapColor {
id: 33u8,
name: "emerald",
col: 55610u32,
rgb: (0u8, 217u8, 58u8),
};
pub const PODZOL: MapColor = MapColor {
id: 34u8,
name: "podzol",
col: 8476209u32,
rgb: (129u8, 86u8, 49u8),
};
pub const NETHER: MapColor = MapColor {
id: 35u8,
name: "nether",
col: 7340544u32,
rgb: (112u8, 2u8, 0u8),
};
pub const TERRACOTTA_WHITE: MapColor = MapColor {
id: 36u8,
name: "terracotta_white",
col: 13742497u32,
rgb: (209u8, 177u8, 161u8),
};
pub const TERRACOTTA_ORANGE: MapColor = MapColor {
id: 37u8,
name: "terracotta_orange",
col: 10441252u32,
rgb: (159u8, 82u8, 36u8),
};
pub const TERRACOTTA_MAGENTA: MapColor = MapColor {
id: 38u8,
name: "terracotta_magenta",
col: 9787244u32,
rgb: (149u8, 87u8, 108u8),
};
pub const TERRACOTTA_LIGHT_BLUE: MapColor = MapColor {
id: 39u8,
name: "terracotta_light_blue",
col: 7367818u32,
rgb: (112u8, 108u8, 138u8),
};
pub const TERRACOTTA_YELLOW: MapColor = MapColor {
id: 40u8,
name: "terracotta_yellow",
col: 12223780u32,
rgb: (186u8, 133u8, 36u8),
};
pub const TERRACOTTA_LIGHT_GREEN: MapColor = MapColor {
id: 41u8,
name: "terracotta_light_green",
col: 6780213u32,
rgb: (103u8, 117u8, 53u8),
};
pub const TERRACOTTA_PINK: MapColor = MapColor {
id: 42u8,
name: "terracotta_pink",
col: 10505550u32,
rgb: (160u8, 77u8, 78u8),
};
pub const TERRACOTTA_GRAY: MapColor = MapColor {
id: 43u8,
name: "terracotta_gray",
col: 3746083u32,
rgb: (57u8, 41u8, 35u8),
};
pub const TERRACOTTA_LIGHT_GRAY: MapColor = MapColor {
id: 44u8,
name: "terracotta_light_gray",
col: 8874850u32,
rgb: (135u8, 107u8, 98u8),
};
pub const TERRACOTTA_CYAN: MapColor = MapColor {
id: 45u8,
name: "terracotta_cyan",
col: 5725276u32,
rgb: (87u8, 92u8, 92u8),
};
pub const TERRACOTTA_PURPLE: MapColor = MapColor {
id: 46u8,
name: "terracotta_purple",
col: 8014168u32,
rgb: (122u8, 73u8, 88u8),
};
pub const TERRACOTTA_BLUE: MapColor = MapColor {
id: 47u8,
name: "terracotta_blue",
col: 4996700u32,
rgb: (76u8, 62u8, 92u8),
};
pub const TERRACOTTA_BROWN: MapColor = MapColor {
id: 48u8,
name: "terracotta_brown",
col: 4993571u32,
rgb: (76u8, 50u8, 35u8),
};
pub const TERRACOTTA_GREEN: MapColor = MapColor {
id: 49u8,
name: "terracotta_green",
col: 5001770u32,
rgb: (76u8, 82u8, 42u8),
};
pub const TERRACOTTA_RED: MapColor = MapColor {
id: 50u8,
name: "terracotta_red",
col: 9321518u32,
rgb: (142u8, 60u8, 46u8),
};
pub const TERRACOTTA_BLACK: MapColor = MapColor {
id: 51u8,
name: "terracotta_black",
col: 2430480u32,
rgb: (37u8, 22u8, 16u8),
};
pub const CRIMSON_NYLIUM: MapColor = MapColor {
id: 52u8,
name: "crimson_nylium",
col: 12398641u32,
rgb: (189u8, 48u8, 49u8),
};
pub const CRIMSON_STEM: MapColor = MapColor {
id: 53u8,
name: "crimson_stem",
col: 9715553u32,
rgb: (148u8, 63u8, 97u8),
};
pub const CRIMSON_HYPHAE: MapColor = MapColor {
id: 54u8,
name: "crimson_hyphae",
col: 6035741u32,
rgb: (92u8, 25u8, 29u8),
};
pub const WARPED_NYLIUM: MapColor = MapColor {
id: 55u8,
name: "warped_nylium",
col: 1474182u32,
rgb: (22u8, 126u8, 134u8),
};
pub const WARPED_STEM: MapColor = MapColor {
id: 56u8,
name: "warped_stem",
col: 3837580u32,
rgb: (58u8, 142u8, 140u8),
};
pub const WARPED_HYPHAE: MapColor = MapColor {
id: 57u8,
name: "warped_hyphae",
col: 5647422u32,
rgb: (86u8, 44u8, 62u8),
};
pub const WARPED_WART_BLOCK: MapColor = MapColor {
id: 58u8,
name: "warped_wart_block",
col: 1356933u32,
rgb: (20u8, 180u8, 133u8),
};
pub const DEEPSLATE: MapColor = MapColor {
id: 59u8,
name: "deepslate",
col: 6579300u32,
rgb: (100u8, 100u8, 100u8),
};
pub const RAW_IRON: MapColor = MapColor {
id: 60u8,
name: "raw_iron",
col: 14200723u32,
rgb: (216u8, 175u8, 147u8),
};
pub const GLOW_LICHEN: MapColor = MapColor {
id: 61u8,
name: "glow_lichen",
col: 8365974u32,
rgb: (127u8, 167u8, 150u8),
};
pub const NONE_62: MapColor = MapColor {
id: 62u8,
name: "none",
col: 0u32,
rgb: (0u8, 0u8, 0u8),
};
pub const NONE_63: MapColor = MapColor {
id: 63u8,
name: "none",
col: 0u32,
rgb: (0u8, 0u8, 0u8),
};
pub const ALL: &'static [MapColor] = &[
MapColor::NONE_0,
MapColor::GRASS,
MapColor::SAND,
MapColor::WOOL,
MapColor::FIRE,
MapColor::ICE,
MapColor::METAL,
MapColor::PLANT,
MapColor::SNOW,
MapColor::CLAY,
MapColor::DIRT,
MapColor::STONE,
MapColor::WATER,
MapColor::WOOD,
MapColor::QUARTZ,
MapColor::COLOR_ORANGE,
MapColor::COLOR_MAGENTA,
MapColor::COLOR_LIGHT_BLUE,
MapColor::COLOR_YELLOW,
MapColor::COLOR_LIGHT_GREEN,
MapColor::COLOR_PINK,
MapColor::COLOR_GRAY,
MapColor::COLOR_LIGHT_GRAY,
MapColor::COLOR_CYAN,
MapColor::COLOR_PURPLE,
MapColor::COLOR_BLUE,
MapColor::COLOR_BROWN,
MapColor::COLOR_GREEN,
MapColor::COLOR_RED,
MapColor::COLOR_BLACK,
MapColor::GOLD,
MapColor::DIAMOND,
MapColor::LAPIS,
MapColor::EMERALD,
MapColor::PODZOL,
MapColor::NETHER,
MapColor::TERRACOTTA_WHITE,
MapColor::TERRACOTTA_ORANGE,
MapColor::TERRACOTTA_MAGENTA,
MapColor::TERRACOTTA_LIGHT_BLUE,
MapColor::TERRACOTTA_YELLOW,
MapColor::TERRACOTTA_LIGHT_GREEN,
MapColor::TERRACOTTA_PINK,
MapColor::TERRACOTTA_GRAY,
MapColor::TERRACOTTA_LIGHT_GRAY,
MapColor::TERRACOTTA_CYAN,
MapColor::TERRACOTTA_PURPLE,
MapColor::TERRACOTTA_BLUE,
MapColor::TERRACOTTA_BROWN,
MapColor::TERRACOTTA_GREEN,
MapColor::TERRACOTTA_RED,
MapColor::TERRACOTTA_BLACK,
MapColor::CRIMSON_NYLIUM,
MapColor::CRIMSON_STEM,
MapColor::CRIMSON_HYPHAE,
MapColor::WARPED_NYLIUM,
MapColor::WARPED_STEM,
MapColor::WARPED_HYPHAE,
MapColor::WARPED_WART_BLOCK,
MapColor::DEEPSLATE,
MapColor::RAW_IRON,
MapColor::GLOW_LICHEN,
MapColor::NONE_62,
MapColor::NONE_63,
];
#[must_use]
pub const fn from_id(id: u8) -> Option<&'static MapColor> {
if (id as usize) < Self::ALL.len() {
Some(&Self::ALL[id as usize])
} else {
None
}
}
#[must_use]
pub fn from_name(name: &str) -> Option<&'static MapColor> {
match name {
"none" => Some(&Self::NONE_0),
"grass" => Some(&Self::GRASS),
"sand" => Some(&Self::SAND),
"wool" => Some(&Self::WOOL),
"fire" => Some(&Self::FIRE),
"ice" => Some(&Self::ICE),
"metal" => Some(&Self::METAL),
"plant" => Some(&Self::PLANT),
"snow" => Some(&Self::SNOW),
"clay" => Some(&Self::CLAY),
"dirt" => Some(&Self::DIRT),
"stone" => Some(&Self::STONE),
"water" => Some(&Self::WATER),
"wood" => Some(&Self::WOOD),
"quartz" => Some(&Self::QUARTZ),
"color_orange" => Some(&Self::COLOR_ORANGE),
"color_magenta" => Some(&Self::COLOR_MAGENTA),
"color_light_blue" => Some(&Self::COLOR_LIGHT_BLUE),
"color_yellow" => Some(&Self::COLOR_YELLOW),
"color_light_green" => Some(&Self::COLOR_LIGHT_GREEN),
"color_pink" => Some(&Self::COLOR_PINK),
"color_gray" => Some(&Self::COLOR_GRAY),
"color_light_gray" => Some(&Self::COLOR_LIGHT_GRAY),
"color_cyan" => Some(&Self::COLOR_CYAN),
"color_purple" => Some(&Self::COLOR_PURPLE),
"color_blue" => Some(&Self::COLOR_BLUE),
"color_brown" => Some(&Self::COLOR_BROWN),
"color_green" => Some(&Self::COLOR_GREEN),
"color_red" => Some(&Self::COLOR_RED),
"color_black" => Some(&Self::COLOR_BLACK),
"gold" => Some(&Self::GOLD),
"diamond" => Some(&Self::DIAMOND),
"lapis" => Some(&Self::LAPIS),
"emerald" => Some(&Self::EMERALD),
"podzol" => Some(&Self::PODZOL),
"nether" => Some(&Self::NETHER),
"terracotta_white" => Some(&Self::TERRACOTTA_WHITE),
"terracotta_orange" => Some(&Self::TERRACOTTA_ORANGE),
"terracotta_magenta" => Some(&Self::TERRACOTTA_MAGENTA),
"terracotta_light_blue" => Some(&Self::TERRACOTTA_LIGHT_BLUE),
"terracotta_yellow" => Some(&Self::TERRACOTTA_YELLOW),
"terracotta_light_green" => Some(&Self::TERRACOTTA_LIGHT_GREEN),
"terracotta_pink" => Some(&Self::TERRACOTTA_PINK),
"terracotta_gray" => Some(&Self::TERRACOTTA_GRAY),
"terracotta_light_gray" => Some(&Self::TERRACOTTA_LIGHT_GRAY),
"terracotta_cyan" => Some(&Self::TERRACOTTA_CYAN),
"terracotta_purple" => Some(&Self::TERRACOTTA_PURPLE),
"terracotta_blue" => Some(&Self::TERRACOTTA_BLUE),
"terracotta_brown" => Some(&Self::TERRACOTTA_BROWN),
"terracotta_green" => Some(&Self::TERRACOTTA_GREEN),
"terracotta_red" => Some(&Self::TERRACOTTA_RED),
"terracotta_black" => Some(&Self::TERRACOTTA_BLACK),
"crimson_nylium" => Some(&Self::CRIMSON_NYLIUM),
"crimson_stem" => Some(&Self::CRIMSON_STEM),
"crimson_hyphae" => Some(&Self::CRIMSON_HYPHAE),
"warped_nylium" => Some(&Self::WARPED_NYLIUM),
"warped_stem" => Some(&Self::WARPED_STEM),
"warped_hyphae" => Some(&Self::WARPED_HYPHAE),
"warped_wart_block" => Some(&Self::WARPED_WART_BLOCK),
"deepslate" => Some(&Self::DEEPSLATE),
"raw_iron" => Some(&Self::RAW_IRON),
"glow_lichen" => Some(&Self::GLOW_LICHEN),
_ => None,
}
}
}

View File

@@ -0,0 +1,414 @@
/* This file is generated. Do not edit manually. */
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MapDecorationType {
pub id: u32,
pub name: &'static str,
pub asset_name: &'static str,
pub show_on_item_frame: bool,
pub map_color: i32,
pub exploration_map_element: bool,
pub track_count: bool,
}
impl MapDecorationType {
pub const PLAYER: MapDecorationType = MapDecorationType {
id: 0u32,
name: "player",
asset_name: "player",
show_on_item_frame: false,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const FRAME: MapDecorationType = MapDecorationType {
id: 1u32,
name: "frame",
asset_name: "frame",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const RED_MARKER: MapDecorationType = MapDecorationType {
id: 2u32,
name: "red_marker",
asset_name: "red_marker",
show_on_item_frame: false,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BLUE_MARKER: MapDecorationType = MapDecorationType {
id: 3u32,
name: "blue_marker",
asset_name: "blue_marker",
show_on_item_frame: false,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const TARGET_X: MapDecorationType = MapDecorationType {
id: 4u32,
name: "target_x",
asset_name: "target_x",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: false,
};
pub const TARGET_POINT: MapDecorationType = MapDecorationType {
id: 5u32,
name: "target_point",
asset_name: "target_point",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: false,
};
pub const PLAYER_OFF_MAP: MapDecorationType = MapDecorationType {
id: 6u32,
name: "player_off_map",
asset_name: "player_off_map",
show_on_item_frame: false,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const PLAYER_OFF_LIMITS: MapDecorationType = MapDecorationType {
id: 7u32,
name: "player_off_limits",
asset_name: "player_off_limits",
show_on_item_frame: false,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const MANSION: MapDecorationType = MapDecorationType {
id: 8u32,
name: "mansion",
asset_name: "woodland_mansion",
show_on_item_frame: true,
map_color: 5393476i32,
exploration_map_element: true,
track_count: false,
};
pub const MONUMENT: MapDecorationType = MapDecorationType {
id: 9u32,
name: "monument",
asset_name: "ocean_monument",
show_on_item_frame: true,
map_color: 3830373i32,
exploration_map_element: true,
track_count: false,
};
pub const BANNER_WHITE: MapDecorationType = MapDecorationType {
id: 10u32,
name: "banner_white",
asset_name: "white_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_ORANGE: MapDecorationType = MapDecorationType {
id: 11u32,
name: "banner_orange",
asset_name: "orange_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_MAGENTA: MapDecorationType = MapDecorationType {
id: 12u32,
name: "banner_magenta",
asset_name: "magenta_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_LIGHT_BLUE: MapDecorationType = MapDecorationType {
id: 13u32,
name: "banner_light_blue",
asset_name: "light_blue_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_YELLOW: MapDecorationType = MapDecorationType {
id: 14u32,
name: "banner_yellow",
asset_name: "yellow_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_LIME: MapDecorationType = MapDecorationType {
id: 15u32,
name: "banner_lime",
asset_name: "lime_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_PINK: MapDecorationType = MapDecorationType {
id: 16u32,
name: "banner_pink",
asset_name: "pink_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_GRAY: MapDecorationType = MapDecorationType {
id: 17u32,
name: "banner_gray",
asset_name: "gray_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_LIGHT_GRAY: MapDecorationType = MapDecorationType {
id: 18u32,
name: "banner_light_gray",
asset_name: "light_gray_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_CYAN: MapDecorationType = MapDecorationType {
id: 19u32,
name: "banner_cyan",
asset_name: "cyan_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_PURPLE: MapDecorationType = MapDecorationType {
id: 20u32,
name: "banner_purple",
asset_name: "purple_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_BLUE: MapDecorationType = MapDecorationType {
id: 21u32,
name: "banner_blue",
asset_name: "blue_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_BROWN: MapDecorationType = MapDecorationType {
id: 22u32,
name: "banner_brown",
asset_name: "brown_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_GREEN: MapDecorationType = MapDecorationType {
id: 23u32,
name: "banner_green",
asset_name: "green_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_RED: MapDecorationType = MapDecorationType {
id: 24u32,
name: "banner_red",
asset_name: "red_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const BANNER_BLACK: MapDecorationType = MapDecorationType {
id: 25u32,
name: "banner_black",
asset_name: "black_banner",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: true,
};
pub const RED_X: MapDecorationType = MapDecorationType {
id: 26u32,
name: "red_x",
asset_name: "red_x",
show_on_item_frame: true,
map_color: -1i32,
exploration_map_element: false,
track_count: false,
};
pub const VILLAGE_DESERT: MapDecorationType = MapDecorationType {
id: 27u32,
name: "village_desert",
asset_name: "desert_village",
show_on_item_frame: true,
map_color: 10066329i32,
exploration_map_element: true,
track_count: false,
};
pub const VILLAGE_PLAINS: MapDecorationType = MapDecorationType {
id: 28u32,
name: "village_plains",
asset_name: "plains_village",
show_on_item_frame: true,
map_color: 10066329i32,
exploration_map_element: true,
track_count: false,
};
pub const VILLAGE_SAVANNA: MapDecorationType = MapDecorationType {
id: 29u32,
name: "village_savanna",
asset_name: "savanna_village",
show_on_item_frame: true,
map_color: 10066329i32,
exploration_map_element: true,
track_count: false,
};
pub const VILLAGE_SNOWY: MapDecorationType = MapDecorationType {
id: 30u32,
name: "village_snowy",
asset_name: "snowy_village",
show_on_item_frame: true,
map_color: 10066329i32,
exploration_map_element: true,
track_count: false,
};
pub const VILLAGE_TAIGA: MapDecorationType = MapDecorationType {
id: 31u32,
name: "village_taiga",
asset_name: "taiga_village",
show_on_item_frame: true,
map_color: 10066329i32,
exploration_map_element: true,
track_count: false,
};
pub const JUNGLE_TEMPLE: MapDecorationType = MapDecorationType {
id: 32u32,
name: "jungle_temple",
asset_name: "jungle_temple",
show_on_item_frame: true,
map_color: 10066329i32,
exploration_map_element: true,
track_count: false,
};
pub const SWAMP_HUT: MapDecorationType = MapDecorationType {
id: 33u32,
name: "swamp_hut",
asset_name: "swamp_hut",
show_on_item_frame: true,
map_color: 10066329i32,
exploration_map_element: true,
track_count: false,
};
pub const TRIAL_CHAMBERS: MapDecorationType = MapDecorationType {
id: 34u32,
name: "trial_chambers",
asset_name: "trial_chambers",
show_on_item_frame: true,
map_color: 12741452i32,
exploration_map_element: true,
track_count: false,
};
pub const ALL: &'static [MapDecorationType] = &[
MapDecorationType::PLAYER,
MapDecorationType::FRAME,
MapDecorationType::RED_MARKER,
MapDecorationType::BLUE_MARKER,
MapDecorationType::TARGET_X,
MapDecorationType::TARGET_POINT,
MapDecorationType::PLAYER_OFF_MAP,
MapDecorationType::PLAYER_OFF_LIMITS,
MapDecorationType::MANSION,
MapDecorationType::MONUMENT,
MapDecorationType::BANNER_WHITE,
MapDecorationType::BANNER_ORANGE,
MapDecorationType::BANNER_MAGENTA,
MapDecorationType::BANNER_LIGHT_BLUE,
MapDecorationType::BANNER_YELLOW,
MapDecorationType::BANNER_LIME,
MapDecorationType::BANNER_PINK,
MapDecorationType::BANNER_GRAY,
MapDecorationType::BANNER_LIGHT_GRAY,
MapDecorationType::BANNER_CYAN,
MapDecorationType::BANNER_PURPLE,
MapDecorationType::BANNER_BLUE,
MapDecorationType::BANNER_BROWN,
MapDecorationType::BANNER_GREEN,
MapDecorationType::BANNER_RED,
MapDecorationType::BANNER_BLACK,
MapDecorationType::RED_X,
MapDecorationType::VILLAGE_DESERT,
MapDecorationType::VILLAGE_PLAINS,
MapDecorationType::VILLAGE_SAVANNA,
MapDecorationType::VILLAGE_SNOWY,
MapDecorationType::VILLAGE_TAIGA,
MapDecorationType::JUNGLE_TEMPLE,
MapDecorationType::SWAMP_HUT,
MapDecorationType::TRIAL_CHAMBERS,
];
#[must_use]
pub const fn from_id(id: u32) -> Option<&'static MapDecorationType> {
if (id as usize) < Self::ALL.len() {
Some(&Self::ALL[id as usize])
} else {
None
}
}
#[must_use]
pub fn from_name(name: &str) -> Option<&'static MapDecorationType> {
match name {
"player" => Some(&Self::PLAYER),
"frame" => Some(&Self::FRAME),
"red_marker" => Some(&Self::RED_MARKER),
"blue_marker" => Some(&Self::BLUE_MARKER),
"target_x" => Some(&Self::TARGET_X),
"target_point" => Some(&Self::TARGET_POINT),
"player_off_map" => Some(&Self::PLAYER_OFF_MAP),
"player_off_limits" => Some(&Self::PLAYER_OFF_LIMITS),
"mansion" => Some(&Self::MANSION),
"monument" => Some(&Self::MONUMENT),
"banner_white" => Some(&Self::BANNER_WHITE),
"banner_orange" => Some(&Self::BANNER_ORANGE),
"banner_magenta" => Some(&Self::BANNER_MAGENTA),
"banner_light_blue" => Some(&Self::BANNER_LIGHT_BLUE),
"banner_yellow" => Some(&Self::BANNER_YELLOW),
"banner_lime" => Some(&Self::BANNER_LIME),
"banner_pink" => Some(&Self::BANNER_PINK),
"banner_gray" => Some(&Self::BANNER_GRAY),
"banner_light_gray" => Some(&Self::BANNER_LIGHT_GRAY),
"banner_cyan" => Some(&Self::BANNER_CYAN),
"banner_purple" => Some(&Self::BANNER_PURPLE),
"banner_blue" => Some(&Self::BANNER_BLUE),
"banner_brown" => Some(&Self::BANNER_BROWN),
"banner_green" => Some(&Self::BANNER_GREEN),
"banner_red" => Some(&Self::BANNER_RED),
"banner_black" => Some(&Self::BANNER_BLACK),
"red_x" => Some(&Self::RED_X),
"village_desert" => Some(&Self::VILLAGE_DESERT),
"village_plains" => Some(&Self::VILLAGE_PLAINS),
"village_savanna" => Some(&Self::VILLAGE_SAVANNA),
"village_snowy" => Some(&Self::VILLAGE_SNOWY),
"village_taiga" => Some(&Self::VILLAGE_TAIGA),
"jungle_temple" => Some(&Self::JUNGLE_TEMPLE),
"swamp_hut" => Some(&Self::SWAMP_HUT),
"trial_chambers" => Some(&Self::TRIAL_CHAMBERS),
_ => None,
}
}
}

View File

@@ -371,3 +371,18 @@ pub mod villager;
#[rustfmt::skip]
#[path = "generated/slot_ranges.rs"]
pub mod slot_ranges;
#[cfg(feature = "map_color")]
#[rustfmt::skip]
#[path = "generated/map_color.rs"]
pub mod map_color;
#[cfg(feature = "map_decoration")]
#[rustfmt::skip]
#[path = "generated/map_decoration.rs"]
pub mod map_decoration;
#[cfg(feature = "dye_color")]
#[rustfmt::skip]
#[path = "generated/dye_color.rs"]
pub mod dye_color;

View File

@@ -0,0 +1,267 @@
use std::any::Any;
use std::future::Future;
use std::pin::Pin;
use std::sync::Mutex;
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
use pumpkin_nbt::compound::NbtCompound;
use pumpkin_nbt::tag::NbtTag;
use pumpkin_protocol::codec::var_int::VarInt;
use pumpkin_protocol::java::client::play::{CMapItemData, MapPatch};
use pumpkin_util::math::position::BlockPos;
use crate::block::entities::BlockEntity;
pub const MAP_BLOCK_ENTITY_ID: &str = "minecraft:map";
pub struct MapBlockEntity {
position: BlockPos,
map_id: AtomicI32,
colors: Mutex<Box<[u8; 128 * 128]>>,
dirty: AtomicBool,
}
impl MapBlockEntity {
#[must_use]
pub fn new(position: BlockPos, map_id: i32) -> Self {
Self {
position,
map_id: AtomicI32::new(map_id),
colors: Mutex::new(Box::new([0; 128 * 128])),
dirty: AtomicBool::new(true),
}
}
#[must_use]
pub fn get_map_id(&self) -> i32 {
self.map_id.load(Ordering::Relaxed)
}
pub fn set_map_id(&self, map_id: i32) {
self.map_id.store(map_id, Ordering::Relaxed);
self.dirty.store(true, Ordering::Relaxed);
}
pub fn get_colors(&self) -> Vec<u8> {
let colors = self
.colors
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
colors.to_vec()
}
pub fn set_colors(&self, new_colors: &[u8]) {
let mut colors = self
.colors
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
if new_colors.len() == 128 * 128 * 3 {
// RGB -> map color byte conversion
for i in 0..(128 * 128) {
let r = new_colors[i * 3];
let g = new_colors[i * 3 + 1];
let b = new_colors[i * 3 + 2];
colors[i] = rgb_to_map_color(r, g, b);
}
} else if new_colors.len() == 128 * 128 * 4 {
// RGBA -> map color byte conversion
for i in 0..(128 * 128) {
let r = new_colors[i * 4];
let g = new_colors[i * 4 + 1];
let b = new_colors[i * 4 + 2];
colors[i] = rgb_to_map_color(r, g, b);
}
} else {
let len = new_colors.len().min(128 * 128);
colors[..len].copy_from_slice(&new_colors[..len]);
}
self.dirty.store(true, Ordering::Relaxed);
}
pub fn set_pixel(&self, x: usize, y: usize, color: u8) {
if x < 128 && y < 128 {
let mut colors = self
.colors
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
colors[y * 128 + x] = color;
self.dirty.store(true, Ordering::Relaxed);
}
}
pub fn get_pixel(&self, x: usize, y: usize) -> u8 {
if x < 128 && y < 128 {
let colors = self
.colors
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
colors[y * 128 + x]
} else {
0
}
}
pub fn stream_frame(&self, frame_data: &[u8], server: Option<&crate::server::Server>) {
self.set_colors(frame_data);
if let Some(server) = server {
self.broadcast_map_data(server);
}
}
pub fn broadcast_map_data(&self, server: &crate::server::Server) {
let map_id = self.get_map_id();
let colors = self
.colors
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
let data = MapPatch {
columns: 128,
rows: 128,
x: 0,
z: 0,
data: &colors[..],
};
let packet = CMapItemData {
map_id: VarInt(map_id),
scale: 0,
locked: false,
icons: Some(&[]),
data: Some(data),
};
server.broadcast_packet_all(&packet);
self.dirty.store(false, Ordering::Relaxed);
}
}
impl BlockEntity for MapBlockEntity {
fn resource_location(&self) -> &'static str {
MAP_BLOCK_ENTITY_ID
}
fn get_position(&self) -> BlockPos {
self.position
}
fn from_nbt(nbt: &NbtCompound, position: BlockPos) -> Self
where
Self: Sized,
{
let map_id = nbt.get_int("MapId").unwrap_or(0);
let entity = Self::new(position, map_id);
if let Some(colors_nbt) = nbt.get("Colors").and_then(|tag| tag.extract_byte_array()) {
let mut colors = entity
.colors
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
let len = colors_nbt.len().min(128 * 128);
for (i, &b) in colors_nbt.iter().take(len).enumerate() {
colors[i] = b as u8;
}
}
entity
}
fn write_nbt<'a>(
&'a self,
nbt: &'a mut NbtCompound,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {
nbt.put_int("MapId", self.get_map_id());
let colors = self
.colors
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
let colors_i8: Vec<i8> = colors.iter().map(|&b| b as i8).collect();
nbt.put("Colors", NbtTag::ByteArray(colors_i8.into_boxed_slice()));
})
}
fn is_dirty(&self) -> bool {
self.dirty.load(Ordering::Relaxed)
}
fn clear_dirty(&self) {
self.dirty.store(false, Ordering::Relaxed);
}
fn as_any(&self) -> &dyn Any {
self
}
}
/// Helper function to convert an RGB value to the closest Minecraft map color index.
fn rgb_to_map_color(r: u8, g: u8, b: u8) -> u8 {
use pumpkin_data::map_color::MapColor;
// Brightness multipliers: 180 (low), 220 (normal), 255 (high), 135 (lowest)
const BRIGHTNESS: &[(u8, u32)] = &[(0, 180), (1, 220), (2, 255), (3, 135)];
let mut best_color: u8 = 0;
let mut min_diff: u32 = u32::MAX;
let r32 = u32::from(r);
let g32 = u32::from(g);
let b32 = u32::from(b);
for map_color in MapColor::ALL {
if map_color.id == 0 {
continue;
}
let (cr, cg, cb) = map_color.rgb;
for &(b_idx, mult) in BRIGHTNESS {
let pr = (u32::from(cr) * mult) / 255;
let pg = (u32::from(cg) * mult) / 255;
let pb = (u32::from(cb) * mult) / 255;
let dr = r32.abs_diff(pr);
let dg = g32.abs_diff(pg);
let db = b32.abs_diff(pb);
let diff = dr * dr + dg * dg + db * db;
if diff < min_diff {
min_diff = diff;
best_color = map_color.id * 4 + b_idx;
}
}
}
best_color
}
#[cfg(test)]
mod tests {
use super::*;
use pumpkin_util::math::position::BlockPos;
#[test]
fn map_block_entity_pixels_and_colors() {
let pos = BlockPos::new(10, 64, -5);
let map_be = MapBlockEntity::new(pos, 42);
assert_eq!(map_be.get_map_id(), 42);
assert_eq!(map_be.get_position(), pos);
map_be.set_map_id(100);
assert_eq!(map_be.get_map_id(), 100);
map_be.set_pixel(10, 20, 15);
assert_eq!(map_be.get_pixel(10, 20), 15);
let mut custom_frame = vec![0u8; 128 * 128];
custom_frame[0] = 5;
custom_frame[127] = 20;
map_be.set_colors(&custom_frame);
assert_eq!(map_be.get_pixel(0, 0), 5);
assert_eq!(map_be.get_pixel(127, 0), 20);
// Test RGB conversion frame
let mut rgb_frame = vec![0u8; 128 * 128 * 3];
// Red pixel at (0, 0)
rgb_frame[0] = 255;
rgb_frame[1] = 0;
rgb_frame[2] = 0;
map_be.set_colors(&rgb_frame);
assert!(map_be.get_pixel(0, 0) > 0);
}
}

View File

@@ -30,6 +30,7 @@ pub mod hopper;
pub mod jigsaw_block;
pub mod jukebox;
pub mod lectern;
pub mod map;
pub mod mob_spawner;
pub mod piston;
pub mod shulker_box;
@@ -277,6 +278,7 @@ pub fn block_entity_from_nbt(nbt: &NbtCompound) -> Option<Arc<dyn BlockEntity>>
conduit::ConduitBlockEntity::ID => {
Some(Arc::new(conduit::ConduitBlockEntity::from_nbt(nbt, pos)))
}
map::MAP_BLOCK_ENTITY_ID => Some(Arc::new(map::MapBlockEntity::from_nbt(nbt, pos))),
campfire::CampfireBlockEntity::ID => {
Some(Arc::new(campfire::CampfireBlockEntity::from_nbt(nbt, pos)))
}
@@ -439,6 +441,7 @@ pub fn create_block_entity(
"potent_sulfur" => Some(Arc::new(potent_sulfur::PotentSulfurBlockEntity::new(
position,
))),
"map" => Some(Arc::new(map::MapBlockEntity::new(position, 0))),
_ => None,
}
}

View File

@@ -11,104 +11,7 @@ use pumpkin_nbt::{compound::NbtCompound, tag::NbtTag};
use pumpkin_util::math::position::BlockPos;
use tokio::sync::Mutex;
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
#[repr(i8)]
pub enum DyeColor {
White = 0,
Orange = 1,
Magenta = 2,
LightBlue = 3,
Yellow = 4,
Lime = 5,
Pink = 6,
Gray = 7,
LightGray = 8,
Cyan = 9,
Purple = 10,
Blue = 11,
Brown = 12,
Green = 13,
Red = 14,
#[default]
Black = 15,
}
impl From<DyeColor> for String {
fn from(value: DyeColor) -> Self {
match value {
DyeColor::White => "white".to_string(),
DyeColor::Orange => "orange".to_string(),
DyeColor::Magenta => "magenta".to_string(),
DyeColor::LightBlue => "light_blue".to_string(),
DyeColor::Yellow => "yellow".to_string(),
DyeColor::Lime => "lime".to_string(),
DyeColor::Pink => "pink".to_string(),
DyeColor::Gray => "gray".to_string(),
DyeColor::LightGray => "light_gray".to_string(),
DyeColor::Cyan => "cyan".to_string(),
DyeColor::Purple => "purple".to_string(),
DyeColor::Blue => "blue".to_string(),
DyeColor::Brown => "brown".to_string(),
DyeColor::Green => "green".to_string(),
DyeColor::Red => "red".to_string(),
DyeColor::Black => "black".to_string(),
}
}
}
impl From<&str> for DyeColor {
fn from(s: &str) -> Self {
match s {
"white" => Self::White,
"orange" => Self::Orange,
"magenta" => Self::Magenta,
"light_blue" => Self::LightBlue,
"yellow" => Self::Yellow,
"lime" => Self::Lime,
"pink" => Self::Pink,
"gray" => Self::Gray,
"light_gray" => Self::LightGray,
"cyan" => Self::Cyan,
"purple" => Self::Purple,
"blue" => Self::Blue,
"brown" => Self::Brown,
"green" => Self::Green,
"red" => Self::Red,
"black" => Self::Black,
_ => Self::default(),
}
}
}
impl From<i8> for DyeColor {
fn from(s: i8) -> Self {
match s {
0 => Self::White,
1 => Self::Orange,
2 => Self::Magenta,
3 => Self::LightBlue,
4 => Self::Yellow,
5 => Self::Lime,
6 => Self::Pink,
7 => Self::Gray,
8 => Self::LightGray,
9 => Self::Cyan,
10 => Self::Purple,
11 => Self::Blue,
12 => Self::Brown,
13 => Self::Green,
14 => Self::Red,
15 => Self::Black,
_ => Self::default(),
}
}
}
impl From<DyeColor> for NbtTag {
fn from(value: DyeColor) -> Self {
Self::Byte(value as i8)
}
}
pub use pumpkin_data::dye_color::DyeColor;
pub struct SignBlockEntity {
pub front_text: Text,
@@ -152,7 +55,7 @@ impl From<Text> for NbtTag {
"has_glowing_text",
value.has_glowing_text.load(Ordering::Relaxed),
);
nbt.put_string("color", value.get_color().into());
nbt.put_string("color", value.get_color().name().to_string());
nbt.put_list(
"messages",
value
@@ -184,7 +87,7 @@ impl From<NbtTag> for Text {
Self {
has_glowing_text: AtomicBool::new(has_glowing_text),
color: AtomicI8::new(DyeColor::from(color) as i8),
color: AtomicI8::new(DyeColor::by_name(color).unwrap_or_default().id() as i8),
messages: Arc::new(std::sync::Mutex::new([
get_message(0),
get_message(1),
@@ -200,17 +103,22 @@ impl Text {
pub fn new(messages: [Box<str>; 4]) -> Self {
Self {
has_glowing_text: AtomicBool::new(false),
color: AtomicI8::new(DyeColor::default() as i8),
color: AtomicI8::new(DyeColor::default().id() as i8),
messages: Arc::new(std::sync::Mutex::new(messages)),
}
}
pub fn get_color(&self) -> DyeColor {
self.color.load(Ordering::Relaxed).into()
let c = self.color.load(Ordering::Relaxed);
if c >= 0 {
DyeColor::by_id(c as u8).unwrap_or_default()
} else {
DyeColor::default()
}
}
pub fn set_color(&self, color: DyeColor) {
self.color.store(color as i8, Ordering::Relaxed);
self.color.store(color.id() as i8, Ordering::Relaxed);
}
}

View File

@@ -4133,15 +4133,26 @@ impl Player {
let dx = pos.x - map_data.center_x as f64;
let dz = pos.z - map_data.center_z as f64;
let icon_x = (dx / scale as f64 * 2.0).clamp(-128.0, 127.0) as i8;
let icon_z = (dz / scale as f64 * 2.0).clamp(-128.0, 127.0) as i8;
let raw_x = dx / scale as f64 * 2.0;
let raw_z = dz / scale as f64 * 2.0;
let is_off_map = !(-127.0..=127.0).contains(&raw_x)
|| !(-127.0..=127.0).contains(&raw_z);
let icon_x = raw_x.clamp(-128.0, 127.0) as i8;
let icon_z = raw_z.clamp(-128.0, 127.0) as i8;
let yaw = self.living_entity.entity.yaw.load();
let icon_direction =
((((yaw * 16.0 / 360.0).round() as i32 + 8) % 16 + 16) % 16) as i8;
let decoration_type = if is_off_map {
&pumpkin_data::map_decoration::MapDecorationType::PLAYER_OFF_MAP
} else {
&pumpkin_data::map_decoration::MapDecorationType::PLAYER
};
let icons = [MapIcon {
icon_type: VarInt(0), // White pointer
icon_type: VarInt(decoration_type.id as i32),
x: icon_x,
z: icon_z,
direction: icon_direction,

View File

@@ -39,7 +39,7 @@ impl DyeItem {
text: &Text,
color_name: &str,
) -> BlockActionResult {
let dye_color = DyeColor::from(color_name);
let dye_color = DyeColor::by_name(color_name).unwrap_or_default();
text.set_color(dye_color);

View File

@@ -67,6 +67,14 @@ pub type ItemStackResource = WasmResource<Arc<Mutex<pumpkin_data::item_stack::It
pub type RecipeManagerResource = WasmResource<Arc<RecipeManager>>;
pub type BlockEntityResource = WasmResource<Arc<dyn crate::block::entities::BlockEntity>>;
#[derive(Clone)]
pub struct ContainerBlockEntity {
pub provider: Arc<dyn crate::block::entities::BlockEntity>,
pub inventory: Arc<dyn pumpkin_world::inventory::Inventory>,
}
pub type ContainerBlockEntityResource = WasmResource<ContainerBlockEntity>;
pub type OwnedConsumedArgs = HashMap<String, OwnedArg>;
pub struct PluginHostState {
@@ -293,6 +301,20 @@ impl PluginHostState {
let resource = self.resource_table.push(BlockEntityResource { provider })?;
Ok(wasmtime::component::Resource::new_own(resource.rep()))
}
pub fn add_container_block_entity<T>(
&mut self,
provider: Arc<dyn crate::block::entities::BlockEntity>,
inventory: Arc<dyn pumpkin_world::inventory::Inventory>,
) -> wasmtime::Result<wasmtime::component::Resource<T>> {
let resource = self.resource_table.push(ContainerBlockEntityResource {
provider: ContainerBlockEntity {
provider,
inventory,
},
})?;
Ok(wasmtime::component::Resource::new_own(resource.rep()))
}
}
pub struct PluginHttpHooks {

View File

@@ -8,11 +8,57 @@ use pumpkin_world::world::BlockFlags;
use std::sync::Arc;
use wasmtime::component::Resource;
use crate::block::entities::banner::BannerBlockEntity as InternalBannerBlockEntity;
use crate::block::entities::barrel::BarrelBlockEntity as InternalBarrelBlockEntity;
use crate::block::entities::beacon::BeaconBlockEntity as InternalBeaconBlockEntity;
use crate::block::entities::bed::BedBlockEntity as InternalBedBlockEntity;
use crate::block::entities::beehive::BeehiveBlockEntity as InternalBeehiveBlockEntity;
use crate::block::entities::bell::BellBlockEntity as InternalBellBlockEntity;
use crate::block::entities::blasting_furnace::BlastingFurnaceBlockEntity as InternalBlastingFurnaceBlockEntity;
use crate::block::entities::brewing_stand::BrewingStandBlockEntity as InternalBrewingStandBlockEntity;
use crate::block::entities::brushable_block::BrushableBlockBlockEntity as InternalBrushableBlockBlockEntity;
use crate::block::entities::calibrated_sculk_sensor::CalibratedSculkSensorBlockEntity as InternalCalibratedSculkSensorBlockEntity;
use crate::block::entities::campfire::CampfireBlockEntity as InternalCampfireBlockEntity;
use crate::block::entities::chest::ChestBlockEntity as InternalChestBlockEntity;
use crate::block::entities::chiseled_bookshelf::ChiseledBookshelfBlockEntity as InternalChiseledBookshelfBlockEntity;
use crate::block::entities::command_block::CommandBlockEntity as InternalCommandBlockEntity;
use crate::block::entities::comparator::ComparatorBlockEntity as InternalComparatorBlockEntity;
use crate::block::entities::conduit::ConduitBlockEntity as InternalConduitBlockEntity;
use crate::block::entities::copper_golem_statue::CopperGolemStatueBlockEntity as InternalCopperGolemStatueBlockEntity;
use crate::block::entities::crafter::CrafterBlockEntity as InternalCrafterBlockEntity;
use crate::block::entities::creaking_heart::CreakingHeartBlockEntity as InternalCreakingHeartBlockEntity;
use crate::block::entities::daylight_detector::DaylightDetectorBlockEntity as InternalDaylightDetectorBlockEntity;
use crate::block::entities::decorated_pot::DecoratedPotBlockEntity as InternalDecoratedPotBlockEntity;
use crate::block::entities::dispenser::DispenserBlockEntity as InternalDispenserBlockEntity;
use crate::block::entities::dropper::DropperBlockEntity as InternalDropperBlockEntity;
use crate::block::entities::enchanting_table::EnchantingTableBlockEntity as InternalEnchantingTableBlockEntity;
use crate::block::entities::end_gateway::EndGatewayBlockEntity as InternalEndGatewayBlockEntity;
use crate::block::entities::end_portal::EndPortalBlockEntity as InternalEndPortalBlockEntity;
use crate::block::entities::ender_chest::EnderChestBlockEntity as InternalEnderChestBlockEntity;
use crate::block::entities::furnace::FurnaceBlockEntity as InternalFurnaceBlockEntity;
use crate::block::entities::hanging_sign::HangingSignBlockEntity as InternalHangingSignBlockEntity;
use crate::block::entities::hopper::HopperBlockEntity as InternalHopperBlockEntity;
use crate::block::entities::jigsaw_block::JigsawBlockEntity as InternalJigsawBlockEntity;
use crate::block::entities::jukebox::JukeboxBlockEntity as InternalJukeboxBlockEntity;
use crate::block::entities::lectern::LecternBlockEntity as InternalLecternBlockEntity;
use crate::block::entities::map::MapBlockEntity as InternalMapBlockEntity;
use crate::block::entities::mob_spawner::MobSpawnerBlockEntity as InternalMobSpawnerBlockEntity;
use crate::block::entities::piston::PistonBlockEntity as InternalPistonBlockEntity;
use crate::block::entities::potent_sulfur::PotentSulfurBlockEntity as InternalPotentSulfurBlockEntity;
use crate::block::entities::sculk_catalyst::SculkCatalystBlockEntity as InternalSculkCatalystBlockEntity;
use crate::block::entities::sculk_sensor::SculkSensorBlockEntity as InternalSculkSensorBlockEntity;
use crate::block::entities::sculk_shrieker::SculkShriekerBlockEntity as InternalSculkShriekerBlockEntity;
use crate::block::entities::shelf::ShelfBlockEntity as InternalShelfBlockEntity;
use crate::block::entities::shulker_box::ShulkerBoxBlockEntity as InternalShulkerBoxBlockEntity;
use crate::block::entities::sign::SignBlockEntity as InternalSignBlockEntity;
use crate::block::entities::skull::SkullBlockEntity as InternalSkullBlockEntity;
use crate::block::entities::smoker::SmokerBlockEntity as InternalSmokerBlockEntity;
use crate::block::entities::structure_block::StructureBlockBlockEntity as InternalStructureBlockBlockEntity;
use crate::block::entities::test_block::TestBlockBlockEntity as InternalTestBlockBlockEntity;
use crate::block::entities::test_instance_block::TestInstanceBlockBlockEntity as InternalTestInstanceBlockBlockEntity;
use crate::block::entities::trapped_chest::TrappedChestBlockEntity as InternalTrappedChestBlockEntity;
use crate::block::entities::trial_spawner::TrialSpawnerBlockEntity as InternalTrialSpawnerBlockEntity;
use crate::block::entities::vault::VaultBlockEntity as InternalVaultBlockEntity;
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::common::Position as WitPosition;
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::world::{
BlockDirection as WitBlockDirection, BlockEntity, BlockEntityType, BlockFlags as WitBlockFlags,
@@ -143,54 +189,72 @@ impl PluginHostState {
block_entity: Arc<dyn crate::block::entities::BlockEntity>,
) -> wasmtime::Result<Option<BlockEntityType>> {
let be = block_entity;
if be
.as_any()
.downcast_ref::<InternalCommandBlockEntity>()
.is_some()
{
let res: Resource<BlockEntity> = self.add_block_entity(be)?;
Ok(Some(BlockEntityType::CommandBlockEntity(
Resource::new_own(res.rep()),
)))
} else if be
.as_any()
.downcast_ref::<InternalSignBlockEntity>()
.is_some()
{
let res: Resource<BlockEntity> = self.add_block_entity(be)?;
Ok(Some(BlockEntityType::SignBlockEntity(Resource::new_own(
res.rep(),
))))
} else if be
.as_any()
.downcast_ref::<InternalJukeboxBlockEntity>()
.is_some()
{
let res: Resource<BlockEntity> = self.add_block_entity(be)?;
Ok(Some(BlockEntityType::JukeboxBlockEntity(
Resource::new_own(res.rep()),
)))
} else if be
.as_any()
.downcast_ref::<InternalChestBlockEntity>()
.is_some()
{
let res: Resource<BlockEntity> = self.add_block_entity(be)?;
Ok(Some(BlockEntityType::ChestBlockEntity(Resource::new_own(
res.rep(),
))))
} else if be
.as_any()
.downcast_ref::<InternalMobSpawnerBlockEntity>()
.is_some()
{
let res: Resource<BlockEntity> = self.add_block_entity(be)?;
Ok(Some(BlockEntityType::MobSpawnerBlockEntity(
Resource::new_own(res.rep()),
)))
} else {
Ok(None)
macro_rules! match_be {
($( $internal_type:ty => $variant:ident ),* $(,)?) => {
$(
if be.as_any().downcast_ref::<$internal_type>().is_some() {
let res: Resource<BlockEntity> = self.add_block_entity(be)?;
return Ok(Some(BlockEntityType::$variant(Resource::new_own(res.rep()))));
}
)*
};
}
match_be! {
InternalCommandBlockEntity => CommandBlockEntity,
InternalSignBlockEntity => SignBlockEntity,
InternalHangingSignBlockEntity => HangingSignBlockEntity,
InternalJukeboxBlockEntity => JukeboxBlockEntity,
InternalChestBlockEntity => ChestBlockEntity,
InternalTrappedChestBlockEntity => TrappedChestBlockEntity,
InternalMobSpawnerBlockEntity => MobSpawnerBlockEntity,
InternalMapBlockEntity => MapBlockEntity,
InternalBannerBlockEntity => BannerBlockEntity,
InternalBarrelBlockEntity => BarrelBlockEntity,
InternalBeaconBlockEntity => BeaconBlockEntity,
InternalBedBlockEntity => BedBlockEntity,
InternalBeehiveBlockEntity => BeehiveBlockEntity,
InternalBellBlockEntity => BellBlockEntity,
InternalBlastingFurnaceBlockEntity => BlastingFurnaceBlockEntity,
InternalBrewingStandBlockEntity => BrewingStandBlockEntity,
InternalBrushableBlockBlockEntity => BrushableBlockBlockEntity,
InternalCalibratedSculkSensorBlockEntity => CalibratedSculkSensorBlockEntity,
InternalCampfireBlockEntity => CampfireBlockEntity,
InternalChiseledBookshelfBlockEntity => ChiseledBookshelfBlockEntity,
InternalComparatorBlockEntity => ComparatorBlockEntity,
InternalConduitBlockEntity => ConduitBlockEntity,
InternalCopperGolemStatueBlockEntity => CopperGolemStatueBlockEntity,
InternalCrafterBlockEntity => CrafterBlockEntity,
InternalCreakingHeartBlockEntity => CreakingHeartBlockEntity,
InternalDaylightDetectorBlockEntity => DaylightDetectorBlockEntity,
InternalDecoratedPotBlockEntity => DecoratedPotBlockEntity,
InternalDispenserBlockEntity => DispenserBlockEntity,
InternalDropperBlockEntity => DropperBlockEntity,
InternalEnchantingTableBlockEntity => EnchantingTableBlockEntity,
InternalEndGatewayBlockEntity => EndGatewayBlockEntity,
InternalEndPortalBlockEntity => EndPortalBlockEntity,
InternalEnderChestBlockEntity => EnderChestBlockEntity,
InternalFurnaceBlockEntity => FurnaceBlockEntity,
InternalHopperBlockEntity => HopperBlockEntity,
InternalJigsawBlockEntity => JigsawBlockEntity,
InternalLecternBlockEntity => LecternBlockEntity,
InternalPistonBlockEntity => PistonBlockEntity,
InternalPotentSulfurBlockEntity => PotentSulfurBlockEntity,
InternalSculkCatalystBlockEntity => SculkCatalystBlockEntity,
InternalSculkSensorBlockEntity => SculkSensorBlockEntity,
InternalSculkShriekerBlockEntity => SculkShriekerBlockEntity,
InternalShelfBlockEntity => ShelfBlockEntity,
InternalShulkerBoxBlockEntity => ShulkerBoxBlockEntity,
InternalSkullBlockEntity => SkullBlockEntity,
InternalSmokerBlockEntity => SmokerBlockEntity,
InternalStructureBlockBlockEntity => StructureBlockBlockEntity,
InternalTestBlockBlockEntity => TestBlockBlockEntity,
InternalTestInstanceBlockBlockEntity => TestInstanceBlockBlockEntity,
InternalTrialSpawnerBlockEntity => TrialSpawnerBlockEntity,
InternalVaultBlockEntity => VaultBlockEntity,
}
Ok(None)
}
}

View File

@@ -0,0 +1,194 @@
use std::fs;
use heck::{ToPascalCase, ToShoutySnakeCase};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use serde::Deserialize;
#[derive(Deserialize)]
struct DyeColorEntry {
id: u8,
name: String,
map_color_id: u8,
terracotta_color_id: u8,
texture_diffuse_color: u32,
firework_color: u32,
text_color: u32,
}
pub fn build() -> TokenStream {
let dye_colors: Vec<DyeColorEntry> =
serde_json::from_str(&fs::read_to_string("../../assets/dye_colors.json").unwrap())
.expect("Failed to parse dye_colors.json");
let mut variants = TokenStream::new();
let mut id_match_arms = TokenStream::new();
let mut name_match_arms = TokenStream::new();
let mut to_id_arms = TokenStream::new();
let mut to_name_arms = TokenStream::new();
let mut map_color_id_arms = TokenStream::new();
let mut terracotta_color_id_arms = TokenStream::new();
let mut texture_diffuse_color_arms = TokenStream::new();
let mut firework_color_arms = TokenStream::new();
let mut text_color_arms = TokenStream::new();
for entry in &dye_colors {
let id = entry.id;
let name_str = &entry.name;
let variant_ident = format_ident!("{}", name_str.to_pascal_case());
let map_color_id = entry.map_color_id;
let terracotta_color_id = entry.terracotta_color_id;
let texture_diffuse_color = entry.texture_diffuse_color;
let firework_color = entry.firework_color;
let text_color = entry.text_color;
let is_default = if name_str == "black" {
quote! { #[default] }
} else {
quote! {}
};
variants.extend(quote! {
#is_default
#variant_ident,
});
id_match_arms.extend(quote! {
#id => Some(Self::#variant_ident),
});
name_match_arms.extend(quote! {
#name_str => Some(Self::#variant_ident),
});
to_id_arms.extend(quote! {
Self::#variant_ident => #id,
});
to_name_arms.extend(quote! {
Self::#variant_ident => #name_str,
});
map_color_id_arms.extend(quote! {
Self::#variant_ident => #map_color_id,
});
terracotta_color_id_arms.extend(quote! {
Self::#variant_ident => #terracotta_color_id,
});
texture_diffuse_color_arms.extend(quote! {
Self::#variant_ident => #texture_diffuse_color,
});
firework_color_arms.extend(quote! {
Self::#variant_ident => #firework_color,
});
text_color_arms.extend(quote! {
Self::#variant_ident => #text_color,
});
}
quote! {
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum DyeColor {
#variants
}
impl DyeColor {
#[must_use]
pub const fn id(&self) -> u8 {
match self {
#to_id_arms
}
}
#[must_use]
pub const fn name(&self) -> &'static str {
match self {
#to_name_arms
}
}
#[must_use]
pub const fn map_color_id(&self) -> u8 {
match self {
#map_color_id_arms
}
}
#[must_use]
pub const fn terracotta_color_id(&self) -> u8 {
match self {
#terracotta_color_id_arms
}
}
#[must_use]
pub const fn texture_diffuse_color(&self) -> u32 {
match self {
#texture_diffuse_color_arms
}
}
#[must_use]
pub const fn firework_color(&self) -> u32 {
match self {
#firework_color_arms
}
}
#[must_use]
pub const fn text_color(&self) -> u32 {
match self {
#text_color_arms
}
}
#[must_use]
pub const fn by_id(id: u8) -> Option<Self> {
match id {
#id_match_arms
_ => None,
}
}
#[must_use]
pub fn by_name(name: &str) -> Option<Self> {
match name {
#name_match_arms
_ => None,
}
}
}
impl From<DyeColor> for String {
fn from(value: DyeColor) -> Self {
value.name().to_string()
}
}
impl From<&str> for DyeColor {
fn from(s: &str) -> Self {
DyeColor::by_name(s).unwrap_or_default()
}
}
impl From<i8> for DyeColor {
fn from(s: i8) -> Self {
if s >= 0 {
DyeColor::by_id(s as u8).unwrap_or_default()
} else {
DyeColor::default()
}
}
}
impl From<u8> for DyeColor {
fn from(s: u8) -> Self {
DyeColor::by_id(s).unwrap_or_default()
}
}
}
}

View File

@@ -42,6 +42,7 @@ mod configured_feature;
mod damage_type;
mod data_component;
mod dimension;
mod dye_color;
mod effect;
mod enchantments;
mod entity_pose;
@@ -55,6 +56,8 @@ mod game_rules;
mod item;
mod jukebox_song;
pub mod loot;
mod map_color;
mod map_decoration;
mod message_type;
mod meta_data_type;
mod noise_parameter;
@@ -160,6 +163,9 @@ pub fn main() {
),
(carver::build, "carver.rs"),
(chest_loot::build, "chest_loot.rs"),
(map_color::build, "map_color.rs"),
(map_decoration::build, "map_decoration.rs"),
(dye_color::build, "dye_color.rs"),
];
build_functions.extend(remap::build());

View File

@@ -0,0 +1,99 @@
use std::fs;
use heck::{ToPascalCase, ToShoutySnakeCase};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use serde::Deserialize;
#[derive(Deserialize)]
struct MapColorEntry {
id: u8,
name: String,
col: u32,
hex: String,
rgb: (u8, u8, u8),
}
pub fn build() -> TokenStream {
let colors: Vec<MapColorEntry> =
serde_json::from_str(&fs::read_to_string("../../assets/map_colors.json").unwrap())
.expect("Failed to parse map_colors.json");
let mut constants = TokenStream::new();
let mut all_elements = TokenStream::new();
let mut id_match_arms = TokenStream::new();
let mut name_match_arms = TokenStream::new();
let mut seen_names = std::collections::HashSet::new();
for entry in &colors {
let id = entry.id;
let name = &entry.name;
let const_name = if name == "none" {
format_ident!("NONE_{}", id)
} else {
format_ident!("{}", name.to_shouty_snake_case())
};
let col = entry.col;
let (r, g, b) = entry.rgb;
constants.extend(quote! {
pub const #const_name: MapColor = MapColor {
id: #id,
name: #name,
col: #col,
rgb: (#r, #g, #b),
};
});
all_elements.extend(quote! {
MapColor::#const_name,
});
id_match_arms.extend(quote! {
#id => Some(&Self::#const_name),
});
if seen_names.insert(name.clone()) {
name_match_arms.extend(quote! {
#name => Some(&Self::#const_name),
});
}
}
quote! {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MapColor {
pub id: u8,
pub name: &'static str,
pub col: u32,
pub rgb: (u8, u8, u8),
}
impl MapColor {
#constants
pub const ALL: &'static [MapColor] = &[
#all_elements
];
#[must_use]
pub const fn from_id(id: u8) -> Option<&'static MapColor> {
if (id as usize) < Self::ALL.len() {
Some(&Self::ALL[id as usize])
} else {
None
}
}
#[must_use]
pub fn from_name(name: &str) -> Option<&'static MapColor> {
match name {
#name_match_arms
_ => None,
}
}
}
}
}

View File

@@ -0,0 +1,95 @@
use std::fs;
use heck::{ToPascalCase, ToShoutySnakeCase};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use serde::Deserialize;
#[derive(Deserialize)]
struct MapDecorationEntry {
name: String,
asset_name: String,
show_on_item_frame: bool,
map_color: i32,
exploration_map_element: bool,
track_count: bool,
}
pub fn build() -> TokenStream {
let decorations: Vec<MapDecorationEntry> =
serde_json::from_str(&fs::read_to_string("../../assets/map_decorations.json").unwrap())
.expect("Failed to parse map_decorations.json");
let mut constants = TokenStream::new();
let mut all_elements = TokenStream::new();
let mut name_match_arms = TokenStream::new();
for (index, entry) in decorations.iter().enumerate() {
let id = index as u32;
let name = &entry.name;
let const_name = format_ident!("{}", name.to_shouty_snake_case());
let asset_name = &entry.asset_name;
let show_on_item_frame = entry.show_on_item_frame;
let map_color = entry.map_color;
let exploration_map_element = entry.exploration_map_element;
let track_count = entry.track_count;
constants.extend(quote! {
pub const #const_name: MapDecorationType = MapDecorationType {
id: #id,
name: #name,
asset_name: #asset_name,
show_on_item_frame: #show_on_item_frame,
map_color: #map_color,
exploration_map_element: #exploration_map_element,
track_count: #track_count,
};
});
all_elements.extend(quote! {
MapDecorationType::#const_name,
});
name_match_arms.extend(quote! {
#name => Some(&Self::#const_name),
});
}
quote! {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MapDecorationType {
pub id: u32,
pub name: &'static str,
pub asset_name: &'static str,
pub show_on_item_frame: bool,
pub map_color: i32,
pub exploration_map_element: bool,
pub track_count: bool,
}
impl MapDecorationType {
#constants
pub const ALL: &'static [MapDecorationType] = &[
#all_elements
];
#[must_use]
pub const fn from_id(id: u32) -> Option<&'static MapDecorationType> {
if (id as usize) < Self::ALL.len() {
Some(&Self::ALL[id as usize])
} else {
None
}
}
#[must_use]
pub fn from_name(name: &str) -> Option<&'static MapDecorationType> {
match name {
#name_match_arms
_ => None,
}
}
}
}
}