diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/advancement/AdvancementRenderContext.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/advancement/AdvancementRenderContext.java
new file mode 100644
index 0000000000..1b48bbff6d
--- /dev/null
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/advancement/AdvancementRenderContext.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.api.client.rendering.v1.advancement;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.Nullable;
+
+import net.minecraft.advancements.Advancement;
+import net.minecraft.advancements.AdvancementHolder;
+import net.minecraft.advancements.AdvancementProgress;
+import net.minecraft.advancements.DisplayInfo;
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.gui.navigation.ScreenRectangle;
+
+@ApiStatus.NonExtendable
+public sealed interface AdvancementRenderContext permits AdvancementRenderContext.Icon, AdvancementRenderContext.Frame, AdvancementRenderContext.Background {
+ /**
+ * The graphics instance used for rendering.
+ * @return {@link GuiGraphics} instance
+ */
+ GuiGraphics graphics();
+
+ /**
+ * The holder for the advancement.
+ * @return {@link AdvancementHolder} instance
+ */
+ AdvancementHolder holder();
+
+ /**
+ * @return The advancement's progress, or {@code null} if there is no progress.
+ */
+ @Nullable
+ AdvancementProgress progress();
+
+ /**
+ * The advancement being rendered.
+ * @return {@link Advancement} instance
+ */
+ default Advancement advancement() {
+ return holder().value();
+ }
+
+ /**
+ * The display info of the advancement.
+ * @return {@link DisplayInfo} instance
+ */
+ default DisplayInfo display() {
+ return advancement().display().orElseThrow();
+ }
+
+ /**
+ * @return {@code true} if the advancement has been obtained.
+ */
+ default boolean isObtained() {
+ AdvancementProgress progress = progress();
+ return progress != null && progress.getPercent() >= 1;
+ }
+
+ @ApiStatus.NonExtendable
+ non-sealed interface Icon extends AdvancementRenderContext {
+ /**
+ * @return The x coordinate of the icon's top-left corner.
+ */
+ int x();
+
+ /**
+ * @return The y coordinate of the icon's top-left corner.
+ */
+ int y();
+
+ /**
+ * @return {@code true} if the mouse is hovered over the icon.
+ */
+ boolean isHovered();
+
+ /**
+ * @return {@code true} if the icon is rendered as a selected tab.
+ */
+ boolean isSelected();
+ }
+
+ @ApiStatus.NonExtendable
+ non-sealed interface Frame extends AdvancementRenderContext {
+ /**
+ * @return The x coordinate of the frame's top-left corner.
+ */
+ int x();
+
+ /**
+ * @return The y coordinate of the frame's top-left corner.
+ */
+ int y();
+
+ /**
+ * @return {@code true} if the mouse is hovered over the frame.
+ */
+ boolean isHovered();
+ }
+
+ @ApiStatus.NonExtendable
+ non-sealed interface Background extends AdvancementRenderContext {
+ /**
+ * @return the {@link ScreenRectangle} that the background is contained within.
+ * @apiNote use {@link ScreenRectangle#left()} and {@link ScreenRectangle#top()} for the starting coordinates of the background.
+ */
+ ScreenRectangle bounds();
+
+ /**
+ * @return the background's x scroll offset.
+ */
+ double scrollX();
+
+ /**
+ * @return the background's y scroll offset.
+ */
+ double scrollY();
+ }
+}
diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/advancement/AdvancementRenderer.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/advancement/AdvancementRenderer.java
new file mode 100644
index 0000000000..c2c407285b
--- /dev/null
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/advancement/AdvancementRenderer.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.api.client.rendering.v1.advancement;
+
+import net.minecraft.resources.Identifier;
+
+import net.fabricmc.fabric.impl.client.rendering.advancement.AdvancementRendererRegistryImpl;
+
+/**
+ * Advancement renderers allow for custom advancement icons, frames, and backgrounds
+ * which render in the {@link net.minecraft.client.gui.screens.advancements.AdvancementsScreen advancements screen}
+ * and {@link net.minecraft.client.gui.components.toasts.AdvancementToast advancement toasts}.
+ */
+public final class AdvancementRenderer {
+ /**
+ * Registers an {@link IconRenderer} for advancement icons that show on advancement widgets, tabs, and toasts.
+ * @param iconRenderer the icon renderer
+ * @param advancementIds identifiers of the advancements
+ * @throws IllegalArgumentException if an advancement already has a registered icon renderer
+ * @throws NullPointerException if either an advancement id or the icon renderer is null
+ */
+ public static void registerIcon(IconRenderer iconRenderer, Identifier... advancementIds) {
+ AdvancementRendererRegistryImpl.registerIcon(iconRenderer, advancementIds);
+ }
+
+ /**
+ * Registers a {@link FrameRenderer} for advancement frames that show on advancement widgets.
+ * @param frameRenderer the frame renderer
+ * @param advancementIds identifiers of the advancements
+ * @throws IllegalArgumentException if an advancement already has a registered frame renderer
+ * @throws NullPointerException if either an advancement id or the frame renderer is null
+ */
+ public static void registerFrame(FrameRenderer frameRenderer, Identifier... advancementIds) {
+ AdvancementRendererRegistryImpl.registerFrame(frameRenderer, advancementIds);
+ }
+
+ /**
+ * Registers a {@link BackgroundRenderer} for the backgrounds of advancement tabs.
+ *
+ *
Only root advancements render their backgrounds.
+ * @param backgroundRenderer the frame renderer
+ * @param advancementIds identifiers of the advancements
+ * @throws IllegalArgumentException if an advancement already has a registered background renderer
+ * @throws NullPointerException if either an advancement id or the background renderer is null
+ */
+ public static void registerBackground(BackgroundRenderer backgroundRenderer, Identifier... advancementIds) {
+ AdvancementRendererRegistryImpl.registerBackground(backgroundRenderer, advancementIds);
+ }
+
+ /**
+ * Called after the icon (display item) of an advancement renders.
+ *
+ *
By default, the original icon does not render.
+ * To have it render, override {@link #shouldRenderOriginalIcon()} and return {@code true}.
+ */
+ @FunctionalInterface
+ public interface IconRenderer {
+ /**
+ * @param context the context of the icon rendering, which has
+ * {@link net.minecraft.client.gui.GuiGraphics gui graphics} for rendering,
+ * the {@link net.minecraft.advancements.Advancement advancement} instance, and the icon's coordinates.
+ */
+ void renderAdvancementIcon(AdvancementRenderContext.Icon context);
+
+ /**
+ * @return {@code true} if the original advancement icon should render alongside this icon renderer.
+ */
+ default boolean shouldRenderOriginalIcon() {
+ return false;
+ }
+ }
+
+ /**
+ * Called after the frame of an advancement renders.
+ *
+ *
By default, the original frame does not render.
+ * To have it render, override {@link #shouldRenderOriginalFrame()} and return {@code true}.
+ *
+ *
The tooltip which shows the advancement's name, description, and progress when hovered will render by default.
+ * To cancel its rendering, override {@link #shouldRenderTooltip()} and return {@code false}.
+ */
+ @FunctionalInterface
+ public interface FrameRenderer {
+ /**
+ * @param context the context of the frame rendering, which has
+ * {@link net.minecraft.client.gui.GuiGraphics gui graphics} for rendering,
+ * the {@link net.minecraft.advancements.Advancement advancement} instance, and the frame's coordinates.
+ */
+ void renderAdvancementFrame(AdvancementRenderContext.Frame context);
+
+ /**
+ * @return {@code true} if the original advancement frame should render alongside this frame renderer.
+ */
+ default boolean shouldRenderOriginalFrame() {
+ return false;
+ }
+
+ /**
+ * @return {@code true} if the tooltip of a hovered advancement widget should render.
+ */
+ default boolean shouldRenderTooltip() {
+ return true;
+ }
+ }
+
+ /**
+ * Called after the background of an advancement tab renders.
+ *
+ *
By default, the original background does not render.
+ * To have it render, override {@link #shouldRenderOriginalBackground()} and return {@code true}.
+ */
+ @FunctionalInterface
+ public interface BackgroundRenderer {
+ /**
+ * @param context the context of the frame rendering, which has
+ * {@link net.minecraft.client.gui.GuiGraphics gui graphics} for rendering,
+ * the {@link net.minecraft.advancements.Advancement advancement} instance,
+ * and the background's {@link net.minecraft.client.gui.navigation.ScreenRectangle bounds}.
+ */
+ void renderAdvancementBackground(AdvancementRenderContext.Background context);
+
+ /**
+ * @return {@code true} if the original advancement background should render alongside this background renderer.
+ */
+ default boolean shouldRenderOriginalBackground() {
+ return false;
+ }
+ }
+
+ private AdvancementRenderer() {
+ }
+}
diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/advancement/AdvancementRenderContextImpl.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/advancement/AdvancementRenderContextImpl.java
new file mode 100644
index 0000000000..42222da2f3
--- /dev/null
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/advancement/AdvancementRenderContextImpl.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.impl.client.rendering.advancement;
+
+import org.jspecify.annotations.Nullable;
+
+import net.minecraft.advancements.AdvancementHolder;
+import net.minecraft.advancements.AdvancementProgress;
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.gui.navigation.ScreenRectangle;
+
+import net.fabricmc.fabric.api.client.rendering.v1.advancement.AdvancementRenderContext;
+
+public final class AdvancementRenderContextImpl {
+ public static final class IconImpl implements AdvancementRenderContext.Icon {
+ private final GuiGraphics graphics;
+ private final AdvancementHolder holder;
+ @Nullable
+ private final AdvancementProgress progress;
+ private int x;
+ private int y;
+ private final boolean hovered;
+ private final boolean selected;
+
+ public IconImpl(GuiGraphics graphics, AdvancementHolder holder, @Nullable AdvancementProgress progress, int x, int y, boolean hovered, boolean selected) {
+ this.graphics = graphics;
+ this.holder = holder;
+ this.progress = progress;
+ this.x = x;
+ this.y = y;
+ this.hovered = hovered;
+ this.selected = selected;
+ }
+
+ public IconImpl(GuiGraphics graphics, AdvancementHolder holder, @Nullable AdvancementProgress progress, boolean hovered, boolean selected) {
+ this(graphics, holder, progress, 0, 0, hovered, selected);
+ }
+
+ @Override
+ public GuiGraphics graphics() {
+ return graphics;
+ }
+
+ @Override
+ public AdvancementHolder holder() {
+ return holder;
+ }
+
+ @Override
+ public @Nullable AdvancementProgress progress() {
+ return progress;
+ }
+
+ @Override
+ public int x() {
+ return x;
+ }
+
+ @Override
+ public int y() {
+ return y;
+ }
+
+ @Override
+ public boolean isHovered() {
+ return hovered;
+ }
+
+ @Override
+ public boolean isSelected() {
+ return selected;
+ }
+
+ public void setPos(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+ }
+
+ public record FrameImpl(GuiGraphics graphics, AdvancementHolder holder, @Nullable AdvancementProgress progress, int x, int y, boolean isHovered) implements AdvancementRenderContext.Frame {
+ }
+
+ public record BackgroundImpl(GuiGraphics graphics, AdvancementHolder holder, @Nullable AdvancementProgress progress, ScreenRectangle bounds, double scrollX, double scrollY) implements AdvancementRenderContext.Background {
+ }
+
+ private AdvancementRenderContextImpl() {
+ }
+}
diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/advancement/AdvancementRendererRegistryImpl.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/advancement/AdvancementRendererRegistryImpl.java
new file mode 100644
index 0000000000..6822d04129
--- /dev/null
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/advancement/AdvancementRendererRegistryImpl.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.impl.client.rendering.advancement;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import org.jspecify.annotations.Nullable;
+
+import net.minecraft.resources.Identifier;
+
+import net.fabricmc.fabric.api.client.rendering.v1.advancement.AdvancementRenderer;
+
+public final class AdvancementRendererRegistryImpl {
+ public static final ScopedValue TAB_ICON_RENDER_CONTEXT = ScopedValue.newInstance();
+ private static final Map ICONS = new HashMap<>();
+ private static final Map FRAMES = new HashMap<>();
+ private static final Map BACKGROUNDS = new HashMap<>();
+
+ public static void registerIcon(AdvancementRenderer.IconRenderer iconRenderer, Identifier... advancementIds) {
+ registerRenderer("Icon", ICONS, iconRenderer, advancementIds);
+ }
+
+ public static void registerFrame(AdvancementRenderer.FrameRenderer frameRenderer, Identifier... advancementIds) {
+ registerRenderer("Frame", FRAMES, frameRenderer, advancementIds);
+ }
+
+ public static void registerBackground(AdvancementRenderer.BackgroundRenderer backgroundRenderer, Identifier... advancementIds) {
+ registerRenderer("Background", BACKGROUNDS, backgroundRenderer, advancementIds);
+ }
+
+ public static AdvancementRenderer.@Nullable IconRenderer getIconRenderer(Identifier advancementId) {
+ return ICONS.get(advancementId);
+ }
+
+ public static AdvancementRenderer.@Nullable FrameRenderer getFrameRenderer(Identifier advancementId) {
+ return FRAMES.get(advancementId);
+ }
+
+ public static AdvancementRenderer.@Nullable BackgroundRenderer getBackgroundRenderer(Identifier advancementId) {
+ return BACKGROUNDS.get(advancementId);
+ }
+
+ private static void registerRenderer(String type, Map renderers, T renderer, Identifier... advancementIds) {
+ Objects.requireNonNull(renderer, type + " renderer is null");
+
+ if (advancementIds.length == 0) {
+ throw new IllegalArgumentException(type + " advancement renderer registered for no advancements");
+ }
+
+ for (Identifier advancementId : advancementIds) {
+ Objects.requireNonNull(advancementId, " advancement id is null");
+
+ if (renderers.putIfAbsent(advancementId, renderer) != null) {
+ throw new IllegalArgumentException(type + " advancement renderer already exists for " + advancementId);
+ }
+ }
+ }
+
+ private AdvancementRendererRegistryImpl() {
+ }
+}
diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementTabAccessor.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementTabAccessor.java
new file mode 100644
index 0000000000..6922450353
--- /dev/null
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementTabAccessor.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.client.rendering.advancement;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+import net.minecraft.client.gui.screens.advancements.AdvancementTab;
+import net.minecraft.client.gui.screens.advancements.AdvancementWidget;
+
+@Mixin(AdvancementTab.class)
+public interface AdvancementTabAccessor {
+ @Accessor("root")
+ AdvancementWidget fabric_getRoot();
+}
diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementTabMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementTabMixin.java
new file mode 100644
index 0000000000..867e5452d5
--- /dev/null
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementTabMixin.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.client.rendering.advancement;
+
+import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.llamalad7.mixinextras.sugar.Share;
+import com.llamalad7.mixinextras.sugar.ref.LocalRef;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Coerce;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import net.minecraft.advancements.AdvancementHolder;
+import net.minecraft.advancements.AdvancementNode;
+import net.minecraft.advancements.AdvancementProgress;
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.gui.navigation.ScreenRectangle;
+import net.minecraft.client.gui.screens.advancements.AdvancementTab;
+import net.minecraft.client.gui.screens.advancements.AdvancementWidget;
+import net.minecraft.world.item.ItemStack;
+
+import net.fabricmc.fabric.api.client.rendering.v1.advancement.AdvancementRenderer;
+import net.fabricmc.fabric.impl.client.rendering.advancement.AdvancementRenderContextImpl;
+import net.fabricmc.fabric.impl.client.rendering.advancement.AdvancementRendererRegistryImpl;
+
+@Mixin(AdvancementTab.class)
+abstract class AdvancementTabMixin {
+ @Shadow
+ @Final
+ private AdvancementNode rootNode;
+
+ @Shadow
+ private double scrollX;
+
+ @Shadow
+ private double scrollY;
+
+ @Shadow
+ @Final
+ private AdvancementWidget root;
+
+ @WrapOperation(method = "drawIcon", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/advancements/AdvancementTabType;drawIcon(Lnet/minecraft/client/gui/GuiGraphics;IIILnet/minecraft/world/item/ItemStack;)V"))
+ private void wrapDrawIcon(@Coerce Object type, GuiGraphics graphics, int xo, int yo, int index, ItemStack icon, Operation original) {
+ if (AdvancementRendererRegistryImpl.TAB_ICON_RENDER_CONTEXT.isBound()) {
+ final AdvancementRenderContextImpl.IconImpl context = AdvancementRendererRegistryImpl.TAB_ICON_RENDER_CONTEXT.get();
+ ScopedValue.where(AdvancementRendererRegistryImpl.TAB_ICON_RENDER_CONTEXT, context)
+ .call(() -> original.call(type, graphics, xo, yo, index, icon));
+ } else {
+ original.call(type, graphics, xo, yo, index, icon);
+ }
+ }
+
+ @WrapOperation(method = "drawContents", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;enableScissor(IIII)V"))
+ private void captureWindowSize(GuiGraphics graphics, int x0, int y0, int x1, int y1, Operation original, @Share("bounds") LocalRef bounds) {
+ bounds.set(new ScreenRectangle(0, 0, x1 - x0, y1 - y0));
+ original.call(graphics, x0, y0, x1, y1);
+ }
+
+ @ModifyExpressionValue(method = "drawContents", at = @At(value = "CONSTANT", args = "intValue=-1", ordinal = 0))
+ private int preBackgroundRender(int original, @Share("backgroundRenderer") LocalRef backgroundRenderer) {
+ AdvancementHolder holder = rootNode.holder();
+ backgroundRenderer.set(AdvancementRendererRegistryImpl.getBackgroundRenderer(holder.id()));
+ return backgroundRenderer.get() == null || backgroundRenderer.get().shouldRenderOriginalBackground() ? original : Integer.MAX_VALUE;
+ }
+
+ @Inject(method = "drawContents", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/advancements/AdvancementWidget;drawConnectivity(Lnet/minecraft/client/gui/GuiGraphics;IIZ)V", ordinal = 0))
+ private void renderAdvancementBackground(GuiGraphics graphics, int windowLeft, int windowTop, CallbackInfo ci, @Share("backgroundRenderer") LocalRef backgroundRenderer, @Share("bounds") LocalRef bounds) {
+ if (backgroundRenderer.get() != null) {
+ AdvancementProgress progress = ((AdvancementWidgetAccessor) root).fabric_getProgress();
+ backgroundRenderer.get().renderAdvancementBackground(
+ new AdvancementRenderContextImpl.BackgroundImpl(graphics, rootNode.holder(), progress, bounds.get(), scrollX, scrollY)
+ );
+ }
+ }
+}
diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementTabTypeMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementTabTypeMixin.java
new file mode 100644
index 0000000000..d99389e397
--- /dev/null
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementTabTypeMixin.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.client.rendering.advancement;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.world.item.ItemStack;
+
+import net.fabricmc.fabric.api.client.rendering.v1.advancement.AdvancementRenderer;
+import net.fabricmc.fabric.impl.client.rendering.advancement.AdvancementRenderContextImpl;
+import net.fabricmc.fabric.impl.client.rendering.advancement.AdvancementRendererRegistryImpl;
+
+@Mixin(targets = "net/minecraft/client/gui/screens/advancements/AdvancementTabType")
+abstract class AdvancementTabTypeMixin {
+ @WrapOperation(method = "drawIcon", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;renderFakeItem(Lnet/minecraft/world/item/ItemStack;II)V"))
+ private void renderAdvancementIcon(GuiGraphics graphics, ItemStack icon, int x, int y, Operation original) {
+ if (AdvancementRendererRegistryImpl.TAB_ICON_RENDER_CONTEXT.isBound()) {
+ final AdvancementRenderContextImpl.IconImpl context = AdvancementRendererRegistryImpl.TAB_ICON_RENDER_CONTEXT.get();
+ context.setPos(x, y);
+ AdvancementRenderer.IconRenderer iconRenderer = AdvancementRendererRegistryImpl.getIconRenderer(context.holder().id());
+
+ if (iconRenderer.shouldRenderOriginalIcon()) {
+ original.call(graphics, icon, x, y);
+ }
+
+ iconRenderer.renderAdvancementIcon(context);
+ } else {
+ original.call(graphics, icon, x, y);
+ }
+ }
+}
diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementToastMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementToastMixin.java
new file mode 100644
index 0000000000..b84df91c39
--- /dev/null
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementToastMixin.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.client.rendering.advancement;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+
+import net.minecraft.advancements.AdvancementHolder;
+import net.minecraft.advancements.AdvancementProgress;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.gui.components.toasts.AdvancementToast;
+import net.minecraft.client.multiplayer.ClientAdvancements;
+import net.minecraft.world.item.ItemStack;
+
+import net.fabricmc.fabric.api.client.rendering.v1.advancement.AdvancementRenderer;
+import net.fabricmc.fabric.impl.client.rendering.advancement.AdvancementRenderContextImpl;
+import net.fabricmc.fabric.impl.client.rendering.advancement.AdvancementRendererRegistryImpl;
+
+@Mixin(AdvancementToast.class)
+abstract class AdvancementToastMixin {
+ @Shadow
+ @Final
+ private AdvancementHolder advancement;
+
+ @WrapOperation(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;renderFakeItem(Lnet/minecraft/world/item/ItemStack;II)V"))
+ private void renderAdvancementIcon(GuiGraphics graphics, ItemStack icon, int x, int y, Operation original) {
+ AdvancementRenderer.IconRenderer iconRenderer = AdvancementRendererRegistryImpl.getIconRenderer(advancement.id());
+
+ if (iconRenderer == null || iconRenderer.shouldRenderOriginalIcon()) {
+ original.call(graphics, icon, x, y);
+ }
+
+ if (iconRenderer != null) {
+ ClientAdvancements advancements = Minecraft.getInstance().getConnection().getAdvancements();
+ AdvancementProgress progress = ((ClientAdvancementsAccessor) advancements).fabric_getProgress().get(advancement);
+ iconRenderer.renderAdvancementIcon(new AdvancementRenderContextImpl.IconImpl(graphics, advancement, progress, x, y, false, false));
+ }
+ }
+}
diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementWidgetAccessor.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementWidgetAccessor.java
new file mode 100644
index 0000000000..73ff0670d8
--- /dev/null
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementWidgetAccessor.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.client.rendering.advancement;
+
+import org.jspecify.annotations.Nullable;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+import net.minecraft.advancements.AdvancementProgress;
+import net.minecraft.client.gui.screens.advancements.AdvancementWidget;
+
+@Mixin(AdvancementWidget.class)
+public interface AdvancementWidgetAccessor {
+ @Accessor("progress")
+ @Nullable AdvancementProgress fabric_getProgress();
+}
diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementWidgetMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementWidgetMixin.java
new file mode 100644
index 0000000000..0f093b8a7a
--- /dev/null
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementWidgetMixin.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.client.rendering.advancement;
+
+import java.util.List;
+
+import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.llamalad7.mixinextras.sugar.Share;
+import com.llamalad7.mixinextras.sugar.ref.LocalBooleanRef;
+import com.mojang.blaze3d.pipeline.RenderPipeline;
+import org.jspecify.annotations.Nullable;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.Unique;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.Slice;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import net.minecraft.advancements.AdvancementNode;
+import net.minecraft.advancements.AdvancementProgress;
+import net.minecraft.client.gui.Font;
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.gui.screens.advancements.AdvancementWidget;
+import net.minecraft.network.chat.Component;
+import net.minecraft.resources.Identifier;
+import net.minecraft.util.FormattedCharSequence;
+import net.minecraft.world.item.ItemStack;
+
+import net.fabricmc.fabric.api.client.rendering.v1.advancement.AdvancementRenderer;
+import net.fabricmc.fabric.impl.client.rendering.advancement.AdvancementRenderContextImpl;
+import net.fabricmc.fabric.impl.client.rendering.advancement.AdvancementRendererRegistryImpl;
+
+@Mixin(AdvancementWidget.class)
+abstract class AdvancementWidgetMixin {
+ @Shadow
+ @Final
+ private AdvancementNode advancementNode;
+
+ @Shadow
+ private @Nullable AdvancementProgress progress;
+
+ @WrapOperation(method = "draw", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;renderFakeItem(Lnet/minecraft/world/item/ItemStack;II)V"))
+ private void renderAdvancementIcon(GuiGraphics graphics, ItemStack icon, int x, int y, Operation original) {
+ renderAdvancementIcon(graphics, x, y, false, () -> original.call(graphics, icon, x, y));
+ }
+
+ @WrapOperation(method = "drawHover", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;renderFakeItem(Lnet/minecraft/world/item/ItemStack;II)V"))
+ private void renderAdvancementIconHover(GuiGraphics graphics, ItemStack icon, int x, int y, Operation original) {
+ renderAdvancementIcon(graphics, x, y, true, () -> original.call(graphics, icon, x, y));
+ }
+
+ @Unique
+ private void renderAdvancementIcon(GuiGraphics graphics, int x, int y, boolean hovered, Runnable original) {
+ AdvancementRenderer.IconRenderer iconRenderer = AdvancementRendererRegistryImpl.getIconRenderer(advancementNode.holder().id());
+
+ if (iconRenderer == null || iconRenderer.shouldRenderOriginalIcon()) {
+ original.run();
+ }
+
+ if (iconRenderer != null) {
+ iconRenderer.renderAdvancementIcon(new AdvancementRenderContextImpl.IconImpl(graphics, advancementNode.holder(), progress, x, y, hovered, false));
+ }
+ }
+
+ @WrapOperation(method = "draw", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;blitSprite(Lcom/mojang/blaze3d/pipeline/RenderPipeline;Lnet/minecraft/resources/Identifier;IIII)V"))
+ private void renderAdvancementFrame(GuiGraphics graphics, RenderPipeline renderPipeline, Identifier location, int x, int y, int width, int height, Operation original) {
+ renderAdvancementFrame(graphics, x, y, false, () -> original.call(graphics, renderPipeline, location, x, y, width, height));
+ }
+
+ @WrapOperation(method = "drawHover", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;blitSprite(Lcom/mojang/blaze3d/pipeline/RenderPipeline;Lnet/minecraft/resources/Identifier;IIII)V", ordinal = 3))
+ private void renderAdvancementFrameHover(GuiGraphics graphics, RenderPipeline renderPipeline, Identifier location, int x, int y, int width, int height, Operation original) {
+ renderAdvancementFrame(graphics, x, y, true, () -> original.call(graphics, renderPipeline, location, x, y, width, height));
+ }
+
+ @Unique
+ private void renderAdvancementFrame(GuiGraphics graphics, int x, int y, boolean hovered, Runnable original) {
+ AdvancementRenderer.FrameRenderer frameRenderer = AdvancementRendererRegistryImpl.getFrameRenderer(advancementNode.holder().id());
+
+ if (frameRenderer == null || frameRenderer.shouldRenderOriginalFrame()) {
+ original.run();
+ }
+
+ if (frameRenderer != null) {
+ frameRenderer.renderAdvancementFrame(new AdvancementRenderContextImpl.FrameImpl(graphics, advancementNode.holder(), progress, x, y, hovered));
+ }
+ }
+
+ @Inject(method = "drawHover", at = @At(value = "INVOKE", target = "Ljava/util/List;isEmpty()Z"))
+ private void captureRenderTooltip(GuiGraphics graphics, int xo, int yo, float fade, int screenxo, int screenyo, CallbackInfo ci, @Share("renderTooltip")LocalBooleanRef renderTooltip) {
+ AdvancementRenderer.FrameRenderer frameRenderer = AdvancementRendererRegistryImpl.getFrameRenderer(advancementNode.holder().id());
+ renderTooltip.set(frameRenderer == null || frameRenderer.shouldRenderTooltip());
+ }
+
+ @WrapWithCondition(method = "drawHover", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/advancements/AdvancementWidget;drawMultilineText(Lnet/minecraft/client/gui/GuiGraphics;Ljava/util/List;III)V"))
+ private boolean cancelTooltipMultilineTextRendering(AdvancementWidget widget, GuiGraphics graphics, List lines, int x, int y, int color, @Share("renderTooltip")LocalBooleanRef renderTooltip) {
+ return renderTooltip.get();
+ }
+
+ @WrapWithCondition(method = "drawHover", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;drawString(Lnet/minecraft/client/gui/Font;Lnet/minecraft/network/chat/Component;III)V"))
+ private boolean cancelTooltipStringRendering(GuiGraphics graphics, Font font, Component str, int x, int y, int color, @Share("renderTooltip") LocalBooleanRef renderTooltip) {
+ return renderTooltip.get();
+ }
+
+ @WrapWithCondition(method = "drawHover", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;blitSprite(Lcom/mojang/blaze3d/pipeline/RenderPipeline;Lnet/minecraft/resources/Identifier;IIIIIIII)V"))
+ private boolean cancelTooltipTitleBarRendering(GuiGraphics graphics, RenderPipeline renderPipeline, Identifier location, int spriteWidth, int spriteHeight, int textureX, int textureY, int x, int y, int width, int height, @Share("renderTooltip") LocalBooleanRef renderTooltip) {
+ return renderTooltip.get();
+ }
+
+ @WrapWithCondition(method = "drawHover",
+ at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;blitSprite(Lcom/mojang/blaze3d/pipeline/RenderPipeline;Lnet/minecraft/resources/Identifier;IIII)V"),
+ slice = @Slice(from = @At(value = "INVOKE", target = "Ljava/util/List;isEmpty()Z"), to = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;blitSprite(Lcom/mojang/blaze3d/pipeline/RenderPipeline;Lnet/minecraft/resources/Identifier;IIII)V", ordinal = 2))
+ )
+ private boolean cancelTooltipTitleBoxRendering(GuiGraphics graphics, RenderPipeline renderPipeline, Identifier location, int x, int y, int width, int height, @Share("renderTooltip") LocalBooleanRef renderTooltip) {
+ return renderTooltip.get();
+ }
+}
diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementsScreenMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementsScreenMixin.java
new file mode 100644
index 0000000000..b76ce73bca
--- /dev/null
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/AdvancementsScreenMixin.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.client.rendering.advancement;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.llamalad7.mixinextras.sugar.Local;
+import org.jspecify.annotations.Nullable;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+
+import net.minecraft.advancements.AdvancementHolder;
+import net.minecraft.advancements.AdvancementProgress;
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.gui.screens.advancements.AdvancementTab;
+import net.minecraft.client.gui.screens.advancements.AdvancementsScreen;
+
+import net.fabricmc.fabric.impl.client.rendering.advancement.AdvancementRenderContextImpl;
+import net.fabricmc.fabric.impl.client.rendering.advancement.AdvancementRendererRegistryImpl;
+
+@Mixin(AdvancementsScreen.class)
+abstract class AdvancementsScreenMixin {
+ @Shadow
+ private @Nullable AdvancementTab selectedTab;
+
+ @WrapOperation(method = "renderWindow", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/advancements/AdvancementTab;drawIcon(Lnet/minecraft/client/gui/GuiGraphics;II)V"))
+ private void wrapDrawIcon(AdvancementTab tab, GuiGraphics graphics, int xo, int yo, Operation original, @Local(name = "mouseX") int mouseX, @Local(name = "mouseY") int mouseY) {
+ AdvancementHolder holder = tab.getRootNode().holder();
+
+ if (AdvancementRendererRegistryImpl.getIconRenderer(holder.id()) != null) {
+ boolean hovered = tab.isMouseOver(xo, yo, mouseX, mouseY);
+ boolean selected = selectedTab == tab;
+ AdvancementProgress progress = ((AdvancementWidgetAccessor) ((AdvancementTabAccessor) tab).fabric_getRoot()).fabric_getProgress();
+ ScopedValue.where(
+ AdvancementRendererRegistryImpl.TAB_ICON_RENDER_CONTEXT,
+ new AdvancementRenderContextImpl.IconImpl(graphics, holder, progress, hovered, selected)
+ ).call(() -> original.call(tab, graphics, xo, yo));
+ } else {
+ original.call(tab, graphics, xo, yo);
+ }
+ }
+}
diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/ClientAdvancementsAccessor.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/ClientAdvancementsAccessor.java
new file mode 100644
index 0000000000..218db96d51
--- /dev/null
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/advancement/ClientAdvancementsAccessor.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.client.rendering.advancement;
+
+import java.util.Map;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+import net.minecraft.advancements.AdvancementHolder;
+import net.minecraft.advancements.AdvancementProgress;
+import net.minecraft.client.multiplayer.ClientAdvancements;
+
+@Mixin(ClientAdvancements.class)
+public interface ClientAdvancementsAccessor {
+ @Accessor("progress")
+ Map fabric_getProgress();
+}
diff --git a/fabric-rendering-v1/src/client/resources/fabric-rendering-v1.mixins.json b/fabric-rendering-v1/src/client/resources/fabric-rendering-v1.mixins.json
index a09d8eb3ff..bed1dc4a57 100644
--- a/fabric-rendering-v1/src/client/resources/fabric-rendering-v1.mixins.json
+++ b/fabric-rendering-v1/src/client/resources/fabric-rendering-v1.mixins.json
@@ -35,6 +35,14 @@
"SpecialModelRenderersMixin",
"ClientTooltipComponentMixin",
"LevelRendererMixin",
+ "advancement.AdvancementsScreenMixin",
+ "advancement.AdvancementTabAccessor",
+ "advancement.AdvancementTabMixin",
+ "advancement.AdvancementTabTypeMixin",
+ "advancement.AdvancementToastMixin",
+ "advancement.AdvancementWidgetAccessor",
+ "advancement.AdvancementWidgetMixin",
+ "advancement.ClientAdvancementsAccessor",
"renderstate.ItemStackRenderStateLayerRenderStateMixin",
"renderstate.ItemStackRenderStateMixin",
"renderstate.SkyRenderStateMixin",
diff --git a/fabric-rendering-v1/src/testmod/resources/fabric.mod.json b/fabric-rendering-v1/src/testmod/resources/fabric.mod.json
index dd2a5b6f01..55f98104ad 100644
--- a/fabric-rendering-v1/src/testmod/resources/fabric.mod.json
+++ b/fabric-rendering-v1/src/testmod/resources/fabric.mod.json
@@ -13,6 +13,7 @@
"net.fabricmc.fabric.test.rendering.TooltipComponentTestInit"
],
"client": [
+ "net.fabricmc.fabric.test.rendering.client.AdvancementRenderingTests",
"net.fabricmc.fabric.test.rendering.client.ArmorRenderingTests",
"net.fabricmc.fabric.test.rendering.client.CustomSpriteSourcesTest",
"net.fabricmc.fabric.test.rendering.client.CustomColorResolverTest",
diff --git a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/AdvancementRenderingTests.java b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/AdvancementRenderingTests.java
new file mode 100644
index 0000000000..4418c09256
--- /dev/null
+++ b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/AdvancementRenderingTests.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.test.rendering.client;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.navigation.ScreenRectangle;
+import net.minecraft.client.renderer.RenderPipelines;
+import net.minecraft.resources.Identifier;
+import net.minecraft.util.CommonColors;
+import net.minecraft.util.Mth;
+
+import net.fabricmc.api.ClientModInitializer;
+import net.fabricmc.fabric.api.client.rendering.v1.advancement.AdvancementRenderContext;
+import net.fabricmc.fabric.api.client.rendering.v1.advancement.AdvancementRenderer;
+
+public class AdvancementRenderingTests implements ClientModInitializer {
+ @Override
+ public void onInitializeClient() {
+ AdvancementRenderer.registerIcon(new StoryRootIconRenderer(), Identifier.withDefaultNamespace("story/root"));
+ AdvancementRenderer.registerBackground(new StoryBackgroundRenderer(), Identifier.withDefaultNamespace("story/root"));
+ AdvancementRenderer.registerFrame(new MineDiamondFrameRenderer(), Identifier.withDefaultNamespace("story/mine_diamond"));
+ }
+
+ static class StoryRootIconRenderer implements AdvancementRenderer.IconRenderer {
+ @Override
+ public void renderAdvancementIcon(AdvancementRenderContext.Icon context) {
+ if (context.isHovered()) {
+ context.graphics().drawString(Minecraft.getInstance().font, "hovered", context.x(), context.y(), -1);
+ }
+
+ if (context.isSelected()) {
+ context.graphics().drawString(Minecraft.getInstance().font, "selected", context.x(), context.y() + 9, -1);
+ }
+ }
+
+ @Override
+ public boolean shouldRenderOriginalIcon() {
+ return true;
+ }
+ }
+
+ static class StoryBackgroundRenderer implements AdvancementRenderer.BackgroundRenderer {
+ private static final Identifier BACKGROUND = Identifier.withDefaultNamespace("textures/painting/unpacked.png");
+
+ @Override
+ public void renderAdvancementBackground(AdvancementRenderContext.Background context) {
+ ScreenRectangle bounds = context.bounds();
+ context.graphics().blit(RenderPipelines.GUI_TEXTURED, BACKGROUND, bounds.left(), bounds.top(), 1 - Mth.floor(context.scrollX()), 3 - Mth.floor(context.scrollY()), bounds.width(), bounds.height(), 64, 64);
+ }
+ }
+
+ static class MineDiamondFrameRenderer implements AdvancementRenderer.FrameRenderer {
+ @Override
+ public void renderAdvancementFrame(AdvancementRenderContext.Frame context) {
+ int x = context.x();
+ int y = context.y();
+ context.graphics().fill(x, y, x + 26, y + 26, context.isObtained() ? CommonColors.GREEN : CommonColors.RED);
+
+ if (context.isHovered()) {
+ context.graphics().drawString(Minecraft.getInstance().font, "hovered", context.x(), context.y(), -1);
+ }
+ }
+
+ @Override
+ public boolean shouldRenderTooltip() {
+ return false;
+ }
+ }
+}