Skip to content

Commit

Permalink
apply feedback by @XFactHD
Browse files Browse the repository at this point in the history
  • Loading branch information
IchHabeHunger54 committed Sep 25, 2024
1 parent 7a8c624 commit 0353445
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 25 deletions.
21 changes: 9 additions & 12 deletions docs/blockentities/ber.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ To add a BEWLR, create a class that extends `BlockEntityWithoutLevelRenderer` an
```java
public class MyBlockEntityWithoutLevelRenderer extends BlockEntityWithoutLevelRenderer {
// We need some boilerplate in the constructor, telling the superclass where to find
// the central block entity and entity renderers.
// We need some boilerplate in the constructor, telling the superclass where to find the central block entity and entity renderers.
public MyBlockEntityWithoutLevelRenderer() {
super(Minecraft.getInstance().getBlockEntityRenderDispatcher(), Minecraft.getInstance().getEntityModels());
}
Expand All @@ -83,31 +82,29 @@ public class MyBlockEntityWithoutLevelRenderer extends BlockEntityWithoutLevelRe
Keep in mind that, like with BERs, there is only one instance of your BEWLR. Stack-specific properties should therefore be stored in the stack, not the BEWLR.
Unlike BERs, we do not register BEWLRs directly. Instead, we register an instance of `IClientItemExtensions` to the `RegisterClientExtensionsEvent`. `IClientItemExtensions` allows us to specify a number of rendering-related behaviors on items, but since we're only interested in replacing the renderer with our newly-made BEWLR, we will just slap the `IClientItemExtensions` interface onto our BEWLR, like so:
Unlike BERs, we do not register BEWLRs directly. Instead, we register an instance of `IClientItemExtensions` to the `RegisterClientExtensionsEvent`. `IClientItemExtensions` is an interface that allows us to specify a number of rendering-related behaviors on items, such as (but not limited to) a BEWLR. As such, our implementation of that interface could look like so:
```java
public class MyBlockEntityWithoutLevelRenderer extends BlockEntityWithoutLevelRenderer implements IClientItemExtensions {
public MyBlockEntityWithoutLevelRenderer() { /* ... */ }

@Override
public void renderByItem( /* ... */ ) { /* ... */ }
public class MyClientItemExtensions implements IClientItemExtensions {
// Cache our BEWLR in a field.
private final MyBlockEntityWithoutLevelRenderer myBEWLR = new MyBlockEntityWithoutLevelRenderer();
// Defined by IClientItemExtensions. Return ourselves here.
// Return our BEWLR here.
@Override
public BlockEntityWithoutLevelRenderer getCustomRenderer() {
return this;
return myBEWLR;
}
}
```
And then, we can register the BEWLR as an `IClientItemExtensions` to the event:
And then, we can register our `IClientItemExtensions` to the event:
```java
@SubscribeEvent
public static void registerClientExtensions(RegisterClientExtensionsEvent event) {
event.registerItem(
// The only instance of your BEWLR.
new MyBlockEntityWithoutLevelRenderer(),
new MyClientItemExtensions(),
// A vararg list of items that use this BEWLR.
MyItems.ITEM_1, MyItems.ITEM_2
);
Expand Down
16 changes: 13 additions & 3 deletions docs/blockentities/container.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ The `Container` interface defines methods such as `#getItem`, `#setItem` and `#r

Due to this, `Container`s can not only be implemented on block entities, but any other class as well. Notable examples include entity inventories, as well as common modded [items][item] such as backpacks.

:::info
:::warning
NeoForge provides the `ItemStackHandler` class as a replacement for `Container`s in many places. It should be used wherever possible in favor of `Container`, as it allows for cleaner interaction with other `Container`s/`ItemStackHandler`s.

The main reason this article exists is for reference in vanilla code, or if you are developing mods on multiple loaders. Always use `ItemStackHandler` in your own code if possible! Docs on that are a work in progress.
:::

## Basic Container Implementation
Expand Down Expand Up @@ -254,7 +256,11 @@ public class MyBackpackContainer extends SimpleContainer {
}
```

And voilà, you have created an item-backed container! Simply call `new MyBackpackContainer(stack)` to create a container for a menu or other use case.
And voilà, you have created an item-backed container! Call `new MyBackpackContainer(stack)` to create a container for a menu or other use case.

:::warning
Be aware that `Menu`s that directly interface with `Container`s must `#copy()` their `ItemStack`s when modifying them, as otherwise the immutability contract on data components is broken.
:::

## `Container`s on `Entity`s

Expand All @@ -281,6 +287,10 @@ mob.setItemSlot(EquipmentSlot.FEET, new ItemStack(Items.BEDROCK));
mob.setDropChance(EquipmentSlot.FEET, 1f);
```

### `InventoryCarrier`

`InventoryCarrier` is an interface implemented by some living entities, such as villagers. It declares a method `#getInventory`, which returns a `SimpleContainer`. This interface is used by non-player entities that need an actual inventory instead of just the equipment slots provided by `EquipmentUser`.

### `Container`s on `Player`s (Player Inventory)

The player's inventory is implemented through the `Inventory` class, a class implementing `Container` as well as the `Nameable` interface mentioned earlier. An instance of that `Inventory` is then stored as a field named `inventory` on the `Player`, accessible via `Player#getInventory`. The inventory can be interacted with like any other container.
Expand All @@ -296,7 +306,7 @@ When iterating over the inventory contents, it is recommended to iterate over `i
[block]: ../blocks/index.md
[blockentity]: index.md
[component]: ../resources/client/i18n.md#components
[datacomponent]: ../items/datacomponents.md
[datacomponent]: ../items/datacomponents.mdx
[item]: ../items/index.md
[itemstack]: ../items/index.md#itemstacks
[menu]: ../gui/menus.md
21 changes: 11 additions & 10 deletions docs/blockentities/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Block Entities

Block entities allow the storage of data on [blocks][block] in cases where [block states][blockstate] are not suited. This is especially the case for data with a non-finite amount of options, such as inventories. Block entities are stationary and bound to a block, but otherwise share many similarities with entities, hence the name.
Block entities allow the storage of data on [blocks][block] in cases where [block states][blockstate] are not suitable. This is especially the case for data with a non-finite amount of options, such as inventories. Block entities are stationary and bound to a block, but otherwise share many similarities with entities, hence the name.

:::note
If you have a finite and reasonably small amount (= a few hundred at most) of possible states for your block, you might want to consider using [block states][blockstate] instead.
Expand Down Expand Up @@ -88,6 +88,10 @@ public static final DeferredBlock<MyEntityBlock> MY_BLOCK_2 =

One of the main purposes of `BlockEntity`s is to store data. Data storage on block entities can happen in two ways: directly reading and writing [NBT][nbt], or using [data attachments][dataattachments]. This section will cover reading and writing NBT directly; for data attachments, please refer to the linked article.

:::info
The main purpose of data attachments is, as the name suggests, attaching data to existing block entities, such as those provided by vanilla or other mods. For your own mod's block entities, saving and loading directly to and from NBT is preferred.
:::

Data can be read from and written to a `CompoundTag` using the `#loadAdditional` and `#saveAdditional` methods, respectively. These methods are called when the block entity is synced to disk or over the network.

```java
Expand Down Expand Up @@ -119,10 +123,6 @@ public class MyBlockEntity extends BlockEntity {

In both methods, it is important that you call super, as that adds basic information such as the position. The tag names `id`, `x`, `y`, `z`, `NeoForgeData` and `neoforge:attachments` are reserved by the super methods, and as such, you should not use them yourself.

:::info
It is expected that Mojang will adapt the [Data Components][datacomponents] system to also work with block entities sometime during the next few updates. Once that happens, both saving to NBT and data attachments will be removed in favor of data components.
:::

Of course, you will want to set other values and not just work with defaults. You can do so freely, like with any other field. However, if you want the game to save those changes, you must call `#setChanged()` afterward, which marks the block entity's chunk as dirty (= in need of being saved). If you do not call that method, the block entity might get skipped during saving, as Minecraft's saving system only saves chunks that have been marked as dirty.

## Tickers
Expand All @@ -135,11 +135,13 @@ Another very common use of block entities, often in combination with some stored
public class MyEntityBlock extends Block implements EntityBlock {
// other stuff here

@SuppressWarnings("unchecked") // Due to generics, an unchecked cast is necessary here.
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
// You can return different tickers here, depending on whatever factors you want. A common use case would be
// to return different tickers on the client or server, or only tick one side to begin with.
return type == MY_BLOCK_ENTITY.get() ? MyBlockEntity::tick : null;
// to return different tickers on the client or server, only tick one side to begin with,
// or only return a ticker for some blockstates (e.g. when using a "my machine is working" blockstate property).
return type == MY_BLOCK_ENTITY.get() ? (BlockEntityTicker<T>) MyBlockEntity::tick : null;
}
}

Expand Down Expand Up @@ -172,8 +174,6 @@ public class MyBlockEntity extends BlockEntity {
@Override
public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
CompoundTag tag = new CompoundTag();
// You can also opt to only save the data that has actually changed here.
// This makes sense especially for block entities with larger amounts of data.
saveAdditional(tag, registries);
return tag;
}
Expand Down Expand Up @@ -206,6 +206,8 @@ public class MyBlockEntity extends BlockEntity {
// Return our packet here. This method returning a non-null result tells the game to use this packet for syncing.
@Override
public Packet<ClientGamePacketListener> getUpdatePacket() {
// The packet uses the CompoundTag returned by #getUpdateTag. An alternative overload of #create exists
// that allows you to specify a custom update tag, including the ability to omit data the client might not need.
return ClientboundBlockEntityDataPacket.create(this);
}

Expand All @@ -232,7 +234,6 @@ It is important that you do safety checks, as the `BlockEntity` might already be
[block]: ../blocks/index.md
[blockstate]: ../blocks/states.md
[dataattachments]: ../datastorage/attachments.md
[datacomponents]: ../items/datacomponents.md
[nbt]: ../datastorage/nbt.md
[networking]: ../networking/index.md
[registration]: ../concepts/registries.md#methods-for-registering
Expand Down

1 comment on commit 0353445

@neoforged-pages-deployments
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploying with Cloudflare Pages

Name Result
Last commit: 03534450cda19ca1d960ae5449dd2a6375006cd2
Status: ✅ Deploy successful!
Preview URL: https://1bc80b0e.neoforged-docs-previews.pages.dev
PR Preview URL: https://pr-160.neoforged-docs-previews.pages.dev

Please sign in to comment.