aboutsummaryrefslogtreecommitdiff
path: root/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'codegen')
-rw-r--r--codegen/README.md2
-rw-r--r--codegen/genentities.py7
-rw-r--r--codegen/lib/code/data_components.py27
-rw-r--r--codegen/lib/code/entity.py49
-rw-r--r--codegen/lib/code/packet.py106
-rw-r--r--codegen/lib/code/registry.py2
-rw-r--r--codegen/lib/code/tags.py39
-rw-r--r--codegen/lib/code/utils.py72
-rw-r--r--codegen/lib/download.py45
-rw-r--r--codegen/lib/extract.py83
-rw-r--r--codegen/lib/mappings.py93
-rw-r--r--codegen/migrate.py4
12 files changed, 153 insertions, 376 deletions
diff --git a/codegen/README.md b/codegen/README.md
index 3e259349..90149dcc 100644
--- a/codegen/README.md
+++ b/codegen/README.md
@@ -41,7 +41,7 @@ If it all works, make a pull request. If the version you updated to is a snapsho
At the time of writing, the following data generators are used:
- [Vanilla data generator](https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Data_Generators)
-- [Burger](https://github.com/mat-1/Burger)
+- [Azalea Burger](https://github.com/azalea-rs/azalea-burger)
- [Pumpkin Extractor](https://github.com/Pumpkin-MC/Extractor)
Some things can be obtained from multiple generators. You should prefer them by the order above (the vanilla generator is the most reliable).
diff --git a/codegen/genentities.py b/codegen/genentities.py
index 944a1a4e..d7ac5dc3 100644
--- a/codegen/genentities.py
+++ b/codegen/genentities.py
@@ -6,14 +6,13 @@ import lib.extract
version_id = lib.code.version.get_version_id()
-mappings = lib.download.get_mappings_for_version(version_id)
burger_data = lib.extract.get_burger_data_for_version(version_id)
-burger_entities_data = burger_data[0]['entities']
+burger_entities_data = burger_data[0]["entities"]
-lib.code.entity.generate_entity_metadata(burger_entities_data, mappings)
+lib.code.entity.generate_entity_metadata(burger_entities_data)
lib.code.entity.generate_entity_dimensions(burger_entities_data)
lib.code.utils.fmt()
-print('Done!')
+print("Done!")
diff --git a/codegen/lib/code/data_components.py b/codegen/lib/code/data_components.py
index e6de6201..992ba83f 100644
--- a/codegen/lib/code/data_components.py
+++ b/codegen/lib/code/data_components.py
@@ -360,7 +360,7 @@ use crate::{
)
elif target_rust_type == "ItemStack":
item_rust_value = python_to_rust_value(python_value["id"], "ItemKind")
- count = python_value["count"]
+ count = python_value.get("count", 1)
if count == 1:
return f"ItemStack::from({item_rust_value})"
else:
@@ -411,9 +411,6 @@ use crate::{
fields_for_rust_type = enum_and_struct_fields.get(target_rust_type, [])
if "Referenced(Identifier)" in fields_for_rust_type:
return f"{target_rust_type}::Referenced({python_to_rust_value(python_value, 'Identifier')})"
- elif "Registry(data::Instrument)" in fields_for_rust_type:
- # TODO
- return f"{target_rust_type}::Registry(azalea_registry::data::Instrument::new_raw(0))"
elif target_rust_type.startswith("HolderSet<"):
holderset_type = target_rust_type.split("<", 1)[1].split(",", 1)[0]
main_vec = python_to_rust_value(
@@ -429,10 +426,10 @@ use crate::{
elif target_rust_type == "Identifier":
# convert minecraft:air into Identifier::from_static("minecraft:air")
return f'"{python_value}".into()'
- elif target_rust_type == "DamageType":
+ elif target_rust_type.startswith("azalea_registry::data::"):
# TODO: this is intentionally incorrect, see the comment in
# azalea-registry/src/data.rs to see how to fix this properly
- return "DamageType::Registry(azalea_registry::data::DamageKind::new_raw(0))"
+ return f"{target_rust_type}::new_raw(0)"
else:
# enum variant
return f"{target_rust_type}::{to_camel_case(identifier_to_path(python_value))}"
@@ -472,9 +469,17 @@ use crate::{
tag_module = "blocks"
else:
tag_module = "FIXME_UNKNOWN_MODULE"
- vectors.append(
- f"azalea_registry::tags::{tag_module}::{tag_name}.clone().into_iter().collect()"
- )
+
+ # TODO: it's not currently possible to have a holderset for data registry items
+ # (because registries would need to be translated during packet parsing/writing),
+ # so we leave this empty for now.
+ if inner_type in {"BannerPatternKind", "DamageKind"}:
+ pass
+ else:
+ vectors.append(
+ f"azalea_registry::tags::{tag_module}::{tag_name}.clone().into_iter().collect()"
+ )
+
continue
main_vec += python_to_rust_value(v, inner_type) + ","
main_vec = main_vec.rstrip(",") + "]"
@@ -533,11 +538,11 @@ use crate::{
item_defaults_original = item_defaults
item_defaults = {}
- for k, v in item_defaults_original.items():
+ for k, v in sorted(item_defaults_original.items(), key=lambda i: i[0]):
item_defaults[k] = python_to_rust_value(v, field_type)
default_values_frequency = {}
- for value in item_defaults.values():
+ for value in sorted(item_defaults.values()):
if value not in default_values_frequency:
default_values_frequency[value] = 0
default_values_frequency[value] += 1
diff --git a/codegen/lib/code/entity.py b/codegen/lib/code/entity.py
index d10a159f..992d9b19 100644
--- a/codegen/lib/code/entity.py
+++ b/codegen/lib/code/entity.py
@@ -1,5 +1,4 @@
from lib.utils import to_camel_case, to_snake_case, get_dir_location, upper_first_letter
-from lib.mappings import Mappings
from typing import Optional
import re
@@ -8,18 +7,19 @@ DATA_RS_DIR = get_dir_location("../azalea-entity/src/data.rs")
DIMENSIONS_RS_DIR = get_dir_location("../azalea-entity/src/dimensions.rs")
-def generate_metadata_names(burger_dataserializers: dict, mappings: Mappings):
+def generate_metadata_names(burger_dataserializers: dict):
serializer_names: list[Optional[str]] = [None] * len(burger_dataserializers)
for burger_serializer in burger_dataserializers.values():
print(burger_serializer)
+ # TODO: remove these comments
# burger gives us the wrong class, so we do this instead
- data_serializers_class = mappings.get_class_from_deobfuscated_name(
- "net.minecraft.network.syncher.EntityDataSerializers"
- )
- mojmap_name = mappings.get_field(
- data_serializers_class, burger_serializer["field"]
- ).lower()
+ # data_serializers_class = "net/minecraft/network/syncher/EntityDataSerializers"
+ # mojmap_name = mappings.get_field(
+ # data_serializers_class, burger_serializer["field"]
+ # ).lower()
+
+ mojmap_name = burger_serializer["field"].lower()
if mojmap_name == "component":
mojmap_name = "formatted_text"
@@ -58,11 +58,11 @@ def parse_metadata_types_from_code():
return data
-def generate_entity_metadata(burger_entities_data: dict, mappings: Mappings):
+def generate_entity_metadata(burger_entities_data: dict):
burger_entity_metadata = burger_entities_data["entity"]
new_metadata_names = generate_metadata_names(
- burger_entities_data["dataserializers"], mappings
+ burger_entities_data["dataserializers"]
)
parsed_metadata_types = parse_metadata_types_from_code()
@@ -173,7 +173,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
for entity_id in burger_entity_metadata.keys():
field_name_map[entity_id] = {}
for field_name_or_bitfield in get_entity_metadata_names(
- entity_id, burger_entity_metadata, mappings
+ entity_id, burger_entity_metadata
).values():
if isinstance(field_name_or_bitfield, str):
if field_name_or_bitfield in previous_field_names:
@@ -204,7 +204,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
# and now figure out what to rename them to
for entity_id in burger_entity_metadata.keys():
for index, field_name_or_bitfield in get_entity_metadata_names(
- entity_id, burger_entity_metadata, mappings
+ entity_id, burger_entity_metadata
).items():
if isinstance(field_name_or_bitfield, str):
new_field_name = field_name_or_bitfield
@@ -245,7 +245,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
parents = get_entity_parents(entity_id, burger_entity_metadata)
for parent_id in list(reversed(parents)):
for index, name_or_bitfield in get_entity_metadata_names(
- parent_id, burger_entity_metadata, mappings
+ parent_id, burger_entity_metadata
).items():
assert index == len(all_field_names_or_bitfields)
all_field_names_or_bitfields.append(name_or_bitfield)
@@ -462,7 +462,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
if parent_struct_name:
code.append(f" parent: {parent_struct_name}MetadataBundle,")
for index, name_or_bitfield in get_entity_metadata_names(
- entity_id, burger_entity_metadata, mappings
+ entity_id, burger_entity_metadata
).items():
if isinstance(name_or_bitfield, str):
name_or_bitfield = maybe_rename_field(name_or_bitfield, index)
@@ -514,7 +514,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
code.append(" parent: Default::default(),")
for index, name_or_bitfield in get_entity_metadata_names(
- this_entity_id, burger_entity_metadata, mappings
+ this_entity_id, burger_entity_metadata
).items():
default = next(
filter(lambda i: i["index"] == index, entity_metadatas)
@@ -792,22 +792,19 @@ def get_entity_metadata(entity_id: str, burger_entity_metadata: dict):
# returns a dict of {index: (name or bitfield)}
-def get_entity_metadata_names(
- entity_id: str, burger_entity_metadata: dict, mappings: Mappings
-):
+def get_entity_metadata_names(entity_id: str, burger_entity_metadata: dict):
entity_metadata = burger_entity_metadata[entity_id]["metadata"]
mapped_metadata_names = {}
for metadata_item in entity_metadata:
if "data" in metadata_item:
- obfuscated_class = metadata_item["class"]
+ # obfuscated_class = metadata_item["class"]
# mojang_class = mappings.get_class(obfuscated_class)
first_byte_index = None
for metadata_attribute in metadata_item["data"]:
- obfuscated_field = metadata_attribute["field"]
- mojang_field = mappings.get_field(obfuscated_class, obfuscated_field)
+ mojang_field = metadata_attribute["field"]
pretty_mojang_name = prettify_mojang_field(mojang_field)
mapped_metadata_names[metadata_attribute["index"]] = pretty_mojang_name
@@ -820,12 +817,10 @@ def get_entity_metadata_names(
if metadata_item["bitfields"] and first_byte_index is not None:
clean_bitfield = {}
for bitfield_item in metadata_item["bitfields"]:
- bitfield_item_obfuscated_class = bitfield_item.get(
- "class", obfuscated_class
- )
- mojang_bitfield_item_name = mappings.get_method(
- bitfield_item_obfuscated_class, bitfield_item["method"], ""
- )
+ # bitfield_item_obfuscated_class = bitfield_item.get(
+ # "class", obfuscated_class
+ # )
+ mojang_bitfield_item_name = bitfield_item["method"]
bitfield_item_name = prettify_mojang_method(
mojang_bitfield_item_name
)
diff --git a/codegen/lib/code/packet.py b/codegen/lib/code/packet.py
index 9ce5c137..1131cb49 100644
--- a/codegen/lib/code/packet.py
+++ b/codegen/lib/code/packet.py
@@ -1,6 +1,5 @@
from lib.utils import identifier_to_path, to_snake_case, to_camel_case, get_dir_location
from lib.code.utils import burger_type_to_rust_type, write_packet_file
-from lib.mappings import Mappings
from typing import Optional
import os
import re
@@ -175,7 +174,6 @@ def burger_instruction_to_code(
instructions: list[dict],
index: int,
generated_packet_code: list[str],
- mappings: Mappings,
obfuscated_class_name: str,
uses: set,
extra_code: list[str],
@@ -208,8 +206,7 @@ def burger_instruction_to_code(
and next_next_instruction
and next_next_instruction["operation"] == "loop"
):
- obfuscated_field_name = instruction["field"].split(".")[0]
- field_name = mappings.get_field(obfuscated_class_name, obfuscated_field_name)
+ field_name = instruction["field"].split("/")[0]
# figure out what kind of iterator it is
loop_instructions = next_next_instruction["instructions"]
@@ -218,7 +215,6 @@ def burger_instruction_to_code(
loop_instructions[1]["type"],
None,
loop_instructions[1],
- mappings,
obfuscated_class_name,
)
field_type_rs = f"Vec<{entry_type_rs}>"
@@ -235,7 +231,6 @@ def burger_instruction_to_code(
loop_instructions[1]["type"],
None,
loop_instructions[1],
- mappings,
obfuscated_class_name,
)
)
@@ -248,7 +243,6 @@ def burger_instruction_to_code(
loop_instructions[2]["type"],
None,
loop_instructions[2],
- mappings,
obfuscated_class_name,
)
)
@@ -277,16 +271,14 @@ def burger_instruction_to_code(
)
):
print("ok is option")
- obfuscated_field_name = instruction["field"].split(".")[0].split(" ")[0]
+ field_name = instruction["field"].split(".")[0].split(" ")[0]
- if obfuscated_field_name in known_variable_types:
- # just use the known name since it's not gonna be in the mappings
- obfuscated_field_name = known_variable_types[obfuscated_field_name]
-
- field_name = mappings.get_field(obfuscated_class_name, obfuscated_field_name)
+ # if obfuscated_field_name in known_variable_types:
+ # just use the known name since it's not gonna be in the mappings
+ # obfuscated_field_name = known_variable_types[obfuscated_field_name]
if field_name is None:
- field_name = obfuscated_field_name.split("/")[-1]
+ field_name = field_name.split("/")[-1]
if "<" in field_name:
field_name = "value"
@@ -306,7 +298,6 @@ def burger_instruction_to_code(
condition_instruction["type"],
None,
condition_instruction,
- mappings,
obfuscated_class_name,
)
)
@@ -321,54 +312,35 @@ def burger_instruction_to_code(
skip = 1
else:
field_type = instruction["type"]
- obfuscated_field_name = instruction["field"]
+ field_name = instruction["field"]
- if obfuscated_field_name.startswith("(float)"):
- obfuscated_field_name = obfuscated_field_name[len("(float)") :]
-
- field_name = mappings.get_field(
- obfuscated_class_name, obfuscated_field_name
- ) or mappings.get_field(
- obfuscated_class_name.split("$")[0], obfuscated_field_name
- )
+ if field_name.startswith("(float)"):
+ field_name = field_name[len("(float)") :]
field_type_rs, is_var, instruction_uses, instruction_extra_code = (
burger_type_to_rust_type(
- field_type, field_name, instruction, mappings, obfuscated_class_name
+ field_type, field_name, instruction, obfuscated_class_name
)
)
- if obfuscated_field_name in known_variable_types:
+ if field_name in known_variable_types:
# just use the known name since it's not gonna be in the mappings
- field_name = obfuscated_field_name
+ pass
- elif (
- "." in obfuscated_field_name
- or " " in obfuscated_field_name
- or "(" in obfuscated_field_name
- ):
- field_type_rs2, obfuscated_field_name, field_comment = burger_field_to_type(
- obfuscated_field_name,
- mappings,
+ elif "." in field_name or " " in field_name or "(" in field_name:
+ field_type_rs2, field_name, field_comment = burger_field_to_type(
+ field_name,
obfuscated_class_name,
known_variable_types,
)
if not field_type_rs2:
generated_packet_code.append(f"// TODO: {instruction}")
return
- if obfuscated_field_name in known_variable_types:
+ if field_name in known_variable_types:
# just use the known name since it's not gonna be in the mappings
- obfuscated_field_name = known_variable_types[obfuscated_field_name]
- print("got obfuscated_field_name", obfuscated_field_name)
-
- # try to get the field name again with the new stuff we know
- field_name = mappings.get_field(
- obfuscated_class_name, obfuscated_field_name
- ) or mappings.get_field(
- obfuscated_class_name.split("$")[0], obfuscated_field_name
- )
- if field_name is None:
- field_name = obfuscated_field_name.split("/")[-1]
+ field_name = known_variable_types[field_name]
+ print("got obfuscated_field_name", field_name)
+
uses.update(instruction_uses)
extra_code.extend(instruction_extra_code)
@@ -387,7 +359,7 @@ def burger_instruction_to_code(
def burger_field_to_type(
- field, mappings: Mappings, obfuscated_class_name: str, known_variable_types={}
+ field, obfuscated_class_name: str, known_variable_types={}
) -> tuple[Optional[str], str, Optional[str]]:
"""
Returns field_type_rs, obfuscated_field_name, field_comment
@@ -399,38 +371,18 @@ def burger_field_to_type(
match = re.match(r"^\w+\.\w+\(\)$", field)
if match:
print("field", field)
- obfuscated_first = field.split(".")[0]
- obfuscated_second = field.split(".")[1].split("(")[0]
+ first_type = field.split(".")[0]
+ second_type = field.split(".")[1].split("(")[0]
# first = mappings.get_field(obfuscated_class_name, obfuscated_first)
- if obfuscated_first in known_variable_types:
- first_type = known_variable_types[obfuscated_first]
- else:
- try:
- first_type = mappings.get_field_type(
- obfuscated_class_name, obfuscated_first
- )
- except Exception:
- first_type = "TODO"
- first_obfuscated_class_name: Optional[str] = (
- mappings.get_class_from_deobfuscated_name(first_type)
- )
- if first_obfuscated_class_name:
- try:
- second = mappings.get_method(
- first_obfuscated_class_name, obfuscated_second, ""
- )
- except Exception:
- # if this happens then the field is probably from a super class
- second = obfuscated_second
- else:
- second = obfuscated_second
- first_type_short = first_type.split(".")[-1]
- if second in {"byteValue"}:
- return (first_type_short, obfuscated_first, None)
+ if first_type in known_variable_types:
+ first_type = known_variable_types[first_type]
+ first_type_short = first_type.split("/")[-1]
+ if second_type in {"byteValue"}:
+ return (first_type_short, first_type, None)
return (
first_type_short,
- obfuscated_first,
- f"TODO: Does {first_type_short}::{second}, may not be implemented",
+ first_type,
+ f"TODO: Does {first_type_short}::{second_type}, may not be implemented",
)
return None, field, None
diff --git a/codegen/lib/code/registry.py b/codegen/lib/code/registry.py
index 01462e1f..9c30a273 100644
--- a/codegen/lib/code/registry.py
+++ b/codegen/lib/code/registry.py
@@ -154,7 +154,7 @@ def registry_name_to_enum_name(registry_name: str) -> str:
# change _type to _kind because that's Rustier (and because _type
# is a reserved keyword)
registry_name = registry_name[:-5] + "_kind"
- elif registry_name in {"menu", "block", "item"}:
+ elif registry_name in {"menu", "block", "item", "banner_pattern"}:
registry_name += "_kind"
return to_camel_case(registry_name)
diff --git a/codegen/lib/code/tags.py b/codegen/lib/code/tags.py
index b6e225ac..2a44d35c 100644
--- a/codegen/lib/code/tags.py
+++ b/codegen/lib/code/tags.py
@@ -1,25 +1,45 @@
from lib.code.registry import registry_name_to_enum_name
-from lib.utils import identifier_to_namespace, identifier_to_path, to_snake_case, upper_first_letter, get_dir_location, to_camel_case
+from lib.utils import (
+ identifier_to_namespace,
+ identifier_to_path,
+ to_snake_case,
+ upper_first_letter,
+ get_dir_location,
+ to_camel_case,
+)
TAGS_DIR = get_dir_location("../azalea-registry/src/tags")
-def generate_tags(registries: dict, tags: dict, file_name: str, registry_name: str):
+def generate_tags(
+ registries: dict,
+ tags: dict,
+ file_name: str,
+ registry_name: str,
+ is_data_registry: bool = False,
+):
struct_name = registry_name_to_enum_name(registry_name)
tags_dir = f"{TAGS_DIR}/{file_name}.rs"
+ registry_module = "data" if is_data_registry else "builtin"
+ if is_data_registry:
+ struct_name += "Key"
+
generated = f"""// This file was @generated by codegen/lib/code/tags.py, don't edit it manually!
use std::sync::LazyLock;
-use crate::{{builtin::{struct_name}, tags::RegistryTag}};
+use crate::{{{registry_module}::{struct_name}, tags::RegistryTag}};
"""
- protocol_ids = {}
- for k, v in registries["minecraft:" + registry_name]["entries"].items():
- protocol_ids[identifier_to_path(k)] = v["protocol_id"]
+ if is_data_registry:
+ protocol_ids = None
+ else:
+ protocol_ids = {}
+ for k, v in registries[f"minecraft:{registry_name}"]["entries"].items():
+ protocol_ids[identifier_to_path(k)] = v["protocol_id"]
for tag_name, tag in sorted(tags.items(), key=lambda x: x[0]):
entries = []
@@ -41,9 +61,10 @@ use crate::{{builtin::{struct_name}, tags::RegistryTag}};
generated += f"pub static {static_set_name}: LazyLock<RegistryTag<{struct_name}>> = LazyLock::new(|| RegistryTag::new(vec!["
- # this is important because we binary search registries in some cases
- # and they need to be sorted by their rust Ord order
- entries.sort(key=lambda e: protocol_ids[e])
+ if not is_data_registry:
+ # this is important because we binary search registries in some cases
+ # and they need to be sorted by their rust Ord order
+ entries.sort(key=lambda e: protocol_ids[e])
for entry_name in entries:
generated += (
diff --git a/codegen/lib/code/utils.py b/codegen/lib/code/utils.py
index 62b4627b..9bfb3504 100644
--- a/codegen/lib/code/utils.py
+++ b/codegen/lib/code/utils.py
@@ -1,7 +1,6 @@
# utilities specifically for codegen
from lib.utils import to_camel_case, to_snake_case, get_dir_location
-from lib.mappings import Mappings
from typing import Optional
import os
@@ -10,8 +9,7 @@ def burger_type_to_rust_type(
burger_type,
field_name: Optional[str] = None,
instruction=None,
- mappings: Optional[Mappings] = None,
- obfuscated_class_name: Optional[str] = None,
+ class_name: Optional[str] = None,
):
is_var = False
uses = set()
@@ -90,7 +88,7 @@ def burger_type_to_rust_type(
# depends on context
field_type_rs = "todo!()"
elif burger_type == "enum":
- if not instruction or not mappings or not obfuscated_class_name:
+ if not instruction or not class_name:
field_type_rs = 'todo!("enum")'
else:
# generate the whole enum :)
@@ -98,57 +96,20 @@ def burger_type_to_rust_type(
enum_field = instruction["field"]
# enums with a.b() as the field
if "." in enum_field:
- enum_first_part_name = mappings.get_field_type(
- obfuscated_class_name, enum_field.split(".")[0]
- )
- enum_first_part_obfuscated_name = (
- mappings.get_class_from_deobfuscated_name(enum_first_part_name)
- )
- print(
- "enum_first_part_obfuscated_name", enum_first_part_obfuscated_name
- )
+ enum_first_part_name = enum_field.split("/")[0]
+ print("enum_first_part_name", enum_first_part_name)
print("enum field", enum_field.split(".")[1].split("(")[0])
- try:
- enum_name = mappings.get_method_type(
- enum_first_part_obfuscated_name,
- enum_field.split(".")[1].split("(")[0],
- "",
- )
- except KeyError:
- # sometimes enums are fields instead of methods
- enum_name = mappings.get_field_type(
- enum_first_part_obfuscated_name,
- enum_field.split(".")[1].split("(")[0],
- )
+ enum_name = enum_field.split("$")[1].split("(")[0]
print("hm", enum_name)
else:
- try:
- enum_name = mappings.get_field_type(
- obfuscated_class_name, enum_field
- )
- except Exception:
- enum_name = mappings.get_class(obfuscated_class_name)
- print(
- f"failed getting {obfuscated_class_name}.{enum_field} but continuing with {enum_name} anyways"
- )
+ enum_name = enum_field or class_name
print("enum_name", enum_name)
- enum_obfuscated_name = mappings.get_class_from_deobfuscated_name(enum_name)
+ enum_obfuscated_name = enum_name
print("enum_obfuscated_name", enum_obfuscated_name)
enum_variants = []
- for obfuscated_field_name in mappings.fields[enum_obfuscated_name]:
- field_name = mappings.get_field(
- enum_obfuscated_name, obfuscated_field_name
- )
-
- # get the type just to make sure it's actually a variant and not something else
- field_type = mappings.get_field_type(
- enum_obfuscated_name, obfuscated_field_name
- )
- if field_type != enum_name:
- continue
-
- enum_variants.append(field_name)
+ raise RuntimeError("TODO: extracting enum variants")
+ enum_variants.append(field_name)
field_type_rs = to_camel_case(enum_name.split(".")[-1].split("$")[-1])
extra_code.append("")
@@ -165,28 +126,19 @@ def burger_type_to_rust_type(
field_type_rs = f"Vec<{field_type_rs}>"
# sometimes burger gives us a slightly incorrect type
- if mappings and instruction:
+ if instruction:
if field_type_rs == "Vec<u8>":
field = instruction["field"]
if field.endswith(".copy()"):
field = field[:-7]
- try:
- array_type = mappings.get_field_type(obfuscated_class_name, field)
- except KeyError:
- print("Error getting array type", field)
- return field_type_rs, is_var, uses, extra_code
+ array_type = field
if array_type == "net.minecraft.network.FriendlyByteBuf":
field_type_rs = "UnsizedByteArray"
uses.add("azalea_buf::UnsizedByteArray")
else:
print("instruction that we errored on:", instruction)
- deobfuscated_class_name = (
- mappings.get_class(obfuscated_class_name) if obfuscated_class_name else None
- )
- raise Exception(
- f"Unknown field type: {burger_type} ({deobfuscated_class_name or obfuscated_class_name})"
- )
+ raise Exception(f"Unknown field type: {burger_type} ({class_name})")
return field_type_rs, is_var, uses, extra_code
diff --git a/codegen/lib/download.py b/codegen/lib/download.py
index 8819cf61..43b42aa5 100644
--- a/codegen/lib/download.py
+++ b/codegen/lib/download.py
@@ -1,12 +1,11 @@
-from lib.utils import get_dir_location
+from .utils import get_dir_location
import xml.etree.ElementTree as ET
-from .mappings import Mappings
import requests
import json
import os
-PUMPKIN_EXTRACTOR_COMMIT = "82926545925baf5f50414cc9374f1cc340b7de0f"
-BURGER_COMMIT = "366d6e4bed0e9e6505d9c40c83628ab80a5fe001"
+PUMPKIN_EXTRACTOR_COMMIT = "f3019d598c06f0d6fd4f3568fbf2d5bebae71173q"
+BURGER_COMMIT = "bb84700e43bf7090877d9a4eb5d87c3125a8d22e"
# make sure the cache directory exists
print("Making __cache__")
@@ -16,26 +15,26 @@ if not os.path.exists(get_dir_location("__cache__")):
def get_burger():
- if not os.path.exists(get_dir_location("__cache__/Burger")):
- print("\033[92mDownloading Burger...\033[m")
+ if not os.path.exists(get_dir_location("__cache__/azalea-burger")):
+ print("\033[92mDownloading azalea-burger...\033[m")
os.system(
- f"cd {get_dir_location('__cache__')} && git clone https://github.com/mat-1/Burger && cd Burger && git pull && git reset --hard {BURGER_COMMIT}"
+ f"cd {get_dir_location('__cache__')} && git clone https://github.com/azalea-rs/azalea-burger && cd azalea-burger && git pull && git reset --hard {BURGER_COMMIT}"
)
print("\033[92mInstalling dependencies...\033[m")
os.system(
- f"cd {get_dir_location('__cache__')}/Burger && python -m venv venv && venv/bin/pip install six jawa"
+ f"cd {get_dir_location('__cache__')}/azalea-burger && python -m venv venv && venv/bin/pip install six jawa"
)
def get_pumpkin_extractor():
- if not os.path.exists(get_dir_location("__cache__/pumpkin-extractor")):
- print("\033[92mDownloading Pumpkin-MC/Extractor...\033[m")
+ if not os.path.exists(get_dir_location("__cache__/azalea-pumpkin-extractor")):
+ print("\033[92mDownloading mat-1/azalea-pumpkin-extractor...\033[m")
os.system(
- f"cd {get_dir_location('__cache__')} && git clone https://github.com/Pumpkin-MC/Extractor pumpkin-extractor && cd pumpkin-extractor && git pull && git reset --hard {PUMPKIN_EXTRACTOR_COMMIT}"
+ f"cd {get_dir_location('__cache__')} && git clone https://github.com/azalea-rs/azalea-pumpkin-extractor && cd azalea-pumpkin-extractor && git pull && git reset --hard {PUMPKIN_EXTRACTOR_COMMIT}"
)
- return get_dir_location("__cache__/pumpkin-extractor")
+ return get_dir_location("__cache__/azalea-pumpkin-extractor")
def get_version_manifest():
@@ -94,29 +93,13 @@ def get_server_jar(version_id: str):
f.write(requests.get(server_jar_url).content)
-def get_mappings_for_version(version_id: str):
- if not os.path.exists(get_dir_location(f"__cache__/mappings-{version_id}.txt")):
- package_data = get_version_data(version_id)
-
- client_mappings_url = package_data["downloads"]["client_mappings"]["url"]
-
- mappings_text = requests.get(client_mappings_url).text
-
- with open(get_dir_location(f"__cache__/mappings-{version_id}.txt"), "w") as f:
- f.write(mappings_text)
- else:
- with open(get_dir_location(f"__cache__/mappings-{version_id}.txt"), "r") as f:
- mappings_text = f.read()
- return Mappings.parse(mappings_text)
-
-
def get_fabric_data(version_id: str):
# https://meta.fabricmc.net/v2/versions/yarn
path = get_dir_location(f"__cache__/fabric-{version_id}.json")
if not os.path.exists(path):
print(f"\033[92mDownloading Fabric metadata for {version_id}...\033[m")
- url = f"https://meta.fabricmc.net/v1/versions/loader/{version_id}"
+ url = f"https://meta.fabricmc.net/v2/versions/loader/{version_id}"
yarn_versions_data = requests.get(url).json()
with open(path, "w") as f:
json.dump(yarn_versions_data, f)
@@ -247,10 +230,10 @@ def clear_version_cache():
if os.path.exists(get_dir_location(f"__cache__/{file}")):
os.remove(get_dir_location(f"__cache__/{file}"))
- burger_path = get_dir_location("__cache__/Burger")
+ burger_path = get_dir_location("__cache__/azalea-burger")
if os.path.exists(burger_path):
os.system(f"cd {burger_path} && git pull && git reset --hard {BURGER_COMMIT}")
- pumpkin_path = get_dir_location("__cache__/pumpkin-extractor")
+ pumpkin_path = get_dir_location("__cache__/azalea-pumpkin-extractor")
if os.path.exists(pumpkin_path):
os.system(
f"cd {pumpkin_path} && git add . && git stash && git checkout master && git pull && git stash pop && git reset --hard {PUMPKIN_EXTRACTOR_COMMIT}"
diff --git a/codegen/lib/extract.py b/codegen/lib/extract.py
index f2f7f4a2..9faa2e22 100644
--- a/codegen/lib/extract.py
+++ b/codegen/lib/extract.py
@@ -1,18 +1,16 @@
# Extracting data from the Minecraft jars
import shutil
-from lib.download import (
+from .download import (
get_fabric_api_version,
get_latest_fabric_kotlin_version,
- get_latest_fabric_loom_version,
- get_mappings_for_version,
get_pumpkin_extractor,
get_server_jar,
get_burger,
get_client_jar,
get_fabric_data,
)
-from lib.utils import get_dir_location, to_camel_case, upper_first_letter
+from .utils import get_dir_location
from zipfile import ZipFile
import subprocess
import json
@@ -43,7 +41,23 @@ def get_packets_report(version_id: str):
def get_items_report(version_id: str):
- return get_report(version_id, "items")
+ generate_data_from_server_jar(version_id)
+ items_dir = get_dir_location(
+ f"__cache__/generated-{version_id}/reports/minecraft/components/item"
+ )
+ if not os.path.exists(items_dir):
+ return {}
+ items = {}
+ for root, dirs, files in os.walk(items_dir, topdown=False):
+ for name in files:
+ file = os.path.join(root, name)
+ relative_path = file.replace(items_dir, "")[1:]
+ if not file.endswith(".json"):
+ continue
+ with open(file, "r") as f:
+ items[relative_path[:-5]] = json.load(f)
+
+ return items
def get_report(version_id: str, name: str):
@@ -143,14 +157,12 @@ def get_burger_data_for_version(version_id: str):
if not os.path.exists(get_dir_location(f"__cache__/burger-{version_id}.json")):
get_burger()
get_client_jar(version_id)
- get_mappings_for_version(version_id)
- print("\033[92mRunning Burger...\033[m")
+ print("\033[92mRunning azalea-burger...\033[m")
run_python_command_and_download_deps(
- f"cd {get_dir_location('__cache__/Burger')} && "
+ f"cd {get_dir_location('__cache__/azalea-burger')} && "
f"venv/bin/python munch.py {get_dir_location('__cache__')}/client-{version_id}.jar "
f"--output {get_dir_location('__cache__')}/burger-{version_id}.json "
- f"--mappings {get_dir_location('__cache__')}/mappings-{version_id}.txt"
)
with open(get_dir_location(f"__cache__/burger-{version_id}.json"), "r") as f:
return json.load(f)
@@ -183,12 +195,11 @@ def get_pumpkin_data(version_id: str, category: str):
fabric_kotlin_version = get_latest_fabric_kotlin_version()
gradle_properties = f"""# Done to increase the memory available to gradle.
-org.gradle.jvmargs=-Xmx1G
+org.gradle.jvmargs=-Xmx2G
org.gradle.parallel=true
# Fabric Properties
-# check these on https://modmuss50.me/fabric.html
+# check these on https://fabricmc.net/develop/
minecraft_version={version_id}
-yarn_mappings={fabric_data["mappings"]["version"]}
loader_version={fabric_data["loader"]["version"]}
kotlin_loader_version={fabric_kotlin_version}
# Mod Properties
@@ -200,24 +211,9 @@ fabric_version={fabric_api_version}
with open(f"{pumpkin_dir}/gradle.properties", "w") as f:
f.write(gradle_properties)
- # update the minecraft version dependency in src/main/resources/fabric.mod.json
- fabric_mod_json_path = f"{pumpkin_dir}/src/main/resources/fabric.mod.json"
- with open(fabric_mod_json_path, "r") as f:
- fabric_mod_json = f.read()
- with open(f"{pumpkin_dir}/build.gradle.kts", "r") as f:
- build_gradle_kts = f.read()
- with open(f"{pumpkin_dir}/build.gradle.kts", "w") as f:
- # build_gradle_kts = re.sub(
- # r'(id\("fabric-loom"\) version )"[^"]+"',
- # rf'\1"{fabric_loom_version}"',
- # build_gradle_kts,
- # )
- f.write(build_gradle_kts)
-
# run ./gradlew runServer until it logs "(pumpkin_extractor) Done"
p = subprocess.Popen(
- # the gradle wrapper (./gradlew) is sometimes on the wrong version so just prefer the system's gradle installation
- f"cd {pumpkin_dir} && gradle clean && gradle runServer",
+ f"cd {pumpkin_dir} && ./gradlew clean && ./gradlew runServer",
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
shell=True,
@@ -253,34 +249,3 @@ def get_file_from_jar(version_id: str, file_dir: str):
def get_en_us_lang(version_id: str):
return json.loads(get_file_from_jar(version_id, "assets/minecraft/lang/en_us.json"))
-
-
-# burger packet id extraction is broken since 1.20.5 (always returns -1, so we have to determine packet id ourselves from the mappings).
-# this is very much not ideal.
-
-
-def get_packet_list(version_id: str):
- if version_id != "1.21":
- return []
-
- generate_data_from_server_jar(version_id)
- with open(
- get_dir_location(f"__cache__/generated-{version_id}/reports/packets.json"), "r"
- ) as f:
- packets_report = json.load(f)
- packet_list = []
- for state, state_value in packets_report.items():
- for direction, direction_value in state_value.items():
- for packet_identifier, packet_value in direction_value.items():
- assert packet_identifier.startswith("minecraft:")
- packet_identifier = upper_first_letter(
- to_camel_case(packet_identifier[len("minecraft:") :])
- )
- packet_list.append(
- {
- "state": state,
- "direction": direction,
- "name": packet_identifier,
- "id": packet_value["protocol_id"],
- }
- )
diff --git a/codegen/lib/mappings.py b/codegen/lib/mappings.py
deleted file mode 100644
index 9c39fc2b..00000000
--- a/codegen/lib/mappings.py
+++ /dev/null
@@ -1,93 +0,0 @@
-from typing import Optional
-
-
-class Mappings:
- __slots__ = ('classes', 'fields', 'methods', 'field_types', 'method_types')
-
- def __init__(self, classes, fields, methods, field_types, method_types):
- self.classes = classes
- self.fields = fields
- self.methods = methods
- self.field_types = field_types
- self.method_types = method_types
-
- @staticmethod
- def parse(mappings_txt):
- classes = {}
- fields = {}
- methods = {}
- field_types = {}
- method_types = {}
-
- current_obfuscated_class_name = None
-
- for line in mappings_txt.splitlines():
- if line.startswith('#') or line == '':
- continue
-
- if line.startswith(' '):
- # if a line starts with 4 spaces, that means it's a method or a field
- if '(' in line:
- # if it has an opening parenthesis, it's a method
- real_name_with_parameters_and_line, obfuscated_name = line.strip().split(' -> ')
- real_name_with_parameters = real_name_with_parameters_and_line.split(
- ':')[-1]
-
- real_type, real_name = real_name_with_parameters.split('(')[
- 0].split(' ')
- parameters = real_name_with_parameters.split('(')[1].split(')')[
- 0]
-
- if current_obfuscated_class_name not in methods:
- methods[current_obfuscated_class_name] = {}
- method_types[current_obfuscated_class_name] = {}
- methods[current_obfuscated_class_name][
- f'{obfuscated_name}({parameters})'] = real_name
- method_types[current_obfuscated_class_name][
- f'{obfuscated_name}({parameters})'] = real_type
- else:
- # otherwise, it's a field
- real_name_with_type, obfuscated_name = line.strip().split(' -> ')
- real_type, real_name = real_name_with_type.split(' ')
-
- if current_obfuscated_class_name not in fields:
- fields[current_obfuscated_class_name] = {}
- field_types[current_obfuscated_class_name] = {}
- fields[current_obfuscated_class_name][obfuscated_name] = real_name
- field_types[current_obfuscated_class_name][obfuscated_name] = real_type
- else:
- # otherwise it's a class
- real_name, obfuscated_name = line.strip(':').split(' -> ')
- current_obfuscated_class_name = obfuscated_name
-
- classes[obfuscated_name] = real_name
-
- return Mappings(classes, fields, methods, field_types, method_types)
-
- def get_field(self, obfuscated_class_name, obfuscated_field_name):
- return self.fields.get(obfuscated_class_name, {}).get(obfuscated_field_name)
-
- def get_class(self, obfuscated_class_name):
- if '<' in obfuscated_class_name:
- first_part, args = obfuscated_class_name.split('<')
- args = args.rstrip('>').strip(';').split(';')
- print(args)
- assert len(args) == 1
- arg = self.get_class(args[0][1:])
- return f'{first_part}<{arg}>'
- return self.classes[obfuscated_class_name]
-
- def get_method(self, obfuscated_class_name, obfuscated_method_name, obfuscated_signature):
- return self.methods[obfuscated_class_name][f'{obfuscated_method_name}({obfuscated_signature})']
-
- def get_field_type(self, obfuscated_class_name, obfuscated_field_name) -> str:
- return self.field_types[obfuscated_class_name][obfuscated_field_name]
-
- def get_method_type(self, obfuscated_class_name, obfuscated_method_name, obfuscated_signature) -> str:
- return self.method_types[obfuscated_class_name][f'{obfuscated_method_name}({obfuscated_signature})']
-
- def get_class_from_deobfuscated_name(self, deobfuscated_name) -> Optional[str]:
- for obfuscated_name, real_name in self.classes.items():
- if real_name == deobfuscated_name:
- return obfuscated_name
- return None
diff --git a/codegen/migrate.py b/codegen/migrate.py
index bf7dde5a..100eaf17 100644
--- a/codegen/migrate.py
+++ b/codegen/migrate.py
@@ -24,11 +24,9 @@ if len(sys.argv) == 1:
old_version_id = lib.code.version.get_version_id()
-old_mappings = lib.download.get_mappings_for_version(old_version_id)
old_burger_data = lib.extract.get_burger_data_for_version(old_version_id)
new_version_id = sys.argv[1]
-new_mappings = lib.download.get_mappings_for_version(new_version_id)
new_burger_data = lib.extract.get_burger_data_for_version(new_version_id)
new_packets_report = lib.extract.get_packets_report(new_version_id)
@@ -63,7 +61,7 @@ genregistries.generate(new_version_id)
print("Generating entity data...")
burger_entities_data = new_burger_data[0]["entities"]
-lib.code.entity.generate_entity_metadata(burger_entities_data, new_mappings)
+lib.code.entity.generate_entity_metadata(burger_entities_data)
lib.code.entity.generate_entity_dimensions(burger_entities_data)
print("Generating item components...")