Skip to content

Commit

Permalink
implement most of XFact's feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
IchHabeHunger54 committed Feb 23, 2024
1 parent e2fbc31 commit 40c17a9
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 17 deletions.
2 changes: 1 addition & 1 deletion docs/concepts/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Results are deprecated and will be replaced by more specific per-event results s

### Priority

Event handlers can optionally get assigned a priority. The `EventPriority` enum contains five values: `HIGHEST`, `HIGH`, `NORMAL` (default), `LOW` and `LOWEST`. Events are executed from highest to lowest priority, with undefined order for two events of the same priority.
Event handlers can optionally get assigned a priority. The `EventPriority` enum contains five values: `HIGHEST`, `HIGH`, `NORMAL` (default), `LOW` and `LOWEST`. Event handlers are executed from highest to lowest priority. If they have the same priority, they fire in registration order on the main bus, which is roughly related to mod load order, and in exact mod load order on the mod bus (see below).

Priorities can be defined by setting the `priority` parameter in `IEventBus#addListener` or `@SubscribeEvent`, depending on how you attach event handlers. Note that priorities are ignored for events that are fired in parallel.

Expand Down
17 changes: 9 additions & 8 deletions docs/concepts/registries.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The main reason all of this works is that `Blocks` is classloaded early enough b

## Methods for Registering

NeoForge offers two ways to register objects: the `DeferredRegister` class, and the `RegisterEvent`. Note that the former is a wrapper around the latter, and is thus recommended in order to prevent mistakes.
NeoForge offers two ways to register objects: the `DeferredRegister` class, and the `RegisterEvent`. Note that the former is a wrapper around the latter, and is recommended in order to prevent mistakes.

### `DeferredRegister`

Expand Down Expand Up @@ -85,8 +85,9 @@ There are specialized variants of `DeferredRegister`s for blocks and items that
public void register(RegisterEvent event) {
event.register(
// This is the registry key of the registry.
// Get these from Registries for vanilla registries, or from NeoForgeRegistries.Keys for NeoForge registries.
Registries.BLOCKS,
// Get these from BuiltInRegistries for vanilla registries,
// or from NeoForgeRegistries.Keys for NeoForge registries.
BuiltInRegistries.BLOCKS,
// Register your objects here.
registry -> {
registry.register(new ResourceLocation(MODID, "example_block_1"), new Block(...));
Expand All @@ -102,12 +103,12 @@ 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
Registries.BLOCKS.get(new ResourceLocation("minecraft", "dirt")); // returns the dirt block
Registries.BLOCKS.getKey(Blocks.DIRT); // returns the resource location "minecraft:dirt"
BuiltInRegistries.BLOCKS.get(new ResourceLocation("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"
Registries.BLOCKS.get(new ResourceLocation("yourmodid", "example_block")); // returns the example block
Registries.BLOCKS.getKey(ExampleBlocksClass.EXAMPLE_BLOCK.get()); // returns the resource location "yourmodid:example_block"
BuiltInRegistries.BLOCKS.get(new ResourceLocation("yourmodid", "example_block")); // returns the example block
BuiltInRegistries.BLOCKS.getKey(ExampleBlocksClass.EXAMPLE_BLOCK.get()); // returns the resource location "yourmodid:example_block"
```

If you just want to check for the presence of an object, this is also possible, though only with keys:
Expand All @@ -131,7 +132,7 @@ for (Map.Entry<ResourceLocation, Block> entry : Registries.BLOCKS.entrySet()) {
```

:::note
Query operations should always use vanilla `Registry`s, not `DeferredRegister`s. This is because `DeferredRegister`s are merely registration utilities and effectively do not exist after registration has finished.
Query operations always use vanilla `Registry`s, not `DeferredRegister`s. This is because `DeferredRegister`s are merely registration utilities.
:::

:::danger
Expand Down
2 changes: 1 addition & 1 deletion docs/concepts/sides.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The logical side is mainly focused on the internal program structure of Minecraf

The difference between physical and logical sides is best exemplified by two scenarios:

- The player joins a **multiplayer** world. This is fairly straightforward: The player's logical and physical client connects to a logical server somewhere else - the player does not care where; so long as they can connect, that's all the client knows of, and all the client needs to know.
- The player joins a **multiplayer** world. This is fairly straightforward: The player's physical (and logical) client connects to a physical (and logical) server somewhere else - the player does not care where; so long as they can connect, that's all the client knows of, and all the client needs to know.
- The player joins a **singleplayer** world. This is where things get interesting. The player's physical client spins up a logical server and then, now in the role of the logical client, connects to that logical server on the same machine. If you are familiar with networking, you can think of it as a connection to `localhost` (only conceptually; there are no actual sockets or similar involved).

These two scenarios also show the main problem with this: If a logical server can work with your code, that alone doesn't guarantee that a physical server will be able to work with as well. This is why you should always test with dedicated servers to check for unexpected behavior. `NoClassDefFoundError`s and `ClassNotFoundException`s due to incorrect client and server separation are among the most common errors there are in modding. Another common mistake is working with static fields and accessing them from both logical sides; this is particularly tricky because there's usually no indication that something is wrong.
Expand Down
8 changes: 4 additions & 4 deletions docs/items/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,21 @@ public static final Supplier<Item> EXAMPLE_ITEM = ITEMS.registerItem(

Internally, this will simply call `ITEMS.register("example_item", () -> new Item(new Item.Properties()))` by applying the properties parameter to the provided item factory (which is commonly the constructor).

If you want to use `Item::new`, you can leave out the factory entirely:
If you want to use `Item::new`, you can leave out the factory entirely and use the `simple` method variant:

```java
public static final Supplier<Item> EXAMPLE_ITEM = ITEMS.registerItem(
public static final Supplier<Item> EXAMPLE_ITEM = ITEMS.registerSimpleItem(
"example_item",
new Item.Properties() // The properties to use.
);
```

This does the exact same as the previous example, but is slightly shorter. Of course, if you want to use a subclass of `Item` and not `Item` itself, you will have to use the previous method instead.

Both of these methods also have `simple` counterparts that omit the `new Item.Properties()` parameter:
Both of these methods also have overloads that omit the `new Item.Properties()` parameter:

```java
public static final Supplier<Item> EXAMPLE_ITEM = ITEMS.registerSimpleItem("example_item", Item::new);
public static final Supplier<Item> EXAMPLE_ITEM = ITEMS.registerItem("example_item", Item::new);
// Variant that also omits the Item::new parameter
public static final Supplier<Item> EXAMPLE_ITEM = ITEMS.registerSimpleItem("example_item");
```
Expand Down
8 changes: 5 additions & 3 deletions docs/misc/resourcelocation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

`ResourceLocation`s are one of the most important things in Minecraft. They are used as keys in [registries][registries], as identifiers for data or resource files, as references to models in code, and in a lot of other places. A `ResourceLocation` consists of two parts: a namespace and a path, separated by a `:`.

The namespace denotes what mod or datapack the location refers to. For example, a mod with the mod id `examplemod` will use the `examplemod` namespace. Minecraft uses the `minecraft` namespace. Extra namespaces can be defined at will simply by creating a corresponding data folder, this is usually done by datapacks to keep their logic separate from the point where they integrate with vanilla.
The namespace denotes what mod, resource pack or datapack the location refers to. For example, a mod with the mod id `examplemod` will use the `examplemod` namespace. Minecraft uses the `minecraft` namespace. Extra namespaces can be defined at will simply by creating a corresponding data folder, this is usually done by datapacks to keep their logic separate from the point where they integrate with vanilla.

The path is a reference to whatever object you want, inside your namespace. For example, `minecraft:cow` is a reference to something named `cow` in the `minecraft` namespace - usually this location would be used to get the cow entity from the entity registry. Another example would be `examplemod:example_item`, which would probably be used to get your mod's `example_item` from the item registry.

Expand All @@ -23,14 +23,14 @@ The namespace and path of a `ResourceLocation` can be retrieved using `ResourceL
Some places, for example registries, use `ResourceLocation`s directly. Some other places, however, will resolve the `ResourceLocation` as needed. For example:

- `ResourceLocation`s are used as identifiers for GUI background. For example, the furnace GUI uses the resource location `minecraft:textures/gui/container/furnace.png`. This maps to the file `assets/minecraft/textures/gui/container/furnace.png` on disk. Note that the `.png` suffix is required in this resource location.
- `ResourceLocation`s are used as identifiers for block models. For example, the block model of dirt uses the resource location `minecraft:models/block/dirt`. This maps to the file `assets/minecraft/models/block/dirt.json` on disk. Note that the `.json` suffix is NOT required in this resource location.
- `ResourceLocation`s are used as identifiers for block models. For example, the block model of dirt uses the resource location `minecraft:block/dirt`. This maps to the file `assets/minecraft/models/block/dirt.json` on disk. Note that the `.json` suffix is not required here. Note as well that this resource location automatically maps into the `models` subfolder.
- `ResourceLocation`s are used as identifiers for recipes. For example, the iron block crafting recipe uses the resource location `minecraft:iron_block`. This maps to the file `data/minecraft/recipes/iron_block.json` on disk. Note that the `.json` suffix is not required here. Note as well that this resource location automatically maps into the `recipes` subfolder.

Whether the `ResourceLocation` expects a file suffix, or what exactly the resource location resolves to, depends on the use case.

## `ModelResourceLocation`s

`ModelResourceLocation`s are a special kind of resource location that includes a third part, called the variant. Minecraft uses these mainly to differentiate between different variants of item models, where the different variants are used in different display contexts (for example with tridents, which have different models in first person, third person and inventories).
`ModelResourceLocation`s are a special kind of resource location that includes a third part, called the variant. Minecraft uses these mainly to differentiate between different variants of models, where the different variants are used in different display contexts (for example with tridents, which have different models in first person, third person and inventories). The variant is always `inventory` for items, and the comma-delimited string of property-value pairs for blockstates (for example `facing=north,waterlogged=false`, empty for blocks with no blockstate properties).

The variant is appended to the regular resource location, along with a `#`. For example, the full name of the diamond sword's item model is `minecraft:diamond_sword#inventory`. However, in most contexts, the `inventory` variant can be omitted.

Expand All @@ -42,5 +42,7 @@ The variant is appended to the regular resource location, along with a `#`. For

A new `ResourceKey` can be created through the static method `ResourceKey#create(ResourceKey<? extends Registry<T>>, ResourceLocation)`. The second parameter here is the registry name, while the first parameter is what is known as a registry key. Registry keys are a special kind of `ResourceKey` whose registry is the root registry (i.e. the registry of all other registries). A registry key can be created via `ResourceKey#createRegistryKey(ResourceLocation)` with the desired registry's id.

`ResourceKey`s are interned at creation. This means that comparing by reference equality (`==`) is possible and encouraged, but their creation is comparatively expensive.

[registries]: ../concepts/registries.md
[sides]: ../concepts/sides.md

1 comment on commit 40c17a9

@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: 40c17a949a53cbcf89b23c543310023ebaa4d5f5
Status: ✅ Deploy successful!
Preview URL: https://bdf62611.neoforged-docs-previews.pages.dev
PR Preview URL: https://pr-48.neoforged-docs-previews.pages.dev

Please sign in to comment.