diff --git a/docs/entities/attributes.md b/docs/entities/attributes.md new file mode 100644 index 00000000..f2ff4649 --- /dev/null +++ b/docs/entities/attributes.md @@ -0,0 +1,6 @@ +--- +sidebar_position: 5 +--- +# Attributes + +TODO \ No newline at end of file diff --git a/docs/entities/data.md b/docs/entities/data.md new file mode 100644 index 00000000..69443996 --- /dev/null +++ b/docs/entities/data.md @@ -0,0 +1,12 @@ +--- +sidebar_position: 2 +--- +# Data and Networking + +TODO + +## Custom Network Messages + +Of course, you can also always opt to use a custom packet to send information. Please refer to the [Networking articles][networking] for more information. + +[networking]: ../networking/index.md diff --git a/docs/entities/index.md b/docs/entities/index.md index 18b2b0c4..9c1a5d38 100644 --- a/docs/entities/index.md +++ b/docs/entities/index.md @@ -1,134 +1,173 @@ +--- +sidebar_position: 1 +--- # Entities -Entities are actors that can interact with the world in a variety of ways. Entities comprise mobs, projectiles, rideable objects, and even players. Each entity is comprised of multiple systems that may not seem understandable at first glance. This section will breakdown some of the key components related to constructing an entity and making it behave as the modder intends. +Entities are in-world objects that can interact with the world in a variety of ways. Common example include mobs, projectiles, rideable objects, and even players. Each entity consists of multiple systems that may not seem understandable at first glance. This section will break down some of the key components related to constructing an entity and making it behave as the modder intends. -## A Quick Summary +## Terminology -Entities, in their simplest and most trivial form, are made up of four parts: +A simple entity is made up of three parts: -- The [`EntityType` registry object][entitytype] - - The default properties that all entities have -- An [`Entity` subclass][entity] - - The logic to execute when this entity ticks or is interacted with -- An [`EntityRenderer` subclass][entityrenderer] - - How the entity is rendered in-game -- A [summoning method][summon] - - How the entity is spanwed into a level +- The [`Entity`][entity] subclass, which holds most of our entity's logic +- The [`EntityType`][type], which is [registered][registration] and holds some common properties, and +- The [`EntityRenderer`][renderer], which is responsible for displaying the entity in-game -An entity may require more parts depending on the subclass of `Entity` and `EntityRenderer` used (e.g., [`LivingEntity` or `Mob`][living]). +More complex entities may require more parts. For example, many of the more complex `EntityRenderer`s use an underlying `EntityModel` instance. Or, a naturally spawning entity will need some sort of [spawn mechanism][spawning]. -:::warning -The simplest and most trivial entity does absolutely nothing. Most users will only need to extend a subclass of `Entity` and `EntityRenderer`. However, understanding the underlying principles is necessary to more effectively create entities and avoid hard to diagnose bugs. -::: - -## `EntityType`: The Grounding Principle +## `EntityType` -An `EntityType` is the singleton that defines what an entity is. Multiple entities within the world can be associated with one `EntityType`. The `EntityType` also links an [`EntityRenderer`][entityrenderer] to its corresponding `Entity` class. It also defines default properties that all entities with this type has. The `EntityType` must be [registered]. +The relationship between `EntityType`s and `Entity`s is similar to that of [`Item`s][item] and [`ItemStack`s][itemstack]. Like `Item`s, `EntityType`s are singletons that are registered to their corresponding registry (the entity type registry) and hold some values common to all entities of that type, while `Entity`s, like `ItemStack`s, are "instances" of that singleton type that hold data specific to that one entity instance. However, the key difference here is that most of the behavior is not defined in the singleton `EntityType`, but rather in the instantiated `Entity` class itself. -An `EntityType` can be constructed via `EntityType.Builder#of`. This method takes in two parameters: an `EntityType.EntityFactory` that [constructs a default `Entity` instance][entity], and a [`MobCategory`][mobcategory] indicating the entity type. The `EntityType` can be built via `EntityType.Builder#build` by passing in `null` as the argument. - -:::info -The `String` in the `build` method represents the registry name of the `EntityType` and is used when dealing with data fixers. The reason we pass in `null` is that data fixers go unused in mod development. If a value is passed in, then Vanilla's data fixer will continually throw a warning when loading the game as there is no definition within an applicable schema. -::: +Let's create our `EntityType` registry and register an `EntityType` for it, assuming we have a class `MyEntity` that extends `Entity` (see [below][entity] for more information). All methods on `EntityType.Builder`, except for the `#build` call at the end, are optional. ```java -// For some entity -public class ExampleEntity extends Entity { - - // This is the constructor definition for use in 'EntityType.EntityFactory' - public ExampleEntity(EntityType type, Level level) { - super(type, level); - // ... - } - - // ... -} - -// In some class that holds registry objects -public static final DeferredRegister> REGISTRAR = DeferredRegister.create(Registries.ENTITY_TYPE, MOD_ID); - -public static final DeferredHolder, EntityType> EXAMPLE_ENITTY = REGISTRAR.register( - "example_entity", - () -> EntityType.Builder.of( - ExampleEntity::new // The constructor definition, - MobCategory.MISC // Category for entities that do not generally extend 'Mob' - ).build(null) // String value goes unused +public static final DeferredRegister> ENTITY_TYPES = + DeferredRegister.create(Registries.ENTITY_TYPE, ExampleMod.MOD_ID); + +public static final Supplier> MY_ENTITY = ENTITY_TYPES.register( + "my_entity", + // The entity type, created using a builder. + () -> EntityType.Builder.of( + // An EntityType.EntityFactory, where T is the entity class used - MyEntity in this case. + // You can think of it as a BiFunction, Level, T>. + // This is commonly a reference to the entity constructor. + MyEntity::new, + // The MobCategory our entity uses. This is mainly relevant for spawning. + // See below for more information. + MobCategory.MISC + ) + // The width and height, in blocks. The width is used in both horizontal directions. + // This also means that non-square footprints are not supported. Default is 0.6f and 1.8f. + .sized(1.0f, 1.0f) + // The spawn dimensions. This is used by mobs that spawn in varying sizes. + // In vanilla, these are only slimes and magma cubes, both of which use 4.0f. + .spawnDimensionsScale(4.0f) + // The eye height, in blocks from the bottom of the size. Defaults to height * 0.85. + // This must be called after #sized to have an effect. + .eyeHeight(0.5f) + // Disables the entity being summonable via /summon. + .noSummon() + // Prevents the entity from being saved to disk. + .noSave() + // Makes the entity fire immune. + .fireImmune() + // Makes the entity immune to damage from a certain block. Vanilla uses this to make + // foxes immune to sweet berry bushes, withers and wither skeletons immune to wither roses, + // and polar bears, snow golems and strays immune to powder snow. + .immuneTo(Blocks.POWDER_SNOW) + // Disables a rule in the spawn handler that limits the distance at which entities can spawn. + // This means that no matter the distance to the player, this entity can spawn. + // Vanilla enables this for pillagers and shulkers. + .canSpawnFarFromPlayer() + // The range in which the entity is kept loaded by the client, in chunks. + // Vanilla values for this vary, but it's often something around 8 or 10. Defaults to 5. + .clientTrackingRange(8) + // How often update packets are sent for this entity, in once every x ticks. This is set to higher values + // for entities that have predictable movement patterns, for example projectiles. Defaults to 3. + .updateInterval(10) + // Build the entity type. The parameter is a string used for datafixing; mods generally + // do not utilize this and can safely pass null here instead. + .build(null) ); ``` -:::note -The builder contains many methods that will be further discussed in other sections to help with understanding. An example for applying each to an `EntityType` will be provided there. +:::warning +Sometimes, there may be generic bounds errors with the entity type and the entity constructor. If this happens, the easiest solution is often to use an explicit generic type for `EntityType.Builder#of`, like so: + +```java +() -> EntityType.Builder.of(...) +``` ::: -## Everything Revolves Around `Entity` +### `MobCategory` -The `Entity` class is the base containing the logic that the entity executes when ticked or interacted with. The `Entity` constructor takes in two parameters: the `EntityType` of the entity, and the `Level` the entity is spawned in. This constructor is passed into the `EntityType` builder to spawn entities on both the server and the client. +TODO -```java -public class ExampleEntity extends Entity { +## The Entity Class - // This is the constructor definition for use in 'EntityType.EntityFactory' - public ExampleEntity(EntityType type, Level level) { +To begin, we create an `Entity` subclass. Alongside a constructor, `Entity` (which is an abstract class) defines three required methods that we are required to implement. These will be explained in the [Data and Networking article][data], in order to not further bloat this article. + +```java +public class MyEntity extends Entity { + // We inherit this constructor without the bound on the generic wildcard. + // The bound is needed for registration below, so we add it here. + public MyEntity(EntityType type, Level level) { super(type, level); - // ... } + + // See the Data and Networking article for information about these methods. + @Override + protected void readAdditionalSaveData(CompoundTag compoundTag) {} + + @Override + protected void addAdditionalSaveData(CompoundTag compoundTag) {} + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) {} } ``` -If the entity will be spawned manually rather than by the game, then additional constructors can be added to spawn the entity. These constructors usually hardcode the entity type to whatever is attempting to be spawned. +:::info +While `Entity` can be extended directly, it often makes sense to use one of its many subclasses as a base instead. See the [entity class hierarchy][hierarchy] for more information. +::: -```java -public class ExampleEntity extends Entity { +If required (e.g. because you're spawning entities from code), you can also add custom constructors. These generally hardcode the entity type as a reference to the registered object, like so: - public ExampleEntity(Level level, double x, double y, double z) { - // Delegates to the factory constructor - this(EXAMPLE_ENITTY.value(), level); - this.setPos(x, y, z); - } +```java +public MyEntity(Level level, double x, double y, double z) { + // Delegates to the factory constructor, using the EntityType we registered before. + this(MY_ENTITY.get(), level); + this.setPos(x, y, z); } ``` -### To Pick or Not to Pick +And now, we are free to do basically whatever we want with our entity. The following subsections will display a variety of common entity use cases. -TODO +### Data Storage on Entities -### Entity Dimensions +_See [Entities/Data and Networking][data]._ -TODO +### Rendering -### Entity Attachments +_See [Entities/Entity Renderers][renderer]._ -TODO +### Spawning -### Reading and Writing Data +If we now boot up the game now and enter a world, we have exactly one way of spawning: through the `/summon` command (assuming `EntityType.Builder#noSummon` was not called). -TODO +Obviously, we want to add our entities some other way. The easiest way to do so is through the `LevelWriter#addFreshEntity` method. This method simply accepts an `Entity` instance and adds it to the world, like so: -### Synchronizing to the Client +```java +// In some method that has a level available +MyEntity entity = new MyEntity(level, 100.0, 200.0, 300.0); +level.addFreshEntity(entity); +``` -TODO (Move to its own page) +For more complex spawn behavior, please refer to the [Spawning article][spawning]. -## Summoning an Entity +### Ticking Entities TODO -### `LevelWriter#addFreshEntity` +### Picking Entities TODO -### `SpawnerData` +### Entity Attachments TODO -#### `MobSpawnCost` +## Entity Class Hierarchy TODO -[entitytype]: #entitytype-the-grounding-principle -[entity]: #everything-revolves-around-entity -[entityrenderer]: ./renderer.md -[summon]: #summoning-an-entity -[registered]: ../concepts/registries.md#methods-for-registering - -[living]: # -[mobcategory]: # +[data]: data.md +[entity]: #the-entity-class +[hierarchy]: #entity-class-hierarchy +[item]: ../items/index.md +[itemstack]: ../items/index.md#itemstacks +[registration]: ../concepts/registries.md#methods-for-registering +[renderer]: renderer.md +[spawning]: spawning.md +[type]: #entitytype diff --git a/docs/entities/livingentity.md b/docs/entities/livingentity.md new file mode 100644 index 00000000..7f94d3bf --- /dev/null +++ b/docs/entities/livingentity.md @@ -0,0 +1,6 @@ +--- +sidebar_position: 4 +--- +# Living Entities, Mobs & Players + +TODO \ No newline at end of file diff --git a/docs/entities/projectile.md b/docs/entities/projectile.md new file mode 100644 index 00000000..87017b1c --- /dev/null +++ b/docs/entities/projectile.md @@ -0,0 +1,6 @@ +--- +sidebar_position: 3 +--- +# Projectiles + +TODO \ No newline at end of file diff --git a/docs/entities/renderer.md b/docs/entities/renderer.md index 539f3733..71b581e7 100644 --- a/docs/entities/renderer.md +++ b/docs/entities/renderer.md @@ -1,3 +1,6 @@ +--- +sidebar_position: 6 +--- # Entity Renderers TODO \ No newline at end of file diff --git a/docs/entities/spawning.md b/docs/entities/spawning.md new file mode 100644 index 00000000..9d7c02a0 --- /dev/null +++ b/docs/entities/spawning.md @@ -0,0 +1,6 @@ +--- +sidebar_position: 7 +--- +# Spawning Entities + +TODO \ No newline at end of file diff --git a/docs/networking/entities.md b/docs/networking/entities.md deleted file mode 100644 index 80be9b6d..00000000 --- a/docs/networking/entities.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -sidebar_position: 4 ---- -# Entities - -In addition to regular network messages, there are various other systems provided to handle synchronizing entity data. - -## Spawn Data - -Since 1.20.2 Mojang introduced the concept of Bundle packets, which are used to send entity spawn packets together. This allows for more data to be sent with the spawn packet, and for that data to be sent more efficiently. - -You can add extra data to the spawn packet NeoForge sends by implementing the following interface. - -### IEntityWithComplexSpawn - -If your entity has data that is needed on the client, but does not change over time, then it can be added to the entity spawn packet using this interface. `#writeSpawnData` and `#readSpawnData` control how the data should be encoded to/decoded from the network buffer. Alternatively you can override the method `IEntityExtension#sendPairingData` which is called when the entity's initial data is sent to the client. This method is called on the server, and can be used to send additional payloads to the client within the same bundle as the spawn packet. - -## Dynamic Data Parameters - -This is the main vanilla system for synchronizing entity data from the server to the client. As such, a number of vanilla examples are available to refer to. - -Firstly, you need a `EntityDataAccessor` for the data you wish to keep synchronized. This should be stored as a `static final` field in your entity class, obtained by calling `SynchedEntityData#defineId` and passing the entity class and a serializer for that type of data. The available serializer implementations can be found as static constants within the `EntityDataSerializers` class. - -:::caution -You should __only__ create data parameters for your own entities, _within that entity's class_. Adding parameters to entities you do not control can cause the IDs used to send that data over the network to become desynchronized, causing difficult to debug crashes. -::: - -Then, override `Entity#defineSynchedData` and call `SynchedEntityData.Builder#define` for each of your data parameters, passing the parameter and an initial value to use. Remember to always call the `super` method first! - -You can then get and set these values via your entity's `entityData` instance. Changes made will be synchronized to the client automatically. diff --git a/docs/networking/streamcodecs.md b/docs/networking/streamcodecs.md index c2a54c0f..6c862382 100644 --- a/docs/networking/streamcodecs.md +++ b/docs/networking/streamcodecs.md @@ -71,7 +71,7 @@ Additionally, there are some static instances that encode and decode primivites #### Trusted Tags -`TRUSTED_TAG` and `TRUSTED_COMPOUND_TAG` are variants of `TAG` and `COMPOUND_TAG`, respectively, that have an unlimited heap to decode the tag to, compared to the 2MiB limit of `TAG` and `COMPOUND_TAG`. Trusted tag stream codecs should ideally only be used in clientbound packets, such as what Vanilla does for [block entity data packet][blockentity] and [entity data serializers][entityserializer]. +`TRUSTED_TAG` and `TRUSTED_COMPOUND_TAG` are variants of `TAG` and `COMPOUND_TAG`, respectively, that have an unlimited heap to decode the tag to, compared to the 2MiB limit of `TAG` and `COMPOUND_TAG`. Trusted tag stream codecs should ideally only be used in clientbound packets, such as what Vanilla does for [block entity data packet][blockentity] and [entity data serializers][entity]. If a different limit should be used, then a `NbtAccounter` can be supplied with the given size using `ByteBufCodecs#tagCodec` or `#compoundTagCodec`. @@ -381,6 +381,6 @@ public static final StreamCodec DISPATCH [networking]: ./payload.md [codecs]: ../datastorage/codecs.md -[blockentity]: ../blockentities/index.md#synchronizing-on-block-update -[entityserializer]: ../networking/entities.md#dynamic-data-parameters +[blockentity]: ../blockentities/index.md#syncing-on-block-update +[entity]: ../entities/data.md [transformers]: ../datastorage/codecs.md#transformers