Skip to content

Commit

Permalink
feat(docs): Update concepts section
Browse files Browse the repository at this point in the history
  • Loading branch information
ChampionAsh5357 committed Oct 14, 2024
1 parent ea78032 commit fdf6dc0
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 29 deletions.
22 changes: 11 additions & 11 deletions docs/concepts/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ public class YourMod {
}

// Heals an entity by half a heart every time they jump.
private static void onLivingJump(LivingJumpEvent event) {
Entity entity = event.getEntity();
private static void onLivingJump(LivingEvent.LivingJumpEvent event) {
LivingEntity entity = event.getEntity();
// Only heal on the server side
if (!entity.level().isClientSide()) {
entity.heal(1);
Expand All @@ -40,8 +40,8 @@ Alternatively, event handlers can be annotation-driven by creating an event hand
```java
public class EventHandler {
@SubscribeEvent
public void onLivingJump(LivingJumpEvent event) {
Entity entity = event.getEntity();
public void onLivingJump(LivingEvent.LivingJumpEvent event) {
LivingEntity entity = event.getEntity();
if (!entity.level().isClientSide()) {
entity.heal(1);
}
Expand All @@ -61,8 +61,8 @@ You can also do it statically. Simply make all event handlers static, and instea
```java
public class EventHandler {
@SubscribeEvent
public static void onLivingJump(LivingJumpEvent event) {
Entity entity = event.getEntity();
public static void onLivingJump(LivingEvent.LivingJumpEvent event) {
LivingEntity entity = event.getEntity();
if (!entity.level().isClientSide()) {
entity.heal(1);
}
Expand All @@ -87,8 +87,8 @@ While not required, it is highly recommended to specify the `modid` parameter in
@EventBusSubscriber(modid = "yourmodid")
public class EventHandler {
@SubscribeEvent
public static void onLivingJump(LivingJumpEvent event) {
Entity entity = event.getEntity();
public static void onLivingJump(LivingEvent.LivingJumpEvent event) {
LivingEntity entity = event.getEntity();
if (!entity.level().isClientSide()) {
entity.heal(1);
}
Expand All @@ -112,7 +112,7 @@ If you listen to an `abstract` event, your game will crash, as this is never wha

### Cancellable Events

Some events implement the `ICancellableEvent` interface. These events can be cancelled using `#setCanceled(boolean canceled)`, and the cancellation status can be checked using `#isCanceled()`. If an event is cancelled, other event handlers for this event will not run, and some kind of behavior that is associated with "cancelling" is enabled. For example, cancelling `LivingJumpEvent` will prevent the jump.
Some events implement the `ICancellableEvent` interface. These events can be cancelled using `#setCanceled(boolean canceled)`, and the cancellation status can be checked using `#isCanceled()`. If an event is cancelled, other event handlers for this event will not run, and some kind of behavior that is associated with "cancelling" is enabled. For example, cancelling `LivingChangeTargetEvent` will prevent the entity's target entity from changing.

Event handlers can opt to explicitly receive cancelled events. This is done by setting the `receiveCanceled` boolean parameter in `IEventBus#addListener` (or `@SubscribeEvent`, depending on your way of attaching the event handlers) to true.

Expand All @@ -126,7 +126,7 @@ An event with three potential return states has some `set*` method to set the de
// In some class where the listeners are subscribed to the game event bus

@SubscribeEvent
public void renderNameTag(RenderNameTagEvent event) {
public void renderNameTag(RenderNameTagEvent.CanRender event) {
// Uses TriState to set the return state
event.setCanRender(TriState.FALSE);
}
Expand Down Expand Up @@ -185,7 +185,7 @@ Then, during `InterModProcessEvent`, you can use `InterModComms#getMessages` to

Next to the lifecycle events, there are a few miscellaneous events that are fired on the mod event bus, mostly for legacy reasons. These are generally events where you can register, set up, or initialize various things. Most of these events are not ran in parallel in contrast to the lifecycle events. A few examples:

- `RegisterColorHandlersEvent`
- `RegisterColorHandlersEvent.Block`, `.Item`, `.ColorResolvers`
- `ModelEvent.BakingCompleted`
- `TextureAtlasStitchedEvent`

Expand Down
63 changes: 45 additions & 18 deletions docs/concepts/registries.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,49 @@ public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(
);
```

We can then add our registry entries as static final fields (see [the article on Blocks][block] for what parameters to add in `new Block()`):
We can then add our registry entries as static final fields using one of the following methods (see [the article on Blocks][block] for what parameters to add in `new Block()`):

```java
public static final DeferredHolder<Block, Block> EXAMPLE_BLOCK = BLOCKS.register(
"example_block" // Our registry name.
() -> new Block(...) // A supplier of the object we want to register.
public static final DeferredHolder<Block, Block> EXAMPLE_BLOCK_1 = BLOCKS.register(
// Our registry name.
"example_block"
// A supplier of the object we want to register.
() -> new Block(...)
);

public static final DeferredHolder<Block, SlabBlock> EXAMPLE_BLOCK_2 = BLOCKS.register(
// Our registry name.
"example_block"
// A function creating the object we want to register
// given its registry name as a ResourceLocation.
registryName -> new SlabBlock(...)
);
```

The class `DeferredHolder<R, T extends R>` holds our object. The type parameter `R` is the type of the registry we are registering to (in our case `Block`). The type parameter `T` is the type of our supplier. Since we directly register a `Block` in this example, we provide `Block` as the second parameter. If we were to register an object of a subclass of `Block`, for example `SlabBlock`, we would provide `SlabBlock` here instead.
The class `DeferredHolder<R, T extends R>` holds our object. The type parameter `R` is the type of the registry we are registering to (in our case `Block`). The type parameter `T` is the type of our supplier. Since we directly register a `Block` in the first example, we provide `Block` as the second parameter. If we were to register an object of a subclass of `Block`, for example `SlabBlock` (as shown in the second example), we would provide `SlabBlock` here instead.

`DeferredHolder<R, T extends R>` is a subclass of `Supplier<T>`. To get our registered object when we need it, we can call `DeferredHolder#get()`. The fact that `DeferredHolder` extends `Supplier` also allows us to use `Supplier` as the type of our field. That way, the above code block becomes the following:

```java
public static final Supplier<Block> EXAMPLE_BLOCK = BLOCKS.register(
"example_block" // Our registry name.
() -> new Block(...) // A supplier of the object we want to register.
public static final Supplier<Block> EXAMPLE_BLOCK_1 = BLOCKS.register(
// Our registry name.
"example_block"
// A supplier of the object we want to register.
() -> new Block(...)
);

public static final Supplier<SlabBlock> EXAMPLE_BLOCK_2 = BLOCKS.register(
// Our registry name.
"example_block"
// A function creating the object we want to register
// given its registry name as a ResourceLocation.
registryName -> new SlabBlock(...)
);
```

:::note
Be aware that a few places explicitly require a `Holder` or `DeferredHolder` and will not just accept any `Supplier`. If you need either of those two, it is best to change the type of your `Supplier` back to `Holder` or `DeferredHolder` as necessary.
:::

Finally, since the entire system is a wrapper around registry events, we need to tell the `DeferredRegister` to attach itself to the registry events as needed:

Expand All @@ -72,7 +94,7 @@ public ExampleMod(IEventBus modBus) {
```

:::info
There are specialized variants of `DeferredRegister`s for blocks and items that provide helper methods, called [`DeferredRegister.Blocks`][defregblocks] and [`DeferredRegister.Items`][defregitems], respectively.
There are specialized variants of `DeferredRegister`s for blocks, items, and data components that provide helper methods: [`DeferredRegister.Blocks`][defregblocks], [`DeferredRegister.Items`][defregitems], and [`DeferredRegister.DataComponents`][defregcomp], respectively.
:::

### `RegisterEvent`
Expand Down Expand Up @@ -102,11 +124,11 @@ public void register(RegisterEvent event) {
Sometimes, you will find yourself in situations where you want to get a registered object by a given id. Or, you want to get the id of a certain registered object. Since registries are basically maps of ids (`ResourceLocation`s) to distinct objects, i.e. a reversible map, both of these operations work:

```java
BuiltInRegistries.BLOCKS.get(ResourceLocation.fromNamespaceAndPath("minecraft", "dirt")); // returns the dirt block
BuiltInRegistries.BLOCKS.getValue(ResourceLocation.fromNamespaceAndPath("minecraft", "dirt")); // returns the dirt block
BuiltInRegistries.BLOCKS.getKey(Blocks.DIRT); // returns the resource location "minecraft:dirt"

// Assume that ExampleBlocksClass.EXAMPLE_BLOCK.get() is a Supplier<Block> with the id "yourmodid:example_block"
BuiltInRegistries.BLOCKS.get(ResourceLocation.fromNamespaceAndPath("yourmodid", "example_block")); // returns the example block
BuiltInRegistries.BLOCKS.getValue(ResourceLocation.fromNamespaceAndPath("yourmodid", "example_block")); // returns the example block
BuiltInRegistries.BLOCKS.getKey(ExampleBlocksClass.EXAMPLE_BLOCK.get()); // returns the resource location "yourmodid:example_block"
```

Expand Down Expand Up @@ -172,7 +194,7 @@ static void registerRegistries(NewRegistryEvent event) {
You can now register new registry contents like with any other registry, through both `DeferredRegister` and `RegisterEvent`:

```java
public static final DeferredRegister<Spell> SPELLS = DeferredRegister.create("yourmodid", SPELL_REGISTRY);
public static final DeferredRegister<Spell> SPELLS = DeferredRegister.create(SPELL_REGISTRY, "yourmodid");
public static final Supplier<Spell> EXAMPLE_SPELL = SPELLS.register("example_spell", () -> new Spell(...));

// Alternatively:
Expand Down Expand Up @@ -228,10 +250,10 @@ First, we create a `RegistrySetBuilder` and add our entries to it (one `Registry
```java
new RegistrySetBuilder()
.add(Registries.CONFIGURED_FEATURE, bootstrap -> {
// Register configured features through the bootstrap context (see below)
// Register configured features through the bootstrap context (see below)
})
.add(Registries.PLACED_FEATURE, bootstrap -> {
// Register placed features through the bootstrap context (see below)
// Register placed features through the bootstrap context (see below)
});
```

Expand All @@ -254,7 +276,7 @@ new RegistrySetBuilder()
);
})
.add(Registries.PLACED_FEATURE, bootstrap -> {
// ...
// ...
});
```

Expand Down Expand Up @@ -287,8 +309,8 @@ Finally, we use our `RegistrySetBuilder` in an actual data provider, and registe

```java
@SubscribeEvent
static void onGatherData(GatherDataEvent event) {
event.getGenerator().addProvider(
public static void onGatherData(GatherDataEvent event) {
CompletableFuture<HolderLookup.Provider> lookupProvider = event.getGenerator().addProvider(
// Only run datapack generation when server data is being generated
event.includeServer(),
// Create the provider
Expand All @@ -300,7 +322,11 @@ static void onGatherData(GatherDataEvent event) {
// A set of mod ids we are generating. Usually only your own mod id.
Set.of("yourmodid")
)
);
).getRegistryProvider();

// Use the lookup provider generated from your datapack entries as input
// to all other data providers.
// ...
}
```

Expand All @@ -311,6 +337,7 @@ static void onGatherData(GatherDataEvent event) {
[datagenindex]: ../resources/index.md#data-generation
[datapack]: ../resources/index.md#data
[defregblocks]: ../blocks/index.md#deferredregisterblocks-helpers
[defregcomp]: ../items/datacomponents.md#creating-custom-data-components
[defregitems]: ../items/index.md#deferredregisteritems
[event]: ./events.md
[item]: ../items/index.md
Expand Down

1 comment on commit fdf6dc0

@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: fdf6dc050b6145d9b079936d26379f14af31cbae
Status: ✅ Deploy successful!
Preview URL: https://0bf99d0d.neoforged-docs-previews.pages.dev
PR Preview URL: https://pr-178.neoforged-docs-previews.pages.dev

Please sign in to comment.