1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-12-04 23:40:00 +00:00

Render pocket computers in tooltips

This commit is contained in:
Jonathan Coates 2024-10-24 18:49:14 +01:00
parent c271ed7c7f
commit 94e7d2d03b
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
7 changed files with 158 additions and 13 deletions

View File

@ -56,4 +56,8 @@ public final class ClientPocketComputers {
var id = PocketComputerItem.getInstanceID(stack); var id = PocketComputerItem.getInstanceID(stack);
return id == null ? null : instances.get(id); return id == null ? null : instances.get(id);
} }
static @Nullable PocketComputerData get(UUID id) {
return instances.get(id);
}
} }

View File

@ -0,0 +1,101 @@
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.client.pocket;
import com.mojang.blaze3d.vertex.PoseStack;
import dan200.computercraft.client.gui.GuiSprites;
import dan200.computercraft.client.render.ComputerBorderRenderer;
import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.client.render.SpriteRenderer;
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
import dan200.computercraft.shared.pocket.items.PocketTooltipComponent;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent;
import net.minecraft.client.renderer.MultiBufferSource;
import javax.annotation.Nullable;
import java.util.UUID;
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
/**
* Renders the pocket computer's terminal in the item's tooltip.
* <p>
* The rendered terminal is downscaled by a factor of {@link #SCALE}.
*/
public class PocketClientTooltipComponent implements ClientTooltipComponent {
private static final float SCALE = 0.5f;
private final UUID id;
private final ComputerFamily family;
public PocketClientTooltipComponent(PocketTooltipComponent component) {
this.id = component.id();
this.family = component.family();
}
private @Nullable PocketComputerData computer() {
return ClientPocketComputers.get(id);
}
private @Nullable NetworkedTerminal terminal() {
var computer = computer();
return computer == null ? null : computer.getTerminal();
}
@Override
public int getHeight() {
var terminal = terminal();
if (terminal == null) return 0;
return (int) Math.ceil(
(terminal.getHeight() * FixedWidthFontRenderer.FONT_HEIGHT + ComputerBorderRenderer.BORDER * 2 + ComputerBorderRenderer.MARGIN * 2) * SCALE
);
}
@Override
public int getWidth(Font font) {
var terminal = terminal();
if (terminal == null) return 0;
return (int) Math.ceil(
(terminal.getWidth() * FixedWidthFontRenderer.FONT_WIDTH + ComputerBorderRenderer.BORDER * 2 + ComputerBorderRenderer.MARGIN * 2) * SCALE
);
}
@Override
public void renderImage(Font font, int x, int y, GuiGraphics guiGraphics) {
var terminal = terminal();
if (terminal == null) return;
var pose = guiGraphics.pose();
pose.pushPose();
pose.translate(x, y, 0);
pose.scale(SCALE, SCALE, 1);
render(pose, guiGraphics.bufferSource(), terminal);
pose.popPose();
}
private void render(PoseStack stack, MultiBufferSource buffers, Terminal terminal) {
var width = terminal.getWidth() * FONT_WIDTH + MARGIN * 2;
var height = terminal.getHeight() * FONT_HEIGHT + MARGIN * 2;
var renderer = SpriteRenderer.createForGui(stack.last().pose(), buffers.getBuffer(RenderTypes.GUI_SPRITES));
ComputerBorderRenderer.render(renderer, GuiSprites.getComputerTextures(family), BORDER, BORDER, width, height, false);
var quadEmitter = FixedWidthFontRenderer.toVertexConsumer(stack, buffers.getBuffer(RenderTypes.TERMINAL));
FixedWidthFontRenderer.drawTerminal(quadEmitter, BORDER + MARGIN, BORDER + MARGIN, terminal, MARGIN, MARGIN, MARGIN, MARGIN);
}
}

View File

@ -34,11 +34,12 @@ public class SpriteRenderer {
this.b = b; this.b = b;
} }
public static SpriteRenderer createForGui(Matrix4f transform, VertexConsumer builder) {
return new SpriteRenderer(transform, builder, 0, RenderTypes.FULL_BRIGHT_LIGHTMAP, 255, 255, 255);
}
public static SpriteRenderer createForGui(GuiGraphics graphics, RenderType renderType) { public static SpriteRenderer createForGui(GuiGraphics graphics, RenderType renderType) {
return new SpriteRenderer( return createForGui(graphics.pose().last().pose(), graphics.bufferSource().getBuffer(renderType));
graphics.pose().last().pose(), graphics.bufferSource().getBuffer(renderType),
0, RenderTypes.FULL_BRIGHT_LIGHTMAP, 255, 255, 255
);
} }
/** /**

View File

@ -28,7 +28,6 @@ import dan200.computercraft.shared.util.IDAssigner;
import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.InventoryUtil;
import dan200.computercraft.shared.util.NBTUtil; import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
@ -39,6 +38,7 @@ import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.tooltip.TooltipComponent;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.TooltipFlag;
@ -47,6 +47,7 @@ import net.minecraft.world.level.Level;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
public class PocketComputerItem extends Item implements IComputerItem, IMedia, IColouredItem { public class PocketComputerItem extends Item implements IComputerItem, IMedia, IColouredItem {
@ -196,6 +197,11 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
} }
} }
@Override
public Optional<TooltipComponent> getTooltipImage(ItemStack stack) {
var id = getInstanceID(stack);
return id == null ? Optional.empty() : Optional.of(new PocketTooltipComponent(id, family));
}
@Override @Override
public void appendHoverText(ItemStack stack, @Nullable Level world, List<Component> list, TooltipFlag flag) { public void appendHoverText(ItemStack stack, @Nullable Level world, List<Component> list, TooltipFlag flag) {
@ -350,8 +356,4 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
compound.put(NBT_UPGRADE_INFO, upgrade.data().copy()); compound.put(NBT_UPGRADE_INFO, upgrade.data().copy());
} }
} }
public static CompoundTag getUpgradeInfo(ItemStack stack) {
return stack.getOrCreateTagElement(NBT_UPGRADE_INFO);
}
} }

View File

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.shared.pocket.items;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import net.minecraft.world.inventory.tooltip.TooltipComponent;
import net.minecraft.world.item.ItemStack;
import java.util.UUID;
/**
* A tooltip computer describing a pocket computer.
* <p>
* This has no behaviour on its own. When rendering, this is converted to an equivalent client-side component,
* that renders the computer's terminal.
*
* @param id The instance ID of this pocket computer.
* @param family The family of this pocket computer.
* @see PocketComputerItem#getTooltipImage(ItemStack)
* @see dan200.computercraft.client.pocket.PocketClientTooltipComponent
*/
public record PocketTooltipComponent(UUID id, ComputerFamily family) implements TooltipComponent {
}

View File

@ -7,6 +7,7 @@ package dan200.computercraft.client;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.client.FabricComputerCraftAPIClient; import dan200.computercraft.api.client.FabricComputerCraftAPIClient;
import dan200.computercraft.client.model.CustomModelLoader; import dan200.computercraft.client.model.CustomModelLoader;
import dan200.computercraft.client.pocket.PocketClientTooltipComponent;
import dan200.computercraft.impl.Services; import dan200.computercraft.impl.Services;
import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.config.ConfigSpec; import dan200.computercraft.shared.config.ConfigSpec;
@ -15,6 +16,7 @@ import dan200.computercraft.shared.network.client.ClientNetworkContext;
import dan200.computercraft.shared.peripheral.modem.wired.CableBlock; import dan200.computercraft.shared.peripheral.modem.wired.CableBlock;
import dan200.computercraft.shared.platform.FabricConfigFile; import dan200.computercraft.shared.platform.FabricConfigFile;
import dan200.computercraft.shared.platform.FabricMessageType; import dan200.computercraft.shared.platform.FabricMessageType;
import dan200.computercraft.shared.pocket.items.PocketTooltipComponent;
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
@ -22,6 +24,7 @@ import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.model.loading.v1.PreparableModelLoadingPlugin; import net.fabricmc.fabric.api.client.model.loading.v1.PreparableModelLoadingPlugin;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.TooltipComponentCallback;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
import net.fabricmc.fabric.api.event.client.player.ClientPickBlockGatherCallback; import net.fabricmc.fabric.api.event.client.player.ClientPickBlockGatherCallback;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
@ -74,6 +77,11 @@ public class ComputerCraftClient {
} }
}); });
TooltipComponentCallback.EVENT.register(c -> {
if (c instanceof PocketTooltipComponent p) return new PocketClientTooltipComponent(p);
return null;
});
// Easier to hook in as an event than use BlockPickInteractionAware. // Easier to hook in as an event than use BlockPickInteractionAware.
ClientPickBlockGatherCallback.EVENT.register((player, hit) -> { ClientPickBlockGatherCallback.EVENT.register((player, hit) -> {
if (hit.getType() != HitResult.Type.BLOCK) return ItemStack.EMPTY; if (hit.getType() != HitResult.Type.BLOCK) return ItemStack.EMPTY;

View File

@ -7,13 +7,12 @@ package dan200.computercraft.client;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.client.turtle.RegisterTurtleModellersEvent; import dan200.computercraft.api.client.turtle.RegisterTurtleModellersEvent;
import dan200.computercraft.client.model.turtle.TurtleModelLoader; import dan200.computercraft.client.model.turtle.TurtleModelLoader;
import dan200.computercraft.client.pocket.PocketClientTooltipComponent;
import dan200.computercraft.shared.pocket.items.PocketTooltipComponent;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.item.ItemProperties; import net.minecraft.client.renderer.item.ItemProperties;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ModelEvent; import net.minecraftforge.client.event.*;
import net.minecraftforge.client.event.RegisterClientReloadListenersEvent;
import net.minecraftforge.client.event.RegisterColorHandlersEvent;
import net.minecraftforge.client.event.RegisterShadersEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModLoader; import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
@ -85,4 +84,9 @@ public final class ForgeClientRegistry {
ClientRegistry.register(); ClientRegistry.register();
event.enqueueWork(() -> ClientRegistry.registerMainThread(ItemProperties::register)); event.enqueueWork(() -> ClientRegistry.registerMainThread(ItemProperties::register));
} }
@SubscribeEvent
public static void onTooltipComponent(RegisterClientTooltipComponentFactoriesEvent event) {
event.register(PocketTooltipComponent.class, PocketClientTooltipComponent::new);
}
} }