Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TooltipDataCallback (copy of #3403 using Mixin Extras) #3486

Open
wants to merge 13 commits into
base: 1.20.4
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
* <p>Note that failure to map some data to a component will throw an exception,
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
*
* <p>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<TooltipDataCallback> 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<TooltipData> tooltipDataList);
}
Original file line number Diff line number Diff line change
@@ -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<TooltipComponent> components;

public static MultiTooltipComponent of(List<TooltipData> data) {
var l = new ArrayList<TooltipComponent>(data.size());

for (TooltipData d : data) {
l.add(TooltipComponent.of(d));
}

return new MultiTooltipComponent(l);
}

public MultiTooltipComponent(List<TooltipComponent> 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();
}
}
Original file line number Diff line number Diff line change
@@ -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;
});
}
}
Original file line number Diff line number Diff line change
@@ -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> tooltipData) implements TooltipData {
}
Original file line number Diff line number Diff line change
@@ -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<TooltipData> addMultiData(ItemStack stack, Operation<Optional<TooltipData>> original) {
var multiData = new MultiTooltipData(new ArrayList<>());
TooltipDataCallback.EVENT.invoker().appendTooltipData(stack, multiData.tooltipData());

if (multiData.tooltipData().isEmpty()) {
return original.call(stack);
Comment on lines +38 to +42
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behaves diffrently to the other PR. Whats the expected behaviour?

}

original.call(stack).ifPresent(multiData.tooltipData()::add);
return Optional.of(multiData);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"EntityModelLayersAccessor",
"EntityModelsMixin",
"EntityRenderersMixin",
"HandledScreenMixin",
"InGameHudMixin",
"ItemColorsMixin",
"LivingEntityRendererAccessor",
Expand Down
5 changes: 5 additions & 0 deletions fabric-rendering-v1/src/client/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
5 changes: 4 additions & 1 deletion fabric-rendering-v1/src/testmod/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
]
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
Loading
Loading