Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export default defineVersionedConfig(

// Versioning plugin configuration.
versioning: {
latestVersion: "1.21.8",
latestVersion: "1.21.10",
rewrites: {
localePrefix: "translated",
},
Expand Down
8 changes: 4 additions & 4 deletions .vitepress/sidebars/develop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,10 @@ export default [
text: "develop.rendering.hud",
link: "/develop/rendering/hud",
},
{
text: "develop.rendering.world",
link: "/develop/rendering/world",
},
// {
// text: "develop.rendering.world",
// link: "/develop/rendering/world",
// },
{
text: "develop.rendering.gui",
items: [
Expand Down
2 changes: 1 addition & 1 deletion .vitepress/theme/components/VersionReminder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { computed } from "vue";

const data = useData();
const route = useRoute();
const LATEST = "1.21.8";
const LATEST = "1.21.10";

const path = computed(() => route.path);
const text = computed(() => data.theme.value.version.reminder as string);
Expand Down
26 changes: 21 additions & 5 deletions develop/blocks/block-entity-renderer.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,33 @@ For example, let's make the Counter Block from the [Block Entities article](../b

## Creating a BlockEntityRenderer {#creating-a-blockentityrenderer}

First, we need to create a `BlockEntityRenderer` for our `CounterBlockEntity`.
Block entity rendering uses a submit/render system where you first submit the data required to render an object to the screen, the game then renders the object using it's submitted state.

When creating a `BlockEntityRenderer` for the `CounterBlockEntity`, it's important to place the class in the appropriate source set, such as `src/client/`, if your project uses split source sets for client and server. Accessing rendering-related classes directly in the `src/main/` source set is not safe because those classes might be loaded on a server.

First, we need to create a `BlockEntityRenderState` for our `CounterBlockEntity` to hold the data that will be used for rendering. In this case, we will need the `clicks` to be available during rendering.

@[code transcludeWith=::render-state](@/reference/latest/src/client/java/com/example/docs/rendering/blockentity/CounterBlockEntityRenderState.java)

Then we create a `BlockEntityRenderer` for our `CounterBlockEntity`.

@[code transcludeWith=:::1](@/reference/latest/src/client/java/com/example/docs/rendering/blockentity/CounterBlockEntityRenderer.java)

The new class has a constructor with `BlockEntityRendererFactory.Context` as a parameter. The `Context` has a few useful rendering utilities, like the `ItemRenderer` or `TextRenderer`.
Also, by including a constructor like this, it becomes possible to use the constructor as the `BlockEntityRendererFactory` functional interface itself:

@[code transcludeWith=:::1](@/reference/latest/src/client/java/com/example/docs/FabricDocsBlockEntityRenderer.java)

We will override a few methods to set up the render state along with the `render` method where the rendering logic will be set up.

`createRenderState` can be used to initialize the render state.

@[code transclude={31-34}](@/reference/latest/src/client/java/com/example/docs/rendering/blockentity/CounterBlockEntityRenderer.java)

`updateRenderState` can be used to update the render state with entity data.

@[code transclude={36-42}](@/reference/latest/src/client/java/com/example/docs/rendering/blockentity/CounterBlockEntityRenderer.java)

You should register block entity renderers in your `ClientModInitializer` class.

`BlockEntityRendererFactories` is a registry that maps each `BlockEntityType` with custom rendering code to its respective `BlockEntityRenderer`.
Expand Down Expand Up @@ -79,15 +95,15 @@ Now, the whole transformation looks like this:

### Drawing Text {#drawing-text}

As mentioned earlier, the `Context` passed into the constructor of our renderer has a `TextRenderer` that we can use to draw text. For this example we'll save it in a field.
As mentioned earlier, the `Context` passed into the constructor of our renderer has a `TextRenderer` that we can use to measure text (`getWidth`), which is useful for centering.

The `TextRenderer` has methods to measure text (`getWidth`), which is useful for centering, and to draw it (`draw`).
To draw the text, we will be submitting the necessary data to the render queue. Since we're drawing some text, we can use the `submitText` method provided through the `OrderedRenderCommandQueue` instance passed into the `render` method.

@[code transcludeWith=:::3](@/reference/latest/src/client/java/com/example/docs/rendering/blockentity/CounterBlockEntityRenderer.java)

The `draw` method takes a lot of parameters, but the most important ones are:
The `submitText` method takes a lot of parameters, but the most important ones are:

- the `Text` (or `String`) to draw;
- the `OrderedText` to draw;
- its `x` and `y` coordinates;
- the RGB `color` value;
- the `Matrix4f` describing how it should be transformed (to get one from a `MatrixStack`, we can use `.peek().getPositionMatrix()` to get the `Matrix4f` for the topmost entry).
Expand Down
2 changes: 1 addition & 1 deletion develop/data-generation/block-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,6 @@ And that is all! Now all that's left to do is to call our method in our `ModelPr

## Sources and Links {#sources-and-links}

You can view the example tests in [Fabric API](https://github.com/FabricMC/fabric/blob/1.21.8/fabric-data-generation-api-v1/src/) and this documentation's [Reference Mod](https://github.com/FabricMC/fabric-docs/tree/main/reference) for more information.
You can view the example tests in [Fabric API](https://github.com/FabricMC/fabric/blob/1.21.10/fabric-data-generation-api-v1/src/) and this documentation's [Reference Mod](https://github.com/FabricMC/fabric-docs/tree/main/reference) for more information.

You can also find more examples of using custom datagen methods by browsing mods' open-source code, for example [Vanilla+ Blocks](https://github.com/Fellteros/vanillablocksplus) and [Vanilla+ Verticals](https://github.com/Fellteros/vanillavsplus) by Fellteros.
2 changes: 1 addition & 1 deletion develop/getting-started/setting-up.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const choices = [

## Install JDK 21 {#install-jdk-21}

To develop mods for Minecraft 1.21.8, you will need JDK 21.
To develop mods for Minecraft 1.21.10, you will need JDK 21.

If you need help installing Java, you can refer to the various Java installation guides in the [player guides section](../../players/index).

Expand Down
2 changes: 1 addition & 1 deletion reference/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx1G
org.gradle.parallel=true

loader_version=0.17.2
loader_version=0.17.3
6 changes: 3 additions & 3 deletions reference/latest/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
def minecraftVersion = "1.21.8"
def yarnVersion = "1.21.8+build.1"
def fabricApiVersion = "0.131.0+1.21.8"
def minecraftVersion = "1.21.10"
def yarnVersion = "1.21.10+build.2"
def fabricApiVersion = "0.135.0+1.21.10"

// :::automatic-testing:game-test:2
dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@

import net.minecraft.client.render.GameRenderer;

import com.example.docs.rendering.CustomRenderPipeline;

@Mixin(GameRenderer.class)
public class GameRendererMixin {
@Inject(method = "close", at = @At("RETURN"))
private void onGameRendererClose(CallbackInfo ci) {
CustomRenderPipeline.getInstance().close();
// CustomRenderPipeline.getInstance().close();
}
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,41 @@
package com.example.docs.rendering;

import java.util.OptionalDouble;
import java.util.OptionalInt;

import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DepthTestFunction;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import org.joml.Vector4f;
import org.lwjgl.system.MemoryUtil;

import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.MappableRingBuffer;
import net.minecraft.client.gl.RenderPipelines;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.BuiltBuffer;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.render.VertexRendering;
import net.minecraft.client.util.BufferAllocator;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d;
// import java.util.OptionalDouble;
// import java.util.OptionalInt;
//
// import com.mojang.blaze3d.buffers.GpuBuffer;
// import com.mojang.blaze3d.buffers.GpuBufferSlice;
// import com.mojang.blaze3d.pipeline.RenderPipeline;
// import com.mojang.blaze3d.platform.DepthTestFunction;
// import com.mojang.blaze3d.systems.CommandEncoder;
// import com.mojang.blaze3d.systems.RenderPass;
// import com.mojang.blaze3d.systems.RenderSystem;
// import com.mojang.blaze3d.vertex.VertexFormat;
// import org.joml.Vector4f;
// import org.lwjgl.system.MemoryUtil;

// import net.minecraft.client.MinecraftClient;
// import net.minecraft.client.gl.MappableRingBuffer;
// import net.minecraft.client.gl.RenderPipelines;
// import net.minecraft.client.render.BufferBuilder;
// import net.minecraft.client.render.BuiltBuffer;
// import net.minecraft.client.render.RenderLayer;
// import net.minecraft.client.render.VertexFormats;
// import net.minecraft.client.render.VertexRendering;
// import net.minecraft.client.util.BufferAllocator;
// import net.minecraft.client.util.math.MatrixStack;
// import net.minecraft.util.Identifier;
// import net.minecraft.util.math.Vec3d;

import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;

import com.example.docs.FabricDocsReference;
// import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
// import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
// import com.example.docs.FabricDocsReference;

public class CustomRenderPipeline implements ClientModInitializer {
@Override
public void onInitializeClient() { }
/*
private static CustomRenderPipeline instance;
// :::custom-pipelines:define-pipeline
private static final RenderPipeline FILLED_THROUGH_WALLS = RenderPipelines.register(RenderPipeline.builder(RenderPipelines.POSITION_COLOR_SNIPPET)
Expand Down Expand Up @@ -176,4 +178,5 @@ public void close() {
}
}
// :::custom-pipelines:clean-up
*/
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) {

// :::2
// x, y, width, height, color
context.drawBorder(rectangleX, rectangleY, rectangleWidth, rectangleHeight, 0xFFFF0000);
context.drawStrokedRectangle(rectangleX, rectangleY, rectangleWidth, rectangleHeight, 0xFFFF0000);
// :::2

// :::3
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.example.docs.rendering.blockentity;

import net.minecraft.client.render.block.entity.state.BlockEntityRenderState;

// :::render-state
public class CounterBlockEntityRenderState extends BlockEntityRenderState {
private int clicks = 0;

public int getClicks() {
return clicks;
}

public void setClicks(int clicks) {
this.clicks = clicks;
}
}
// :::render-state
Original file line number Diff line number Diff line change
@@ -1,30 +1,48 @@
package com.example.docs.rendering.blockentity;

import org.jetbrains.annotations.Nullable;

import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
import net.minecraft.client.render.command.ModelCommandRenderer;
import net.minecraft.client.render.command.OrderedRenderCommandQueue;
import net.minecraft.client.render.state.CameraRenderState;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
import net.minecraft.util.math.RotationAxis;
import net.minecraft.util.math.Vec3d;

import com.example.docs.block.entity.custom.CounterBlockEntity;

// :::1
public class CounterBlockEntityRenderer implements BlockEntityRenderer<CounterBlockEntity> {
public class CounterBlockEntityRenderer implements BlockEntityRenderer<CounterBlockEntity, CounterBlockEntityRenderState> {
// :::1

private final TextRenderer textRenderer;

// :::1
public CounterBlockEntityRenderer(BlockEntityRendererFactory.Context context) {
// :::1
textRenderer = context.getTextRenderer();
textRenderer = context.textRenderer();
// :::1
}

@Override
public void render(CounterBlockEntity entity, float tickProgress, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, Vec3d cameraPos) {
public CounterBlockEntityRenderState createRenderState() {
return new CounterBlockEntityRenderState();
}

@Override
public void updateRenderState(CounterBlockEntity blockEntity, CounterBlockEntityRenderState state, float tickProgress, Vec3d cameraPos, @Nullable ModelCommandRenderer.CrumblingOverlayCommand crumblingOverlay) {
// :::1
BlockEntityRenderer.super.updateRenderState(blockEntity, state, tickProgress, cameraPos, crumblingOverlay);
state.setClicks(blockEntity.getClicks());
// :::1
}

@Override
public void render(CounterBlockEntityRenderState state, MatrixStack matrices, OrderedRenderCommandQueue queue, CameraRenderState cameraState) {
// :::1

// :::2
Expand All @@ -35,21 +53,21 @@ public void render(CounterBlockEntity entity, float tickProgress, MatrixStack ma
// :::2

// :::3
String text = entity.getClicks() + "";
String text = state.getClicks() + "";
float width = textRenderer.getWidth(text);

// draw the text. params:
// text, x, y, color, shadow, matrix, vertexConsumers, layerType, backgroundColor, light
textRenderer.draw(
text,
-width/2, -4f,
0xffffffff,
// text, x, y, color, ordered text, shadow, text layer type, light, color, background color, outline color
queue.submitText(
matrices,
-width / 2, -4f,
Text.literal(text).asOrderedText(),
false,
matrices.peek().getPositionMatrix(),
vertexConsumers,
TextRenderer.TextLayerType.SEE_THROUGH,
state.lightmapCoordinates,
0xffffffff,
0,
light
0
);
// :::3

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public TestItem(Settings settings) {
// ::::::problems:logger-usage-example
@Override
public ActionResult useOnEntity(ItemStack stack, PlayerEntity user, LivingEntity entity, Hand hand) {
World world = user.getWorld();
World world = user.getEntityWorld();

// ::::::problems:logger-usage-example
if (world.isClient()) {
Expand All @@ -36,11 +36,11 @@ public ActionResult useOnEntity(ItemStack stack, PlayerEntity user, LivingEntity

// Values are used in a String to provide more information in the console
String output = "Is Client World: %s | Health: %s / %s | The item was used with the %s"
.formatted(user.getWorld().isClient(), entity.getHealth(), entity.getMaxHealth(), hand.name());
.formatted(user.getEntityWorld().isClient(), entity.getHealth(), entity.getMaxHealth(), hand.name());

FabricDocsReferenceDebug.LOGGER.info(output);

if (!user.getWorld().isClient()) {
if (!user.getEntityWorld().isClient()) {
// you can log non-critical issues differently as a warning
FabricDocsReferenceDebug.LOGGER.warn("Don't touch that!");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ public void onInitialize() {

// Create diamond item entity at sheep's position.
ItemStack stack = new ItemStack(Items.DIAMOND);
ItemEntity itemEntity = new ItemEntity(player.getWorld(), sheep.getX(), sheep.getY(), sheep.getZ(), stack);
player.getWorld().spawnEntity(itemEntity);
ItemEntity itemEntity = new ItemEntity(player.getEntityWorld(), sheep.getX(), sheep.getY(), sheep.getZ(), stack);
player.getEntityWorld().spawnEntity(itemEntity);

return ActionResult.FAIL;
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public CustomSoundItem(Settings settings) {
public ActionResult useOnEntity(ItemStack stack, PlayerEntity user, LivingEntity entity, Hand hand) {
// As stated above, don't use the playSound() method on the client side
// ... it won't work!
if (!entity.getWorld().isClient()) {
if (!entity.getEntityWorld().isClient()) {
// Play the sound as if it was coming from the entity.
entity.playSound(SoundEvents.ENTITY_PILLAGER_AMBIENT, 2f, 0.7f);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public LightningStick(Settings settings) {
public ActionResult use(World world, PlayerEntity user, Hand hand) {
// Ensure we don't spawn the lightning only on the client.
// This is to prevent desync.
if (world.isClient) {
if (world.isClient()) {
return ActionResult.PASS;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void onInitialize() {

// :::server_global_receiver
ServerPlayNetworking.registerGlobalReceiver(GiveGlowingEffectC2SPayload.ID, (payload, context) -> {
Entity entity = context.player().getWorld().getEntityById(payload.entityId());
Entity entity = context.player().getEntityWorld().getEntityById(payload.entityId());

if (entity instanceof LivingEntity livingEntity && livingEntity.isInRange(context.player(), 5)) {
livingEntity.addStatusEffect(new StatusEffectInstance(StatusEffects.GLOWING, 100));
Expand Down
Loading