Update to 26.1

- Replace vanilla-extract with Fabric Loom for common mod. Now that we
   no longer have to worry about remapping, this probably makes more
   sense.

 - Switch turtle upgrades to use ItemStackTemplate. Yay, immutability! I
   think I might change up the upgrade API here a bit, but not a blocker
   for release.

 - Lots of small things. I'm very glad for our game tests — these caught
   a fair few bugs.
This commit is contained in:
Jonathan Coates
2026-04-13 19:06:44 +01:00
parent f31d0b20e6
commit 8be5c28484
334 changed files with 1023 additions and 1076 deletions
@@ -6,27 +6,27 @@ package dan200.computercraft.api.client;
import com.google.common.base.Suppliers;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.QuadInstance;
import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator;
import com.mojang.blaze3d.vertex.VertexConsumer;
import dan200.computercraft.api.client.turtle.TurtleUpgradeModel;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.Sheets;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.dispatch.BlockModelRotation;
import net.minecraft.client.renderer.feature.ModelFeatureRenderer;
import net.minecraft.client.renderer.item.BlockModelWrapper;
import net.minecraft.client.renderer.item.CuboidItemModelWrapper;
import net.minecraft.client.renderer.item.ItemModel;
import net.minecraft.client.renderer.item.ItemModelResolver;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BlockModelRotation;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ResolvedModel;
import net.minecraft.client.resources.model.geometry.BakedQuad;
import net.minecraft.client.resources.model.sprite.Material;
import net.minecraft.resources.Identifier;
import net.minecraft.util.ARGB;
import net.minecraft.world.entity.ItemOwner;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
@@ -39,13 +39,13 @@ import java.util.function.Supplier;
/**
* A standalone model.
* <p>
* This is very similar to vanilla's {@link BlockModelWrapper}, but suitable for use in both {@link ItemModel}s and
* block models. This is primarily intended for use with {@link TurtleUpgradeModel}s.
* This is very similar to vanilla's {@link CuboidItemModelWrapper}, but suitable for use in both {@link ItemModel}s
* and block models. This is primarily intended for use with {@link TurtleUpgradeModel}s.
*/
public final class StandaloneModel {
private final List<BakedQuad> quads;
private final boolean useBlockLight;
private final TextureAtlasSprite particleIcon;
private final Material.Baked particleIcon;
private final RenderType renderType;
private final Supplier<Vector3fc[]> extents;
@@ -54,15 +54,15 @@ public final class StandaloneModel {
*
* @param quads The list of quads which form this model.
* @param usesBlockLight Whether this uses block lighting. See {@link ItemStackRenderState.LayerRenderState#setUsesBlockLight(boolean)}.
* @param particleIcon The sprite for the model's particles. See {@link ItemStackRenderState.LayerRenderState#setParticleIcon(TextureAtlasSprite)}.
* @param particleIcon The sprite for the model's particles. See {@link ItemStackRenderState.LayerRenderState#setParticleMaterial(Material.Baked)}.
* @param renderType The render type for this model.
*/
public StandaloneModel(List<BakedQuad> quads, boolean usesBlockLight, TextureAtlasSprite particleIcon, RenderType renderType) {
public StandaloneModel(List<BakedQuad> quads, boolean usesBlockLight, Material.Baked particleIcon, RenderType renderType) {
this.quads = quads;
this.useBlockLight = usesBlockLight;
this.particleIcon = particleIcon;
this.renderType = renderType;
this.extents = Suppliers.memoize(() -> BlockModelWrapper.computeExtents(quads));
this.extents = Suppliers.memoize(() -> CuboidItemModelWrapper.computeExtents(quads));
}
/**
@@ -110,7 +110,7 @@ public final class StandaloneModel {
return new StandaloneModel(
quads,
model.getTopGuiLight().lightLikeBlock(),
model.resolveParticleSprite(slots, baker),
model.resolveParticleMaterial(slots, baker),
detectRenderType(quads)
);
}
@@ -118,19 +118,20 @@ public final class StandaloneModel {
private static RenderType detectRenderType(List<BakedQuad> list) {
if (list.isEmpty()) return Sheets.translucentItemSheet();
var atlas = list.getFirst().sprite().atlasLocation();
var atlas = list.getFirst().materialInfo().sprite().atlasLocation();
var mismatchedAtlas = list.stream()
.map(x -> x.sprite().atlasLocation())
.map(x -> x.materialInfo().sprite().atlasLocation())
.filter(x -> !x.equals(atlas)).findFirst().orElse(null);
if (mismatchedAtlas != null) {
throw new IllegalStateException("Multiple atlases used in model, expected " + atlas + ", but also got " + mismatchedAtlas);
}
var hasTranslucent = list.stream().anyMatch(x -> x.materialInfo().itemRenderType().hasBlending());
if (atlas.equals(TextureAtlas.LOCATION_ITEMS)) {
return Sheets.translucentItemSheet();
return hasTranslucent ? Sheets.translucentItemSheet() : Sheets.cutoutItemSheet();
} else if (atlas.equals(TextureAtlas.LOCATION_BLOCKS)) {
return Sheets.translucentBlockItemSheet();
return hasTranslucent ? Sheets.translucentBlockItemSheet() : Sheets.cutoutBlockItemSheet();
} else {
throw new IllegalArgumentException("Atlas " + atlas + " can't be used for models");
}
@@ -144,9 +145,8 @@ public final class StandaloneModel {
*/
public void setupItemLayer(ItemStackRenderState.LayerRenderState layer) {
layer.setExtents(extents);
layer.setRenderType(renderType);
layer.setUsesBlockLight(useBlockLight);
layer.setParticleIcon(particleIcon);
layer.setParticleMaterial(particleIcon);
layer.prepareQuadList().addAll(quads);
}
@@ -159,7 +159,7 @@ public final class StandaloneModel {
* @param overlay The current overlay texture coordinate.
*/
public void submit(PoseStack transform, SubmitNodeCollector collector, int light, int overlay) {
submit(transform, collector, light, overlay, null, null);
submit(transform, collector, light, overlay, -1, null);
}
/**
@@ -169,36 +169,28 @@ public final class StandaloneModel {
* @param collector The node collector to render to.
* @param light The current light texture coordinate.
* @param overlay The current overlay texture coordinate.
* @param tints The tints for this model.
* @param tintColour The tint for this model.
* @param crumblingOverlay The current breaking progress.
*/
public void submit(PoseStack transform, SubmitNodeCollector collector, int light, int overlay, int @Nullable [] tints, ModelFeatureRenderer.@Nullable CrumblingOverlay crumblingOverlay) {
collector.submitCustomGeometry(transform, renderType, (pose, buffer) -> render(pose, buffer, tints, light, overlay));
public void submit(PoseStack transform, SubmitNodeCollector collector, int light, int overlay, int tintColour, ModelFeatureRenderer.@Nullable CrumblingOverlay crumblingOverlay) {
collector.submitCustomGeometry(transform, renderType, (pose, buffer) -> render(pose, buffer, tintColour, light, overlay));
if (crumblingOverlay != null && renderType.affectsCrumbling()) {
// FIXME: We need a custom hook here, which renders to crumblingBufferSource. Currently the DESTROY_TYPES
// buffer gets flushed before the main model gets rendered.
collector.submitCustomGeometry(transform, ModelBakery.DESTROY_TYPES.get(crumblingOverlay.progress()), (pose, buffer) ->
render(pose, new SheetedDecalTextureGenerator(buffer, crumblingOverlay.cameraPose(), 1.0f), null, light, overlay)
render(pose, new SheetedDecalTextureGenerator(buffer, crumblingOverlay.cameraPose(), 1.0f), -1, light, overlay)
);
}
}
private void render(PoseStack.Pose pose, VertexConsumer buffer, int @Nullable [] tints, int light, int overlay) {
private void render(PoseStack.Pose pose, VertexConsumer buffer, int tintColour, int light, int overlay) {
var instance = new QuadInstance();
instance.setLightCoords(light);
instance.setOverlayCoords(overlay);
for (var quad : quads) {
float r, g, b, a;
var idx = quad.tintIndex();
if (tints != null && idx >= 0 && idx < tints.length) {
var tint = tints[idx];
r = ARGB.red(tint) / 255.0f;
g = ARGB.green(tint) / 255.0f;
b = ARGB.blue(tint) / 255.0f;
a = ARGB.alpha(tint) / 255.0f;
} else {
r = g = b = a = 1.0f;
}
buffer.putBulkData(pose, quad, r, g, b, a, light, overlay);
instance.setColor(quad.materialInfo().isTinted() ? tintColour : -1);
buffer.putBakedQuad(pose, quad, instance);
}
}
}
@@ -11,17 +11,17 @@ import dan200.computercraft.api.client.StandaloneModel;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.upgrades.UpgradeData;
import net.minecraft.client.renderer.block.model.ItemTransform;
import net.minecraft.client.renderer.item.BlockModelWrapper;
import net.minecraft.client.renderer.item.CuboidItemModelWrapper;
import net.minecraft.client.renderer.item.ItemModelResolver;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.cuboid.ItemTransform;
import net.minecraft.resources.Identifier;
/**
* A {@link TurtleUpgradeModel} that renders a basic model.
* <p>
* This is the {@link TurtleUpgradeModel} equivalent of {@link BlockModelWrapper}.
* This is the {@link TurtleUpgradeModel} equivalent of {@link CuboidItemModelWrapper}.
*/
public final class BasicUpgradeModel implements TurtleUpgradeModel {
public static final Identifier ID = Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "sided");
@@ -63,7 +63,7 @@ public final class BasicUpgradeModel implements TurtleUpgradeModel {
renderer.appendModelIdentityElement(transform);
var layer = renderer.newLayer();
layer.setTransform(transform);
layer.setItemTransform(transform);
getModel(side).setupItemLayer(layer);
}
@@ -13,12 +13,12 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.upgrades.UpgradeData;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.block.model.ItemTransform;
import net.minecraft.client.renderer.item.ItemModelResolver;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.renderer.item.TrackingItemStackRenderState;
import net.minecraft.client.renderer.special.SpecialModelRenderer;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.cuboid.ItemTransform;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.resources.Identifier;
import net.minecraft.world.item.ItemDisplayContext;
@@ -30,7 +30,7 @@ import org.jspecify.annotations.Nullable;
import java.util.function.Consumer;
/**
* A sic {@link TurtleUpgradeModel} that renders the upgrade's {@linkplain ITurtleUpgrade#getUpgradeItem(DataComponentPatch)
* A {@link TurtleUpgradeModel} that renders the upgrade's {@linkplain ITurtleUpgrade#getUpgradeItem(DataComponentPatch)
* upgrade item}.
* <p>
* This uses appropriate transformations for "flat" items, namely those extending the {@literal minecraft:item/generated}
@@ -63,13 +63,13 @@ public final class ItemUpgradeModel implements TurtleUpgradeModel {
renderer.appendModelIdentityElement(this);
var childState = new TrackingItemStackRenderState();
resolver.updateForTopItem(childState, upgrade.getUpgradeItem(), ItemDisplayContext.NONE, null, null, seed);
resolver.updateForTopItem(childState, upgrade.getUpgradeItem().create(), ItemDisplayContext.NONE, null, null, seed);
if (!childState.isEmpty()) {
renderer.appendModelIdentityElement(childState.getModelIdentity());
renderer.appendModelIdentityElement(transform);
var layer = renderer.newLayer();
layer.setTransform(transform);
layer.setItemTransform(transform);
layer.setupSpecialModel(getRenderer(side), childState);
}
}
@@ -109,7 +109,7 @@ public final class ItemUpgradeModel implements TurtleUpgradeModel {
private record TransformedRenderer(Transformation transform) implements SpecialModelRenderer<ItemStackRenderState> {
@Override
public void submit(
@Nullable ItemStackRenderState state, ItemDisplayContext context, PoseStack poseStack, SubmitNodeCollector sink,
@Nullable ItemStackRenderState state, PoseStack poseStack, SubmitNodeCollector sink,
int light, int overlay, boolean foil, int outlineColour
) {
if (state == null) return;
@@ -16,12 +16,12 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.upgrades.UpgradeData;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.client.renderer.block.model.ItemTransform;
import net.minecraft.client.renderer.item.ItemModelResolver;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.renderer.item.SelectItemModel;
import net.minecraft.client.resources.model.MissingBlockModel;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.cuboid.ItemTransform;
import net.minecraft.client.resources.model.cuboid.MissingCuboidModel;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.resources.Identifier;
import net.minecraft.util.Util;
@@ -72,7 +72,7 @@ public final class SelectUpgradeModel<T> implements TurtleUpgradeModel {
Cases<T> cases,
Optional<TurtleUpgradeModel.Unbaked> fallback
) implements TurtleUpgradeModel.Unbaked {
private static final TurtleUpgradeModel.Unbaked MISSING = BasicUpgradeModel.unbaked(MissingBlockModel.LOCATION, MissingBlockModel.LOCATION);
private static final TurtleUpgradeModel.Unbaked MISSING = BasicUpgradeModel.unbaked(MissingCuboidModel.LOCATION, MissingCuboidModel.LOCATION);
@Override
public MapCodec<? extends TurtleUpgradeModel.Unbaked> type() {
@@ -12,15 +12,16 @@ import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.impl.client.ComputerCraftAPIClientService;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.block.model.ItemTransform;
import net.minecraft.client.renderer.item.ItemModel;
import net.minecraft.client.renderer.item.ItemModelResolver;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.ResolvableModel;
import net.minecraft.client.resources.model.cuboid.ItemTransform;
import net.minecraft.world.entity.ItemOwner;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import org.joml.Matrix4fc;
/**
* The model for a {@link ITurtleUpgrade}.
@@ -86,7 +87,7 @@ public interface TurtleUpgradeModel {
*
* @param baker The current model baker
* @return The baked upgrade model.
* @see ItemModel.Unbaked#bake(ItemModel.BakingContext)
* @see ItemModel.Unbaked#bake(ItemModel.BakingContext, Matrix4fc)
*/
TurtleUpgradeModel bake(ModelBaker baker);
}
@@ -6,7 +6,6 @@ package dan200.computercraft.api;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.Identifier;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.TagKey;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
@@ -54,8 +53,7 @@ public class ComputerCraftTags {
/**
* Items which can be dyed.
* <p>
* This is similar to {@link ItemTags#DYEABLE}, but allows cleaning the item with a sponge, rather than in a
* cauldron.
* These items can be dyed with a recipe, and cleaned with a sponge.
*/
public static final TagKey<Item> DYEABLE = make("dyeable");
@@ -54,7 +54,7 @@ public interface IMedia {
*/
@Nullable
default Holder<JukeboxSong> getAudio(HolderLookup.Provider registries, ItemStack stack) {
return JukeboxSong.fromStack(registries, stack).orElse(null);
return JukeboxSong.fromStack(stack).orElse(null);
}
/**
@@ -5,7 +5,7 @@
package dan200.computercraft.api.pocket;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
/**
@@ -15,14 +15,14 @@ import net.minecraft.world.item.ItemStack;
*/
public abstract class AbstractPocketUpgrade implements IPocketUpgrade {
private final Component adjective;
private final ItemStack stack;
private final ItemStackTemplate stack;
protected AbstractPocketUpgrade(Component adjective, ItemStack stack) {
protected AbstractPocketUpgrade(Component adjective, ItemStackTemplate stack) {
this.adjective = adjective;
this.stack = stack;
}
protected AbstractPocketUpgrade(String adjective, ItemStack stack) {
protected AbstractPocketUpgrade(String adjective, ItemStackTemplate stack) {
this(Component.translatable(adjective), stack);
}
@@ -32,7 +32,7 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade {
}
@Override
public final ItemStack getCraftingItem() {
public final ItemStackTemplate getCraftingItem() {
return stack;
}
}
@@ -7,7 +7,7 @@ package dan200.computercraft.api.pocket;
import dan200.computercraft.api.upgrades.UpgradeBase;
import dan200.computercraft.api.upgrades.UpgradeData;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.Nullable;
@@ -63,7 +63,7 @@ public interface IPocketAccess extends PocketComputer {
* @return The upgrade's NBT.
* @see #setUpgradeData(DataComponentPatch)
* @see UpgradeBase#getUpgradeItem(DataComponentPatch)
* @see UpgradeBase#getUpgradeData(ItemStack)
* @see UpgradeBase#getUpgradeData(ItemStackTemplate)
* @see #getUpgrade()
*/
DataComponentPatch getUpgradeData();
@@ -5,7 +5,7 @@
package dan200.computercraft.api.turtle;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
/**
@@ -16,15 +16,15 @@ import net.minecraft.world.item.ItemStack;
public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade {
private final TurtleUpgradeType type;
private final Component adjective;
private final ItemStack stack;
private final ItemStackTemplate stack;
protected AbstractTurtleUpgrade(TurtleUpgradeType type, Component adjective, ItemStack stack) {
protected AbstractTurtleUpgrade(TurtleUpgradeType type, Component adjective, ItemStackTemplate stack) {
this.type = type;
this.adjective = adjective;
this.stack = stack;
}
protected AbstractTurtleUpgrade(TurtleUpgradeType type, String adjective, ItemStack stack) {
protected AbstractTurtleUpgrade(TurtleUpgradeType type, String adjective, ItemStackTemplate stack) {
this(type, Component.translatable(adjective), stack);
}
@@ -39,7 +39,7 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade {
}
@Override
public final ItemStack getCraftingItem() {
public final ItemStackTemplate getCraftingItem() {
return stack;
}
}
@@ -14,7 +14,7 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.world.Container;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.Nullable;
@@ -273,7 +273,7 @@ public interface ITurtleAccess {
* @return The upgrade-specific data.
* @see #setUpgradeData(TurtleSide, DataComponentPatch)
* @see UpgradeBase#getUpgradeItem(DataComponentPatch)
* @see UpgradeBase#getUpgradeData(ItemStack)
* @see UpgradeBase#getUpgradeData(ItemStackTemplate)
*/
DataComponentPatch getUpgradeData(TurtleSide side);
@@ -130,7 +130,7 @@ public final class TurtleToolBuilder {
public ITurtleUpgrade build() {
return ComputerCraftAPIService.get().createTurtleTool(new TurtleToolSpec(
adjective,
item,
item.builtInRegistryHolder(),
damageMultiplier,
allowEnchantments,
consumeDurability,
@@ -14,6 +14,7 @@ import net.minecraft.network.chat.Component;
import net.minecraft.resources.Identifier;
import net.minecraft.util.Util;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
/**
* Common functionality between {@link ITurtleUpgrade} and {@link IPocketUpgrade}.
@@ -47,9 +48,9 @@ public interface UpgradeBase {
* that you cache the stack too, in order to prevent constructing it every time the method
* is called.
*
* @return The item stack to craft with, or {@link ItemStack#EMPTY} if it cannot be crafted.
* @return The item stack to craft with.
*/
ItemStack getCraftingItem();
ItemStackTemplate getCraftingItem();
/**
* Returns the item stack representing a currently equipped turtle upgrade.
@@ -58,16 +59,16 @@ public interface UpgradeBase {
* {@link IPocketAccess#getUpgradeData()}}, by default this data is discarded when an upgrade is unequipped,
* and the original item stack is returned.
* <p>
* By overriding this method, you can create a new {@link ItemStack} which contains enough data to
* {@linkplain #getUpgradeData(ItemStack) re-create the upgrade data} if the item is re-equipped.
* By overriding this method, you can create a new {@link ItemStackTemplate} which contains enough data to
* {@linkplain #getUpgradeData(ItemStackTemplate) re-create the upgrade data} if the item is re-equipped.
* <p>
* When overriding this, you should override {@link #getUpgradeData(ItemStack)} and {@link #isItemSuitable(ItemStack)}
* at the same time,
* When overriding this, you should override {@link #getUpgradeData(ItemStackTemplate)} and
* {@link #isItemSuitable(ItemStack)} at the same time,
*
* @param upgradeData The current upgrade data. This should <strong>NOT</strong> be mutated.
* @return The item stack returned when unequipping.
*/
default ItemStack getUpgradeItem(DataComponentPatch upgradeData) {
default ItemStackTemplate getUpgradeItem(DataComponentPatch upgradeData) {
return getCraftingItem();
}
@@ -83,7 +84,7 @@ public interface UpgradeBase {
* {@link #getCraftingItem()}.
* @return The upgrade data that should be set on the turtle or pocket computer.
*/
default DataComponentPatch getUpgradeData(ItemStack stack) {
default DataComponentPatch getUpgradeData(ItemStackTemplate stack) {
return DataComponentPatch.EMPTY;
}
@@ -102,7 +103,7 @@ public interface UpgradeBase {
* @return If this stack may be used to equip this upgrade.
*/
default boolean isItemSuitable(ItemStack stack) {
return ItemStack.isSameItemSameComponents(getCraftingItem(), stack);
return stack.is(getCraftingItem().item()) && stack.getComponentsPatch().equals(getCraftingItem().components());
}
/**
@@ -8,9 +8,10 @@ import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponentGetter;
import net.minecraft.core.component.DataComponentMap;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
import org.jspecify.annotations.Nullable;
/**
@@ -62,14 +63,11 @@ public record UpgradeData<T extends UpgradeBase>(
/**
* Get the {@linkplain UpgradeBase#getUpgradeItem(DataComponentPatch) upgrade item} for this upgrade.
* <p>
* This returns a defensive copy of the item, to prevent accidental mutation of the upgrade data or original
* {@linkplain UpgradeBase#getCraftingItem() upgrade stack}.
*
* @return This upgrade's item.
*/
public ItemStack getUpgradeItem() {
return upgrade().getUpgradeItem(data).copy();
public ItemStackTemplate getUpgradeItem() {
return upgrade().getUpgradeItem(data());
}
/**
@@ -81,7 +79,6 @@ public record UpgradeData<T extends UpgradeBase>(
*/
@Override
public <U> @Nullable U get(DataComponentType<? extends U> component) {
var result = data().get(component);
return result == null ? null : result.orElse(null);
return data().get(DataComponentMap.EMPTY, component);
}
}
@@ -7,8 +7,9 @@ package dan200.computercraft.api.upgrades;
import com.mojang.serialization.MapCodec;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.item.ItemStack;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStackTemplate;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.level.storage.loot.functions.LootItemFunction;
@@ -80,9 +81,9 @@ public sealed interface UpgradeType<T extends UpgradeBase> permits UpgradeTypeIm
* @return A new upgrade type.
* @see #simple(UpgradeBase) For upgrades whose crafting stack should not vary.
*/
static <T extends UpgradeBase> UpgradeType<T> simpleWithCustomItem(Function<ItemStack, T> factory) {
return create(BuiltInRegistries.ITEM.byNameCodec()
.xmap(x -> factory.apply(new ItemStack(x)), x -> x.getCraftingItem().getItem())
static <T extends UpgradeBase> UpgradeType<T> simpleWithCustomItem(Function<ItemStackTemplate, T> factory) {
return create(Item.CODEC
.xmap(x -> factory.apply(new ItemStackTemplate(x, 1, DataComponentPatch.EMPTY)), x -> x.getCraftingItem().item())
.fieldOf("item"));
}
}
@@ -8,7 +8,7 @@ import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import dan200.computercraft.api.turtle.TurtleToolDurability;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.ComponentSerialization;
@@ -30,7 +30,7 @@ import java.util.Optional;
*/
public record TurtleToolSpec(
Component adjective,
Item item,
Holder<Item> item,
float damageMultiplier,
boolean allowEnchantments,
TurtleToolDurability consumeDurability,
@@ -40,7 +40,7 @@ public record TurtleToolSpec(
public static final MapCodec<TurtleToolSpec> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
ComponentSerialization.CODEC.fieldOf("adjective").forGetter(TurtleToolSpec::adjective),
BuiltInRegistries.ITEM.byNameCodec().fieldOf("item").forGetter(TurtleToolSpec::item),
Item.CODEC.fieldOf("item").forGetter(TurtleToolSpec::item),
Codec.FLOAT.optionalFieldOf("damageMultiplier", DEFAULT_DAMAGE_MULTIPLIER).forGetter(TurtleToolSpec::damageMultiplier),
Codec.BOOL.optionalFieldOf("allowEnchantments", false).forGetter(TurtleToolSpec::allowEnchantments),
TurtleToolDurability.CODEC.optionalFieldOf("consumeDurability", TurtleToolDurability.NEVER).forGetter(TurtleToolSpec::consumeDurability),
+13 -4
View File
@@ -3,6 +3,7 @@
// SPDX-License-Identifier: MPL-2.0
import cc.tweaked.gradle.*
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor
plugins {
id("cc-tweaked.vanilla")
@@ -11,10 +12,18 @@ plugins {
id("cc-tweaked.publishing")
}
minecraft {
accessWideners(
"src/main/resources/computercraft.accesswidener",
"src/main/resources/computercraft-common.accesswidener",
loom {
accessWidenerPath = project.file("src/main/resources/computercraft.accesswidener")
// Loom doesn't support multiple access wideners. We inject an additional processor which applies our
// Fabric/Forge-provided AWs.
addMinecraftJarProcessor(
AccessWidenerJarProcessor::class.java,
"cct:extra-aw",
false,
project.objects.fileProperty().also {
it.set(project.file("src/main/resources/computercraft-common.accesswidener"))
it.finalizeValue()
},
)
}
@@ -28,7 +28,6 @@ import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
import net.minecraft.client.color.item.ItemTintSource;
import net.minecraft.client.gui.components.debug.DebugScreenEntry;
import net.minecraft.client.gui.render.pip.PictureInPictureRenderer;
import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState;
import net.minecraft.client.gui.screens.MenuScreens;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.MenuAccess;
@@ -40,10 +39,11 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
import net.minecraft.client.renderer.item.ItemModel;
import net.minecraft.client.renderer.item.properties.conditional.ConditionalItemModelProperty;
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperty;
import net.minecraft.client.resources.model.MissingBlockModel;
import net.minecraft.client.renderer.state.gui.pip.PictureInPictureRenderState;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.ResolvableModel;
import net.minecraft.client.resources.model.cuboid.MissingCuboidModel;
import net.minecraft.resources.Identifier;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.inventory.AbstractContainerMenu;
@@ -81,7 +81,7 @@ public final class ClientRegistry {
var model = getModel(modelId).get(manager);
if (model != null) return model;
return Objects.requireNonNull(getModel(MissingBlockModel.LOCATION).get(manager));
return Objects.requireNonNull(getModel(MissingCuboidModel.LOCATION).get(manager));
}
/**
@@ -121,7 +121,7 @@ public final class ClientRegistry {
TurtleBlockEntityRenderer.NORMAL_TURTLE_MODEL,
TurtleBlockEntityRenderer.ADVANCED_TURTLE_MODEL,
TurtleBlockEntityRenderer.COLOUR_TURTLE_MODEL,
MissingBlockModel.LOCATION,
MissingCuboidModel.LOCATION,
};
/**
@@ -8,10 +8,11 @@ import dan200.computercraft.shared.command.text.ChatHelpers;
import dan200.computercraft.shared.command.text.TableBuilder;
import dan200.computercraft.shared.command.text.TableFormatter;
import net.minecraft.ChatFormatting;
import net.minecraft.client.GuiMessageTag;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.ChatComponent;
import net.minecraft.client.multiplayer.chat.GuiMessageSource;
import net.minecraft.client.multiplayer.chat.GuiMessageTag;
import net.minecraft.network.chat.Component;
import net.minecraft.util.Mth;
import org.apache.commons.lang3.StringUtils;
@@ -66,7 +67,7 @@ public class ClientTableFormatter implements TableFormatter {
// int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() );
// List<ITextProperties> list = RenderComponentsUtil.wrapComponents( component, maxWidth, mc.fontRenderer );
// if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id );
chat.addMessage(component, null, createTag(label));
chat.addMessage(component, null, GuiMessageSource.SYSTEM_SERVER, createTag(label));
}
@Override
@@ -17,7 +17,7 @@ import dan200.computercraft.shared.computer.upload.UploadResult;
import dan200.computercraft.shared.config.Config;
import dan200.computercraft.shared.network.server.UploadFileMessage;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.input.KeyEvent;
@@ -67,8 +67,8 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
private final int uploadMaxSize;
private final ItemStack displayStack;
public AbstractComputerScreen(T container, Inventory player, Component title, int sidebarYOffset) {
super(container, player, title);
public AbstractComputerScreen(T container, Inventory player, Component title, int sidebarYOffset, int width, int height) {
super(container, player, title, width, height);
terminalData = container.getTerminal();
family = container.getFamily();
displayStack = container.getDisplayStack();
@@ -136,12 +136,6 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
return super.mouseScrolled(mouseX, mouseY, scrollX, scrollY);
}
@Override
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
super.render(graphics, mouseX, mouseY, partialTicks);
renderTooltip(graphics, mouseX, mouseY);
}
@Override
public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) {
var changed = super.mouseClicked(event, doubleClick);
@@ -164,7 +158,7 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
}
@Override
protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
protected void extractLabels(GuiGraphicsExtractor graphics, int mouseX, int mouseY) {
// Skip rendering labels.
}
@@ -8,7 +8,7 @@ import dan200.computercraft.client.gui.widgets.ComputerSidebar;
import dan200.computercraft.client.gui.widgets.TerminalWidget;
import dan200.computercraft.core.util.Nullability;
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
@@ -24,10 +24,11 @@ import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
*/
public final class ComputerScreen<T extends AbstractComputerMenu> extends AbstractComputerScreen<T> {
public ComputerScreen(T container, Inventory player, Component title) {
super(container, player, title, BORDER);
imageWidth = TerminalWidget.getWidth(terminalData.getWidth()) + BORDER * 2 + AbstractComputerMenu.SIDEBAR_WIDTH;
imageHeight = TerminalWidget.getHeight(terminalData.getHeight()) + BORDER * 2;
super(
container, player, title, BORDER,
TerminalWidget.getWidth(container.getTerminal().getWidth()) + BORDER * 2 + AbstractComputerMenu.SIDEBAR_WIDTH,
TerminalWidget.getHeight(container.getTerminal().getHeight()) + BORDER * 2
);
}
@Override
@@ -39,7 +40,8 @@ public final class ComputerScreen<T extends AbstractComputerMenu> extends Abstra
}
@Override
public void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
public void extractBackground(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) {
super.extractBackground(graphics, mouseX, mouseY, partialTicks);
// Draw a border around the terminal
var terminal = getTerminal();
var computerTextures = GuiSprites.getComputerTextures(family);
@@ -5,7 +5,7 @@
package dan200.computercraft.client.gui;
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveMenu;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
@@ -23,13 +23,8 @@ public class DiskDriveScreen extends AbstractContainerScreen<DiskDriveMenu> {
}
@Override
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
public void extractBackground(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) {
super.extractBackground(graphics, mouseX, mouseY, partialTicks);
graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND, leftPos, topPos, 0, 0, imageWidth, imageHeight, 256, 256);
}
@Override
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
super.render(graphics, mouseX, mouseY, partialTicks);
renderTooltip(graphics, mouseX, mouseY);
}
}
@@ -6,7 +6,7 @@ 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.GuiGraphicsExtractor;
import net.minecraft.client.gui.components.toasts.Toast;
import net.minecraft.client.gui.components.toasts.ToastManager;
import net.minecraft.client.renderer.RenderPipelines;
@@ -90,18 +90,18 @@ public class ItemToast implements Toast {
}
@Override
public void render(GuiGraphics graphics, Font font, long time) {
public void extractRenderState(GuiGraphicsExtractor graphics, Font font, long fullyVisibleForMs) {
graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURE, 0, 0, width(), height());
var textX = MARGIN;
if (!stack.isEmpty()) {
textX += MARGIN + IMAGE_SIZE;
graphics.renderFakeItem(stack, MARGIN, MARGIN + height() / 2 - IMAGE_SIZE);
graphics.item(stack, MARGIN, MARGIN + height() / 2 - IMAGE_SIZE);
}
graphics.drawString(font, title, textX, MARGIN, 0xff500050, false);
graphics.text(font, title, textX, MARGIN, 0xff500050, false);
for (var i = 0; i < message.size(); ++i) {
graphics.drawString(font, message.get(i), textX, LINE_SPACING + (i + 1) * LINE_SPACING, 0xff000000, false);
graphics.text(font, message.get(i), textX, LINE_SPACING + (i + 1) * LINE_SPACING, 0xff000000, false);
}
}
}
@@ -9,21 +9,16 @@ import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
import net.minecraft.SharedConstants;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.debug.DebugEntryLookingAtBlock;
import net.minecraft.client.gui.components.debug.DebugScreenDisplayer;
import net.minecraft.client.gui.components.debug.DebugEntryLookingAt;
import net.minecraft.client.gui.components.debug.DebugScreenEntry;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.Identifier;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import org.jspecify.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -31,10 +26,8 @@ import java.util.function.BiConsumer;
/**
* A {@link DebugScreenEntry} that provides information about the currently looked at block entity.
*
* @see DebugEntryLookingAtBlock
*/
public final class LookingAtBlockEntityDebugEntry implements DebugScreenEntry {
public final class LookingAtBlockEntityDebugEntry extends DebugEntryLookingAt {
public static final Identifier ID = Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "looking_at_block_entity");
private final Map<BlockEntityType<?>, BiConsumer<List<String>, BlockEntity>> blockEntityEmitters = new HashMap<>();
@@ -43,22 +36,24 @@ public final class LookingAtBlockEntityDebugEntry implements DebugScreenEntry {
}
@Override
public void display(DebugScreenDisplayer displayer, @Nullable Level level, @Nullable LevelChunk clientChunk, @Nullable LevelChunk serverChunk) {
var entity = Minecraft.getInstance().getCameraEntity();
var trueLevel = SharedConstants.DEBUG_SHOW_SERVER_DEBUG_VALUES ? level : Minecraft.getInstance().level;
if (entity == null || trueLevel == null) return;
public HitResult getHitResult(Entity camera) {
return camera.pick(20.0, 0.0F, false);
}
var hitResult = entity.pick(20.0, 0.0F, false);
if (hitResult.getType() != HitResult.Type.BLOCK) return;
var blockEntity = trueLevel.getBlockEntity(((BlockHitResult) hitResult).getBlockPos());
@Override
public void extractInfo(List<String> result, Level level, BlockPos pos) {
var blockEntity = level.getBlockEntity(pos);
if (blockEntity == null) return;
var emitter = blockEntityEmitters.get(blockEntity.getType());
if (emitter == null) return;
List<String> lines = new ArrayList<>();
emitter.accept(lines, blockEntity);
displayer.addToGroup(ID, lines);
emitter.accept(result, blockEntity);
}
@Override
public Identifier group() {
return ID;
}
@SuppressWarnings("unchecked")
@@ -9,7 +9,7 @@ import dan200.computercraft.core.input.UserComputerInput;
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.ScrollWheelHandler;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.MenuAccess;
import net.minecraft.client.input.KeyEvent;
@@ -102,20 +102,20 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
}
@Override
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
super.render(graphics, mouseX, mouseY, partialTicks);
public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) {
super.extractRenderState(graphics, mouseX, mouseY, partialTicks);
var font = minecraft.font;
var lines = font.split(Component.translatable("gui.computercraft.pocket_computer_overlay"), (int) (width * 0.8));
var y = 10;
for (var line : lines) {
graphics.drawString(font, line, (width / 2) - (font.width(line) / 2), y, 0xFFFFFFFF, true);
graphics.text(font, line, (width / 2) - (font.width(line) / 2), y, 0xFFFFFFFF, true);
y += 9;
}
}
@Override
public void renderBackground(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
public void extractBackground(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) {
// Skip rendering the background.
}
}
@@ -5,7 +5,7 @@
package dan200.computercraft.client.gui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
@@ -85,7 +85,7 @@ public final class OptionScreen extends Screen {
}
@Override
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) {
// Render the actual texture.
graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND, x, y, 0, 0, innerWidth, PADDING, 256, 256);
graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND,
@@ -97,11 +97,11 @@ public final class OptionScreen extends Screen {
var textY = this.y + PADDING;
for (var line : messageLines) {
graphics.drawString(font, line, x, textY, ARGB.opaque(0x404040), false);
graphics.text(font, line, x, textY, ARGB.opaque(0x404040), false);
textY += FONT_HEIGHT;
}
super.render(graphics, mouseX, mouseY, partialTicks);
super.extractRenderState(graphics, mouseX, mouseY, partialTicks);
}
@Override
@@ -5,7 +5,7 @@
package dan200.computercraft.client.gui;
import dan200.computercraft.shared.peripheral.printer.PrinterMenu;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
@@ -23,17 +23,12 @@ public class PrinterScreen extends AbstractContainerScreen<PrinterMenu> {
}
@Override
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
public void extractBackground(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) {
super.extractBackground(graphics, mouseX, mouseY, partialTicks);
graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND, leftPos, topPos, 0, 0, imageWidth, imageHeight, 256, 256);
if (getMenu().isPrinting()) {
graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND, leftPos + 34, topPos + 21, 176, 0, 25, 45, 256, 256);
}
}
@Override
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
super.render(graphics, mouseX, mouseY, partialTicks);
renderTooltip(graphics, mouseX, mouseY);
}
}
@@ -10,16 +10,16 @@ import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.media.PrintoutMenu;
import dan200.computercraft.shared.media.items.PrintoutData;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.navigation.ScreenRectangle;
import net.minecraft.client.gui.render.pip.PictureInPictureRenderer;
import net.minecraft.client.gui.render.state.GuiElementRenderState;
import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.input.KeyEvent;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.state.gui.GuiElementRenderState;
import net.minecraft.client.renderer.state.gui.pip.PictureInPictureRenderState;
import net.minecraft.network.chat.Component;
import net.minecraft.util.LightCoordsUtil;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerListener;
@@ -42,8 +42,7 @@ public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu>
private int page = 0;
public PrintoutScreen(PrintoutMenu container, Inventory player, Component title) {
super(container, player, title);
imageHeight = Y_SIZE;
super(container, player, title, DEFAULT_IMAGE_WIDTH, Y_SIZE);
}
private void setPrintout(ItemStack stack) {
@@ -121,9 +120,10 @@ public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu>
}
@Override
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
public void extractBackground(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) {
super.extractBackground(graphics, mouseX, mouseY, partialTicks);
// Push the printout slightly forward, to avoid clipping into the background.
graphics.guiRenderState.submitPicturesInPictureState(new PrintoutRenderState(
graphics.guiRenderState.addPicturesInPictureState(new PrintoutRenderState(
leftPos - COVER_SIZE - 32, leftPos + X_SIZE + COVER_SIZE + 32,
topPos - COVER_SIZE, topPos + Y_SIZE + COVER_SIZE,
printout, page, new Matrix3x2f(graphics.pose()), graphics.scissorStack.peek()
@@ -131,7 +131,7 @@ public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu>
}
@Override
protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
protected void extractLabels(GuiGraphicsExtractor graphics, int mouseX, int mouseY) {
// Skip rendering labels.
}
@@ -187,10 +187,10 @@ public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu>
pose.scale(1.0f, 1.0f, -1.0f);
var buffer = bufferSource.getBuffer(PrintoutRenderer.BACKGROUND);
drawBorder(pose.last().pose(), buffer, 0, 0, 0, state.page(), state.printout().pages(), state.printout().book(), LightTexture.FULL_BRIGHT);
drawBorder(pose.last().pose(), buffer, 0, 0, 0, state.page(), state.printout().pages(), state.printout().book(), LightCoordsUtil.FULL_BRIGHT);
drawText(
pose, bufferSource, X_TEXT_MARGIN, Y_TEXT_MARGIN, PrintoutData.LINES_PER_PAGE * state.page(), LightTexture.FULL_BRIGHT,
pose, bufferSource, X_TEXT_MARGIN, Y_TEXT_MARGIN, PrintoutData.LINES_PER_PAGE * state.page(), LightCoordsUtil.FULL_BRIGHT,
state.printout().text(), state.printout().colour()
);
pose.popPose();
@@ -11,7 +11,7 @@ import dan200.computercraft.core.util.Nullability;
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.gui.GuiGraphicsExtractor;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.Identifier;
@@ -35,10 +35,7 @@ public class TurtleScreen extends AbstractComputerScreen<TurtleMenu> {
private static final int FULL_TEX_SIZE = 512;
public TurtleScreen(TurtleMenu container, Inventory player, Component title) {
super(container, player, title, BORDER);
imageWidth = TEX_WIDTH + AbstractComputerMenu.SIDEBAR_WIDTH;
imageHeight = TEX_HEIGHT;
super(container, player, title, BORDER, TEX_WIDTH + AbstractComputerMenu.SIDEBAR_WIDTH, TEX_HEIGHT);
}
@Override
@@ -50,7 +47,8 @@ public class TurtleScreen extends AbstractComputerScreen<TurtleMenu> {
}
@Override
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
public void extractBackground(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) {
super.extractBackground(graphics, mouseX, mouseY, partialTicks);
var advanced = family == ComputerFamily.ADVANCED;
graphics.blit(
RenderPipelines.GUI_TEXTURED, advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL,
@@ -6,7 +6,7 @@ package dan200.computercraft.client.gui.widgets;
import it.unimi.dsi.fastutil.booleans.Boolean2ObjectFunction;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.Tooltip;
import net.minecraft.client.renderer.RenderPipelines;
@@ -42,7 +42,7 @@ public class DynamicImageButton extends Button {
}
@Override
public void renderContents(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
protected void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) {
var message = messageSupplier.get();
setMessage(message.message());
setTooltip(message.tooltip());
@@ -15,19 +15,19 @@ import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import dan200.computercraft.core.input.UserComputerInput;
import dan200.computercraft.core.terminal.Terminal;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.narration.NarratedElementType;
import net.minecraft.client.gui.narration.NarrationElementOutput;
import net.minecraft.client.gui.navigation.ScreenRectangle;
import net.minecraft.client.gui.render.TextureSetup;
import net.minecraft.client.gui.render.state.GuiElementRenderState;
import net.minecraft.client.input.CharacterEvent;
import net.minecraft.client.input.KeyEvent;
import net.minecraft.client.input.MouseButtonEvent;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.client.renderer.state.gui.GuiElementRenderState;
import net.minecraft.network.chat.Component;
import net.minecraft.util.LightCoordsUtil;
import org.joml.Matrix3x2f;
import org.joml.Matrix4f;
import org.jspecify.annotations.Nullable;
@@ -203,7 +203,7 @@ public class TerminalWidget extends AbstractWidget {
}
@Override
public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
protected void extractWidgetRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) {
if (!visible) return;
var scissor = graphics.scissorStack.peek();
@@ -213,7 +213,7 @@ public class TerminalWidget extends AbstractWidget {
RenderSystem.getSamplerCache().getClampToEdge(FilterMode.NEAREST)
);
graphics.guiRenderState.submitGuiElement(new TerminalBackgroundRenderState(
graphics.guiRenderState.addGuiElement(new TerminalBackgroundRenderState(
innerX, innerY, terminal, terminalPose, terminalTextures,
maybeIntersect(scissor, new ScreenRectangle(
innerX, innerY, terminal.getWidth() * FONT_WIDTH, terminal.getHeight() * FONT_HEIGHT).transformMaxBounds(graphics.pose())
@@ -221,7 +221,7 @@ public class TerminalWidget extends AbstractWidget {
scissor
));
graphics.guiRenderState.submitGuiElement(new TerminalTextRenderState(
graphics.guiRenderState.addGuiElement(new TerminalTextRenderState(
innerX, innerY, terminal, terminalPose, terminalTextures,
maybeIntersect(scissor, new ScreenRectangle(getX(), getY(), getWidth(), getHeight()).transformMaxBounds(graphics.pose())),
scissor
@@ -275,7 +275,7 @@ public class TerminalWidget extends AbstractWidget {
// The GUI renderer requires that the buffer is non-empty. Add a zero-size vertex so we always have something.
for (var i = 0; i < 4; i++) {
buffer.addVertex(0, 0, 0).setColor(0x00ffffff).setUv(0, 0).setLight(LightTexture.FULL_BRIGHT);
buffer.addVertex(0, 0, 0).setColor(0x00ffffff).setUv(0, 0).setLight(LightCoordsUtil.FULL_BRIGHT);
}
}
@@ -10,7 +10,7 @@ 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.client.renderer.LightTexture;
import net.minecraft.util.LightCoordsUtil;
import java.nio.ByteBuffer;
import java.util.Optional;
@@ -48,7 +48,7 @@ public class IrisShaderMod implements ShaderMod.Provider {
@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);
sink.quad(x1, y1, x2, y2, z, colour, u1, v1, u2, v2, LightCoordsUtil.FULL_BRIGHT);
}
@Override
@@ -80,10 +80,20 @@ class RecipeResolver implements ISimpleRecipeManagerPlugin<RecipeHolder<Crafting
}
@Override
public ItemStack assemble(CraftingInput input, HolderLookup.Provider registries) {
public ItemStack assemble(CraftingInput input) {
return ItemStack.EMPTY;
}
@Override
public boolean showNotification() {
return false;
}
@Override
public String group() {
return "";
}
@Override
public PlacementInfo placementInfo() {
return PlacementInfo.NOT_PLACEABLE;
@@ -12,23 +12,25 @@ import dan200.computercraft.client.turtle.TurtleOverlayManager;
import dan200.computercraft.shared.turtle.items.TurtleItem;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.item.ItemModel;
import net.minecraft.client.renderer.item.ItemModelResolver;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.resources.model.cuboid.ItemTransforms;
import net.minecraft.resources.Identifier;
import net.minecraft.world.entity.ItemOwner;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import org.joml.Matrix4fc;
import org.jspecify.annotations.Nullable;
/**
* An {@link ItemModel} that renders the {@linkplain TurtleOverlay turtle overlay}.
*
* @param transforms The item transformations from the base model.
* @param transforms The item transformations from the base model.
* @param transformation The transformation this model was baked with.
* @see TurtleOverlay#model()
*/
public record TurtleOverlayModel(ItemTransforms transforms) implements ItemModel {
public record TurtleOverlayModel(Matrix4fc transformation, ItemTransforms transforms) implements ItemModel {
public static final Identifier ID = Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "turtle/overlay");
public static final MapCodec<Unbaked> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
Identifier.CODEC.fieldOf("transforms").forGetter(Unbaked::base)
@@ -44,7 +46,8 @@ public record TurtleOverlayModel(ItemTransforms transforms) implements ItemModel
var layer = state.newLayer();
TurtleOverlayManager.get(Minecraft.getInstance().getModelManager(), overlay).model().setupItemLayer(layer);
layer.setTransform(transforms().getTransform(context));
layer.setLocalTransform(transformation());
layer.setItemTransform(transforms().getTransform(context));
}
public record Unbaked(Identifier base) implements ItemModel.Unbaked {
@@ -54,8 +57,8 @@ public record TurtleOverlayModel(ItemTransforms transforms) implements ItemModel
}
@Override
public ItemModel bake(BakingContext bakingContext) {
return new TurtleOverlayModel(bakingContext.blockModelBaker().getModel(base).getTopTransforms());
public ItemModel bake(BakingContext bakingContext, Matrix4fc transformation) {
return new TurtleOverlayModel(transformation, bakingContext.blockModelBaker().getModel(base).getTopTransforms());
}
@Override
@@ -12,23 +12,25 @@ import dan200.computercraft.client.turtle.TurtleUpgradeModelManager;
import dan200.computercraft.shared.turtle.items.TurtleItem;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.item.ItemModel;
import net.minecraft.client.renderer.item.ItemModelResolver;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.resources.model.cuboid.ItemTransforms;
import net.minecraft.resources.Identifier;
import net.minecraft.world.entity.ItemOwner;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import org.joml.Matrix4fc;
import org.jspecify.annotations.Nullable;
/**
* An {@link ItemModel} that renders a turtle upgrade, using its {@link dan200.computercraft.api.client.turtle.TurtleUpgradeModel}.
*
* @param side The side the upgrade resides on.
* @param transformation The transformation this model was baked with.
* @param base The base model. Only used to provide item transforms.
*/
public record TurtleUpgradeModel(TurtleSide side, ItemTransforms base) implements ItemModel {
public record TurtleUpgradeModel(TurtleSide side, Matrix4fc transformation, ItemTransforms base) implements ItemModel {
public static final Identifier ID = Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "turtle/upgrade");
public static final MapCodec<Unbaked> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
TurtleSide.CODEC.fieldOf("side").forGetter(Unbaked::side),
@@ -40,6 +42,7 @@ public record TurtleUpgradeModel(TurtleSide side, ItemTransforms base) implement
var upgrade = TurtleItem.getUpgradeWithData(stack, side);
if (upgrade == null) return;
// TODO: How do we apply "transformation" here?
TurtleUpgradeModelManager.get(Minecraft.getInstance().getModelManager(), upgrade.holder())
.renderForItem(upgrade, side, state, resolver, base.getTransform(context), seed);
}
@@ -51,8 +54,8 @@ public record TurtleUpgradeModel(TurtleSide side, ItemTransforms base) implement
}
@Override
public ItemModel bake(BakingContext bakingContext) {
return new TurtleUpgradeModel(side, bakingContext.blockModelBaker().getModel(base).getTopTransforms());
public ItemModel bake(BakingContext bakingContext, Matrix4fc transformation) {
return new TurtleUpgradeModel(side, transformation, bakingContext.blockModelBaker().getModel(base).getTopTransforms());
}
@Override
@@ -17,14 +17,14 @@ import net.minecraft.client.model.geom.PartPose;
import net.minecraft.client.model.geom.builders.CubeListBuilder;
import net.minecraft.client.model.geom.builders.LayerDefinition;
import net.minecraft.client.model.geom.builders.MeshDefinition;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.Sheets;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.rendertype.RenderTypes;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.MaterialSet;
import net.minecraft.client.resources.model.sprite.SpriteGetter;
import net.minecraft.client.resources.model.sprite.SpriteId;
import net.minecraft.resources.Identifier;
import net.minecraft.util.LightCoordsUtil;
import net.minecraft.util.Unit;
import net.minecraft.world.item.component.DyedItemColor;
@@ -36,11 +36,11 @@ import net.minecraft.world.item.component.DyedItemColor;
public class LecternPocketModel extends Model<Unit> {
public static final ModelLayerLocation LAYER = new ModelLayerLocation(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "lectern_pocket"), "main");
public static final Material MATERIAL_NORMAL = Sheets.BLOCK_ENTITIES_MAPPER.apply(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_normal"));
public static final Material MATERIAL_ADVANCED = Sheets.BLOCK_ENTITIES_MAPPER.apply(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_advanced"));
public static final Material MATERIAL_COLOUR = Sheets.BLOCK_ENTITIES_MAPPER.apply(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_colour"));
public static final Material MATERIAL_FRAME = Sheets.BLOCK_ENTITIES_MAPPER.apply(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_frame"));
public static final Material MATERIAL_LIGHT = Sheets.BLOCK_ENTITIES_MAPPER.apply(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_light"));
public static final SpriteId SPRITE_NORMAL = Sheets.BLOCK_ENTITIES_MAPPER.apply(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_normal"));
public static final SpriteId SPRITE_ADVANCED = Sheets.BLOCK_ENTITIES_MAPPER.apply(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_advanced"));
public static final SpriteId SPRITE_COLOUR = Sheets.BLOCK_ENTITIES_MAPPER.apply(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_colour"));
public static final SpriteId SPRITE_FRAME = Sheets.BLOCK_ENTITIES_MAPPER.apply(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_frame"));
public static final SpriteId SPRITE_LIGHT = Sheets.BLOCK_ENTITIES_MAPPER.apply(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_light"));
// The size of the terminal within the model.
public static final float TERM_WIDTH = 12.0f / 32.0f;
@@ -70,35 +70,35 @@ public class LecternPocketModel extends Model<Unit> {
*
* @param poseStack The current pose stack.
* @param collector The collector to draw to.
* @param materials The current materials
* @param sprites The current sprites
* @param packedLight The current light level.
* @param family The computer family.
* @param frameColour The pocket computer's {@linkplain DyedItemColor colour}.
* @param lightColour The pocket computer's {@linkplain PocketComputerData#getLightState() light colour}.
*/
public void submit(
PoseStack poseStack, SubmitNodeCollector collector, MaterialSet materials, int packedLight, ComputerFamily family, int frameColour, int lightColour
PoseStack poseStack, SubmitNodeCollector collector, SpriteGetter sprites, int packedLight, ComputerFamily family, int frameColour, int lightColour
) {
if (frameColour != -1) {
collector.submitModel(
this, Unit.INSTANCE, poseStack, MATERIAL_FRAME.renderType(RenderTypes::entityCutout),
packedLight, OverlayTexture.NO_OVERLAY, -1, materials.get(MATERIAL_FRAME), 0, null
this, Unit.INSTANCE, poseStack, SPRITE_FRAME.renderType(RenderTypes::entityCutout),
packedLight, OverlayTexture.NO_OVERLAY, -1, sprites.get(SPRITE_FRAME), 0, null
);
collector.submitModel(
this, Unit.INSTANCE, poseStack, MATERIAL_COLOUR.renderType(RenderTypes::entityCutout),
packedLight, OverlayTexture.NO_OVERLAY, frameColour, materials.get(MATERIAL_COLOUR), 0, null
this, Unit.INSTANCE, poseStack, SPRITE_COLOUR.renderType(RenderTypes::entityCutout),
packedLight, OverlayTexture.NO_OVERLAY, frameColour, sprites.get(SPRITE_COLOUR), 0, null
);
} else {
var material = family == ComputerFamily.ADVANCED ? MATERIAL_ADVANCED : MATERIAL_NORMAL;
var material = family == ComputerFamily.ADVANCED ? SPRITE_ADVANCED : SPRITE_NORMAL;
collector.submitModel(
this, Unit.INSTANCE, poseStack, material.renderType(RenderTypes::entityCutout),
packedLight, OverlayTexture.NO_OVERLAY, -1, materials.get(material), 0, null
packedLight, OverlayTexture.NO_OVERLAY, -1, sprites.get(material), 0, null
);
}
collector.submitModel(
this, Unit.INSTANCE, poseStack, MATERIAL_LIGHT.renderType(RenderTypes::entityCutout),
LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, lightColour, materials.get(MATERIAL_LIGHT), 0, null
this, Unit.INSTANCE, poseStack, SPRITE_LIGHT.renderType(RenderTypes::entityCutout),
LightCoordsUtil.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, lightColour, sprites.get(SPRITE_LIGHT), 0, null
);
}
}
@@ -16,7 +16,7 @@ import net.minecraft.client.model.geom.builders.LayerDefinition;
import net.minecraft.client.model.geom.builders.MeshDefinition;
import net.minecraft.client.renderer.Sheets;
import net.minecraft.client.renderer.rendertype.RenderTypes;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.sprite.SpriteId;
import net.minecraft.resources.Identifier;
import java.util.List;
@@ -30,7 +30,7 @@ import java.util.List;
public final class LecternPrintoutModel extends Model<LecternPrintoutModel.State> {
public static final ModelLayerLocation LAYER = new ModelLayerLocation(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "lectern_printout"), "main");
public static final Material MATERIAL = Sheets.BLOCK_ENTITIES_MAPPER.apply(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "printout"));
public static final SpriteId SPRITE = Sheets.BLOCK_ENTITIES_MAPPER.apply(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "printout"));
static final int TEXTURE_WIDTH = 32;
static final int TEXTURE_HEIGHT = 32;
@@ -12,7 +12,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.rendertype.RenderTypes;
import net.minecraft.client.renderer.state.LevelRenderState;
import net.minecraft.client.renderer.state.level.LevelRenderState;
import net.minecraft.util.ARGB;
import net.minecraft.util.CommonColors;
import net.minecraft.world.phys.BlockHitResult;
@@ -26,9 +26,11 @@ public final class CableHighlightRenderer {
*/
public static BlockOutlineRenderer.@Nullable Renderer drawHighlight(Camera camera, BlockHitResult hit) {
var pos = hit.getBlockPos();
var level = camera.entity().level();
var state = level.getBlockState(pos);
var player = camera.entity();
if (player == null) return null;
var state = player.level().getBlockState(pos);
// We only care about instances with both cable and modem.
if (state.getBlock() != ModRegistry.Blocks.CABLE.get() || state.getValue(CableBlock.MODEM).getFacing() == null || !state.getValue(CableBlock.CABLE)) {
@@ -26,12 +26,13 @@ import net.minecraft.client.renderer.blockentity.LecternRenderer;
import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState;
import net.minecraft.client.renderer.feature.ModelFeatureRenderer;
import net.minecraft.client.renderer.rendertype.RenderTypes;
import net.minecraft.client.renderer.state.CameraRenderState;
import net.minecraft.client.renderer.state.level.CameraRenderState;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.MaterialSet;
import net.minecraft.client.resources.model.sprite.SpriteGetter;
import net.minecraft.util.ARGB;
import net.minecraft.util.Unit;
import net.minecraft.world.item.component.DyedItemColor;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.LecternBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
@@ -50,13 +51,13 @@ import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FON
public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternBlockEntity, CustomLecternRenderer.State> {
private static final int POCKET_TERMINAL_RENDER_DISTANCE = 32;
private final MaterialSet materials;
private final SpriteGetter sprites;
private final LecternPrintoutModel printoutModel;
private final LecternBookModel bookModel;
private final LecternPocketModel pocketModel;
public CustomLecternRenderer(BlockEntityRendererProvider.Context context) {
materials = context.materials();
sprites = context.sprites();
bookModel = new LecternBookModel(context.bakeLayer(LecternBookModel.LAYER));
printoutModel = new LecternPrintoutModel(context.bakeLayer(LecternPrintoutModel.LAYER));
pocketModel = new LecternPocketModel(context.bakeLayer(LecternPocketModel.LAYER));
@@ -83,6 +84,7 @@ public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternB
@Override
public void extractRenderState(CustomLecternBlockEntity lectern, State state, float f, Vec3 camera, ModelFeatureRenderer.@Nullable CrumblingOverlay overlay) {
BlockEntityRenderer.super.extractRenderState(lectern, state, f, camera, overlay);
state.blockState = lectern.getBlockState();
var item = lectern.getItem();
if (item.getItem() instanceof PrintoutItem) {
@@ -109,19 +111,19 @@ public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternB
if (state.type == Type.PRINTOUT) {
if (state.isBook) {
collector.submitModel(
bookModel, Unit.INSTANCE, poseStack, LecternPrintoutModel.MATERIAL.renderType(RenderTypes::entitySolid),
bookModel, Unit.INSTANCE, poseStack, LecternPrintoutModel.SPRITE.renderType(RenderTypes::entitySolid),
state.lightCoords, OverlayTexture.NO_OVERLAY, -1,
materials.get(LecternPrintoutModel.MATERIAL), 0, null
sprites.get(LecternPrintoutModel.SPRITE), 0, null
);
} else {
collector.submitModel(
printoutModel, state.printoutState, poseStack, LecternPrintoutModel.MATERIAL.renderType(RenderTypes::entitySolid),
printoutModel, state.printoutState, poseStack, LecternPrintoutModel.SPRITE.renderType(RenderTypes::entitySolid),
state.lightCoords, OverlayTexture.NO_OVERLAY, -1,
materials.get(LecternPrintoutModel.MATERIAL), 0, null
sprites.get(LecternPrintoutModel.SPRITE), 0, null
);
}
} else if (state.type == Type.POCKET_COMPUTER) {
pocketModel.submit(poseStack, collector, materials, state.lightCoords, state.pocketFamily, state.pocketColour, state.pocketLight);
pocketModel.submit(poseStack, collector, sprites, state.lightCoords, state.pocketFamily, state.pocketColour, state.pocketLight);
applyPocketComputerTerminalTransform(poseStack);
@@ -187,6 +189,7 @@ public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternB
}
public static final class State extends BlockEntityRenderState {
private BlockState blockState = Blocks.AIR.defaultBlockState();
private Type type = Type.PRINTOUT;
private boolean isBook;
private final LecternPrintoutModel.State printoutState = new LecternPrintoutModel.State();
@@ -8,7 +8,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
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.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
import net.minecraft.world.entity.decoration.ItemFrame;
import net.minecraft.world.item.ItemStack;
@@ -17,7 +17,7 @@ import org.jspecify.annotations.Nullable;
/**
* Additional render state attached to a {@link ItemFrameRenderState}.
*
* @see dan200.computercraft.client.ClientHooks#onRenderItemFrame(PoseStack, MultiBufferSource, ItemFrameRenderState, ExtendedItemFrameRenderState, int)
* @see dan200.computercraft.client.ClientHooks#onRenderItemFrame(PoseStack, SubmitNodeCollector, ItemFrameRenderState, ExtendedItemFrameRenderState)
*/
public class ExtendedItemFrameRenderState {
public @Nullable PrintoutData printoutData;
@@ -14,13 +14,13 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.config.Config;
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.metadata.gui.GuiMetadataSection;
import net.minecraft.client.resources.metadata.gui.GuiSpriteScaling;
import net.minecraft.data.AtlasIds;
import net.minecraft.util.ARGB;
import net.minecraft.util.LightCoordsUtil;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.DyedItemColor;
@@ -162,7 +162,7 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
render.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, buffer) -> FixedWidthFontRenderer.drawQuad(
pose.pose(), buffer,
width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0.001f, LIGHT_HEIGHT * 2, LIGHT_HEIGHT,
ARGB.opaque(colour), LightTexture.FULL_BRIGHT
ARGB.opaque(colour), LightCoordsUtil.FULL_BRIGHT
));
}
@@ -6,15 +6,15 @@ package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.rendertype.RenderTypes;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
/**
* A {@link GuiGraphics}-equivalent renders to a {@link VertexConsumer}. This is suitable for rendering outside of a
* GUI, such as part of an entity renderer.
* A {@link GuiGraphicsExtractor}-equivalent that renders to a {@link VertexConsumer}. This is suitable for rendering
* outside of a GUI, such as part of an entity renderer.
* <p>
* This batches all render calls together, though requires that all {@link TextureAtlasSprite}s are on the same sprite
* sheet.
@@ -20,15 +20,15 @@ import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
import dan200.computercraft.shared.util.Holiday;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.block.model.ItemTransform;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState;
import net.minecraft.client.renderer.feature.ModelFeatureRenderer;
import net.minecraft.client.renderer.item.ItemModelResolver;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.renderer.state.CameraRenderState;
import net.minecraft.client.renderer.state.level.CameraRenderState;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.cuboid.ItemTransform;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.Identifier;
import net.minecraft.util.ARGB;
@@ -132,7 +132,7 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
transform.mulPose(Axis.YP.rotationDegrees(180.0f - state.yaw));
transform.translate(-0.5f, -0.5f, -0.5f);
state.model.submit(transform, collector, state.lightCoords, OverlayTexture.NO_OVERLAY, state.colour == -1 ? null : new int[]{ ARGB.opaque(state.colour) }, state.breakProgress);
state.model.submit(transform, collector, state.lightCoords, OverlayTexture.NO_OVERLAY, state.colour == -1 ? -1 : ARGB.opaque(state.colour), state.breakProgress);
if (state.overlay != null) {
state.overlay.submit(transform, collector, state.lightCoords, OverlayTexture.NO_OVERLAY);
@@ -29,7 +29,7 @@ import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState;
import net.minecraft.client.renderer.feature.ModelFeatureRenderer;
import net.minecraft.client.renderer.fog.FogRenderer;
import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.client.renderer.state.CameraRenderState;
import net.minecraft.client.renderer.state.level.CameraRenderState;
import net.minecraft.core.Direction;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
@@ -27,12 +27,12 @@ public final class MonitorHighlightRenderer {
public static BlockOutlineRenderer.@Nullable Renderer drawHighlight(Camera camera, BlockHitResult hit) {
// Preserve normal behaviour when crouching.
if (camera.entity().isCrouching()) return null;
var player = camera.entity();
if (player == null || player.isCrouching()) return null;
var world = camera.entity().level();
var pos = hit.getBlockPos();
if (!(world.getBlockEntity(pos) instanceof MonitorBlockEntity monitor)) return null;
if (!(player.level().getBlockEntity(pos) instanceof MonitorBlockEntity monitor)) return null;
// Determine which sides are part of the external faces of the monitor, and so which need to be rendered.
var faces = EnumSet.allOf(Direction.class);
@@ -11,12 +11,12 @@ 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.SubmitNodeCollector;
import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.client.renderer.rendertype.RenderTypes;
import net.minecraft.resources.Identifier;
import net.minecraft.util.ARGB;
import net.minecraft.util.LightCoordsUtil;
import org.joml.Matrix4f;
import org.joml.Vector3f;
@@ -146,7 +146,7 @@ public final class FixedWidthFontRenderer {
var rowY = y + FONT_HEIGHT * i;
drawString(
matrix, buffer, x, rowY, terminal.getLine(i), terminal.getTextColourLine(i),
palette, LightTexture.FULL_BRIGHT
palette, LightCoordsUtil.FULL_BRIGHT
);
}
}
@@ -161,12 +161,12 @@ public final class FixedWidthFontRenderer {
// Top and bottom margins
drawBackground(
matrix, buffer, x, y - topMarginSize, terminal.getBackgroundColourLine(0), palette,
leftMarginSize, rightMarginSize, topMarginSize, LightTexture.FULL_BRIGHT
leftMarginSize, rightMarginSize, topMarginSize, LightCoordsUtil.FULL_BRIGHT
);
drawBackground(
matrix, buffer, x, y + height * FONT_HEIGHT, terminal.getBackgroundColourLine(height - 1), palette,
leftMarginSize, rightMarginSize, bottomMarginSize, LightTexture.FULL_BRIGHT
leftMarginSize, rightMarginSize, bottomMarginSize, LightCoordsUtil.FULL_BRIGHT
);
// The main text
@@ -174,7 +174,7 @@ public final class FixedWidthFontRenderer {
var rowY = y + FONT_HEIGHT * i;
drawBackground(
matrix, buffer, x, rowY, terminal.getBackgroundColourLine(i), palette,
leftMarginSize, rightMarginSize, FONT_HEIGHT, LightTexture.FULL_BRIGHT
leftMarginSize, rightMarginSize, FONT_HEIGHT, LightCoordsUtil.FULL_BRIGHT
);
}
}
@@ -190,7 +190,7 @@ public final class FixedWidthFontRenderer {
public static void drawCursor(Matrix4f matrix, VertexConsumer buffer, float x, float y, Terminal terminal) {
if (isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink()) {
var colour = terminal.getPalette().getRenderColours(15 - terminal.getTextColour());
drawChar(matrix, buffer, x + terminal.getCursorX() * FONT_WIDTH, y + terminal.getCursorY() * FONT_HEIGHT, '_', colour, LightTexture.FULL_BRIGHT);
drawChar(matrix, buffer, x + terminal.getCursorX() * FONT_WIDTH, y + terminal.getCursorY() * FONT_HEIGHT, '_', colour, LightCoordsUtil.FULL_BRIGHT);
}
}
@@ -214,7 +214,7 @@ public final class FixedWidthFontRenderer {
public static void drawEmptyTerminal(PoseStack transform, SubmitNodeCollector collector, float x, float y, float width, float height) {
collector.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, buffer) ->
drawQuad(pose.pose(), buffer, x, y, 0, width, height, BLACK, LightTexture.FULL_BRIGHT));
drawQuad(pose.pose(), buffer, x, y, 0, width, height, BLACK, LightCoordsUtil.FULL_BRIGHT));
}
private static void quad(Matrix4f matrix, VertexConsumer buffer, float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2, int light) {
@@ -5,8 +5,8 @@
package dan200.computercraft.client.turtle;
import dan200.computercraft.client.CustomModelManager;
import net.minecraft.client.resources.model.MissingBlockModel;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.cuboid.MissingCuboidModel;
import net.minecraft.resources.FileToIdConverter;
import net.minecraft.resources.Identifier;
import org.jetbrains.annotations.Contract;
@@ -19,7 +19,7 @@ public class TurtleOverlayManager {
private static final CustomModelManager<TurtleOverlay.Unbaked, TurtleOverlay> loader = new CustomModelManager<>(
"turtle overlay", FileToIdConverter.json(TurtleOverlay.SOURCE), TurtleOverlay.CODEC,
TurtleOverlay.Unbaked::bake,
new TurtleOverlay.Unbaked(MissingBlockModel.LOCATION, false)
new TurtleOverlay.Unbaked(MissingCuboidModel.LOCATION, false)
);
@@ -8,8 +8,8 @@ import dan200.computercraft.api.client.turtle.BasicUpgradeModel;
import dan200.computercraft.api.client.turtle.TurtleUpgradeModel;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.client.CustomModelManager;
import net.minecraft.client.resources.model.MissingBlockModel;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.cuboid.MissingCuboidModel;
import net.minecraft.core.Holder;
import net.minecraft.resources.FileToIdConverter;
import org.jetbrains.annotations.Contract;
@@ -22,7 +22,7 @@ public final class TurtleUpgradeModelManager {
private static final CustomModelManager<TurtleUpgradeModel.Unbaked, TurtleUpgradeModel> loader = new CustomModelManager<>(
"turtle upgrade", FileToIdConverter.json(TurtleUpgradeModel.SOURCE), TurtleUpgradeModel.CODEC,
TurtleUpgradeModel.Unbaked::bake,
BasicUpgradeModel.unbaked(MissingBlockModel.LOCATION, MissingBlockModel.LOCATION)
BasicUpgradeModel.unbaked(MissingCuboidModel.LOCATION, MissingCuboidModel.LOCATION)
);
public static CustomModelManager<TurtleUpgradeModel.Unbaked, TurtleUpgradeModel> loader() {
@@ -1,30 +0,0 @@
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.mixin.client;
import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import dan200.computercraft.client.ClientHooks;
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
/**
* Provides custom block breaking progress for modems, so it only applies to the current part.
*
* @see BlockRenderDispatcher#renderBreakingTexture(BlockState, BlockPos, BlockAndTintGetter, PoseStack, VertexConsumer)
*/
@Mixin(BlockRenderDispatcher.class)
public class BlockRenderDispatcherMixin {
@ModifyVariable(method = "renderBreakingTexture", at = @At("HEAD"))
public BlockState renderBlockDamage(BlockState state, @Local BlockPos pos) {
return ClientHooks.getBlockBreakingState(state, pos);
}
}
@@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.mixin.client;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.mojang.blaze3d.vertex.PoseStack;
import dan200.computercraft.client.ClientHooks;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.state.level.BlockBreakingRenderState;
import net.minecraft.client.renderer.state.level.LevelRenderState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
/**
* Provides custom block breaking progress for modems, so it only applies to the current part.
*
* @see LevelRenderer#submitBlockDestroyAnimation(PoseStack, SubmitNodeCollector, LevelRenderState)
*/
@Mixin(LevelRenderer.class)
public class LevelRendererMixin {
@ModifyExpressionValue(
method = "submitBlockDestroyAnimation", at = @At(value = "INVOKE", target = "Ljava/util/Iterator;next()Ljava/lang/Object;")
)
private Object submitBlockDestroyAnimation(Object breaking) {
return getBlockDamageState((BlockBreakingRenderState) breaking);
}
@Unique
private BlockBreakingRenderState getBlockDamageState(BlockBreakingRenderState breaking) {
var newState = ClientHooks.getBlockBreakingState(breaking.blockState(), breaking.blockPos());
return breaking.blockState() == newState ? breaking : new BlockBreakingRenderState(breaking.blockPos(), newState, breaking.progress());
}
}
@@ -7,6 +7,6 @@
"defaultRequire": 1
},
"client": [
"BlockRenderDispatcherMixin"
"LevelRendererMixin"
]
}
@@ -71,9 +71,9 @@ public final class DataProviders {
generator.addFromCodec("Block atlases", PackOutput.Target.RESOURCE_PACK, "atlases", SpriteSources.FILE_CODEC, out -> {
out.accept(AtlasIds.BLOCKS, makeSprites(Stream.of(
LecternPrintoutModel.MATERIAL.texture(),
LecternPocketModel.MATERIAL_NORMAL.texture(), LecternPocketModel.MATERIAL_ADVANCED.texture(),
LecternPocketModel.MATERIAL_COLOUR.texture(), LecternPocketModel.MATERIAL_FRAME.texture(), LecternPocketModel.MATERIAL_LIGHT.texture()
LecternPrintoutModel.SPRITE.texture(),
LecternPocketModel.SPRITE_NORMAL.texture(), LecternPocketModel.SPRITE_ADVANCED.texture(),
LecternPocketModel.SPRITE_COLOUR.texture(), LecternPocketModel.SPRITE_FRAME.texture(), LecternPocketModel.SPRITE_LIGHT.texture()
)));
out.accept(AtlasIds.GUI, makeSprites(
@@ -11,15 +11,15 @@ import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
import net.minecraft.data.worldgen.BootstrapContext;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
import static dan200.computercraft.shared.ModRegistry.Items;
class PocketUpgradeProvider {
public static void addUpgrades(BootstrapContext<IPocketUpgrade> upgrades) {
upgrades.register(id("speaker"), new PocketSpeaker(new ItemStack(Items.SPEAKER.get())));
upgrades.register(id("wireless_modem_normal"), new PocketModem(new ItemStack(Items.WIRELESS_MODEM_NORMAL.get()), false));
upgrades.register(id("wireless_modem_advanced"), new PocketModem(new ItemStack(Items.WIRELESS_MODEM_ADVANCED.get()), true));
upgrades.register(id("speaker"), new PocketSpeaker(new ItemStackTemplate(Items.SPEAKER.get())));
upgrades.register(id("wireless_modem_normal"), new PocketModem(new ItemStackTemplate(Items.WIRELESS_MODEM_NORMAL.get()), false));
upgrades.register(id("wireless_modem_advanced"), new PocketModem(new ItemStackTemplate(Items.WIRELESS_MODEM_ADVANCED.get()), true));
}
private static ResourceKey<IPocketUpgrade> id(String id) {
@@ -27,13 +27,13 @@ import dan200.computercraft.shared.recipe.function.CopyComponents;
import dan200.computercraft.shared.turtle.items.TurtleItem;
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
import dan200.computercraft.shared.util.ColourUtils;
import dan200.computercraft.shared.util.DataComponentUtil;
import dan200.computercraft.shared.util.RegistryHelper;
import net.minecraft.advancements.Criterion;
import net.minecraft.advancements.criterion.InventoryChangeTrigger;
import net.minecraft.advancements.criterion.ItemPredicate;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
@@ -46,10 +46,9 @@ import net.minecraft.tags.ItemTags;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.ResolvableProfile;
import net.minecraft.world.item.crafting.CraftingBookCategory;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.level.ItemLike;
@@ -80,10 +79,10 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
turtleUpgrades();
turtleOverlays();
special(new ColourableRecipe(CraftingBookCategory.MISC));
special(new ClearColourRecipe(CraftingBookCategory.MISC));
special(new TurtleUpgradeRecipe(CraftingBookCategory.MISC));
special(new PocketComputerUpgradeRecipe(CraftingBookCategory.MISC));
special(new ColourableRecipe());
special(new ClearColourRecipe());
special(new TurtleUpgradeRecipe(registries.lookupOrThrow(ITurtleUpgrade.REGISTRY)));
special(new PocketComputerUpgradeRecipe(registries.lookupOrThrow(IPocketUpgrade.REGISTRY)));
}
/**
@@ -112,12 +111,15 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
registries.lookupOrThrow(ITurtleUpgrade.REGISTRY).listElements().forEach(upgradeHolder -> {
var upgrade = upgradeHolder.value();
customShaped(RecipeCategory.REDSTONE, DataComponentUtil.createStack(turtleItem, ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(upgradeHolder)))
customShaped(RecipeCategory.REDSTONE, new ItemStackTemplate(turtleItem, DataComponentPatch.builder()
.set(ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(upgradeHolder))
.build()
))
.group(name.toString())
.pattern("#T")
.define('T', turtleItem)
.define('#', upgrade.getCraftingItem().getItem())
.unlockedBy("has_items", has(turtleItem, upgrade.getCraftingItem().getItem()))
.define('#', upgrade.getCraftingItem().item().value())
.unlockedBy("has_items", has(turtleItem, upgrade.getCraftingItem().item().value()))
.build(ImpostorShapedRecipe::new)
.save(
output,
@@ -140,13 +142,16 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
registries.lookupOrThrow(IPocketUpgrade.REGISTRY).listElements().forEach(upgradeHolder -> {
var upgrade = upgradeHolder.value();
customShaped(RecipeCategory.REDSTONE, DataComponentUtil.createStack(pocket, ModRegistry.DataComponents.BACK_POCKET_UPGRADE.get(), UpgradeData.ofDefault(upgradeHolder)))
customShaped(RecipeCategory.REDSTONE, new ItemStackTemplate(pocket, DataComponentPatch.builder()
.set(ModRegistry.DataComponents.BACK_POCKET_UPGRADE.get(), UpgradeData.ofDefault(upgradeHolder))
.build()
))
.group(name.toString())
.pattern("#")
.pattern("P")
.define('P', pocket)
.define('#', upgrade.getCraftingItem().getItem())
.unlockedBy("has_items", has(pocket, upgrade.getCraftingItem().getItem()))
.define('#', upgrade.getCraftingItem().item().value())
.unlockedBy("has_items", has(pocket, upgrade.getCraftingItem().item().value()))
.build(ImpostorShapedRecipe::new)
.save(
output,
@@ -181,7 +186,10 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
for (var turtleItem : turtleItems()) {
var name = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, turtleItem);
var builder = customShapeless(RecipeCategory.REDSTONE, DataComponentUtil.createStack(turtleItem, ModRegistry.DataComponents.OVERLAY.get(), overlay))
var builder = customShapeless(RecipeCategory.REDSTONE, new ItemStackTemplate(turtleItem, DataComponentPatch.builder()
.set(ModRegistry.DataComponents.OVERLAY.get(), overlay)
.build()
))
.group(name.withSuffix("_overlay").toString())
.unlockedBy("has_turtle", has(turtleItem));
build.accept(builder);
@@ -446,24 +454,27 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
return ItemPredicate.Builder.item().of(items, item).build();
}
private static ItemStack playerHead(String name, String uuid) {
return DataComponentUtil.createStack(Items.PLAYER_HEAD, DataComponents.PROFILE, ResolvableProfile.createResolved(new GameProfile(UUID.fromString(uuid), name)));
private static ItemStackTemplate playerHead(String name, String uuid) {
return new ItemStackTemplate(Items.PLAYER_HEAD, DataComponentPatch.builder()
.set(DataComponents.PROFILE, ResolvableProfile.createResolved(new GameProfile(UUID.fromString(uuid), name)))
.build()
);
}
private ShapedSpecBuilder customShaped(RecipeCategory category, ItemStack result) {
private ShapedSpecBuilder customShaped(RecipeCategory category, ItemStackTemplate result) {
return new ShapedSpecBuilder(items, category, result);
}
private ShapedSpecBuilder customShaped(RecipeCategory category, ItemLike result) {
return new ShapedSpecBuilder(items, category, new ItemStack(result));
return new ShapedSpecBuilder(items, category, new ItemStackTemplate(result.asItem()));
}
private ShapelessSpecBuilder customShapeless(RecipeCategory category, ItemStack result) {
private ShapelessSpecBuilder customShapeless(RecipeCategory category, ItemStackTemplate result) {
return new ShapelessSpecBuilder(items, category, result);
}
private ShapelessSpecBuilder customShapeless(RecipeCategory category, ItemLike result) {
return new ShapelessSpecBuilder(items, category, new ItemStack(result));
return new ShapelessSpecBuilder(items, category, new ItemStackTemplate(result.asItem()));
}
private void special(Recipe<?> recipe) {
@@ -98,6 +98,8 @@ class TagProvider {
ModRegistry.Items.MONITOR_ADVANCED.get()
);
tags.tag(ItemTags.CAULDRON_CAN_REMOVE_DYE).addTag(ComputerCraftTags.Items.TURTLE);
// Allow printed books to be placed in bookshelves.
tags.tag(ItemTags.BOOKSHELF_BOOKS).add(ModRegistry.Items.PRINTED_BOOK.get());
@@ -18,7 +18,7 @@ import dan200.computercraft.shared.turtle.upgrades.TurtleSpeaker;
import net.minecraft.data.worldgen.BootstrapContext;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
import net.minecraft.world.item.Items;
import java.util.function.BiConsumer;
@@ -47,10 +47,10 @@ class TurtleUpgradeProvider {
}
public static void register(BootstrapContext<ITurtleUpgrade> upgrades) {
upgrades.register(SPEAKER, new TurtleSpeaker(new ItemStack(ModRegistry.Items.SPEAKER.get())));
upgrades.register(CRAFTING_TABLE, new TurtleCraftingTable(new ItemStack(Items.CRAFTING_TABLE)));
upgrades.register(WIRELESS_MODEM_NORMAL, new TurtleModem(new ItemStack(ModRegistry.Items.WIRELESS_MODEM_NORMAL.get()), false));
upgrades.register(WIRELESS_MODEM_ADVANCED, new TurtleModem(new ItemStack(ModRegistry.Items.WIRELESS_MODEM_ADVANCED.get()), true));
upgrades.register(SPEAKER, new TurtleSpeaker(new ItemStackTemplate(ModRegistry.Items.SPEAKER.get())));
upgrades.register(CRAFTING_TABLE, new TurtleCraftingTable(new ItemStackTemplate(Items.CRAFTING_TABLE)));
upgrades.register(WIRELESS_MODEM_NORMAL, new TurtleModem(new ItemStackTemplate(ModRegistry.Items.WIRELESS_MODEM_NORMAL.get()), false));
upgrades.register(WIRELESS_MODEM_ADVANCED, new TurtleModem(new ItemStackTemplate(ModRegistry.Items.WIRELESS_MODEM_ADVANCED.get()), true));
tool(DIAMOND_AXE, Items.DIAMOND_AXE).damageMultiplier(6.0f).register(upgrades);
tool(DIAMOND_PICKAXE, Items.DIAMOND_PICKAXE).register(upgrades);
@@ -32,9 +32,10 @@ import net.minecraft.client.data.models.blockstates.MultiPartGenerator;
import net.minecraft.client.data.models.blockstates.MultiVariantGenerator;
import net.minecraft.client.data.models.blockstates.PropertyDispatch;
import net.minecraft.client.data.models.model.*;
import net.minecraft.client.renderer.block.model.VariantMutator;
import net.minecraft.client.renderer.block.dispatch.VariantMutator;
import net.minecraft.client.renderer.item.EmptyModel;
import net.minecraft.client.renderer.item.properties.conditional.HasComponent;
import net.minecraft.client.resources.model.sprite.Material;
import net.minecraft.core.Direction;
import net.minecraft.core.component.DataComponents;
import net.minecraft.resources.Identifier;
@@ -186,7 +187,7 @@ public class BlockModelProvider {
);
case ON, BLINKING -> COMPUTER_ON.createWithSuffix(
block, "_" + state.getSerializedName(),
TextureMapping.orientableCube(block).put(CURSOR, Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/computer" + state.getTexture())),
TextureMapping.orientableCube(block).put(CURSOR, new Material(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/computer" + state.getTexture()))),
generators.modelOutput
);
}))
@@ -244,7 +245,7 @@ public class BlockModelProvider {
generators.blockStateOutput.accept(MultiVariantGenerator.dispatch(fullBlock)
.with(createModelDispatch(WiredModemFullBlock.MODEM_ON, WiredModemFullBlock.PERIPHERAL_ON, (on, peripheral) -> {
var suffix = (on ? "_on" : "_off") + (peripheral ? "_peripheral" : "");
var faceTexture = Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/wired_modem_face" + (peripheral ? "_peripheral" : "") + (on ? "_on" : ""));
var faceTexture = new Material(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/wired_modem_face" + (peripheral ? "_peripheral" : "") + (on ? "_on" : "")));
// TODO: Do this somewhere more elegant!
modemModel(generators, Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/wired_modem" + suffix), faceTexture);
@@ -260,12 +261,12 @@ public class BlockModelProvider {
generators.registerSimpleItemModel(ModRegistry.Items.WIRED_MODEM.get(), Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/wired_modem_off"));
}
private static Identifier modemModel(BlockModelGenerators generators, Identifier name, Identifier texture) {
private static Identifier modemModel(BlockModelGenerators generators, Identifier name, Material texture) {
return MODEM.create(
name,
new TextureMapping()
.put(TextureSlot.FRONT, texture)
.put(TextureSlot.BACK, Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/modem_back")),
.put(TextureSlot.BACK, new Material(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/modem_back"))),
generators.modelOutput
);
}
@@ -404,12 +405,12 @@ public class BlockModelProvider {
private static void registerTurtleUpgrade(BlockModelGenerators generators, String name, String texture) {
TURTLE_UPGRADE_LEFT.create(
Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name + "_left"),
TextureMapping.defaultTexture(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, texture)),
TextureMapping.defaultTexture(new Material(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, texture))),
generators.modelOutput
);
TURTLE_UPGRADE_RIGHT.create(
Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name + "_right"),
TextureMapping.defaultTexture(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, texture)),
TextureMapping.defaultTexture(new Material(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, texture))),
generators.modelOutput
);
}
@@ -13,9 +13,10 @@ import dan200.computercraft.shared.computer.core.ComputerState;
import net.minecraft.client.color.item.Dye;
import net.minecraft.client.data.models.ItemModelGenerators;
import net.minecraft.client.data.models.model.*;
import net.minecraft.client.renderer.item.BlockModelWrapper;
import net.minecraft.client.renderer.item.CuboidItemModelWrapper;
import net.minecraft.client.renderer.item.ItemModel;
import net.minecraft.client.renderer.item.properties.conditional.HasComponent;
import net.minecraft.client.resources.model.sprite.Material;
import net.minecraft.core.component.DataComponents;
import net.minecraft.resources.Identifier;
import net.minecraft.world.item.Item;
@@ -81,9 +82,9 @@ public final class ItemModelProvider {
);
return ItemModelUtils.select(PocketComputerStateProperty.create(),
ItemModelUtils.when(ComputerState.OFF, new BlockModelWrapper.Unbaked(id, tints)),
ItemModelUtils.when(ComputerState.ON, new BlockModelWrapper.Unbaked(id.withSuffix("_on"), tints)),
ItemModelUtils.when(ComputerState.BLINKING, new BlockModelWrapper.Unbaked(id.withSuffix("_blinking"), tints))
ItemModelUtils.when(ComputerState.OFF, new CuboidItemModelWrapper.Unbaked(id, Optional.empty(), tints)),
ItemModelUtils.when(ComputerState.ON, new CuboidItemModelWrapper.Unbaked(id.withSuffix("_on"), Optional.empty(), tints)),
ItemModelUtils.when(ComputerState.BLINKING, new CuboidItemModelWrapper.Unbaked(id.withSuffix("_blinking"), Optional.empty(), tints))
);
}
@@ -94,7 +95,7 @@ public final class ItemModelProvider {
Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "item/disk_colour")
);
generators.itemModelOutput.accept(item, new BlockModelWrapper.Unbaked(model, List.of(
generators.itemModelOutput.accept(item, new CuboidItemModelWrapper.Unbaked(model, Optional.empty(), List.of(
ItemModelUtils.constantTint(-1),
new Dye(colour)
)));
@@ -106,13 +107,13 @@ public final class ItemModelProvider {
* @param generators The current item generator helper.
* @param model The model we're writing to.
* @param textures The textures which make up this model.
* @see net.minecraft.client.renderer.block.model.ItemModelGenerator The parser for this file format.
* @see net.minecraft.client.resources.model.cuboid.ItemModelGenerator The parser for this file format.
*/
private static void createFlatItem(ItemModelGenerators generators, Identifier model, Identifier... textures) {
if (textures.length > 5) throw new IndexOutOfBoundsException("Too many layers");
if (textures.length == 0) throw new IndexOutOfBoundsException("Must have at least one texture");
if (textures.length == 1) {
ModelTemplates.FLAT_ITEM.create(model, TextureMapping.layer0(textures[0]), generators.modelOutput);
ModelTemplates.FLAT_ITEM.create(model, TextureMapping.layer0(new Material(textures[0])), generators.modelOutput);
return;
}
@@ -120,7 +121,7 @@ public final class ItemModelProvider {
var mapping = new TextureMapping();
for (var i = 0; i < textures.length; i++) {
var slot = slots[i] = TextureSlot.create("layer" + i);
mapping.put(slot, textures[i]);
mapping.put(slot, new Material(textures[i]));
}
new ModelTemplate(Optional.of(Identifier.withDefaultNamespace("item/generated")), Optional.empty(), slots)
@@ -18,7 +18,8 @@ import net.minecraft.data.recipes.RecipeOutput;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
import net.minecraft.world.item.crafting.CraftingRecipe;
import net.minecraft.world.item.crafting.Recipe;
import java.util.LinkedHashMap;
@@ -35,11 +36,11 @@ import java.util.function.Function;
public abstract class AbstractRecipeBuilder<S extends AbstractRecipeBuilder<S, O>, O> {
protected final HolderGetter<Item> items;
private final RecipeCategory category;
protected final ItemStack result;
protected final ItemStackTemplate result;
private String group = "";
private final Map<String, Criterion<?>> criteria = new LinkedHashMap<>();
protected AbstractRecipeBuilder(HolderGetter<Item> items, RecipeCategory category, ItemStack result) {
protected AbstractRecipeBuilder(HolderGetter<Item> items, RecipeCategory category, ItemStackTemplate result) {
this.items = items;
this.category = category;
this.result = result;
@@ -83,8 +84,11 @@ public abstract class AbstractRecipeBuilder<S extends AbstractRecipeBuilder<S, O
* @return The "built" recipe.
*/
public final FinishedRecipe build(Function<O, Recipe<?>> factory) {
var properties = new RecipeProperties(group, RecipeBuilder.determineBookCategory(category), true);
return new FinishedRecipe(factory.apply(build(properties)), result.getItem(), category, criteria);
var properties = new RecipeProperties(
new CraftingRecipe.CraftingBookInfo(RecipeBuilder.determineCraftingBookCategory(category), group),
new Recipe.CommonInfo(true)
);
return new FinishedRecipe(factory.apply(build(properties)), result, category, criteria);
}
/**
@@ -104,11 +108,11 @@ public abstract class AbstractRecipeBuilder<S extends AbstractRecipeBuilder<S, O
public static final class FinishedRecipe {
private final Recipe<?> recipe;
private final Item result;
private final ItemStackTemplate result;
private final RecipeCategory category;
private final Map<String, Criterion<?>> criteria;
private FinishedRecipe(Recipe<?> recipe, Item result, RecipeCategory category, Map<String, Criterion<?>> criteria) {
private FinishedRecipe(Recipe<?> recipe, ItemStackTemplate result, RecipeCategory category, Map<String, Criterion<?>> criteria) {
this.recipe = recipe;
this.result = result;
this.category = category;
@@ -129,7 +133,7 @@ public abstract class AbstractRecipeBuilder<S extends AbstractRecipeBuilder<S, O
}
public void save(RecipeOutput output) {
save(output, RecipeBuilder.getDefaultRecipeId(result));
save(output, RecipeBuilder.getDefaultRecipeId(result).identifier());
}
}
@@ -11,7 +11,7 @@ import net.minecraft.data.recipes.RecipeCategory;
import net.minecraft.data.recipes.ShapedRecipeBuilder;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.ShapedRecipePattern;
import net.minecraft.world.level.ItemLike;
@@ -28,7 +28,7 @@ public final class ShapedSpecBuilder extends AbstractRecipeBuilder<ShapedSpecBui
private final List<String> rows = new ArrayList<>();
private final Map<Character, Ingredient> key = new LinkedHashMap<>();
public ShapedSpecBuilder(HolderGetter<Item> items, RecipeCategory category, ItemStack result) {
public ShapedSpecBuilder(HolderGetter<Item> items, RecipeCategory category, ItemStackTemplate result) {
super(items, category, result);
}
@@ -12,7 +12,7 @@ import net.minecraft.data.recipes.RecipeCategory;
import net.minecraft.data.recipes.ShapelessRecipeBuilder;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.ItemLike;
@@ -22,7 +22,7 @@ import net.minecraft.world.level.ItemLike;
public final class ShapelessSpecBuilder extends AbstractRecipeBuilder<ShapelessSpecBuilder, ShapelessRecipeSpec> {
private final NonNullList<Ingredient> ingredients = NonNullList.create();
public ShapelessSpecBuilder(HolderGetter<Item> items, RecipeCategory category, ItemStack result) {
public ShapelessSpecBuilder(HolderGetter<Item> items, RecipeCategory category, ItemStackTemplate result) {
super(items, category, result);
}
@@ -3,14 +3,14 @@ package com.example.examplemod;
import dan200.computercraft.api.turtle.AbstractTurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleUpgradeType;
import dan200.computercraft.api.upgrades.UpgradeType;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
/**
* An example turtle upgrade.
*/
// @start region=body
public class ExampleTurtleUpgrade extends AbstractTurtleUpgrade {
public ExampleTurtleUpgrade(ItemStack stack) {
public ExampleTurtleUpgrade(ItemStackTemplate stack) {
super(TurtleUpgradeType.PERIPHERAL, "upgrade.examplemod.example_turtle_upgrade.adjective", stack);
}
@@ -11,7 +11,7 @@ import net.minecraft.data.registries.RegistryPatchGenerator;
import net.minecraft.data.worldgen.BootstrapContext;
import net.minecraft.resources.Identifier;
import net.minecraft.util.Util;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
import net.minecraft.world.item.Items;
import java.util.concurrent.CompletableFuture;
@@ -27,7 +27,7 @@ public class TurtleUpgradeProvider {
// Register our turtle upgrades.
public static void addUpgrades(BootstrapContext<ITurtleUpgrade> upgrades) {
upgrades.register(ITurtleUpgrade.createKey(EXAMPLE_TURTLE_UPGRADE), new ExampleTurtleUpgrade(new ItemStack(Items.COMPASS)));
upgrades.register(ITurtleUpgrade.createKey(EXAMPLE_TURTLE_UPGRADE), new ExampleTurtleUpgrade(new ItemStackTemplate(Items.COMPASS)));
}
// Set up the dynamic registries to contain our turtle upgrades.
@@ -7,7 +7,13 @@
"entries": [
{
"type": "minecraft:item",
"functions": [{"function": "minecraft:copy_name", "source": "block_entity"}],
"functions": [
{
"function": "minecraft:copy_components",
"include": ["minecraft:custom_name"],
"source": "block_entity"
}
],
"name": "computercraft:disk_drive"
}
],
@@ -7,7 +7,13 @@
"entries": [
{
"type": "minecraft:item",
"functions": [{"function": "minecraft:copy_name", "source": "block_entity"}],
"functions": [
{
"function": "minecraft:copy_components",
"include": ["minecraft:custom_name"],
"source": "block_entity"
}
],
"name": "computercraft:printer"
}
],
@@ -1 +1 @@
{"type": "computercraft:clear_colour", "category": "misc"}
{"type": "computercraft:clear_colour"}
@@ -1 +1 @@
{"type": "computercraft:colour", "category": "misc"}
{"type": "computercraft:colour"}
@@ -3,5 +3,5 @@
"category": "redstone",
"key": {"#": "#c:ingots/gold", "G": "#c:glass_panes", "R": "#c:dusts/redstone"},
"pattern": ["###", "#R#", "#G#"],
"result": {"count": 1, "id": "computercraft:computer_advanced"}
"result": {"id": "computercraft:computer_advanced"}
}
@@ -4,5 +4,5 @@
"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"}
"result": {"id": "computercraft:computer_advanced"}
}
@@ -3,5 +3,5 @@
"category": "redstone",
"key": {"#": "#c:ingots/gold", "G": "#c:glass_panes", "R": "minecraft:command_block"},
"pattern": ["###", "#R#", "#G#"],
"result": {"count": 1, "id": "computercraft:computer_command"}
"result": {"id": "computercraft:computer_command"}
}
@@ -3,5 +3,5 @@
"category": "redstone",
"key": {"#": "minecraft:stone", "G": "#c:glass_panes", "R": "#c:dusts/redstone"},
"pattern": ["###", "#R#", "#G#"],
"result": {"count": 1, "id": "computercraft:computer_normal"}
"result": {"id": "computercraft:computer_normal"}
}
@@ -3,5 +3,5 @@
"category": "redstone",
"key": {"#": "minecraft:stone", "R": "#c:dusts/redstone"},
"pattern": ["###", "#R#", "#R#"],
"result": {"count": 1, "id": "computercraft:disk_drive"}
"result": {"id": "computercraft:disk_drive"}
}
@@ -3,5 +3,5 @@
"category": "redstone",
"key": {"#": "minecraft:stone", "G": "#c:glass_panes"},
"pattern": ["###", "#G#", "###"],
"result": {"count": 1, "id": "computercraft:monitor_normal"}
"result": {"id": "computercraft:monitor_normal"}
}
@@ -6,7 +6,6 @@
"pattern": ["#", "P"],
"result": {
"components": {"computercraft:back_pocket_upgrade": {"id": "computercraft:speaker"}},
"count": 1,
"id": "computercraft:pocket_computer_advanced"
}
}
@@ -6,7 +6,6 @@
"pattern": ["#", "P"],
"result": {
"components": {"computercraft:back_pocket_upgrade": {"id": "computercraft:wireless_modem_advanced"}},
"count": 1,
"id": "computercraft:pocket_computer_advanced"
}
}
@@ -6,7 +6,6 @@
"pattern": ["#", "P"],
"result": {
"components": {"computercraft:back_pocket_upgrade": {"id": "computercraft:wireless_modem_normal"}},
"count": 1,
"id": "computercraft:pocket_computer_advanced"
}
}
@@ -3,5 +3,5 @@
"category": "redstone",
"key": {"#": "#c:ingots/gold", "A": "minecraft:golden_apple", "G": "#c:glass_panes"},
"pattern": ["###", "#A#", "#G#"],
"result": {"count": 1, "id": "computercraft:pocket_computer_advanced"}
"result": {"id": "computercraft:pocket_computer_advanced"}
}
@@ -4,5 +4,5 @@
"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"}
"result": {"id": "computercraft:pocket_computer_advanced"}
}
@@ -3,5 +3,5 @@
"category": "redstone",
"key": {"#": "minecraft:stone", "A": "minecraft:golden_apple", "G": "#c:glass_panes"},
"pattern": ["###", "#A#", "#G#"],
"result": {"count": 1, "id": "computercraft:pocket_computer_normal"}
"result": {"id": "computercraft:pocket_computer_normal"}
}
@@ -1 +1 @@
{"type": "computercraft:pocket_computer_upgrade", "category": "misc"}
{"type": "computercraft:pocket_computer_upgrade"}
@@ -6,7 +6,6 @@
"pattern": ["#", "P"],
"result": {
"components": {"computercraft:back_pocket_upgrade": {"id": "computercraft:speaker"}},
"count": 1,
"id": "computercraft:pocket_computer_normal"
}
}
@@ -6,7 +6,6 @@
"pattern": ["#", "P"],
"result": {
"components": {"computercraft:back_pocket_upgrade": {"id": "computercraft:wireless_modem_advanced"}},
"count": 1,
"id": "computercraft:pocket_computer_normal"
}
}
@@ -6,7 +6,6 @@
"pattern": ["#", "P"],
"result": {
"components": {"computercraft:back_pocket_upgrade": {"id": "computercraft:wireless_modem_normal"}},
"count": 1,
"id": "computercraft:pocket_computer_normal"
}
}
@@ -4,5 +4,5 @@
"ingredients": ["#c:leathers", "#c:strings"],
"min_printouts": 1,
"printout": ["computercraft:printed_page", "computercraft:printed_pages", "minecraft:paper"],
"result": {"count": 1, "id": "computercraft:printed_book"}
"result": {"id": "computercraft:printed_book"}
}
@@ -4,5 +4,5 @@
"ingredients": ["#c:strings"],
"min_printouts": 2,
"printout": ["computercraft:printed_page", "computercraft:printed_pages", "minecraft:paper"],
"result": {"count": 1, "id": "computercraft:printed_pages"}
"result": {"id": "computercraft:printed_pages"}
}
@@ -3,5 +3,5 @@
"category": "redstone",
"key": {"#": "minecraft:stone", "D": "#c:dyes", "R": "#c:dusts/redstone"},
"pattern": ["###", "#R#", "#D#"],
"result": {"count": 1, "id": "computercraft:printer"}
"result": {"id": "computercraft:printer"}
}
@@ -3,5 +3,5 @@
"category": "redstone",
"key": {"C": "computercraft:wired_modem", "R": "#c:dusts/redstone", "S": "minecraft:stone"},
"pattern": ["SRS", "RCR", "SRS"],
"result": {"count": 1, "id": "computercraft:redstone_relay"}
"result": {"id": "computercraft:redstone_relay"}
}
@@ -6,7 +6,6 @@
"components": {
"minecraft:profile": {"id": [1829193526, -1310112904, -1449411193, 2005015708], "name": "Cloudhunter"}
},
"count": 1,
"id": "minecraft:player_head"
}
}
@@ -4,7 +4,6 @@
"ingredients": ["#minecraft:skulls", "computercraft:computer_advanced"],
"result": {
"components": {"minecraft:profile": {"id": [-204941669, 125191442, -2076913230, 374933995], "name": "dan200"}},
"count": 1,
"id": "minecraft:player_head"
}
}
@@ -3,5 +3,5 @@
"category": "redstone",
"key": {"#": "minecraft:stone", "N": "minecraft:note_block", "R": "#c:dusts/redstone"},
"pattern": ["###", "#N#", "#R#"],
"result": {"count": 1, "id": "computercraft:speaker"}
"result": {"id": "computercraft:speaker"}
}
@@ -4,5 +4,5 @@
"function": [{"type": "computercraft:copy_components", "from": "computercraft:computer_advanced"}],
"key": {"#": "#c:ingots/gold", "C": "computercraft:computer_advanced", "I": "#c:chests/wooden"},
"pattern": ["###", "#C#", "#I#"],
"result": {"count": 1, "id": "computercraft:turtle_advanced"}
"result": {"id": "computercraft:turtle_advanced"}
}
@@ -6,7 +6,6 @@
"pattern": ["#T"],
"result": {
"components": {"computercraft:right_turtle_upgrade": {"id": "computercraft:speaker"}},
"count": 1,
"id": "computercraft:turtle_advanced"
}
}
@@ -6,7 +6,6 @@
"pattern": ["#T"],
"result": {
"components": {"computercraft:right_turtle_upgrade": {"id": "computercraft:wireless_modem_advanced"}},
"count": 1,
"id": "computercraft:turtle_advanced"
}
}
@@ -6,7 +6,6 @@
"pattern": ["#T"],
"result": {
"components": {"computercraft:right_turtle_upgrade": {"id": "computercraft:wireless_modem_normal"}},
"count": 1,
"id": "computercraft:turtle_advanced"
}
}
@@ -6,7 +6,6 @@
"pattern": ["#T"],
"result": {
"components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:crafting_table"}},
"count": 1,
"id": "computercraft:turtle_advanced"
}
}
@@ -6,7 +6,6 @@
"pattern": ["#T"],
"result": {
"components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:diamond_axe"}},
"count": 1,
"id": "computercraft:turtle_advanced"
}
}
@@ -6,7 +6,6 @@
"pattern": ["#T"],
"result": {
"components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:diamond_hoe"}},
"count": 1,
"id": "computercraft:turtle_advanced"
}
}
@@ -6,7 +6,6 @@
"pattern": ["#T"],
"result": {
"components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:diamond_pickaxe"}},
"count": 1,
"id": "computercraft:turtle_advanced"
}
}
@@ -6,7 +6,6 @@
"pattern": ["#T"],
"result": {
"components": {"computercraft:right_turtle_upgrade": {"id": "minecraft:diamond_shovel"}},
"count": 1,
"id": "computercraft:turtle_advanced"
}
}

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