diff options
Diffstat (limited to 'codegen/lib/code')
| -rw-r--r-- | codegen/lib/code/entity.py | 649 | ||||
| -rwxr-xr-x | codegen/lib/code/registry.py | 7 | ||||
| -rwxr-xr-x | codegen/lib/code/utils.py | 4 |
3 files changed, 391 insertions, 269 deletions
diff --git a/codegen/lib/code/entity.py b/codegen/lib/code/entity.py index 6616c8d7..844793f6 100644 --- a/codegen/lib/code/entity.py +++ b/codegen/lib/code/entity.py @@ -15,8 +15,8 @@ def generate_entity_metadata(burger_entity_data: dict, mappings: Mappings): {'name': 'Long', 'type': 'i64'}, {'name': 'Float', 'type': 'f32'}, {'name': 'String', 'type': 'String'}, - {'name': 'Component', 'type': 'Component'}, - {'name': 'OptionalComponent', 'type': 'Option<Component>'}, + {'name': 'FormattedText', 'type': 'FormattedText'}, + {'name': 'OptionalFormattedText', 'type': 'Option<FormattedText>'}, {'name': 'ItemStack', 'type': 'Slot'}, {'name': 'Boolean', 'type': 'bool'}, {'name': 'Rotations', 'type': 'Rotations'}, @@ -37,313 +37,426 @@ def generate_entity_metadata(burger_entity_data: dict, mappings: Mappings): ] code = [] - code.append('// This file is generated from codegen/lib/code/entity.py.') - code.append("// Don't change it manually!") - code.append('') - code.append('#![allow(clippy::clone_on_copy, clippy::derivable_impls)]') - code.append( - 'use super::{EntityDataValue, Rotations, VillagerData, OptionalUnsignedInt, Pose};') - code.append('use azalea_block::BlockState;') - code.append('use azalea_chat::Component;') - code.append('use azalea_core::{BlockPos, Direction, Particle, Slot};') - code.append('use std::{collections::VecDeque, ops::{Deref, DerefMut}};') - code.append('use uuid::Uuid;') - code.append('') - - entity_structs = [] - - parent_field_name = None - for entity_id in burger_entity_data: - entity_parents = get_entity_parents(entity_id, burger_entity_data) - entity_metadata = get_entity_metadata(entity_id, burger_entity_data) - entity_metadata_names = get_entity_metadata_names( - entity_id, burger_entity_data, mappings) - - struct_name: str = upper_first_letter( - to_camel_case(entity_parents[0].replace('~', ''))) - parent_struct_name: Optional[str] = upper_first_letter(to_camel_case( - entity_parents[1].replace('~', ''))) if (len(entity_parents) >= 2) else None - if parent_struct_name: - parent_field_name = to_snake_case(parent_struct_name) - if not entity_parents[0].startswith('~'): - entity_structs.append(struct_name) + code.append('''#![allow(clippy::single_match)] + +// 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 azalea_chat::FormattedText; +use azalea_core::{BlockPos, Direction, Particle, Slot}; +use azalea_ecs::{bundle::Bundle, component::Component}; +use derive_more::{Deref, DerefMut}; +use thiserror::Error; +use uuid::Uuid; + +#[derive(Error, Debug)] +pub enum UpdateMetadataError { + #[error("Wrong type ({0:?})")] + WrongType(EntityDataValue), +} +impl From<EntityDataValue> for UpdateMetadataError { + fn from(value: EntityDataValue) -> Self { + Self::WrongType(value) + } +} +''') + + # types that are only ever used in one entity + single_use_imported_types = {'particle', 'pose'} + + added_metadata_fields = set() + + # a dict of { entity_id: { field_name: new_name } } + field_name_map = {} + + # build the duplicate_field_names set + previous_field_names = set() + duplicate_field_names = set() + for entity_id in burger_entity_data.keys(): + field_name_map[entity_id] = {} + for field_name_or_bitfield in get_entity_metadata_names(entity_id, burger_entity_data, 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) + else: + previous_field_names.add(field_name_or_bitfield) + else: + for mask, name in field_name_or_bitfield.items(): + if name in previous_field_names: + duplicate_field_names.add(name) + else: + previous_field_names.add(name) + + # oh and also just add the entity id to the duplicate field names to + # make sure entity names don't clash with field names + duplicate_field_names.add(entity_id) + + # 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') + + # 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(): + if isinstance(field_name_or_bitfield, str): + new_field_name = field_name_or_bitfield + 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}' + else: + for mask, name in field_name_or_bitfield.items(): + new_field_name = name + 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}' + + def new_entity(entity_id: str): + # note: fields are components + + # if it doesn't start with ~ then also make a marker struct and Query struct for it + all_field_names_or_bitfields = [] + entity_ids_for_all_field_names_or_bitfields = [] + 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] + return name + + parents = get_entity_parents(entity_id, burger_entity_data) + for parent_id in list(reversed(parents)): + for index, name_or_bitfield in get_entity_metadata_names(parent_id, burger_entity_data, 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 = 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] + if hashable_name_or_bitfield in added_metadata_fields: + continue + added_metadata_fields.add(hashable_name_or_bitfield) - reader_code = [] - writer_code = [] - set_index_code = [] - field_names = [] + if isinstance(name_or_bitfield, str): + # we just use the imported type instead of making our own + if name_or_bitfield in single_use_imported_types: + continue - code.append(f'#[derive(Debug, Clone)]') - code.append(f'pub struct {struct_name} {{') + name_or_bitfield = maybe_rename_field(name_or_bitfield, index) - if parent_struct_name: - assert parent_field_name - code.append(f'pub {parent_field_name}: {parent_struct_name},') - reader_code.append( - f'let {parent_field_name} = {parent_struct_name}::read(metadata)?;') - writer_code.append( - f'metadata.extend(self.{parent_field_name}.write());') - for index, name_or_bitfield in entity_metadata_names.items(): - if isinstance(name_or_bitfield, str): - # normal field (can be any type) - name = name_or_bitfield - if name == 'type': - name = 'kind' - field_names.append(name) - type_id = next(filter(lambda i: i['index'] == index, entity_metadata))[ + 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'] - type_name = metadata_type_data['name'] - code.append(f'pub {name}: {rust_type},') - type_name_field = to_snake_case(type_name) - reader_code.append( - f'let {name} = metadata.pop_front()?.into_{type_name_field}().ok()?;') - writer_code.append( - f'metadata.push(EntityDataValue::{type_name}(self.{name}.clone()));') - - # 1 => self.dancing = value.into_boolean().ok()?, - set_index_code.append( - f'{index} => self.{name} = value.into_{type_name_field}().ok()?,' - ) + code.append(f'#[derive(Component, Deref, DerefMut)]') + code.append(f'pub struct {struct_name}(pub {rust_type});') else: - # bitfield (sent as a byte, each bit in the byte is used as a boolean) - reader_code.append( - 'let bitfield = metadata.pop_front()?.into_byte().ok()?;') - writer_code.append('let mut bitfield = 0u8;') - set_index_code.append(f'{index} => {{') - set_index_code.append( - f'let bitfield = value.into_byte().ok()?;') + # if it's a bitfield just make a struct for each bit for mask, name in name_or_bitfield.items(): - if name == 'type': - name = 'kind' - - field_names.append(name) - code.append(f'pub {name}: bool,') - reader_code.append(f'let {name} = bitfield & {mask} != 0;') - writer_code.append( - f'if self.{name} {{ bitfield &= {mask}; }}') - set_index_code.append( - f'self.{name} = bitfield & {mask} != 0;') - writer_code.append( - 'metadata.push(EntityDataValue::Byte(bitfield));') - set_index_code.append('},') + name = maybe_rename_field(name, index) + struct_name = upper_first_letter(to_camel_case(name)) + code.append(f'#[derive(Component, Deref, DerefMut)]') + code.append(f'pub struct {struct_name}(pub bool);') - code.append('}') - code.append('') + # 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};') - code.append(f'impl {struct_name} {{') + parent_struct_name = upper_first_letter( + to_camel_case(parent_id.lstrip("~"))) if parent_id else None + # impl Allay { + # pub fn apply_metadata( + # entity: &mut azalea_ecs::system::EntityCommands, + # d: EntityDataItem, + # ) -> Result<(), UpdateMetadataError> { + # match d.index { + # 0..=15 => AbstractCreatureBundle::apply_metadata(entity, d)?, + # 16 => entity.insert(Dancing(d.value.into_boolean()?)), + # 17 => entity.insert(CanDuplicate(d.value.into_boolean()?)), + # } + # Ok(()) + # } + # } + code.append(f'impl {struct_name} {{') code.append( - 'pub fn read(metadata: &mut VecDeque<EntityDataValue>) -> Option<Self> {') - code.extend(reader_code) - - self_args = [] - if parent_struct_name: - self_args.append( - f'{parent_field_name}') - self_args.extend(field_names) - code.append(f'Some(Self {{ {",".join(self_args)} }})') - code.append('}') - code.append('') + f' pub fn apply_metadata(entity: &mut azalea_ecs::system::EntityCommands, d: EntityDataItem) -> Result<(), UpdateMetadataError> {{') + code.append(f' 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 + 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)?,') - code.append('pub fn write(&self) -> Vec<EntityDataValue> {') - code.append('let mut metadata = Vec::new();') - code.extend(writer_code) - code.append('metadata') - code.append('}') + 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) - code.append('}') - code.append('') + field_struct_name = upper_first_letter( + to_camel_case(name_or_bitfield)) + if name_or_bitfield in single_use_imported_types: + field_struct_name = '' - # default - code.append(f'impl Default for {struct_name} {{') - code.append('fn default() -> Self {') - default_fields_code = [] - if parent_struct_name: - assert parent_field_name - default_fields_code.append( - f'{parent_field_name}: Default::default()') - for index, name_or_bitfield in entity_metadata_names.items(): - default = next(filter(lambda i: i['index'] == index, entity_metadata)).get( - 'default', 'Default::default()') - if isinstance(name_or_bitfield, str): - type_id = next(filter(lambda i: i['index'] == index, entity_metadata))[ + 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'] - # TODO: burger doesn't get the default if it's a complex type - # like `Rotations`, so entities like armor stands will have the - # 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 = 'azalea_nbt::Tag::Compound(Default::default())' - elif type_name == 'CatVariant': - default = 'azalea_registry::CatVariant::Tabby' - elif type_name == 'PaintingVariant': - default = 'azalea_registry::PaintingVariant::Kebab' - elif type_name == 'FrogVariant': - default = 'azalea_registry::FrogVariant::Temperate' - elif type_name == 'VillagerData': - default = 'VillagerData { kind: azalea_registry::VillagerType::Plains, profession: azalea_registry::VillagerProfession::None, level: 0 }' - else: - default = 'Default::default()' - else: - 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 == 'OptionalUuid': - 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'Slot::Present({default})' if default != 'Empty' else 'Slot::Empty' - elif type_name == 'BlockState': - default = f'{default}' if default != 'Empty' else 'BlockState::Air' - elif type_name == 'OptionalComponent': - 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())' - - print(default, name_or_bitfield, type_name) - name = name_or_bitfield - if name == 'type': - name = 'kind' - default_fields_code.append(f'{name}: {default}') + 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}()?' + code.append( + f' {index} => {{ entity.insert({read_field_code}); }},') else: - # if it's a bitfield, we'll have to extract the default for - # each bool from each bit in the default + code.append(f' {index} => {{') + code.append( + f'let bitfield = d.value.into_byte()?;') for mask, name in name_or_bitfield.items(): - if name == 'type': - name = 'kind' - mask = int(mask, 0) - field_names.append(name) - bit_default = 'true' if (default & mask != 0) else 'false' - default_fields_code.append(f'{name}: {bit_default}') - - # Self { abstract_creature: Default::default(), dancing: Default::default(), can_duplicate: Default::default() } - code.append(f'Self {{ {", ".join(default_fields_code)} }}') - code.append('}') + 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('') - # impl Allay { - # pub fn set_index(&mut self, index: u8, value: EntityDataValue) -> Option<()> { - # match index { - # 0..=0 => self.abstract_creature.set_index(index, value), - # 1 => self.dancing = value.into_boolean().ok()?, - # 2 => self.can_duplicate = value.into_boolean().ok()?, - # _ => {} - # } - # Some(()) - # } + # #[derive(Bundle)] + # struct AllayBundle { + # health: Health, + # ... + # dancing: Dancing, + # can_duplicate: CanDuplicate, # } - code.append(f'impl {struct_name} {{') + 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( - 'pub fn set_index(&mut self, index: u8, value: EntityDataValue) -> Option<()> {') - if len(entity_metadata_names) > 0: - code.append('match index {') - # get the smallest index for this entity - smallest_index = min(entity_metadata_names.keys()) - if parent_struct_name: - code.append( - f'0..={smallest_index-1} => self.{parent_field_name}.set_index(index, value)?,') - code.extend(set_index_code) - code.append('_ => {}') - code.append('}') - code.append('Some(())') - elif parent_struct_name: - code.append(f'self.{parent_field_name}.set_index(index, value)') - else: - code.append('Some(())') - code.append('}') - code.append('}') - - # deref + f' _marker: {struct_name},') if parent_struct_name: - code.append(f'impl Deref for {struct_name} {{') - code.append(f'type Target = {parent_struct_name};') code.append( - f'fn deref(&self) -> &Self::Target {{ &self.{parent_field_name} }}') - code.append('}') - code.append(f'impl DerefMut for {struct_name} {{') - code.append( - f'fn deref_mut(&mut self) -> &mut Self::Target {{ &mut self.{parent_field_name} }}') - code.append('}') - code.append('') - - # make the EntityMetadata enum from entity_structs - code.append(f'#[derive(Debug, Clone)]') - code.append('pub enum EntityMetadata {') - for struct_name in entity_structs: - code.append(f'{struct_name}({struct_name}),') - code.append('}') - 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(): + 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},') + 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('}') - # impl From<azalea_registry::EntityType> for EntityMetadata { - code.append('impl From<azalea_registry::EntityType> for EntityMetadata {') - code.append('fn from(value: azalea_registry::EntityType) -> Self {') - code.append('match value {') - # azalea_registry::EntityType::Allay => EntityMetadata::Allay(Allay::default()), - for struct_name in entity_structs: + # impl Default for AllayBundle { + # fn default() -> Self { + # Self { + # _marker: Allay, + # parent: AbstractCreatureBundle { + # on_fire: OnFire(false), + # shift_key_down: ShiftKeyDown(false), + # }, + # sprinting: Sprinting(false), + # swimming: Swimming(false) + # } + # } + # } + code.append(f'impl Default for {bundle_struct_name} {{') code.append( - f'azalea_registry::EntityType::{struct_name} => EntityMetadata::{struct_name}({struct_name}::default()),') - code.append('}') - code.append('}') - code.append('}') - code.append('') + ' fn default() -> Self {') - # impl EntityMetadata - # pub fn set_index(&mut self, index: u8, value: EntityDataValue) - code.append('impl EntityMetadata {') + def generate_fields(this_entity_id: str): + # on_fire: OnFire(false), + # shift_key_down: ShiftKeyDown(false), + + # _marker + this_entity_struct_name = upper_first_letter( + 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_data) + 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} {{') + generate_fields(this_entity_parent_id) + code.append( + ' },') + + for index, name_or_bitfield in get_entity_metadata_names(this_entity_id, burger_entity_data, 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'] + metadata_type_data = metadata_types[type_id] + type_name = metadata_type_data['name'] + + name = maybe_rename_field(name_or_bitfield, index) + + # TODO: burger doesn't get the default if it's a complex type + # like `Rotations`, so entities like armor stands will have the + # 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 = 'azalea_nbt::Tag::Compound(Default::default())' + elif type_name == 'CatVariant': + default = 'azalea_registry::CatVariant::Tabby' + elif type_name == 'PaintingVariant': + default = 'azalea_registry::PaintingVariant::Kebab' + elif type_name == 'FrogVariant': + default = 'azalea_registry::FrogVariant::Temperate' + 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()' + else: + 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 == 'OptionalUuid': + 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'Slot::Present({default})' if default != 'Empty' else 'Slot::Empty' + elif type_name == 'BlockState': + default = f'{default}' if default != 'Empty' else '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())' + if name in single_use_imported_types: + code.append(f' {name}: {default},') + else: + code.append( + 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 + for mask, name in name_or_bitfield.items(): + name = maybe_rename_field(name, index) + mask = int(mask, 0) + 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 {') + generate_fields(entity_id) + code.append(' }') + code.append(' }') + code.append('}') + code.append('') + + # parent_field_name = None + for entity_id in burger_entity_data: + new_entity(entity_id) + + # and now make the main apply_metadata + # pub fn apply_metadata( + # entity: &mut azalea_ecs::system::EntityCommands, + # items: Vec<EntityDataItem>, + # ) -> Result<(), UpdateMetadataError> { + # if entity.contains::<Allay>() { + # for d in items { + # Allay::apply_metadata(entity, d)?; + # } + # return Ok(()); + # } + # + # Ok(()) + # } code.append( - 'pub fn set_index(&mut self, index: u8, value: EntityDataValue) -> Option<()> {') - code.append('match self {') - # EntityMetadata::Allay(allay) => allay.set_index(index, value), - for struct_name in entity_structs: + f'''pub fn apply_metadata( + entity: &mut azalea_ecs::system::EntityCommands, + entity_kind: azalea_registry::EntityKind, + items: Vec<EntityDataItem>, +) -> Result<(), UpdateMetadataError> {{ + match entity_kind {{''') + for entity_id in burger_entity_data: + if entity_id.startswith('~'): + # not actually an entity + continue + struct_name: str = upper_first_letter(to_camel_case(entity_id)) code.append( - f'EntityMetadata::{struct_name}(entity) => entity.set_index(index, value),') - 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('') - # impl Deref for EntityMetadata { - # type Target = AbstractEntity; - # fn deref(&self) -> &Self::Target { - # match self { - # EntityMetadata::Allay(entity) => entity, - # _ => {} + # pub fn apply_default_metadata(entity: &mut azalea_ecs::system::EntityCommands, kind: azalea_registry::EntityKind) { + # match kind { + # azalea_registry::EntityKind::AreaEffectCloud => { + # entity.insert(AreaEffectCloudMetadataBundle::default()); # } # } # } - code.append('impl Deref for EntityMetadata {') - code.append('type Target = AbstractEntity;') - code.append('fn deref(&self) -> &Self::Target {') - code.append('match self {') - for struct_name in entity_structs: + code.append( + 'pub fn apply_default_metadata(entity: &mut azalea_ecs::system::EntityCommands, kind: azalea_registry::EntityKind) {') + code.append(' match kind {') + for entity_id in burger_entity_data: + if entity_id.startswith('~'): + # not actually an entity + continue + struct_name: str = upper_first_letter(to_camel_case(entity_id)) code.append( - f'EntityMetadata::{struct_name}(entity) => entity,') - code.append('}') - code.append('}') - code.append('}') - code.append('impl DerefMut for EntityMetadata {') - code.append('fn deref_mut(&mut self) -> &mut Self::Target {') - code.append('match self {') - for struct_name in entity_structs: + f' azalea_registry::EntityKind::{struct_name} => {{') code.append( - f'EntityMetadata::{struct_name}(entity) => entity,') - code.append('}') - code.append('}') + f' entity.insert({struct_name}MetadataBundle::default());') + code.append(' },') + code.append(' }') code.append('}') code.append('') @@ -378,6 +491,8 @@ def get_entity_metadata(entity_id: str, burger_entity_data: dict): }) return entity_useful_metadata +# 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'] diff --git a/codegen/lib/code/registry.py b/codegen/lib/code/registry.py index 86f5f02d..1e9d9f43 100755 --- a/codegen/lib/code/registry.py +++ b/codegen/lib/code/registry.py @@ -56,7 +56,14 @@ impl<T: Registry> McBufWritable for OptionalRegistry<T> { # Air => "minecraft:air", # Stone => "minecraft:stone" # }); + + 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' + registry_struct_name = to_camel_case(registry_name.split(':')[1]) + code.append(f'registry!({registry_struct_name}, {{') registry_entries = sorted( registry['entries'].items(), key=lambda x: x[1]['protocol_id']) diff --git a/codegen/lib/code/utils.py b/codegen/lib/code/utils.py index 5550cdb2..fe4aca7f 100755 --- a/codegen/lib/code/utils.py +++ b/codegen/lib/code/utils.py @@ -44,8 +44,8 @@ def burger_type_to_rust_type(burger_type, field_name: Optional[str] = None, inst field_type_rs = 'String' elif burger_type == 'chatcomponent': - field_type_rs = 'Component' - uses.add('azalea_chat::Component') + field_type_rs = 'FormattedText' + uses.add('azalea_chat::FormattedText') elif burger_type == 'identifier': field_type_rs = 'ResourceLocation' uses.add('azalea_core::ResourceLocation') |
