1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-01-08 08:20:29 +00:00

Update to 1.21.3

This is a very preliminary port. I can get in game and use computers,
but I've not tested much beyond that (there's at least one failing game
test).

== Rendering ==

 - Remove TBO monitor renderer: There was a big overhaul to how shaders
   are defined and loaded in 1.21.2. It might have been possible to
   update the monitor shader code to this version, it doesn't see much
   use nowadays, so let's just delete it.

   This is a real shame — the TBO renderer was one of my favourite
   projects I've worked on. Unfortunately, it just doesn't seem worth
   the ongoing maintenance burden. It lives on in the standalone
   emulator :D.

 - Similarly, the VBO rendering code got a bit of an overhaul. We no
   longer use a custom VBO subclass, and instead just hack vanilla's to
   support changing the number of vertices rendered.

   This does mean we need to construct a MeshData, rather than a raw
   ByteBuffer. This isn't too hard, but not sure how it'll play with
   Iris. Given recent vanilla performance improvements, maybe we can
   remove our Unsafe code and use a normal BufferBuilder now.

 - Move some textures to vanilla's GUI sprite sheet (from our own). We
   also move the turtle "selected slot" texture to a sprite sheet -
   would be good to do the other ones (printer progress, maybe
   printouts) in the future.

 - Remove our custom emissive model code, now that vanilla supports
   it. We should add emissive textures to some other models at some
   point.

== Recipes ==

There were several major changes to ingredients this update. The code
here hasn't been very well tested right now — might be nice to add some
game tests for this.

 - Ingredients can no longer be constructed directly from a tag key (it
   needs to be fetched from the current registries), so the recipe
   generation code needs a bit of a reshuffle.

 - DiskRecipe now accepts a custom list of ingredients, rather than
   being hard-coded (fixes #1755). Recipes can now return custom
   `RecipeDisplay`s used to show a recipe in the crafting book. We use
   this to replace the impostor recipes.

   I'm not entirely sure how well this'll play with other recipe
   mods. Here's hoping.

 - Similarly, our recipe mod integration has been updated to use
   RecipeDisplay. We had to do this as ingredients no longer accept
   arbitrary ItemStacks (only a specific item), but the design is a
   little speculative - JEI/REI haven't updated yet.

== Misc ==

 - Blocks/items now need to know their ID ahead of time (so they can
   compute their description). This requires some reshuffling to the
   registration code, but it's pretty minor.

 - updateShape and neighborChanged have been tweaked slightly, I assume
   to work with the upcoming redstone changes. neighborChanged is
   currently commented out — we need to handle that properly.

 - All the positions were lowered by one in game tests. It's a good
   change (they now match the positions in structures), but annoying to
   update for!
This commit is contained in:
Jonathan Coates 2024-10-23 20:21:04 +01:00
parent 63181e73a1
commit ef36fc18ae
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
269 changed files with 1480 additions and 2635 deletions

View File

@ -4,10 +4,8 @@
/** Default configuration for Fabric projects. */
import cc.tweaked.gradle.CCTweakedExtension
import cc.tweaked.gradle.CCTweakedPlugin
import cc.tweaked.gradle.*
import cc.tweaked.gradle.IdeaRunConfigurations
import cc.tweaked.gradle.MinecraftConfigurations
plugins {
`java-library`
@ -67,3 +65,9 @@ dependencies {
tasks.ideaSyncTask {
doLast { IdeaRunConfigurations(project).patch() }
}
tasks.named("checkDependencyConsistency", DependencyCheck::class.java) {
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
// Fabric forces asm to a more recent version
override(libs.findLibrary("asm").get(), "9.7.1")
}

View File

@ -15,4 +15,4 @@ isUnstable=true
modVersion=1.113.1
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
mcVersion=1.21.1
mcVersion=1.21.3

View File

@ -7,14 +7,14 @@
# Minecraft
# MC version is specified in gradle.properties, as we need that in settings.gradle.
# Remember to update corresponding versions in fabric.mod.json/neoforge.mods.toml
fabric-api = "0.102.1+1.21.1"
fabric-loader = "0.15.11"
neoForge = "21.1.9"
fabric-api = "0.106.1+1.21.3"
fabric-loader = "0.16.7"
neoForge = "21.3.0-beta"
neoForgeSpi = "8.0.1"
mixin = "0.8.5"
parchment = "2024.07.28"
parchmentMc = "1.21"
yarn = "1.21.1+build.1"
yarn = "1.21.3+build.1"
# Core dependencies (these versions are tied to the version Minecraft uses)
fastutil = "8.5.12"
@ -62,14 +62,14 @@ checkstyle = "10.14.1"
curseForgeGradle = "1.1.18"
errorProne-core = "2.27.0"
errorProne-plugin = "3.1.0"
fabric-loom = "1.7.1"
fabric-loom = "1.8.10"
githubRelease = "2.5.2"
gradleVersions = "0.50.0"
ideaExt = "1.1.7"
illuaminate = "0.1.0-73-g43ee16c"
lwjgl = "3.3.3"
minotaur = "2.8.7"
neoGradle = "7.0.152"
neoGradle = "7.0.165"
nullAway = "0.10.25"
shadow = "8.3.1"
spotless = "6.23.3"
@ -186,9 +186,9 @@ kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
# Minecraft
externalMods-common = ["iris-forge", "jei-api", "nightConfig-core", "nightConfig-toml"]
externalMods-forge-compile = ["moreRed", "iris-forge", "jei-api"]
externalMods-forge-runtime = ["jei-forge"]
externalMods-forge-runtime = []
externalMods-fabric-compile = ["fabricPermissions", "iris-fabric", "jei-api", "rei-api", "rei-builtin"]
externalMods-fabric-runtime = ["jei-fabric", "modmenu"]
externalMods-fabric-runtime = []
# Testing
test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"]

Binary file not shown.

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@ -60,7 +60,7 @@ public record TransformedModel(BakedModel model, Transformation matrix) {
}
public static TransformedModel of(ItemStack item, Transformation transform) {
var model = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getItemModel(item);
var model = Minecraft.getInstance().getItemRenderer().getModel(item, null, null, 0);
return new TransformedModel(model, transform);
}
}

View File

@ -48,7 +48,7 @@ public interface TurtleUpgradeModeller<T extends ITurtleUpgrade> {
* by other means.
*
* @return A list of models that this modeller depends on.
* @see UnbakedModel#getDependencies()
* @see UnbakedModel#resolveDependencies(UnbakedModel.Resolver)
*/
default Stream<ResourceLocation> getDependencies() {
return Stream.of();

View File

@ -38,7 +38,7 @@ final class TurtleUpgradeModellers {
@Override
public TransformedModel getModel(ITurtleUpgrade upgrade, @Nullable ITurtleAccess turtle, TurtleSide side, DataComponentPatch data) {
var stack = upgrade.getUpgradeItem(data);
var model = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getItemModel(stack);
var model = Minecraft.getInstance().getItemRenderer().getModel(stack, null, null, 0);
if (stack.hasFoil()) model = ClientPlatformHelper.get().createdFoiledModel(model);
return new TransformedModel(model, side == TurtleSide.LEFT ? leftTransform : rightTransform);
}

View File

@ -15,6 +15,12 @@ sourceSets {
main {
resources.srcDir("src/generated/resources")
}
client {
java {
exclude("dan200/computercraft/client/integration/emi")
exclude("dan200/computercraft/client/integration/jei")
}
}
}
minecraft {

View File

@ -11,7 +11,6 @@ import dan200.computercraft.client.pocket.ClientPocketComputers;
import dan200.computercraft.client.render.CableHighlightRenderer;
import dan200.computercraft.client.render.PocketItemRenderer;
import dan200.computercraft.client.render.PrintoutItemRenderer;
import dan200.computercraft.client.render.monitor.MonitorBlockEntityRenderer;
import dan200.computercraft.client.render.monitor.MonitorHighlightRenderer;
import dan200.computercraft.client.render.monitor.MonitorRenderState;
import dan200.computercraft.client.sound.SpeakerManager;
@ -29,11 +28,11 @@ import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
import net.minecraft.client.sounds.AudioStream;
import net.minecraft.client.sounds.SoundEngine;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.decoration.ItemFrame;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
@ -88,7 +87,7 @@ public final class ClientHooks {
return false;
}
public static boolean onRenderItemFrame(PoseStack transform, MultiBufferSource render, ItemFrame frame, ItemStack stack, int light) {
public static boolean onRenderItemFrame(PoseStack transform, MultiBufferSource render, ItemFrameRenderState frame, ItemStack stack, int light) {
if (stack.getItem() instanceof PrintoutItem) {
PrintoutItemRenderer.onRenderInFrame(transform, render, frame, stack, light);
return true;
@ -132,17 +131,6 @@ public final class ClientHooks {
if (upgrade != null) out.accept(String.format("Upgrade[%s]: %s", side, upgrade.holder().key().location()));
}
/**
* Add additional information about the game to the debug screen.
*
* @param addText A callback which adds a single line of text.
*/
public static void addGameDebugInfo(Consumer<String> addText) {
if (MonitorBlockEntityRenderer.hasRenderedThisFrame() && Minecraft.getInstance().getDebugOverlay().showDebugScreen()) {
addText.accept("[CC:T] Monitor renderer: " + MonitorBlockEntityRenderer.currentRenderer());
}
}
public static @Nullable BlockState getBlockBreakingState(BlockState state, BlockPos pos) {
// Only apply to cables which have both a cable and modem
if (state.getBlock() != ModRegistry.Blocks.CABLE.get()

View File

@ -14,7 +14,6 @@ import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
import dan200.computercraft.client.gui.*;
import dan200.computercraft.client.pocket.ClientPocketComputers;
import dan200.computercraft.client.render.CustomLecternRenderer;
import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.client.render.TurtleBlockEntityRenderer;
import dan200.computercraft.client.render.monitor.MonitorBlockEntityRenderer;
import dan200.computercraft.client.turtle.TurtleModemModeller;
@ -34,7 +33,6 @@ import net.minecraft.client.gui.screens.MenuScreens;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.MenuAccess;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
import net.minecraft.client.renderer.item.ClampedItemPropertyFunction;
@ -42,8 +40,7 @@ import net.minecraft.client.renderer.item.ItemProperties;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.PreparableReloadListener;
import net.minecraft.server.packs.resources.ResourceProvider;
import net.minecraft.util.FastColor;
import net.minecraft.util.ARGB;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.MenuType;
@ -54,7 +51,6 @@ import net.minecraft.world.level.ItemLike;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@ -182,7 +178,7 @@ public final class ClientRegistry {
case 1 -> DyedItemColor.getOrDefault(stack, -1); // Frame colour
case 2 -> { // Light colour
var computer = ClientPocketComputers.get(stack);
yield computer == null || computer.getLightState() == -1 ? Colour.BLACK.getARGB() : FastColor.ARGB32.opaque(computer.getLightState());
yield computer == null || computer.getLightState() == -1 ? Colour.BLACK.getARGB() : ARGB.opaque(computer.getLightState());
}
};
}
@ -191,10 +187,6 @@ public final class ClientRegistry {
return layer == 0 ? DyedItemColor.getOrDefault(stack, -1) : -1;
}
public static void registerShaders(ResourceProvider resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException {
RenderTypes.registerShaders(resources, load);
}
private record UnclampedPropertyFunction(
ClampedItemPropertyFunction function
) implements ClampedItemPropertyFunction {

View File

@ -99,7 +99,7 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
if (uploadNagDeadline != Long.MAX_VALUE && Util.getNanos() >= uploadNagDeadline) {
new ItemToast(minecraft(), displayStack, NO_RESPONSE_TITLE, NO_RESPONSE_MSG, ItemToast.TRANSFER_NO_RESPONSE_TOKEN)
.showOrReplace(minecraft().getToasts());
.showOrReplace(minecraft().getToastManager());
uploadNagDeadline = Long.MAX_VALUE;
}
}

View File

@ -7,7 +7,6 @@ package dan200.computercraft.client.gui;
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
import dan200.computercraft.client.gui.widgets.TerminalWidget;
import dan200.computercraft.client.render.ComputerBorderRenderer;
import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.client.render.SpriteRenderer;
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
import net.minecraft.client.gui.GuiGraphics;
@ -40,14 +39,14 @@ public final class ComputerScreen<T extends AbstractComputerMenu> extends Abstra
public void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
// Draw a border around the terminal
var terminal = getTerminal();
var spriteRenderer = SpriteRenderer.createForGui(graphics, RenderTypes.GUI_SPRITES);
var computerTextures = GuiSprites.getComputerTextures(family);
ComputerBorderRenderer.render(
spriteRenderer, computerTextures,
terminal.getX(), terminal.getY(), terminal.getWidth(), terminal.getHeight(), false
);
ComputerSidebar.renderBackground(spriteRenderer, computerTextures, leftPos, topPos + sidebarYOffset);
graphics.flush(); // Flush to ensure background textures are drawn before foreground.
SpriteRenderer.inGui(graphics, spriteRenderer -> {
var computerTextures = GuiSprites.getComputerTextures(family);
ComputerBorderRenderer.render(
spriteRenderer, computerTextures,
terminal.getX(), terminal.getY(), terminal.getWidth(), terminal.getHeight(), false
);
ComputerSidebar.renderBackground(spriteRenderer, computerTextures, leftPos, topPos + sidebarYOffset);
});
}
}

View File

@ -7,6 +7,7 @@ package dan200.computercraft.client.gui;
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveMenu;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
@ -23,7 +24,7 @@ public class DiskDriveScreen extends AbstractContainerScreen<DiskDriveMenu> {
@Override
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
graphics.blit(BACKGROUND, leftPos, topPos, 0, 0, imageWidth, imageHeight);
graphics.blit(RenderType::guiTextured, BACKGROUND, leftPos, topPos, 0, 0, imageWidth, imageHeight, 256, 256);
}
@Override

View File

@ -35,8 +35,8 @@ public final class GuiSprites extends TextureAtlasHolder {
private static ButtonTextures button(String name) {
return new ButtonTextures(
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "gui/buttons/" + name),
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "gui/buttons/" + name + "_hover")
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "buttons/" + name),
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "buttons/" + name + "_hover")
);
}
@ -97,12 +97,8 @@ public final class GuiSprites extends TextureAtlasHolder {
* @param active The texture for the button when it is active (hovered or focused).
*/
public record ButtonTextures(ResourceLocation normal, ResourceLocation active) {
public TextureAtlasSprite get(boolean active) {
return GuiSprites.get(active ? this.active : normal);
}
public Stream<ResourceLocation> textures() {
return Stream.of(normal, active);
public ResourceLocation get(boolean active) {
return active ? this.active : normal;
}
}

View File

@ -5,9 +5,11 @@
package dan200.computercraft.client.gui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.toasts.Toast;
import net.minecraft.client.gui.components.toasts.ToastComponent;
import net.minecraft.client.gui.components.toasts.ToastManager;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.FormattedCharSequence;
@ -35,8 +37,9 @@ public class ItemToast implements Toast {
private final Object token;
private final int width;
private boolean isNew = true;
private long firstDisplay;
private boolean changed = true;
private long lastChanged;
private Visibility visibility = Visibility.HIDE;
public ItemToast(Minecraft minecraft, ItemStack stack, Component title, Component message, Object token) {
this.stack = stack;
@ -48,10 +51,10 @@ public class ItemToast implements Toast {
width = Math.max(MAX_LINE_SIZE, this.message.stream().mapToInt(font::width).max().orElse(MAX_LINE_SIZE)) + MARGIN * 3 + IMAGE_SIZE;
}
public void showOrReplace(ToastComponent toasts) {
public void showOrReplace(ToastManager toasts) {
var existing = toasts.getToast(ItemToast.class, getToken());
if (existing != null) {
existing.isNew = true;
existing.changed = true;
} else {
toasts.addToast(this);
}
@ -73,28 +76,22 @@ public class ItemToast implements Toast {
}
@Override
public Visibility render(GuiGraphics graphics, ToastComponent component, long time) {
if (isNew) {
public Visibility getWantedVisibility() {
return visibility;
}
firstDisplay = time;
isNew = false;
@Override
public void update(ToastManager toastManager, long time) {
if (changed) {
lastChanged = time;
changed = false;
}
visibility = time - lastChanged < DISPLAY_TIME * toastManager.getNotificationDisplayTimeMultiplier() ? Visibility.SHOW : Visibility.HIDE;
}
if (width == 160 && message.size() <= 1) {
graphics.blitSprite(TEXTURE, 0, 0, width, height());
} else {
var height = height();
var bottom = Math.min(4, height - 28);
renderBackgroundRow(graphics, width, 0, 0, 28);
for (var i = 28; i < height - bottom; i += 10) {
renderBackgroundRow(graphics, width, 16, i, Math.min(16, height - i - bottom));
}
renderBackgroundRow(graphics, width, 32 - bottom, height - bottom, bottom);
}
@Override
public void render(GuiGraphics graphics, Font font, long time) {
graphics.blitSprite(RenderType::guiTextured, TEXTURE, 0, 0, width(), height());
var textX = MARGIN;
if (!stack.isEmpty()) {
@ -102,23 +99,9 @@ public class ItemToast implements Toast {
graphics.renderFakeItem(stack, MARGIN, MARGIN + height() / 2 - IMAGE_SIZE);
}
graphics.drawString(component.getMinecraft().font, title, textX, MARGIN, 0xff500050, false);
graphics.drawString(font, title, textX, MARGIN, 0xff500050, false);
for (var i = 0; i < message.size(); ++i) {
graphics.drawString(component.getMinecraft().font, message.get(i), textX, LINE_SPACING + (i + 1) * LINE_SPACING, 0xff000000, false);
graphics.drawString(font, message.get(i), textX, LINE_SPACING + (i + 1) * LINE_SPACING, 0xff000000, false);
}
return time - firstDisplay < DISPLAY_TIME ? Visibility.SHOW : Visibility.HIDE;
}
private static void renderBackgroundRow(GuiGraphics graphics, int x, int u, int y, int height) {
var leftOffset = u == 0 ? 20 : 5;
var rightOffset = Math.min(60, x - leftOffset);
graphics.blitSprite(TEXTURE, 160, 32, 0, u, 0, y, leftOffset, height);
for (var k = leftOffset; k < x - rightOffset; k += 64) {
graphics.blitSprite(TEXTURE, 160, 32, 32, u, k, y, Math.min(64, x - k - rightOffset), height);
}
graphics.blitSprite(TEXTURE, 160, 32, 160 - rightOffset, u, x - rightOffset, y, rightOffset, height);
}
}

View File

@ -67,7 +67,7 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
@Override
public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
Objects.requireNonNull(minecraft().player).getInventory().swapPaint(scrollY);
// FIXME(1.21.2): Objects.requireNonNull(minecraft().player).getInventory().setSelectedHotbarSlot(scrollY);
return super.mouseScrolled(mouseX, mouseY, scrollX, scrollY);
}

View File

@ -10,6 +10,7 @@ import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.MultiLineLabel;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
@ -87,12 +88,13 @@ public final class OptionScreen extends Screen {
@Override
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
// Render the actual texture.
graphics.blit(BACKGROUND, x, y, 0, 0, innerWidth, PADDING);
graphics.blit(BACKGROUND,
graphics.blit(RenderType::guiTextured, BACKGROUND, x, y, 0, 0, innerWidth, PADDING, 256, 256);
graphics.blit(RenderType::guiTextured, BACKGROUND,
x, y + PADDING, 0, PADDING, innerWidth, innerHeight - PADDING * 2,
innerWidth, PADDING
innerWidth, PADDING,
256, 256
);
graphics.blit(BACKGROUND, x, y + innerHeight - PADDING, 0, 256 - PADDING, innerWidth, PADDING);
graphics.blit(RenderType::guiTextured, BACKGROUND, x, y + innerHeight - PADDING, 0, 256 - PADDING, innerWidth, PADDING, 256, 256);
assertNonNull(messageRenderer).renderLeftAlignedNoShadow(graphics, x + PADDING, y + PADDING, FONT_HEIGHT, 0x404040);
super.render(graphics, mouseX, mouseY, partialTicks);

View File

@ -7,6 +7,7 @@ package dan200.computercraft.client.gui;
import dan200.computercraft.shared.peripheral.printer.PrinterMenu;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
@ -23,9 +24,11 @@ public class PrinterScreen extends AbstractContainerScreen<PrinterMenu> {
@Override
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
graphics.blit(BACKGROUND, leftPos, topPos, 0, 0, imageWidth, imageHeight);
graphics.blit(RenderType::guiTextured, BACKGROUND, leftPos, topPos, 0, 0, imageWidth, imageHeight, 256, 256);
if (getMenu().isPrinting()) graphics.blit(BACKGROUND, leftPos + 34, topPos + 21, 176, 0, 25, 45);
if (getMenu().isPrinting()) {
graphics.blit(RenderType::guiTextured, BACKGROUND, leftPos + 34, topPos + 21, 176, 0, 25, 45, 256, 256);
}
}
@Override

View File

@ -10,6 +10,7 @@ import dan200.computercraft.shared.media.PrintoutMenu;
import dan200.computercraft.shared.media.items.PrintoutData;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.AbstractContainerMenu;
@ -20,7 +21,6 @@ import org.lwjgl.glfw.GLFW;
import java.util.Objects;
import static dan200.computercraft.client.render.PrintoutRenderer.*;
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
/**
* The GUI for printed pages and books.
@ -116,8 +116,10 @@ public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu>
graphics.pose().pushPose();
graphics.pose().translate(0, 0, 1);
drawBorder(graphics.pose(), graphics.bufferSource(), leftPos, topPos, 0, page, printout.pages(), printout.book(), FULL_BRIGHT_LIGHTMAP);
drawText(graphics.pose(), graphics.bufferSource(), leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, PrintoutData.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, printout.text(), printout.colour());
graphics.drawSpecial(bufferSource -> {
drawBorder(graphics.pose(), bufferSource, leftPos, topPos, 0, page, printout.pages(), printout.book(), LightTexture.FULL_BRIGHT);
drawText(graphics.pose(), bufferSource, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, PrintoutData.LINES_PER_PAGE * page, LightTexture.FULL_BRIGHT, printout.text(), printout.colour());
});
graphics.pose().popPose();
}

View File

@ -7,12 +7,12 @@ package dan200.computercraft.client.gui;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
import dan200.computercraft.client.gui.widgets.TerminalWidget;
import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.client.render.SpriteRenderer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
import dan200.computercraft.shared.turtle.inventory.TurtleMenu;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
@ -26,6 +26,9 @@ public class TurtleScreen extends AbstractComputerScreen<TurtleMenu> {
private static final ResourceLocation BACKGROUND_NORMAL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "textures/gui/turtle_normal.png");
private static final ResourceLocation BACKGROUND_ADVANCED = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "textures/gui/turtle_advanced.png");
private static final ResourceLocation SELECTED_NORMAL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "turtle_normal_selected_slot");
private static final ResourceLocation SELECTED_ADVANCED = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "turtle_advanced_selected_slot");
private static final int TEX_WIDTH = 278;
private static final int TEX_HEIGHT = 217;
@ -46,23 +49,28 @@ public class TurtleScreen extends AbstractComputerScreen<TurtleMenu> {
@Override
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
var advanced = family == ComputerFamily.ADVANCED;
var texture = advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL;
graphics.blit(texture, leftPos + AbstractComputerMenu.SIDEBAR_WIDTH, topPos, 0, 0, 0, TEX_WIDTH, TEX_HEIGHT, FULL_TEX_SIZE, FULL_TEX_SIZE);
graphics.blit(
RenderType::guiTextured, advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL,
leftPos + AbstractComputerMenu.SIDEBAR_WIDTH, topPos, 0, 0,
TEX_WIDTH, TEX_HEIGHT, FULL_TEX_SIZE, FULL_TEX_SIZE
);
// Render selected slot
var slot = getMenu().getSelectedSlot();
if (slot >= 0) {
var slotX = slot % 4;
var slotY = slot / 4;
graphics.blit(texture,
leftPos + TURTLE_START_X - 2 + slotX * 18, topPos + PLAYER_START_Y - 2 + slotY * 18, 0,
0, 217, 24, 24, FULL_TEX_SIZE, FULL_TEX_SIZE
graphics.blitSprite(
RenderType::guiTextured, advanced ? SELECTED_ADVANCED : SELECTED_NORMAL,
leftPos + TURTLE_START_X - 2 + slotX * 18, topPos + PLAYER_START_Y - 2 + slotY * 18,
22, 22
);
}
// Render sidebar
var spriteRenderer = SpriteRenderer.createForGui(graphics, RenderTypes.GUI_SPRITES);
ComputerSidebar.renderBackground(spriteRenderer, GuiSprites.getComputerTextures(family), leftPos, topPos + sidebarYOffset);
graphics.flush(); // Flush to ensure background textures are drawn before foreground.
SpriteRenderer.inGui(graphics, spriteRenderer ->
ComputerSidebar.renderBackground(spriteRenderer, GuiSprites.getComputerTextures(family), leftPos, topPos + sidebarYOffset)
);
}
}

View File

@ -4,14 +4,14 @@
package dan200.computercraft.client.gui.widgets;
import com.mojang.blaze3d.systems.RenderSystem;
import it.unimi.dsi.fastutil.booleans.Boolean2ObjectFunction;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.Tooltip;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import javax.annotation.Nullable;
import java.util.function.Supplier;
@ -21,11 +21,11 @@ import java.util.function.Supplier;
* dynamically.
*/
public class DynamicImageButton extends Button {
private final Boolean2ObjectFunction<TextureAtlasSprite> texture;
private final Boolean2ObjectFunction<ResourceLocation> texture;
private final Supplier<HintedMessage> message;
public DynamicImageButton(
int x, int y, int width, int height, Boolean2ObjectFunction<TextureAtlasSprite> texture, OnPress onPress,
int x, int y, int width, int height, Boolean2ObjectFunction<ResourceLocation> texture, OnPress onPress,
HintedMessage message
) {
this(x, y, width, height, texture, onPress, () -> message);
@ -33,7 +33,7 @@ public class DynamicImageButton extends Button {
public DynamicImageButton(
int x, int y, int width, int height,
Boolean2ObjectFunction<TextureAtlasSprite> texture,
Boolean2ObjectFunction<ResourceLocation> texture,
OnPress onPress, Supplier<HintedMessage> message
) {
super(x, y, width, height, Component.empty(), onPress, DEFAULT_NARRATION);
@ -48,10 +48,7 @@ public class DynamicImageButton extends Button {
setTooltip(message.tooltip());
var texture = this.texture.get(isHoveredOrFocused());
RenderSystem.disableDepthTest();
graphics.blit(getX(), getY(), 0, width, height, texture);
RenderSystem.enableDepthTest();
graphics.blitSprite(RenderType::guiTextured, texture, getX(), getY(), width, height);
}
public record HintedMessage(Component message, Tooltip tooltip) {

View File

@ -4,7 +4,6 @@
package dan200.computercraft.client.gui.widgets;
import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.util.StringUtil;
@ -257,12 +256,12 @@ public class TerminalWidget extends AbstractWidget {
public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
if (!visible) return;
var emitter = FixedWidthFontRenderer.toVertexConsumer(graphics.pose(), graphics.bufferSource().getBuffer(RenderTypes.TERMINAL));
FixedWidthFontRenderer.drawTerminal(
emitter,
(float) innerX, (float) innerY, terminal, (float) MARGIN, (float) MARGIN, (float) MARGIN, (float) MARGIN
);
graphics.drawSpecial(bufferSource -> {
FixedWidthFontRenderer.drawTerminal(
FixedWidthFontRenderer.toVertexConsumer(graphics.pose(), bufferSource.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT)),
(float) innerX, (float) innerY, terminal, (float) MARGIN, (float) MARGIN, (float) MARGIN, (float) MARGIN
);
});
}
@Override

View File

@ -5,17 +5,18 @@
package dan200.computercraft.client.integration;
import com.google.auto.service.AutoService;
import com.mojang.blaze3d.vertex.ByteBufferBuilder;
import com.mojang.blaze3d.vertex.VertexFormat;
import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer;
import dan200.computercraft.shared.platform.PlatformHelper;
import net.irisshaders.iris.api.v0.IrisApi;
import net.irisshaders.iris.api.v0.IrisTextVertexSink;
import net.minecraft.util.FastColor;
import net.minecraft.client.renderer.LightTexture;
import org.lwjgl.system.MemoryUtil;
import javax.annotation.Nullable;
import java.nio.ByteBuffer;
import java.util.Optional;
import java.util.function.IntFunction;
@AutoService(ShaderMod.Provider.class)
public class IrisShaderMod implements ShaderMod.Provider {
@ -31,7 +32,7 @@ public class IrisShaderMod implements ShaderMod.Provider {
}
@Override
public DirectFixedWidthFontRenderer.QuadEmitter getQuadEmitter(int vertexCount, IntFunction<ByteBuffer> makeBuffer) {
public DirectFixedWidthFontRenderer.QuadEmitter getQuadEmitter(int vertexCount, ByteBufferBuilder makeBuffer) {
return IrisApi.getInstance().getMinorApiRevision() >= 1
? new IrisQuadEmitter(vertexCount, makeBuffer)
: super.getQuadEmitter(vertexCount, makeBuffer);
@ -39,25 +40,24 @@ public class IrisShaderMod implements ShaderMod.Provider {
private static final class IrisQuadEmitter implements DirectFixedWidthFontRenderer.QuadEmitter {
private final IrisTextVertexSink sink;
private @Nullable ByteBuffer buffer;
private IrisQuadEmitter(int vertexCount, IntFunction<ByteBuffer> makeBuffer) {
sink = IrisApi.getInstance().createTextVertexSink(vertexCount, makeBuffer);
private IrisQuadEmitter(int vertexCount, ByteBufferBuilder builder) {
sink = IrisApi.getInstance().createTextVertexSink(vertexCount, i -> {
if (buffer != null) throw new IllegalStateException("Allocated multiple buffers");
return buffer = MemoryUtil.memByteBuffer(builder.reserve(i), i);
});
}
@Override
public void quad(float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2) {
sink.quad(x1, y1, x2, y2, z, colour, u1, v1, u2, v2, LightTexture.FULL_BRIGHT);
}
@Override
public VertexFormat format() {
return sink.getUnderlyingVertexFormat();
}
@Override
public ByteBuffer buffer() {
return sink.getUnderlyingByteBuffer();
}
@Override
public void quad(float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2) {
sink.quad(x1, y1, x2, y2, z, FastColor.ABGR32.fromArgb32(colour), u1, v1, u2, v2, RenderTypes.FULL_BRIGHT_LIGHTMAP);
}
}
}
}

View File

@ -4,14 +4,12 @@
package dan200.computercraft.client.integration;
import dan200.computercraft.client.render.RenderTypes;
import com.mojang.blaze3d.vertex.ByteBufferBuilder;
import com.mojang.blaze3d.vertex.VertexBuffer;
import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer;
import dan200.computercraft.client.render.vbo.DirectVertexBuffer;
import java.nio.ByteBuffer;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.function.IntFunction;
/**
* Find the currently loaded shader mod (if present) and provides utilities for interacting with it.
@ -31,16 +29,14 @@ public class ShaderMod {
}
/**
* Get an appropriate quad emitter for use with {@link DirectVertexBuffer} and {@link DirectFixedWidthFontRenderer} .
* Get an appropriate quad emitter for use with {@link VertexBuffer} and {@link DirectFixedWidthFontRenderer} .
*
* @param vertexCount The number of vertices.
* @param makeBuffer A function to allocate a temporary buffer.
* @param buffer A function to allocate a temporary buffer.
* @return The quad emitter.
*/
public DirectFixedWidthFontRenderer.QuadEmitter getQuadEmitter(int vertexCount, IntFunction<ByteBuffer> makeBuffer) {
return new DirectFixedWidthFontRenderer.ByteBufferEmitter(
makeBuffer.apply(RenderTypes.TERMINAL.format().getVertexSize() * vertexCount * 4)
);
public DirectFixedWidthFontRenderer.QuadEmitter getQuadEmitter(int vertexCount, ByteBufferBuilder buffer) {
return new DirectFixedWidthFontRenderer.ByteBufferEmitter(buffer);
}
public interface Provider {

View File

@ -80,7 +80,7 @@ public class ModelTransformer {
}
var direction = Direction.rotate(transformation, quad.getDirection());
return new BakedQuad(outputData, quad.getTintIndex(), direction, quad.getSprite(), quad.isShade());
return new BakedQuad(outputData, quad.getTintIndex(), direction, quad.getSprite(), quad.isShade(), 0);
}
public static int getVertexOffset(int vertex, boolean invert) {

View File

@ -107,8 +107,7 @@ public final class TurtleModelParts<T> {
}
private List<BakedModel> buildModel(Combination combo) {
var mc = Minecraft.getInstance();
var modelManager = mc.getItemRenderer().getItemModelShaper().getModelManager();
var modelManager = Minecraft.getInstance().getModelManager();
var transformation = combo.flip ? flip : identity;
var parts = new ArrayList<BakedModel>(4);

View File

@ -22,11 +22,13 @@ import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.JukeboxSong;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.LevelEvent;
import javax.annotation.Nullable;
import java.util.UUID;
@ -62,10 +64,14 @@ public final class ClientNetworkContextImpl implements ClientNetworkContext {
@Override
public void handlePlayRecord(BlockPos pos, @Nullable Holder<JukeboxSong> song) {
var level = Minecraft.getInstance().level;
if (level == null) return;
if (song == null) {
Minecraft.getInstance().levelRenderer.stopJukeboxSongAndNotifyNearby(pos);
level.levelEvent(LevelEvent.SOUND_STOP_JUKEBOX_SONG, pos, 0);
} else {
Minecraft.getInstance().levelRenderer.playJukeboxSong(song, pos);
var id = level.registryAccess().lookupOrThrow(Registries.JUKEBOX_SONG).getIdOrThrow(song.value());
level.levelEvent(LevelEvent.SOUND_PLAY_JUKEBOX_SONG, pos, id);
}
}

View File

@ -70,7 +70,7 @@ public final class ModelRenderer {
var matrix = pose.pose();
// It's a little dubious to transform using this matrix rather than the normal matrix. This mirrors the logic in
// Direction.rotate (so not out of nowhere!), but is a little suspicious.
var dirNormal = quad.getDirection().getNormal();
var dirNormal = quad.getDirection().getUnitVec3i();
var vector = new Vector4f();
matrix.transform(dirNormal.getX(), dirNormal.getY(), dirNormal.getZ(), 0.0f, vector).normalize();

View File

@ -13,8 +13,10 @@ import dan200.computercraft.core.util.Colour;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.config.Config;
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.util.FastColor;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.util.ARGB;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.DyedItemColor;
import org.joml.Matrix4f;
@ -72,7 +74,7 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
var lightColour = computer == null || computer.getLightState() == -1 ? Colour.BLACK.getHex() : computer.getLightState();
renderLight(transform, bufferSource, lightColour, width, height);
var quadEmitter = FixedWidthFontRenderer.toVertexConsumer(transform, bufferSource.getBuffer(RenderTypes.TERMINAL));
var quadEmitter = FixedWidthFontRenderer.toVertexConsumer(transform, bufferSource.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT));
if (terminal == null) {
FixedWidthFontRenderer.drawEmptyTerminal(quadEmitter, 0, 0, width, height);
} else {
@ -89,16 +91,16 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
var g = (colour >>> 8) & 0xFF;
var b = colour & 0xFF;
var spriteRenderer = new SpriteRenderer(transform, render.getBuffer(RenderTypes.GUI_SPRITES), 0, light, r, g, b);
var spriteRenderer = new SpriteRenderer(transform, render.getBuffer(RenderType.text(GuiSprites.TEXTURE)), 0, light, r, g, b);
ComputerBorderRenderer.render(spriteRenderer, texture, 0, 0, width, height, true);
}
private static void renderLight(PoseStack transform, MultiBufferSource render, int colour, int width, int height) {
var buffer = render.getBuffer(RenderTypes.TERMINAL);
var buffer = render.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT);
FixedWidthFontRenderer.drawQuad(
FixedWidthFontRenderer.toVertexConsumer(transform, buffer),
width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0.001f, LIGHT_HEIGHT * 2, LIGHT_HEIGHT,
FastColor.ARGB32.opaque(colour), RenderTypes.FULL_BRIGHT_LIGHTMAP
ARGB.opaque(colour), LightTexture.FULL_BRIGHT
);
}
}

View File

@ -10,8 +10,7 @@ import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.media.items.PrintoutData;
import dan200.computercraft.shared.media.items.PrintoutItem;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.decoration.ItemFrame;
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
import net.minecraft.world.item.ItemStack;
import static dan200.computercraft.client.render.PrintoutRenderer.*;
@ -38,14 +37,14 @@ public final class PrintoutItemRenderer extends ItemMapLikeRenderer {
drawPrintout(transform, render, stack, light);
}
public static void onRenderInFrame(PoseStack transform, MultiBufferSource render, ItemFrame frame, ItemStack stack, int packedLight) {
public static void onRenderInFrame(PoseStack transform, MultiBufferSource render, ItemFrameRenderState frame, ItemStack stack, int packedLight) {
// Move a little bit forward to ensure we're not clipping with the frame
transform.translate(0.0f, 0.0f, -0.001f);
transform.mulPose(Axis.ZP.rotationDegrees(180f));
transform.scale(0.95f, 0.95f, -0.95f);
transform.translate(-0.5f, -0.5f, 0.0f);
var light = frame.getType() == EntityType.GLOW_ITEM_FRAME ? 0xf000d2 : packedLight; // See getLightVal.
var light = frame.isGlowFrame ? 0xf000d2 : packedLight; // See getLightVal.
drawPrintout(transform, render, stack, light);
}

View File

@ -11,6 +11,8 @@ import dan200.computercraft.core.terminal.Palette;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.media.items.PrintoutData;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.resources.ResourceLocation;
import org.joml.Matrix4f;
import java.util.List;
@ -23,6 +25,12 @@ import static dan200.computercraft.shared.media.items.PrintoutData.LINES_PER_PAG
* {@linkplain PrintoutItemRenderer in-hand/item frame printouts}.
*/
public final class PrintoutRenderer {
/**
* Printout's background texture. {@link RenderType#text(ResourceLocation)} is a <em>little</em> questionable, but
* it is what maps use, so should behave the same as vanilla in both item frames and in-hand.
*/
private static final RenderType BACKGROUND = RenderType.text(ResourceLocation.fromNamespaceAndPath("computercraft", "textures/gui/printout.png"));
private static final float BG_SIZE = 256.0f;
/**
@ -62,7 +70,7 @@ public final class PrintoutRenderer {
}
public static void drawText(PoseStack transform, MultiBufferSource bufferSource, int x, int y, int start, int light, TextBuffer[] text, TextBuffer[] colours) {
var buffer = bufferSource.getBuffer(RenderTypes.PRINTOUT_TEXT);
var buffer = bufferSource.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT);
var emitter = FixedWidthFontRenderer.toVertexConsumer(transform, buffer);
for (var line = 0; line < LINES_PER_PAGE && line < text.length; line++) {
FixedWidthFontRenderer.drawString(emitter,
@ -73,7 +81,7 @@ public final class PrintoutRenderer {
}
public static void drawText(PoseStack transform, MultiBufferSource bufferSource, int x, int y, int start, int light, List<PrintoutData.Line> lines) {
var buffer = bufferSource.getBuffer(RenderTypes.PRINTOUT_TEXT);
var buffer = bufferSource.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT);
var emitter = FixedWidthFontRenderer.toVertexConsumer(transform, buffer);
for (var line = 0; line < LINES_PER_PAGE && line < lines.size(); line++) {
var lineContents = lines.get(start + line);
@ -90,7 +98,7 @@ public final class PrintoutRenderer {
var leftPages = page;
var rightPages = pages - page - 1;
var buffer = bufferSource.getBuffer(RenderTypes.PRINTOUT_BACKGROUND);
var buffer = bufferSource.getBuffer(BACKGROUND);
if (isBook) {
// Border

View File

@ -1,102 +0,0 @@
// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.client.gui.GuiSprites;
import dan200.computercraft.client.render.monitor.MonitorTextureBufferShader;
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.RenderStateShard;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceProvider;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
* Shared {@link RenderType}s used throughout the mod.
*/
public class RenderTypes {
public static final int FULL_BRIGHT_LIGHTMAP = (0xF << 4) | (0xF << 20);
private static @Nullable MonitorTextureBufferShader monitorTboShader;
/**
* Renders a fullbright terminal.
*/
public static final RenderType TERMINAL = RenderType.text(FixedWidthFontRenderer.FONT);
/**
* Renders a monitor with the TBO shader.
*
* @see MonitorTextureBufferShader
*/
public static final RenderType MONITOR_TBO = Types.MONITOR_TBO;
/**
* A variant of {@link #TERMINAL} which uses the lightmap rather than rendering fullbright.
*/
public static final RenderType PRINTOUT_TEXT = RenderType.text(FixedWidthFontRenderer.FONT);
/**
* Printout's background texture. {@link RenderType#text(ResourceLocation)} is a <em>little</em> questionable, but
* it is what maps use, so should behave the same as vanilla in both item frames and in-hand.
*/
public static final RenderType PRINTOUT_BACKGROUND = RenderType.text(ResourceLocation.fromNamespaceAndPath("computercraft", "textures/gui/printout.png"));
/**
* Render type for {@linkplain GuiSprites GUI sprites}.
*/
public static final RenderType GUI_SPRITES = RenderType.text(GuiSprites.TEXTURE);
public static MonitorTextureBufferShader getMonitorTextureBufferShader() {
if (monitorTboShader == null) throw new NullPointerException("MonitorTboShader has not been registered");
return monitorTboShader;
}
public static ShaderInstance getTerminalShader() {
return Objects.requireNonNull(GameRenderer.getRendertypeTextShader(), "Text shader has not been registered");
}
public static void registerShaders(ResourceProvider resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException {
load.accept(
new MonitorTextureBufferShader(
resources,
ComputerCraftAPI.MOD_ID + "/monitor_tbo",
MONITOR_TBO.format()
),
x -> monitorTboShader = (MonitorTextureBufferShader) x
);
}
private static final class Types extends RenderType {
private static final RenderStateShard.TextureStateShard TERM_FONT_TEXTURE = new TextureStateShard(
FixedWidthFontRenderer.FONT,
false, false // blur, minimap
);
static final RenderType MONITOR_TBO = RenderType.create(
"monitor_tbo", DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.TRIANGLE_STRIP, 128,
false, false, // useDelegate, needsSorting
RenderType.CompositeState.builder()
.setTextureState(TERM_FONT_TEXTURE)
.setShaderState(new ShaderStateShard(RenderTypes::getMonitorTextureBufferShader))
.createCompositeState(false)
);
@SuppressWarnings("UnusedMethod")
private Types(String name, VertexFormat format, VertexFormat.Mode mode, int buffer, boolean crumbling, boolean sort, Runnable setup, Runnable teardown) {
super(name, format, mode, buffer, crumbling, sort, setup, teardown);
}
}
}

View File

@ -5,11 +5,15 @@
package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.VertexConsumer;
import dan200.computercraft.client.gui.GuiSprites;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import org.joml.Matrix4f;
import java.util.function.Consumer;
/**
* A {@link GuiGraphics}-equivalent which is suitable for both rendering in to a GUI and in-world (as part of an entity
* renderer).
@ -34,11 +38,11 @@ public class SpriteRenderer {
this.b = b;
}
public static SpriteRenderer createForGui(GuiGraphics graphics, RenderType renderType) {
return new SpriteRenderer(
graphics.pose().last().pose(), graphics.bufferSource().getBuffer(renderType),
0, RenderTypes.FULL_BRIGHT_LIGHTMAP, 255, 255, 255
);
public static void inGui(GuiGraphics graphics, Consumer<SpriteRenderer> renderer) {
graphics.drawSpecial(bufferSource -> renderer.accept(new SpriteRenderer(
graphics.pose().last().pose(), bufferSource.getBuffer(RenderType.guiTextured(GuiSprites.TEXTURE)),
0, LightTexture.FULL_BRIGHT, 255, 255, 255
)));
}
/**

View File

@ -22,8 +22,9 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.ARGB;
import net.minecraft.util.CommonColors;
import net.minecraft.util.FastColor;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
@ -84,13 +85,13 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
if (colour == -1) {
// Render the turtle using its item model.
var modelManager = Minecraft.getInstance().getItemRenderer().getItemModelShaper();
var model = modelManager.getItemModel(turtle.getBlockState().getBlock().asItem());
if (model == null) model = modelManager.getModelManager().getMissingModel();
var model = Minecraft.getInstance().getItemRenderer().getModel(
new ItemStack(turtle.getBlockState().getBlock().asItem()), null, null, 0
);
renderModel(transform, buffers, lightmapCoord, overlayLight, model, null);
} else {
// Otherwise render it using the colour item.
renderModel(transform, buffers, lightmapCoord, overlayLight, COLOUR_TURTLE_MODEL, new int[]{ FastColor.ARGB32.opaque(colour) });
renderModel(transform, buffers, lightmapCoord, overlayLight, COLOUR_TURTLE_MODEL, new int[]{ ARGB.opaque(colour) });
}
// Render the overlay
@ -125,7 +126,7 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
}
private void renderModel(PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight, ResourceLocation modelLocation, @Nullable int[] tints) {
var modelManager = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getModelManager();
var modelManager = Minecraft.getInstance().getModelManager();
renderModel(transform, buffers, lightmapCoord, overlayLight, ClientPlatformHelper.get().getModel(modelManager, modelLocation), tints);
}

View File

@ -4,40 +4,28 @@
package dan200.computercraft.client.render.monitor;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexBuffer;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.blaze3d.vertex.*;
import com.mojang.math.Axis;
import dan200.computercraft.annotations.ForgeOverride;
import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.integration.ShaderMod;
import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer;
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import dan200.computercraft.client.render.vbo.DirectBuffers;
import dan200.computercraft.client.render.vbo.DirectVertexBuffer;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.util.Nullability;
import dan200.computercraft.shared.config.Config;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.client.renderer.CompiledShaderProgram;
import net.minecraft.client.renderer.FogParameters;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.world.phys.AABB;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL31;
import org.lwjgl.system.MemoryUtil;
import javax.annotation.Nullable;
import java.nio.ByteBuffer;
import java.util.function.Consumer;
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
@ -51,9 +39,7 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
*/
private static final float MARGIN = (float) (MonitorBlockEntity.RENDER_MARGIN * 1.1);
private static @Nullable ByteBuffer backingBuffer;
private static long lastFrame = -1;
private static final ByteBufferBuilder backingBufferBuilder = new ByteBufferBuilder(0x4000);
public MonitorBlockEntityRenderer(BlockEntityRendererProvider.Context context) {
}
@ -76,7 +62,6 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
return;
}
lastFrame = renderFrame;
renderState.lastRenderFrame = renderFrame;
renderState.lastRenderPos = monitorPos;
@ -124,7 +109,7 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
transform.popPose();
} else {
FixedWidthFontRenderer.drawEmptyTerminal(
FixedWidthFontRenderer.toVertexConsumer(transform, bufferSource.getBuffer(RenderTypes.TERMINAL)),
FixedWidthFontRenderer.toVertexConsumer(transform, bufferSource.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT)),
-MARGIN, MARGIN,
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
);
@ -136,126 +121,100 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
private static void renderTerminal(
Matrix4f matrix, ClientMonitor monitor, MonitorRenderState renderState, Terminal terminal, float xMargin, float yMargin
) {
int width = terminal.getWidth(), height = terminal.getHeight();
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
var renderType = currentRenderer();
var redraw = monitor.pollTerminalChanged();
if (renderState.createBuffer(renderType)) redraw = true;
if (renderState.createBuffer()) redraw = true;
switch (renderType) {
case TBO -> {
if (redraw) {
var terminalBuffer = getBuffer(width * height * 3);
MonitorTextureBufferShader.setTerminalData(terminalBuffer, terminal);
DirectBuffers.setBufferData(GL31.GL_TEXTURE_BUFFER, renderState.tboBuffer, terminalBuffer, GL20.GL_STATIC_DRAW);
var backgroundBuffer = assertNonNull(renderState.backgroundBuffer);
var foregroundBuffer = assertNonNull(renderState.foregroundBuffer);
if (redraw) {
var size = DirectFixedWidthFontRenderer.getVertexCount(terminal);
var uniformBuffer = getBuffer(MonitorTextureBufferShader.UNIFORM_SIZE);
MonitorTextureBufferShader.setUniformData(uniformBuffer, terminal);
DirectBuffers.setBufferData(GL31.GL_UNIFORM_BUFFER, renderState.tboUniform, uniformBuffer, GL20.GL_STATIC_DRAW);
}
// In an ideal world we could upload these both into one buffer. However, we can't render VBOs with
// and starting and ending offset, and so need to use two buffers instead.
// Nobody knows what they're doing!
var active = GlStateManager._getActiveTexture();
RenderSystem.activeTexture(MonitorTextureBufferShader.TEXTURE_INDEX);
GL11.glBindTexture(GL31.GL_TEXTURE_BUFFER, renderState.tboTexture);
RenderSystem.activeTexture(active);
renderToBuffer(backgroundBuffer, size, sink ->
DirectFixedWidthFontRenderer.drawTerminalBackground(sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin));
var shader = RenderTypes.getMonitorTextureBufferShader();
shader.setupUniform(renderState.tboUniform);
var buffer = Tesselator.getInstance().begin(RenderTypes.MONITOR_TBO.mode(), RenderTypes.MONITOR_TBO.format());
tboVertex(buffer, matrix, -xMargin, -yMargin);
tboVertex(buffer, matrix, -xMargin, pixelHeight + yMargin);
tboVertex(buffer, matrix, pixelWidth + xMargin, -yMargin);
tboVertex(buffer, matrix, pixelWidth + xMargin, pixelHeight + yMargin);
RenderTypes.MONITOR_TBO.draw(Nullability.assertNonNull(buffer.build()));
}
case VBO -> {
var backgroundBuffer = assertNonNull(renderState.backgroundBuffer);
var foregroundBuffer = assertNonNull(renderState.foregroundBuffer);
if (redraw) {
var size = DirectFixedWidthFontRenderer.getVertexCount(terminal);
// In an ideal world we could upload these both into one buffer. However, we can't render VBOs with
// and starting and ending offset, and so need to use two buffers instead.
renderToBuffer(backgroundBuffer, size, sink ->
DirectFixedWidthFontRenderer.drawTerminalBackground(sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin));
renderToBuffer(foregroundBuffer, size, sink -> {
DirectFixedWidthFontRenderer.drawTerminalForeground(sink, 0, 0, terminal);
// If the cursor is visible, we append it to the end of our buffer. When rendering, we can either
// render n or n+1 quads and so toggle the cursor on and off.
DirectFixedWidthFontRenderer.drawCursor(sink, 0, 0, terminal);
});
}
// Our VBO renders coordinates in monitor-space rather than world space. A full sized monitor (8x6) will
// use positions from (0, 0) to (164*FONT_WIDTH, 81*FONT_HEIGHT) = (984, 729). This is far outside the
// normal render distance (~200), and the edges of the monitor fade out due to fog.
// There's not really a good way around this, at least without using a custom render type (which the VBO
// renderer is trying to avoid!). Instead, we just disable fog entirely by setting the fog start to an
// absurdly high value.
var oldFogStart = RenderSystem.getShaderFogStart();
RenderSystem.setShaderFogStart(1e4f);
RenderTypes.TERMINAL.setupRenderState();
// Compose the existing model view matrix with our transformation matrix.
var modelView = new Matrix4f(RenderSystem.getModelViewMatrix()).mul(matrix);
// Render background geometry
backgroundBuffer.bind();
backgroundBuffer.drawWithShader(modelView, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader());
// Render foreground geometry with glPolygonOffset enabled.
RenderSystem.polygonOffset(-1.0f, -10.0f);
RenderSystem.enablePolygonOffset();
foregroundBuffer.bind();
foregroundBuffer.drawWithShader(
modelView, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader(),
// As mentioned in the above comment, render the extra cursor quad if it is visible this frame. Each
// // quad has an index count of 6.
FixedWidthFontRenderer.isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink()
? foregroundBuffer.getIndexCount() + 6 : foregroundBuffer.getIndexCount()
);
// Clear state
RenderSystem.polygonOffset(0.0f, -0.0f);
RenderSystem.disablePolygonOffset();
RenderTypes.TERMINAL.clearRenderState();
VertexBuffer.unbind();
RenderSystem.setShaderFogStart(oldFogStart);
}
case BEST -> throw new IllegalStateException("Impossible: Should never use BEST renderer");
renderToBuffer(foregroundBuffer, size + 4, sink -> {
DirectFixedWidthFontRenderer.drawTerminalForeground(sink, 0, 0, terminal);
// If the cursor is visible, we append it to the end of our buffer. When rendering, we can either
// render n or n+1 quads and so toggle the cursor on and off.
DirectFixedWidthFontRenderer.drawCursor(sink, 0, 0, terminal);
});
}
// Our VBO renders coordinates in monitor-space rather than world space. A full sized monitor (8x6) will
// use positions from (0, 0) to (164*FONT_WIDTH, 81*FONT_HEIGHT) = (984, 729). This is far outside the
// normal render distance (~200), and the edges of the monitor fade out due to fog.
// There's not really a good way around this, at least without using a custom render type (which the VBO
// renderer is trying to avoid!). Instead, we just disable fog entirely by setting the fog start to an
// absurdly high value.
var oldFog = RenderSystem.getShaderFog();
RenderSystem.setShaderFog(FogParameters.NO_FOG);
FixedWidthFontRenderer.TERMINAL_TEXT.setupRenderState();
// Compose the existing model view matrix with our transformation matrix.
var modelView = new Matrix4f(RenderSystem.getModelViewMatrix()).mul(matrix);
// Render background geometry
backgroundBuffer.bind();
backgroundBuffer.drawWithShader(modelView, RenderSystem.getProjectionMatrix(), RenderSystem.getShader());
// Render foreground geometry with glPolygonOffset enabled.
RenderSystem.polygonOffset(-1.0f, -10.0f);
RenderSystem.enablePolygonOffset();
foregroundBuffer.bind();
drawWithShader(
foregroundBuffer, modelView, RenderSystem.getProjectionMatrix(), RenderSystem.getShader(),
// As mentioned in the above comment, render the extra cursor quad if it is visible this frame.
FixedWidthFontRenderer.isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink()
? foregroundBuffer.indexCount
: foregroundBuffer.indexCount - FixedWidthFontRenderer.TERMINAL_TEXT.mode().indexCount(4)
);
// Clear state
RenderSystem.polygonOffset(0.0f, -0.0f);
RenderSystem.disablePolygonOffset();
FixedWidthFontRenderer.TERMINAL_TEXT.clearRenderState();
VertexBuffer.unbind();
RenderSystem.setShaderFog(oldFog);
}
private static void renderToBuffer(DirectVertexBuffer vbo, int size, Consumer<DirectFixedWidthFontRenderer.QuadEmitter> draw) {
var sink = ShaderMod.get().getQuadEmitter(size, MonitorBlockEntityRenderer::getBuffer);
var buffer = sink.buffer();
private static void renderToBuffer(VertexBuffer vbo, int size, Consumer<DirectFixedWidthFontRenderer.QuadEmitter> draw) {
var sink = ShaderMod.get().getQuadEmitter(size, backingBufferBuilder);
draw.accept(sink);
buffer.flip();
vbo.upload(buffer.limit() / sink.format().getVertexSize(), RenderTypes.TERMINAL.mode(), sink.format(), buffer);
}
private static void tboVertex(VertexConsumer builder, Matrix4f matrix, float x, float y) {
// We encode position in the UV, as that's not transformed by the matrix.
builder.addVertex(matrix, x, y, 0).setUv(x, y);
}
private static ByteBuffer getBuffer(int capacity) {
var buffer = backingBuffer;
if (buffer == null || buffer.capacity() < capacity) {
buffer = backingBuffer = buffer == null ? MemoryUtil.memAlloc(capacity) : MemoryUtil.memRealloc(buffer, capacity);
var result = backingBufferBuilder.build();
if (result == null) {
// If we have nothing to draw, just mark it as empty. We'll skip drawing in drawWithShader.
vbo.indexCount = 0;
return;
}
buffer.clear();
return buffer;
var buffer = result.byteBuffer();
var vertices = buffer.limit() / sink.format().getVertexSize();
vbo.bind();
vbo.upload(new MeshData(result, new MeshData.DrawState(
sink.format(),
vertices, FixedWidthFontRenderer.TERMINAL_TEXT.mode().indexCount(vertices),
FixedWidthFontRenderer.TERMINAL_TEXT.mode(), VertexFormat.IndexType.least(vertices)
)));
}
private static void drawWithShader(VertexBuffer buffer, Matrix4f modelView, Matrix4f projection, @Nullable CompiledShaderProgram compiledShaderProgram, int indicies) {
var originalIndexCount = buffer.indexCount;
if (originalIndexCount == 0) return;
try {
buffer.indexCount = indicies;
buffer.drawWithShader(modelView, projection, compiledShaderProgram);
} finally {
buffer.indexCount = originalIndexCount;
}
}
@Override
@ -267,28 +226,4 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
public AABB getRenderBoundingBox(MonitorBlockEntity monitor) {
return monitor.getRenderBoundingBox();
}
/**
* Determine if any monitors were rendered this frame.
*
* @return Whether any monitors were rendered.
*/
public static boolean hasRenderedThisFrame() {
return FrameInfo.getRenderFrame() == lastFrame;
}
/**
* Get the current renderer to use.
*
* @return The current renderer. Will not return {@link MonitorRenderer#BEST}.
*/
public static MonitorRenderer currentRenderer() {
var current = Config.monitorRenderer;
if (current == MonitorRenderer.BEST) current = Config.monitorRenderer = bestRenderer();
return current;
}
private static MonitorRenderer bestRenderer() {
return MonitorRenderer.VBO;
}
}

View File

@ -5,16 +5,10 @@
package dan200.computercraft.client.render.monitor;
import com.google.errorprone.annotations.concurrent.GuardedBy;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.client.render.vbo.DirectBuffers;
import dan200.computercraft.client.render.vbo.DirectVertexBuffer;
import com.mojang.blaze3d.buffers.BufferUsage;
import com.mojang.blaze3d.vertex.VertexBuffer;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
import net.minecraft.core.BlockPos;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL31;
import javax.annotation.Nullable;
import java.util.HashSet;
@ -34,52 +28,23 @@ public class MonitorRenderState implements ClientMonitor.RenderState {
public long lastRenderFrame = -1;
public @Nullable BlockPos lastRenderPos = null;
public int tboBuffer;
public int tboTexture;
public int tboUniform;
public @Nullable DirectVertexBuffer backgroundBuffer;
public @Nullable DirectVertexBuffer foregroundBuffer;
public @Nullable VertexBuffer backgroundBuffer;
public @Nullable VertexBuffer foregroundBuffer;
/**
* Create the appropriate buffer if needed.
*
* @param renderer The renderer to use.
* @return If a buffer was created. This will return {@code false} if we already have an appropriate buffer,
* or this mode does not require one.
*/
public boolean createBuffer(MonitorRenderer renderer) {
switch (renderer) {
case TBO: {
if (tboBuffer != 0) return false;
public boolean createBuffer() {
if (backgroundBuffer != null) return false;
deleteBuffers();
tboBuffer = DirectBuffers.createBuffer();
DirectBuffers.setEmptyBufferData(GL31.GL_TEXTURE_BUFFER, tboBuffer, GL15.GL_STATIC_DRAW);
tboTexture = GlStateManager._genTexture();
GL11.glBindTexture(GL31.GL_TEXTURE_BUFFER, tboTexture);
GL31.glTexBuffer(GL31.GL_TEXTURE_BUFFER, GL30.GL_R8UI, tboBuffer);
GL11.glBindTexture(GL31.GL_TEXTURE_BUFFER, 0);
tboUniform = DirectBuffers.createBuffer();
DirectBuffers.setEmptyBufferData(GL31.GL_UNIFORM_BUFFER, tboUniform, GL15.GL_STATIC_DRAW);
addMonitor();
return true;
}
case VBO:
if (backgroundBuffer != null) return false;
deleteBuffers();
backgroundBuffer = new DirectVertexBuffer();
foregroundBuffer = new DirectVertexBuffer();
addMonitor();
return true;
default:
return false;
}
deleteBuffers();
backgroundBuffer = new VertexBuffer(BufferUsage.STATIC_WRITE);
foregroundBuffer = new VertexBuffer(BufferUsage.STATIC_WRITE);
addMonitor();
return true;
}
private void addMonitor() {
@ -89,21 +54,6 @@ public class MonitorRenderState implements ClientMonitor.RenderState {
}
private void deleteBuffers() {
if (tboBuffer != 0) {
DirectBuffers.deleteBuffer(GL31.GL_TEXTURE_BUFFER, tboBuffer);
tboBuffer = 0;
}
if (tboTexture != 0) {
GlStateManager._deleteTexture(tboTexture);
tboTexture = 0;
}
if (tboUniform != 0) {
DirectBuffers.deleteBuffer(GL31.GL_UNIFORM_BUFFER, tboUniform);
tboUniform = 0;
}
if (backgroundBuffer != null) {
backgroundBuffer.close();
backgroundBuffer = null;
@ -117,7 +67,7 @@ public class MonitorRenderState implements ClientMonitor.RenderState {
@Override
public void close() {
if (tboBuffer != 0 || backgroundBuffer != null) {
if (backgroundBuffer != null) {
synchronized (allMonitors) {
allMonitors.remove(this);
}

View File

@ -1,127 +0,0 @@
// SPDX-FileCopyrightText: 2020 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.client.render.monitor;
import com.mojang.blaze3d.shaders.Uniform;
import com.mojang.blaze3d.vertex.VertexFormat;
import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.core.util.Colour;
import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.server.packs.resources.ResourceProvider;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL31;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.IOException;
import java.nio.ByteBuffer;
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.getColour;
/**
* The shader used for the monitor TBO renderer.
* <p>
* This extends Minecraft's default shader loading code to extract out the TBO buffer and handle our custom uniforms
* ({@code MonitorData}, {@code CursorBlink}).
* <p>
* See also {@code monitor_tbo.fsh} and {@code monitor_tbo.vsh} in the mod's resources.
*
* @see RenderTypes#getMonitorTextureBufferShader()
*/
public class MonitorTextureBufferShader extends ShaderInstance {
private static final Logger LOG = LoggerFactory.getLogger(MonitorTextureBufferShader.class);
public static final int UNIFORM_SIZE = 4 * 4 * 16 + 4 + 4 + 2 * 4 + 4;
static final int TEXTURE_INDEX = GL13.GL_TEXTURE3;
private final int monitorData;
private int uniformBuffer = 0;
private final @Nullable Uniform cursorBlink;
public MonitorTextureBufferShader(ResourceProvider provider, String location, VertexFormat format) throws IOException {
super(provider, location, format);
monitorData = GL31.glGetUniformBlockIndex(getId(), "MonitorData");
if (monitorData == -1) throw new IllegalStateException("Could not find MonitorData uniform.");
cursorBlink = getUniformChecked("CursorBlink");
var tbo = getUniformChecked("Tbo");
if (tbo != null) tbo.set(TEXTURE_INDEX - GL13.GL_TEXTURE0);
}
public void setupUniform(int buffer) {
uniformBuffer = buffer;
var cursorAlpha = FrameInfo.getGlobalCursorBlink() ? 1 : 0;
if (cursorBlink != null && cursorBlink.getIntBuffer().get(0) != cursorAlpha) cursorBlink.set(cursorAlpha);
}
@Override
public void apply() {
super.apply();
GL31.glBindBufferBase(GL31.GL_UNIFORM_BUFFER, monitorData, uniformBuffer);
}
@Nullable
private Uniform getUniformChecked(String name) {
var uniform = getUniform(name);
if (uniform == null) {
LOG.warn("Monitor shader {} should have uniform {}, but it was not present.", getName(), name);
}
return uniform;
}
public static void setTerminalData(ByteBuffer buffer, Terminal terminal) {
int width = terminal.getWidth(), height = terminal.getHeight();
var pos = 0;
for (var y = 0; y < height; y++) {
TextBuffer text = terminal.getLine(y), textColour = terminal.getTextColourLine(y), background = terminal.getBackgroundColourLine(y);
for (var x = 0; x < width; x++) {
buffer.put(pos, (byte) (text.charAt(x) & 0xFF));
buffer.put(pos + 1, (byte) getColour(textColour.charAt(x), Colour.WHITE));
buffer.put(pos + 2, (byte) getColour(background.charAt(x), Colour.BLACK));
pos += 3;
}
}
buffer.limit(pos);
}
public static void setUniformData(ByteBuffer buffer, Terminal terminal) {
var pos = 0;
var palette = terminal.getPalette();
for (var i = 0; i < 16; i++) {
{
var colour = palette.getColour(i);
if (!terminal.isColour()) {
var f = FixedWidthFontRenderer.toGreyscale(colour);
buffer.putFloat(pos, f).putFloat(pos + 4, f).putFloat(pos + 8, f);
} else {
buffer.putFloat(pos, (float) colour[0]).putFloat(pos + 4, (float) colour[1]).putFloat(pos + 8, (float) colour[2]);
}
}
pos += 4 * 4; // std140 requires these are 4-wide
}
var showCursor = FixedWidthFontRenderer.isCursorVisible(terminal);
buffer
.putInt(pos, terminal.getWidth()).putInt(pos + 4, terminal.getHeight())
.putInt(pos + 8, showCursor ? terminal.getCursorX() : -2)
.putInt(pos + 12, showCursor ? terminal.getCursorY() : -2)
.putInt(pos + 16, 15 - terminal.getTextColour());
buffer.limit(UNIFORM_SIZE);
}
}

View File

@ -4,18 +4,17 @@
package dan200.computercraft.client.render.text;
import com.mojang.blaze3d.vertex.ByteBufferBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.blaze3d.vertex.VertexFormat;
import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.core.terminal.Palette;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.core.util.Colour;
import net.minecraft.util.FastColor;
import net.minecraft.util.ARGB;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.*;
@ -168,40 +167,38 @@ public final class DirectFixedWidthFontRenderer {
public interface QuadEmitter {
VertexFormat format();
ByteBuffer buffer();
void quad(float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2);
}
public record ByteBufferEmitter(ByteBuffer buffer) implements QuadEmitter {
public record ByteBufferEmitter(ByteBufferBuilder builder) implements QuadEmitter {
@Override
public VertexFormat format() {
return RenderTypes.TERMINAL.format();
return TERMINAL_TEXT.format();
}
@Override
public void quad(float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2) {
DirectFixedWidthFontRenderer.quad(buffer, x1, y1, x2, y2, z, colour, u1, v1, u2, v2);
DirectFixedWidthFontRenderer.quad(builder, x1, y1, x2, y2, z, colour, u1, v1, u2, v2);
}
}
static void quad(ByteBuffer buffer, float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2) {
static void quad(ByteBufferBuilder builder, float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2) {
// Emit a single quad to our buffer. This uses Unsafe (well, LWJGL's MemoryUtil) to directly blit bytes to the
// underlying buffer. This allows us to have a single bounds check up-front, rather than one for every write.
// This provides significant performance gains, at the cost of well, using Unsafe.
// Each vertex is 28 bytes, giving 112 bytes in total. Vertices are of the form (xyz:FFF)(rgba:BBBB)(uv1:FF)(uv2:SS),
// Each vertex is 28 bytes, giving 112 bytes in total. Vertices are of the form (xyz:FFF)(abgr:BBBB)(uv1:FF)(uv2:SS),
// which matches the POSITION_COLOR_TEX_LIGHTMAP vertex format.
var position = buffer.position();
var addr = MemoryUtil.memAddress(buffer);
var addr = builder.reserve(112);
// We're doing terrible unsafe hacks below, so let's be really sure that what we're doing is reasonable.
if (position < 0 || 112 > buffer.limit() - position) throw new IndexOutOfBoundsException();
// Require the pointer to be aligned to a 32-bit boundary.
if ((addr & 3) != 0) throw new IllegalStateException("Memory is not aligned");
if (TERMINAL_TEXT.format().getVertexSize() != 28) {
throw new IllegalStateException("Incorrect vertex size");
}
// Pack colour so it is equivalent to rgba:BBBB. This matches the logic in BufferBuilder.
var colourAbgr = FastColor.ABGR32.fromArgb32(colour);
var colourAbgr = ARGB.toABGR(colour);
// Pack colour so it is equivalent to abgr:BBBB. This matches the logic in BufferBuilder.
var nativeColour = IS_LITTLE_ENDIAN ? colourAbgr : Integer.reverseBytes(colourAbgr);
memPutFloat(addr + 0, x1);
@ -240,9 +237,6 @@ public final class DirectFixedWidthFontRenderer {
memPutShort(addr + 108, (short) 0xF0);
memPutShort(addr + 110, (short) 0xF0);
// Finally increment the position.
buffer.position(position + 112);
// Well done for getting to the end of this method. I recommend you take a break and go look at cute puppies.
}
}

View File

@ -11,13 +11,13 @@ import dan200.computercraft.core.terminal.Palette;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.core.util.Colour;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.FastColor;
import net.minecraft.util.ARGB;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
/**
* Handles rendering fixed width text and computer terminals.
* <p>
@ -33,7 +33,12 @@ import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMA
* {@link DirectFixedWidthFontRenderer}.
*/
public final class FixedWidthFontRenderer {
public static final ResourceLocation FONT = ResourceLocation.fromNamespaceAndPath("computercraft", "textures/gui/term_font.png");
private static final ResourceLocation FONT = ResourceLocation.fromNamespaceAndPath("computercraft", "textures/gui/term_font.png");
/**
* A render type for terminal text.
*/
public static final RenderType TERMINAL_TEXT = RenderType.text(FONT);
public static final int FONT_HEIGHT = 9;
public static final int FONT_WIDTH = 6;
@ -42,7 +47,7 @@ public final class FixedWidthFontRenderer {
static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH;
static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH;
private static final int BLACK = FastColor.ARGB32.color(255, byteColour(Colour.BLACK.getR()), byteColour(Colour.BLACK.getR()), byteColour(Colour.BLACK.getR()));
private static final int BLACK = ARGB.color(255, byteColour(Colour.BLACK.getR()), byteColour(Colour.BLACK.getR()), byteColour(Colour.BLACK.getR()));
private static final float Z_OFFSET = 1e-3f;
private FixedWidthFontRenderer() {
@ -137,7 +142,7 @@ public final class FixedWidthFontRenderer {
var rowY = y + FONT_HEIGHT * i;
drawString(
emitter, x, rowY, terminal.getLine(i), terminal.getTextColourLine(i),
palette, FULL_BRIGHT_LIGHTMAP
palette, LightTexture.FULL_BRIGHT
);
}
}
@ -152,12 +157,12 @@ public final class FixedWidthFontRenderer {
// Top and bottom margins
drawBackground(
emitter, x, y - topMarginSize, terminal.getBackgroundColourLine(0), palette,
leftMarginSize, rightMarginSize, topMarginSize, FULL_BRIGHT_LIGHTMAP
leftMarginSize, rightMarginSize, topMarginSize, LightTexture.FULL_BRIGHT
);
drawBackground(
emitter, x, y + height * FONT_HEIGHT, terminal.getBackgroundColourLine(height - 1), palette,
leftMarginSize, rightMarginSize, bottomMarginSize, FULL_BRIGHT_LIGHTMAP
leftMarginSize, rightMarginSize, bottomMarginSize, LightTexture.FULL_BRIGHT
);
// The main text
@ -165,7 +170,7 @@ public final class FixedWidthFontRenderer {
var rowY = y + FONT_HEIGHT * i;
drawBackground(
emitter, x, rowY, terminal.getBackgroundColourLine(i), palette,
leftMarginSize, rightMarginSize, FONT_HEIGHT, FULL_BRIGHT_LIGHTMAP
leftMarginSize, rightMarginSize, FONT_HEIGHT, LightTexture.FULL_BRIGHT
);
}
}
@ -181,7 +186,7 @@ public final class FixedWidthFontRenderer {
public static void drawCursor(QuadEmitter emitter, float x, float y, Terminal terminal) {
if (isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink()) {
var colour = terminal.getPalette().getRenderColours(15 - terminal.getTextColour());
drawChar(emitter, x + terminal.getCursorX() * FONT_WIDTH, y + terminal.getCursorY() * FONT_HEIGHT, '_', colour, FULL_BRIGHT_LIGHTMAP);
drawChar(emitter, x + terminal.getCursorX() * FONT_WIDTH, y + terminal.getCursorY() * FONT_HEIGHT, '_', colour, LightTexture.FULL_BRIGHT);
}
}
@ -207,7 +212,7 @@ public final class FixedWidthFontRenderer {
}
public static void drawEmptyTerminal(QuadEmitter emitter, float x, float y, float width, float height) {
drawQuad(emitter, x, y, 0, width, height, BLACK, FULL_BRIGHT_LIGHTMAP);
drawQuad(emitter, x, y, 0, width, height, BLACK, LightTexture.FULL_BRIGHT);
}
public record QuadEmitter(Matrix4f poseMatrix, VertexConsumer consumer) {
@ -220,11 +225,10 @@ public final class FixedWidthFontRenderer {
private static void quad(QuadEmitter c, float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2, int light) {
var poseMatrix = c.poseMatrix();
var consumer = c.consumer();
int r = FastColor.ARGB32.red(colour), g = FastColor.ARGB32.green(colour), b = FastColor.ARGB32.blue(colour), a = FastColor.ARGB32.alpha(colour);
consumer.addVertex(poseMatrix, x1, y1, z).setColor(r, g, b, a).setUv(u1, v1).setLight(light);
consumer.addVertex(poseMatrix, x1, y2, z).setColor(r, g, b, a).setUv(u1, v2).setLight(light);
consumer.addVertex(poseMatrix, x2, y2, z).setColor(r, g, b, a).setUv(u2, v2).setLight(light);
consumer.addVertex(poseMatrix, x2, y1, z).setColor(r, g, b, a).setUv(u2, v1).setLight(light);
consumer.addVertex(poseMatrix, x1, y1, z).setColor(colour).setUv(u1, v1).setLight(light);
consumer.addVertex(poseMatrix, x1, y2, z).setColor(colour).setUv(u1, v2).setLight(light);
consumer.addVertex(poseMatrix, x2, y2, z).setColor(colour).setUv(u2, v2).setLight(light);
consumer.addVertex(poseMatrix, x2, y1, z).setColor(colour).setUv(u2, v1).setLight(light);
}
}

View File

@ -1,71 +0,0 @@
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.client.render.vbo;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.BufferUploader;
import net.minecraft.Util;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL15C;
import org.lwjgl.opengl.GL45C;
import java.nio.ByteBuffer;
/**
* Provides utilities to interact with OpenGL's buffer objects, either using direct state access or binding/unbinding
* it.
*/
public class DirectBuffers {
public static final boolean HAS_DSA;
static final boolean ON_LINUX = Util.getPlatform() == Util.OS.LINUX;
static {
var capabilities = GL.getCapabilities();
HAS_DSA = capabilities.OpenGL45 || capabilities.GL_ARB_direct_state_access;
}
public static int createBuffer() {
return HAS_DSA ? GL45C.glCreateBuffers() : GL15C.glGenBuffers();
}
/**
* Delete a previously created buffer.
* <p>
* On Linux, {@link GlStateManager#_glDeleteBuffers(int)} clears a buffer before deleting it. However, this involves
* binding and unbinding the buffer, conflicting with {@link BufferUploader}'s cache. This deletion method uses
* our existing {@link #setEmptyBufferData(int, int, int)}, which correctly handles clearing the buffer.
*
* @param type The buffer's type.
* @param id The buffer's ID.
*/
public static void deleteBuffer(int type, int id) {
RenderSystem.assertOnRenderThread();
if (ON_LINUX) DirectBuffers.setEmptyBufferData(type, id, GL15C.GL_DYNAMIC_DRAW);
GL15C.glDeleteBuffers(id);
}
public static void setBufferData(int type, int id, ByteBuffer buffer, int flags) {
if (HAS_DSA) {
GL45C.glNamedBufferData(id, buffer, flags);
} else {
if (type == GL15C.GL_ARRAY_BUFFER) BufferUploader.reset();
GlStateManager._glBindBuffer(type, id);
GlStateManager._glBufferData(type, buffer, flags);
GlStateManager._glBindBuffer(type, 0);
}
}
public static void setEmptyBufferData(int type, int id, int flags) {
if (HAS_DSA) {
GL45C.glNamedBufferData(id, 0, flags);
} else {
if (type == GL15C.GL_ARRAY_BUFFER) BufferUploader.reset();
GlStateManager._glBindBuffer(type, id);
GlStateManager._glBufferData(type, 0, flags);
GlStateManager._glBindBuffer(type, 0);
}
}
}

View File

@ -1,77 +0,0 @@
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.client.render.vbo;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.BufferUploader;
import com.mojang.blaze3d.vertex.VertexBuffer;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.renderer.ShaderInstance;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL15C;
import org.lwjgl.opengl.GL45C;
import java.nio.ByteBuffer;
/**
* A version of {@link VertexBuffer} which allows uploading {@link ByteBuffer}s directly.
* <p>
* This should probably be its own class (rather than subclassing), but I need access to {@link VertexBuffer#drawWithShader}.
*/
public class DirectVertexBuffer extends VertexBuffer {
private int actualIndexCount;
public DirectVertexBuffer() {
super(Usage.STATIC);
if (DirectBuffers.HAS_DSA) {
RenderSystem.glDeleteBuffers(vertexBufferId);
if (DirectBuffers.ON_LINUX) BufferUploader.reset(); // See comment on DirectBuffers.deleteBuffer.
vertexBufferId = GL45C.glCreateBuffers();
}
}
public void upload(int vertexCount, VertexFormat.Mode mode, VertexFormat format, ByteBuffer buffer) {
bind();
this.mode = mode;
actualIndexCount = indexCount = mode.indexCount(vertexCount);
indexType = VertexFormat.IndexType.SHORT;
RenderSystem.assertOnRenderThread();
DirectBuffers.setBufferData(GL15.GL_ARRAY_BUFFER, vertexBufferId, buffer, GL15.GL_STATIC_DRAW);
if (format != this.format) {
if (this.format != null) this.format.clearBufferState();
this.format = format;
GL15C.glBindBuffer(GL15C.GL_ARRAY_BUFFER, vertexBufferId);
format.setupBufferState();
GL15C.glBindBuffer(GL15C.GL_ARRAY_BUFFER, 0);
}
var indexBuffer = RenderSystem.getSequentialBuffer(mode);
if (indexBuffer != sequentialIndices || !indexBuffer.hasStorage(indexCount)) {
indexBuffer.bind(indexCount);
sequentialIndices = indexBuffer;
}
}
public void drawWithShader(Matrix4f modelView, Matrix4f projection, ShaderInstance shader, int indexCount) {
this.indexCount = indexCount;
drawWithShader(modelView, projection, shader);
this.indexCount = actualIndexCount;
}
public int getIndexCount() {
return actualIndexCount;
}
@Override
public void close() {
super.close();
if (DirectBuffers.ON_LINUX) BufferUploader.reset(); // See comment on DirectBuffers.deleteBuffer.
}
}

View File

@ -16,9 +16,11 @@ import net.minecraft.core.HolderLookup;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.PackType;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Stream;
/**
@ -32,22 +34,21 @@ public final class ClientDataProviders {
public static void add(DataProviders.GeneratorSink generator, CompletableFuture<HolderLookup.Provider> registries) {
generator.addFromCodec("Block atlases", PackType.CLIENT_RESOURCES, "atlases", SpriteSources.FILE_CODEC, out -> {
out.accept(ResourceLocation.withDefaultNamespace("blocks"), List.of(
new SingleFile(UpgradeSlot.LEFT_UPGRADE, Optional.empty()),
new SingleFile(UpgradeSlot.RIGHT_UPGRADE, Optional.empty()),
new SingleFile(LecternPrintoutModel.TEXTURE, Optional.empty())
));
out.accept(GuiSprites.SPRITE_SHEET, Stream.of(
// Buttons
GuiSprites.TURNED_OFF.textures(),
GuiSprites.TURNED_ON.textures(),
GuiSprites.TERMINATE.textures(),
out.accept(ResourceLocation.withDefaultNamespace("blocks"), makeSprites(Stream.of(
// Upgrade slot backgrounds
UpgradeSlot.LEFT_UPGRADE,
UpgradeSlot.RIGHT_UPGRADE,
// Texture for lectern printouts
LecternPrintoutModel.TEXTURE
)));
out.accept(GuiSprites.SPRITE_SHEET, makeSprites(
// Computers
GuiSprites.COMPUTER_NORMAL.textures(),
GuiSprites.COMPUTER_ADVANCED.textures(),
GuiSprites.COMPUTER_COMMAND.textures(),
GuiSprites.COMPUTER_COLOUR.textures()
).flatMap(x -> x).<SpriteSource>map(x -> new SingleFile(x, Optional.empty())).toList());
));
});
generator.add(pack -> new ExtraModelsProvider(pack, registries) {
@ -57,4 +58,10 @@ public final class ClientDataProviders {
}
});
}
@SafeVarargs
@SuppressWarnings("varargs")
private static List<SpriteSource> makeSprites(final Stream<ResourceLocation>... files) {
return Arrays.stream(files).flatMap(Function.identity()).<SpriteSource>map(x -> new SingleFile(x, Optional.empty())).toList();
}
}

View File

@ -1,11 +1,5 @@
{
"sources": [
{"type": "minecraft:single", "resource": "computercraft:gui/buttons/turned_off"},
{"type": "minecraft:single", "resource": "computercraft:gui/buttons/turned_off_hover"},
{"type": "minecraft:single", "resource": "computercraft:gui/buttons/turned_on"},
{"type": "minecraft:single", "resource": "computercraft:gui/buttons/turned_on_hover"},
{"type": "minecraft:single", "resource": "computercraft:gui/buttons/terminate"},
{"type": "minecraft:single", "resource": "computercraft:gui/buttons/terminate_hover"},
{"type": "minecraft:single", "resource": "computercraft:gui/border_normal"},
{"type": "minecraft:single", "resource": "computercraft:gui/pocket_bottom_normal"},
{"type": "minecraft:single", "resource": "computercraft:gui/sidebar_normal"},

View File

@ -124,8 +124,6 @@
"gui.computercraft.config.maximum_open_files.tooltip": "Set how many files a computer can have open at the same time. Set to 0 for unlimited.\nRange: > 0",
"gui.computercraft.config.monitor_distance": "Monitor distance",
"gui.computercraft.config.monitor_distance.tooltip": "The maximum distance monitors will render at. This defaults to the standard tile\nentity limit, but may be extended if you wish to build larger monitors.\nRange: 16 ~ 1024",
"gui.computercraft.config.monitor_renderer": "Monitor renderer",
"gui.computercraft.config.monitor_renderer.tooltip": "The renderer to use for monitors. Generally this should be kept at \"best\" - if\nmonitors have performance issues, you may wish to experiment with alternative\nrenderers.\nAllowed Values: BEST, TBO, VBO",
"gui.computercraft.config.peripheral": "Peripherals",
"gui.computercraft.config.peripheral.command_block_enabled": "Enable command block peripheral",
"gui.computercraft.config.peripheral.command_block_enabled.tooltip": "Enable Command Block peripheral support",

View File

@ -5,8 +5,8 @@
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_1"}, "trigger": "minecraft:recipe_unlocked"}
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_1"]}
"rewards": {"recipes": ["computercraft:disk"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_10"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_10"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_11"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_11"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_12"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_12"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_13"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_13"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_14"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_14"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_15"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_15"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_16"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_16"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_2"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_2"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_3"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_3"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_4"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_4"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_5"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_5"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_6"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_6"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_7"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_7"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_8"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_8"]}
}

View File

@ -1,12 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_drive": {
"conditions": {"items": [{"items": "computercraft:disk_drive"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_9"}, "trigger": "minecraft:recipe_unlocked"}
},
"requirements": [["has_the_recipe", "has_drive"]],
"rewards": {"recipes": ["computercraft:disk_9"]}
}

View File

@ -1,15 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_modem": {
"conditions": {"items": [{"items": "#computercraft:wired_modem"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {
"conditions": {"recipe": "computercraft:wired_modem_full_from"},
"trigger": "minecraft:recipe_unlocked"
}
},
"requirements": [["has_the_recipe", "has_modem"]],
"rewards": {"recipes": ["computercraft:wired_modem_full_from"]}
}

View File

@ -1,15 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_modem": {
"conditions": {"items": [{"items": "#computercraft:wired_modem"}]},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {
"conditions": {"recipe": "computercraft:wired_modem_full_to"},
"trigger": "minecraft:recipe_unlocked"
}
},
"requirements": [["has_the_recipe", "has_modem"]],
"rewards": {"recipes": ["computercraft:wired_modem_full_to"]}
}

View File

@ -1,7 +1,7 @@
{
"type": "minecraft:crafting_shaped",
"category": "redstone",
"key": {"#": {"item": "minecraft:stone"}, "R": {"tag": "c:dusts/redstone"}},
"key": {"#": "minecraft:stone", "R": "#c:dusts/redstone"},
"pattern": [" # ", "#R#", " # "],
"result": {"count": 6, "id": "computercraft:cable"}
}

View File

@ -1,7 +1,7 @@
{
"type": "minecraft:crafting_shaped",
"category": "redstone",
"key": {"#": {"tag": "c:ingots/gold"}, "G": {"tag": "c:glass_panes"}, "R": {"tag": "c:dusts/redstone"}},
"key": {"#": "#c:ingots/gold", "G": "#c:glass_panes", "R": "#c:dusts/redstone"},
"pattern": ["###", "#R#", "#G#"],
"result": {"count": 1, "id": "computercraft:computer_advanced"}
}

View File

@ -1,8 +1,8 @@
{
"type": "computercraft:transform_shaped",
"category": "redstone",
"function": [{"type": "computercraft:copy_components", "from": {"item": "computercraft:computer_normal"}}],
"key": {"#": {"tag": "c:ingots/gold"}, "C": {"item": "computercraft:computer_normal"}},
"function": [{"type": "computercraft:copy_components", "from": "computercraft:computer_normal"}],
"key": {"#": "#c:ingots/gold", "C": "computercraft:computer_normal"},
"pattern": ["###", "#C#", "# #"],
"result": {"count": 1, "id": "computercraft:computer_advanced"}
}

View File

@ -1,11 +1,7 @@
{
"type": "minecraft:crafting_shaped",
"category": "redstone",
"key": {
"#": {"tag": "c:ingots/gold"},
"G": {"tag": "c:glass_panes"},
"R": {"item": "minecraft:command_block"}
},
"key": {"#": "#c:ingots/gold", "G": "#c:glass_panes", "R": "minecraft:command_block"},
"pattern": ["###", "#R#", "#G#"],
"result": {"count": 1, "id": "computercraft:computer_command"}
}

View File

@ -1,7 +1,7 @@
{
"type": "minecraft:crafting_shaped",
"category": "redstone",
"key": {"#": {"item": "minecraft:stone"}, "G": {"tag": "c:glass_panes"}, "R": {"tag": "c:dusts/redstone"}},
"key": {"#": "minecraft:stone", "G": "#c:glass_panes", "R": "#c:dusts/redstone"},
"pattern": ["###", "#R#", "#G#"],
"result": {"count": 1, "id": "computercraft:computer_normal"}
}

View File

@ -1 +1,6 @@
{"type": "computercraft:disk", "category": "misc"}
{
"type": "computercraft:disk",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": ["#c:dusts/redstone", "minecraft:paper"]
}

View File

@ -1,11 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:black_dye"}],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 1118481, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,11 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:pink_dye"}],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 15905484, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,11 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:lime_dye"}],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 8375321, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,11 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:yellow_dye"}],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 14605932, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,15 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [
{"tag": "c:dusts/redstone"},
{"item": "minecraft:paper"},
{"item": "minecraft:light_blue_dye"}
],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 10072818, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,11 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:magenta_dye"}],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 15040472, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,11 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:orange_dye"}],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 15905331, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,11 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:white_dye"}],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 15790320, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,11 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:red_dye"}],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 13388876, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,11 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:green_dye"}],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 5744206, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,11 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:brown_dye"}],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 8349260, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,11 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:blue_dye"}],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 3368652, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,11 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:purple_dye"}],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 11691749, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,11 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:cyan_dye"}],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 5020082, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,15 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [
{"tag": "c:dusts/redstone"},
{"item": "minecraft:paper"},
{"item": "minecraft:light_gray_dye"}
],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 10066329, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,11 +0,0 @@
{
"type": "computercraft:impostor_shapeless",
"category": "redstone",
"group": "computercraft:disk",
"ingredients": [{"tag": "c:dusts/redstone"}, {"item": "minecraft:paper"}, {"item": "minecraft:gray_dye"}],
"result": {
"components": {"minecraft:dyed_color": {"rgb": 5000268, "show_in_tooltip": false}},
"count": 1,
"id": "computercraft:disk"
}
}

View File

@ -1,7 +1,7 @@
{
"type": "minecraft:crafting_shaped",
"category": "redstone",
"key": {"#": {"item": "minecraft:stone"}, "R": {"tag": "c:dusts/redstone"}},
"key": {"#": "minecraft:stone", "R": "#c:dusts/redstone"},
"pattern": ["###", "#R#", "#R#"],
"result": {"count": 1, "id": "computercraft:disk_drive"}
}

View File

@ -1,7 +1,7 @@
{
"type": "minecraft:crafting_shaped",
"category": "redstone",
"key": {"#": {"tag": "c:ingots/gold"}, "G": {"tag": "c:glass_panes"}},
"key": {"#": "#c:ingots/gold", "G": "#c:glass_panes"},
"pattern": ["###", "#G#", "###"],
"result": {"count": 4, "id": "computercraft:monitor_advanced"}
}

View File

@ -1,7 +1,7 @@
{
"type": "minecraft:crafting_shaped",
"category": "redstone",
"key": {"#": {"item": "minecraft:stone"}, "G": {"tag": "c:glass_panes"}},
"key": {"#": "minecraft:stone", "G": "#c:glass_panes"},
"pattern": ["###", "#G#", "###"],
"result": {"count": 1, "id": "computercraft:monitor_normal"}
}

View File

@ -2,7 +2,7 @@
"type": "computercraft:impostor_shaped",
"category": "redstone",
"group": "computercraft:pocket_advanced",
"key": {"#": {"item": "computercraft:speaker"}, "P": {"item": "computercraft:pocket_computer_advanced"}},
"key": {"#": "computercraft:speaker", "P": "computercraft:pocket_computer_advanced"},
"pattern": ["#", "P"],
"result": {
"components": {"computercraft:pocket_upgrade": {"id": "computercraft:speaker"}},

View File

@ -2,10 +2,7 @@
"type": "computercraft:impostor_shaped",
"category": "redstone",
"group": "computercraft:pocket_advanced",
"key": {
"#": {"item": "computercraft:wireless_modem_advanced"},
"P": {"item": "computercraft:pocket_computer_advanced"}
},
"key": {"#": "computercraft:wireless_modem_advanced", "P": "computercraft:pocket_computer_advanced"},
"pattern": ["#", "P"],
"result": {
"components": {"computercraft:pocket_upgrade": {"id": "computercraft:wireless_modem_advanced"}},

View File

@ -2,10 +2,7 @@
"type": "computercraft:impostor_shaped",
"category": "redstone",
"group": "computercraft:pocket_advanced",
"key": {
"#": {"item": "computercraft:wireless_modem_normal"},
"P": {"item": "computercraft:pocket_computer_advanced"}
},
"key": {"#": "computercraft:wireless_modem_normal", "P": "computercraft:pocket_computer_advanced"},
"pattern": ["#", "P"],
"result": {
"components": {"computercraft:pocket_upgrade": {"id": "computercraft:wireless_modem_normal"}},

View File

@ -1,7 +1,7 @@
{
"type": "minecraft:crafting_shaped",
"category": "redstone",
"key": {"#": {"tag": "c:ingots/gold"}, "A": {"item": "minecraft:golden_apple"}, "G": {"tag": "c:glass_panes"}},
"key": {"#": "#c:ingots/gold", "A": "minecraft:golden_apple", "G": "#c:glass_panes"},
"pattern": ["###", "#A#", "#G#"],
"result": {"count": 1, "id": "computercraft:pocket_computer_advanced"}
}

View File

@ -1,10 +1,8 @@
{
"type": "computercraft:transform_shaped",
"category": "redstone",
"function": [
{"type": "computercraft:copy_components", "from": {"item": "computercraft:pocket_computer_normal"}}
],
"key": {"#": {"tag": "c:ingots/gold"}, "C": {"item": "computercraft:pocket_computer_normal"}},
"function": [{"type": "computercraft:copy_components", "from": "computercraft:pocket_computer_normal"}],
"key": {"#": "#c:ingots/gold", "C": "computercraft:pocket_computer_normal"},
"pattern": ["###", "#C#", "# #"],
"result": {"count": 1, "id": "computercraft:pocket_computer_advanced"}
}

View File

@ -1,11 +1,7 @@
{
"type": "minecraft:crafting_shaped",
"category": "redstone",
"key": {
"#": {"item": "minecraft:stone"},
"A": {"item": "minecraft:golden_apple"},
"G": {"tag": "c:glass_panes"}
},
"key": {"#": "minecraft:stone", "A": "minecraft:golden_apple", "G": "#c:glass_panes"},
"pattern": ["###", "#A#", "#G#"],
"result": {"count": 1, "id": "computercraft:pocket_computer_normal"}
}

View File

@ -2,7 +2,7 @@
"type": "computercraft:impostor_shaped",
"category": "redstone",
"group": "computercraft:pocket_normal",
"key": {"#": {"item": "computercraft:speaker"}, "P": {"item": "computercraft:pocket_computer_normal"}},
"key": {"#": "computercraft:speaker", "P": "computercraft:pocket_computer_normal"},
"pattern": ["#", "P"],
"result": {
"components": {"computercraft:pocket_upgrade": {"id": "computercraft:speaker"}},

View File

@ -2,10 +2,7 @@
"type": "computercraft:impostor_shaped",
"category": "redstone",
"group": "computercraft:pocket_normal",
"key": {
"#": {"item": "computercraft:wireless_modem_advanced"},
"P": {"item": "computercraft:pocket_computer_normal"}
},
"key": {"#": "computercraft:wireless_modem_advanced", "P": "computercraft:pocket_computer_normal"},
"pattern": ["#", "P"],
"result": {
"components": {"computercraft:pocket_upgrade": {"id": "computercraft:wireless_modem_advanced"}},

View File

@ -2,10 +2,7 @@
"type": "computercraft:impostor_shaped",
"category": "redstone",
"group": "computercraft:pocket_normal",
"key": {
"#": {"item": "computercraft:wireless_modem_normal"},
"P": {"item": "computercraft:pocket_computer_normal"}
},
"key": {"#": "computercraft:wireless_modem_normal", "P": "computercraft:pocket_computer_normal"},
"pattern": ["#", "P"],
"result": {
"components": {"computercraft:pocket_upgrade": {"id": "computercraft:wireless_modem_normal"}},

View File

@ -1,12 +1,8 @@
{
"type": "computercraft:printout",
"category": "redstone",
"ingredients": [{"tag": "c:leathers"}, {"tag": "c:strings"}],
"ingredients": ["#c:leathers", "#c:strings"],
"min_printouts": 1,
"printout": [
{"item": "computercraft:printed_page"},
{"item": "computercraft:printed_pages"},
{"item": "minecraft:paper"}
],
"printout": ["computercraft:printed_page", "computercraft:printed_pages", "minecraft:paper"],
"result": {"count": 1, "id": "computercraft:printed_book"}
}

View File

@ -1,12 +1,8 @@
{
"type": "computercraft:printout",
"category": "redstone",
"ingredients": [{"tag": "c:strings"}],
"ingredients": ["#c:strings"],
"min_printouts": 2,
"printout": [
{"item": "computercraft:printed_page"},
{"item": "computercraft:printed_pages"},
{"item": "minecraft:paper"}
],
"printout": ["computercraft:printed_page", "computercraft:printed_pages", "minecraft:paper"],
"result": {"count": 1, "id": "computercraft:printed_pages"}
}

View File

@ -1,7 +1,7 @@
{
"type": "minecraft:crafting_shaped",
"category": "redstone",
"key": {"#": {"item": "minecraft:stone"}, "D": {"tag": "c:dyes"}, "R": {"tag": "c:dusts/redstone"}},
"key": {"#": "minecraft:stone", "D": "#c:dyes", "R": "#c:dusts/redstone"},
"pattern": ["###", "#R#", "#D#"],
"result": {"count": 1, "id": "computercraft:printer"}
}

Some files were not shown because too many files have changed in this diff Show More