aboutsummaryrefslogtreecommitdiff
path: root/codegen/lib
diff options
context:
space:
mode:
Diffstat (limited to 'codegen/lib')
-rw-r--r--codegen/lib/code/entity.py649
-rwxr-xr-xcodegen/lib/code/registry.py7
-rwxr-xr-xcodegen/lib/code/utils.py4
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')