-
Notifications
You must be signed in to change notification settings - Fork 1
/
build.rs
156 lines (149 loc) · 5.4 KB
/
build.rs
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
use serde::Deserialize;
use serde_json::{Value, Map};
const AUTOGENERATED: &str =
"/*
* THIS FILE IS AUTOGENERATED BY golden_apple::build.rs
* MODIFICATIONS WILL BE OVERWRITTEN
*/
";
fn main() -> Result<(), serde_json::Error> {
let registries_bytes = include_bytes!("mojang/registries.json");
// TODO: decide what to do about blockstates
let blockstates_bytes = include_bytes!("mojang/blocks.json");
let registries: Registries = serde_json::from_slice(registries_bytes)?;
generate_enum(
registries.mob_effect.entries.as_object().unwrap(),
"potion_effects.rs",
"PotionEffect",
"/// Represents any effect that can be given, via potions or otherwise"
);
generate_enum(
registries.block.entries.as_object().unwrap(),
"blocks.rs",
"Block",
"/// This represents the block's ID, **NOT** the blockstate ID!"
);
generate_enum(
registries.entity_type.entries.as_object().unwrap(),
"entity_types.rs",
"EntityType",
""
);
generate_enum(
registries.item.entries.as_object().unwrap(),
"items.rs",
"Item",
""
);
generate_enum(
registries.particle_type.entries.as_object().unwrap(),
"particles.rs",
"Particle",
""
);
generate_enum(
registries.profession.entries.as_object().unwrap(),
"professions.rs",
"VillagerProfession",
""
);
generate_enum(
registries.custom_stat.entries.as_object().unwrap(),
"custom_stats.rs",
"CustomStatistic",
"/// Represents a statistic that doesn't fall under the main categories"
);
Ok(())
}
#[derive(Deserialize)]
struct Registries {
#[serde(rename(deserialize = "minecraft:sound_event"))]
sound_event: Registry,
#[serde(rename(deserialize = "minecraft:fluid"))]
fluid: Registry,
#[serde(rename(deserialize = "minecraft:mob_effect"))]
mob_effect: Registry,
#[serde(rename(deserialize = "minecraft:block"))]
block: Registry,
#[serde(rename(deserialize = "minecraft:entity_type"))]
entity_type: Registry,
#[serde(rename(deserialize = "minecraft:item"))]
item: Registry,
#[serde(rename(deserialize = "minecraft:particle_type"))]
particle_type: Registry,
#[serde(rename(deserialize = "minecraft:potion"))]
potion: Registry,
#[serde(rename(deserialize = "minecraft:villager_profession"))]
profession: Registry,
#[serde(rename(deserialize = "minecraft:custom_stat"))]
custom_stat: Registry,
}
#[derive(Deserialize)]
struct Registry {
protocol_id: u8,
default: Option<String>,
entries: Value
}
/// An entry in a registry is made up of the namespaced entry name and its protocol ID.
type Entries = Vec<(String, u32)>;
fn convert_to_camel_case(snake_case: &str) -> String {
let mut last_char = None;
let mut final_out = String::new();
for char in snake_case.chars() {
if char == '_' {
// don't write _ to end name
}
else if last_char == Some('_') {
final_out += &char.to_ascii_uppercase().to_string();
}
else {
final_out += &char.to_string();
}
last_char = Some(char);
}
let mut tmp_iter = final_out.chars();
tmp_iter.next().unwrap();
let final_final_out = format!("{}{}", final_out.chars().take(1).next().unwrap().to_ascii_uppercase(), tmp_iter.as_str());
return final_final_out;
}
// TODO: this is gross. I could do this so much better now, so I should. Maybe later!
fn generate_enum(data_bloq: &Map<String, Value>, save_loc: &str, enum_name: &str, doc_comment: &str) {
let mut constructed_blocks = String::from(AUTOGENERATED);
constructed_blocks += doc_comment;
constructed_blocks += "\n";
constructed_blocks += "#[derive(Clone, Copy, Eq, PartialEq, Debug)]\n";
constructed_blocks += "pub enum ";
constructed_blocks += enum_name;
constructed_blocks += " {\n";
let mut all_blocks: Entries = vec![];
for (name, value) in data_bloq.iter() {
all_blocks.push((name.clone(), value["protocol_id"].as_i64().unwrap() as u32));
}
all_blocks.sort_by(|a, b| { a.1.cmp(&b.1) });
let mut cleaned_names = vec![];
for (name, id) in all_blocks {
let cleaned_name = convert_to_camel_case(name.strip_prefix("minecraft:").unwrap());
constructed_blocks += &format!(" {}", cleaned_name);
constructed_blocks += &format!(" = {},\n", id);
cleaned_names.push(cleaned_name);
}
constructed_blocks += "}\n\n";
constructed_blocks += "impl TryFrom<u32> for ";
constructed_blocks += enum_name;
constructed_blocks += " {\n";
constructed_blocks += " type Error = Error;\n";
constructed_blocks += " fn try_from(value: u32) -> Result<Self, Self::Error> {\n";
constructed_blocks += " match value {\n";
for name in cleaned_names {
constructed_blocks += " x if x == Self::";
constructed_blocks += &name;
constructed_blocks += " as u32 => Ok(Self::";
constructed_blocks += &name;
constructed_blocks += "),\n";
}
constructed_blocks += " _ => Err(Error::EnumOutOfBound)\n";
constructed_blocks += " }\n }\n}\n";
let valid_out = std::env::var_os("OUT_DIR").unwrap();
let destination = std::path::Path::new(&valid_out).join(save_loc);
std::fs::write(destination, constructed_blocks).unwrap();
}