From 5c90d046a3517a8f5d9c46b646d52796b896c139 Mon Sep 17 00:00:00 2001 From: DekinDev Date: Sat, 10 Jan 2026 14:24:08 +0100 Subject: [PATCH] add hotbar borders --- .../v1/HudLayerRegistrationCallback.java | 62 +++++++ .../rendering/v1/HudRenderCallback.java | 42 +++++ .../client/rendering/v1/IdentifiedLayer.java | 113 +++++++++++++ .../rendering/v1/LayeredDrawerWrapper.java | 151 +++++++++++++++++ .../client/rendering/v1/hud/HudElement.java | 36 +++++ .../rendering/v1/hud/HudElementRegistry.java | 153 ++++++++++++++++++ .../rendering/v1/hud/VanillaHudElements.java | 134 +++++++++++++++ .../iconsenhanced/client/BorderRenderer.java | 40 +++++ .../iconsenhanced/client/ClientInit.java | 30 ++++ 9 files changed, 761 insertions(+) create mode 100644 net/fabricmc/fabric/api/client/rendering/v1/HudLayerRegistrationCallback.java create mode 100644 net/fabricmc/fabric/api/client/rendering/v1/HudRenderCallback.java create mode 100644 net/fabricmc/fabric/api/client/rendering/v1/IdentifiedLayer.java create mode 100644 net/fabricmc/fabric/api/client/rendering/v1/LayeredDrawerWrapper.java create mode 100644 net/fabricmc/fabric/api/client/rendering/v1/hud/HudElement.java create mode 100644 net/fabricmc/fabric/api/client/rendering/v1/hud/HudElementRegistry.java create mode 100644 net/fabricmc/fabric/api/client/rendering/v1/hud/VanillaHudElements.java diff --git a/net/fabricmc/fabric/api/client/rendering/v1/HudLayerRegistrationCallback.java b/net/fabricmc/fabric/api/client/rendering/v1/HudLayerRegistrationCallback.java new file mode 100644 index 0000000..0a7b048 --- /dev/null +++ b/net/fabricmc/fabric/api/client/rendering/v1/HudLayerRegistrationCallback.java @@ -0,0 +1,62 @@ +/* + * 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; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; + +/** + * Callback for when hud layers are registered. + * + *

To register a layer, register a listener to this event and register your layers in the listener. + * For common use cases, see {@link LayeredDrawerWrapper}. + * + *

For example, the following code registers a layer after {@link IdentifiedLayer#MISC_OVERLAYS}: + * {@snippet : + * // @link region substring=HudLayerRegistrationCallback target=HudLayerRegistrationCallback + * // @link region substring=EVENT target="HudLayerRegistrationCallback#EVENT" + * // @link region substring=layeredDrawer target="LayeredDrawerWrapper" + * // @link region substring=attachLayerAfter target="LayeredDrawerWrapper#attachLayerAfter" + * // @link region substring=IdentifiedLayer target=IdentifiedLayer + * // @link region substring=MISC_OVERLAYS target="IdentifiedLayer#MISC_OVERLAYS" + * // @link region substring=Identifier target="net.minecraft.util.Identifier" + * // @link region substring=of target="net.minecraft.util.Identifier#of" + * // @link region substring=context target="net.minecraft.client.gui.DrawContext" + * // @link region substring=tickCounter target="net.minecraft.client.render.RenderTickCounter" + * HudLayerRegistrationCallback.EVENT.register(layeredDrawer -> layeredDrawer.attachLayerAfter(IdentifiedLayer.MISC_OVERLAYS, Identifier.of("example", "example_layer_after_misc_overlays"), (context, tickCounter) -> { + * // Your rendering code here + * })); + * // @end @end @end @end @end @end @end @end @end @end + * } + * + * @see LayeredDrawerWrapper + */ +public interface HudLayerRegistrationCallback { + Event EVENT = EventFactory.createArrayBacked(HudLayerRegistrationCallback.class, callbacks -> layeredDrawer -> { + for (HudLayerRegistrationCallback callback : callbacks) { + callback.register(layeredDrawer); + } + }); + + /** + * Called when registering hud layers. + * + * @param layeredDrawer the layered drawer to register layers to + * @see LayeredDrawerWrapper + */ + void register(LayeredDrawerWrapper layeredDrawer); +} diff --git a/net/fabricmc/fabric/api/client/rendering/v1/HudRenderCallback.java b/net/fabricmc/fabric/api/client/rendering/v1/HudRenderCallback.java new file mode 100644 index 0000000..85139b7 --- /dev/null +++ b/net/fabricmc/fabric/api/client/rendering/v1/HudRenderCallback.java @@ -0,0 +1,42 @@ +/* + * 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; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.class_332; +import net.minecraft.class_9779; + +/** + * @deprecated Use {@link HudLayerRegistrationCallback} instead. For common use cases, see {@link LayeredDrawerWrapper}. + */ +@Deprecated +public interface HudRenderCallback { + Event EVENT = EventFactory.createArrayBacked(HudRenderCallback.class, (listeners) -> (context, tickCounter) -> { + for (HudRenderCallback event : listeners) { + event.onHudRender(context, tickCounter); + } + }); + + /** + * Called after rendering the whole hud, which is displayed in game, in a world. + * + * @param drawContext the {@link class_332} instance + * @param tickCounter the {@link class_9779} instance + */ + void onHudRender(class_332 drawContext, class_9779 tickCounter); +} diff --git a/net/fabricmc/fabric/api/client/rendering/v1/IdentifiedLayer.java b/net/fabricmc/fabric/api/client/rendering/v1/IdentifiedLayer.java new file mode 100644 index 0000000..0c3ce94 --- /dev/null +++ b/net/fabricmc/fabric/api/client/rendering/v1/IdentifiedLayer.java @@ -0,0 +1,113 @@ +/* + * 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; + +import net.fabricmc.fabric.impl.client.rendering.WrappedLayer; +import net.minecraft.class_2960; +import net.minecraft.class_9080; + +/** + * A hud layer that has an identifier attached for use in {@link LayeredDrawerWrapper}. + * + *

The identifiers in this interface are the vanilla hud layers in the order they are drawn in. + * The first layer is drawn first, which means it is at the bottom. + * All vanilla layers except {@link #SLEEP} are in sub drawers and have a render condition attached ({@link net.minecraft.class_315#field_1842}). + * Operations relative to any layer will generally inherit that layer's render condition. + * There is currently no mechanism to change the render condition of a layer. + * + *

For common use cases and more details on how this API deals with render condition, see {@link LayeredDrawerWrapper}. + */ +public interface IdentifiedLayer extends class_9080.class_9081 { + /** + * The identifier for the vanilla miscellaneous overlays (such as vignette, spyglass, and powder snow) layer. + */ + class_2960 MISC_OVERLAYS = class_2960.method_60656("misc_overlays"); + /** + * The identifier for the vanilla crosshair layer. + */ + class_2960 CROSSHAIR = class_2960.method_60656("crosshair"); + /** + * The identifier for the vanilla hotbar, spectator hud, experience bar, and status bars layer. + */ + class_2960 HOTBAR_AND_BARS = class_2960.method_60656("hotbar_and_bars"); + /** + * The identifier for the vanilla experience level layer. + */ + class_2960 EXPERIENCE_LEVEL = class_2960.method_60656("experience_level"); + /** + * The identifier for the vanilla status effects layer. + */ + class_2960 STATUS_EFFECTS = class_2960.method_60656("status_effects"); + /** + * The identifier for the vanilla boss bar layer. + */ + class_2960 BOSS_BAR = class_2960.method_60656("boss_bar"); + /** + * The identifier for the vanilla sleep overlay layer. + */ + class_2960 SLEEP = class_2960.method_60656("sleep"); + /** + * The identifier for the vanilla demo timer layer. + */ + class_2960 DEMO_TIMER = class_2960.method_60656("demo_timer"); + /** + * The identifier for the vanilla debug hud layer. + */ + class_2960 DEBUG = class_2960.method_60656("debug"); + /** + * The identifier for the vanilla scoreboard layer. + */ + class_2960 SCOREBOARD = class_2960.method_60656("scoreboard"); + /** + * The identifier for the vanilla overlay message layer. + */ + class_2960 OVERLAY_MESSAGE = class_2960.method_60656("overlay_message"); + /** + * The identifier for the vanilla title and subtitle layer. + * + *

Note that this is not the sound subtitles. + */ + class_2960 TITLE_AND_SUBTITLE = class_2960.method_60656("title_and_subtitle"); + /** + * The identifier for the vanilla chat layer. + */ + class_2960 CHAT = class_2960.method_60656("chat"); + /** + * The identifier for the vanilla player list layer. + */ + class_2960 PLAYER_LIST = class_2960.method_60656("player_list"); + /** + * The identifier for the vanilla sound subtitles layer. + */ + class_2960 SUBTITLES = class_2960.method_60656("subtitles"); + + /** + * @return the identifier of the layer + */ + class_2960 id(); + + /** + * Wraps a hud layer in an identified layer. + * + * @param id the identifier to give the layer + * @param layer the layer to wrap + * @return the identified layer + */ + static IdentifiedLayer of(class_2960 id, class_9080.class_9081 layer) { + return new WrappedLayer(id, layer); + } +} diff --git a/net/fabricmc/fabric/api/client/rendering/v1/LayeredDrawerWrapper.java b/net/fabricmc/fabric/api/client/rendering/v1/LayeredDrawerWrapper.java new file mode 100644 index 0000000..a5ceb45 --- /dev/null +++ b/net/fabricmc/fabric/api/client/rendering/v1/LayeredDrawerWrapper.java @@ -0,0 +1,151 @@ +/* + * 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; + +import java.util.function.Function; +import net.minecraft.class_2960; +import net.minecraft.class_9080; +import org.jetbrains.annotations.Contract; + +/** + * A layered drawer that has an identifier attached to each layer and methods to add layers in specific positions. + * + *

Operations relative to a layer will generally inherit that layer's render condition. + * The render condition for all vanilla layers except {@link IdentifiedLayer#SLEEP} is {@link net.minecraft.class_315#field_1842}. + * Only {@link #addLayer(IdentifiedLayer)} will not inherit any render condition. + * There is currently no mechanism to change the render condition of a layer. + * For vanilla layers, see {@link IdentifiedLayer}. + * + *

Common places to add layers (as of 1.21.4): + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Injection PointUse Case
Before {@link IdentifiedLayer#MISC_OVERLAYS MISC_OVERLAYS}Render before everything
After {@link IdentifiedLayer#MISC_OVERLAYS MISC_OVERLAYS}Render after misc overlays (vignette, spyglass, and powder snow) and before the crosshair
After {@link IdentifiedLayer#EXPERIENCE_LEVEL EXPERIENCE_LEVEL}Render after most main hud elements like hotbar, spectator hud, status bars, experience bar, status effects overlays, and boss bar and before the sleep overlay
Before {@link IdentifiedLayer#DEMO_TIMER DEMO_TIMER}Render after sleep overlay and before the demo timer, debug HUD, scoreboard, overlay message (action bar), and title and subtitle
Before {@link IdentifiedLayer#CHAT CHAT}Render after the debug HUD, scoreboard, overlay message (action bar), and title and subtitle and before {@link net.minecraft.class_338 ChatHud}, player list, and sound subtitles
After {@link IdentifiedLayer#SUBTITLES SUBTITLES}Render after everything
+ * + * @see HudLayerRegistrationCallback + */ +public interface LayeredDrawerWrapper { + /** + * Adds a layer to the end of the layered drawer. + * + * @param layer the layer to add + * @return this layered drawer + */ + @Contract("_ -> this") + LayeredDrawerWrapper addLayer(IdentifiedLayer layer); + + /** + * Attaches a layer before the layer with the specified identifier. + * + *

The render condition of the layer being attached to, if any, also applies to the new layer. + * + * @param beforeThis the identifier of the layer to add the new layer before + * @param layer the layer to add + * @return this layered drawer + */ + @Contract("_, _ -> this") + LayeredDrawerWrapper attachLayerBefore(class_2960 beforeThis, IdentifiedLayer layer); + + /** + * Attaches a layer before the layer with the specified identifier. + * + *

The render condition of the layer being attached to, if any, also applies to the new layer. + * + * @param beforeThis the identifier of the layer to add the new layer before + * @param identifier the identifier of the new layer + * @param layer the layer to add + * @return this layered drawer + */ + @Contract("_, _, _ -> this") + default LayeredDrawerWrapper attachLayerBefore(class_2960 beforeThis, class_2960 identifier, class_9080.class_9081 layer) { + return attachLayerBefore(beforeThis, IdentifiedLayer.of(identifier, layer)); + } + + /** + * Attaches a layer after the layer with the specified identifier. + * + *

The render condition of the layer being attached to, if any, also applies to the new layer. + * + * @param afterThis the identifier of the layer to add the new layer after + * @param layer the layer to add + * @return this layered drawer + */ + @Contract("_, _ -> this") + LayeredDrawerWrapper attachLayerAfter(class_2960 afterThis, IdentifiedLayer layer); + + /** + * Attaches a layer after the layer with the specified identifier. + * + *

The render condition of the layer being attached to, if any, also applies to the new layer. + * + * @param afterThis the identifier of the layer to add the new layer after + * @param identifier the identifier of the new layer + * @param layer the layer to add + * @return this layered drawer + */ + @Contract("_, _, _ -> this") + default LayeredDrawerWrapper attachLayerAfter(class_2960 afterThis, class_2960 identifier, class_9080.class_9081 layer) { + return attachLayerAfter(afterThis, IdentifiedLayer.of(identifier, layer)); + } + + /** + * Removes a layer with the specified identifier. + * + * @param identifier the identifier of the layer to remove + * @return this layered drawer + */ + @Contract("_ -> this") + LayeredDrawerWrapper removeLayer(class_2960 identifier); + + /** + * Replaces a layer with the specified identifier. + * + *

The render condition of the layer being replaced, if any, also applies to the new layer. + * + * @param identifier the identifier of the layer to replace + * @param replacer a function that takes the old layer and returns the new layer + * @return this layered drawer + */ + @Contract("_, _ -> this") + LayeredDrawerWrapper replaceLayer(class_2960 identifier, Function replacer); +} diff --git a/net/fabricmc/fabric/api/client/rendering/v1/hud/HudElement.java b/net/fabricmc/fabric/api/client/rendering/v1/hud/HudElement.java new file mode 100644 index 0000000..974349a --- /dev/null +++ b/net/fabricmc/fabric/api/client/rendering/v1/hud/HudElement.java @@ -0,0 +1,36 @@ +/* + * 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.hud; + +import net.minecraft.class_332; +import net.minecraft.class_9779; + +/** + * Represents a mod added {@link net.minecraft.class_329} element that can be rendered on the screen. + * + * + *

HUD elements should be registered using {@link HudElementRegistry} + */ +public interface HudElement { + /** + * Renders the HUD element. + * + * @param context the {@link class_332} used for rendering + * @param tickCounter the {@link class_9779} providing timing information + */ + void render(class_332 context, class_9779 tickCounter); +} diff --git a/net/fabricmc/fabric/api/client/rendering/v1/hud/HudElementRegistry.java b/net/fabricmc/fabric/api/client/rendering/v1/hud/HudElementRegistry.java new file mode 100644 index 0000000..ff253ff --- /dev/null +++ b/net/fabricmc/fabric/api/client/rendering/v1/hud/HudElementRegistry.java @@ -0,0 +1,153 @@ +/* + * 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.hud; + +import java.util.Objects; +import java.util.function.Function; +import net.fabricmc.fabric.impl.client.rendering.hud.HudElementRegistryImpl; +import net.minecraft.class_2960; + +/** + * A registry of identified hud layers with methods to add layers in specific positions. + * + *

Operations relative to a vanilla element will inherit that element's render condition. + * + *

The render condition for all vanilla layers except {@link VanillaHudElements#SLEEP} is + * {@link net.minecraft.class_315#field_1842}. + * + *

Only {@link #addFirst(class_2960, HudElement)} and {@link #addLast(class_2960, HudElement)} will not inherit any + * render condition. + * + *

There is currently no mechanism to change the render condition of a vanilla element. + * + *

For vanilla layers, see {@link VanillaHudElements}. + * + *

Common places to add layers (as of 1.21.6): + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Injection PointUse Case
Before {@link VanillaHudElements#MISC_OVERLAYS MISC_OVERLAYS}Render before everything
After {@link VanillaHudElements#MISC_OVERLAYS MISC_OVERLAYS}Render after misc overlays (vignette, spyglass, and powder snow) and before the crosshair
After {@link VanillaHudElements#BOSS_BAR BOSS_BAR}Render after most main hud layers like hotbar, spectator hud, status bars, experience bar, status effects overlays, and boss bar and before the sleep overlay
Before {@link VanillaHudElements#DEMO_TIMER DEMO_TIMER}Render after sleep overlay and before the demo timer, debug HUD, scoreboard, overlay message (action bar), and title and subtitle
Before {@link VanillaHudElements#CHAT CHAT}Render after the debug HUD, scoreboard, overlay message (action bar), and title and subtitle and before {@link net.minecraft.class_338 ChatHud}, player list, and sound subtitles
After {@link VanillaHudElements#SUBTITLES SUBTITLES}Render after everything
+ */ +public interface HudElementRegistry { + /** + * Adds an element to the front. + * + * @param element the element to add + */ + static void addFirst(class_2960 id, HudElement element) { + Objects.requireNonNull(id, "identifier"); + Objects.requireNonNull(element, "hudElement"); + HudElementRegistryImpl.addFirst(id, element); + } + + /** + * Adds an element to the end. + * + * @param element the element to add + */ + static void addLast(class_2960 id, HudElement element) { + Objects.requireNonNull(id, "identifier"); + Objects.requireNonNull(element, "hudElement"); + HudElementRegistryImpl.addLast(id, element); + } + + /** + * Attaches an element before the element with the specified identifier. + * + *

The render condition of the vanilla element being attached to, if any, also applies to the new element. + * + * @param beforeThis the identifier of the element to add the new element before + * @param identifier the identifier of the new element + * @param element the element to add + */ + static void attachElementBefore(class_2960 beforeThis, class_2960 identifier, HudElement element) { + Objects.requireNonNull(beforeThis, "beforeThis"); + Objects.requireNonNull(identifier, "identifier"); + Objects.requireNonNull(element, "hudElement"); + HudElementRegistryImpl.attachElementBefore(beforeThis, identifier, element); + } + + /** + * Attaches an element after the element with the specified identifier. + * + *

The render condition of the vanilla element being attached to, if any, also applies to the new element. + * + * @param afterThis the identifier of the element to add the new element after + * @param identifier the identifier of the new element + * @param element the element to add + */ + static void attachElementAfter(class_2960 afterThis, class_2960 identifier, HudElement element) { + Objects.requireNonNull(afterThis, "afterThis"); + Objects.requireNonNull(identifier, "identifier"); + Objects.requireNonNull(element, "hudElement"); + HudElementRegistryImpl.attachElementAfter(afterThis, identifier, element); + } + + /** + * Removes an element with the specified identifier. + * + * @param identifier the identifier of the element to remove + */ + static void removeElement(class_2960 identifier) { + Objects.requireNonNull(identifier, "identifier"); + HudElementRegistryImpl.removeElement(identifier); + } + + /** + * Replaces an element with the specified identifier, the element retains its original identifier. + * + *

The render condition of the vanilla element being replaced, if any, also applies to the new element. + * + *

If the replaced element is a status bar (like {@link VanillaHudElements#HEALTH_BAR HEALTH_BAR}, + * {@link VanillaHudElements#ARMOR_BAR ARMOR_BAR} or {@link VanillaHudElements#FOOD_BAR FOOD_BAR}), it may be + * necessary to register a new {@link StatusBarHeightProvider} in {@link HudStatusBarHeightRegistry}. + * + * @param identifier the identifier of the element to replace + * @param replacer a function that takes the old element and returns the new element + */ + static void replaceElement(class_2960 identifier, Function replacer) { + Objects.requireNonNull(identifier, "identifier"); + Objects.requireNonNull(replacer, "replacer"); + HudElementRegistryImpl.replaceElement(identifier, replacer); + } +} diff --git a/net/fabricmc/fabric/api/client/rendering/v1/hud/VanillaHudElements.java b/net/fabricmc/fabric/api/client/rendering/v1/hud/VanillaHudElements.java new file mode 100644 index 0000000..af940d0 --- /dev/null +++ b/net/fabricmc/fabric/api/client/rendering/v1/hud/VanillaHudElements.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.api.client.rendering.v1.hud; + +import net.minecraft.class_2960; + +/** + * A hud element that has an identifier attached for use in {@link HudElementRegistry}. + * + *

The identifiers in this interface are the vanilla hud layers in the order they are drawn in. + * The first element is drawn first, which means it is at the bottom. + * All vanilla layers except {@link #SLEEP} are in sub drawers and have a render condition attached ({@link net.minecraft.class_315#field_1842}). + * Operations relative to any element will generally inherit that element's render condition. + * There is currently no mechanism to change the render condition of an element. + * + *

For common use cases and more details on how this API deals with render condition, see {@link HudElementRegistry}. + */ +public final class VanillaHudElements { + /** + * The identifier for the vanilla miscellaneous overlays (such as vignette, spyglass, and powder snow) element. + */ + public static final class_2960 MISC_OVERLAYS = class_2960.method_60656("misc_overlays"); + /** + * The identifier for the vanilla crosshair element. + */ + public static final class_2960 CROSSHAIR = class_2960.method_60656("crosshair"); + /** + * The identifier for the vanilla spectator menu. + */ + public static final class_2960 SPECTATOR_MENU = class_2960.method_60656("spectator_menu"); + /** + * The identifier for the vanilla hotbar. + */ + public static final class_2960 HOTBAR = class_2960.method_60656("hotbar"); + /** + * The identifier for the player armor level bar. + */ + public static final class_2960 ARMOR_BAR = class_2960.method_60656("armor_bar"); + /** + * The identifier for the player health bar. + */ + public static final class_2960 HEALTH_BAR = class_2960.method_60656("health_bar"); + /** + * The identifier for the player hunger level bar. + */ + public static final class_2960 FOOD_BAR = class_2960.method_60656("food_bar"); + /** + * The identifier for the player air level bar. + */ + public static final class_2960 AIR_BAR = class_2960.method_60656("air_bar"); + /** + * The identifier for the vanilla mount health. + */ + public static final class_2960 MOUNT_HEALTH = class_2960.method_60656("mount_health"); + /** + * The identifier for the info bar, either empty, experience bar, locator, or jump bar. + */ + public static final class_2960 INFO_BAR = class_2960.method_60656("info_bar"); + /** + * The identifier for experience level tooltip. + */ + public static final class_2960 EXPERIENCE_LEVEL = class_2960.method_60656("experience_level"); + /** + * The identifier for held item tooltip. + */ + public static final class_2960 HELD_ITEM_TOOLTIP = class_2960.method_60656("held_item_tooltip"); + /** + * The identifier for the vanilla spectator tooltip. + */ + public static final class_2960 SPECTATOR_TOOLTIP = class_2960.method_60656("spectator_tooltip"); + /** + * The identifier for the vanilla status effects element. + */ + public static final class_2960 STATUS_EFFECTS = class_2960.method_60656("status_effects"); + /** + * The identifier for the vanilla boss bar element. + */ + public static final class_2960 BOSS_BAR = class_2960.method_60656("boss_bar"); + /** + * The identifier for the vanilla sleep overlay element. + */ + public static final class_2960 SLEEP = class_2960.method_60656("sleep"); + /** + * The identifier for the vanilla demo timer element. + */ + public static final class_2960 DEMO_TIMER = class_2960.method_60656("demo_timer"); + /** + * The identifier for the vanilla debug hud element. + */ + public static final class_2960 DEBUG = class_2960.method_60656("debug"); + /** + * The identifier for the vanilla scoreboard element. + */ + public static final class_2960 SCOREBOARD = class_2960.method_60656("scoreboard"); + /** + * The identifier for the vanilla overlay message element. + */ + public static final class_2960 OVERLAY_MESSAGE = class_2960.method_60656("overlay_message"); + /** + * The identifier for the vanilla title and subtitle element. + * + *

Note that this is not the sound subtitles. + */ + public static final class_2960 TITLE_AND_SUBTITLE = class_2960.method_60656("title_and_subtitle"); + /** + * The identifier for the vanilla chat element. + */ + public static final class_2960 CHAT = class_2960.method_60656("chat"); + /** + * The identifier for the vanilla player list element. + */ + public static final class_2960 PLAYER_LIST = class_2960.method_60656("player_list"); + /** + * The identifier for the vanilla sound subtitles element. + */ + public static final class_2960 SUBTITLES = class_2960.method_60656("subtitles"); + + private VanillaHudElements() { + } +} diff --git a/src/client/java/dev/dekin/iconsenhanced/client/BorderRenderer.java b/src/client/java/dev/dekin/iconsenhanced/client/BorderRenderer.java index d725321..de6f5c4 100644 --- a/src/client/java/dev/dekin/iconsenhanced/client/BorderRenderer.java +++ b/src/client/java/dev/dekin/iconsenhanced/client/BorderRenderer.java @@ -58,6 +58,46 @@ public final class BorderRenderer { } } + public static void renderHud(GuiGraphics graphics) { + IconsEnhancedConfig config = ConfigManager.get(); + if (!config.borders.enabled) { + return; + } + Minecraft client = Minecraft.getInstance(); + if (client.player == null || client.level == null || client.options.hideGui) { + return; + } + if (client.screen != null) { + return; + } + + int thickness = clamp(config.borders.thickness, 1, 3); + boolean redrawItems = config.tooltips.enabled && config.tooltips.showIcons; + Font font = redrawItems ? client.font : null; + int width = client.getWindow().getGuiScaledWidth(); + int height = client.getWindow().getGuiScaledHeight(); + int left = (width / 2) - 91; + int top = height - 22; + + for (int i = 0; i < 9; i++) { + ItemStack stack = client.player.getInventory().getItem(i); + if (stack.isEmpty()) { + continue; + } + int slotX = left + (i * 20) + 3; + int slotY = top + 3; + int color = COLOR_LOGIC.resolve(stack); + if ((color >>> 24) == 0) { + continue; + } + drawBorder(graphics, slotX, slotY, thickness, color); + if (redrawItems) { + graphics.renderItem(stack, slotX, slotY); + graphics.renderItemDecorations(font, stack, slotX, slotY); + } + } + } + private static void drawBorder(GuiGraphics graphics, int x, int y, int thickness, int color) { int left = x; int top = y; diff --git a/src/client/java/dev/dekin/iconsenhanced/client/ClientInit.java b/src/client/java/dev/dekin/iconsenhanced/client/ClientInit.java index b3e7b7c..d06bfcd 100644 --- a/src/client/java/dev/dekin/iconsenhanced/client/ClientInit.java +++ b/src/client/java/dev/dekin/iconsenhanced/client/ClientInit.java @@ -1,9 +1,22 @@ package dev.dekin.iconsenhanced.client; +import dev.dekin.iconsenhanced.IconsEnhanced; import dev.dekin.iconsenhanced.common.ConfigManager; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; +//? if >=1.20.5 { +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry; +import net.fabricmc.fabric.api.client.rendering.v1.hud.VanillaHudElements; +//?} else { +/*import net.fabricmc.fabric.api.client.rendering.v1.HudLayerRegistrationCallback; +import net.fabricmc.fabric.api.client.rendering.v1.IdentifiedLayer; +*///?} import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; +//? if >=1.21.11 { +import net.minecraft.resources.Identifier; +//?} else { +/*import net.minecraft.resources.ResourceLocation; +*///?} public final class ClientInit implements ClientModInitializer { @Override @@ -12,6 +25,7 @@ public final class ClientInit implements ClientModInitializer { BorderRenderer.applyConfig(); TooltipAugmenter.register(); ClientTickEvents.END_CLIENT_TICK.register(client -> TooltipAugmenter.registerLate()); + registerHudBorders(); ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> { ScreenEvents.beforeRender(screen).register((current, graphics, mouseX, mouseY, delta) -> { @@ -24,4 +38,20 @@ public final class ClientInit implements ClientModInitializer { }); }); } + + private static void registerHudBorders() { + //? if >=1.21.11 { + Identifier id = Identifier.fromNamespaceAndPath(IconsEnhanced.MOD_ID, "hotbar_borders"); + //?} else if >=1.21 { + /*ResourceLocation id = ResourceLocation.fromNamespaceAndPath(IconsEnhanced.MOD_ID, "hotbar_borders"); + *///?} else { + /*ResourceLocation id = new ResourceLocation(IconsEnhanced.MOD_ID, "hotbar_borders"); + *///?} + //? if >=1.20.5 { + HudElementRegistry.attachElementAfter(VanillaHudElements.HOTBAR, id, (graphics, tickCounter) -> BorderRenderer.renderHud(graphics)); + //?} else { + /*HudLayerRegistrationCallback.EVENT.register(layeredDrawer -> + layeredDrawer.attachLayerAfter(IdentifiedLayer.HOTBAR_AND_BARS, id, (graphics, tickCounter) -> BorderRenderer.renderHud(graphics))); + *///?} + } }