aboutsummaryrefslogtreecommitdiff
path: root/codegen
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2025-12-15 05:45:53 -0100
committermat <git@matdoes.dev>2025-12-15 05:45:53 -0100
commit9846cb008abd88cb1785881dcac14014762977eb (patch)
tree58961e1c661f8a7879e441d8706ae9deea0cab0b /codegen
parent0b5e5d2b8a1a462f27c9f998845765e35d7158d5 (diff)
downloadazalea-drasl-9846cb008abd88cb1785881dcac14014762977eb.tar.xz
generate docs for metadata components
Diffstat (limited to 'codegen')
-rw-r--r--codegen/lib/code/entity.py127
1 files changed, 114 insertions, 13 deletions
diff --git a/codegen/lib/code/entity.py b/codegen/lib/code/entity.py
index 02167dfa..9d9e7733 100644
--- a/codegen/lib/code/entity.py
+++ b/codegen/lib/code/entity.py
@@ -102,13 +102,26 @@ def generate_entity_metadata(burger_entities_data: dict, mappings: Mappings):
metadata_types = parse_metadata_types_from_code()
- code = []
- code.append("""#![allow(clippy::single_match)]
-
-// This file is @generated from codegen/lib/code/entity.py.
-// Don't change it manually!
+ code_header = []
+ code_header.append("// This file is @generated from codegen/lib/code/entity.py.")
+ code_header.append("// Don't change it manually!")
+ code_header.append("")
+
+ code_header.append("""//! Metadata fields stored on entities.
+//!
+//! Also see the [protocol wiki documentation](https://minecraft.wiki/w/Java_Edition_protocol/Entity_metadata).
+//!
+//! # Entities
+//!
+//! Azalea creates a marker ECS component for every entity and abstract entity.
+//! You can use these to check if an entity is of a given type with an ECS
+//! filter, such as `With<AbstractMonster>`.
+//!
+//! All marker components are shown as a tree structure below:
+//!""")
-use azalea_chat::FormattedText;
+ code = []
+ code.append("""use azalea_chat::FormattedText;
use azalea_core::{
direction::Direction,
position::{BlockPos, Vec3f32},
@@ -157,6 +170,8 @@ impl From<EntityDataValue> for UpdateMetadataError {
# make this one longer to avoid accidental use -- AbstractEntityShiftKeyDown instead of ShiftKeydown
duplicate_field_names.add("shift_key_down")
+ entity_ids_to_children_ids = {}
+
for entity_id in burger_entity_metadata.keys():
field_name_map[entity_id] = {}
for field_name_or_bitfield in get_entity_metadata_names(
@@ -178,6 +193,11 @@ impl From<EntityDataValue> for UpdateMetadataError {
# make sure entity names don't clash with field names
duplicate_field_names.add(entity_id)
+ parent_id = get_entity_parent(entity_id, burger_entity_metadata)
+ if parent_id not in entity_ids_to_children_ids:
+ entity_ids_to_children_ids[parent_id] = []
+ entity_ids_to_children_ids[parent_id].append(entity_id)
+
# make sure these types are only ever made once
for name in single_use_imported_types:
if name in duplicate_field_names:
@@ -237,6 +257,12 @@ impl From<EntityDataValue> for UpdateMetadataError {
)
parent_id = parents[1] if len(parents) > 1 else None
+ entity_struct_name = entity_id_to_struct_name(entity_id)
+ code_header_indent = " " * (len(parents) - 1)
+ code_header.append(f"//! {code_header_indent}- [{entity_struct_name}]")
+
+ entity_metadata_doc_code = []
+
# 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
@@ -262,8 +288,10 @@ impl From<EntityDataValue> for UpdateMetadataError {
metadata_type_data = metadata_types[type_id]
rust_type = metadata_type_data["type"]
+ code.append(f"/// A metadata field for [{entity_struct_name}].")
code.append("#[derive(Component, Deref, DerefMut, Clone, PartialEq)]")
code.append(f"pub struct {struct_name}(pub {rust_type});")
+ entity_metadata_doc_code.append(f"/// - [{struct_name}]")
else:
# if it's a bitfield just make a struct for each bit
for mask, name in name_or_bitfield.items():
@@ -272,12 +300,70 @@ impl From<EntityDataValue> for UpdateMetadataError {
code.append(
"#[derive(Component, Deref, DerefMut, Clone, Copy, PartialEq)]"
)
+ code.append(f"/// A metadata field for [{entity_struct_name}].")
code.append(f"pub struct {struct_name}(pub bool);")
+ entity_metadata_doc_code.append(f"/// - [{struct_name}]")
# add the entity struct and Bundle struct
- struct_name: str = upper_first_letter(to_camel_case(entity_id.lstrip("~")))
+ if entity_id == "~abstract_entity":
+ code.append("/// The root entity marker component.")
+ code.append("///")
+ code.append(
+ "/// All entities that have had their metadata sent by the server will have this component."
+ )
+ elif entity_id.startswith("~"):
+ code.append("/// An abstract entity marker component.")
+ else:
+ code.append(
+ f"/// The marker component for entities of type `minecraft:{entity_id}`."
+ )
+
+ code.append("///")
+ code.append("/// # Metadata")
+ code.append("///")
+ if len(entity_metadata_doc_code) == 0:
+ code.append(
+ "/// This entity type does not add any additional metadata. It will still have metadata from parent types."
+ )
+ else:
+ code.append(
+ f"/// These are the metadata components that all `{entity_struct_name}` entities are guaranteed to have, in addition to the metadata components from parent types:"
+ )
+ code.append("///")
+ code.extend(entity_metadata_doc_code)
+
+ if len(parents) > 1:
+ code.append("///")
+ code.append("/// # Parents")
+ code.append("///")
+ code.append(
+ f"/// Entities with `{entity_struct_name}` will also have the following marker components and their metadata fields:"
+ )
+ code.append("///")
+ for parent_entity_id in parents[1:]:
+ code.append(f"/// - [{entity_id_to_struct_name(parent_entity_id)}]")
+
+ code.append("///")
+ code.append("/// # Children")
+ code.append("///")
+
+ def add_children_recursively(current_entity_id, indentation=""):
+ for child_entity_id in entity_ids_to_children_ids.get(
+ current_entity_id, []
+ ):
+ code.append(
+ f"/// {indentation}- [{entity_id_to_struct_name(child_entity_id)}]"
+ )
+ add_children_recursively(child_entity_id, indentation + " ")
+
+ children_entity_ids = entity_ids_to_children_ids.get(entity_id)
+ if children_entity_ids:
+ add_children_recursively(entity_id)
+ else:
+ code.append("/// This entity type has no children types.")
+
code.append("#[derive(Component)]")
- code.append(f"pub struct {struct_name};")
+ code.append(f"pub struct {entity_struct_name};")
parent_struct_name = (
upper_first_letter(to_camel_case(parent_id.lstrip("~")))
@@ -298,7 +384,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
# Ok(())
# }
# }
- code.append(f"impl {struct_name} {{")
+ code.append(f"impl {entity_struct_name} {{")
code.append(
" pub fn apply_metadata(entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem) -> Result<(), UpdateMetadataError> {"
)
@@ -367,11 +453,14 @@ impl From<EntityDataValue> for UpdateMetadataError {
# dancing: Dancing,
# can_duplicate: CanDuplicate,
# }
- bundle_struct_name = f"{struct_name}MetadataBundle"
+ bundle_struct_name = f"{entity_struct_name}MetadataBundle"
code.append("")
+ code.append(f"/// The metadata bundle for [{entity_struct_name}].")
+ code.append("///")
+ code.append("/// This type should generally not be used directly.")
code.append("#[derive(Bundle)]")
code.append(f"pub struct {bundle_struct_name} {{")
- code.append(f" _marker: {struct_name},")
+ code.append(f" _marker: {entity_struct_name},")
if parent_struct_name:
code.append(f" parent: {parent_struct_name}MetadataBundle,")
for index, name_or_bitfield in get_entity_metadata_names(
@@ -560,10 +649,14 @@ impl From<EntityDataValue> for UpdateMetadataError {
code.append("}")
code.append("")
- # parent_field_name = None
- for entity_id in burger_entity_metadata:
+ def new_entity_recursive(entity_id: str):
new_entity(entity_id)
+ for child_entity_id in entity_ids_to_children_ids.get(entity_id, []):
+ new_entity_recursive(child_entity_id)
+
+ new_entity_recursive("~abstract_entity")
+
# and now make the main apply_metadata
# pub fn apply_metadata(
# entity: &mut bevy_ecs::system::EntityCommands,
@@ -626,10 +719,18 @@ impl From<EntityDataValue> for UpdateMetadataError {
code.append("}")
code.append("")
+ code_header.append("")
+ code_header.append("#![allow(clippy::single_match)]")
+
with open(METADATA_RS_DIR, "w") as f:
+ f.write("\n".join(code_header) + "\n\n")
f.write("\n".join(code))
+def entity_id_to_struct_name(entity_id: str) -> str:
+ return upper_first_letter(to_camel_case(entity_id.lstrip("~")))
+
+
def generate_entity_dimensions(burger_entities_data: dict):
# lines look like
# EntityKind::Player => EntityDimensions::new(0.6, 1.8).eye_height(1.62),