1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//! Block metadata queries: per-block facts, tags, kinds, shape variants and
//! block-state enumeration over the built-in block table. Bridge-native
//! surface (no old `ffi/*.rs` counterpart) fronting
//! [`crate::blockpedia::facts_json`].
#[diplomat::bridge]
pub mod ffi {
use super::super::shared::ffi::NucleationError;
use diplomat_runtime::DiplomatWrite;
use std::fmt::Write;
/// Namespace for read-only queries over the built-in block table
/// (Java 26.2 blocks + official semantics extracted from the vanilla
/// jars: definition kinds, base-block links, block tags, model
/// geometry). All list results are JSON array strings sorted by id;
/// block/tag/kind arguments accept both `minecraft:`-prefixed and
/// short forms (`minecraft:oak_stairs` / `oak_stairs`).
#[diplomat::opaque]
pub struct Blocks;
impl Blocks {
/// Full facts for one block as a JSON object:
/// `{id, kind, base_block, tags: [...], full_cube, transparent,
/// color: [r, g, b] | null, properties: {name: [values...]},
/// default_state: {name: value}}`. `kind` is the official
/// definition kind (`minecraft:stair`, plain full blocks are
/// `minecraft:block`); `base_block` is the block this one is a
/// shape variant of (or `null`); `color` is the texture-derived
/// average RGB. Errors with `NotFound` for unknown ids.
pub fn get_json(
id: &DiplomatStr,
out: &mut DiplomatWrite,
) -> Result<(), NucleationError> {
let id = std::str::from_utf8(id).map_err(|_| NucleationError::InvalidArgument)?;
let json = crate::blockpedia::facts_json::block_facts_json(id)
.ok_or(NucleationError::NotFound)?;
let _ = write!(out, "{json}");
Ok(())
}
/// All known block ids as a sorted JSON array string.
pub fn ids_json(out: &mut DiplomatWrite) {
let _ = write!(out, "{}", crate::blockpedia::facts_json::all_block_ids_json());
}
/// Ids of every block carrying the vanilla block tag, as a sorted
/// Blocks whose measured texture color is within `max_distance`
/// (Oklab; ~0.05 = same color family, ~0.15 = generous) of the given
/// RGB, as a JSON array of `{"id", "color": [r,g,b], "distance"}`
/// sorted nearest-first. Blocks without color data never match.
pub fn by_color_json(
r: u8,
g: u8,
b: u8,
max_distance: f32,
out: &mut DiplomatWrite,
) -> Result<(), NucleationError> {
let target = crate::blockpedia::ExtendedColorData::from_rgb(r, g, b);
let mut hits: Vec<(f32, &str, [u8; 3])> = crate::blockpedia::all_blocks()
.filter_map(|f| {
let c = f.extras.color.as_ref()?.to_extended();
let d = c.distance_oklab(&target);
(d <= max_distance).then_some((d, f.id, c.rgb))
})
.collect();
hits.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal));
let rows: Vec<serde_json::Value> = hits
.into_iter()
.map(|(d, id, rgb)| {
serde_json::json!({"id": id, "color": rgb, "distance": (d * 1000.0).round() / 1000.0})
})
.collect();
let _ = write!(
out,
"{}",
serde_json::to_string(&rows).unwrap_or_default()
);
Ok(())
}
/// JSON array string (`[]` for unknown tags). Accepts
/// `minecraft:wool` and short `wool` forms, including nested paths
/// like `mineable/pickaxe`.
pub fn by_tag_json(
tag: &DiplomatStr,
out: &mut DiplomatWrite,
) -> Result<(), NucleationError> {
let tag = std::str::from_utf8(tag).map_err(|_| NucleationError::InvalidArgument)?;
let _ = write!(
out,
"{}",
crate::blockpedia::facts_json::block_ids_by_tag_json(tag)
);
Ok(())
}
/// Ids of every block of the given official definition kind
/// (`minecraft:stair`, `minecraft:slab`, `minecraft:door`, ...), as
/// a sorted JSON array string (`[]` for unknown kinds).
pub fn by_kind_json(
kind: &DiplomatStr,
out: &mut DiplomatWrite,
) -> Result<(), NucleationError> {
let kind = std::str::from_utf8(kind).map_err(|_| NucleationError::InvalidArgument)?;
let _ = write!(
out,
"{}",
crate::blockpedia::facts_json::block_ids_by_kind_json(kind)
);
Ok(())
}
/// The base block followed by all its shape variants — blocks whose
/// `base_block` is `base_id` (stairs, slabs, walls, fences of the
/// base) — as a JSON array string. The base itself is always first;
/// variants follow sorted by id. Errors with `NotFound` for unknown
/// base ids.
pub fn variants_of_json(
base_id: &DiplomatStr,
out: &mut DiplomatWrite,
) -> Result<(), NucleationError> {
let base_id =
std::str::from_utf8(base_id).map_err(|_| NucleationError::InvalidArgument)?;
let json = crate::blockpedia::facts_json::variants_of_ids_json(base_id)
.ok_or(NucleationError::NotFound)?;
let _ = write!(out, "{json}");
Ok(())
}
/// All known vanilla block tag names as a sorted JSON array string
/// (`minecraft:`-prefixed, e.g. `minecraft:wool`).
pub fn tags_json(out: &mut DiplomatWrite) {
let _ = write!(out, "{}", crate::blockpedia::facts_json::all_tags_json());
}
/// Every property-value combination of the block as a JSON array of
/// `{prop: value}` objects (a single `{}` entry for property-less
/// blocks). Errors with `NotFound` for unknown ids and with
/// `InvalidArgument` if the combination count exceeds 4096 (guard
/// against pathological output; the current data tops out at 1350
/// for `minecraft:note_block`).
pub fn states_json(
id: &DiplomatStr,
out: &mut DiplomatWrite,
) -> Result<(), NucleationError> {
let id = std::str::from_utf8(id).map_err(|_| NucleationError::InvalidArgument)?;
let json = crate::blockpedia::facts_json::block_states_json(id).map_err(
|e| match e {
crate::blockpedia::BlockpediaError::Block(
crate::blockpedia::errors::BlockError::NotFound(_),
) => NucleationError::NotFound,
_ => NucleationError::InvalidArgument,
},
)?;
let _ = write!(out, "{json}");
Ok(())
}
/// Total number of blocks in the table.
pub fn count() -> usize {
crate::blockpedia::facts_json::block_count()
}
}
}