aboutsummaryrefslogtreecommitdiff
path: root/codegen/lib/code
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2023-03-14 16:33:03 -0500
committerGitHub <noreply@github.com>2023-03-14 16:33:03 -0500
commit12a9c8ce65b58f0c600fd7b9fc5d454ce228b420 (patch)
tree9bada4164ea12fa533d413c0c7090f4779b519f1 /codegen/lib/code
parentb792e21d1c2b7dba04d88dba479ed451104a6514 (diff)
downloadazalea-drasl-12a9c8ce65b58f0c600fd7b9fc5d454ce228b420.tar.xz
1.19.4 (#57)
* 23w03a * 23w04a * 23w05a * 23w06a * fix * 23w07a mojang broke their json data generator so some stuff is missing * didn't mean to commit that file here * 1.19.4-pre2 * fix * 1.19.4-pre3 * fix * how did these packets get here * 1.19.4-pre4 * 1.19.4-rc1 * 1.19.4-rc2 * 1.19.4-rc3 * merge main * remove debugging code * 1.19.4
Diffstat (limited to 'codegen/lib/code')
-rw-r--r--codegen/lib/code/entity.py178
-rwxr-xr-xcodegen/lib/code/packet.py53
-rwxr-xr-xcodegen/lib/code/utils.py8
3 files changed, 171 insertions, 68 deletions
diff --git a/codegen/lib/code/entity.py b/codegen/lib/code/entity.py
index e3e88edf..23a94c52 100644
--- a/codegen/lib/code/entity.py
+++ b/codegen/lib/code/entity.py
@@ -1,4 +1,6 @@
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
@@ -6,35 +8,91 @@ import re
METADATA_RS_DIR = get_dir_location(
'../azalea-world/src/entity/metadata.rs')
-
-def generate_entity_metadata(burger_entity_data: dict, mappings: Mappings):
- # TODO: auto generate this and use it for generating the EntityDataValue enum
- metadata_types = [
- {'name': 'Byte', 'type': 'u8'},
- {'name': 'Int', 'type': 'i32', 'var': True},
- {'name': 'Long', 'type': 'i64'},
- {'name': 'Float', 'type': 'f32'},
- {'name': 'String', 'type': 'String'},
- {'name': 'FormattedText', 'type': 'FormattedText'},
- {'name': 'OptionalFormattedText', 'type': 'Option<FormattedText>'},
- {'name': 'ItemStack', 'type': 'Slot'},
- {'name': 'Boolean', 'type': 'bool'},
- {'name': 'Rotations', 'type': 'Rotations'},
- {'name': 'BlockPos', 'type': 'BlockPos'},
- {'name': 'OptionalBlockPos', 'type': 'Option<BlockPos>'},
- {'name': 'Direction', 'type': 'Direction'},
- {'name': 'OptionalUuid', 'type': 'Option<Uuid>'},
- {'name': 'BlockState', 'type': 'BlockState'},
- {'name': 'CompoundTag', 'type': 'azalea_nbt::Tag'},
- {'name': 'Particle', 'type': 'Particle'},
- {'name': 'VillagerData', 'type': 'VillagerData'},
- {'name': 'OptionalUnsignedInt', 'type': 'OptionalUnsignedInt'},
- {'name': 'Pose', 'type': 'Pose'},
- {'name': 'CatVariant', 'type': 'azalea_registry::CatVariant'},
- {'name': 'FrogVariant', 'type': 'azalea_registry::FrogVariant'},
- {'name': 'GlobalPos', 'type': 'GlobalPos'},
- {'name': 'PaintingVariant', 'type': 'azalea_registry::PaintingVariant'}
- ]
+DATA_RS_DIR = get_dir_location(
+ '../azalea-world/src/entity/data.rs')
+
+def generate_metadata_names(burger_dataserializers: dict, mappings: Mappings):
+ serializer_names = [None] * len(burger_dataserializers)
+ for burger_serializer in burger_dataserializers.values():
+ 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))
+ return serializer_names
+
+def parse_metadata_types_from_code():
+ 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 {':
+ in_enum = True
+ elif line == '}':
+ in_enum = False
+ elif in_enum:
+ line = line.strip()
+ if line.startswith('//'): continue
+ name, type = line.rstrip('),').split('(')
+ is_var = False
+ if type.startswith('#[var] '):
+ is_var = True
+ 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']
+
+ 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'])
+
+ 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
+ # making it correct while preserving comments was too annoying so i didn't
+ added_metadata_names = []
+ for n in new_metadata_names:
+ if n not in parsed_metadata_names:
+ added_metadata_names.append(n)
+ if added_metadata_names != []:
+ in_enum = False
+ for i, line in enumerate(list(lines)):
+ if line == 'pub enum EntityDataValue {':
+ in_enum = True
+ elif in_enum and line == '}':
+ in_enum = False
+ for n in added_metadata_names:
+ 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-world/src/entity/data.rs, go make sure they\'re correct and then press enter')
+ input()
+
+ metadata_types = parse_metadata_types_from_code()
code = []
code.append('''#![allow(clippy::single_match)]
@@ -42,10 +100,12 @@ def generate_entity_metadata(burger_entity_data: dict, mappings: Mappings):
// This file is generated from codegen/lib/code/entity.py.
// Don't change it manually!
-use super::{EntityDataItem, EntityDataValue, OptionalUnsignedInt, Pose, Rotations, VillagerData};
-use azalea_block::BlockState;
+use super::{
+ EntityDataItem, EntityDataValue, OptionalUnsignedInt, Pose, Quaternion, Rotations,
+ SnifferState, VillagerData
+};
use azalea_chat::FormattedText;
-use azalea_core::{BlockPos, Direction, Particle, Slot};
+use azalea_core::{BlockPos, Direction, Particle, Slot, Vec3};
use bevy_ecs::{bundle::Bundle, component::Component};
use derive_more::{Deref, DerefMut};
use thiserror::Error;
@@ -74,9 +134,9 @@ impl From<EntityDataValue> for UpdateMetadataError {
# build the duplicate_field_names set
previous_field_names = set()
duplicate_field_names = set()
- for entity_id in burger_entity_data.keys():
+ 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_data, 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)
@@ -99,8 +159,8 @@ impl From<EntityDataValue> for UpdateMetadataError {
raise Exception(f'{name} should only exist once')
# and now figure out what to rename them to
- for entity_id in burger_entity_data.keys():
- for index, field_name_or_bitfield in get_entity_metadata_names(entity_id, burger_entity_data, mappings).items():
+ 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():
if isinstance(field_name_or_bitfield, str):
new_field_name = field_name_or_bitfield
if new_field_name == 'type':
@@ -129,14 +189,14 @@ impl From<EntityDataValue> for UpdateMetadataError {
return field_name_map[entity_ids_for_all_field_names_or_bitfields[index]][name]
return name
- parents = get_entity_parents(entity_id, burger_entity_data)
+ 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_data, 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_data))
+ parent_id, burger_entity_metadata))
parent_id = parents[1] if len(parents) > 1 else None
# now add all the fields/component structs
@@ -264,7 +324,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
if parent_struct_name:
code.append(
f' parent: {parent_struct_name}MetadataBundle,')
- for index, name_or_bitfield in get_entity_metadata_names(entity_id, burger_entity_data, mappings).items():
+ 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)
@@ -310,7 +370,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
# if it has a parent, put it (do recursion)
# parent: AbstractCreatureBundle { ... },
this_entity_parent_ids = get_entity_parents(
- this_entity_id, burger_entity_data)
+ 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:
@@ -322,7 +382,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
code.append(
' },')
- for index, name_or_bitfield in get_entity_metadata_names(this_entity_id, burger_entity_data, mappings).items():
+ 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):
@@ -367,11 +427,21 @@ impl From<EntityDataValue> for UpdateMetadataError {
elif type_name == 'ItemStack':
default = f'Slot::Present({default})' if default != 'Empty' else 'Slot::Empty'
elif type_name == 'BlockState':
- default = f'{default}' if default != 'Empty' else 'BlockState::AIR'
+ 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'azalea_nbt::Tag::Compound({default})' if default != 'Empty' else 'azalea_nbt::Tag::Compound(Default::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},')
else:
@@ -395,7 +465,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
code.append('')
# parent_field_name = None
- for entity_id in burger_entity_data:
+ for entity_id in burger_entity_metadata:
new_entity(entity_id)
# and now make the main apply_metadata
@@ -419,7 +489,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
items: Vec<EntityDataItem>,
) -> Result<(), UpdateMetadataError> {{
match entity_kind {{''')
- for entity_id in burger_entity_data:
+ for entity_id in burger_entity_metadata:
if entity_id.startswith('~'):
# not actually an entity
continue
@@ -446,7 +516,7 @@ 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 {')
- for entity_id in burger_entity_data:
+ for entity_id in burger_entity_metadata:
if entity_id.startswith('~'):
# not actually an entity
continue
@@ -464,22 +534,22 @@ impl From<EntityDataValue> for UpdateMetadataError {
f.write('\n'.join(code))
-def get_entity_parents(entity_id: str, burger_entity_data: dict):
+def get_entity_parents(entity_id: str, burger_entity_metadata: dict):
parents = []
while entity_id:
parents.append(entity_id)
- entity_id = get_entity_parent(entity_id, burger_entity_data)
+ entity_id = get_entity_parent(entity_id, burger_entity_metadata)
return parents
-def get_entity_parent(entity_id: str, burger_entity_data: dict):
- entity_metadata = burger_entity_data[entity_id]['metadata']
+def get_entity_parent(entity_id: str, burger_entity_metadata: dict):
+ entity_metadata = burger_entity_metadata[entity_id]['metadata']
first_metadata = entity_metadata[0]
return first_metadata.get('entity')
-def get_entity_metadata(entity_id: str, burger_entity_data: dict):
- entity_metadata = burger_entity_data[entity_id]['metadata']
+def get_entity_metadata(entity_id: str, burger_entity_metadata: dict):
+ entity_metadata = burger_entity_metadata[entity_id]['metadata']
entity_useful_metadata = []
for metadata_item in entity_metadata:
if 'data' in metadata_item:
@@ -494,8 +564,8 @@ def get_entity_metadata(entity_id: str, burger_entity_data: dict):
# returns a dict of {index: (name or bitfield)}
-def get_entity_metadata_names(entity_id: str, burger_entity_data: dict, mappings: Mappings):
- entity_metadata = burger_entity_data[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:
diff --git a/codegen/lib/code/packet.py b/codegen/lib/code/packet.py
index 48572aed..58e50136 100755
--- a/codegen/lib/code/packet.py
+++ b/codegen/lib/code/packet.py
@@ -222,7 +222,7 @@ def get_packets(direction: str, state: str):
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]) -> 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).
'''
@@ -237,12 +237,14 @@ def burger_instruction_to_code(instructions: list[dict], index: int, generated_p
field_type_rs = None
field_comment = None
+ print('instruction', 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':
- field_obfuscated_name = instruction['field'].split('.')[
+ obfuscated_field_name = instruction['field'].split('.')[
0]
field_name = mappings.get_field(
- obfuscated_class_name, field_obfuscated_name)
+ obfuscated_class_name, obfuscated_field_name)
# figure out what kind of iterator it is
loop_instructions = next_next_instruction['instructions']
@@ -282,10 +284,21 @@ def burger_instruction_to_code(instructions: list[dict], index: int, generated_p
# 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')):
- field_obfuscated_name = instruction['field'].split('.')[
+ 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, field_obfuscated_name)
+ 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_types_rs = []
@@ -312,23 +325,34 @@ def burger_instruction_to_code(instructions: list[dict], index: int, generated_p
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 '.' in obfuscated_field_name or ' ' in obfuscated_field_name or '(' in obfuscated_field_name:
+ if obfuscated_field_name in known_variable_types:
+ # just use the known name since it's not gonna be in the mappings
+ field_name = 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)
+ obfuscated_field_name, mappings, obfuscated_class_name, known_variable_types)
if not field_type_rs2:
generated_packet_code.append(f'// TODO: {instruction}')
return
+ if obfuscated_field_name in known_variable_types:
+ # just use the known name since it's not gonna be in the mappings
+ obfuscated_field_name = known_variable_types[obfuscated_field_name]
+ print('got obfuscated_field_name', obfuscated_field_name)
+
# try to get the field name again with the new stuff we know
field_name = mappings.get_field(
obfuscated_class_name, obfuscated_field_name) or mappings.get_field(
obfuscated_class_name.split('$')[0], obfuscated_field_name)
+ if field_name is None:
+ field_name = obfuscated_field_name.split('/')[-1]
uses.update(instruction_uses)
extra_code.extend(instruction_extra_code)
if not field_name:
generated_packet_code.append(
f'// TODO: unknown field {instruction}')
- return
+ return skip
if is_var:
generated_packet_code.append('#[var]')
@@ -340,7 +364,7 @@ def burger_instruction_to_code(instructions: list[dict], index: int, generated_p
return skip
-def burger_field_to_type(field, mappings: Mappings, obfuscated_class_name: str) -> 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
'''
@@ -353,9 +377,12 @@ def burger_field_to_type(field, mappings: Mappings, obfuscated_class_name: str)
print('field', field)
obfuscated_first = field.split('.')[0]
obfuscated_second = field.split('.')[1].split('(')[0]
- first = mappings.get_field(obfuscated_class_name, obfuscated_first)
- first_type = mappings.get_field_type(
- obfuscated_class_name, obfuscated_first)
+ # first = mappings.get_field(obfuscated_class_name, obfuscated_first)
+ if obfuscated_first in known_variable_types:
+ first_type = known_variable_types[obfuscated_first]
+ else:
+ first_type = mappings.get_field_type(
+ obfuscated_class_name, obfuscated_first)
first_obfuscated_class_name: Optional[str] = mappings.get_class_from_deobfuscated_name(
first_type)
if first_obfuscated_class_name:
@@ -368,6 +395,8 @@ def burger_field_to_type(field, mappings: Mappings, obfuscated_class_name: str)
else:
second = obfuscated_second
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 None, field, None
diff --git a/codegen/lib/code/utils.py b/codegen/lib/code/utils.py
index fe4aca7f..aaa166ff 100755
--- a/codegen/lib/code/utils.py
+++ b/codegen/lib/code/utils.py
@@ -97,8 +97,12 @@ def burger_type_to_rust_type(burger_type, field_name: Optional[str] = None, inst
print('hm', enum_name)
else:
- enum_name = mappings.get_field_type(
- obfuscated_class_name, enum_field)
+ try:
+ enum_name = mappings.get_field_type(
+ obfuscated_class_name, enum_field)
+ except:
+ 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)