Skip to content

Commit

Permalink
basic structure setup and entitytype documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
IchHabeHunger54 committed Oct 2, 2024
1 parent 41f583b commit a9937e3
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 116 deletions.
6 changes: 6 additions & 0 deletions docs/entities/attributes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
sidebar_position: 5
---
# Attributes

TODO
12 changes: 12 additions & 0 deletions docs/entities/data.md
Original file line number Diff line number Diff line change
@@ -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
205 changes: 122 additions & 83 deletions docs/entities/index.md
Original file line number Diff line number Diff line change
@@ -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<? extends ExampleEntity> type, Level level) {
super(type, level);
// ...
}

// ...
}

// In some class that holds registry objects
public static final DeferredRegister<EntityType<?>> REGISTRAR = DeferredRegister.create(Registries.ENTITY_TYPE, MOD_ID);

public static final DeferredHolder<EntityType<?>, EntityType<ExampleEntity>> 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<EntityType<?>> ENTITY_TYPES =
DeferredRegister.create(Registries.ENTITY_TYPE, ExampleMod.MOD_ID);

public static final Supplier<EntityType<MyEntity>> MY_ENTITY = ENTITY_TYPES.register(
"my_entity",
// The entity type, created using a builder.
() -> EntityType.Builder.of(
// An EntityType.EntityFactory<T>, where T is the entity class used - MyEntity in this case.
// You can think of it as a BiFunction<EntityType<T>, 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.<MyEntity>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<? extends ExampleEntity> 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<? extends MyEntity> 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
<!-- Replace with living entity docs -->
[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
6 changes: 6 additions & 0 deletions docs/entities/livingentity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
sidebar_position: 4
---
# Living Entities, Mobs & Players

TODO
6 changes: 6 additions & 0 deletions docs/entities/projectile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
sidebar_position: 3
---
# Projectiles

TODO
3 changes: 3 additions & 0 deletions docs/entities/renderer.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
---
sidebar_position: 6
---
# Entity Renderers

TODO
6 changes: 6 additions & 0 deletions docs/entities/spawning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
sidebar_position: 7
---
# Spawning Entities

TODO
30 changes: 0 additions & 30 deletions docs/networking/entities.md

This file was deleted.

6 changes: 3 additions & 3 deletions docs/networking/streamcodecs.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

Expand Down Expand Up @@ -381,6 +381,6 @@ public static final StreamCodec<RegistryFriendlyByteBuf, ExampleObject> 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

0 comments on commit a9937e3

Please sign in to comment.