aboutsummaryrefslogtreecommitdiff
path: root/codegen
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2025-05-31 08:56:17 +0500
committermat <git@matdoes.dev>2025-05-30 19:22:09 -0845
commitf27c87b291a920376e006a470efb353dee46ed17 (patch)
treef1720081b856c5b7b96ab8111e6de4233f884e75 /codegen
parente37524899eef8a0034faee35cef4bbf1ba779a7d (diff)
downloadazalea-drasl-f27c87b291a920376e006a470efb353dee46ed17.tar.xz
more formatting fixes
Diffstat (limited to 'codegen')
-rw-r--r--codegen/lib/code/blocks.py256
-rw-r--r--codegen/lib/code/entity.py601
-rw-r--r--codegen/lib/code/inventory.py91
-rw-r--r--codegen/lib/code/item_components.py126
-rw-r--r--codegen/lib/code/language.py7
-rw-r--r--codegen/lib/code/packet.py432
-rw-r--r--codegen/lib/code/registry.py58
-rw-r--r--codegen/lib/code/shapes.py143
-rw-r--r--codegen/lib/code/tags.py30
-rw-r--r--codegen/lib/code/utils.py235
-rw-r--r--codegen/lib/code/version.py73
-rw-r--r--codegen/lib/download.py161
-rw-r--r--codegen/lib/extract.py153
13 files changed, 1342 insertions, 1024 deletions
diff --git a/codegen/lib/code/blocks.py b/codegen/lib/code/blocks.py
index 212d080c..550ccf83 100644
--- a/codegen/lib/code/blocks.py
+++ b/codegen/lib/code/blocks.py
@@ -1,9 +1,6 @@
from lib.utils import get_dir_location, to_camel_case
-from ..mappings import Mappings
-from typing import Optional
-import re
-BLOCKS_RS_DIR = get_dir_location('../azalea-block/src/generated.rs')
+BLOCKS_RS_DIR = get_dir_location("../azalea-block/src/generated.rs")
# Terminology:
# - Property: A property of a block, like "direction"
@@ -12,18 +9,23 @@ BLOCKS_RS_DIR = get_dir_location('../azalea-block/src/generated.rs')
# - Block: Has properties and states.
-def generate_blocks(blocks_report: dict, pumpkin_block_datas: dict, ordered_blocks: list[str], burger_data: dict):
- with open(BLOCKS_RS_DIR, 'r') as f:
+def generate_blocks(
+ blocks_report: dict,
+ pumpkin_block_datas: dict,
+ ordered_blocks: list[str],
+ burger_data: dict,
+):
+ with open(BLOCKS_RS_DIR, "r") as f:
existing_code = f.read().splitlines()
new_make_block_states_macro_code = []
- new_make_block_states_macro_code.append('make_block_states! {')
+ new_make_block_states_macro_code.append("make_block_states! {")
- burger_block_datas = burger_data[0]['blocks']['block']
+ burger_block_datas = burger_data[0]["blocks"]["block"]
pumpkin_block_map = {}
- for block_data in pumpkin_block_datas['blocks']:
- block_id = block_data['name']
+ for block_data in pumpkin_block_datas["blocks"]:
+ block_id = block_data["name"]
pumpkin_block_map[block_id] = block_data
# Find properties
@@ -32,20 +34,22 @@ def generate_blocks(blocks_report: dict, pumpkin_block_datas: dict, ordered_bloc
# This dict looks like { 'FloweringAzaleaLeavesDistance': 'distance' }
property_struct_names_to_names = {}
for block_id in ordered_blocks:
- block_data_report = blocks_report[f'minecraft:{block_id}']
+ block_data_report = blocks_report[f"minecraft:{block_id}"]
block_properties = {}
- for property_id in list(block_data_report.get('properties', {}).keys()):
- property_variants = block_data_report['properties'][property_id]
+ for property_id in list(block_data_report.get("properties", {}).keys()):
+ property_variants = block_data_report["properties"][property_id]
- property_struct_name = get_property_struct_name(block_id, property_id, property_variants)
+ property_struct_name = get_property_struct_name(
+ block_id, property_id, property_variants
+ )
if property_struct_name in properties:
if not properties[property_struct_name] == property_variants:
raise Exception(
- 'There are multiple enums with the same name! '
- f'Name: {property_struct_name}, variants: {property_variants}/{properties[property_struct_name]}. '
- 'This can be fixed by hardcoding a name in the get_property_struct_name function.'
+ "There are multiple enums with the same name! "
+ f"Name: {property_struct_name}, variants: {property_variants}/{properties[property_struct_name]}. "
+ "This can be fixed by hardcoding a name in the get_property_struct_name function."
)
block_properties[property_struct_name] = property_variants
@@ -55,7 +59,7 @@ def generate_blocks(blocks_report: dict, pumpkin_block_datas: dict, ordered_bloc
properties.update(block_properties)
# Property codegen
- new_make_block_states_macro_code.append(' Properties => {')
+ new_make_block_states_macro_code.append(" Properties => {")
for property_struct_name, property_variants in properties.items():
# "face" => Face {
# Floor,
@@ -65,99 +69,104 @@ def generate_blocks(blocks_report: dict, pumpkin_block_datas: dict, ordered_bloc
property_id = property_struct_names_to_names[property_struct_name]
# if the only variants are true and false, we make it unit struct with a boolean instead of an enum
- if property_variants == ['true', 'false']:
- property_shape_code = f'{property_struct_name}(bool)'
+ if property_variants == ["true", "false"]:
+ property_shape_code = f"{property_struct_name}(bool)"
else:
- property_shape_code = f'{property_struct_name} {{\n'
+ property_shape_code = f"{property_struct_name} {{\n"
for variant in property_variants:
- property_shape_code += f' {to_camel_case(variant)},\n'
- property_shape_code += ' }'
+ property_shape_code += f" {to_camel_case(variant)},\n"
+ property_shape_code += " }"
new_make_block_states_macro_code.append(
- f' "{property_id}" => {property_shape_code},')
+ f' "{property_id}" => {property_shape_code},'
+ )
- new_make_block_states_macro_code.append(' },')
+ new_make_block_states_macro_code.append(" },")
# Block codegen
- new_make_block_states_macro_code.append(' Blocks => {')
+ new_make_block_states_macro_code.append(" Blocks => {")
for block_id in ordered_blocks:
- block_data_report = blocks_report['minecraft:' + block_id]
+ block_data_report = blocks_report["minecraft:" + block_id]
block_data_burger = burger_block_datas.get(block_id, {})
block_data_pumpkin = pumpkin_block_map[block_id]
default_property_variants: dict[str, str] = {}
- for state in block_data_report['states']:
- if state.get('default'):
- default_property_variants = state.get('properties', {})
+ for state in block_data_report["states"]:
+ if state.get("default"):
+ default_property_variants = state.get("properties", {})
- properties_code = '{'
- for property_id in list(block_data_report.get('properties', {}).keys()):
+ properties_code = "{"
+ for property_id in list(block_data_report.get("properties", {}).keys()):
property_default = default_property_variants.get(property_id)
- property_variants = block_data_report['properties'][property_id]
+ property_variants = block_data_report["properties"][property_id]
property_struct_name = get_property_struct_name(
- block_id, property_id, property_variants)
+ block_id, property_id, property_variants
+ )
- is_boolean_property = property_variants == ['true', 'false']
+ is_boolean_property = property_variants == ["true", "false"]
if is_boolean_property:
# if it's a boolean, keep the type lowercase
# (so it's either `true` or `false`)
- property_default_type = f'{property_struct_name}({property_default})'
+ property_default_type = f"{property_struct_name}({property_default})"
else:
- property_default_type = f'{property_struct_name}::{to_camel_case(property_default)}'
+ property_default_type = (
+ f"{property_struct_name}::{to_camel_case(property_default)}"
+ )
assert property_default is not None
this_property_code = f'"{property_id}": {property_default_type}'
- properties_code += f'\n {this_property_code},'
+ properties_code += f"\n {this_property_code},"
# if there's nothing inside the properties, keep it in one line
- if properties_code == '{':
- properties_code += '}'
+ if properties_code == "{":
+ properties_code += "}"
else:
- properties_code += '\n }'
+ properties_code += "\n }"
# make the block behavior
- behavior_constructor = 'BlockBehavior::new()'
+ behavior_constructor = "BlockBehavior::new()"
# requires tool
- if block_data_burger.get('requires_correct_tool_for_drops'):
- behavior_constructor += '.requires_correct_tool_for_drops()'
+ if block_data_burger.get("requires_correct_tool_for_drops"):
+ behavior_constructor += ".requires_correct_tool_for_drops()"
# strength
- destroy_time = block_data_pumpkin.get('hardness')
- explosion_resistance = block_data_pumpkin.get('blast_resistance')
+ destroy_time = block_data_pumpkin.get("hardness")
+ explosion_resistance = block_data_pumpkin.get("blast_resistance")
if destroy_time and explosion_resistance:
- behavior_constructor += f'.strength({destroy_time}, {explosion_resistance})'
+ behavior_constructor += f".strength({destroy_time}, {explosion_resistance})"
elif destroy_time:
- behavior_constructor += f'.destroy_time({destroy_time})'
+ behavior_constructor += f".destroy_time({destroy_time})"
elif explosion_resistance:
- behavior_constructor += f'.explosion_resistance({explosion_resistance})'
+ behavior_constructor += f".explosion_resistance({explosion_resistance})"
# friction
- friction = block_data_burger.get('friction')
- if friction != None:
- behavior_constructor += f'.friction({friction})'
-
+ friction = block_data_burger.get("friction")
+ if friction is not None:
+ behavior_constructor += f".friction({friction})"
+
force_solid = None
- if block_data_burger.get('force_solid_on'):
- force_solid = 'true'
- elif block_data_burger.get('force_solid_off'):
- force_solid = 'false'
- if force_solid != None:
- behavior_constructor += f'.force_solid({force_solid})'
+ if block_data_burger.get("force_solid_on"):
+ force_solid = "true"
+ elif block_data_burger.get("force_solid_off"):
+ force_solid = "false"
+ if force_solid is not None:
+ behavior_constructor += f".force_solid({force_solid})"
# TODO: use burger to generate the blockbehavior
new_make_block_states_macro_code.append(
- f' {block_id} => {behavior_constructor}, {properties_code},')
+ f" {block_id} => {behavior_constructor}, {properties_code},"
+ )
- new_make_block_states_macro_code.append(' }')
- new_make_block_states_macro_code.append('}')
+ new_make_block_states_macro_code.append(" }")
+ new_make_block_states_macro_code.append("}")
new_code = []
in_macro = False
for line in existing_code:
- if line == 'make_block_states! {':
+ if line == "make_block_states! {":
in_macro = True
- elif line == '}':
+ elif line == "}":
if in_macro:
in_macro = False
new_code.extend(new_make_block_states_macro_code)
@@ -166,69 +175,94 @@ def generate_blocks(blocks_report: dict, pumpkin_block_datas: dict, ordered_bloc
continue
new_code.append(line)
# empty line at the end
- new_code.append('')
+ new_code.append("")
+
+ with open(BLOCKS_RS_DIR, "w") as f:
+ f.write("\n".join(new_code))
- with open(BLOCKS_RS_DIR, 'w') as f:
- f.write('\n'.join(new_code))
-def get_property_struct_name(block_id: str, property_id: str, property_variants: list[str]) -> str:
+def get_property_struct_name(
+ block_id: str, property_id: str, property_variants: list[str]
+) -> str:
# these are hardcoded because otherwise they cause conflicts
# some names inspired by https://github.com/feather-rs/feather/blob/main/feather/blocks/src/generated/table.rs
- if property_variants == ['north', 'east', 'south', 'west', 'up', 'down']:
- return 'FacingCubic'
- if property_variants == ['north', 'south', 'west', 'east']:
- return 'FacingCardinal'
- if property_variants == ['top', 'bottom']:
- return 'TopBottom'
- if property_variants == ['north_south', 'east_west', 'ascending_east', 'ascending_west', 'ascending_north', 'ascending_south']:
- return 'RailShape'
- if property_variants == ['straight', 'inner_left', 'inner_right', 'outer_left', 'outer_right']:
- return 'StairShape'
- if property_variants == ['normal', 'sticky']:
- return 'PistonType'
- if property_variants == ['x', 'z']:
- return 'AxisXZ'
- if property_variants == ['single', 'left', 'right']:
- return 'ChestType'
- if property_variants == ['compare', 'subtract']:
- return 'ComparatorType'
- if property_variants == ['inactive', 'waiting_for_players', 'active', 'waiting_for_reward_ejection', 'ejecting_reward', 'cooldown']:
- return 'TrialSpawnerState'
- if property_variants == ['inactive', 'active', 'unlocking', 'ejecting']:
- return 'VaultState'
- if property_variants == ['start', 'log', 'fail', 'accept']:
- return 'TestMode'
- if property_variants == ['save', 'load', 'corner', 'data']:
- return 'StructureMode'
- if 'harp' in property_variants and 'didgeridoo' in property_variants:
- return 'Sound'
+ if property_variants == ["north", "east", "south", "west", "up", "down"]:
+ return "FacingCubic"
+ if property_variants == ["north", "south", "west", "east"]:
+ return "FacingCardinal"
+ if property_variants == ["top", "bottom"]:
+ return "TopBottom"
+ if property_variants == [
+ "north_south",
+ "east_west",
+ "ascending_east",
+ "ascending_west",
+ "ascending_north",
+ "ascending_south",
+ ]:
+ return "RailShape"
+ if property_variants == [
+ "straight",
+ "inner_left",
+ "inner_right",
+ "outer_left",
+ "outer_right",
+ ]:
+ return "StairShape"
+ if property_variants == ["normal", "sticky"]:
+ return "PistonType"
+ if property_variants == ["x", "z"]:
+ return "AxisXZ"
+ if property_variants == ["single", "left", "right"]:
+ return "ChestType"
+ if property_variants == ["compare", "subtract"]:
+ return "ComparatorType"
+ if property_variants == [
+ "inactive",
+ "waiting_for_players",
+ "active",
+ "waiting_for_reward_ejection",
+ "ejecting_reward",
+ "cooldown",
+ ]:
+ return "TrialSpawnerState"
+ if property_variants == ["inactive", "active", "unlocking", "ejecting"]:
+ return "VaultState"
+ if property_variants == ["start", "log", "fail", "accept"]:
+ return "TestMode"
+ if property_variants == ["save", "load", "corner", "data"]:
+ return "StructureMode"
+ if "harp" in property_variants and "didgeridoo" in property_variants:
+ return "Sound"
if is_list_of_string_integers(property_variants):
# if the values are all integers, then prepend the block name
return to_camel_case(block_id) + to_camel_case(property_id)
- if property_variants == ['up', 'side', 'none']:
- return 'Wire' + to_camel_case(property_id)
- if property_variants == ['none', 'low', 'tall']:
- return 'Wall' + to_camel_case(property_id)
+ if property_variants == ["up", "side", "none"]:
+ return "Wire" + to_camel_case(property_id)
+ if property_variants == ["none", "low", "tall"]:
+ return "Wall" + to_camel_case(property_id)
return to_camel_case(property_id)
-def is_list_of_string_integers(l: list[str]) -> bool:
- return all(map(str.isdigit, l))
+
+def is_list_of_string_integers(list_to_check: list[str]) -> bool:
+ return all(map(str.isdigit, list_to_check))
+
def get_ordered_blocks(registries_report: dict[str, dict]) -> list[str]:
- '''
+ """
Returns a list of block ids (like ['air', 'stone', ...]) ordered by their protocol id.
- '''
- blocks_registry = registries_report['minecraft:block']
+ """
+ blocks_registry = registries_report["minecraft:block"]
- blocks_to_ids = {}
- for block_id, value in blocks_registry['entries'].items():
- prefix = 'minecraft:'
+ blocks_to_ids = {}
+ for block_id, value in blocks_registry["entries"].items():
+ prefix = "minecraft:"
assert block_id.startswith(prefix)
- block_id = block_id[len(prefix):]
- protocol_id = value['protocol_id']
+ block_id = block_id[len(prefix) :]
+ protocol_id = value["protocol_id"]
blocks_to_ids[block_id] = protocol_id
-
+
ordered_blocks = []
for block_id in sorted(blocks_to_ids, key=blocks_to_ids.get):
ordered_blocks.append(block_id)
diff --git a/codegen/lib/code/entity.py b/codegen/lib/code/entity.py
index c27c4ce7..41a94991 100644
--- a/codegen/lib/code/entity.py
+++ b/codegen/lib/code/entity.py
@@ -1,18 +1,14 @@
from lib.utils import to_camel_case, to_snake_case, get_dir_location, upper_first_letter
-from lib.code.packet import burger_instruction_to_code
-from lib.code.utils import burger_type_to_rust_type
from lib.mappings import Mappings
from typing import Optional
import re
-METADATA_RS_DIR = get_dir_location(
- '../azalea-entity/src/metadata.rs')
+METADATA_RS_DIR = get_dir_location("../azalea-entity/src/metadata.rs")
-DATA_RS_DIR = get_dir_location(
- '../azalea-entity/src/data.rs')
+DATA_RS_DIR = get_dir_location("../azalea-entity/src/data.rs")
+
+DIMENSIONS_RS_DIR = get_dir_location("../azalea-entity/src/dimensions.rs")
-DIMENSIONS_RS_DIR = get_dir_location(
- '../azalea-entity/src/dimensions.rs')
def generate_metadata_names(burger_dataserializers: dict, mappings: Mappings):
serializer_names: list[Optional[str]] = [None] * len(burger_dataserializers)
@@ -20,56 +16,63 @@ def generate_metadata_names(burger_dataserializers: dict, mappings: Mappings):
print(burger_serializer)
# 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()
-
- if mojmap_name == 'component':
- mojmap_name = 'formatted_text'
- elif mojmap_name == 'optional_component':
- mojmap_name = 'optional_formatted_text'
-
- serializer_names[burger_serializer['id']] = upper_first_letter(to_camel_case(mojmap_name))
+ 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()
+
+ if mojmap_name == "component":
+ mojmap_name = "formatted_text"
+ elif mojmap_name == "optional_component":
+ mojmap_name = "optional_formatted_text"
+
+ serializer_names[burger_serializer["id"]] = upper_first_letter(
+ to_camel_case(mojmap_name)
+ )
return serializer_names
+
def parse_metadata_types_from_code():
- with open(DATA_RS_DIR, 'r') as f:
+ with open(DATA_RS_DIR, "r") as f:
lines = f.read().splitlines()
-
+
data = []
in_enum = False
for line in lines:
- if line == 'pub enum EntityDataValue {':
+ if line == "pub enum EntityDataValue {":
in_enum = True
- elif line == '}':
+ elif line == "}":
in_enum = False
elif in_enum:
line = line.strip()
- if line.startswith('//'): continue
- name, type = line.rstrip('),').split('(')
+ if line.startswith("//"):
+ continue
+ name, type = line.rstrip("),").split("(")
is_var = False
- if type.startswith('#[var] '):
+ if type.startswith("#[var] "):
is_var = True
- type = type[len('#[var] '):]
- data.append({
- 'name': name,
- 'type': type,
- 'var': is_var
- })
+ type = type[len("#[var] ") :]
+ data.append({"name": name, "type": type, "var": is_var})
print(data)
return data
+
def generate_entity_metadata(burger_entities_data: dict, mappings: Mappings):
- burger_entity_metadata = burger_entities_data['entity']
+ burger_entity_metadata = burger_entities_data["entity"]
- new_metadata_names = generate_metadata_names(burger_entities_data['dataserializers'], mappings)
+ new_metadata_names = generate_metadata_names(
+ burger_entities_data["dataserializers"], mappings
+ )
parsed_metadata_types = parse_metadata_types_from_code()
parsed_metadata_names = []
for t in parsed_metadata_types:
- parsed_metadata_names.append(t['name'])
+ parsed_metadata_names.append(t["name"])
- with open(DATA_RS_DIR, 'r') as f:
+ with open(DATA_RS_DIR, "r") as f:
lines = f.read().splitlines()
# add the metadata names that weren't there before to the end of the enum.
# this technically might cause them to be in the wrong order but i decided
@@ -81,26 +84,28 @@ def generate_entity_metadata(burger_entities_data: dict, mappings: Mappings):
if added_metadata_names != []:
in_enum = False
for i, line in enumerate(list(lines)):
- if line == 'pub enum EntityDataValue {':
+ if line == "pub enum EntityDataValue {":
in_enum = True
- elif in_enum and line == '}':
+ elif in_enum and line == "}":
in_enum = False
for n in added_metadata_names:
- lines.insert(i, f'{n}(TODO),')
+ lines.insert(i, f"{n}(TODO),")
i += 1
print(lines)
- with open(DATA_RS_DIR, 'w') as f:
- f.write('\n'.join(lines))
- print('Expected metadata types:\n' + '\n'.join(new_metadata_names))
- print('Updated metadata types in azalea-entity/src/data.rs, go make sure they\'re correct (check EntityDataSerializers.java) and then press enter')
+ with open(DATA_RS_DIR, "w") as f:
+ f.write("\n".join(lines))
+ print("Expected metadata types:\n" + "\n".join(new_metadata_names))
+ print(
+ "Updated metadata types in azalea-entity/src/data.rs, go make sure they're correct (check EntityDataSerializers.java) and then press enter"
+ )
input()
-
+
metadata_types = parse_metadata_types_from_code()
code = []
- code.append('''#![allow(clippy::single_match)]
+ code.append("""#![allow(clippy::single_match)]
-// This file is generated from codegen/lib/code/entity.py.
+// This file is @generated from codegen/lib/code/entity.py.
// Don't change it manually!
use azalea_chat::FormattedText;
@@ -131,10 +136,10 @@ impl From<EntityDataValue> for UpdateMetadataError {
Self::WrongType(value)
}
}
-''')
+""")
# types that are only ever used in one entity
- single_use_imported_types = {'particle', 'pose'}
+ single_use_imported_types = {"particle", "pose"}
added_metadata_fields = set()
@@ -146,11 +151,13 @@ impl From<EntityDataValue> for UpdateMetadataError {
duplicate_field_names = set()
# some generic names... we don't like these
- duplicate_field_names.add('state') # SnifferState instead of State
+ duplicate_field_names.add("state") # SnifferState instead of State
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).values():
+ for field_name_or_bitfield in get_entity_metadata_names(
+ entity_id, burger_entity_metadata, mappings
+ ).values():
if isinstance(field_name_or_bitfield, str):
if field_name_or_bitfield in previous_field_names:
duplicate_field_names.add(field_name_or_bitfield)
@@ -170,25 +177,30 @@ impl From<EntityDataValue> for UpdateMetadataError {
# make sure these types are only ever made once
for name in single_use_imported_types:
if name in duplicate_field_names:
- raise Exception(f'{name} should only exist once')
+ raise Exception(f"{name} should only exist once")
# 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).items():
+ for index, field_name_or_bitfield in get_entity_metadata_names(
+ entity_id, burger_entity_metadata, mappings
+ ).items():
if isinstance(field_name_or_bitfield, str):
new_field_name = field_name_or_bitfield
- if new_field_name == 'type':
- new_field_name = 'kind'
+ if new_field_name == "type":
+ new_field_name = "kind"
if field_name_or_bitfield in duplicate_field_names:
- field_name_map[entity_id][
- field_name_or_bitfield] = f'{entity_id.strip("~")}_{new_field_name}'
+ field_name_map[entity_id][field_name_or_bitfield] = (
+ f"{entity_id.strip('~')}_{new_field_name}"
+ )
else:
for mask, name in field_name_or_bitfield.items():
new_field_name = name
- if new_field_name == 'type':
- new_field_name = 'kind'
+ if new_field_name == "type":
+ new_field_name = "kind"
if name in duplicate_field_names:
- field_name_map[entity_id][name] = f'{entity_id.strip("~")}_{new_field_name}'
+ field_name_map[entity_id][name] = (
+ f"{entity_id.strip('~')}_{new_field_name}"
+ )
def new_entity(entity_id: str):
# note: fields are components
@@ -199,25 +211,35 @@ impl From<EntityDataValue> for UpdateMetadataError {
entity_metadatas = []
def maybe_rename_field(name: str, index: int) -> str:
- if name in field_name_map[entity_ids_for_all_field_names_or_bitfields[index]]:
- return field_name_map[entity_ids_for_all_field_names_or_bitfields[index]][name]
+ if (
+ name
+ in field_name_map[entity_ids_for_all_field_names_or_bitfields[index]]
+ ):
+ return field_name_map[
+ entity_ids_for_all_field_names_or_bitfields[index]
+ ][name]
return name
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).items():
+ for index, name_or_bitfield in get_entity_metadata_names(
+ parent_id, burger_entity_metadata, mappings
+ ).items():
assert index == len(all_field_names_or_bitfields)
all_field_names_or_bitfields.append(name_or_bitfield)
entity_ids_for_all_field_names_or_bitfields.append(parent_id)
- entity_metadatas.extend(get_entity_metadata(
- parent_id, burger_entity_metadata))
+ entity_metadatas.extend(
+ get_entity_metadata(parent_id, burger_entity_metadata)
+ )
parent_id = parents[1] if len(parents) > 1 else None
# now add all the fields/component structs
for index, name_or_bitfield in enumerate(all_field_names_or_bitfields):
# make sure we only ever make these structs once
- hashable_name_or_bitfield = str(
- name_or_bitfield) + entity_ids_for_all_field_names_or_bitfields[index]
+ hashable_name_or_bitfield = (
+ str(name_or_bitfield)
+ + entity_ids_for_all_field_names_or_bitfields[index]
+ )
if hashable_name_or_bitfield in added_metadata_fields:
continue
added_metadata_fields.add(hashable_name_or_bitfield)
@@ -229,30 +251,33 @@ impl From<EntityDataValue> for UpdateMetadataError {
name_or_bitfield = maybe_rename_field(name_or_bitfield, index)
- struct_name = upper_first_letter(
- to_camel_case(name_or_bitfield))
- type_id = next(filter(lambda i: i['index'] == index, entity_metadatas))['type_id']
+ struct_name = upper_first_letter(to_camel_case(name_or_bitfield))
+ type_id = next(filter(lambda i: i["index"] == index, entity_metadatas))[
+ "type_id"
+ ]
metadata_type_data = metadata_types[type_id]
- rust_type = metadata_type_data['type']
+ rust_type = metadata_type_data["type"]
- code.append(f'#[derive(Component, Deref, DerefMut, Clone)]')
- code.append(f'pub struct {struct_name}(pub {rust_type});')
+ code.append("#[derive(Component, Deref, DerefMut, Clone)]")
+ code.append(f"pub struct {struct_name}(pub {rust_type});")
else:
# if it's a bitfield just make a struct for each bit
for mask, name in name_or_bitfield.items():
name = maybe_rename_field(name, index)
struct_name = upper_first_letter(to_camel_case(name))
- code.append(f'#[derive(Component, Deref, DerefMut, Clone, Copy)]')
- code.append(f'pub struct {struct_name}(pub bool);')
+ code.append("#[derive(Component, Deref, DerefMut, Clone, Copy)]")
+ code.append(f"pub struct {struct_name}(pub bool);")
# add the entity struct and Bundle struct
- struct_name: str = upper_first_letter(
- to_camel_case(entity_id.lstrip('~')))
- code.append(f'#[derive(Component)]')
- code.append(f'pub struct {struct_name};')
+ struct_name: str = upper_first_letter(to_camel_case(entity_id.lstrip("~")))
+ code.append("#[derive(Component)]")
+ code.append(f"pub struct {struct_name};")
- parent_struct_name = upper_first_letter(
- to_camel_case(parent_id.lstrip("~"))) if parent_id else None
+ parent_struct_name = (
+ upper_first_letter(to_camel_case(parent_id.lstrip("~")))
+ if parent_id
+ else None
+ )
# impl Allay {
# pub fn apply_metadata(
@@ -267,58 +292,67 @@ impl From<EntityDataValue> for UpdateMetadataError {
# Ok(())
# }
# }
- code.append(f'impl {struct_name} {{')
+ code.append(f"impl {struct_name} {{")
code.append(
- f' pub fn apply_metadata(entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem) -> Result<(), UpdateMetadataError> {{')
- code.append(f' match d.index {{')
+ " pub fn apply_metadata(entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem) -> Result<(), UpdateMetadataError> {"
+ )
+ code.append(" match d.index {")
parent_last_index = -1
for index, name_or_bitfield in enumerate(all_field_names_or_bitfields):
- is_from_parent = entity_ids_for_all_field_names_or_bitfields[index] != entity_id
+ is_from_parent = (
+ entity_ids_for_all_field_names_or_bitfields[index] != entity_id
+ )
if is_from_parent:
parent_last_index = index
if parent_last_index != -1:
code.append(
- f' 0..={parent_last_index} => {parent_struct_name}::apply_metadata(entity, d)?,')
+ f" 0..={parent_last_index} => {parent_struct_name}::apply_metadata(entity, d)?,"
+ )
for index, name_or_bitfield in enumerate(all_field_names_or_bitfields):
if index <= parent_last_index:
continue
if isinstance(name_or_bitfield, str):
- name_or_bitfield = maybe_rename_field(
- name_or_bitfield, index)
+ name_or_bitfield = maybe_rename_field(name_or_bitfield, index)
- field_struct_name = upper_first_letter(
- to_camel_case(name_or_bitfield))
+ field_struct_name = upper_first_letter(to_camel_case(name_or_bitfield))
if name_or_bitfield in single_use_imported_types:
- field_struct_name = ''
+ field_struct_name = ""
- type_id = next(filter(lambda i: i['index'] == index, entity_metadatas))['type_id']
+ type_id = next(filter(lambda i: i["index"] == index, entity_metadatas))[
+ "type_id"
+ ]
metadata_type_data = metadata_types[type_id]
- rust_type = metadata_type_data['type']
- type_name = metadata_type_data['name']
+ rust_type = metadata_type_data["type"]
+ type_name = metadata_type_data["name"]
type_name_field = to_snake_case(type_name)
- read_field_code = f'{field_struct_name}(d.value.into_{type_name_field}()?)' if field_struct_name else f'd.value.into_{type_name_field}()?'
+ read_field_code = (
+ f"{field_struct_name}(d.value.into_{type_name_field}()?)"
+ if field_struct_name
+ else f"d.value.into_{type_name_field}()?"
+ )
code.append(
- f' {index} => {{ entity.insert({read_field_code}); }},')
+ f" {index} => {{ entity.insert({read_field_code}); }},"
+ )
else:
- code.append(f' {index} => {{')
- code.append(
- f'let bitfield = d.value.into_byte()?;')
+ code.append(f" {index} => {{")
+ code.append("let bitfield = d.value.into_byte()?;")
for mask, name in name_or_bitfield.items():
name = maybe_rename_field(name, index)
field_struct_name = upper_first_letter(to_camel_case(name))
code.append(
- f'entity.insert({field_struct_name}(bitfield & {mask} != 0));')
- code.append(' },')
- code.append(' _ => {}')
- code.append(' }')
- code.append(' Ok(())')
- code.append(' }')
- code.append('}')
- code.append('')
+ f"entity.insert({field_struct_name}(bitfield & {mask} != 0));"
+ )
+ code.append(" },")
+ code.append(" _ => {}")
+ code.append(" }")
+ code.append(" Ok(())")
+ code.append(" }")
+ code.append("}")
+ code.append("")
# #[derive(Bundle)]
# struct AllayBundle {
@@ -327,30 +361,27 @@ impl From<EntityDataValue> for UpdateMetadataError {
# dancing: Dancing,
# can_duplicate: CanDuplicate,
# }
- bundle_struct_name = f'{struct_name}MetadataBundle'
- code.append(f'')
- code.append(f'#[derive(Bundle)]')
- code.append(f'pub struct {bundle_struct_name} {{')
- code.append(
- f' _marker: {struct_name},')
+ bundle_struct_name = f"{struct_name}MetadataBundle"
+ code.append("")
+ code.append("#[derive(Bundle)]")
+ code.append(f"pub struct {bundle_struct_name} {{")
+ code.append(f" _marker: {struct_name},")
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).items():
+ code.append(f" parent: {parent_struct_name}MetadataBundle,")
+ for index, name_or_bitfield in get_entity_metadata_names(
+ entity_id, burger_entity_metadata, mappings
+ ).items():
if isinstance(name_or_bitfield, str):
- name_or_bitfield = maybe_rename_field(
- name_or_bitfield, index)
- struct_name = upper_first_letter(
- to_camel_case(name_or_bitfield))
- code.append(
- f' {name_or_bitfield}: {struct_name},')
+ name_or_bitfield = maybe_rename_field(name_or_bitfield, index)
+ struct_name = upper_first_letter(to_camel_case(name_or_bitfield))
+ code.append(f" {name_or_bitfield}: {struct_name},")
else:
for mask, name in name_or_bitfield.items():
name = maybe_rename_field(name, index)
struct_name = upper_first_letter(to_camel_case(name))
- code.append(f' {name}: {struct_name},')
- code.append('}')
+ code.append(f" {name}: {struct_name},")
+ code.append("}")
# impl Default for AllayBundle {
# fn default() -> Self {
@@ -365,9 +396,8 @@ impl From<EntityDataValue> for UpdateMetadataError {
# }
# }
# }
- code.append(f'impl Default for {bundle_struct_name} {{')
- code.append(
- ' fn default() -> Self {')
+ code.append(f"impl Default for {bundle_struct_name} {{")
+ code.append(" fn default() -> Self {")
def generate_fields(this_entity_id: str):
# on_fire: OnFire(false),
@@ -375,32 +405,39 @@ impl From<EntityDataValue> for UpdateMetadataError {
# _marker
this_entity_struct_name = upper_first_letter(
- to_camel_case(this_entity_id.lstrip('~')))
- code.append(
- f' _marker: {this_entity_struct_name},')
+ to_camel_case(this_entity_id.lstrip("~"))
+ )
+ code.append(f" _marker: {this_entity_struct_name},")
# if it has a parent, put it (do recursion)
# parent: AbstractCreatureBundle { ... },
this_entity_parent_ids = get_entity_parents(
- this_entity_id, burger_entity_metadata)
- this_entity_parent_id = this_entity_parent_ids[1] if len(
- this_entity_parent_ids) > 1 else None
+ this_entity_id, burger_entity_metadata
+ )
+ this_entity_parent_id = (
+ this_entity_parent_ids[1] if len(this_entity_parent_ids) > 1 else None
+ )
if this_entity_parent_id:
- bundle_struct_name = upper_first_letter(
- to_camel_case(this_entity_parent_id.lstrip('~'))) + 'MetadataBundle'
- code.append(
- f' parent: {bundle_struct_name} {{')
+ bundle_struct_name = (
+ upper_first_letter(to_camel_case(this_entity_parent_id.lstrip("~")))
+ + "MetadataBundle"
+ )
+ code.append(f" parent: {bundle_struct_name} {{")
generate_fields(this_entity_parent_id)
- code.append(
- ' },')
-
- for index, name_or_bitfield in get_entity_metadata_names(this_entity_id, burger_entity_metadata, mappings).items():
- default = next(filter(lambda i: i['index'] == index, entity_metadatas)).get('default', 'Default::default()')
+ code.append(" },")
+
+ for index, name_or_bitfield in get_entity_metadata_names(
+ this_entity_id, burger_entity_metadata, mappings
+ ).items():
+ default = next(
+ filter(lambda i: i["index"] == index, entity_metadatas)
+ ).get("default", "Default::default()")
if isinstance(name_or_bitfield, str):
- type_id = next(filter(lambda i: i['index'] == index, entity_metadatas))[
- 'type_id']
+ type_id = next(
+ filter(lambda i: i["index"] == index, entity_metadatas)
+ )["type_id"]
metadata_type_data = metadata_types[type_id]
- type_name = metadata_type_data['name']
+ type_name = metadata_type_data["name"]
name = maybe_rename_field(name_or_bitfield, index)
@@ -409,8 +446,8 @@ impl From<EntityDataValue> for UpdateMetadataError {
# wrong default metadatas. This should be added to Burger.
if default is None:
# some types don't have Default implemented
- if type_name == 'CompoundTag':
- default = 'simdnbt::owned::NbtCompound::default()'
+ if type_name == "CompoundTag":
+ default = "simdnbt::owned::NbtCompound::default()"
# elif type_name == 'CatVariant':
# # TODO: the default should be Tabby but we don't have a way to get that from here
# default = 'azalea_registry::CatVariant::new_raw(0)'
@@ -418,49 +455,84 @@ impl From<EntityDataValue> for UpdateMetadataError {
# default = 'azalea_registry::PaintingVariant::Kebab'
# elif type_name == 'FrogVariant':
# default = 'azalea_registry::FrogVariant::Temperate'
- elif type_name.endswith('Variant'):
- default = f'azalea_registry::{type_name}::new_raw(0)'
- elif type_name == 'VillagerData':
- default = 'VillagerData { kind: azalea_registry::VillagerKind::Plains, profession: azalea_registry::VillagerProfession::None, level: 0 }'
+ elif type_name.endswith("Variant"):
+ default = f"azalea_registry::{type_name}::new_raw(0)"
+ elif type_name == "VillagerData":
+ default = "VillagerData { kind: azalea_registry::VillagerKind::Plains, profession: azalea_registry::VillagerProfession::None, level: 0 }"
else:
- default = f'{type_name}::default()' if name in single_use_imported_types else 'Default::default()'
+ default = (
+ f"{type_name}::default()"
+ if name in single_use_imported_types
+ else "Default::default()"
+ )
else:
- if type_name == 'Boolean':
- default = 'true' if default else 'false'
- elif type_name == 'String':
+ if type_name == "Boolean":
+ default = "true" if default else "false"
+ elif type_name == "String":
string_escaped = default.replace('"', '\\"')
default = f'"{string_escaped}".to_string()'
- elif type_name == 'BlockPos':
- default = f'BlockPos::new{default}'
- elif type_name == 'OptionalBlockPos': # Option<BlockPos>
- default = f'Some(BlockPos::new{default})' if default != 'Empty' else 'None'
- elif type_name == 'OptionalLivingEntityReference':
- default = f'Some(uuid::uuid!({default}))' if default != 'Empty' else 'None'
- elif type_name == 'OptionalUnsignedInt':
- default = f'OptionalUnsignedInt(Some({default}))' if default != 'Empty' else 'OptionalUnsignedInt(None)'
- elif type_name == 'ItemStack':
- default = f'ItemStack::Present({default})' if default != 'Empty' else 'ItemStack::Empty'
- elif type_name == 'BlockState':
- default = f'{default}' if default != 'Empty' else 'azalea_block::BlockState::AIR'
- elif type_name == 'OptionalBlockState':
- default = f'{default}' if default != 'Empty' else 'azalea_block::BlockState::AIR'
- elif type_name == 'OptionalFormattedText':
- default = f'Some({default})' if default != 'Empty' else 'None'
- elif type_name == 'CompoundTag':
- default = f'simdnbt::owned::NbtCompound({default})' if default != 'Empty' else 'simdnbt::owned::NbtCompound::default()'
- elif type_name == 'Quaternion':
- default = f'Quaternion {{ x: {float(default["x"])}, y: {float(default["y"])}, z: {float(default["z"])}, w: {float(default["w"])} }}'
- elif type_name == 'Vector3':
- default = f'Vec3 {{ x: {float(default["x"])}, y: {float(default["y"])}, z: {float(default["z"])} }}'
- elif type_name == 'Byte':
+ elif type_name == "BlockPos":
+ default = f"BlockPos::new{default}"
+ elif type_name == "OptionalBlockPos": # Option<BlockPos>
+ default = (
+ f"Some(BlockPos::new{default})"
+ if default != "Empty"
+ else "None"
+ )
+ elif type_name == "OptionalLivingEntityReference":
+ default = (
+ f"Some(uuid::uuid!({default}))"
+ if default != "Empty"
+ else "None"
+ )
+ elif type_name == "OptionalUnsignedInt":
+ default = (
+ f"OptionalUnsignedInt(Some({default}))"
+ if default != "Empty"
+ else "OptionalUnsignedInt(None)"
+ )
+ elif type_name == "ItemStack":
+ default = (
+ f"ItemStack::Present({default})"
+ if default != "Empty"
+ else "ItemStack::Empty"
+ )
+ elif type_name == "BlockState":
+ default = (
+ f"{default}"
+ if default != "Empty"
+ else "azalea_block::BlockState::AIR"
+ )
+ elif type_name == "OptionalBlockState":
+ default = (
+ f"{default}"
+ if default != "Empty"
+ else "azalea_block::BlockState::AIR"
+ )
+ elif type_name == "OptionalFormattedText":
+ default = (
+ f"Some({default})" if default != "Empty" else "None"
+ )
+ elif type_name == "CompoundTag":
+ default = (
+ f"simdnbt::owned::NbtCompound({default})"
+ if default != "Empty"
+ else "simdnbt::owned::NbtCompound::default()"
+ )
+ elif type_name == "Quaternion":
+ default = f"Quaternion {{ x: {float(default['x'])}, y: {float(default['y'])}, z: {float(default['z'])}, w: {float(default['w'])} }}"
+ elif type_name == "Vector3":
+ default = f"Vec3 {{ x: {float(default['x'])}, y: {float(default['y'])}, z: {float(default['z'])} }}"
+ elif type_name == "Byte":
# in 1.19.4 TextOpacity is a -1 by default
if default < 0:
default += 128
if name in single_use_imported_types:
- code.append(f' {name}: {default},')
+ code.append(f" {name}: {default},")
else:
code.append(
- f' {name}: {upper_first_letter(to_camel_case(name))}({default}),')
+ f" {name}: {upper_first_letter(to_camel_case(name))}({default}),"
+ )
else:
# if it's a bitfield, we'll have to extract the default for
# each bool from each bit in the default
@@ -468,17 +540,19 @@ impl From<EntityDataValue> for UpdateMetadataError {
name = maybe_rename_field(name, index)
mask = int(mask, 0)
if default is None:
- bit_default = 'false'
+ bit_default = "false"
else:
- bit_default = 'true' if (default & mask != 0) else 'false'
+ bit_default = "true" if (default & mask != 0) else "false"
code.append(
- f' {name}: {upper_first_letter(to_camel_case(name))}({bit_default}),')
- code.append(' Self {')
+ f" {name}: {upper_first_letter(to_camel_case(name))}({bit_default}),"
+ )
+
+ code.append(" Self {")
generate_fields(entity_id)
- code.append(' }')
- code.append(' }')
- code.append('}')
- code.append('')
+ code.append(" }")
+ code.append(" }")
+ code.append("}")
+ code.append("")
# parent_field_name = None
for entity_id in burger_entity_metadata:
@@ -499,28 +573,27 @@ impl From<EntityDataValue> for UpdateMetadataError {
# Ok(())
# }
code.append(
- f'''pub fn apply_metadata(
+ """pub fn apply_metadata(
entity: &mut bevy_ecs::system::EntityCommands,
entity_kind: azalea_registry::EntityKind,
items: Vec<EntityDataItem>,
-) -> Result<(), UpdateMetadataError> {{
- match entity_kind {{''')
+) -> Result<(), UpdateMetadataError> {
+ match entity_kind {"""
+ )
for entity_id in burger_entity_metadata:
- if entity_id.startswith('~'):
+ if entity_id.startswith("~"):
# not actually an entity
continue
struct_name: str = upper_first_letter(to_camel_case(entity_id))
- code.append(
- f' azalea_registry::EntityKind::{struct_name} => {{')
- code.append(' for d in items {')
- code.append(
- f' {struct_name}::apply_metadata(entity, d)?;')
- code.append(' }')
- code.append(' },')
- code.append(' }')
- code.append(' Ok(())')
- code.append('}')
- code.append('')
+ code.append(f" azalea_registry::EntityKind::{struct_name} => {{")
+ code.append(" for d in items {")
+ code.append(f" {struct_name}::apply_metadata(entity, d)?;")
+ code.append(" }")
+ code.append(" },")
+ code.append(" }")
+ code.append(" Ok(())")
+ code.append("}")
+ code.append("")
# pub fn apply_default_metadata(entity: &mut bevy_ecs::system::EntityCommands, kind: azalea_registry::EntityKind) {
# match kind {
@@ -530,57 +603,61 @@ impl From<EntityDataValue> for UpdateMetadataError {
# }
# }
code.append(
- 'pub fn apply_default_metadata(entity: &mut bevy_ecs::system::EntityCommands, kind: azalea_registry::EntityKind) {')
- code.append(' match kind {')
+ "pub fn apply_default_metadata(entity: &mut bevy_ecs::system::EntityCommands, kind: azalea_registry::EntityKind) {"
+ )
+ code.append(" match kind {")
for entity_id in burger_entity_metadata:
- if entity_id.startswith('~'):
+ if entity_id.startswith("~"):
# not actually an entity
continue
struct_name: str = upper_first_letter(to_camel_case(entity_id))
+ code.append(f" azalea_registry::EntityKind::{struct_name} => {{")
code.append(
- f' azalea_registry::EntityKind::{struct_name} => {{')
- code.append(
- f' entity.insert({struct_name}MetadataBundle::default());')
- code.append(' },')
- code.append(' }')
- code.append('}')
- code.append('')
+ f" entity.insert({struct_name}MetadataBundle::default());"
+ )
+ code.append(" },")
+ code.append(" }")
+ code.append("}")
+ code.append("")
+
+ with open(METADATA_RS_DIR, "w") as f:
+ f.write("\n".join(code))
- with open(METADATA_RS_DIR, 'w') as f:
- f.write('\n'.join(code))
def generate_entity_dimensions(burger_entities_data: dict):
# lines look like
# EntityKind::Player => EntityDimensions::new(0.6, 1.8),
new_match_lines = []
- for entity_id, entity_data in burger_entities_data['entity'].items():
- if entity_id.startswith('~'):
+ for entity_id, entity_data in burger_entities_data["entity"].items():
+ if entity_id.startswith("~"):
# not actually an entity
continue
variant_name: str = upper_first_letter(to_camel_case(entity_id))
- width = entity_data['width']
- height = entity_data['height']
+ width = entity_data["width"]
+ height = entity_data["height"]
new_match_lines.append(
- f' EntityKind::{variant_name} => EntityDimensions::new({width}, {height}),')
+ f" EntityKind::{variant_name} => EntityDimensions::new({width}, {height}),"
+ )
- with open(DIMENSIONS_RS_DIR, 'r') as f:
- lines = f.read().split('\n')
+ with open(DIMENSIONS_RS_DIR, "r") as f:
+ lines = f.read().split("\n")
new_lines = []
in_match = False
for i, line in enumerate(lines):
if not in_match:
new_lines.append(line)
- if line.strip() == 'match entity {':
+ if line.strip() == "match entity {":
in_match = True
else:
- if line.strip() == '}':
+ if line.strip() == "}":
new_lines.extend(new_match_lines)
new_lines.extend(lines[i:])
break
- with open(DIMENSIONS_RS_DIR, 'w') as f:
- f.write('\n'.join(new_lines))
+ with open(DIMENSIONS_RS_DIR, "w") as f:
+ f.write("\n".join(new_lines))
+
def get_entity_parents(entity_id: str, burger_entity_metadata: dict):
parents = []
@@ -591,59 +668,68 @@ def get_entity_parents(entity_id: str, burger_entity_metadata: dict):
def get_entity_parent(entity_id: str, burger_entity_metadata: dict):
- entity_metadata = burger_entity_metadata[entity_id]['metadata']
+ entity_metadata = burger_entity_metadata[entity_id]["metadata"]
first_metadata = entity_metadata[0]
- return first_metadata.get('entity')
+ return first_metadata.get("entity")
def get_entity_metadata(entity_id: str, burger_entity_metadata: dict):
- entity_metadata = burger_entity_metadata[entity_id]['metadata']
+ entity_metadata = burger_entity_metadata[entity_id]["metadata"]
entity_useful_metadata = []
for metadata_item in entity_metadata:
- if 'data' in metadata_item:
- for metadata_attribute in metadata_item['data']:
- entity_useful_metadata.append({
- 'index': metadata_attribute['index'],
- 'type_id': metadata_attribute['serializer_id'],
- 'default': metadata_attribute.get('default')
- })
+ if "data" in metadata_item:
+ for metadata_attribute in metadata_item["data"]:
+ entity_useful_metadata.append(
+ {
+ "index": metadata_attribute["index"],
+ "type_id": metadata_attribute["serializer_id"],
+ "default": metadata_attribute.get("default"),
+ }
+ )
return entity_useful_metadata
+
# returns a dict of {index: (name or bitfield)}
-def get_entity_metadata_names(entity_id: str, burger_entity_metadata: dict, mappings: Mappings):
- entity_metadata = burger_entity_metadata[entity_id]['metadata']
+def get_entity_metadata_names(
+ entity_id: str, burger_entity_metadata: dict, mappings: Mappings
+):
+ 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']
- mojang_class = mappings.get_class(obfuscated_class)
+ if "data" in metadata_item:
+ 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)
+ for metadata_attribute in metadata_item["data"]:
+ obfuscated_field = metadata_attribute["field"]
+ mojang_field = mappings.get_field(obfuscated_class, obfuscated_field)
pretty_mojang_name = prettify_mojang_field(mojang_field)
- mapped_metadata_names[metadata_attribute['index']
- ] = pretty_mojang_name
+ mapped_metadata_names[metadata_attribute["index"]] = pretty_mojang_name
- if metadata_attribute['serializer'] == 'Byte' and first_byte_index is None:
- first_byte_index = metadata_attribute['index']
+ if (
+ metadata_attribute["serializer"] == "Byte"
+ and first_byte_index is None
+ ):
+ first_byte_index = metadata_attribute["index"]
- if metadata_item['bitfields'] and first_byte_index is not None:
+ if metadata_item["bitfields"] and first_byte_index is not None:
clean_bitfield = {}
- for bitfield_item in metadata_item['bitfields']:
+ for bitfield_item in metadata_item["bitfields"]:
bitfield_item_obfuscated_class = bitfield_item.get(
- 'class', obfuscated_class)
+ "class", obfuscated_class
+ )
mojang_bitfield_item_name = mappings.get_method(
- bitfield_item_obfuscated_class, bitfield_item['method'], '')
+ bitfield_item_obfuscated_class, bitfield_item["method"], ""
+ )
bitfield_item_name = prettify_mojang_method(
- mojang_bitfield_item_name)
- bitfield_hex_mask = hex(bitfield_item['mask'])
+ mojang_bitfield_item_name
+ )
+ bitfield_hex_mask = hex(bitfield_item["mask"])
clean_bitfield[bitfield_hex_mask] = bitfield_item_name
mapped_metadata_names[first_byte_index] = clean_bitfield
return mapped_metadata_names
@@ -652,14 +738,14 @@ def get_entity_metadata_names(entity_id: str, burger_entity_metadata: dict, mapp
def prettify_mojang_field(mojang_field: str):
# mojang names are like "DATA_AIR_SUPPLY" and that's ugly
better_name = mojang_field
- if better_name.startswith('DATA_'):
+ if better_name.startswith("DATA_"):
better_name = better_name[5:]
# remove the weird "Id" from the end of names
- if better_name.endswith('_ID'):
+ if better_name.endswith("_ID"):
better_name = better_name[:-3]
# remove the weird "id" from the front of names
- if better_name.startswith('ID_'):
+ if better_name.startswith("ID_"):
better_name = better_name[3:]
return better_name.lower()
@@ -667,9 +753,8 @@ def prettify_mojang_field(mojang_field: str):
def prettify_mojang_method(mojang_method: str):
better_name = mojang_method
- if better_name.endswith('()'):
+ if better_name.endswith("()"):
better_name = better_name[:-2]
- if re.match(r'is[A-Z]', better_name):
+ if re.match(r"is[A-Z]", better_name):
better_name = better_name[2:]
return to_snake_case(better_name)
-
diff --git a/codegen/lib/code/inventory.py b/codegen/lib/code/inventory.py
index caab57f2..066319e0 100644
--- a/codegen/lib/code/inventory.py
+++ b/codegen/lib/code/inventory.py
@@ -1,25 +1,21 @@
-from lib.utils import padded_hex, 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 Any, Optional
-import os
-import re
+from typing import Any
+from lib.utils import to_camel_case, get_dir_location
# The directory where declare_menus! {} is done
-inventory_menus_dir = get_dir_location(f'../azalea-inventory/src/lib.rs')
+inventory_menus_dir = get_dir_location("../azalea-inventory/src/lib.rs")
def update_menus(initial_menu_entries: dict[str, Any]):
# new_menus is a dict of { menu_id: { "protocol_id": protocol_id } }
# so convert that into an array where the protocol id is the index and the
# values are enum variant names
- new_menus: list[str] = [''] * len(initial_menu_entries)
+ new_menus: list[str] = [""] * len(initial_menu_entries)
for menu_id, menu in initial_menu_entries.items():
- new_menus[menu['protocol_id']] = menu_name_to_enum_name(menu_id)
+ new_menus[menu["protocol_id"]] = menu_name_to_enum_name(menu_id)
- new_menus.insert(0, 'Player')
+ new_menus.insert(0, "Player")
- with open(inventory_menus_dir, 'r') as f:
+ with open(inventory_menus_dir, "r") as f:
menus_rs = f.read().splitlines()
start_line_index = 0
@@ -27,17 +23,17 @@ def update_menus(initial_menu_entries: dict[str, Any]):
current_menus = []
in_the_macro = False
for i, line in enumerate(menus_rs):
- if line.startswith('declare_menus!'):
+ if line.startswith("declare_menus!"):
in_the_macro = True
start_line_index = i
if in_the_macro:
- if line.startswith(' ') and line.endswith('{'):
+ if line.startswith(" ") and line.endswith("{"):
# get the variant name for this menu
current_menu = line[:-1].strip()
current_menus.append(current_menu)
- print('current_menus', current_menus)
- print('new_menus', new_menus)
+ print("current_menus", current_menus)
+ print("new_menus", new_menus)
# now we have the current menus, so compare that with the expected
# menus and update the file if needed
@@ -52,57 +48,84 @@ def update_menus(initial_menu_entries: dict[str, Any]):
if (
current_menus_list_index < len(current_menus)
and new_menus_list_index < len(new_menus)
- and current_menus[current_menus_list_index] == new_menus[new_menus_list_index]
+ and current_menus[current_menus_list_index]
+ == new_menus[new_menus_list_index]
):
current_menus_list_index += 1
new_menus_list_index += 1
# increase insert_line_index until we get a line that starts with }
- while not menus_rs[insert_line_index].strip().startswith('}'):
+ while not menus_rs[insert_line_index].strip().startswith("}"):
insert_line_index += 1
insert_line_index += 1
# print('same', current_menus_list_index,
# new_menus_list_index, insert_line_index)
# something was added to new_menus but not current_menus
- elif new_menus_list_index < len(new_menus) and new_menus[new_menus_list_index] not in current_menus:
+ elif (
+ new_menus_list_index < len(new_menus)
+ and new_menus[new_menus_list_index] not in current_menus
+ ):
# insert the new menu
menus_rs.insert(
- insert_line_index, f' {new_menus[new_menus_list_index]} {{\n todo!()\n }},')
+ insert_line_index,
+ f" {new_menus[new_menus_list_index]} {{\n todo!()\n }},",
+ )
insert_line_index += 1
new_menus_list_index += 1
- print('added', current_menus_list_index,
- new_menus_list_index, insert_line_index)
+ print(
+ "added",
+ current_menus_list_index,
+ new_menus_list_index,
+ insert_line_index,
+ )
# something was removed from new_menus but is still in current_menus
- elif current_menus_list_index < len(current_menus) and current_menus[current_menus_list_index] not in new_menus:
+ elif (
+ current_menus_list_index < len(current_menus)
+ and current_menus[current_menus_list_index] not in new_menus
+ ):
# remove the current menu
- while not menus_rs[insert_line_index].strip().startswith('}'):
+ while not menus_rs[insert_line_index].strip().startswith("}"):
menus_rs.pop(insert_line_index)
menus_rs.pop(insert_line_index)
current_menus_list_index += 1
- print('removed', current_menus_list_index,
- new_menus_list_index, insert_line_index)
+ print(
+ "removed",
+ current_menus_list_index,
+ new_menus_list_index,
+ insert_line_index,
+ )
# if current_menus_list_index overflowed, then add the rest of the new menus
elif current_menus_list_index >= len(current_menus):
for i in range(new_menus_list_index, len(new_menus)):
menus_rs.insert(
- insert_line_index, f' {new_menus[i]} {{\n todo!()\n }},')
+ insert_line_index,
+ f" {new_menus[i]} {{\n todo!()\n }},",
+ )
insert_line_index += 1
- print('current_menus_list_index overflowed', current_menus_list_index,
- new_menus_list_index, insert_line_index)
+ print(
+ "current_menus_list_index overflowed",
+ current_menus_list_index,
+ new_menus_list_index,
+ insert_line_index,
+ )
break
# if new_menus_list_index overflowed, then remove the rest of the current menus
elif new_menus_list_index >= len(new_menus):
for _ in range(current_menus_list_index, len(current_menus)):
- while not menus_rs[insert_line_index].strip().startswith('}'):
+ while not menus_rs[insert_line_index].strip().startswith("}"):
menus_rs.pop(insert_line_index)
menus_rs.pop(insert_line_index)
# current_menus_list_index += 1
- print('new_menus_list_index overflowed', current_menus_list_index,
- new_menus_list_index, insert_line_index)
+ print(
+ "new_menus_list_index overflowed",
+ current_menus_list_index,
+ new_menus_list_index,
+ insert_line_index,
+ )
break
- with open(inventory_menus_dir, 'w') as f:
- f.write('\n'.join(menus_rs))
+ with open(inventory_menus_dir, "w") as f:
+ f.write("\n".join(menus_rs))
def menu_name_to_enum_name(menu_name: str) -> str:
- return to_camel_case(menu_name.split(':')[-1])
+ return to_camel_case(menu_name.split(":")[-1])
diff --git a/codegen/lib/code/item_components.py b/codegen/lib/code/item_components.py
index 3d4bf6a6..ce5d6d82 100644
--- a/codegen/lib/code/item_components.py
+++ b/codegen/lib/code/item_components.py
@@ -1,15 +1,10 @@
-import lib.code.inventory
-import lib.code.registry
-import lib.code.version
-import lib.code.packet
import lib.code.utils
-import lib.code.tags
-import lib.download
import lib.extract
import lib.utils
-ITEM_COMPONENTS_DIR = 'azalea-inventory/src/components.rs'
+ITEM_COMPONENTS_DIR = "azalea-inventory/src/components.rs"
+
def generate(version_id: str):
expected_variants = get_expected_variants(version_id)
@@ -25,61 +20,65 @@ def generate(version_id: str):
if variant not in expected_variants:
removed_variants.append(variant)
- print('New variants:')
+ print("New variants:")
for variant in new_variants:
- print('-', variant)
+ print("-", variant)
print()
- print('Removed variants:')
+ print("Removed variants:")
for variant in removed_variants:
- print('-', variant)
+ print("-", variant)
print()
for variant in removed_variants:
- print(f'Removing {variant}...')
+ print(f"Removing {variant}...")
remove_variant(variant)
for variant in new_variants:
- print(f'Adding {variant}...')
+ print(f"Adding {variant}...")
add_variant(variant)
lib.code.utils.fmt()
- print('Done!')
+ print("Done!")
+
def get_expected_variants(version_id: str):
expected_variants = []
registries = lib.extract.get_registries_report(version_id)
- registry = registries['minecraft:data_component_type']
+ registry = registries["minecraft:data_component_type"]
registry_entries = sorted(
- registry['entries'].items(), key=lambda x: x[1]['protocol_id'])
+ registry["entries"].items(), key=lambda x: x[1]["protocol_id"]
+ )
for variant_name, _variant in registry_entries:
- variant_struct_name = lib.utils.to_camel_case(variant_name.split(':')[-1])
+ variant_struct_name = lib.utils.to_camel_case(variant_name.split(":")[-1])
expected_variants.append(variant_struct_name)
return expected_variants
+
def get_actual_variants():
actual_variants = []
- with open(ITEM_COMPONENTS_DIR, 'r') as f:
- code = f.read().split('\n')
+ with open(ITEM_COMPONENTS_DIR, "r") as f:
+ code = f.read().split("\n")
in_match = False
for line in code:
if in_match:
- if line == ' })':
+ if line == " })":
break
- variant_line_prefix = ' DataComponentKind::'
+ variant_line_prefix = " DataComponentKind::"
if line.startswith(variant_line_prefix):
- variant = line[len(variant_line_prefix):].split(' ', 1)[0]
+ variant = line[len(variant_line_prefix) :].split(" ", 1)[0]
actual_variants.append(variant)
- elif line == ' Ok(match kind {':
+ elif line == " Ok(match kind {":
in_match = True
return actual_variants
+
def remove_variant(variant: str):
- with open(ITEM_COMPONENTS_DIR, 'r') as f:
- code = f.read().split('\n')
+ with open(ITEM_COMPONENTS_DIR, "r") as f:
+ code = f.read().split("\n")
first_line_with_variant = None
line_after_variant = None
@@ -87,78 +86,83 @@ def remove_variant(variant: str):
in_match = False
for i, line in enumerate(list(code)):
if in_match:
- if line == ' })':
+ if line == " })":
line_after_variant = i
break
- variant_line_prefix = ' DataComponentKind::'
+ variant_line_prefix = " DataComponentKind::"
if line.startswith(variant_line_prefix):
if first_line_with_variant is not None:
line_after_variant = i
break
- variant_name = line[len(variant_line_prefix):].split(' ', 1)[0]
+ variant_name = line[len(variant_line_prefix) :].split(" ", 1)[0]
if variant_name == variant:
first_line_with_variant = i
- elif line == ' Ok(match kind {':
+ elif line == " Ok(match kind {":
in_match = True
-
+
if first_line_with_variant is None:
- raise ValueError(f'Variant {variant} not found')
+ raise ValueError(f"Variant {variant} not found")
if line_after_variant is None:
- raise ValueError(f'Couldn\'t find end of variant {variant}')
+ raise ValueError(f"Couldn't find end of variant {variant}")
code = code[:first_line_with_variant] + code[line_after_variant:]
# now remove the struct
- line_before_struct = None # this is the #[derive] line
- line_after_struct = None # impl DataComponent for ... {\n...\n}
+ line_before_struct = None # this is the #[derive] line
+ line_after_struct = None # impl DataComponent for ... {\n...\n}
for i, line in enumerate(list(code)):
- if line == f'pub struct {variant} {{' or line == f'pub struct {variant};':
+ if line == f"pub struct {variant} {{" or line == f"pub struct {variant};":
line_before_struct = i - 1
- elif line == f'impl DataComponent for {variant} {{':
+ elif line == f"impl DataComponent for {variant} {{":
line_after_struct = i + 3
break
if line_before_struct is None:
- raise ValueError(f'Couldn\'t find struct {variant}')
+ raise ValueError(f"Couldn't find struct {variant}")
if line_after_struct is None:
- raise ValueError(f'Couldn\'t find impl DataComponent for {variant}')
-
+ raise ValueError(f"Couldn't find impl DataComponent for {variant}")
+
code = code[:line_before_struct] + code[line_after_struct:]
- with open(ITEM_COMPONENTS_DIR, 'w') as f:
- f.write('\n'.join(code))
+ with open(ITEM_COMPONENTS_DIR, "w") as f:
+ f.write("\n".join(code))
+
def add_variant(variant: str):
- with open(ITEM_COMPONENTS_DIR, 'r') as f:
- code = f.read().split('\n')
+ with open(ITEM_COMPONENTS_DIR, "r") as f:
+ code = f.read().split("\n")
in_match = False
last_line_in_match = None
for i, line in enumerate(list(code)):
if in_match:
- if line == ' })':
+ if line == " })":
last_line_in_match = i
break
- elif line == ' Ok(match kind {':
+ elif line == " Ok(match kind {":
in_match = True
if last_line_in_match is None:
- raise ValueError('Couldn\'t find end of match')
-
- code = code[:last_line_in_match] + [
- f' DataComponentKind::{variant} => Box::new({variant}::azalea_read(buf)?),',
- ] + code[last_line_in_match:]
+ raise ValueError("Couldn't find end of match")
+
+ code = (
+ code[:last_line_in_match]
+ + [
+ f" DataComponentKind::{variant} => Box::new({variant}::azalea_read(buf)?),",
+ ]
+ + code[last_line_in_match:]
+ )
# now insert the struct
- code.append('')
- code.append('#[derive(Clone, PartialEq, AzBuf)]')
- code.append(f'pub struct {variant} {{')
- code.append(' pub todo: todo!(), // see DataComponents.java')
- code.append('}')
- code.append(f'impl DataComponent for {variant} {{')
- code.append(f' const KIND: DataComponentKind = DataComponentKind::{variant};')
- code.append('}')
-
- with open(ITEM_COMPONENTS_DIR, 'w') as f:
- f.write('\n'.join(code))
+ code.append("")
+ code.append("#[derive(Clone, PartialEq, AzBuf)]")
+ code.append(f"pub struct {variant} {{")
+ code.append(" pub todo: todo!(), // see DataComponents.java")
+ code.append("}")
+ code.append(f"impl DataComponent for {variant} {{")
+ code.append(f" const KIND: DataComponentKind = DataComponentKind::{variant};")
+ code.append("}")
+
+ with open(ITEM_COMPONENTS_DIR, "w") as f:
+ f.write("\n".join(code))
lib.code.utils.fmt()
diff --git a/codegen/lib/code/language.py b/codegen/lib/code/language.py
index d27dde81..ff3e6906 100644
--- a/codegen/lib/code/language.py
+++ b/codegen/lib/code/language.py
@@ -1,8 +1,9 @@
from lib.utils import get_dir_location
import json
-LANGUAGE_DIR = get_dir_location('../azalea-language/src/en_us.json')
+LANGUAGE_DIR = get_dir_location("../azalea-language/src/en_us.json")
+
def write_language(contents: dict):
- with open(LANGUAGE_DIR, 'w') as f:
- f.write(json.dumps(contents, indent=' ')) \ No newline at end of file
+ with open(LANGUAGE_DIR, "w") as f:
+ f.write(json.dumps(contents, indent=" "))
diff --git a/codegen/lib/code/packet.py b/codegen/lib/code/packet.py
index 5ae2d41f..98f51ae9 100644
--- a/codegen/lib/code/packet.py
+++ b/codegen/lib/code/packet.py
@@ -8,92 +8,106 @@ import re
MOJMAP_TO_AZALEA_STATE_NAME_MAPPING = {
# shorter name, i like it more
- 'configuration': 'config',
+ "configuration": "config",
# in the files mojang calls the directory "game" so we do that too
- 'play': 'game'
+ "play": "game",
}
-AZALEA_TO_MOJMAP_STATE_NAME_MAPPING = {v: k for k, v in MOJMAP_TO_AZALEA_STATE_NAME_MAPPING.items()}
+AZALEA_TO_MOJMAP_STATE_NAME_MAPPING = {
+ v: k for k, v in MOJMAP_TO_AZALEA_STATE_NAME_MAPPING.items()
+}
+
+PACKETS_DIR = "../azalea-protocol/src/packets"
-PACKETS_DIR = '../azalea-protocol/src/packets'
def generate_packet(packets_report, packet_name, direction, state):
mojmap_state = AZALEA_TO_MOJMAP_STATE_NAME_MAPPING.get(state, state)
- _packet_report = packets_report[mojmap_state][direction]['minecraft:' + packet_name]
+ _packet_report = packets_report[mojmap_state][direction]["minecraft:" + packet_name]
code = []
- uses = set()
- packet_derive_name = f'{to_camel_case(direction)}{to_camel_case(state)}Packet'
+ packet_derive_name = f"{to_camel_case(direction)}{to_camel_case(state)}Packet"
- packet_struct_name = to_camel_case(f'{direction}_{packet_name}')
+ packet_struct_name = to_camel_case(f"{direction}_{packet_name}")
packet_module_name = get_packet_module_name(packet_name, direction)
- code.append(f'use azalea_buf::AzBuf;')
- code.append(f'use azalea_protocol_macros::{packet_derive_name};')
- code.append('')
-
- code.append(
- f'#[derive(Clone, Debug, AzBuf, {packet_derive_name})]')
- code.append(
- f'pub struct {packet_struct_name} {{')
- code.append(' TODO')
- code.append('}')
+ code.append("use azalea_buf::AzBuf;")
+ code.append(f"use azalea_protocol_macros::{packet_derive_name};")
+ code.append("")
+
+ code.append(f"#[derive(Clone, Debug, AzBuf, {packet_derive_name})]")
+ code.append(f"pub struct {packet_struct_name} {{")
+ code.append(" TODO")
+ code.append("}")
print(code)
- write_packet_file(state, packet_module_name, '\n'.join(code))
+ write_packet_file(state, packet_module_name, "\n".join(code))
# this won't handle writing to the packets/{state}/mod.rs file since we'd need to know the full packet list
+
def get_packet_module_name(packet_name: str, direction: str):
- return f'{direction[0]}_{packet_name}'
+ return f"{direction[0]}_{packet_name}"
+
-def set_packets(packets_report):
+def set_packets(packets_report):
for mojmap_state in packets_report:
state = MOJMAP_TO_AZALEA_STATE_NAME_MAPPING.get(mojmap_state, mojmap_state)
expected_packet_module_names = set()
- state_dir = get_dir_location(f'{PACKETS_DIR}/{state}')
- mod_rs_dir = get_dir_location(f'{state_dir}/mod.rs')
+ state_dir = get_dir_location(f"{PACKETS_DIR}/{state}")
+ mod_rs_dir = get_dir_location(f"{state_dir}/mod.rs")
- serverbound_packets = packet_direction_report_to_packet_names(packets_report[mojmap_state]['serverbound'])
- clientbound_packets = packet_direction_report_to_packet_names(packets_report[mojmap_state].get('clientbound', {}))
+ serverbound_packets = packet_direction_report_to_packet_names(
+ packets_report[mojmap_state]["serverbound"]
+ )
+ clientbound_packets = packet_direction_report_to_packet_names(
+ packets_report[mojmap_state].get("clientbound", {})
+ )
code = []
- code.append('// NOTE: This file is generated automatically by codegen/packet.py.')
+ code.append(
+ "// NOTE: This file is @generated automatically by codegen/packet.py."
+ )
code.append("// Don't edit it directly!")
- code.append('')
- code.append('use azalea_protocol_macros::declare_state_packets;')
- code.append('')
- code.append(f'declare_state_packets!({to_camel_case(state)}Packet,')
- code.append(' Clientbound => [')
+ code.append("")
+ code.append("use azalea_protocol_macros::declare_state_packets;")
+ code.append("")
+ code.append(f"declare_state_packets!({to_camel_case(state)}Packet,")
+ code.append(" Clientbound => [")
for packet_id, packet_name in enumerate(clientbound_packets):
- code.append(f' {packet_name}, // {padded_hex(packet_id)}')
- expected_packet_module_names.add(get_packet_module_name(packet_name, 'clientbound'))
- code.append(' ],')
- code.append(' Serverbound => [')
+ code.append(f" {packet_name}, // {padded_hex(packet_id)}")
+ expected_packet_module_names.add(
+ get_packet_module_name(packet_name, "clientbound")
+ )
+ code.append(" ],")
+ code.append(" Serverbound => [")
for packet_id, packet_name in enumerate(serverbound_packets):
- code.append(f' {packet_name}, // {padded_hex(packet_id)}')
- expected_packet_module_names.add(get_packet_module_name(packet_name, 'serverbound'))
- code.append(' ]')
- code.append(');')
- code.append('')
+ code.append(f" {packet_name}, // {padded_hex(packet_id)}")
+ expected_packet_module_names.add(
+ get_packet_module_name(packet_name, "serverbound")
+ )
+ code.append(" ]")
+ code.append(");")
+ code.append("")
- with open(mod_rs_dir, 'w') as f:
- f.write('\n'.join(code))
+ with open(mod_rs_dir, "w") as f:
+ f.write("\n".join(code))
existing_packet_module_names = set()
# iterate over the directory
for file in os.listdir(state_dir):
- if file.endswith('.rs') and file != 'mod.rs':
- existing_packet_module_names.add(file[:-len('.rs')])
- for packet_module_name in expected_packet_module_names - existing_packet_module_names:
+ if file.endswith(".rs") and file != "mod.rs":
+ existing_packet_module_names.add(file[: -len(".rs")])
+ for packet_module_name in (
+ expected_packet_module_names - existing_packet_module_names
+ ):
direction = None
- if packet_module_name.startswith('c_'):
- direction = 'clientbound'
- elif packet_module_name.startswith('s_'):
- direction = 'serverbound'
+ if packet_module_name.startswith("c_"):
+ direction = "clientbound"
+ elif packet_module_name.startswith("s_"):
+ direction = "serverbound"
else:
- raise Exception(f'Invalid packet module name: {packet_module_name}')
+ raise Exception(f"Invalid packet module name: {packet_module_name}")
packet = packet_module_name[2:]
generate_packet(packets_report, packet, direction, state)
@@ -101,15 +115,16 @@ def set_packets(packets_report):
def packet_direction_report_to_packet_names(report):
name_to_id = {}
for resource_location, packet in report.items():
- packet_id = packet['protocol_id']
- name_to_id[resource_location.split(':')[-1]] = packet_id
-
+ packet_id = packet["protocol_id"]
+ name_to_id[resource_location.split(":")[-1]] = packet_id
+
names_sorted = [name for name in sorted(name_to_id, key=lambda x: name_to_id[x])]
return names_sorted
+
def get_packets(direction: str, state: str):
- mod_rs_dir = get_dir_location(f'{PACKETS_DIR}/{state}/mod.rs')
- with open(mod_rs_dir, 'r') as f:
+ mod_rs_dir = get_dir_location(f"{PACKETS_DIR}/{state}/mod.rs")
+ with open(mod_rs_dir, "r") as f:
mod_rs = f.read().splitlines()
in_serverbound = False
@@ -119,90 +134,125 @@ def get_packets(direction: str, state: str):
packet_class_names: list[str] = []
for line in mod_rs:
- if line.strip() == 'Serverbound => {':
+ if line.strip() == "Serverbound => {":
in_serverbound = True
continue
- elif line.strip() == 'Clientbound => {':
+ elif line.strip() == "Clientbound => {":
in_clientbound = True
continue
- elif line.strip() in ('}', '},'):
- if (in_serverbound and direction == 'serverbound') or (in_clientbound and direction == 'clientbound'):
+ elif line.strip() in ("}", "},"):
+ if (in_serverbound and direction == "serverbound") or (
+ in_clientbound and direction == "clientbound"
+ ):
break
in_serverbound = in_clientbound = False
continue
- if line.strip() == '' or line.strip().startswith('//') or (not in_serverbound and direction == 'serverbound') or (not in_clientbound and direction == 'clientbound'):
+ if (
+ line.strip() == ""
+ or line.strip().startswith("//")
+ or (not in_serverbound and direction == "serverbound")
+ or (not in_clientbound and direction == "clientbound")
+ ):
continue
- line_packet_id_hex = line.strip().split(':')[0]
- assert line_packet_id_hex.startswith('0x')
+ line_packet_id_hex = line.strip().split(":")[0]
+ assert line_packet_id_hex.startswith("0x")
line_packet_id = int(line_packet_id_hex[2:], 16)
packet_ids.append(line_packet_id)
- packet_class_name = line.strip().split(':')[1].strip()
+ packet_class_name = line.strip().split(":")[1].strip()
packet_class_names.append(packet_class_name)
return packet_ids, packet_class_names
-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], known_variable_types={}) -> Optional[int]:
- '''
+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],
+ known_variable_types={},
+) -> Optional[int]:
+ """
Generate a field for an instruction, returns the number of instructions to skip (if any).
- '''
+ """
instruction = instructions[index]
- next_instruction = instructions[index +
- 1] if index + 1 < len(instructions) else None
- next_next_instruction = instructions[index +
- 2] if index + 2 < len(instructions) else None
+ next_instruction = (
+ instructions[index + 1] if index + 1 < len(instructions) else None
+ )
+ next_next_instruction = (
+ instructions[index + 2] if index + 2 < len(instructions) else None
+ )
is_var = False
skip = 0
field_type_rs = None
field_comment = None
- print('instruction', instruction, next_instruction, next_next_instruction)
+ print("instruction", instruction, next_instruction, next_next_instruction)
# iterators
- if instruction['operation'] == 'write'\
- and instruction['field'].endswith('.size()')\
- and next_instruction\
- and next_instruction['type'] == 'Iterator'\
- 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)
+ if (
+ instruction["operation"] == "write"
+ and instruction["field"].endswith(".size()")
+ and next_instruction
+ and next_instruction["type"] == "Iterator"
+ 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)
# figure out what kind of iterator it is
- loop_instructions = next_next_instruction['instructions']
+ loop_instructions = next_next_instruction["instructions"]
if len(loop_instructions) == 2:
entry_type_rs, is_var, value_uses, extra_code = burger_type_to_rust_type(
- loop_instructions[1]['type'], None, loop_instructions[1], mappings, obfuscated_class_name)
- field_type_rs = f'Vec<{entry_type_rs}>'
+ loop_instructions[1]["type"],
+ None,
+ loop_instructions[1],
+ mappings,
+ obfuscated_class_name,
+ )
+ field_type_rs = f"Vec<{entry_type_rs}>"
uses.update(value_uses)
elif len(loop_instructions) == 3:
- is_map = loop_instructions[0]['type'].startswith(
- 'Map.Entry<')
+ is_map = loop_instructions[0]["type"].startswith("Map.Entry<")
if is_map:
- assert loop_instructions[1]['field'].endswith(
- '.getKey()')
- assert loop_instructions[2]['field'].endswith(
- '.getValue()')
+ assert loop_instructions[1]["field"].endswith(".getKey()")
+ assert loop_instructions[2]["field"].endswith(".getValue()")
# generate the type for the key
- key_type_rs, is_key_var, key_uses, key_extra_code = burger_type_to_rust_type(
- loop_instructions[1]['type'], None, loop_instructions[1], mappings, obfuscated_class_name)
+ key_type_rs, is_key_var, key_uses, key_extra_code = (
+ burger_type_to_rust_type(
+ loop_instructions[1]["type"],
+ None,
+ loop_instructions[1],
+ mappings,
+ obfuscated_class_name,
+ )
+ )
uses.update(key_uses)
extra_code.extend(key_extra_code)
# generate the type for the value
- value_type_rs, is_value_var, value_uses, value_extra_code = burger_type_to_rust_type(
- loop_instructions[2]['type'], None, loop_instructions[2], mappings, obfuscated_class_name)
+ value_type_rs, is_value_var, value_uses, value_extra_code = (
+ burger_type_to_rust_type(
+ loop_instructions[2]["type"],
+ None,
+ loop_instructions[2],
+ mappings,
+ obfuscated_class_name,
+ )
+ )
uses.update(value_uses)
extra_code.extend(value_extra_code)
- field_type_rs = f'HashMap<{key_type_rs}, {value_type_rs}>'
- uses.add('std::collections::HashMap')
+ field_type_rs = f"HashMap<{key_type_rs}, {value_type_rs}>"
+ uses.add("std::collections::HashMap")
# only the key is var since the value can be made var in other ways
is_var = is_key_var
@@ -210,160 +260,206 @@ def burger_instruction_to_code(instructions: list[dict], index: int, generated_p
skip = 2 # skip the next 2 instructions
# Option<T>
- elif instruction['operation'] == 'write' and (instruction['field'].endswith('.isPresent()') or instruction['field'].endswith(' != null')) and next_instruction and (next_instruction.get('condition', '').endswith('.isPresent()') or next_instruction.get('condition', '').endswith(' != null')):
- print('ok is option')
- obfuscated_field_name = instruction['field'].split('.')[
- 0].split(' ')[0]
-
+ elif (
+ instruction["operation"] == "write"
+ and (
+ instruction["field"].endswith(".isPresent()")
+ or instruction["field"].endswith(" != null")
+ )
+ and next_instruction
+ and (
+ next_instruction.get("condition", "").endswith(".isPresent()")
+ or next_instruction.get("condition", "").endswith(" != null")
+ )
+ ):
+ print("ok is option")
+ obfuscated_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 field_name is None: field_name = obfuscated_field_name.split('/')[-1]
- if '<' in field_name:
- field_name = 'value'
+ field_name = mappings.get_field(obfuscated_class_name, obfuscated_field_name)
+
+ if field_name is None:
+ field_name = obfuscated_field_name.split("/")[-1]
+ if "<" in field_name:
+ field_name = "value"
- condition_instructions = next_instruction['instructions']
+ condition_instructions = next_instruction["instructions"]
condition_types_rs = []
for condition_instruction in condition_instructions:
- print('condition_instruction', condition_instruction)
- if 'type' not in condition_instruction:
+ print("condition_instruction", condition_instruction)
+ if "type" not in condition_instruction:
# weird type, maybe it's a loop or something
- condition_types_rs.append('todo!("weird type, maybe it\'s a loop or something")')
+ condition_types_rs.append(
+ 'todo!("weird type, maybe it\'s a loop or something")'
+ )
continue
- condition_type_rs, is_var, this_uses, this_extra_code = burger_type_to_rust_type(
- condition_instruction['type'], None, condition_instruction, mappings, obfuscated_class_name)
+ condition_type_rs, is_var, this_uses, this_extra_code = (
+ burger_type_to_rust_type(
+ condition_instruction["type"],
+ None,
+ condition_instruction,
+ mappings,
+ obfuscated_class_name,
+ )
+ )
condition_types_rs.append(condition_type_rs)
uses.update(this_uses)
extra_code.extend(this_extra_code)
- field_type_rs = f'Option<({", ".join(condition_types_rs)})>' if len(
- condition_types_rs) != 1 else f'Option<{condition_types_rs[0]}>'
+ field_type_rs = (
+ f"Option<({', '.join(condition_types_rs)})>"
+ if len(condition_types_rs) != 1
+ else f"Option<{condition_types_rs[0]}>"
+ )
skip = 1
else:
- field_type = instruction['type']
- obfuscated_field_name = instruction['field']
+ field_type = instruction["type"]
+ obfuscated_field_name = instruction["field"]
- if obfuscated_field_name.startswith('(float)'):
- obfuscated_field_name = obfuscated_field_name[len('(float)'):]
+ 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)
+ obfuscated_class_name, obfuscated_field_name
+ ) or mappings.get_field(
+ obfuscated_class_name.split("$")[0], obfuscated_field_name
+ )
- 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_rs, is_var, instruction_uses, instruction_extra_code = (
+ burger_type_to_rust_type(
+ field_type, field_name, instruction, mappings, obfuscated_class_name
+ )
+ )
if obfuscated_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
- elif '.' in obfuscated_field_name or ' ' in obfuscated_field_name or '(' in obfuscated_field_name:
+ 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, obfuscated_class_name, known_variable_types)
+ obfuscated_field_name,
+ mappings,
+ obfuscated_class_name,
+ known_variable_types,
+ )
if not field_type_rs2:
- generated_packet_code.append(f'// TODO: {instruction}')
+ generated_packet_code.append(f"// TODO: {instruction}")
return
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]
- print('got obfuscated_field_name', 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)
+ 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 = obfuscated_field_name.split("/")[-1]
uses.update(instruction_uses)
extra_code.extend(instruction_extra_code)
if not field_name:
- generated_packet_code.append(
- f'// TODO: unknown field {instruction}')
+ generated_packet_code.append(f"// TODO: unknown field {instruction}")
return skip
if is_var:
- generated_packet_code.append('#[var]')
- line = f'pub {to_snake_case(field_name)}: {field_type_rs or "todo!()"},'
+ generated_packet_code.append("#[var]")
+ line = f"pub {to_snake_case(field_name)}: {field_type_rs or 'todo!()'},"
if field_comment:
- line += f' // {field_comment}'
+ line += f" // {field_comment}"
generated_packet_code.append(line)
return skip
-def burger_field_to_type(field, mappings: Mappings, obfuscated_class_name: str, known_variable_types={}) -> tuple[Optional[str], str, Optional[str]]:
- '''
+def burger_field_to_type(
+ field, mappings: Mappings, obfuscated_class_name: str, known_variable_types={}
+) -> tuple[Optional[str], str, Optional[str]]:
+ """
Returns field_type_rs, obfuscated_field_name, field_comment
- '''
+ """
# match `(x) ? 1 : 0`
- match = re.match(r'\((.*)\) \? 1 : 0', field)
+ match = re.match(r"\((.*)\) \? 1 : 0", field)
if match:
- return ('bool', match.group(1), None)
- match = re.match(r'^\w+\.\w+\(\)$', field)
+ return ("bool", match.group(1), None)
+ match = re.match(r"^\w+\.\w+\(\)$", field)
if match:
- print('field', field)
- obfuscated_first = field.split('.')[0]
- obfuscated_second = field.split('.')[1].split('(')[0]
+ print("field", field)
+ obfuscated_first = field.split(".")[0]
+ obfuscated_second = 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:
- first_type = 'TODO'
- first_obfuscated_class_name: Optional[str] = mappings.get_class_from_deobfuscated_name(
- first_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:
+ 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'}:
+ first_type_short = first_type.split(".")[-1]
+ if second in {"byteValue"}:
return (first_type_short, obfuscated_first, None)
- return (first_type_short, obfuscated_first, f'TODO: Does {first_type_short}::{second}, may not be implemented')
+ return (
+ first_type_short,
+ obfuscated_first,
+ f"TODO: Does {first_type_short}::{second}, may not be implemented",
+ )
return None, field, None
def change_packet_ids(id_map: dict[int, int], direction: str, state: str):
- existing_packet_ids, existing_packet_class_names = get_packets(
- direction, state)
+ existing_packet_ids, existing_packet_class_names = get_packets(direction, state)
new_packet_ids = []
for packet_id in existing_packet_ids:
new_packet_id = id_map.get(packet_id, packet_id)
if new_packet_id in new_packet_ids:
- raise Exception('Two packets have the same id')
+ raise Exception("Two packets have the same id")
new_packet_ids.append(new_packet_id)
set_packets(new_packet_ids, existing_packet_class_names, direction, state)
def remove_packet_ids(removing_packet_ids: list[int], direction: str, state: str):
- existing_packet_ids, existing_packet_class_names = get_packets(
- direction, state)
+ existing_packet_ids, existing_packet_class_names = get_packets(direction, state)
new_packet_ids = []
new_packet_class_names = []
- for packet_id, packet_class_name in zip(existing_packet_ids, existing_packet_class_names):
+ for packet_id, packet_class_name in zip(
+ existing_packet_ids, existing_packet_class_names
+ ):
if packet_id in removing_packet_ids:
try:
os.remove(
- f'../azalea-protocol/src/packets/{state}/{packet_class_name}.rs')
- except:
+ f"../azalea-protocol/src/packets/{state}/{packet_class_name}.rs"
+ )
+ except Exception:
pass
else:
new_packet_ids.append(packet_id)
@@ -380,18 +476,22 @@ def are_packet_instructions_identical(old_packet, new_packet):
return False
for old_field, new_field in zip(old_packet, new_packet):
- if old_field['operation'] != new_field['operation']:
+ if old_field["operation"] != new_field["operation"]:
return False
- if new_field['operation'] == 'write':
- if burger_type_to_rust_type(old_field.get('type')) != burger_type_to_rust_type(new_field.get('type')):
+ if new_field["operation"] == "write":
+ if burger_type_to_rust_type(
+ old_field.get("type")
+ ) != burger_type_to_rust_type(new_field.get("type")):
return False
else:
# comparing is too complicated here since it's possible the type has variables
# so we just don't
pass
- if 'instructions' in old_field and 'instructions' in new_field:
- if not are_packet_instructions_identical(old_field['instructions'], new_field['instructions']):
+ if "instructions" in old_field and "instructions" in new_field:
+ if not are_packet_instructions_identical(
+ old_field["instructions"], new_field["instructions"]
+ ):
return False
return True
diff --git a/codegen/lib/code/registry.py b/codegen/lib/code/registry.py
index d1399da5..84d613ba 100644
--- a/codegen/lib/code/registry.py
+++ b/codegen/lib/code/registry.py
@@ -1,13 +1,11 @@
-from lib.utils import to_snake_case, upper_first_letter, get_dir_location, to_camel_case
-from ..mappings import Mappings
-from typing import Optional
-import re
+from lib.utils import get_dir_location, to_camel_case
+
+REGISTRIES_DIR = get_dir_location("../azalea-registry/src/lib.rs")
-REGISTRIES_DIR = get_dir_location('../azalea-registry/src/lib.rs')
def generate_registries(registries: dict):
- with open(REGISTRIES_DIR, 'r') as f:
- code = f.read().split('\n')
+ with open(REGISTRIES_DIR, "r") as f:
+ code = f.read().split("\n")
existing_registry_enum_names = set()
@@ -17,19 +15,20 @@ def generate_registries(registries: dict):
# Stone => "minecraft:stone"
# });
- registry_name = registry_name.split(':')[1]
+ registry_name = registry_name.split(":")[1]
registry_enum_name = registry_name_to_enum_name(registry_name)
existing_registry_enum_names.add(registry_enum_name)
registry_code = []
- registry_code.append(f'enum {registry_enum_name} {{')
+ registry_code.append(f"enum {registry_enum_name} {{")
registry_entries = sorted(
- registry['entries'].items(), key=lambda x: x[1]['protocol_id'])
+ registry["entries"].items(), key=lambda x: x[1]["protocol_id"]
+ )
for variant_name, _variant in registry_entries:
- variant_struct_name = to_camel_case(variant_name.split(':')[-1])
+ variant_struct_name = to_camel_case(variant_name.split(":")[-1])
registry_code.append(f'\t{variant_struct_name} => "{variant_name}",')
- registry_code.append('}')
+ registry_code.append("}")
# when we find a "registry! {" line, find the next line that starts
# with "enum <name>" and replace that until we find a line that's "}"
@@ -40,28 +39,28 @@ def generate_registries(registries: dict):
in_registry_macro = True
elif in_registry_macro and line == registry_code[0]:
# found it, now delete until we get to "}"
- while code[i] != '}':
+ while code[i] != "}":
code.pop(i)
- code[i] = '\n'.join(registry_code)
+ code[i] = "\n".join(registry_code)
found = True
break
if not found:
- code.append('registry! {')
- code.append('\n'.join(registry_code))
- code.append('}')
- code.append('')
+ code.append("registry! {")
+ code.append("\n".join(registry_code))
+ code.append("}")
+ code.append("")
# delete the unused registries
i = 0
while i < len(code):
- if code[i] == 'registry! {':
+ if code[i] == "registry! {":
# skip until we get to the enum line
- while not code[i].startswith('enum '):
+ while not code[i].startswith("enum "):
i += 1
- enum_name = code[i].split(' ')[1]
+ enum_name = code[i].split(" ")[1]
if enum_name not in existing_registry_enum_names:
i -= 1
- while code[i] != '}':
+ while code[i] != "}":
code.pop(i)
code.pop(i)
# close the registry! block
@@ -69,17 +68,18 @@ def generate_registries(registries: dict):
else:
i += 1
- with open(REGISTRIES_DIR, 'w') as f:
- f.write('\n'.join(code))
+ with open(REGISTRIES_DIR, "w") as f:
+ f.write("\n".join(code))
+
def registry_name_to_enum_name(registry_name: str) -> str:
- registry_name = registry_name.split(':')[-1]
+ registry_name = registry_name.split(":")[-1]
- if registry_name.endswith('_type'):
+ if registry_name.endswith("_type"):
# 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'}:
- registry_name += '_kind'
+ registry_name = registry_name[:-5] + "_kind"
+ elif registry_name in {"menu"}:
+ registry_name += "_kind"
return to_camel_case(registry_name)
diff --git a/codegen/lib/code/shapes.py b/codegen/lib/code/shapes.py
index 3a3e6d83..f3a5d513 100644
--- a/codegen/lib/code/shapes.py
+++ b/codegen/lib/code/shapes.py
@@ -1,46 +1,40 @@
-from lib.utils import get_dir_location, to_camel_case
-from ..mappings import Mappings
+from lib.utils import get_dir_location
-COLLISION_BLOCKS_RS_DIR = get_dir_location(
- '../azalea-physics/src/collision/blocks.rs')
+COLLISION_BLOCKS_RS_DIR = get_dir_location("../azalea-physics/src/collision/blocks.rs")
def generate_block_shapes(pumpkin_block_datas: dict, block_states_report):
blocks, shapes = simplify_shapes(pumpkin_block_datas)
code = generate_block_shapes_code(blocks, shapes, block_states_report)
- with open(COLLISION_BLOCKS_RS_DIR, 'w') as f:
+ with open(COLLISION_BLOCKS_RS_DIR, "w") as f:
f.write(code)
def simplify_shapes(blocks: dict) -> tuple[dict, dict]:
- '''
+ """
Returns new_blocks and new_shapes,
where new_blocks is like { grass_block: { collision: [1, 1], outline: [1, 1] } }
and new_shapes is like { 1: [ [0, 0, 0, 1, 1, 1] ] }
- '''
+ """
new_blocks = {}
new_shapes = {}
all_shapes_ids = {}
- for block_data in blocks['blocks']:
+ for block_data in blocks["blocks"]:
new_block_collision_shapes = []
new_block_outline_shapes = []
- for state in block_data['states']:
+ for state in block_data["states"]:
collision_shape = []
- for box_id in state['collision_shapes']:
- box = blocks['shapes'][box_id]
- collision_shape.append(
- tuple(box['min'] + box['max'])
- )
+ for box_id in state["collision_shapes"]:
+ box = blocks["shapes"][box_id]
+ collision_shape.append(tuple(box["min"] + box["max"]))
outline_shape = []
- for box_id in state['outline_shapes']:
- box = blocks['shapes'][box_id]
- outline_shape.append(
- tuple(box['min'] + box['max'])
- )
+ for box_id in state["outline_shapes"]:
+ box = blocks["shapes"][box_id]
+ outline_shape.append(tuple(box["min"] + box["max"]))
collision_shape = tuple(collision_shape)
outline_shape = tuple(outline_shape)
@@ -58,27 +52,25 @@ def simplify_shapes(blocks: dict) -> tuple[dict, dict]:
all_shapes_ids[outline_shape] = outline_shape_id
new_shapes[outline_shape_id] = outline_shape
- block_id = block_data['name']
+ block_id = block_data["name"]
new_block_collision_shapes.append(collision_shape_id)
new_block_outline_shapes.append(outline_shape_id)
new_blocks[block_id] = {
- 'collision': new_block_collision_shapes,
- 'outline': new_block_outline_shapes
+ "collision": new_block_collision_shapes,
+ "outline": new_block_outline_shapes,
}
-
return new_blocks, new_shapes
def generate_block_shapes_code(blocks: dict, shapes: dict, block_states_report):
# look at __cache__/generator-mod-*/blockCollisionShapes.json for format of blocks and shapes
- generated_shape_code = ''
- for (shape_id, shape) in sorted(shapes.items(), key=lambda shape: int(shape[0])):
+ generated_shape_code = ""
+ for shape_id, shape in sorted(shapes.items(), key=lambda shape: int(shape[0])):
generated_shape_code += generate_code_for_shape(shape_id, shape)
-
# static COLLISION_SHAPES_MAP: [&LazyLock<VoxelShape>; 26644] = [&SHAPE0, &SHAPE1, &SHAPE1, ...]
empty_shapes = []
full_shapes = []
@@ -88,48 +80,56 @@ def generate_block_shapes_code(blocks: dict, shapes: dict, block_states_report):
outline_shapes_map = []
for block_id, shape_datas in blocks.items():
- collision_shapes = shape_datas['collision']
- outline_shapes = shape_datas['outline']
-
- if isinstance(collision_shapes, int): collision_shapes = [collision_shapes]
- if isinstance(outline_shapes, int): outline_shapes = [outline_shapes]
-
- block_report_data = block_states_report['minecraft:' + block_id]
-
- for possible_state, shape_id in zip(block_report_data['states'], collision_shapes):
- block_state_id = possible_state['id']
- if shape_id == 0: empty_shapes.append(block_state_id)
- elif shape_id == 1: full_shapes.append(block_state_id)
+ collision_shapes = shape_datas["collision"]
+ outline_shapes = shape_datas["outline"]
+
+ if isinstance(collision_shapes, int):
+ collision_shapes = [collision_shapes]
+ if isinstance(outline_shapes, int):
+ outline_shapes = [outline_shapes]
+
+ block_report_data = block_states_report["minecraft:" + block_id]
+
+ for possible_state, shape_id in zip(
+ block_report_data["states"], collision_shapes
+ ):
+ block_state_id = possible_state["id"]
+ if shape_id == 0:
+ empty_shapes.append(block_state_id)
+ elif shape_id == 1:
+ full_shapes.append(block_state_id)
while len(collision_shapes_map) <= block_state_id:
# default to shape 1 for missing shapes (full block)
collision_shapes_map.append(1)
collision_shapes_map[block_state_id] = shape_id
- for possible_state, shape_id in zip(block_report_data['states'], outline_shapes):
- block_state_id = possible_state['id']
+ for possible_state, shape_id in zip(
+ block_report_data["states"], outline_shapes
+ ):
+ block_state_id = possible_state["id"]
while len(outline_shapes_map) <= block_state_id:
# default to shape 1 for missing shapes (full block)
outline_shapes_map.append(1)
outline_shapes_map[block_state_id] = shape_id
- generated_map_code = f'static COLLISION_SHAPES_MAP: [&LazyLock<VoxelShape>; {len(collision_shapes_map)}] = ['
+ generated_map_code = f"static COLLISION_SHAPES_MAP: [&LazyLock<VoxelShape>; {len(collision_shapes_map)}] = ["
empty_shape_match_code = convert_ints_to_rust_ranges(empty_shapes)
block_shape_match_code = convert_ints_to_rust_ranges(full_shapes)
for block_state_id, shape_id in enumerate(collision_shapes_map):
- generated_map_code += f'&SHAPE{shape_id},\n'
- generated_map_code += '];\n'
+ generated_map_code += f"&SHAPE{shape_id},\n"
+ generated_map_code += "];\n"
- generated_map_code += f'static OUTLINE_SHAPES_MAP: [&LazyLock<VoxelShape>; {len(outline_shapes_map)}] = ['
+ generated_map_code += f"static OUTLINE_SHAPES_MAP: [&LazyLock<VoxelShape>; {len(outline_shapes_map)}] = ["
for block_state_id, shape_id in enumerate(outline_shapes_map):
- generated_map_code += f'&SHAPE{shape_id},\n'
- generated_map_code += '];\n'
+ generated_map_code += f"&SHAPE{shape_id},\n"
+ generated_map_code += "];\n"
- if empty_shape_match_code == '':
- print('Error: shape 0 was not found')
+ if empty_shape_match_code == "":
+ print("Error: shape 0 was not found")
- return f'''
+ return f"""
//! Autogenerated block collisions for every block
-// This file is generated from codegen/lib/code/shapes.py. If you want to
+// This file is @generated from codegen/lib/code/shapes.py. If you want to
// modify it, change that file.
#![allow(clippy::explicit_auto_deref)]
@@ -172,36 +172,35 @@ impl BlockWithShape for BlockState {{
}}
{generated_map_code}
-'''
-
-
+"""
def generate_code_for_shape(shape_id: str, parts: list[list[float]]):
def make_arguments(part: list[float]):
- return ', '.join(map(lambda n: str(n).rstrip('0'), part))
- code = ''
- code += f'static SHAPE{shape_id}: LazyLock<VoxelShape> = LazyLock::new(|| {{'
+ return ", ".join(map(lambda n: str(n).rstrip("0"), part))
+
+ code = ""
+ code += f"static SHAPE{shape_id}: LazyLock<VoxelShape> = LazyLock::new(|| {{"
steps = []
if parts == ():
- steps.append('collision::EMPTY_SHAPE.clone()')
+ steps.append("collision::EMPTY_SHAPE.clone()")
else:
- steps.append(f'collision::box_shape({make_arguments(parts[0])})')
+ steps.append(f"collision::box_shape({make_arguments(parts[0])})")
for part in parts[1:]:
- steps.append(
- f'Shapes::or(s, collision::box_shape({make_arguments(part)}))')
+ steps.append(f"Shapes::or(s, collision::box_shape({make_arguments(part)}))")
if len(steps) == 1:
code += steps[0]
else:
- code += '{\n'
+ code += "{\n"
for step in steps[:-1]:
- code += f' let s = {step};\n'
- code += f' {steps[-1]}\n'
- code += '}\n'
- code += '});\n'
+ code += f" let s = {step};\n"
+ code += f" {steps[-1]}\n"
+ code += "}\n"
+ code += "});\n"
return code
+
def convert_ints_to_rust_ranges(block_state_ids: list[int]) -> str:
# convert them into ranges (so like 1|2|3 is 1..=3 instead)
block_state_ids_ranges = []
@@ -214,10 +213,18 @@ def convert_ints_to_rust_ranges(block_state_ids: list[int]) -> str:
if last_block_state_id is not None:
# check if the range is done
if block_state_id - 1 != last_block_state_id:
- block_state_ids_ranges.append(f'{range_start_block_state_id}..={last_block_state_id}' if range_start_block_state_id != last_block_state_id else str(range_start_block_state_id))
+ block_state_ids_ranges.append(
+ f"{range_start_block_state_id}..={last_block_state_id}"
+ if range_start_block_state_id != last_block_state_id
+ else str(range_start_block_state_id)
+ )
range_start_block_state_id = block_state_id
last_block_state_id = block_state_id
- block_state_ids_ranges.append(f'{range_start_block_state_id}..={last_block_state_id}' if range_start_block_state_id != last_block_state_id else str(range_start_block_state_id))
- return '|'.join(block_state_ids_ranges)
+ block_state_ids_ranges.append(
+ f"{range_start_block_state_id}..={last_block_state_id}"
+ if range_start_block_state_id != last_block_state_id
+ else str(range_start_block_state_id)
+ )
+ return "|".join(block_state_ids_ranges)
diff --git a/codegen/lib/code/tags.py b/codegen/lib/code/tags.py
index 6f6ec9a3..9bacc3d5 100644
--- a/codegen/lib/code/tags.py
+++ b/codegen/lib/code/tags.py
@@ -1,34 +1,36 @@
from lib.utils import to_snake_case, upper_first_letter, get_dir_location, to_camel_case
-REGISTRIES_DIR = get_dir_location('../azalea-registry/src/tags')
+REGISTRIES_DIR = get_dir_location("../azalea-registry/src/tags")
def generate_tags(registries: dict, file_name: str, struct_name: str):
- tags_dir = f'{REGISTRIES_DIR}/{file_name}.rs'
+ tags_dir = f"{REGISTRIES_DIR}/{file_name}.rs"
- generated = f'''// This file was generated by codegen/lib/code/tags.py, don't edit it manually!
+ generated = f"""// This file was @generated by codegen/lib/code/tags.py, don't edit it manually!
use std::{{collections::HashSet, sync::LazyLock}};
use crate::{struct_name};
-'''
+"""
for tag_name, tag in sorted(registries.items(), key=lambda x: x[0]):
- tag_name = tag_name.replace('/', '_')
+ tag_name = tag_name.replace("/", "_")
static_set_name = to_snake_case(tag_name).upper()
- generated += f'pub static {static_set_name}: LazyLock<HashSet<{struct_name}>> = LazyLock::new(|| HashSet::from_iter(vec!['
+ generated += f"pub static {static_set_name}: LazyLock<HashSet<{struct_name}>> = LazyLock::new(|| HashSet::from_iter(vec!["
- queue = tag['values'].copy()
+ queue = tag["values"].copy()
while queue != []:
item = queue.pop(0)
- namespace, item_name = item.split(':')
- if namespace[0] == '#':
- queue += registries[item_name]['values']
+ namespace, item_name = item.split(":")
+ if namespace[0] == "#":
+ queue += registries[item_name]["values"]
continue
- generated += f'{struct_name}::{upper_first_letter(to_camel_case(item_name))},\n'
- generated += ']));\n'
+ generated += (
+ f"{struct_name}::{upper_first_letter(to_camel_case(item_name))},\n"
+ )
+ generated += "]));\n"
- with open(tags_dir, 'w') as f:
- f.write(generated) \ No newline at end of file
+ with open(tags_dir, "w") as f:
+ f.write(generated)
diff --git a/codegen/lib/code/utils.py b/codegen/lib/code/utils.py
index 1a87b7f6..b8970628 100644
--- a/codegen/lib/code/utils.py
+++ b/codegen/lib/code/utils.py
@@ -1,175 +1,204 @@
+# 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
-# utilities specifically for codegen
-
-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):
+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,
+):
is_var = False
uses = set()
# extra code, like enum definitions
extra_code = []
should_be_signed = False
- if field_name and any(map(lambda w: w in {'x', 'y', 'z', 'xa', 'ya', 'za'}, to_snake_case(field_name).split('_'))):
+ if field_name and any(
+ map(
+ lambda w: w in {"x", "y", "z", "xa", "ya", "za"},
+ to_snake_case(field_name).split("_"),
+ )
+ ):
# coordinates are signed
should_be_signed = True
- if burger_type == 'byte':
- field_type_rs = 'i8' if should_be_signed else 'u8'
- elif burger_type == 'short':
- field_type_rs = 'i16' if should_be_signed else 'u16'
- elif burger_type == 'int':
- field_type_rs = 'i32' if should_be_signed else 'u32'
- elif burger_type == 'long':
- field_type_rs = 'i64' if should_be_signed else 'u64'
- elif burger_type == 'float':
- field_type_rs = 'f32'
- elif burger_type == 'double':
- field_type_rs = 'f64'
-
- elif burger_type == 'varint':
+ if burger_type == "byte":
+ field_type_rs = "i8" if should_be_signed else "u8"
+ elif burger_type == "short":
+ field_type_rs = "i16" if should_be_signed else "u16"
+ elif burger_type == "int":
+ field_type_rs = "i32" if should_be_signed else "u32"
+ elif burger_type == "long":
+ field_type_rs = "i64" if should_be_signed else "u64"
+ elif burger_type == "float":
+ field_type_rs = "f32"
+ elif burger_type == "double":
+ field_type_rs = "f64"
+
+ elif burger_type == "varint":
is_var = True
- field_type_rs = 'i32' if should_be_signed else 'u32'
- elif burger_type == 'varlong':
+ field_type_rs = "i32" if should_be_signed else "u32"
+ elif burger_type == "varlong":
is_var = True
- field_type_rs = 'i64' if should_be_signed else 'u64'
-
- elif burger_type == 'boolean':
- field_type_rs = 'bool'
- elif burger_type == 'string':
- field_type_rs = 'String'
-
- elif burger_type == 'chatcomponent':
- field_type_rs = 'FormattedText'
- uses.add('azalea_chat::FormattedText')
- elif burger_type == 'identifier':
- field_type_rs = 'ResourceLocation'
- uses.add('azalea_core::resource_location::ResourceLocation')
- elif burger_type == 'uuid':
- field_type_rs = 'Uuid'
- uses.add('uuid::Uuid')
- elif burger_type == 'position':
- field_type_rs = 'BlockPos'
- uses.add('azalea_core::position::BlockPos')
- elif burger_type == 'nbtcompound':
- field_type_rs = 'simdnbt::owned::NbtCompound'
- elif burger_type == 'itemstack':
- field_type_rs = 'Slot'
- uses.add('azalea_core::slot::Slot')
- elif burger_type == 'metadata':
- field_type_rs = 'EntityMetadata'
- uses.add('azalea_entity::EntityMetadata')
- elif burger_type == 'bitset':
+ field_type_rs = "i64" if should_be_signed else "u64"
+
+ elif burger_type == "boolean":
+ field_type_rs = "bool"
+ elif burger_type == "string":
+ field_type_rs = "String"
+
+ elif burger_type == "chatcomponent":
+ field_type_rs = "FormattedText"
+ uses.add("azalea_chat::FormattedText")
+ elif burger_type == "identifier":
+ field_type_rs = "ResourceLocation"
+ uses.add("azalea_core::resource_location::ResourceLocation")
+ elif burger_type == "uuid":
+ field_type_rs = "Uuid"
+ uses.add("uuid::Uuid")
+ elif burger_type == "position":
+ field_type_rs = "BlockPos"
+ uses.add("azalea_core::position::BlockPos")
+ elif burger_type == "nbtcompound":
+ field_type_rs = "simdnbt::owned::NbtCompound"
+ elif burger_type == "itemstack":
+ field_type_rs = "Slot"
+ uses.add("azalea_core::slot::Slot")
+ elif burger_type == "metadata":
+ field_type_rs = "EntityMetadata"
+ uses.add("azalea_entity::EntityMetadata")
+ elif burger_type == "bitset":
if instruction:
- length = instruction['length']
+ length = instruction["length"]
field_type_rs = f'todo!("fixed bitset of length {length}")'
else:
field_type_rs = 'todo!("fixed bitset")'
- elif burger_type == 'abstract':
- field_type_rs = 'todo!()'
- elif burger_type == 'interface':
+ elif burger_type == "abstract":
+ field_type_rs = "todo!()"
+ elif burger_type == "interface":
# depends on context
- field_type_rs = 'todo!()'
- elif burger_type == 'Iterator':
- field_type_rs = 'todo!()'
- elif burger_type == 'Object':
+ field_type_rs = "todo!()"
+ elif burger_type == "Iterator":
+ field_type_rs = "todo!()"
+ elif burger_type == "Object":
# depends on context
- field_type_rs = 'todo!()'
- elif burger_type == 'enum':
+ field_type_rs = "todo!()"
+ elif burger_type == "enum":
if not instruction or not mappings or not obfuscated_class_name:
field_type_rs = 'todo!("enum")'
else:
# generate the whole enum :)
print(instruction)
- enum_field = instruction['field']
+ enum_field = instruction["field"]
# enums with a.b() as the field
- if '.' in enum_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)
- print('enum field', enum_field.split('.')[1].split('(')[0])
+ 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
+ )
+ 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], '')
+ 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_first_part_obfuscated_name,
+ enum_field.split(".")[1].split("(")[0],
+ )
- print('hm', enum_name)
+ print("hm", enum_name)
else:
try:
enum_name = mappings.get_field_type(
- obfuscated_class_name, enum_field)
- except:
+ 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')
- print('enum_name', enum_name)
- enum_obfuscated_name = mappings.get_class_from_deobfuscated_name(
- enum_name)
- print('enum_obfuscated_name', enum_obfuscated_name)
+ print(
+ f"failed getting {obfuscated_class_name}.{enum_field} but continuing with {enum_name} anyways"
+ )
+ print("enum_name", enum_name)
+ enum_obfuscated_name = mappings.get_class_from_deobfuscated_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)
+ 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)
+ enum_obfuscated_name, obfuscated_field_name
+ )
if field_type != enum_name:
continue
enum_variants.append(field_name)
- field_type_rs = to_camel_case(
- enum_name.split('.')[-1].split('$')[-1])
- extra_code.append('')
- extra_code.append(f'#[derive(AzBuf, Clone, Copy, Debug)]')
- extra_code.append(f'pub enum {field_type_rs} {{')
+ field_type_rs = to_camel_case(enum_name.split(".")[-1].split("$")[-1])
+ extra_code.append("")
+ extra_code.append("#[derive(AzBuf, Clone, Copy, Debug)]")
+ extra_code.append(f"pub enum {field_type_rs} {{")
for index, variant in enumerate(enum_variants):
- extra_code.append(
- f' {to_camel_case(variant.lower())}={index},')
- extra_code.append('}')
+ extra_code.append(f" {to_camel_case(variant.lower())}={index},")
+ extra_code.append("}")
- elif burger_type.endswith('[]'):
+ elif burger_type.endswith("[]"):
field_type_rs, is_var, uses, extra_code = burger_type_to_rust_type(
- burger_type[:-2])
- field_type_rs = f'Vec<{field_type_rs}>'
+ burger_type[:-2]
+ )
+ field_type_rs = f"Vec<{field_type_rs}>"
# sometimes burger gives us a slightly incorrect type
if mappings and instruction:
- if field_type_rs == 'Vec<u8>':
- field = instruction['field']
- if field.endswith('.copy()'):
+ 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)
+ array_type = mappings.get_field_type(obfuscated_class_name, field)
except KeyError:
- print('Error getting array type', field)
+ print("Error getting array type", field)
return field_type_rs, is_var, uses, extra_code
- if array_type == 'net.minecraft.network.FriendlyByteBuf':
- field_type_rs = 'UnsizedByteArray'
- uses.add('azalea_buf::UnsizedByteArray')
+ 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})')
+ 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})"
+ )
return field_type_rs, is_var, uses, extra_code
def write_packet_file(state, packet_module_name, code):
- with open(get_dir_location(f'../azalea-protocol/src/packets/{state}/{packet_module_name}.rs'), 'w') as f:
+ with open(
+ get_dir_location(
+ f"../azalea-protocol/src/packets/{state}/{packet_module_name}.rs"
+ ),
+ "w",
+ ) as f:
f.write(code)
def fmt():
- os.system(f'cd {get_dir_location("..")} && cargo fmt')
+ os.system(f"cd {get_dir_location('..')} && cargo fmt")
diff --git a/codegen/lib/code/version.py b/codegen/lib/code/version.py
index d4a37232..478c12b2 100644
--- a/codegen/lib/code/version.py
+++ b/codegen/lib/code/version.py
@@ -2,12 +2,12 @@ from lib.utils import get_dir_location
import re
import os
-README_DIR = get_dir_location('../README.md')
-VERSION_REGEX = r'\_Currently supported Minecraft version: `(.*)`.\_'
+README_DIR = get_dir_location("../README.md")
+VERSION_REGEX = r"\_Currently supported Minecraft version: `(.*)`.\_"
def get_version_id() -> str:
- with open(README_DIR, 'rb') as f:
+ with open(README_DIR, "rb") as f:
readme_text = f.read().decode()
version_line_match = re.search(VERSION_REGEX, readme_text)
@@ -15,80 +15,85 @@ def get_version_id() -> str:
version_id = version_line_match.group(1)
return version_id
else:
- raise Exception('Could not find version id in README.md')
+ raise Exception("Could not find version id in README.md")
def set_version_id(version_id: str) -> None:
- with open(README_DIR, 'rb') as f:
+ with open(README_DIR, "rb") as f:
readme_text = f.read().decode()
version_line_match = re.search(VERSION_REGEX, readme_text)
if version_line_match:
- readme_text = readme_text.replace(
- version_line_match.group(1), version_id)
+ readme_text = readme_text.replace(version_line_match.group(1), version_id)
else:
- raise Exception('Could not find version id in README.md')
+ raise Exception("Could not find version id in README.md")
- with open(README_DIR, 'wb') as f:
+ with open(README_DIR, "wb") as f:
f.write(readme_text.encode())
-
+
# update the version in all Cargo.toml files
# version = "0.10.3+mc1.21.1"
- for root, _, files in os.walk(get_dir_location('..')):
+ for root, _, files in os.walk(get_dir_location("..")):
for file in files:
- if file == 'Cargo.toml':
- with open(os.path.join(root, file), 'r') as f:
+ if file == "Cargo.toml":
+ with open(os.path.join(root, file), "r") as f:
cargo_toml = f.read().splitlines()
for i, line in enumerate(cargo_toml):
- if line.strip().startswith('version = '):
+ if line.strip().startswith("version = "):
replaced = re.sub(r'\+mc[^"]+?"', f'+mc{version_id}"', line)
cargo_toml[i] = replaced
break
else:
# didn't have a version line
continue
- if cargo_toml[-1] != '':
+ if cargo_toml[-1] != "":
# make sure there's always a trailing newline
- cargo_toml.append('')
- with open(os.path.join(root, file), 'w') as f:
- f.write('\n'.join(cargo_toml))
- print('Updated version in README.md and Cargo.toml files')
+ cargo_toml.append("")
+ with open(os.path.join(root, file), "w") as f:
+ f.write("\n".join(cargo_toml))
+ print("Updated version in README.md and Cargo.toml files")
+
def get_protocol_version() -> str:
# azalea-protocol/src/packets/mod.rs
# pub const PROTOCOL_VERSION: i32 = 758;
- with open(get_dir_location('../azalea-protocol/src/packets/mod.rs'), 'r') as f:
+ with open(get_dir_location("../azalea-protocol/src/packets/mod.rs"), "r") as f:
mod_rs = f.read().splitlines()
for line in mod_rs:
- if line.strip().startswith('pub const PROTOCOL_VERSION'):
- return line.strip().split(' ')[-1].strip(';')
+ if line.strip().startswith("pub const PROTOCOL_VERSION"):
+ return line.strip().split(" ")[-1].strip(";")
raise Exception(
- 'Could not find protocol version in azalea-protocol/src/packets/mod.rs')
+ "Could not find protocol version in azalea-protocol/src/packets/mod.rs"
+ )
def set_protocol_version(protocol_version: str) -> None:
- with open(get_dir_location('../azalea-protocol/src/packets/mod.rs'), 'r') as f:
+ with open(get_dir_location("../azalea-protocol/src/packets/mod.rs"), "r") as f:
mod_rs = f.read().splitlines()
for i, line in enumerate(mod_rs):
- if line.strip().startswith('pub const PROTOCOL_VERSION:'):
- mod_rs[i] = f'pub const PROTOCOL_VERSION: i32 = {protocol_version};'
+ if line.strip().startswith("pub const PROTOCOL_VERSION:"):
+ mod_rs[i] = f"pub const PROTOCOL_VERSION: i32 = {protocol_version};"
break
else:
raise Exception(
- 'Could not find protocol version in azalea-protocol/src/packets/mod.rs')
+ "Could not find protocol version in azalea-protocol/src/packets/mod.rs"
+ )
+
+ with open(get_dir_location("../azalea-protocol/src/packets/mod.rs"), "w") as f:
+ f.write("\n".join(mod_rs))
+
- with open(get_dir_location('../azalea-protocol/src/packets/mod.rs'), 'w') as f:
- f.write('\n'.join(mod_rs))
def set_version_name(version_name: str) -> None:
- with open(get_dir_location('../azalea-protocol/src/packets/mod.rs'), 'r') as f:
+ with open(get_dir_location("../azalea-protocol/src/packets/mod.rs"), "r") as f:
mod_rs = f.read().splitlines()
for i, line in enumerate(mod_rs):
- if line.strip().startswith('pub const VERSION_NAME:'):
+ if line.strip().startswith("pub const VERSION_NAME:"):
mod_rs[i] = f'pub const VERSION_NAME: &str = "{version_name}";'
break
else:
raise Exception(
- 'Could not find version name in azalea-protocol/src/packets/mod.rs')
+ "Could not find version name in azalea-protocol/src/packets/mod.rs"
+ )
- with open(get_dir_location('../azalea-protocol/src/packets/mod.rs'), 'w') as f:
- f.write('\n'.join(mod_rs))
+ with open(get_dir_location("../azalea-protocol/src/packets/mod.rs"), "w") as f:
+ f.write("\n".join(mod_rs))
diff --git a/codegen/lib/download.py b/codegen/lib/download.py
index 43ca8d2a..238336e2 100644
--- a/codegen/lib/download.py
+++ b/codegen/lib/download.py
@@ -6,29 +6,33 @@ import json
import os
# make sure the cache directory exists
-print('Making __cache__')
-if not os.path.exists(get_dir_location('__cache__')):
- print('Made __cache__ directory.', get_dir_location('__cache__'))
- os.mkdir(get_dir_location('__cache__'))
+print("Making __cache__")
+if not os.path.exists(get_dir_location("__cache__")):
+ print("Made __cache__ directory.", get_dir_location("__cache__"))
+ os.mkdir(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__/Burger")):
+ print("\033[92mDownloading Burger...\033[m")
os.system(
- f'cd {get_dir_location("__cache__")} && git clone https://github.com/mat-1/Burger && cd Burger && git pull')
+ f"cd {get_dir_location('__cache__')} && git clone https://github.com/mat-1/Burger && cd Burger && git pull"
+ )
- 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')
+ 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"
+ )
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__/pumpkin-extractor")):
+ print("\033[92mDownloading Pumpkin-MC/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_PATCH = '''diff --git a/src/main/kotlin/de/snowii/extractor/extractors/Blocks.kt b/src/main/kotlin/de/snowii/extractor/extractors/Blocks.kt
+ f"cd {get_dir_location('__cache__')} && git clone https://github.com/Pumpkin-MC/Extractor pumpkin-extractor && cd pumpkin-extractor && git pull"
+ )
+
+ GIT_PATCH = """diff --git a/src/main/kotlin/de/snowii/extractor/extractors/Blocks.kt b/src/main/kotlin/de/snowii/extractor/extractors/Blocks.kt
index 936cd7b..9876a4b 100644
--- a/src/main/kotlin/de/snowii/extractor/extractors/Blocks.kt
+++ b/src/main/kotlin/de/snowii/extractor/extractors/Blocks.kt
@@ -51,166 +55,171 @@ index 936cd7b..9876a4b 100644
for (blockEntity in Registries.BLOCK_ENTITY_TYPE) {
if (blockEntity.supports(state)) {
-'''
+"""
os.system(
- f'cd {get_dir_location("__cache__")}/pumpkin-extractor && git apply - <<EOF\n{GIT_PATCH}\nEOF'
+ f"cd {get_dir_location('__cache__')}/pumpkin-extractor && git apply - <<EOF\n{GIT_PATCH}\nEOF"
)
-
- return get_dir_location('__cache__/pumpkin-extractor')
+
+ return get_dir_location("__cache__/pumpkin-extractor")
def get_version_manifest():
- if not os.path.exists(get_dir_location(f'__cache__/version_manifest.json')):
- print(
- f'\033[92mDownloading version manifest...\033[m')
+ if not os.path.exists(get_dir_location("__cache__/version_manifest.json")):
+ print("\033[92mDownloading version manifest...\033[m")
version_manifest_data = requests.get(
- 'https://piston-meta.mojang.com/mc/game/version_manifest_v2.json').json()
- with open(get_dir_location(f'__cache__/version_manifest.json'), 'w') as f:
+ "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json"
+ ).json()
+ with open(get_dir_location("__cache__/version_manifest.json"), "w") as f:
json.dump(version_manifest_data, f)
else:
- with open(get_dir_location(f'__cache__/version_manifest.json'), 'r') as f:
+ with open(get_dir_location("__cache__/version_manifest.json"), "r") as f:
version_manifest_data = json.load(f)
return version_manifest_data
def get_version_data(version_id: str):
- if not os.path.exists(get_dir_location(f'__cache__/{version_id}.json')):
+ if not os.path.exists(get_dir_location(f"__cache__/{version_id}.json")):
version_manifest_data = get_version_manifest()
- print(
- f'\033[92mGetting data for \033[1m{version_id}..\033[m')
+ print(f"\033[92mGetting data for \033[1m{version_id}..\033[m")
try:
package_url = next(
- filter(lambda v: v['id'] == version_id, version_manifest_data['versions']))['url']
+ filter(
+ lambda v: v["id"] == version_id, version_manifest_data["versions"]
+ )
+ )["url"]
except StopIteration:
raise ValueError(
- f'No version with id {version_id} found. Maybe delete __cache__/version_manifest.json and try again?')
+ f"No version with id {version_id} found. Maybe delete __cache__/version_manifest.json and try again?"
+ )
package_data = requests.get(package_url).json()
- with open(get_dir_location(f'__cache__/{version_id}.json'), 'w') as f:
+ with open(get_dir_location(f"__cache__/{version_id}.json"), "w") as f:
json.dump(package_data, f)
else:
- with open(get_dir_location(f'__cache__/{version_id}.json'), 'r') as f:
+ with open(get_dir_location(f"__cache__/{version_id}.json"), "r") as f:
package_data = json.load(f)
return package_data
def get_client_jar(version_id: str):
- if not os.path.exists(get_dir_location(f'__cache__/client-{version_id}.jar')):
+ if not os.path.exists(get_dir_location(f"__cache__/client-{version_id}.jar")):
package_data = get_version_data(version_id)
- print('\033[92mDownloading client jar...\033[m')
- client_jar_url = package_data['downloads']['client']['url']
- with open(get_dir_location(f'__cache__/client-{version_id}.jar'), 'wb') as f:
+ print("\033[92mDownloading client jar...\033[m")
+ client_jar_url = package_data["downloads"]["client"]["url"]
+ with open(get_dir_location(f"__cache__/client-{version_id}.jar"), "wb") as f:
f.write(requests.get(client_jar_url).content)
def get_server_jar(version_id: str):
- if not os.path.exists(get_dir_location(f'__cache__/server-{version_id}.jar')):
+ if not os.path.exists(get_dir_location(f"__cache__/server-{version_id}.jar")):
package_data = get_version_data(version_id)
- print('\033[92mDownloading server jar...\033[m')
- server_jar_url = package_data['downloads']['server']['url']
- with open(get_dir_location(f'__cache__/server-{version_id}.jar'), 'wb') as f:
+ print("\033[92mDownloading server jar...\033[m")
+ server_jar_url = package_data["downloads"]["server"]["url"]
+ with open(get_dir_location(f"__cache__/server-{version_id}.jar"), "wb") as f:
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')):
+ 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']
+ 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:
+ 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:
+ 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_yarn_versions():
# https://meta.fabricmc.net/v2/versions/yarn
- if not os.path.exists(get_dir_location('__cache__/yarn_versions.json')):
- print('\033[92mDownloading yarn versions...\033[m')
+ if not os.path.exists(get_dir_location("__cache__/yarn_versions.json")):
+ print("\033[92mDownloading yarn versions...\033[m")
yarn_versions_data = requests.get(
- 'https://meta.fabricmc.net/v2/versions/yarn').json()
- with open(get_dir_location('__cache__/yarn_versions.json'), 'w') as f:
+ "https://meta.fabricmc.net/v2/versions/yarn"
+ ).json()
+ with open(get_dir_location("__cache__/yarn_versions.json"), "w") as f:
json.dump(yarn_versions_data, f)
else:
- with open(get_dir_location('__cache__/yarn_versions.json'), 'r') as f:
+ with open(get_dir_location("__cache__/yarn_versions.json"), "r") as f:
yarn_versions_data = json.load(f)
return yarn_versions_data
def get_yarn_data(version_id: str):
for version in get_yarn_versions():
- if version['gameVersion'] == version_id:
+ if version["gameVersion"] == version_id:
return version
def get_fabric_api_versions():
# https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api/maven-metadata.xml
- if not os.path.exists(get_dir_location('__cache__/fabric_api_versions.json')):
- print('\033[92mDownloading Fabric API versions...\033[m')
+ if not os.path.exists(get_dir_location("__cache__/fabric_api_versions.json")):
+ print("\033[92mDownloading Fabric API versions...\033[m")
fabric_api_versions_xml_text = requests.get(
- 'https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api/maven-metadata.xml').text
+ "https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api/maven-metadata.xml"
+ ).text
# parse xml
- fabric_api_versions_data_xml = ET.fromstring(
- fabric_api_versions_xml_text)
+ fabric_api_versions_data_xml = ET.fromstring(fabric_api_versions_xml_text)
fabric_api_versions = []
- versioning_el = fabric_api_versions_data_xml.find('versioning')
+ versioning_el = fabric_api_versions_data_xml.find("versioning")
assert versioning_el
- versions_el = versioning_el.find('versions')
+ versions_el = versioning_el.find("versions")
assert versions_el
- for version_el in versions_el.findall('version'):
+ for version_el in versions_el.findall("version"):
fabric_api_versions.append(version_el.text)
- with open(get_dir_location('__cache__/fabric_api_versions.json'), 'w') as f:
+ with open(get_dir_location("__cache__/fabric_api_versions.json"), "w") as f:
f.write(json.dumps(fabric_api_versions))
else:
- with open(get_dir_location('__cache__/fabric_api_versions.json'), 'r') as f:
+ with open(get_dir_location("__cache__/fabric_api_versions.json"), "r") as f:
fabric_api_versions = json.loads(f.read())
return fabric_api_versions
def get_fabric_loader_versions():
# https://meta.fabricmc.net/v2/versions/loader
- if not os.path.exists(get_dir_location('__cache__/fabric_loader_versions.json')):
- print('\033[92mDownloading Fabric loader versions...\033[m')
+ if not os.path.exists(get_dir_location("__cache__/fabric_loader_versions.json")):
+ print("\033[92mDownloading Fabric loader versions...\033[m")
fabric_api_versions_json = requests.get(
- 'https://meta.fabricmc.net/v2/versions/loader').json()
+ "https://meta.fabricmc.net/v2/versions/loader"
+ ).json()
fabric_api_versions = []
for version in fabric_api_versions_json:
- fabric_api_versions.append(version['version'])
+ fabric_api_versions.append(version["version"])
- with open(get_dir_location('__cache__/fabric_loader_versions.json'), 'w') as f:
+ with open(get_dir_location("__cache__/fabric_loader_versions.json"), "w") as f:
f.write(json.dumps(fabric_api_versions))
else:
- with open(get_dir_location('__cache__/fabric_loader_versions.json'), 'r') as f:
+ with open(get_dir_location("__cache__/fabric_loader_versions.json"), "r") as f:
fabric_api_versions = json.loads(f.read())
return fabric_api_versions
def clear_version_cache():
- print('\033[92mClearing version cache...\033[m')
+ print("\033[92mClearing version cache...\033[m")
files = [
- 'version_manifest.json',
- 'yarn_versions.json',
- 'fabric_api_versions.json',
- 'fabric_loader_versions.json'
+ "version_manifest.json",
+ "yarn_versions.json",
+ "fabric_api_versions.json",
+ "fabric_loader_versions.json",
]
for file in files:
- if os.path.exists(get_dir_location(f'__cache__/{file}')):
- os.remove(get_dir_location(f'__cache__/{file}'))
+ 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")
if os.path.exists(burger_path):
- os.system(
- f'cd {burger_path} && git pull')
- pumpkin_path = get_dir_location('__cache__/pumpkin-extractor')
+ os.system(f"cd {burger_path} && git pull")
+ pumpkin_path = get_dir_location("__cache__/pumpkin-extractor")
if os.path.exists(pumpkin_path):
os.system(
- f'cd {pumpkin_path} && git add . && git stash && git pull && git stash pop') \ No newline at end of file
+ f"cd {pumpkin_path} && git add . && git stash && git pull && git stash pop"
+ )
diff --git a/codegen/lib/extract.py b/codegen/lib/extract.py
index e8fc5b4d..97f37ccf 100644
--- a/codegen/lib/extract.py
+++ b/codegen/lib/extract.py
@@ -1,81 +1,92 @@
# Extracting data from the Minecraft jars
-from typing import TYPE_CHECKING
-from lib.download import get_mappings_for_version, get_pumpkin_extractor, get_server_jar, get_burger, get_client_jar
+from lib.download import (
+ get_mappings_for_version,
+ get_pumpkin_extractor,
+ get_server_jar,
+ get_burger,
+ get_client_jar,
+)
from lib.utils import get_dir_location, to_camel_case, upper_first_letter
from zipfile import ZipFile
import subprocess
-import requests
import json
-import sys
import re
import os
def generate_data_from_server_jar(version_id: str):
- if os.path.exists(get_dir_location(f'__cache__/generated-{version_id}')):
+ if os.path.exists(get_dir_location(f"__cache__/generated-{version_id}")):
return
get_server_jar(version_id)
os.system(
- f'cd {get_dir_location(f"__cache__")} && java -DbundlerMainClass=net.minecraft.data.Main -jar {get_dir_location(f"__cache__/server-{version_id}.jar")} --all --output \"{get_dir_location(f"__cache__/generated-{version_id}")}\"'
+ f'cd {get_dir_location("__cache__")} && java -DbundlerMainClass=net.minecraft.data.Main -jar {get_dir_location(f"__cache__/server-{version_id}.jar")} --all --output "{get_dir_location(f"__cache__/generated-{version_id}")}"'
)
def get_block_states_report(version_id: str):
- return get_report(version_id, 'blocks')
+ return get_report(version_id, "blocks")
+
+
def get_registries_report(version_id: str):
- return get_report(version_id, 'registries')
+ return get_report(version_id, "registries")
+
+
def get_packets_report(version_id: str):
- return get_report(version_id, 'packets')
+ return get_report(version_id, "packets")
+
+
def get_report(version_id: str, name: str):
generate_data_from_server_jar(version_id)
- with open(get_dir_location(f'__cache__/generated-{version_id}/reports/{name}.json'), 'r') as f:
+ with open(
+ get_dir_location(f"__cache__/generated-{version_id}/reports/{name}.json"), "r"
+ ) as f:
return json.load(f)
+
def get_registry_tags(version_id: str, name: str):
generate_data_from_server_jar(version_id)
- tags_directory = get_dir_location(f'__cache__/generated-{version_id}/data/minecraft/tags/{name}')
+ tags_directory = get_dir_location(
+ f"__cache__/generated-{version_id}/data/minecraft/tags/{name}"
+ )
if not os.path.exists(tags_directory):
return {}
tags = {}
for root, dirs, files in os.walk(tags_directory, topdown=False):
for name in files:
file = os.path.join(root, name)
- relative_path = file.replace(tags_directory, '')[1:]
- if not file.endswith('.json'):
+ relative_path = file.replace(tags_directory, "")[1:]
+ if not file.endswith(".json"):
continue
- with open(file, 'r') as f:
+ with open(file, "r") as f:
tags[relative_path[:-5]] = json.load(f)
return tags
+
python_command = None
def determine_python_command():
- return 'venv/bin/python'
-
+ return "venv/bin/python"
def run_python_command_and_download_deps(command):
- print('>', command)
+ print(">", command)
for _ in range(10):
- p = subprocess.Popen(
- command,
- stderr=subprocess.PIPE,
- shell=True
- )
+ p = subprocess.Popen(command, stderr=subprocess.PIPE, shell=True)
- stderr = b''
+ stderr = b""
while True:
data = p.stderr.read()
- if data == b'':
+ if data == b"":
break
- print(data.decode(), end='', flush=True)
+ print(data.decode(), end="", flush=True)
stderr += data
regex_match = re.search(
- r'ModuleNotFoundError: No module named \'(\w+?)\'', stderr.decode())
+ r"ModuleNotFoundError: No module named \'(\w+?)\'", stderr.decode()
+ )
if not regex_match:
out, err = p.communicate()
if out:
@@ -84,58 +95,61 @@ def run_python_command_and_download_deps(command):
print(err)
break
missing_lib = regex_match.group(1)
- print('Missing required lib:', missing_lib)
- subprocess.run(f'venv/bin/pip install {missing_lib}', cwd=os.path.dirname(os.path.dirname(__file__)))
- print('ok')
+ print("Missing required lib:", missing_lib)
+ subprocess.run(
+ f"venv/bin/pip install {missing_lib}",
+ cwd=os.path.dirname(os.path.dirname(__file__)),
+ )
+ print("ok")
def get_burger_data_for_version(version_id: str):
- if not os.path.exists(get_dir_location(f'__cache__/burger-{version_id}.json')):
+ 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 Burger...\033[m")
run_python_command_and_download_deps(
- f'cd {get_dir_location("__cache__/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'
+ f"cd {get_dir_location('__cache__/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:
+ with open(get_dir_location(f"__cache__/burger-{version_id}.json"), "r") as f:
return json.load(f)
def get_pumpkin_data(version_id: str, category: str):
- assert '/' not in version_id
- assert '\\' not in version_id
- target_parent_dir = get_dir_location(f'__cache__/pumpkin-{version_id}')
- category_dir = f'{target_parent_dir}/{category}.json'
+ assert "/" not in version_id
+ assert "\\" not in version_id
+ target_parent_dir = get_dir_location(f"__cache__/pumpkin-{version_id}")
+ category_dir = f"{target_parent_dir}/{category}.json"
if os.path.exists(category_dir):
- with open(category_dir, 'r') as f:
+ with open(category_dir, "r") as f:
return json.load(f)
pumpkin_dir = get_pumpkin_extractor()
- os.makedirs(f'{pumpkin_dir}/run', exist_ok=True)
- with open(f'{pumpkin_dir}/run/eula.txt', 'w') as f:
- f.write('eula=true')
+ os.makedirs(f"{pumpkin_dir}/run", exist_ok=True)
+ with open(f"{pumpkin_dir}/run/eula.txt", "w") as f:
+ f.write("eula=true")
# run ./gradlew runServer until it logs "(pumpkin_extractor) Done"
p = subprocess.Popen(
- f'cd {pumpkin_dir} && ./gradlew runServer',
+ f"cd {pumpkin_dir} && ./gradlew runServer",
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
- shell=True
+ shell=True,
)
while True:
data = p.stdout.readline().decode()
- print('>' + data, end='', flush=True)
- if '[Server thread/INFO] (pumpkin_extractor) Done' in data:
- print('Pumpkin extractor done')
+ print(">" + data, end="", flush=True)
+ if "[Server thread/INFO] (pumpkin_extractor) Done" in data:
+ print("Pumpkin extractor done")
break
- if data == b'':
+ if data == b"":
break
p.terminate()
@@ -144,44 +158,49 @@ def get_pumpkin_data(version_id: str, category: str):
# delete target_parent_dir if it's empty
if os.path.exists(target_parent_dir):
os.rmdir(target_parent_dir)
- os.rename(f'{pumpkin_dir}/run/pumpkin_extractor_output', target_parent_dir)
+ os.rename(f"{pumpkin_dir}/run/pumpkin_extractor_output", target_parent_dir)
- with open(category_dir, 'r') as f:
+ with open(category_dir, "r") as f:
return json.load(f)
def get_file_from_jar(version_id: str, file_dir: str):
get_client_jar(version_id)
- with ZipFile(get_dir_location(f'__cache__/client-{version_id}.jar')) as z:
+ with ZipFile(get_dir_location(f"__cache__/client-{version_id}.jar")) as z:
with z.open(file_dir) as f:
return f.read()
def get_en_us_lang(version_id: str):
- return json.loads(
- get_file_from_jar(version_id, 'assets/minecraft/lang/en_us.json')
- )
+ 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.
-if TYPE_CHECKING: from codegen.lib.mappings import Mappings
+
def get_packet_list(version_id: str):
- if version_id != '1.21':
+ 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:
+ 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_resourcelocation, packet_value in direction_value.items():
- assert packet_resourcelocation.startswith('minecraft:')
- packet_resourcelocation = upper_first_letter(to_camel_case(packet_resourcelocation[len('minecraft:'):]))
- packet_list.append({
- 'state': state,
- 'direction': direction,
- 'name': packet_resourcelocation,
- 'id': packet_value['protocol_id']
- })
+ assert packet_resourcelocation.startswith("minecraft:")
+ packet_resourcelocation = upper_first_letter(
+ to_camel_case(packet_resourcelocation[len("minecraft:") :])
+ )
+ packet_list.append(
+ {
+ "state": state,
+ "direction": direction,
+ "name": packet_resourcelocation,
+ "id": packet_value["protocol_id"],
+ }
+ )