diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/TooltipComponentCallback.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/TooltipComponentCallback.java index f0a6b0c941..ee2786d205 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/TooltipComponentCallback.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/TooltipComponentCallback.java @@ -27,7 +27,8 @@ /** * Allows registering a mapping from {@link TooltipData} to {@link TooltipComponent}. - * This allows custom tooltips for items: first, override {@link Item#getTooltipData} and return a custom {@code TooltipData}. + * This allows custom tooltips for items: first, override {@link Item#getTooltipData} and return a custom {@code TooltipData}, or use + * {@link TooltipDataCallback} to add {@link TooltipData} to an existing item. * Second, register a listener to this event and convert the data to your component implementation if it's an instance of your data class. * *

Note that failure to map some data to a component will throw an exception, diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/TooltipDataCallback.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/TooltipDataCallback.java new file mode 100644 index 0000000000..eef5298fbc --- /dev/null +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/TooltipDataCallback.java @@ -0,0 +1,47 @@ +/* + * 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.List; + +import net.minecraft.client.gui.tooltip.TooltipComponent; +import net.minecraft.client.item.TooltipData; +import net.minecraft.item.ItemStack; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; + +/** + * Allows registering custom {@link TooltipData} object for item. + * This allows you to add your own tooltips to existing items. + * + *

Custom {@link TooltipData} should be registered using {@link TooltipComponentCallback}, + * otherwise game will crash when trying to map {@link TooltipData} to {@link TooltipComponent}. + */ +@FunctionalInterface +public interface TooltipDataCallback { + Event EVENT = EventFactory.createArrayBacked(TooltipDataCallback.class, callbacks -> (itemStack, tooltipDataList) -> { + for (TooltipDataCallback callback : callbacks) { + callback.appendTooltipData(itemStack, tooltipDataList); + } + }); + + /** + * Add your own {@link TooltipData} to passed list if itemStack matches your requirements. + */ + void appendTooltipData(ItemStack itemStack, List tooltipDataList); +} diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/tooltip/MultiTooltipComponent.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/tooltip/MultiTooltipComponent.java new file mode 100644 index 0000000000..aeef327f50 --- /dev/null +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/tooltip/MultiTooltipComponent.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.impl.client.rendering.tooltip; + +import java.util.ArrayList; +import java.util.List; + +import org.joml.Matrix4f; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.tooltip.TooltipComponent; +import net.minecraft.client.item.TooltipData; +import net.minecraft.client.render.VertexConsumerProvider; + +/** + * This class renders multiple tooltip components as one. + */ +public class MultiTooltipComponent implements TooltipComponent { + private final int height; + private final int width; + private final List components; + + public static MultiTooltipComponent of(List data) { + var l = new ArrayList(data.size()); + + for (TooltipData d : data) { + l.add(TooltipComponent.of(d)); + } + + return new MultiTooltipComponent(l); + } + + public MultiTooltipComponent(List components) { + this.components = components; + int height = 0; + int width = 0; + + for (TooltipComponent component : components) { + height += component.getHeight(); + width = Math.max(width, component.getWidth(MinecraftClient.getInstance().textRenderer)); + } + + this.height = height; + this.width = width; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public int getWidth(TextRenderer textRenderer) { + return width; + } + + @Override + public void drawText(TextRenderer textRenderer, int x, int y, Matrix4f matrix, VertexConsumerProvider.Immediate vertexConsumers) { + Matrix4f matrixCopy = new Matrix4f(matrix); + + for (TooltipComponent c : components) { + c.drawText(textRenderer, x, y, matrixCopy, vertexConsumers); + matrixCopy.translate(0, c.getHeight(), 0); + } + } + + @Override + public void drawItems(TextRenderer textRenderer, int x, int y, DrawContext context) { + context.getMatrices().push(); + + for (TooltipComponent c : components) { + c.drawItems(textRenderer, x, y, context); + context.getMatrices().translate(0, c.getHeight(), 0); + } + + context.getMatrices().pop(); + } +} diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/tooltip/MultiTooltipComponentRegister.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/tooltip/MultiTooltipComponentRegister.java new file mode 100644 index 0000000000..3828331423 --- /dev/null +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/tooltip/MultiTooltipComponentRegister.java @@ -0,0 +1,33 @@ +/* + * 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.tooltip; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.rendering.v1.TooltipComponentCallback; + +public class MultiTooltipComponentRegister implements ClientModInitializer { + @Override + public void onInitializeClient() { + TooltipComponentCallback.EVENT.register((tooltipData) -> { + if (tooltipData instanceof MultiTooltipData multiTooltipData) { + return MultiTooltipComponent.of(multiTooltipData.tooltipData()); + } + + return null; + }); + } +} diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/tooltip/MultiTooltipData.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/tooltip/MultiTooltipData.java new file mode 100644 index 0000000000..9e98cea7bd --- /dev/null +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/tooltip/MultiTooltipData.java @@ -0,0 +1,27 @@ +/* + * 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.tooltip; + +import java.util.List; + +import net.minecraft.client.item.TooltipData; + +/** + * This class stores multiple TooltipData object to their further mapping to MultiTooltipComponent. + */ +public record MultiTooltipData(List tooltipData) implements TooltipData { +} diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/HandledScreenMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/HandledScreenMixin.java new file mode 100644 index 0000000000..69b5e969a0 --- /dev/null +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/HandledScreenMixin.java @@ -0,0 +1,48 @@ +/* + * 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; + +import java.util.ArrayList; +import java.util.Optional; + +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.screen.ingame.HandledScreen; +import net.minecraft.client.item.TooltipData; +import net.minecraft.item.ItemStack; + +import net.fabricmc.fabric.api.client.rendering.v1.TooltipDataCallback; +import net.fabricmc.fabric.impl.client.rendering.tooltip.MultiTooltipData; + +@Mixin(HandledScreen.class) +class HandledScreenMixin { + @WrapOperation(method = "drawMouseoverTooltip", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getTooltipData()Ljava/util/Optional;")) + private Optional addMultiData(ItemStack stack, Operation> original) { + var multiData = new MultiTooltipData(new ArrayList<>()); + TooltipDataCallback.EVENT.invoker().appendTooltipData(stack, multiData.tooltipData()); + + if (multiData.tooltipData().isEmpty()) { + return original.call(stack); + } + + original.call(stack).ifPresent(multiData.tooltipData()::add); + return Optional.of(multiData); + } +} 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 3ef02acce3..ca8bc623ba 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 @@ -12,6 +12,7 @@ "EntityModelLayersAccessor", "EntityModelsMixin", "EntityRenderersMixin", + "HandledScreenMixin", "InGameHudMixin", "ItemColorsMixin", "LivingEntityRendererAccessor", diff --git a/fabric-rendering-v1/src/client/resources/fabric.mod.json b/fabric-rendering-v1/src/client/resources/fabric.mod.json index b0b955876a..5aa596656e 100644 --- a/fabric-rendering-v1/src/client/resources/fabric.mod.json +++ b/fabric-rendering-v1/src/client/resources/fabric.mod.json @@ -19,6 +19,11 @@ "fabricloader": ">=0.15.1", "fabric-api-base": "*" }, + "entrypoints": { + "client": [ + "net.fabricmc.fabric.impl.client.rendering.tooltip.MultiTooltipComponentRegister" + ] + }, "description": "Hooks and registries for rendering-related things.", "mixins": [ "fabric-rendering-v1.mixins.json" diff --git a/fabric-rendering-v1/src/testmod/resources/fabric.mod.json b/fabric-rendering-v1/src/testmod/resources/fabric.mod.json index f51ecb36c6..be6842d09e 100644 --- a/fabric-rendering-v1/src/testmod/resources/fabric.mod.json +++ b/fabric-rendering-v1/src/testmod/resources/fabric.mod.json @@ -15,7 +15,10 @@ "net.fabricmc.fabric.test.rendering.client.FeatureRendererTest", "net.fabricmc.fabric.test.rendering.client.TooltipComponentTests", "net.fabricmc.fabric.test.rendering.client.DimensionalRenderingTest", - "net.fabricmc.fabric.test.rendering.client.HudAndShaderTest" + "net.fabricmc.fabric.test.rendering.client.HudAndShaderTest", + "net.fabricmc.fabric.test.rendering.client.tooltip.BundleFullnessTooltipTest", + "net.fabricmc.fabric.test.rendering.client.tooltip.DurabilityTooltipTest", + "net.fabricmc.fabric.test.rendering.client.tooltip.FoodTooltipTest" ] } } diff --git a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/tooltip/BundleFullnessTooltipTest.java b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/tooltip/BundleFullnessTooltipTest.java new file mode 100644 index 0000000000..5c406f2608 --- /dev/null +++ b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/tooltip/BundleFullnessTooltipTest.java @@ -0,0 +1,82 @@ +/* + * 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.tooltip; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.tooltip.TooltipComponent; +import net.minecraft.client.item.TooltipData; +import net.minecraft.item.BundleItem; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.rendering.v1.TooltipComponentCallback; +import net.fabricmc.fabric.api.client.rendering.v1.TooltipDataCallback; + +public class BundleFullnessTooltipTest implements ClientModInitializer { + @Override + public void onInitializeClient() { + TooltipDataCallback.EVENT.register((itemStack, tooltipDataList) -> { + if (itemStack.getItem() instanceof BundleItem bundle) { + tooltipDataList.add(0, new BundleCustomTooltipData(BundleItem.getAmountFilled(itemStack))); + } + }); + TooltipComponentCallback.EVENT.register(data -> { + if (data instanceof BundleCustomTooltipData bundleCustomTooltipData) { + return new BundleFullnessTooltipComponent(bundleCustomTooltipData.fullness); + } + + return null; + }); + } + + private static class BundleCustomTooltipData implements TooltipData { + private final float fullness; + BundleCustomTooltipData(float fullness) { + this.fullness = fullness; + } + } + + private static class BundleFullnessTooltipComponent implements TooltipComponent { + private static final int BAR_WIDTH = 40; + private static final int BAR_HEIGHT = 10; + private static final int GAP = 2; + private final float fullness; + + BundleFullnessTooltipComponent(float fullness) { + this.fullness = fullness; + } + + @Override + public int getHeight() { + return BAR_HEIGHT + GAP; + } + + @Override + public int getWidth(TextRenderer textRenderer) { + return BAR_WIDTH; + } + + @Override + public void drawItems(TextRenderer textRenderer, int x, int y, DrawContext context) { + context.getMatrices().push(); + context.getMatrices().translate(x, y, 0); + context.fill(0, 0, BAR_WIDTH, BAR_HEIGHT, 0xFF3F007F); + context.fill(0, 0, (int) (BAR_WIDTH * fullness), BAR_HEIGHT, 0xFF7F00FF); + context.getMatrices().pop(); + } + } +} diff --git a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/tooltip/DurabilityTooltipTest.java b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/tooltip/DurabilityTooltipTest.java new file mode 100644 index 0000000000..dde717c9ad --- /dev/null +++ b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/tooltip/DurabilityTooltipTest.java @@ -0,0 +1,79 @@ +/* + * 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.tooltip; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.tooltip.TooltipComponent; +import net.minecraft.client.item.TooltipData; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.rendering.v1.TooltipComponentCallback; +import net.fabricmc.fabric.api.client.rendering.v1.TooltipDataCallback; + +public class DurabilityTooltipTest implements ClientModInitializer { + @Override + public void onInitializeClient() { + TooltipDataCallback.EVENT.register((itemStack, tooltipDataList) -> { + if (itemStack.isDamageable()) { + tooltipDataList.add(new DamagedItemData(itemStack.getDamage(), itemStack.getMaxDamage())); + } + }); + + TooltipComponentCallback.EVENT.register(data -> { + if (data instanceof DamagedItemData damagedItemData) { + return new DurabilityModTooltipComponent(damagedItemData); + } + + return null; + }); + } + + public record DamagedItemData(int durability, int maxDurability) implements TooltipData { + } + + private static class DurabilityModTooltipComponent implements TooltipComponent { + private static final int BAR_WIDTH = 40; + private static final int BAR_HEIGHT = 10; + private static final int GAP = 2; + private final DamagedItemData damage; + + DurabilityModTooltipComponent(DamagedItemData data) { + this.damage = data; + } + + @Override + public int getHeight() { + return BAR_HEIGHT + GAP; + } + + @Override + public int getWidth(TextRenderer textRenderer) { + return BAR_WIDTH; + } + + @Override + public void drawItems(TextRenderer textRenderer, int x, int y, DrawContext context) { + context.getMatrices().push(); + context.getMatrices().translate(x, y, 0); + float width = 1-(float) this.damage.durability / this.damage.maxDurability; + context.fill(0, 0, BAR_WIDTH, BAR_HEIGHT, 0xFFFF0000); + context.fill(0, 0, (int) (BAR_WIDTH * width), BAR_HEIGHT, 0xFF00FF00); + context.getMatrices().pop(); + } + } +} diff --git a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/tooltip/FoodTooltipTest.java b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/tooltip/FoodTooltipTest.java new file mode 100644 index 0000000000..6f07aeeb79 --- /dev/null +++ b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/tooltip/FoodTooltipTest.java @@ -0,0 +1,87 @@ +/* + * 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.tooltip; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.tooltip.TooltipComponent; +import net.minecraft.client.item.TooltipData; +import net.minecraft.item.FoodComponent; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.rendering.v1.TooltipComponentCallback; +import net.fabricmc.fabric.api.client.rendering.v1.TooltipDataCallback; + +public class FoodTooltipTest implements ClientModInitializer { + @Override + public void onInitializeClient() { + TooltipDataCallback.EVENT.register((itemStack, tooltipDataList) -> { + if (itemStack.getItem().getFoodComponent() != null) { + var foodData = new FoodItemData(itemStack.getItem().getFoodComponent()); + tooltipDataList.add(foodData); + } + }); + + TooltipComponentCallback.EVENT.register(data -> { + if (data instanceof FoodItemData foodItemData) { + return new FoodModTooltip(foodItemData); + } + + return null; + }); + } + + private static class FoodItemData implements TooltipData { + public final int hunger; + FoodItemData(FoodComponent foodComponent) { + this.hunger = foodComponent.getHunger(); + } + } + + private static class FoodModTooltip implements TooltipComponent { + private final FoodItemData food; + private static final int SIZE = 8; + private static final int GAP = 2; + + FoodModTooltip(FoodItemData foodItemData) { + this.food = foodItemData; + } + + @Override + public int getHeight() { + return (SIZE + GAP); + } + + @Override + public int getWidth(TextRenderer textRenderer) { + return (SIZE + GAP) * food.hunger - GAP; + } + + @Override + public void drawItems(TextRenderer textRenderer, int x, int y, DrawContext context) { + context.getMatrices().push(); + context.getMatrices().translate(x, y, 0); + + for (int i = 0; i < food.hunger; i++) { + context.fill(0, 0, SIZE, SIZE, 0xFFFFFF00); + context.getMatrices().translate(GAP + SIZE, 0, 0); + } + + context.getMatrices().pop(); + } + } +} diff --git a/fabric-sound-api-v1/build.gradle b/fabric-sound-api-v1/build.gradle index b484a8a73e..82d948803c 100644 --- a/fabric-sound-api-v1/build.gradle +++ b/fabric-sound-api-v1/build.gradle @@ -5,3 +5,10 @@ testDependencies(project, [ ':fabric-resource-loader-v0', ':fabric-command-api-v2' ]) +repositories { + maven { url "https://maven.kikugie.dev/releases"} +} + +dependencies { + include(modImplementation "dev.kikugie:crash-pipe:0.1.0") +}