Skip to content

Commit

Permalink
feat: Add 1.20.5 base and fix broken links
Browse files Browse the repository at this point in the history
  • Loading branch information
ahaim5357 committed Apr 24, 2024
1 parent 6369904 commit 1a734ab
Show file tree
Hide file tree
Showing 79 changed files with 9,727 additions and 16 deletions.
6 changes: 3 additions & 3 deletions docs/datagen/advancements.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,6 @@ Advancement example = Advancement.Builder.advancement()
.save(writer, name, existingFileHelper); // Add data to builder
```

[advancements]: ../../resources/server/advancements.md
[datagen]: ../index.md#data-providers
[conditional]: ../../resources/server/conditional.md
[advancements]: ../resources/server/advancements.md
[datagen]: ../resources/index.md#data-generation
[conditional]: ../resources/server/conditional.md
6 changes: 3 additions & 3 deletions docs/datagen/glm.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ this.add("example_modifier", new ExampleModifier(
));
```

[glm]: ../../resources/server/glm.md
[instance]: ../../resources/server/glm.md#igloballootmodifier
[datagen]: ../index.md#data-providers
[glm]: ../resources/server/glm.md
[instance]: ../resources/server/glm.md#igloballootmodifier
[datagen]: ../resources/index.md#data-generation
6 changes: 3 additions & 3 deletions docs/datagen/loottables.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,6 @@ Number providers determine how many times a loot pool executes. Each provider ha
Scoreboard providers are a special type of number providers defined by `ScoreboardValue`. They define the name of the scoreboard to pull the number of rolls to execute from. Each provider has an associated, [registered] `LootScoreProviderType`.
[loottable]: ../../resources/server/loottables.md
[datagen]: ../index.md#data-providers
[registered]: ../../concepts/registries.md
[loottable]: ../resources/server/loottables.md
[datagen]: ../resources/index.md#data-generation
[registered]: ../concepts/registries.md
8 changes: 4 additions & 4 deletions docs/datagen/recipes.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ Custom recipe serializers can be data generated by creating a builder that can c
`FinishedRecipe`s are flexible enough that any object transformation can be data generated, not just items.
:::
[datagen]: ../index.md#data-providers
[ingredients]: ../../resources/server/recipes/ingredients.md#forge-types
[stack]: ../../resources/server/recipes/index.md#recipe-itemstack-result
[conditional]: ../../resources/server/conditional.md
[datagen]: ../resources/index.md#data-generation
[ingredients]: ../resources/server/recipes/ingredients.md#forge-types
[stack]: ../resources/server/recipes/index.md#recipe-itemstack-result
[conditional]: ../resources/server/conditional.md
[special]: #specialrecipebuilder
6 changes: 3 additions & 3 deletions docs/datagen/tags.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,6 @@ public AttributeTagsProvider(PackOutput output, CompletableFuture<HolderLookup.P
}
```

[tags]: ../../resources/server/tags.md
[datagen]: ../index.md#data-providers
[custom]: ../../concepts/registries.md#custom-registries
[tags]: ../resources/server/tags.md
[datagen]: ../resources/index.md#data-generation
[custom]: ../concepts/registries.md#custom-registries
3 changes: 3 additions & 0 deletions versioned_docs/version-1.20.4/advanced/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"label": "Advanced Topics"
}
158 changes: 158 additions & 0 deletions versioned_docs/version-1.20.4/advanced/accesstransformers.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Access Transformers

Access Transformers (ATs for short) allow for widening the visibility and modifying the `final` flags of classes, methods, and fields. They allow modders to access and modify otherwise inaccessible members in classes outside their control.

The [specification document][specs] can be viewed on the NeoForged GitHub.

## Adding ATs

Adding an Access Transformer to your mod project is as simple as adding a single line into your `build.gradle`:

<Tabs defaultValue="latest">
<TabItem value="latest" label="Latest">
Access Transformers need to be declared in both `build.gradle` and `mods.toml`:

```groovy
// In build.gradle:
// This block is where your mappings version is also specified
minecraft {
accessTransformers {
file('src/main/resources/META-INF/accesstransformer.cfg')
}
}
```

```toml
# In mods.toml:
[[accessTransformers]]
file="META-INF/accesstransformer.cfg"
```

AT files can be anywhere specified by the lines above, though NeoForge will default to searching for `META-INF/accesstransformer.cfg` if no other file is specified.

Additionally, multiple AT files can be specified and will be applied in order. This can be useful for larger mods with multiple packages.

```groovy
// In build.gradle:
minecraft {
accessTransformers {
file('src/main/resources/accesstransformer_main.cfg')
file('src/additions/resources/accesstransformer_additions.cfg')
}
}
```

```toml
# In mods.toml
[[accessTransformers]]
file="accesstransformer_main.cfg"

[[accessTransformers]]
file="accesstransformer_additions.cfg"
```

After adding or modifying any Access Transformer, the Gradle project must be refreshed for the transformations to take effect.
</TabItem>

<TabItem value="1.20.1" label="1.20.1-47.1 and older">
Adding an Access Transformer to your mod project is as simple as adding a single line into your `build.gradle`:

```groovy
// This block is where your mappings version is also specified
minecraft {
accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
}
```

During development, the AT file can be anywhere specified by the line above. However, when loading in a non-development environment, NeoForge will only search for the exact path of `META-INF/accesstransformer.cfg` in your JAR file.

After adding or modifying the Access Transformer, the Gradle project must be refreshed for the transformations to take effect.
</TabItem>
</Tabs>

## Comments

All text after a `#` until the end of the line will be treated as a comment and will not be parsed.

## Access Modifiers

Access modifiers specify to what new member visibility the given target will be transformed to. In decreasing order of visibility:

* `public` - visible to all classes inside and outside its package
* `protected` - visible only to classes inside the package and subclasses
* `default` - visible only to classes inside the package
* `private` - visible only to inside the class

A special modifier `+f` and `-f` can be appended to the aforementioned modifiers to either add or remove respectively the `final` modifier, which prevents subclassing, method overriding, or field modification when applied.

:::danger
Directives only modify the method they directly reference; any overriding methods will not be access-transformed. It is advised to ensure transformed methods do not have non-transformed overrides that restrict the visibility, which will result in the JVM throwing an error.

Examples of methods that can be safely transformed are `private` methods, `final` methods (or methods in `final` classes), and `static` methods.
:::

## Targets and Directives

### Classes
To target classes:
```
<access modifier> <fully qualified class name>
```
Inner classes are denoted by combining the fully qualified name of the outer class and the name of the inner class with a `$` as separator.

### Fields
To target fields:
```
<access modifier> <fully qualified class name> <field name>
```

### Methods
Targeting methods require a special syntax to denote the method parameters and return type:
```
<access modifier> <fully qualified class name> <method name>(<parameter types>)<return type>
```

#### Specifying Types

Also called "descriptors": see the [Java Virtual Machine Specification, SE 8, sections 4.3.2 and 4.3.3][jvmdescriptors] for more technical details.

* `B` - `byte`, a signed byte
* `C` - `char`, a Unicode character code point in UTF-16
* `D` - `double`, a double-precision floating-point value
* `F` - `float`, a single-precision floating-point value
* `I` - `integer`, a 32-bit integer
* `J` - `long`, a 64-bit integer
* `S` - `short`, a signed short
* `Z` - `boolean`, a `true` or `false` value
* `[` - references one dimension of an array
* Example: `[[S` refers to `short[][]`
* `L<class name>;` - references a reference type
* Example: `Ljava/lang/String;` refers to `java.lang.String` reference type _(note the use of slashes instead of periods)_
* `(` - references a method descriptor, parameters should be supplied here or nothing if no parameters are present
* Example: `<method>(I)Z` refers to a method that requires an integer argument and returns a boolean
* `V` - indicates a method returns no value, can only be used at the end of a method descriptor
* Example: `<method>()V` refers to a method that has no arguments and returns nothing

## Examples

```
# Makes public the ByteArrayToKeyFunction interface in Crypt
public net.minecraft.util.Crypt$ByteArrayToKeyFunction
# Makes protected and removes the final modifier from 'random' in MinecraftServer
protected-f net.minecraft.server.MinecraftServer random
# Makes public the 'makeExecutor' method in Util,
# accepting a String and returns an ExecutorService
public net.minecraft.Util makeExecutor(Ljava/lang/String;)Ljava/util/concurrent/ExecutorService;
# Makes public the 'leastMostToIntArray' method in UUIDUtil,
# accepting two longs and returning an int[]
public net.minecraft.core.UUIDUtil leastMostToIntArray(JJ)[I
```

[specs]: https://github.com/NeoForged/AccessTransformers/blob/main/FMLAT.md
[jvmdescriptors]: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.2
28 changes: 28 additions & 0 deletions versioned_docs/version-1.20.4/blockentities/ber.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
BlockEntityRenderer
==================

A `BlockEntityRenderer` or `BER` is used to render blocks in a way that cannot be represented with a static baked model (JSON, OBJ, B3D, others). A block entity renderer requires the block to have a `BlockEntity`.

Creating a BER
--------------

To create a BER, create a class that inherits from `BlockEntityRenderer`. It takes a generic argument specifying the block's `BlockEntity` class. The generic argument is used in the BER's `render` method.

Only one BER exists for a given `BlockEntityType`. Therefore, values that are specific to a single instance in the level should be stored in the block entity being passed to the renderer rather than in the BER itself. For example, an integer that increments every frame, if stored in the BER, will increment every frame for every block entity of this type in the level.

### `render`

This method is called every frame in order to render the block entity.

#### Parameters
* `blockEntity`: This is the instance of the block entity being rendered.
* `partialTick`: The amount of time, in fractions of a tick, that has passed since the last full tick.
* `poseStack`: A stack holding four-dimensional matrix entries offset to the current position of the block entity.
* `bufferSource`: A rendering buffer able to access a vertex consumer.
* `combinedLight`: An integer of the current light value on the block entity.
* `combinedOverlay`: An integer set to the current overlay of the block entity, usually `OverlayTexture#NO_OVERLAY` or 655,360.

Registering a BER
-----------------

In order to register a BER, you must subscribe to the `EntityRenderersEvent$RegisterRenderers` event on the mod event bus and call `#registerBlockEntityRenderer`.
146 changes: 146 additions & 0 deletions versioned_docs/version-1.20.4/blockentities/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
Block Entities
======

`BlockEntities` are like simplified `Entities` that are bound to a Block.
They are used to store dynamic data, execute tick based tasks, and dynamic rendering.
Some examples from vanilla Minecraft would be handling of inventories on chests, smelting logic on furnaces, or area effects on beacons.
More advanced examples exist in mods, such as quarries, sorting machines, pipes, and displays.

:::note
`BlockEntities` aren't a solution for everything and they can cause lag when used wrongly.
When possible, try to avoid them.
:::

## Registering

Block Entities are created and removed dynamically and as such are not registry objects on their own.

In order to create a `BlockEntity`, you need to extend the `BlockEntity` class. As such, another object is registered instead to easily create and refer to the *type* of the dynamic object. For a `BlockEntity`, these are known as `BlockEntityType`s.

A `BlockEntityType` can be [registered][registration] like any other registry object. To construct a `BlockEntityType`, its builder form can be used via `BlockEntityType$Builder#of`. This takes in two arguments: a `BlockEntityType$BlockEntitySupplier` which takes in a `BlockPos` and `BlockState` to create a new instance of the associated `BlockEntity`, and a varargs of `Block`s which this `BlockEntity` can be attached to. Building the `BlockEntityType` is done by calling `BlockEntityType$Builder#build`. This takes in a `Type` which represents the type-safe reference used to refer to this registry object in a `DataFixer`. Since `DataFixer`s are an optional system to use for mods, this can be passed as `null`.

```java
// For some DeferredRegister<BlockEntityType<?>> REGISTER
public static final RegistryObject<BlockEntityType<MyBE>> MY_BE = REGISTER.register("mybe", () -> BlockEntityType.Builder.of(MyBE::new, validBlocks).build(null));

// In MyBE, a BlockEntity subclass
public MyBE(BlockPos pos, BlockState state) {
super(MY_BE.get(), pos, state);
}
```

## Creating a `BlockEntity`

To create a `BlockEntity` and attach it to a `Block`, the `EntityBlock` interface must be implemented on your `Block` subclass. The method `EntityBlock#newBlockEntity(BlockPos, BlockState)` must be implemented and return a new instance of your `BlockEntity`.

## Storing Data within your `BlockEntity`

In order to save data, override the following two methods:
```java
BlockEntity#saveAdditional(CompoundTag tag)

BlockEntity#load(CompoundTag tag)
```
These methods are called whenever the `LevelChunk` containing the `BlockEntity` gets loaded from/saved to a tag.
Use them to read and write to the fields in your block entity class.

:::note
Whenever your data changes, you need to call `BlockEntity#setChanged`; otherwise, the `LevelChunk` containing your `BlockEntity` might be skipped while the level is saved.
:::

:::danger
It is important that you call the `super` methods!

The tag names `id`, `x`, `y`, `z`, `ForgeData` and `ForgeCaps` are reserved by the `super` methods.
:::

## Ticking `BlockEntities`

If you need a ticking `BlockEntity`, for example to keep track of the progress during a smelting process, another method must be implemented and overridden within `EntityBlock`: `EntityBlock#getTicker(Level, BlockState, BlockEntityType)`. This can implement different tickers depending on which logical side the user is on, or just implement one general ticker. In either case, a `BlockEntityTicker` must be returned. Since this is a functional interface, it can just take in a method representing the ticker instead:

```java
// Inside some Block subclass
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
return type == MyBlockEntityTypes.MYBE.get() ? MyBlockEntity::tick : null;
}

// Inside MyBlockEntity
public static void tick(Level level, BlockPos pos, BlockState state, MyBlockEntity blockEntity) {
// Do stuff
}
```

:::note
This method is called each tick; therefore, you should avoid having complicated calculations in here. If possible, you should make more complex calculations every X ticks. (The amount of ticks in a second may be lower then 20 (twenty) but won't be higher)
:::
## Synchronizing the Data to the Client
There are three ways of syncing data to the client: synchronizing on chunk load, on block updates, and with a custom network message.
### Synchronizing on LevelChunk Load
For this you need to override
```java
BlockEntity#getUpdateTag()
IForgeBlockEntity#handleUpdateTag(CompoundTag tag)
```
Again, this is pretty simple, the first method collects the data that should be sent to the client,
while the second one processes that data. If your `BlockEntity` doesn't contain much data, you might be able to use the methods out of the [Storing Data within your `BlockEntity`][storing-data] section.

:::caution
Synchronizing excessive/useless data for block entities can lead to network congestion. You should optimize your network usage by sending only the information the client needs when the client needs it. For instance, it is more often than not unnecessary to send the inventory of a block entity in the update tag, as this can be synchronized via its [`AbstractContainerMenu`][menu].
:::

### Synchronizing on Block Update

This method is a bit more complicated, but again you just need to override two or three methods.
Here is a tiny example implementation of it:
```java
@Override
public CompoundTag getUpdateTag() {
CompoundTag tag = new CompoundTag();
//Write your data into the tag
return tag;
}

@Override
public Packet<ClientGamePacketListener> getUpdatePacket() {
// Will get tag from #getUpdateTag
return ClientboundBlockEntityDataPacket.create(this);
}

// Can override IForgeBlockEntity#onDataPacket. By default, this will defer to the #load.
```
The static constructors `ClientboundBlockEntityDataPacket#create` takes:

* The `BlockEntity`.
* An optional function to get the `CompoundTag` from the `BlockEntity`. By default, this uses `BlockEntity#getUpdateTag`.

Now, to send the packet, an update notification must be given on the server.
```java
Level#sendBlockUpdated(BlockPos pos, BlockState oldState, BlockState newState, int flags)
```
The `pos` should be your `BlockEntity`'s position.
For `oldState` and `newState`, you can pass the current `BlockState` at that position.
`flags` is a bitmask that should contain `2`, which will sync the changes to the client. See `Block` for more info as well as the rest of the flags. The flag `2` is equivalent to `Block#UPDATE_CLIENTS`.
### Synchronizing Using a Custom Network Message
This way of synchronizing is probably the most complicated but is usually the most optimized,
as you can make sure that only the data you need to be synchronized is actually synchronized.
You should first check out the [`Networking`][networking] section and especially [`SimpleImpl`][simple_impl] before attempting this.
Once you've created your custom network message, you can send it to all users that have the `BlockEntity` loaded with `SimpleChannel#send(PacketDistributor$PacketTarget, MSG)`.

:::caution
It is important that you do safety checks, the `BlockEntity` might already be destroyed/replaced when the message arrives at the player! You should also check if the chunk is loaded (`Level#hasChunkAt(BlockPos)`).
:::

[registration]: ../concepts/registries.md#methods-for-registering
[storing-data]: #storing-data-within-your-blockentity
[menu]: ../gui/menus.md
[networking]: ../networking/index.md
[simple_impl]: ../networking/simpleimpl.md
Loading

1 comment on commit 1a734ab

@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: 1a734ab402c51939d6e0b1aca4daef6a2f7148dc
Status: ✅ Deploy successful!
Preview URL: https://b4ba2b23.neoforged-docs-previews.pages.dev
PR Preview URL: https://pr-65.neoforged-docs-previews.pages.dev

Please sign in to comment.