mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-08-25 15:02:17 +00:00
Update to Minecraft 1.21.5
0/10, would not recommend. Though increasingly feeling that about modding as a whole — really not feeling as emotionally rewarding as it once did. Server-side changes are well, not simple, but relatively straightforward: - Block removal code is now called before the BE is removed, not after. - Monitors now need to track if they've being removed or not again. - Turtle drop consuming code no longer tries to insert items into the turtle immediately, instead waiting 'til the action is complete. Otherwise if the turtle gets destroyed mid-action (e.g. the block explodes), then it tries to insert its drops into itself! We previously guarded against this by checking if the turtle BE had been removed, but obviously this no longer works, so just easier to shift the insertion. - The interface for reading/writing NBT has been overhauled. It has native "getOr" and codec support (nice!) but also has been changed again in the latest snapshot (less nice!). - The dye item component no longer has a "hide tooltip" flag. We now hide the tooltip with a default component instead. - Related to the above, we can now do all the tooltip-related things we needed to do with vanilla's TooltipProvider. This did require splitting NonNegativeId into subclasses for disk/computer, but otherwise is quite nice. - Some changes to model datagen. Annoying, but boring. - Game tests got a complete overhaul. I'm keeping the interface the same for now (@GameTest), because I'm blowed if I'm datagenning test instances :p. If it's any consolation, both NF and Fabric are doing this too. Client changes are a bit more involved though: - VertexBuffer has been entirely removed. We now construct the GpuBuffer directly. - BakedModel is gone! Oh this caused so much suffering for turtle models. I ended up rewriting the whole system in processes (which then involved PRs to NF and Fabric). Rather than returning a TransformedModel, turtle models are now responsible for rendering the model. This may see another rewrite in the future. I'd like to switch to JSON-based turtle models (like item models), but that's blocked on some changes to NF right now. Sorry to all add-on devs, I know this is a big change.
This commit is contained in:
parent
a939ad8b97
commit
a1df196673
@ -15,4 +15,4 @@ isUnstable=true
|
|||||||
modVersion=1.115.1
|
modVersion=1.115.1
|
||||||
|
|
||||||
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
||||||
mcVersion=1.21.4
|
mcVersion=1.21.5
|
||||||
|
@ -7,19 +7,19 @@
|
|||||||
# Minecraft
|
# Minecraft
|
||||||
# MC version is specified in gradle.properties, as we need that in settings.gradle.
|
# MC version is specified in gradle.properties, as we need that in settings.gradle.
|
||||||
# Remember to update corresponding versions in fabric.mod.json/neoforge.mods.toml
|
# Remember to update corresponding versions in fabric.mod.json/neoforge.mods.toml
|
||||||
fabric-api = "0.118.0+1.21.4"
|
fabric-api = "0.120.0+1.21.5"
|
||||||
fabric-loader = "0.16.10"
|
fabric-loader = "0.16.10"
|
||||||
neoForge = "21.4.101-beta"
|
neoForge = "21.5.49-beta"
|
||||||
neoMergeTool = "2.0.0"
|
neoMergeTool = "2.0.0"
|
||||||
mixin = "0.8.5"
|
mixin = "0.8.5"
|
||||||
parchment = "2024.12.07"
|
parchment = "2025.04.19"
|
||||||
parchmentMc = "1.21.4"
|
parchmentMc = "1.21.5"
|
||||||
yarn = "1.21.4+build.1"
|
yarn = "1.21.5+build.1"
|
||||||
|
|
||||||
# Core dependencies (these versions are tied to the version Minecraft uses)
|
# Core dependencies (these versions are tied to the version Minecraft uses)
|
||||||
fastutil = "8.5.15"
|
fastutil = "8.5.15"
|
||||||
guava = "33.3.1-jre"
|
guava = "33.3.1-jre"
|
||||||
netty = "4.1.115.Final"
|
netty = "4.1.118.Final"
|
||||||
slf4j = "2.0.16"
|
slf4j = "2.0.16"
|
||||||
|
|
||||||
# Core dependencies (independent of Minecraft)
|
# Core dependencies (independent of Minecraft)
|
||||||
@ -38,14 +38,14 @@ nightConfig = "3.8.1"
|
|||||||
# Minecraft mods
|
# Minecraft mods
|
||||||
emi = "1.1.7+1.21"
|
emi = "1.1.7+1.21"
|
||||||
fabricPermissions = "0.3.3"
|
fabricPermissions = "0.3.3"
|
||||||
iris-fabric = "1.8.8+1.21.4-fabric"
|
iris-fabric = "1.8.11+1.21.5-fabric"
|
||||||
iris-forge = "1.8.8+1.21.4-neoforge"
|
iris-forge = "1.8.11+1.21.5-neoforge"
|
||||||
jei = "19.8.2.99"
|
jei = "19.8.2.99"
|
||||||
modmenu = "13.0.2"
|
modmenu = "13.0.2"
|
||||||
moreRed = "6.0.0.3"
|
moreRed = "6.0.0.3"
|
||||||
rei = "18.0.800"
|
rei = "18.0.800"
|
||||||
sodium-fabric = "mc1.21.4-0.6.10-fabric"
|
sodium-fabric = "mc1.21.5-0.6.12-fabric"
|
||||||
sodium-forge = "mc1.21.4-0.6.10-neoforge"
|
sodium-forge = "mc1.21.5-0.6.12-neoforge"
|
||||||
mixinExtra = "0.3.5"
|
mixinExtra = "0.3.5"
|
||||||
create-forge = "6.0.0-6"
|
create-forge = "6.0.0-6"
|
||||||
create-fabric = "0.5.1-f-build.1467+mc1.20.1"
|
create-fabric = "0.5.1-f-build.1467+mc1.20.1"
|
||||||
@ -69,7 +69,7 @@ ideaExt = "1.1.7"
|
|||||||
illuaminate = "0.1.0-83-g1131f68"
|
illuaminate = "0.1.0-83-g1131f68"
|
||||||
lwjgl = "3.3.3"
|
lwjgl = "3.3.3"
|
||||||
minotaur = "2.8.7"
|
minotaur = "2.8.7"
|
||||||
modDevGradle = "2.0.78"
|
modDevGradle = "2.0.82"
|
||||||
nullAway = "0.12.4"
|
nullAway = "0.12.4"
|
||||||
shadow = "8.3.1"
|
shadow = "8.3.1"
|
||||||
spotless = "7.0.2"
|
spotless = "7.0.2"
|
||||||
|
@ -0,0 +1,153 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.client;
|
||||||
|
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import dan200.computercraft.api.client.turtle.TurtleUpgradeModel;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.Sheets;
|
||||||
|
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||||
|
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||||
|
import net.minecraft.client.renderer.item.BlockModelWrapper;
|
||||||
|
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.texture.TextureAtlasSprite;
|
||||||
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||||
|
import net.minecraft.client.resources.model.ModelBaker;
|
||||||
|
import net.minecraft.client.resources.model.ResolvedModel;
|
||||||
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.ARGB;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
public final class StandaloneModel {
|
||||||
|
private final List<BakedQuad> quads;
|
||||||
|
private final boolean useBlockLight;
|
||||||
|
private final TextureAtlasSprite particleIcon;
|
||||||
|
private final RenderType renderType;
|
||||||
|
private final Supplier<Vector3f[]> extents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new {@link 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 renderType The render type for this model.
|
||||||
|
*/
|
||||||
|
public StandaloneModel(List<BakedQuad> quads, boolean usesBlockLight, TextureAtlasSprite particleIcon, RenderType renderType) {
|
||||||
|
this.quads = quads;
|
||||||
|
this.useBlockLight = usesBlockLight;
|
||||||
|
this.particleIcon = particleIcon;
|
||||||
|
this.renderType = renderType;
|
||||||
|
this.extents = Suppliers.memoize(() -> BlockModelWrapper.computeExtents(quads));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a model from a {@link ModelBaker} and bake it.
|
||||||
|
*
|
||||||
|
* @param model The model id to load.
|
||||||
|
* @param baker The model baker.
|
||||||
|
* @return The baked {@link StandaloneModel}.
|
||||||
|
*/
|
||||||
|
public static StandaloneModel of(ResourceLocation model, ModelBaker baker) {
|
||||||
|
return of(baker.getModel(model), baker);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bake a {@link ResolvedModel} into a {@link StandaloneModel}.
|
||||||
|
*
|
||||||
|
* @param model The resolved model.
|
||||||
|
* @param baker The model baker.
|
||||||
|
* @return The baked {@link StandaloneModel}.
|
||||||
|
*/
|
||||||
|
public static StandaloneModel of(ResolvedModel model, ModelBaker baker) {
|
||||||
|
var slots = model.getTopTextureSlots();
|
||||||
|
return new StandaloneModel(
|
||||||
|
model.bakeTopGeometry(slots, baker, BlockModelRotation.X0_Y0).getAll(),
|
||||||
|
model.getTopGuiLight().lightLikeBlock(),
|
||||||
|
model.resolveParticleSprite(slots, baker),
|
||||||
|
Sheets.translucentItemSheet()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up an {@link ItemStackRenderState.LayerRenderState} to render this model.
|
||||||
|
*
|
||||||
|
* @param layer The layer to set up.
|
||||||
|
* @see ItemModel#update(ItemStackRenderState, ItemStack, ItemModelResolver, ItemDisplayContext, ClientLevel, LivingEntity, int)
|
||||||
|
* @see TurtleUpgradeModel#renderForItem(ITurtleUpgrade, TurtleSide, DataComponentPatch, ItemStackRenderState, ItemModelResolver, ItemTransform, int)
|
||||||
|
*/
|
||||||
|
public void setupItemLayer(ItemStackRenderState.LayerRenderState layer) {
|
||||||
|
layer.setExtents(extents);
|
||||||
|
layer.setRenderType(renderType);
|
||||||
|
layer.setUsesBlockLight(useBlockLight);
|
||||||
|
layer.setParticleIcon(particleIcon);
|
||||||
|
layer.prepareQuadList().addAll(quads);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the model directly.
|
||||||
|
*
|
||||||
|
* @param transform The current pose stack transformations.
|
||||||
|
* @param buffers The buffer source to use for rendering.
|
||||||
|
* @param light The current light texture coordinate.
|
||||||
|
* @param overlay The current overlay texture coordinate.
|
||||||
|
* @see TurtleUpgradeModel#renderForLevel(ITurtleUpgrade, ITurtleAccess, TurtleSide, DataComponentPatch, PoseStack, MultiBufferSource, int, int)
|
||||||
|
*/
|
||||||
|
public void render(PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
||||||
|
render(transform, buffers, light, overlay, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the model directly.
|
||||||
|
*
|
||||||
|
* @param transform The current pose stack transformations.
|
||||||
|
* @param buffers The buffer source to use for rendering.
|
||||||
|
* @param light The current light texture coordinate.
|
||||||
|
* @param overlay The current overlay texture coordinate.
|
||||||
|
* @param tints The tints for this model.
|
||||||
|
* @see TurtleUpgradeModel#renderForLevel(ITurtleUpgrade, ITurtleAccess, TurtleSide, DataComponentPatch, PoseStack, MultiBufferSource, int, int)
|
||||||
|
*/
|
||||||
|
public void render(PoseStack transform, MultiBufferSource buffers, int light, int overlay, int @Nullable [] tints) {
|
||||||
|
var pose = transform.last();
|
||||||
|
var buffer = buffers.getBuffer(renderType);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,43 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2020 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
|
|
||||||
package dan200.computercraft.api.client;
|
|
||||||
|
|
||||||
import com.mojang.math.Transformation;
|
|
||||||
import dan200.computercraft.impl.client.ClientPlatformHelper;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A model to render, combined with a transformation matrix to apply.
|
|
||||||
*/
|
|
||||||
public sealed interface TransformedModel permits TransformedModel.Baked, TransformedModel.Item {
|
|
||||||
record Baked(BakedModel model) implements TransformedModel {
|
|
||||||
}
|
|
||||||
|
|
||||||
record Item(ItemStack stack, Transformation transformation) implements TransformedModel {
|
|
||||||
}
|
|
||||||
|
|
||||||
static TransformedModel of(BakedModel model) {
|
|
||||||
return new TransformedModel.Baked(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Look up a model in the model bakery and construct a {@link TransformedModel} with no transformation.
|
|
||||||
*
|
|
||||||
* @param location The location of the model to load.
|
|
||||||
* @return The new {@link TransformedModel} instance.
|
|
||||||
*/
|
|
||||||
static TransformedModel of(ResourceLocation location) {
|
|
||||||
var modelManager = Minecraft.getInstance().getModelManager();
|
|
||||||
return of(ClientPlatformHelper.get().getModel(modelManager, location));
|
|
||||||
}
|
|
||||||
|
|
||||||
static TransformedModel of(ItemStack item, Transformation transform) {
|
|
||||||
return new TransformedModel.Item(item, transform);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,102 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.client.turtle;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.math.Axis;
|
||||||
|
import com.mojang.math.Transformation;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
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.special.SpecialModelRenderer;
|
||||||
|
import net.minecraft.client.resources.model.ModelBaker;
|
||||||
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
final class ItemUpgradeModel<T extends ITurtleUpgrade> implements TurtleUpgradeModel<T> {
|
||||||
|
static final TurtleUpgradeModel.Unbaked<ITurtleUpgrade> UNBAKED = new Unbaked();
|
||||||
|
static final TurtleUpgradeModel<ITurtleUpgrade> INSTANCE = new ItemUpgradeModel<>();
|
||||||
|
|
||||||
|
private static final TransformedRenderer LEFT = computeRenderer(TurtleSide.LEFT);
|
||||||
|
private static final TransformedRenderer RIGHT = computeRenderer(TurtleSide.RIGHT);
|
||||||
|
|
||||||
|
private ItemUpgradeModel() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderForItem(T upgrade, TurtleSide side, DataComponentPatch data, ItemStackRenderState renderer, ItemModelResolver resolver, ItemTransform transform, int seed) {
|
||||||
|
var childState = new ItemStackRenderState();
|
||||||
|
resolver.updateForTopItem(childState, upgrade.getUpgradeItem(data), ItemDisplayContext.NONE, null, null, seed);
|
||||||
|
if (!childState.isEmpty()) {
|
||||||
|
var layer = renderer.newLayer();
|
||||||
|
layer.setTransform(transform);
|
||||||
|
layer.setupSpecialModel(getRenderer(side), childState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderForLevel(T upgrade, ITurtleAccess turtle, TurtleSide side, DataComponentPatch data, PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
||||||
|
transform.mulPose(getRenderer(side).transform().getMatrix());
|
||||||
|
transform.mulPose(Axis.YP.rotation(Mth.PI));
|
||||||
|
Minecraft.getInstance().getItemRenderer().renderStatic(
|
||||||
|
upgrade.getUpgradeItem(data), ItemDisplayContext.FIXED, light, overlay, transform, buffers, turtle.getLevel(), 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class Unbaked implements TurtleUpgradeModel.Unbaked<ITurtleUpgrade> {
|
||||||
|
@Override
|
||||||
|
public TurtleUpgradeModel<ITurtleUpgrade> bake(ModelBaker baker) {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolveDependencies(Resolver resolver) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TransformedRenderer computeRenderer(TurtleSide side) {
|
||||||
|
var pose = new Matrix4f();
|
||||||
|
pose.translate(0.5f, 0.5f, 0.5f);
|
||||||
|
pose.rotate(Axis.YN.rotationDegrees(90f));
|
||||||
|
pose.rotate(Axis.ZP.rotationDegrees(90f));
|
||||||
|
pose.translate(0.0f, 0.0f, side == TurtleSide.RIGHT ? -0.4065f : 0.4065f);
|
||||||
|
return new TransformedRenderer(new Transformation(pose));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TransformedRenderer getRenderer(TurtleSide side) {
|
||||||
|
return switch (side) {
|
||||||
|
case LEFT -> LEFT;
|
||||||
|
case RIGHT -> RIGHT;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private record TransformedRenderer(Transformation transform) implements SpecialModelRenderer<ItemStackRenderState> {
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
@Nullable ItemStackRenderState state, ItemDisplayContext itemDisplayContext, PoseStack poseStack,
|
||||||
|
MultiBufferSource multiBufferSource, int overlay, int light, boolean bl
|
||||||
|
) {
|
||||||
|
if (state == null) return;
|
||||||
|
poseStack.pushPose();
|
||||||
|
poseStack.mulPose(transform.getMatrix());
|
||||||
|
state.render(poseStack, multiBufferSource, overlay, light);
|
||||||
|
poseStack.popPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ItemStackRenderState extractArgument(ItemStack itemStack) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,19 +8,19 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|||||||
import dan200.computercraft.api.upgrades.UpgradeType;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A functional interface to register a {@link TurtleUpgradeModeller} for a class of turtle upgrades.
|
* A functional interface to register a {@link TurtleUpgradeModel} for a class of turtle upgrades.
|
||||||
* <p>
|
* <p>
|
||||||
* This interface is largely intended to be used from multi-loader code, to allow sharing registration code between
|
* This interface is largely intended to be used from multi-loader code, to allow sharing registration code between
|
||||||
* multiple loaders.
|
* multiple loaders.
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface RegisterTurtleUpgradeModeller {
|
public interface RegisterTurtleUpgradeModel {
|
||||||
/**
|
/**
|
||||||
* Register a {@link TurtleUpgradeModeller}.
|
* Register a {@link TurtleUpgradeModel}.
|
||||||
*
|
*
|
||||||
* @param type The turtle upgrade type.
|
* @param type The turtle upgrade type.
|
||||||
* @param modeller The upgrade modeller.
|
* @param mode The unbaked upgrade model.
|
||||||
* @param <T> The type of the turtle upgrade.
|
* @param <T> The type of the turtle upgrade.
|
||||||
*/
|
*/
|
||||||
<T extends ITurtleUpgrade> void register(UpgradeType<T> type, TurtleUpgradeModeller<T> modeller);
|
<T extends ITurtleUpgrade> void register(UpgradeType<T> type, TurtleUpgradeModel.Unbaked<? super T> mode);
|
||||||
}
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.client.turtle;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.client.StandaloneModel;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import net.minecraft.client.resources.model.ModelBaker;
|
||||||
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
record SidedUpgradeModel<T extends ITurtleUpgrade>(
|
||||||
|
StandaloneModel left, StandaloneModel right
|
||||||
|
) implements TurtleUpgradeModelViaStandalone<T> {
|
||||||
|
@Override
|
||||||
|
public StandaloneModel getModel(T upgrade, TurtleSide side, DataComponentPatch data) {
|
||||||
|
return switch (side) {
|
||||||
|
case LEFT -> left();
|
||||||
|
case RIGHT -> right();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
record Unbaked<T extends ITurtleUpgrade>(
|
||||||
|
ResourceLocation left, ResourceLocation right
|
||||||
|
) implements TurtleUpgradeModel.Unbaked<T> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TurtleUpgradeModel<T> bake(ModelBaker baker) {
|
||||||
|
return new SidedUpgradeModel<>(StandaloneModel.of(left(), baker), StandaloneModel.of(right(), baker));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolveDependencies(Resolver resolver) {
|
||||||
|
resolver.markDependency(left());
|
||||||
|
resolver.markDependency(right());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,107 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.client.turtle;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
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.core.component.DataComponentPatch;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The model for a {@link ITurtleUpgrade}.
|
||||||
|
* <p>
|
||||||
|
* Use {@code dan200.computercraft.api.client.FabricComputerCraftAPIClient#registerTurtleUpgradeModeller} to register a
|
||||||
|
* modeller on Fabric and {@code dan200.computercraft.api.client.turtle.RegisterTurtleModellersEvent} to register one
|
||||||
|
* on Forge.
|
||||||
|
*
|
||||||
|
* <h2>Example</h2>
|
||||||
|
* <h3>Fabric</h3>
|
||||||
|
* {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_model}
|
||||||
|
*
|
||||||
|
* <h3>Forge</h3>
|
||||||
|
* {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_model}
|
||||||
|
*
|
||||||
|
* @param <T> The type of turtle upgrade this modeller applies to.
|
||||||
|
* @see RegisterTurtleUpgradeModel For multi-loader registration support.
|
||||||
|
*/
|
||||||
|
public interface TurtleUpgradeModel<T extends ITurtleUpgrade> {
|
||||||
|
/**
|
||||||
|
* Render this upgrade to an {@link ItemStackRenderState}. This is used for rendering the item form of the upgrade.
|
||||||
|
*
|
||||||
|
* @param upgrade The upgrade being rendered.
|
||||||
|
* @param side Which side of the turtle (left or right) the upgrade resides on.
|
||||||
|
* @param data Upgrade data instance for current turtle side.
|
||||||
|
* @param renderer The render state to draw to.
|
||||||
|
* @param resolver The model resolver.
|
||||||
|
* @param transform The root model's transformation.
|
||||||
|
* @param seed The current model seed.
|
||||||
|
* @see ItemModel#update(ItemStackRenderState, ItemStack, ItemModelResolver, ItemDisplayContext, ClientLevel, LivingEntity, int)
|
||||||
|
*/
|
||||||
|
void renderForItem(T upgrade, TurtleSide side, DataComponentPatch data, ItemStackRenderState renderer, ItemModelResolver resolver, ItemTransform transform, int seed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render this upgrade to a {@link MultiBufferSource}. This is used for rendering the block-entity form of the
|
||||||
|
* upgrade.
|
||||||
|
*
|
||||||
|
* @param upgrade The upgrade being rendered.
|
||||||
|
* @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models.
|
||||||
|
* @param side Which side of the turtle (left or right) the upgrade resides on.
|
||||||
|
* @param data Upgrade data instance for current turtle side.
|
||||||
|
* @param transform The current pose stack.
|
||||||
|
* @param buffers The buffers to render to.
|
||||||
|
* @param light The lightmap coordinate.
|
||||||
|
* @param overlay The overlay coordinate.
|
||||||
|
*/
|
||||||
|
void renderForLevel(T upgrade, ITurtleAccess turtle, TurtleSide side, DataComponentPatch data, PoseStack transform, MultiBufferSource buffers, int light, int overlay);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An unbaked turtle model. Much like other unbaked models (e.g. {@link ItemModel.Unbaked}), this should resolve
|
||||||
|
* any dependencies and returned the fully-resolved model.
|
||||||
|
*
|
||||||
|
* @param <T> The type of turtle upgrade for this model.
|
||||||
|
*/
|
||||||
|
interface Unbaked<T extends ITurtleUpgrade> extends ResolvableModel {
|
||||||
|
TurtleUpgradeModel<T> bake(ModelBaker baker);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A basic {@link TurtleUpgradeModel} which renders using 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}
|
||||||
|
* model type. It will not appear correct for 3D models with additional depth, such as blocks.
|
||||||
|
*
|
||||||
|
* @param <T> The type of the turtle upgrade.
|
||||||
|
* @return The constructed modeller.
|
||||||
|
*/
|
||||||
|
static <T extends ITurtleUpgrade> TurtleUpgradeModel.Unbaked<? super T> flatItem() {
|
||||||
|
return ItemUpgradeModel.UNBAKED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a {@link TurtleUpgradeModel} which has a single model for the left and right side.
|
||||||
|
*
|
||||||
|
* @param left The model to use on the left.
|
||||||
|
* @param right The model to use on the right.
|
||||||
|
* @param <T> The type of the turtle upgrade.
|
||||||
|
* @return The constructed modeller.
|
||||||
|
*/
|
||||||
|
static <T extends ITurtleUpgrade> TurtleUpgradeModel.Unbaked<T> sided(ResourceLocation left, ResourceLocation right) {
|
||||||
|
return new SidedUpgradeModel.Unbaked<>(left, right);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.client.turtle;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import dan200.computercraft.api.client.StandaloneModel;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
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.core.component.DataComponentPatch;
|
||||||
|
|
||||||
|
public interface TurtleUpgradeModelViaStandalone<T extends ITurtleUpgrade> extends TurtleUpgradeModel<T> {
|
||||||
|
StandaloneModel getModel(T upgrade, TurtleSide side, DataComponentPatch data);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void renderForItem(T upgrade, TurtleSide side, DataComponentPatch data, ItemStackRenderState renderer, ItemModelResolver resolver, ItemTransform transform, int seed) {
|
||||||
|
var layer = renderer.newLayer();
|
||||||
|
layer.setTransform(transform);
|
||||||
|
getModel(upgrade, side, data).setupItemLayer(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void renderForLevel(T upgrade, ITurtleAccess turtle, TurtleSide side, DataComponentPatch data, PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
||||||
|
getModel(upgrade, side, data).render(transform, buffers, light, overlay);
|
||||||
|
}
|
||||||
|
}
|
@ -1,99 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.api.client.turtle;
|
|
||||||
|
|
||||||
import dan200.computercraft.api.client.TransformedModel;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
|
||||||
import net.minecraft.client.resources.model.UnbakedModel;
|
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides models for a {@link ITurtleUpgrade}.
|
|
||||||
* <p>
|
|
||||||
* Use {@code dan200.computercraft.api.client.FabricComputerCraftAPIClient#registerTurtleUpgradeModeller} to register a
|
|
||||||
* modeller on Fabric and {@code dan200.computercraft.api.client.turtle.RegisterTurtleModellersEvent} to register one
|
|
||||||
* on Forge.
|
|
||||||
*
|
|
||||||
* <h2>Example</h2>
|
|
||||||
* <h3>Fabric</h3>
|
|
||||||
* {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_modellers}
|
|
||||||
*
|
|
||||||
* <h3>Forge</h3>
|
|
||||||
* {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_modellers}
|
|
||||||
*
|
|
||||||
* @param <T> The type of turtle upgrade this modeller applies to.
|
|
||||||
* @see RegisterTurtleUpgradeModeller For multi-loader registration support.
|
|
||||||
*/
|
|
||||||
public interface TurtleUpgradeModeller<T extends ITurtleUpgrade> {
|
|
||||||
/**
|
|
||||||
* Obtain the model to be used when rendering a turtle peripheral.
|
|
||||||
* <p>
|
|
||||||
* When the current turtle is {@literal null}, this function should be constant for a given upgrade, side and data.
|
|
||||||
*
|
|
||||||
* @param upgrade The upgrade that you're getting the model for.
|
|
||||||
* @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models.
|
|
||||||
* @param side Which side of the turtle (left or right) the upgrade resides on.
|
|
||||||
* @param data Upgrade data instance for current turtle side.
|
|
||||||
* @return The model that you wish to be used to render your upgrade.
|
|
||||||
*/
|
|
||||||
TransformedModel getModel(T upgrade, @Nullable ITurtleAccess turtle, TurtleSide side, DataComponentPatch data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the models that this turtle modeller depends on.
|
|
||||||
* <p>
|
|
||||||
* Models included in this stream will be loaded and baked alongside item and block models, and so may be referenced
|
|
||||||
* by {@link TransformedModel#of(ResourceLocation)}. You do not need to override this method if you will load models
|
|
||||||
* by other means.
|
|
||||||
*
|
|
||||||
* @return A list of models that this modeller depends on.
|
|
||||||
* @see UnbakedModel#resolveDependencies(UnbakedModel.Resolver)
|
|
||||||
*/
|
|
||||||
default Stream<ResourceLocation> getDependencies() {
|
|
||||||
return Stream.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A basic {@link TurtleUpgradeModeller} which renders using 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}
|
|
||||||
* model type. It will not appear correct for 3D models with additional depth, such as blocks.
|
|
||||||
*
|
|
||||||
* @param <T> The type of the turtle upgrade.
|
|
||||||
* @return The constructed modeller.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
static <T extends ITurtleUpgrade> TurtleUpgradeModeller<T> flatItem() {
|
|
||||||
return (TurtleUpgradeModeller<T>) TurtleUpgradeModellers.UPGRADE_ITEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a {@link TurtleUpgradeModeller} which has a single model for the left and right side.
|
|
||||||
*
|
|
||||||
* @param left The model to use on the left.
|
|
||||||
* @param right The model to use on the right.
|
|
||||||
* @param <T> The type of the turtle upgrade.
|
|
||||||
* @return The constructed modeller.
|
|
||||||
*/
|
|
||||||
static <T extends ITurtleUpgrade> TurtleUpgradeModeller<T> sided(ResourceLocation left, ResourceLocation right) {
|
|
||||||
return new TurtleUpgradeModeller<>() {
|
|
||||||
@Override
|
|
||||||
public TransformedModel getModel(T upgrade, @Nullable ITurtleAccess turtle, TurtleSide side, DataComponentPatch data) {
|
|
||||||
return TransformedModel.of(side == TurtleSide.LEFT ? left : right);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<ResourceLocation> getDependencies() {
|
|
||||||
return Stream.of(left, right);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.api.client.turtle;
|
|
||||||
|
|
||||||
import com.mojang.math.Axis;
|
|
||||||
import com.mojang.math.Transformation;
|
|
||||||
import dan200.computercraft.api.client.TransformedModel;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
|
||||||
import org.joml.Matrix4f;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
|
||||||
|
|
||||||
final class TurtleUpgradeModellers {
|
|
||||||
private static final Transformation leftTransform = getMatrixFor(TurtleSide.LEFT);
|
|
||||||
private static final Transformation rightTransform = getMatrixFor(TurtleSide.RIGHT);
|
|
||||||
|
|
||||||
private static Transformation getMatrixFor(TurtleSide side) {
|
|
||||||
var pose = new Matrix4f();
|
|
||||||
pose.translate(0.5f, 0.5f, 0.5f);
|
|
||||||
pose.rotate(Axis.YN.rotationDegrees(90f));
|
|
||||||
pose.rotate(Axis.ZP.rotationDegrees(90f));
|
|
||||||
pose.translate(0.0f, 0.0f, side == TurtleSide.RIGHT ? -0.4065f : 0.4065f);
|
|
||||||
return new Transformation(pose);
|
|
||||||
}
|
|
||||||
|
|
||||||
static final TurtleUpgradeModeller<ITurtleUpgrade> UPGRADE_ITEM = new UpgradeItemModeller();
|
|
||||||
|
|
||||||
private static final class UpgradeItemModeller implements TurtleUpgradeModeller<ITurtleUpgrade> {
|
|
||||||
@Override
|
|
||||||
public TransformedModel getModel(ITurtleUpgrade upgrade, @Nullable ITurtleAccess turtle, TurtleSide side, DataComponentPatch data) {
|
|
||||||
return TransformedModel.of(upgrade.getUpgradeItem(data), side == TurtleSide.LEFT ? leftTransform : rightTransform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.impl.client;
|
|
||||||
|
|
||||||
import dan200.computercraft.impl.Services;
|
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
|
||||||
import net.minecraft.client.resources.model.ModelManager;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
|
||||||
|
|
||||||
@ApiStatus.Internal
|
|
||||||
public interface ClientPlatformHelper {
|
|
||||||
/**
|
|
||||||
* Get a model from a resource.
|
|
||||||
*
|
|
||||||
* @param manager The model manager.
|
|
||||||
* @param resourceLocation The model resourceLocation.
|
|
||||||
* @return The baked model.
|
|
||||||
*/
|
|
||||||
BakedModel getModel(ModelManager manager, ResourceLocation resourceLocation);
|
|
||||||
|
|
||||||
static ClientPlatformHelper get() {
|
|
||||||
var instance = Instance.INSTANCE;
|
|
||||||
return instance == null ? Services.raise(ClientPlatformHelper.class, Instance.ERROR) : instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
final class Instance {
|
|
||||||
static final @Nullable ClientPlatformHelper INSTANCE;
|
|
||||||
static final @Nullable Throwable ERROR;
|
|
||||||
|
|
||||||
static {
|
|
||||||
var helper = Services.tryLoad(ClientPlatformHelper.class);
|
|
||||||
INSTANCE = helper.instance();
|
|
||||||
ERROR = helper.error();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Instance() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -53,13 +53,13 @@ import java.util.function.Function;
|
|||||||
*
|
*
|
||||||
* <h3>Rendering the upgrade</h3>
|
* <h3>Rendering the upgrade</h3>
|
||||||
* Next, we need to register a model for our upgrade. This is done by registering a
|
* Next, we need to register a model for our upgrade. This is done by registering a
|
||||||
* {@link dan200.computercraft.api.client.turtle.TurtleUpgradeModeller} for your upgrade type.
|
* {@link dan200.computercraft.api.client.turtle.TurtleUpgradeModel} for your upgrade type.
|
||||||
*
|
*
|
||||||
* <h4>Fabric</h4>
|
* <h4>Fabric</h4>
|
||||||
* {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_modellers}
|
* {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_model}
|
||||||
*
|
*
|
||||||
* <h4>Forge</h4>
|
* <h4>Forge</h4>
|
||||||
* {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_modellers}
|
* {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_model}
|
||||||
*
|
*
|
||||||
* <h3 id="datagen">Registering the upgrade itself</h3>
|
* <h3 id="datagen">Registering the upgrade itself</h3>
|
||||||
* Upgrades themselves are loaded from datapacks when a level is loaded. In order to register our new upgrade, we must
|
* Upgrades themselves are loaded from datapacks when a level is loaded. In order to register our new upgrade, we must
|
||||||
|
@ -39,7 +39,6 @@ import net.minecraft.world.item.ItemStack;
|
|||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.HitResult;
|
import net.minecraft.world.phys.HitResult;
|
||||||
import org.jspecify.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@ -137,20 +136,20 @@ public final class ClientHooks {
|
|||||||
if (upgrade != null) out.accept(String.format("Upgrade[%s]: %s", side, upgrade.holder().key().location()));
|
if (upgrade != null) out.accept(String.format("Upgrade[%s]: %s", side, upgrade.holder().key().location()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @Nullable BlockState getBlockBreakingState(BlockState state, BlockPos pos) {
|
public static BlockState getBlockBreakingState(BlockState state, BlockPos pos) {
|
||||||
// Only apply to cables which have both a cable and modem
|
// Only apply to cables which have both a cable and modem
|
||||||
if (state.getBlock() != ModRegistry.Blocks.CABLE.get()
|
if (state.getBlock() != ModRegistry.Blocks.CABLE.get()
|
||||||
|| !state.getValue(CableBlock.CABLE)
|
|| !state.getValue(CableBlock.CABLE)
|
||||||
|| state.getValue(CableBlock.MODEM) == CableModemVariant.None
|
|| state.getValue(CableBlock.MODEM) == CableModemVariant.None
|
||||||
) {
|
) {
|
||||||
return null;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
var hit = Minecraft.getInstance().hitResult;
|
var hit = Minecraft.getInstance().hitResult;
|
||||||
if (hit == null || hit.getType() != HitResult.Type.BLOCK) return null;
|
if (hit == null || hit.getType() != HitResult.Type.BLOCK) return state;
|
||||||
var hitPos = ((BlockHitResult) hit).getBlockPos();
|
var hitPos = ((BlockHitResult) hit).getBlockPos();
|
||||||
|
|
||||||
if (!hitPos.equals(pos)) return null;
|
if (!hitPos.equals(pos)) return state;
|
||||||
|
|
||||||
return WorldUtil.isVecInside(CableShapes.getModemShape(state), hit.getLocation().subtract(pos.getX(), pos.getY(), pos.getZ()))
|
return WorldUtil.isVecInside(CableShapes.getModemShape(state), hit.getLocation().subtract(pos.getX(), pos.getY(), pos.getZ()))
|
||||||
? state.getBlock().defaultBlockState().setValue(CableBlock.MODEM, state.getValue(CableBlock.MODEM))
|
? state.getBlock().defaultBlockState().setValue(CableBlock.MODEM, state.getValue(CableBlock.MODEM))
|
||||||
|
@ -6,19 +6,21 @@ package dan200.computercraft.client;
|
|||||||
|
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.client.turtle.RegisterTurtleUpgradeModeller;
|
import dan200.computercraft.api.client.StandaloneModel;
|
||||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
import dan200.computercraft.api.client.turtle.RegisterTurtleUpgradeModel;
|
||||||
|
import dan200.computercraft.api.client.turtle.TurtleUpgradeModel;
|
||||||
import dan200.computercraft.client.gui.*;
|
import dan200.computercraft.client.gui.*;
|
||||||
import dan200.computercraft.client.item.colour.PocketComputerLight;
|
import dan200.computercraft.client.item.colour.PocketComputerLight;
|
||||||
import dan200.computercraft.client.item.model.TurtleOverlayModel;
|
import dan200.computercraft.client.item.model.TurtleOverlayModel;
|
||||||
import dan200.computercraft.client.item.model.TurtleUpgradeModel;
|
|
||||||
import dan200.computercraft.client.item.properties.PocketComputerStateProperty;
|
import dan200.computercraft.client.item.properties.PocketComputerStateProperty;
|
||||||
import dan200.computercraft.client.item.properties.TurtleShowElfOverlay;
|
import dan200.computercraft.client.item.properties.TurtleShowElfOverlay;
|
||||||
|
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||||
|
import dan200.computercraft.client.platform.ModelKey;
|
||||||
import dan200.computercraft.client.render.CustomLecternRenderer;
|
import dan200.computercraft.client.render.CustomLecternRenderer;
|
||||||
import dan200.computercraft.client.render.TurtleBlockEntityRenderer;
|
import dan200.computercraft.client.render.TurtleBlockEntityRenderer;
|
||||||
import dan200.computercraft.client.render.monitor.MonitorBlockEntityRenderer;
|
import dan200.computercraft.client.render.monitor.MonitorBlockEntityRenderer;
|
||||||
import dan200.computercraft.client.turtle.TurtleModemModeller;
|
import dan200.computercraft.client.turtle.TurtleModemModel;
|
||||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
import dan200.computercraft.client.turtle.TurtleUpgradeModels;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||||
@ -32,14 +34,18 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
|
|||||||
import net.minecraft.client.renderer.item.ItemModel;
|
import net.minecraft.client.renderer.item.ItemModel;
|
||||||
import net.minecraft.client.renderer.item.properties.conditional.ConditionalItemModelProperty;
|
import net.minecraft.client.renderer.item.properties.conditional.ConditionalItemModelProperty;
|
||||||
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperty;
|
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperty;
|
||||||
|
import net.minecraft.client.resources.model.MissingBlockModel;
|
||||||
|
import net.minecraft.client.resources.model.ModelManager;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.packs.resources.PreparableReloadListener;
|
import net.minecraft.server.packs.resources.PreparableReloadListener;
|
||||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
import net.minecraft.world.inventory.MenuType;
|
import net.minecraft.world.inventory.MenuType;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers client-side objects, such as {@link BlockEntityRendererProvider}s and
|
* Registers client-side objects, such as {@link BlockEntityRendererProvider}s and
|
||||||
@ -53,6 +59,19 @@ public final class ClientRegistry {
|
|||||||
private ClientRegistry() {
|
private ClientRegistry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Map<ResourceLocation, ModelKey<StandaloneModel>> models = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public static ModelKey<StandaloneModel> getModel(ResourceLocation model) {
|
||||||
|
return models.computeIfAbsent(model, m -> ClientPlatformHelper.get().createModelKey(m, m::toString));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StandaloneModel getModel(ModelManager manager, ResourceLocation modelId) {
|
||||||
|
var model = getModel(modelId).get(manager);
|
||||||
|
if (model != null) return model;
|
||||||
|
|
||||||
|
return Objects.requireNonNull(getModel(MissingBlockModel.LOCATION).get(manager));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register any client-side objects which don't have to be done on the main thread.
|
* Register any client-side objects which don't have to be done on the main thread.
|
||||||
*/
|
*/
|
||||||
@ -78,17 +97,17 @@ public final class ClientRegistry {
|
|||||||
<M extends AbstractContainerMenu, U extends Screen & MenuAccess<M>> void register(MenuType<? extends M> type, MenuScreens.ScreenConstructor<M, U> factory);
|
<M extends AbstractContainerMenu, U extends Screen & MenuAccess<M>> void register(MenuType<? extends M> type, MenuScreens.ScreenConstructor<M, U> factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerTurtleModellers(RegisterTurtleUpgradeModeller register) {
|
public static void registerTurtleModels(RegisterTurtleUpgradeModel register) {
|
||||||
register.register(ModRegistry.TurtleUpgradeTypes.SPEAKER.get(), TurtleUpgradeModeller.sided(
|
register.register(ModRegistry.TurtleUpgradeTypes.SPEAKER.get(), TurtleUpgradeModel.sided(
|
||||||
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_left"),
|
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_left"),
|
||||||
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_right")
|
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_right")
|
||||||
));
|
));
|
||||||
register.register(ModRegistry.TurtleUpgradeTypes.WORKBENCH.get(), TurtleUpgradeModeller.sided(
|
register.register(ModRegistry.TurtleUpgradeTypes.WORKBENCH.get(), TurtleUpgradeModel.sided(
|
||||||
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_left"),
|
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_left"),
|
||||||
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_right")
|
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_right")
|
||||||
));
|
));
|
||||||
register.register(ModRegistry.TurtleUpgradeTypes.WIRELESS_MODEM.get(), new TurtleModemModeller());
|
register.register(ModRegistry.TurtleUpgradeTypes.WIRELESS_MODEM.get(), TurtleModemModel.UNBAKED);
|
||||||
register.register(ModRegistry.TurtleUpgradeTypes.TOOL.get(), TurtleUpgradeModeller.flatItem());
|
register.register(ModRegistry.TurtleUpgradeTypes.TOOL.get(), TurtleUpgradeModel.flatItem());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerReloadListeners(BiConsumer<ResourceLocation, PreparableReloadListener> register, Minecraft minecraft) {
|
public static void registerReloadListeners(BiConsumer<ResourceLocation, PreparableReloadListener> register, Minecraft minecraft) {
|
||||||
@ -100,17 +119,22 @@ public final class ClientRegistry {
|
|||||||
TurtleBlockEntityRenderer.NORMAL_TURTLE_MODEL,
|
TurtleBlockEntityRenderer.NORMAL_TURTLE_MODEL,
|
||||||
TurtleBlockEntityRenderer.ADVANCED_TURTLE_MODEL,
|
TurtleBlockEntityRenderer.ADVANCED_TURTLE_MODEL,
|
||||||
TurtleBlockEntityRenderer.COLOUR_TURTLE_MODEL,
|
TurtleBlockEntityRenderer.COLOUR_TURTLE_MODEL,
|
||||||
|
MissingBlockModel.LOCATION,
|
||||||
};
|
};
|
||||||
|
|
||||||
public static void registerExtraModels(Consumer<ResourceLocation> register, Collection<ResourceLocation> extraModels) {
|
public static void registerExtraModels(
|
||||||
for (var model : EXTRA_MODELS) register.accept(model);
|
BiConsumer<ModelKey<StandaloneModel>, ResourceLocation> registerBasic,
|
||||||
extraModels.forEach(register);
|
BiConsumer<ModelKey<? extends TurtleUpgradeModel<?>>, TurtleUpgradeModel.Unbaked<?>> registerTurtle,
|
||||||
TurtleUpgradeModellers.getDependencies().forEach(register);
|
Collection<ResourceLocation> extraModels
|
||||||
|
) {
|
||||||
|
for (var model : EXTRA_MODELS) registerBasic.accept(getModel(model), model);
|
||||||
|
for (var model : extraModels) registerBasic.accept(getModel(model), model);
|
||||||
|
TurtleUpgradeModels.bake(registerTurtle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerItemModels(BiConsumer<ResourceLocation, MapCodec<? extends ItemModel.Unbaked>> register) {
|
public static void registerItemModels(BiConsumer<ResourceLocation, MapCodec<? extends ItemModel.Unbaked>> register) {
|
||||||
register.accept(TurtleOverlayModel.ID, TurtleOverlayModel.CODEC);
|
register.accept(TurtleOverlayModel.ID, TurtleOverlayModel.CODEC);
|
||||||
register.accept(TurtleUpgradeModel.ID, TurtleUpgradeModel.CODEC);
|
register.accept(dan200.computercraft.client.item.model.TurtleUpgradeModel.ID, dan200.computercraft.client.item.model.TurtleUpgradeModel.CODEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerItemColours(BiConsumer<ResourceLocation, MapCodec<? extends ItemTintSource>> register) {
|
public static void registerItemColours(BiConsumer<ResourceLocation, MapCodec<? extends ItemTintSource>> register) {
|
||||||
|
@ -72,8 +72,8 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
|||||||
public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
|
public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
|
||||||
var direction = scrollHandler.onMouseScroll(scrollX, scrollY);
|
var direction = scrollHandler.onMouseScroll(scrollX, scrollY);
|
||||||
var inventory = Objects.requireNonNull(minecraft().player).getInventory();
|
var inventory = Objects.requireNonNull(minecraft().player).getInventory();
|
||||||
inventory.setSelectedHotbarSlot(ScrollWheelHandler.getNextScrollWheelSelection(
|
inventory.setSelectedSlot(ScrollWheelHandler.getNextScrollWheelSelection(
|
||||||
direction.y == 0 ? -direction.x : direction.y, inventory.selected, Inventory.getSelectionSize()
|
direction.y == 0 ? -direction.x : direction.y, inventory.getSelectedSlot(), Inventory.getSelectionSize()
|
||||||
));
|
));
|
||||||
|
|
||||||
return super.mouseScrolled(mouseX, mouseY, scrollX, scrollY);
|
return super.mouseScrolled(mouseX, mouseY, scrollX, scrollY);
|
||||||
|
@ -38,7 +38,7 @@ public class IrisShaderMod implements ShaderMod.Provider {
|
|||||||
: super.getQuadEmitter(vertexCount, makeBuffer);
|
: super.getQuadEmitter(vertexCount, makeBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class IrisQuadEmitter implements DirectFixedWidthFontRenderer.QuadEmitter {
|
private static final class IrisQuadEmitter extends DirectFixedWidthFontRenderer.QuadEmitter {
|
||||||
private final IrisTextVertexSink sink;
|
private final IrisTextVertexSink sink;
|
||||||
private @Nullable ByteBuffer buffer;
|
private @Nullable ByteBuffer buffer;
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package dan200.computercraft.client.integration;
|
package dan200.computercraft.client.integration;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.ByteBufferBuilder;
|
import com.mojang.blaze3d.vertex.ByteBufferBuilder;
|
||||||
import com.mojang.blaze3d.vertex.VertexBuffer;
|
|
||||||
import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer;
|
import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -29,7 +28,7 @@ public class ShaderMod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an appropriate quad emitter for use with {@link VertexBuffer} and {@link DirectFixedWidthFontRenderer} .
|
* Get an appropriate quad emitter for use with a vertex buffer and {@link DirectFixedWidthFontRenderer} .
|
||||||
*
|
*
|
||||||
* @param vertexCount The number of vertices.
|
* @param vertexCount The number of vertices.
|
||||||
* @param buffer A function to allocate a temporary buffer.
|
* @param buffer A function to allocate a temporary buffer.
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.client.item.model;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.Sheets;
|
|
||||||
import net.minecraft.client.renderer.block.model.ItemTransforms;
|
|
||||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
|
||||||
import net.minecraft.client.resources.model.DelegateBakedModel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link BakedModel} that wraps another model, but providing different {@link ItemTransforms}.
|
|
||||||
*/
|
|
||||||
class BakedModelWithTransform extends DelegateBakedModel {
|
|
||||||
private final ItemTransforms transforms;
|
|
||||||
|
|
||||||
BakedModelWithTransform(BakedModel bakedModel, ItemTransforms transforms) {
|
|
||||||
super(bakedModel);
|
|
||||||
this.transforms = transforms;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addLayer(ItemStackRenderState state, BakedModel model, ItemTransforms transforms) {
|
|
||||||
state.newLayer().setupBlockModel(new BakedModelWithTransform(model, transforms), Sheets.translucentItemSheet());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemTransforms getTransforms() {
|
|
||||||
return transforms;
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,7 +7,7 @@ package dan200.computercraft.client.item.model;
|
|||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
import dan200.computercraft.client.ClientRegistry;
|
||||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
@ -39,8 +39,9 @@ public record TurtleOverlayModel(ItemTransforms transforms) implements ItemModel
|
|||||||
var overlay = TurtleItem.getOverlay(stack);
|
var overlay = TurtleItem.getOverlay(stack);
|
||||||
if (overlay == null) return;
|
if (overlay == null) return;
|
||||||
|
|
||||||
var model = ClientPlatformHelper.get().getModel(Minecraft.getInstance().getModelManager(), overlay.model());
|
var layer = state.newLayer();
|
||||||
BakedModelWithTransform.addLayer(state, model, transforms());
|
ClientRegistry.getModel(Minecraft.getInstance().getModelManager(), overlay.model()).setupItemLayer(layer);
|
||||||
|
layer.setTransform(transforms().getTransform(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
public record Unbaked(ResourceLocation base) implements ItemModel.Unbaked {
|
public record Unbaked(ResourceLocation base) implements ItemModel.Unbaked {
|
||||||
@ -51,7 +52,7 @@ public record TurtleOverlayModel(ItemTransforms transforms) implements ItemModel
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemModel bake(BakingContext bakingContext) {
|
public ItemModel bake(BakingContext bakingContext) {
|
||||||
return new TurtleOverlayModel(bakingContext.bake(base).getTransforms());
|
return new TurtleOverlayModel(bakingContext.blockModelBaker().getModel(base).getTopTransforms());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -4,23 +4,17 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.item.model;
|
package dan200.computercraft.client.item.model;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
import com.mojang.math.Transformation;
|
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.client.TransformedModel;
|
|
||||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
import dan200.computercraft.client.turtle.TurtleUpgradeModels;
|
||||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.block.model.ItemTransforms;
|
||||||
import net.minecraft.client.renderer.item.ItemModel;
|
import net.minecraft.client.renderer.item.ItemModel;
|
||||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||||
import net.minecraft.client.renderer.special.SpecialModelRenderer;
|
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.item.ItemDisplayContext;
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
@ -28,12 +22,12 @@ import net.minecraft.world.item.ItemStack;
|
|||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link ItemModel} that renders a turtle upgrade, using its {@link TurtleUpgradeModeller}.
|
* 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 side The side the upgrade resides on.
|
||||||
* @param base The base model. Only used to provide item transforms.
|
* @param base The base model. Only used to provide item transforms.
|
||||||
*/
|
*/
|
||||||
public record TurtleUpgradeModel(TurtleSide side, BakedModel base) implements ItemModel {
|
public record TurtleUpgradeModel(TurtleSide side, ItemTransforms base) implements ItemModel {
|
||||||
public static final ResourceLocation ID = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "turtle/upgrade");
|
public static final ResourceLocation ID = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "turtle/upgrade");
|
||||||
public static final MapCodec<Unbaked> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
public static final MapCodec<Unbaked> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||||
TurtleSide.CODEC.fieldOf("side").forGetter(Unbaked::side),
|
TurtleSide.CODEC.fieldOf("side").forGetter(Unbaked::side),
|
||||||
@ -41,21 +35,11 @@ public record TurtleUpgradeModel(TurtleSide side, BakedModel base) implements It
|
|||||||
).apply(instance, Unbaked::new));
|
).apply(instance, Unbaked::new));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(ItemStackRenderState state, ItemStack stack, ItemModelResolver resolver, ItemDisplayContext context, @Nullable ClientLevel level, @Nullable LivingEntity holder, int light) {
|
public void update(ItemStackRenderState state, ItemStack stack, ItemModelResolver resolver, ItemDisplayContext context, @Nullable ClientLevel level, @Nullable LivingEntity holder, int seed) {
|
||||||
var upgrade = TurtleItem.getUpgradeWithData(stack, side);
|
var upgrade = TurtleItem.getUpgradeWithData(stack, side);
|
||||||
if (upgrade == null) return;
|
if (upgrade == null) return;
|
||||||
|
|
||||||
switch (TurtleUpgradeModellers.getModel(upgrade.upgrade(), upgrade.data(), side)) {
|
TurtleUpgradeModels.getModeller(upgrade.upgrade()).renderForItem(upgrade.upgrade(), side, upgrade.data(), state, resolver, base.getTransform(context), seed);
|
||||||
case TransformedModel.Item model -> {
|
|
||||||
var childState = new ItemStackRenderState();
|
|
||||||
resolver.updateForTopItem(childState, model.stack(), ItemDisplayContext.NONE, false, level, null, 0);
|
|
||||||
if (!childState.isEmpty()) {
|
|
||||||
state.newLayer().setupSpecialModel(new TransformedRenderer(childState, model.transformation()), null, base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case TransformedModel.Baked baked ->
|
|
||||||
BakedModelWithTransform.addLayer(state, baked.model(), base.getTransforms());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public record Unbaked(TurtleSide side, ResourceLocation base) implements ItemModel.Unbaked {
|
public record Unbaked(TurtleSide side, ResourceLocation base) implements ItemModel.Unbaked {
|
||||||
@ -66,29 +50,12 @@ public record TurtleUpgradeModel(TurtleSide side, BakedModel base) implements It
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemModel bake(BakingContext bakingContext) {
|
public ItemModel bake(BakingContext bakingContext) {
|
||||||
return new TurtleUpgradeModel(side, bakingContext.bake(base));
|
return new TurtleUpgradeModel(side, bakingContext.blockModelBaker().getModel(base).getTopTransforms());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resolveDependencies(Resolver resolver) {
|
public void resolveDependencies(Resolver resolver) {
|
||||||
resolver.resolve(base);
|
resolver.markDependency(base);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private record TransformedRenderer(
|
|
||||||
ItemStackRenderState state, Transformation transform
|
|
||||||
) implements SpecialModelRenderer<Void> {
|
|
||||||
@Override
|
|
||||||
public void render(@Nullable Void object, ItemDisplayContext itemDisplayContext, PoseStack poseStack, MultiBufferSource multiBufferSource, int overlay, int light, boolean bl) {
|
|
||||||
poseStack.pushPose();
|
|
||||||
poseStack.mulPose(transform.getMatrix());
|
|
||||||
state.render(poseStack, multiBufferSource, overlay, light);
|
|
||||||
poseStack.popPose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable Void extractArgument(ItemStack itemStack) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.item.properties;
|
package dan200.computercraft.client.item.properties;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.client.pocket.ClientPocketComputers;
|
import dan200.computercraft.client.pocket.ClientPocketComputers;
|
||||||
@ -38,6 +39,11 @@ public final class PocketComputerStateProperty implements SelectItemModelPropert
|
|||||||
return computer == null ? ComputerState.OFF : computer.getState();
|
return computer == null ? ComputerState.OFF : computer.getState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Codec<ComputerState> valueCodec() {
|
||||||
|
return ComputerState.CODEC;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type<? extends SelectItemModelProperty<ComputerState>, ComputerState> type() {
|
public Type<? extends SelectItemModelProperty<ComputerState>, ComputerState> type() {
|
||||||
return TYPE;
|
return TYPE;
|
||||||
|
@ -4,25 +4,40 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.platform;
|
package dan200.computercraft.client.platform;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import dan200.computercraft.impl.Services;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.resources.model.ModelDebugName;
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
public interface ClientPlatformHelper extends dan200.computercraft.impl.client.ClientPlatformHelper {
|
public interface ClientPlatformHelper {
|
||||||
static ClientPlatformHelper get() {
|
static ClientPlatformHelper get() {
|
||||||
return (ClientPlatformHelper) dan200.computercraft.impl.client.ClientPlatformHelper.get();
|
var instance = Instance.INSTANCE;
|
||||||
|
return instance == null ? Services.raise(ClientPlatformHelper.class, Instance.ERROR) : instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render a {@link BakedModel}, using any loader-specific hooks.
|
* Create a new unique {@link ModelKey}.
|
||||||
*
|
*
|
||||||
* @param transform The current matrix transformation to apply.
|
* @param id An identifier for this model key.
|
||||||
* @param buffers The current pool of render buffers.
|
* @param name The debug name for this model key.
|
||||||
* @param model The model to draw.
|
* @param <T> The type of baked model.
|
||||||
* @param lightmapCoord The current packed lightmap coordinate.
|
* @return The newly created model key.
|
||||||
* @param overlayLight The current overlay light.
|
|
||||||
* @param tints Block colour tints to apply to the model.
|
|
||||||
*/
|
*/
|
||||||
void renderBakedModel(PoseStack transform, MultiBufferSource buffers, BakedModel model, int lightmapCoord, int overlayLight, int @Nullable [] tints);
|
@Contract("_, _ -> new")
|
||||||
|
<T> ModelKey<T> createModelKey(ResourceLocation id, ModelDebugName name);
|
||||||
|
|
||||||
|
final class Instance {
|
||||||
|
static final @Nullable ClientPlatformHelper INSTANCE;
|
||||||
|
static final @Nullable Throwable ERROR;
|
||||||
|
|
||||||
|
static {
|
||||||
|
var helper = Services.tryLoad(ClientPlatformHelper.class);
|
||||||
|
INSTANCE = helper.instance();
|
||||||
|
ERROR = helper.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Instance() {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.client.platform;
|
||||||
|
|
||||||
|
import net.minecraft.client.resources.model.ModelManager;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A key used to identify extra/standalone models.
|
||||||
|
*
|
||||||
|
* @param <T> The type of baked model.
|
||||||
|
*/
|
||||||
|
public interface ModelKey<T> {
|
||||||
|
/**
|
||||||
|
* Lookup this model key in the model manager.
|
||||||
|
*
|
||||||
|
* @param manager The model manager.
|
||||||
|
* @return The loaded model, or {@code null} if not available.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
T get(ModelManager manager);
|
||||||
|
}
|
@ -19,7 +19,6 @@ import dan200.computercraft.shared.media.items.PrintoutItem;
|
|||||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
|
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||||
import net.minecraft.client.renderer.blockentity.LecternRenderer;
|
import net.minecraft.client.renderer.blockentity.LecternRenderer;
|
||||||
@ -40,19 +39,16 @@ import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FON
|
|||||||
public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternBlockEntity> {
|
public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternBlockEntity> {
|
||||||
private static final int POCKET_TERMINAL_RENDER_DISTANCE = 32;
|
private static final int POCKET_TERMINAL_RENDER_DISTANCE = 32;
|
||||||
|
|
||||||
private final BlockEntityRenderDispatcher berDispatcher;
|
|
||||||
private final LecternPrintoutModel printoutModel;
|
private final LecternPrintoutModel printoutModel;
|
||||||
private final LecternPocketModel pocketModel;
|
private final LecternPocketModel pocketModel;
|
||||||
|
|
||||||
public CustomLecternRenderer(BlockEntityRendererProvider.Context context) {
|
public CustomLecternRenderer(BlockEntityRendererProvider.Context context) {
|
||||||
berDispatcher = context.getBlockEntityRenderDispatcher();
|
|
||||||
|
|
||||||
printoutModel = new LecternPrintoutModel();
|
printoutModel = new LecternPrintoutModel();
|
||||||
pocketModel = new LecternPocketModel();
|
pocketModel = new LecternPocketModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(CustomLecternBlockEntity lectern, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay) {
|
public void render(CustomLecternBlockEntity lectern, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay, Vec3 camera) {
|
||||||
poseStack.pushPose();
|
poseStack.pushPose();
|
||||||
poseStack.translate(0.5f, 1.0625f, 0.5f);
|
poseStack.translate(0.5f, 1.0625f, 0.5f);
|
||||||
poseStack.mulPose(Axis.YP.rotationDegrees(-lectern.getBlockState().getValue(LecternBlock.FACING).getClockWise().toYRot()));
|
poseStack.mulPose(Axis.YP.rotationDegrees(-lectern.getBlockState().getValue(LecternBlock.FACING).getClockWise().toYRot()));
|
||||||
@ -83,7 +79,7 @@ public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternB
|
|||||||
// Either render the terminal or a black screen, depending on how close we are.
|
// Either render the terminal or a black screen, depending on how close we are.
|
||||||
var terminal = computer == null ? null : computer.getTerminal();
|
var terminal = computer == null ? null : computer.getTerminal();
|
||||||
var quadEmitter = FixedWidthFontRenderer.toVertexConsumer(poseStack, buffer.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT));
|
var quadEmitter = FixedWidthFontRenderer.toVertexConsumer(poseStack, buffer.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT));
|
||||||
if (terminal != null && Vec3.atCenterOf(lectern.getBlockPos()).closerThan(berDispatcher.camera.getPosition(), POCKET_TERMINAL_RENDER_DISTANCE)) {
|
if (terminal != null && Vec3.atCenterOf(lectern.getBlockPos()).closerThan(camera, POCKET_TERMINAL_RENDER_DISTANCE)) {
|
||||||
renderPocketTerminal(poseStack, quadEmitter, terminal);
|
renderPocketTerminal(poseStack, quadEmitter, terminal);
|
||||||
} else {
|
} else {
|
||||||
FixedWidthFontRenderer.drawEmptyTerminal(quadEmitter, 0, 0, LecternPocketModel.TERM_WIDTH, LecternPocketModel.TERM_HEIGHT);
|
FixedWidthFontRenderer.drawEmptyTerminal(quadEmitter, 0, 0, LecternPocketModel.TERM_WIDTH, LecternPocketModel.TERM_HEIGHT);
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.client.render;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
|
||||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
|
||||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
|
||||||
import net.minecraft.client.renderer.entity.ItemRenderer;
|
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
|
||||||
import net.minecraft.util.ARGB;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utilities for rendering {@link BakedModel}s and {@link BakedQuad}s.
|
|
||||||
*/
|
|
||||||
public final class ModelRenderer {
|
|
||||||
private ModelRenderer() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render a list of {@linkplain BakedQuad quads} to a buffer.
|
|
||||||
* <p>
|
|
||||||
* This is not intended to be used directly, but instead by {@link ClientPlatformHelper#renderBakedModel(PoseStack, MultiBufferSource, BakedModel, int, int, int[])}. The
|
|
||||||
* implementation here is identical to {@link ItemRenderer#renderQuadList(PoseStack, VertexConsumer, List, int[], int, int)}.
|
|
||||||
*
|
|
||||||
* @param transform The current matrix transformation to apply.
|
|
||||||
* @param buffer The buffer to draw to.
|
|
||||||
* @param quads The quads to draw.
|
|
||||||
* @param lightmapCoord The current packed lightmap coordinate.
|
|
||||||
* @param overlayLight The current overlay light.
|
|
||||||
* @param tints Block colour tints to apply to the model.
|
|
||||||
*/
|
|
||||||
public static void renderQuads(PoseStack transform, VertexConsumer buffer, List<BakedQuad> quads, int lightmapCoord, int overlayLight, int @Nullable [] tints) {
|
|
||||||
var matrix = transform.last();
|
|
||||||
|
|
||||||
for (var bakedquad : quads) {
|
|
||||||
float r = 1.0f, g = 1.0f, b = 1.0f, a = 1.0f;
|
|
||||||
if (tints != null && bakedquad.isTinted()) {
|
|
||||||
var idx = bakedquad.getTintIndex();
|
|
||||||
if (idx >= 0 && idx < tints.length) {
|
|
||||||
var tint = tints[bakedquad.getTintIndex()];
|
|
||||||
r = ARGB.red(tint) / 255.0f;
|
|
||||||
g = ARGB.green(tint) / 255.0f;
|
|
||||||
b = ARGB.blue(tint) / 255.0f;
|
|
||||||
a = ARGB.alpha(tint) / 255.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.putBulkData(matrix, bakedquad, r, g, b, a, lightmapCoord, overlayLight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,10 +7,9 @@ package dan200.computercraft.client.render;
|
|||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.math.Axis;
|
import com.mojang.math.Axis;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.client.TransformedModel;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
import dan200.computercraft.client.ClientRegistry;
|
||||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
import dan200.computercraft.client.turtle.TurtleUpgradeModels;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||||
@ -21,14 +20,12 @@ import net.minecraft.client.renderer.MultiBufferSource;
|
|||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.util.ARGB;
|
import net.minecraft.util.ARGB;
|
||||||
import net.minecraft.util.CommonColors;
|
import net.minecraft.util.CommonColors;
|
||||||
import net.minecraft.util.Mth;
|
|
||||||
import net.minecraft.world.item.ItemDisplayContext;
|
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.HitResult;
|
import net.minecraft.world.phys.HitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBlockEntity> {
|
public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBlockEntity> {
|
||||||
@ -45,7 +42,7 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(TurtleBlockEntity turtle, float partialTicks, PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight) {
|
public void render(TurtleBlockEntity turtle, float partialTicks, PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight, Vec3 camera) {
|
||||||
transform.pushPose();
|
transform.pushPose();
|
||||||
|
|
||||||
// Translate the turtle first, so the label moves with it.
|
// Translate the turtle first, so the label moves with it.
|
||||||
@ -114,18 +111,7 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
|
|||||||
transform.mulPose(Axis.XN.rotationDegrees(toolAngle));
|
transform.mulPose(Axis.XN.rotationDegrees(toolAngle));
|
||||||
transform.translate(0.0f, -0.5f, -0.5f);
|
transform.translate(0.0f, -0.5f, -0.5f);
|
||||||
|
|
||||||
switch (TurtleUpgradeModellers.getModel(upgrade, turtle.getAccess(), side)) {
|
TurtleUpgradeModels.getModeller(upgrade).renderForLevel(upgrade, turtle.getAccess(), side, turtle.getAccess().getUpgradeData(side), transform, buffers, lightmapCoord, overlayLight);
|
||||||
case TransformedModel.Item model -> {
|
|
||||||
transform.mulPose(model.transformation().getMatrix());
|
|
||||||
transform.mulPose(Axis.YP.rotation(Mth.PI));
|
|
||||||
Minecraft.getInstance().getItemRenderer().renderStatic(
|
|
||||||
model.stack(), ItemDisplayContext.FIXED, lightmapCoord, overlayLight, transform, buffers, turtle.getLevel(), 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
case TransformedModel.Baked model ->
|
|
||||||
renderModel(transform, buffers, lightmapCoord, overlayLight, model.model(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
transform.popPose();
|
transform.popPose();
|
||||||
@ -133,21 +119,7 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
|
|||||||
|
|
||||||
private void renderModel(PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight, ResourceLocation modelLocation, int @Nullable [] tints) {
|
private void renderModel(PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight, ResourceLocation modelLocation, int @Nullable [] tints) {
|
||||||
var modelManager = Minecraft.getInstance().getModelManager();
|
var modelManager = Minecraft.getInstance().getModelManager();
|
||||||
renderModel(transform, buffers, lightmapCoord, overlayLight, ClientPlatformHelper.get().getModel(modelManager, modelLocation), tints);
|
ClientRegistry.getModel(modelManager, modelLocation).render(transform, buffers, lightmapCoord, overlayLight, tints);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Render a block model.
|
|
||||||
*
|
|
||||||
* @param transform The current matrix stack.
|
|
||||||
* @param renderer The buffer to write to.
|
|
||||||
* @param lightmapCoord The current lightmap coordinate.
|
|
||||||
* @param overlayLight The overlay light.
|
|
||||||
* @param model The model to render.
|
|
||||||
* @param tints Tints for the quads, as an array of RGB values.
|
|
||||||
* @see net.minecraft.client.renderer.block.ModelBlockRenderer#renderModel
|
|
||||||
*/
|
|
||||||
private void renderModel(PoseStack transform, MultiBufferSource renderer, int lightmapCoord, int overlayLight, BakedModel model, int @Nullable [] tints) {
|
|
||||||
ClientPlatformHelper.get().renderBakedModel(transform, renderer, model, lightmapCoord, overlayLight, tints);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,11 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.render.monitor;
|
package dan200.computercraft.client.render.monitor;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.BufferType;
|
||||||
|
import com.mojang.blaze3d.buffers.BufferUsage;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
import com.mojang.blaze3d.vertex.*;
|
import com.mojang.blaze3d.vertex.ByteBufferBuilder;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.math.Axis;
|
import com.mojang.math.Axis;
|
||||||
import dan200.computercraft.annotations.ForgeOverride;
|
import dan200.computercraft.annotations.ForgeOverride;
|
||||||
import dan200.computercraft.client.FrameInfo;
|
import dan200.computercraft.client.FrameInfo;
|
||||||
@ -17,20 +20,20 @@ import dan200.computercraft.shared.config.Config;
|
|||||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||||
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
||||||
import dan200.computercraft.shared.util.DirectionUtil;
|
import dan200.computercraft.shared.util.DirectionUtil;
|
||||||
import net.minecraft.client.renderer.CompiledShaderProgram;
|
|
||||||
import net.minecraft.client.renderer.FogParameters;
|
import net.minecraft.client.renderer.FogParameters;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
import org.jspecify.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.OptionalDouble;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
|
||||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
|
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
|
||||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
|
||||||
|
|
||||||
public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBlockEntity> {
|
public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBlockEntity> {
|
||||||
/**
|
/**
|
||||||
@ -45,7 +48,7 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(MonitorBlockEntity monitor, float partialTicks, PoseStack transform, MultiBufferSource bufferSource, int lightmapCoord, int overlayLight) {
|
public void render(MonitorBlockEntity monitor, float partialTicks, PoseStack transform, MultiBufferSource bufferSource, int lightmapCoord, int overlayLight, Vec3 camera) {
|
||||||
// Render from the origin monitor
|
// Render from the origin monitor
|
||||||
var originTerminal = monitor.getOriginClientMonitor();
|
var originTerminal = monitor.getOriginClientMonitor();
|
||||||
if (originTerminal == null) return;
|
if (originTerminal == null) return;
|
||||||
@ -122,27 +125,64 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
|||||||
Matrix4f matrix, ClientMonitor monitor, MonitorRenderState renderState, Terminal terminal, float xMargin, float yMargin
|
Matrix4f matrix, ClientMonitor monitor, MonitorRenderState renderState, Terminal terminal, float xMargin, float yMargin
|
||||||
) {
|
) {
|
||||||
var redraw = monitor.pollTerminalChanged();
|
var redraw = monitor.pollTerminalChanged();
|
||||||
if (renderState.createBuffer()) redraw = true;
|
if (renderState.vertexBuffer == null) redraw = true;
|
||||||
|
|
||||||
var backgroundBuffer = assertNonNull(renderState.backgroundBuffer);
|
|
||||||
var foregroundBuffer = assertNonNull(renderState.foregroundBuffer);
|
|
||||||
if (redraw) {
|
if (redraw) {
|
||||||
var size = DirectFixedWidthFontRenderer.getVertexCount(terminal);
|
// Cursor, Foreground, Background+Margin
|
||||||
|
var maxVertexCount = 4 * (1 + (terminal.getWidth() * terminal.getHeight()) + ((terminal.getWidth() + 2) * (terminal.getHeight() + 2)));
|
||||||
|
backingBufferBuilder.clear();
|
||||||
|
var sink = ShaderMod.get().getQuadEmitter(maxVertexCount, backingBufferBuilder);
|
||||||
|
|
||||||
// In an ideal world we could upload these both into one buffer. However, we can't render VBOs with
|
DirectFixedWidthFontRenderer.drawTerminalBackground(sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin);
|
||||||
// a starting and ending offset, and so need to use two buffers instead.
|
var vertexCountAfterBackground = sink.vertexCount();
|
||||||
|
|
||||||
renderToBuffer(backgroundBuffer, size, sink ->
|
DirectFixedWidthFontRenderer.drawTerminalForeground(sink, 0, 0, terminal);
|
||||||
DirectFixedWidthFontRenderer.drawTerminalBackground(sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin));
|
var vertexCountAfterForeground = sink.vertexCount();
|
||||||
|
|
||||||
renderToBuffer(foregroundBuffer, size + 4, sink -> {
|
DirectFixedWidthFontRenderer.drawCursor(sink, 0, 0, terminal);
|
||||||
DirectFixedWidthFontRenderer.drawTerminalForeground(sink, 0, 0, terminal);
|
var vertexCountAfterCursor = sink.vertexCount();
|
||||||
// If the cursor is visible, we append it to the end of our buffer. When rendering, we can either
|
|
||||||
// render n or n+1 quads and so toggle the cursor on and off.
|
if (vertexCountAfterCursor > maxVertexCount) {
|
||||||
DirectFixedWidthFontRenderer.drawCursor(sink, 0, 0, terminal);
|
throw new IllegalStateException("Drew too many vertices. Expected " + maxVertexCount + ", drew " + vertexCountAfterCursor);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
try (var result = backingBufferBuilder.build()) {
|
||||||
|
if (result == null) {
|
||||||
|
// If we have nothing to draw, just mark it as empty. We'll skip drawing in drawWithShader.
|
||||||
|
renderState.indexAfterBackground = renderState.indexAfterForeground = renderState.indexAfterCursor = 0;
|
||||||
|
} else {
|
||||||
|
renderState.register();
|
||||||
|
|
||||||
|
var commandEncoder = RenderSystem.getDevice().createCommandEncoder();
|
||||||
|
|
||||||
|
var resultBuffer = result.byteBuffer();
|
||||||
|
if (resultBuffer.limit() / sink.format().getVertexSize() != vertexCountAfterCursor) {
|
||||||
|
throw new IllegalStateException("Mismatched vertex count");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (renderState.vertexBuffer == null || resultBuffer.limit() > renderState.vertexBuffer.size()) {
|
||||||
|
if (renderState.vertexBuffer != null) {
|
||||||
|
renderState.vertexBuffer.close();
|
||||||
|
renderState.vertexBuffer = null;
|
||||||
|
}
|
||||||
|
renderState.vertexBuffer = RenderSystem.getDevice().createBuffer(
|
||||||
|
() -> "Monitor at " + monitor.getOrigin().getBlockPos(),
|
||||||
|
BufferType.VERTICES, BufferUsage.STATIC_WRITE, resultBuffer
|
||||||
|
);
|
||||||
|
} else if (!renderState.vertexBuffer.isClosed()) {
|
||||||
|
commandEncoder.writeToBuffer(renderState.vertexBuffer, resultBuffer, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var mode = FixedWidthFontRenderer.TERMINAL_TEXT.mode();
|
||||||
|
renderState.indexAfterBackground = mode.indexCount(vertexCountAfterBackground);
|
||||||
|
renderState.indexAfterForeground = mode.indexCount(vertexCountAfterForeground);
|
||||||
|
renderState.indexAfterCursor = mode.indexCount(vertexCountAfterCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (renderState.indexAfterCursor == 0) return;
|
||||||
|
|
||||||
// Our VBO renders coordinates in monitor-space rather than world space. A full sized monitor (8x6) will
|
// Our VBO renders coordinates in monitor-space rather than world space. A full sized monitor (8x6) will
|
||||||
// use positions from (0, 0) to (164*FONT_WIDTH, 81*FONT_HEIGHT) = (984, 729). This is far outside the
|
// use positions from (0, 0) to (164*FONT_WIDTH, 81*FONT_HEIGHT) = (984, 729). This is far outside the
|
||||||
// normal render distance (~200), and the edges of the monitor fade out due to fog.
|
// normal render distance (~200), and the edges of the monitor fade out due to fog.
|
||||||
@ -152,69 +192,52 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
|||||||
var oldFog = RenderSystem.getShaderFog();
|
var oldFog = RenderSystem.getShaderFog();
|
||||||
RenderSystem.setShaderFog(FogParameters.NO_FOG);
|
RenderSystem.setShaderFog(FogParameters.NO_FOG);
|
||||||
|
|
||||||
FixedWidthFontRenderer.TERMINAL_TEXT.setupRenderState();
|
|
||||||
|
|
||||||
// Compose the existing model view matrix with our transformation matrix.
|
// Compose the existing model view matrix with our transformation matrix.
|
||||||
var modelView = new Matrix4f(RenderSystem.getModelViewMatrix()).mul(matrix);
|
RenderSystem.getModelViewStack().pushMatrix();
|
||||||
|
RenderSystem.getModelViewStack().mul(matrix);
|
||||||
|
|
||||||
// Render background geometry
|
// Render background geometry
|
||||||
backgroundBuffer.bind();
|
drawWithShader(renderState, FixedWidthFontRenderer.TERMINAL_TEXT, 0, renderState.indexAfterBackground);
|
||||||
backgroundBuffer.drawWithShader(modelView, RenderSystem.getProjectionMatrix(), RenderSystem.getShader());
|
|
||||||
|
|
||||||
// Render foreground geometry with glPolygonOffset enabled.
|
|
||||||
RenderSystem.polygonOffset(-1.0f, -10.0f);
|
|
||||||
RenderSystem.enablePolygonOffset();
|
|
||||||
|
|
||||||
foregroundBuffer.bind();
|
|
||||||
drawWithShader(
|
drawWithShader(
|
||||||
foregroundBuffer, modelView, RenderSystem.getProjectionMatrix(), RenderSystem.getShader(),
|
renderState, FixedWidthFontRenderer.TERMINAL_TEXT_OFFSET, renderState.indexAfterBackground,
|
||||||
// Skip the cursor quad if it is not visible this frame.
|
(
|
||||||
FixedWidthFontRenderer.isCursorVisible(terminal) && !FrameInfo.getGlobalCursorBlink()
|
FixedWidthFontRenderer.isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink()
|
||||||
? foregroundBuffer.indexCount - FixedWidthFontRenderer.TERMINAL_TEXT.mode().indexCount(4)
|
? renderState.indexAfterCursor : renderState.indexAfterForeground
|
||||||
: foregroundBuffer.indexCount
|
) - renderState.indexAfterBackground
|
||||||
);
|
);
|
||||||
|
|
||||||
// Clear state
|
// Clear state
|
||||||
RenderSystem.polygonOffset(0.0f, -0.0f);
|
RenderSystem.getModelViewStack().popMatrix();
|
||||||
RenderSystem.disablePolygonOffset();
|
|
||||||
FixedWidthFontRenderer.TERMINAL_TEXT.clearRenderState();
|
|
||||||
VertexBuffer.unbind();
|
|
||||||
|
|
||||||
RenderSystem.setShaderFog(oldFog);
|
RenderSystem.setShaderFog(oldFog);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void renderToBuffer(VertexBuffer vbo, int size, Consumer<DirectFixedWidthFontRenderer.QuadEmitter> draw) {
|
private static void drawWithShader(MonitorRenderState renderState, RenderType renderType, int indexOffset, int indexCount) {
|
||||||
var sink = ShaderMod.get().getQuadEmitter(size, backingBufferBuilder);
|
if (renderState.vertexBuffer == null) {
|
||||||
draw.accept(sink);
|
throw new IllegalStateException("MonitorRenderState has not been initialised");
|
||||||
|
}
|
||||||
|
if (indexCount == 0) return;
|
||||||
|
|
||||||
var result = backingBufferBuilder.build();
|
renderType.setupRenderState();
|
||||||
if (result == null) {
|
|
||||||
// If we have nothing to draw, just mark it as empty. We'll skip drawing in drawWithShader.
|
var autoStorageBuffer = RenderSystem.getSequentialBuffer(renderType.mode());
|
||||||
vbo.indexCount = 0;
|
var indexBuffer = autoStorageBuffer.getBuffer(indexOffset + indexCount);
|
||||||
return;
|
|
||||||
|
try (var renderPass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(
|
||||||
|
renderType.getRenderTarget().getColorTexture(), OptionalInt.empty(), renderType.getRenderTarget().getDepthTexture(), OptionalDouble.empty()
|
||||||
|
)) {
|
||||||
|
renderPass.setPipeline(renderType.getRenderPipeline());
|
||||||
|
renderPass.setVertexBuffer(0, renderState.vertexBuffer);
|
||||||
|
renderPass.setIndexBuffer(indexBuffer, autoStorageBuffer.type());
|
||||||
|
|
||||||
|
for (var j = 0; j < 12; j++) {
|
||||||
|
var gpuTexture = RenderSystem.getShaderTexture(j);
|
||||||
|
if (gpuTexture != null) renderPass.bindSampler("Sampler" + j, gpuTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPass.drawIndexed(indexOffset, indexCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
var buffer = result.byteBuffer();
|
renderType.clearRenderState();
|
||||||
var vertices = buffer.limit() / sink.format().getVertexSize();
|
|
||||||
|
|
||||||
vbo.bind();
|
|
||||||
vbo.upload(new MeshData(result, new MeshData.DrawState(
|
|
||||||
sink.format(),
|
|
||||||
vertices, FixedWidthFontRenderer.TERMINAL_TEXT.mode().indexCount(vertices),
|
|
||||||
FixedWidthFontRenderer.TERMINAL_TEXT.mode(), VertexFormat.IndexType.least(vertices)
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void drawWithShader(VertexBuffer buffer, Matrix4f modelView, Matrix4f projection, @Nullable CompiledShaderProgram compiledShaderProgram, int indicies) {
|
|
||||||
var originalIndexCount = buffer.indexCount;
|
|
||||||
if (originalIndexCount == 0) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
buffer.indexCount = indicies;
|
|
||||||
buffer.drawWithShader(modelView, projection, compiledShaderProgram);
|
|
||||||
} finally {
|
|
||||||
buffer.indexCount = originalIndexCount;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -5,8 +5,7 @@
|
|||||||
package dan200.computercraft.client.render.monitor;
|
package dan200.computercraft.client.render.monitor;
|
||||||
|
|
||||||
import com.google.errorprone.annotations.concurrent.GuardedBy;
|
import com.google.errorprone.annotations.concurrent.GuardedBy;
|
||||||
import com.mojang.blaze3d.buffers.BufferUsage;
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
import com.mojang.blaze3d.vertex.VertexBuffer;
|
|
||||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
@ -21,53 +20,39 @@ import java.util.Set;
|
|||||||
* This is automatically cleared by {@link dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity} when the
|
* This is automatically cleared by {@link dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity} when the
|
||||||
* entity is unloaded on the client side (see {@link MonitorRenderState#close()}).
|
* entity is unloaded on the client side (see {@link MonitorRenderState#close()}).
|
||||||
*/
|
*/
|
||||||
public class MonitorRenderState implements ClientMonitor.RenderState {
|
public final class MonitorRenderState implements ClientMonitor.RenderState {
|
||||||
@GuardedBy("allMonitors")
|
@GuardedBy("allMonitors")
|
||||||
private static final Set<MonitorRenderState> allMonitors = new HashSet<>();
|
private static final Set<MonitorRenderState> allMonitors = new HashSet<>();
|
||||||
|
|
||||||
public long lastRenderFrame = -1;
|
long lastRenderFrame = -1;
|
||||||
public @Nullable BlockPos lastRenderPos = null;
|
@Nullable
|
||||||
|
BlockPos lastRenderPos = null;
|
||||||
|
|
||||||
public @Nullable VertexBuffer backgroundBuffer;
|
@Nullable
|
||||||
public @Nullable VertexBuffer foregroundBuffer;
|
GpuBuffer vertexBuffer;
|
||||||
|
|
||||||
/**
|
int indexAfterBackground;
|
||||||
* Create the appropriate buffer if needed.
|
int indexAfterForeground;
|
||||||
*
|
int indexAfterCursor;
|
||||||
* @return If a buffer was created. This will return {@code false} if we already have an appropriate buffer,
|
|
||||||
* or this mode does not require one.
|
|
||||||
*/
|
|
||||||
public boolean createBuffer() {
|
|
||||||
if (backgroundBuffer != null) return false;
|
|
||||||
|
|
||||||
deleteBuffers();
|
void register() {
|
||||||
backgroundBuffer = new VertexBuffer(BufferUsage.STATIC_WRITE);
|
if (vertexBuffer != null) return;
|
||||||
foregroundBuffer = new VertexBuffer(BufferUsage.STATIC_WRITE);
|
|
||||||
addMonitor();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addMonitor() {
|
|
||||||
synchronized (allMonitors) {
|
synchronized (allMonitors) {
|
||||||
allMonitors.add(this);
|
allMonitors.add(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteBuffers() {
|
private void deleteBuffers() {
|
||||||
if (backgroundBuffer != null) {
|
if (vertexBuffer != null) {
|
||||||
backgroundBuffer.close();
|
vertexBuffer.close();
|
||||||
backgroundBuffer = null;
|
vertexBuffer = null;
|
||||||
}
|
|
||||||
|
|
||||||
if (foregroundBuffer != null) {
|
|
||||||
foregroundBuffer.close();
|
|
||||||
foregroundBuffer = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
if (backgroundBuffer != null) {
|
if (vertexBuffer != null) {
|
||||||
synchronized (allMonitors) {
|
synchronized (allMonitors) {
|
||||||
allMonitors.remove(this);
|
allMonitors.remove(this);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ import static org.lwjgl.system.MemoryUtil.*;
|
|||||||
* <p>
|
* <p>
|
||||||
* Note this is almost an exact copy of {@link FixedWidthFontRenderer}. While the code duplication is unfortunate,
|
* Note this is almost an exact copy of {@link FixedWidthFontRenderer}. While the code duplication is unfortunate,
|
||||||
* it is measurably faster than introducing polymorphism into {@link FixedWidthFontRenderer}.
|
* it is measurably faster than introducing polymorphism into {@link FixedWidthFontRenderer}.
|
||||||
*
|
* <p>
|
||||||
* <strong>IMPORTANT: </strong> When making changes to this class, please check if you need to make the same changes to
|
* <strong>IMPORTANT: </strong> When making changes to this class, please check if you need to make the same changes to
|
||||||
* {@link FixedWidthFontRenderer}.
|
* {@link FixedWidthFontRenderer}.
|
||||||
*/
|
*/
|
||||||
@ -156,21 +156,30 @@ public final class DirectFixedWidthFontRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getVertexCount(Terminal terminal) {
|
|
||||||
return (terminal.getHeight() + 2) * (terminal.getWidth() + 2) * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void quad(QuadEmitter buffer, float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2) {
|
private static void quad(QuadEmitter buffer, float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2) {
|
||||||
|
buffer.vertexCount += 4;
|
||||||
buffer.quad(x1, y1, x2, y2, z, colour, u1, v1, u2, v2);
|
buffer.quad(x1, y1, x2, y2, z, colour, u1, v1, u2, v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface QuadEmitter {
|
public abstract static class QuadEmitter {
|
||||||
VertexFormat format();
|
private int vertexCount;
|
||||||
|
|
||||||
void quad(float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2);
|
public abstract VertexFormat format();
|
||||||
|
|
||||||
|
protected abstract void quad(float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2);
|
||||||
|
|
||||||
|
public int vertexCount() {
|
||||||
|
return vertexCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record ByteBufferEmitter(ByteBufferBuilder builder) implements QuadEmitter {
|
public static final class ByteBufferEmitter extends QuadEmitter {
|
||||||
|
private final ByteBufferBuilder builder;
|
||||||
|
|
||||||
|
public ByteBufferEmitter(ByteBufferBuilder builder) {
|
||||||
|
this.builder = builder;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VertexFormat format() {
|
public VertexFormat format() {
|
||||||
return TERMINAL_TEXT.format();
|
return TERMINAL_TEXT.format();
|
||||||
|
@ -40,6 +40,8 @@ public final class FixedWidthFontRenderer {
|
|||||||
*/
|
*/
|
||||||
public static final RenderType TERMINAL_TEXT = RenderType.text(FONT);
|
public static final RenderType TERMINAL_TEXT = RenderType.text(FONT);
|
||||||
|
|
||||||
|
public static final RenderType TERMINAL_TEXT_OFFSET = RenderType.textPolygonOffset(FONT);
|
||||||
|
|
||||||
public static final int FONT_HEIGHT = 9;
|
public static final int FONT_HEIGHT = 9;
|
||||||
public static final int FONT_WIDTH = 6;
|
public static final int FONT_WIDTH = 6;
|
||||||
static final float WIDTH = 256.0f;
|
static final float WIDTH = 256.0f;
|
||||||
|
@ -0,0 +1,89 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.client.turtle;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.api.client.StandaloneModel;
|
||||||
|
import dan200.computercraft.api.client.turtle.TurtleUpgradeModel;
|
||||||
|
import dan200.computercraft.api.client.turtle.TurtleUpgradeModelViaStandalone;
|
||||||
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
|
import dan200.computercraft.shared.turtle.upgrades.TurtleModem;
|
||||||
|
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||||
|
import net.minecraft.client.resources.model.ModelBaker;
|
||||||
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link TurtleUpgradeModel} for modems, providing different models depending on if the modem is on/off.
|
||||||
|
*
|
||||||
|
* @param normal The models for a normal wireless modem.
|
||||||
|
* @param advanced The models for an advanced/ender modem.
|
||||||
|
*/
|
||||||
|
public record TurtleModemModel(
|
||||||
|
ModemModels<StandaloneModel> normal, ModemModels<StandaloneModel> advanced
|
||||||
|
) implements TurtleUpgradeModelViaStandalone<TurtleModem> {
|
||||||
|
public static final TurtleUpgradeModel.Unbaked<TurtleModem> UNBAKED = new Unbaked();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StandaloneModel getModel(TurtleModem modem, TurtleSide side, DataComponentPatch data) {
|
||||||
|
var active = DataComponentUtil.isPresent(data, ModRegistry.DataComponents.ON.get(), x -> x);
|
||||||
|
|
||||||
|
var models = modem.advanced() ? advanced() : normal();
|
||||||
|
return side == TurtleSide.LEFT
|
||||||
|
? (active ? models.leftOnModel() : models.leftOffModel())
|
||||||
|
: (active ? models.rightOnModel() : models.rightOffModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class Unbaked implements TurtleUpgradeModel.Unbaked<TurtleModem> {
|
||||||
|
@Override
|
||||||
|
public TurtleUpgradeModel<TurtleModem> bake(ModelBaker baker) {
|
||||||
|
return new TurtleModemModel(
|
||||||
|
ModemModels.NORMAL.map(x -> StandaloneModel.of(x, baker)),
|
||||||
|
ModemModels.ADVANCED.map(x -> StandaloneModel.of(x, baker))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolveDependencies(Resolver resolver) {
|
||||||
|
ModemModels.NORMAL.forEach(resolver::markDependency);
|
||||||
|
ModemModels.ADVANCED.forEach(resolver::markDependency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private record ModemModels<T>(
|
||||||
|
T leftOffModel, T rightOffModel,
|
||||||
|
T leftOnModel, T rightOnModel
|
||||||
|
) {
|
||||||
|
private static final ModemModels<ResourceLocation> NORMAL = create("normal");
|
||||||
|
private static final ModemModels<ResourceLocation> ADVANCED = create("advanced");
|
||||||
|
|
||||||
|
static ModemModels<ResourceLocation> create(String type) {
|
||||||
|
return new ModemModels<>(
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_modem_" + type + "_off_left"),
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_modem_" + type + "_off_right"),
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_modem_" + type + "_on_left"),
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_modem_" + type + "_on_right")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void forEach(Consumer<T> out) {
|
||||||
|
out.accept(leftOffModel());
|
||||||
|
out.accept(rightOffModel);
|
||||||
|
out.accept(leftOnModel());
|
||||||
|
out.accept(rightOnModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
public <U> ModemModels<U> map(Function<T, U> mapper) {
|
||||||
|
return new ModemModels<>(
|
||||||
|
mapper.apply(leftOffModel()), mapper.apply(rightOffModel()),
|
||||||
|
mapper.apply(leftOnModel()), mapper.apply(rightOnModel())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,60 +0,0 @@
|
|||||||
// Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: LicenseRef-CCPL
|
|
||||||
|
|
||||||
package dan200.computercraft.client.turtle;
|
|
||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
|
||||||
import dan200.computercraft.api.client.TransformedModel;
|
|
||||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
|
||||||
import dan200.computercraft.shared.turtle.upgrades.TurtleModem;
|
|
||||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link TurtleUpgradeModeller} for modems, providing different models depending on if the modem is on/off.
|
|
||||||
*/
|
|
||||||
public class TurtleModemModeller implements TurtleUpgradeModeller<TurtleModem> {
|
|
||||||
@Override
|
|
||||||
public TransformedModel getModel(TurtleModem upgrade, @Nullable ITurtleAccess turtle, TurtleSide side, DataComponentPatch data) {
|
|
||||||
var active = DataComponentUtil.isPresent(data, ModRegistry.DataComponents.ON.get(), x -> x);
|
|
||||||
|
|
||||||
var models = upgrade.advanced() ? ModemModels.ADVANCED : ModemModels.NORMAL;
|
|
||||||
return side == TurtleSide.LEFT
|
|
||||||
? TransformedModel.of(active ? models.leftOnModel() : models.leftOffModel())
|
|
||||||
: TransformedModel.of(active ? models.rightOnModel() : models.rightOffModel());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<ResourceLocation> getDependencies() {
|
|
||||||
return Stream.of(ModemModels.NORMAL, ModemModels.ADVANCED).flatMap(ModemModels::getDependencies);
|
|
||||||
}
|
|
||||||
|
|
||||||
private record ModemModels(
|
|
||||||
ResourceLocation leftOffModel, ResourceLocation rightOffModel,
|
|
||||||
ResourceLocation leftOnModel, ResourceLocation rightOnModel
|
|
||||||
) {
|
|
||||||
private static final ModemModels NORMAL = create("normal");
|
|
||||||
private static final ModemModels ADVANCED = create("advanced");
|
|
||||||
|
|
||||||
public static ModemModels create(String type) {
|
|
||||||
return new ModemModels(
|
|
||||||
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_modem_" + type + "_off_left"),
|
|
||||||
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_modem_" + type + "_off_right"),
|
|
||||||
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_modem_" + type + "_on_left"),
|
|
||||||
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_modem_" + type + "_on_right")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Stream<ResourceLocation> getDependencies() {
|
|
||||||
return Stream.of(leftOffModel, rightOffModel, leftOnModel, rightOnModel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.client.turtle;
|
|
||||||
|
|
||||||
import dan200.computercraft.api.client.TransformedModel;
|
|
||||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeType;
|
|
||||||
import dan200.computercraft.shared.util.RegistryHelper;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A registry of {@link TurtleUpgradeModeller}s.
|
|
||||||
*/
|
|
||||||
public final class TurtleUpgradeModellers {
|
|
||||||
private static final TurtleUpgradeModeller<ITurtleUpgrade> NULL_TURTLE_MODELLER = (upgrade, turtle, side, data) ->
|
|
||||||
TransformedModel.of(Minecraft.getInstance().getModelManager().getMissingModel());
|
|
||||||
|
|
||||||
private static final Map<UpgradeType<? extends ITurtleUpgrade>, TurtleUpgradeModeller<?>> turtleModels = new ConcurrentHashMap<>();
|
|
||||||
private static volatile boolean fetchedModels;
|
|
||||||
|
|
||||||
private TurtleUpgradeModellers() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T extends ITurtleUpgrade> void register(UpgradeType<T> type, TurtleUpgradeModeller<T> modeller) {
|
|
||||||
if (fetchedModels) {
|
|
||||||
throw new IllegalStateException(String.format(
|
|
||||||
"Turtle upgrade type %s must be registered before models are baked.",
|
|
||||||
RegistryHelper.getKeyOrThrow(RegistryHelper.getRegistry(ITurtleUpgrade.typeRegistry()), type)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (turtleModels.putIfAbsent(type, modeller) != null) {
|
|
||||||
throw new IllegalStateException("Modeller already registered for serialiser");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TransformedModel getModel(ITurtleUpgrade upgrade, ITurtleAccess access, TurtleSide side) {
|
|
||||||
return getModeller(upgrade).getModel(upgrade, access, side, access.getUpgradeData(side));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TransformedModel getModel(ITurtleUpgrade upgrade, DataComponentPatch data, TurtleSide side) {
|
|
||||||
return getModeller(upgrade).getModel(upgrade, null, side, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private static <T extends ITurtleUpgrade> TurtleUpgradeModeller<T> getModeller(T upgrade) {
|
|
||||||
var modeller = turtleModels.get(upgrade.getType());
|
|
||||||
return (TurtleUpgradeModeller<T>) (modeller == null ? NULL_TURTLE_MODELLER : modeller);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Stream<ResourceLocation> getDependencies() {
|
|
||||||
fetchedModels = true;
|
|
||||||
return turtleModels.values().stream().flatMap(TurtleUpgradeModeller::getDependencies);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,86 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.client.turtle;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.client.turtle.TurtleUpgradeModel;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
|
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||||
|
import dan200.computercraft.client.platform.ModelKey;
|
||||||
|
import dan200.computercraft.shared.util.RegistryHelper;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.resources.model.MissingBlockModel;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A registry of {@link TurtleUpgradeModel}s.
|
||||||
|
*/
|
||||||
|
public final class TurtleUpgradeModels {
|
||||||
|
private static final Object fetchedLock = new Object();
|
||||||
|
private static volatile boolean fetchedModels;
|
||||||
|
|
||||||
|
private static final Map<ModelKey<? extends TurtleUpgradeModel<?>>, TurtleUpgradeModel.Unbaked<?>> unbaked = new ConcurrentHashMap<>();
|
||||||
|
private static final Map<UpgradeType<? extends ITurtleUpgrade>, ModelKey<? extends TurtleUpgradeModel<?>>> modelKeys = new ConcurrentHashMap<>();
|
||||||
|
public static final ModelKey<TurtleUpgradeModel<ITurtleUpgrade>> missingModelKey = ClientPlatformHelper.get().createModelKey(
|
||||||
|
MissingBlockModel.LOCATION,
|
||||||
|
() -> "Missing turtle model"
|
||||||
|
);
|
||||||
|
|
||||||
|
private TurtleUpgradeModels() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends ITurtleUpgrade> void register(UpgradeType<T> type, TurtleUpgradeModel.Unbaked<? super T> modeller) {
|
||||||
|
if (fetchedModels) {
|
||||||
|
throw new IllegalStateException(String.format(
|
||||||
|
"Turtle upgrade type %s must be registered before models are baked.",
|
||||||
|
RegistryHelper.getKeyOrThrow(RegistryHelper.getRegistry(ITurtleUpgrade.typeRegistry()), type)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unbaked.putIfAbsent(getModelKey(type), modeller) != null) {
|
||||||
|
throw new IllegalStateException("Modeller already registered for serialiser");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void fetch(Runnable action) {
|
||||||
|
if (fetchedModels) return;
|
||||||
|
synchronized (fetchedLock) {
|
||||||
|
if (fetchedModels) return;
|
||||||
|
action.run();
|
||||||
|
fetchedModels = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static <T extends ITurtleUpgrade> ModelKey<TurtleUpgradeModel<? super T>> getModelKey(UpgradeType<T> type) {
|
||||||
|
return (ModelKey<TurtleUpgradeModel<? super T>>) modelKeys.computeIfAbsent(type, t -> {
|
||||||
|
var id = RegistryHelper.getKeyOrThrow(RegistryHelper.getRegistry(ITurtleUpgrade.typeRegistry()), t);
|
||||||
|
return ClientPlatformHelper.get().createModelKey(
|
||||||
|
RegistryHelper.getKeyOrThrow(RegistryHelper.getRegistry(ITurtleUpgrade.typeRegistry()), t),
|
||||||
|
() -> "Turtle upgrade " + id
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends ITurtleUpgrade> TurtleUpgradeModel<? super T> getModeller(T upgrade) {
|
||||||
|
var modelManager = Minecraft.getInstance().getModelManager();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
var model = getModelKey((UpgradeType<T>) upgrade.getType()).get(modelManager);
|
||||||
|
if (model != null) return model;
|
||||||
|
|
||||||
|
var missing = missingModelKey.get(modelManager);
|
||||||
|
if (missing == null) throw new IllegalStateException("Rendering turtles before models are baked");
|
||||||
|
return missing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bake(BiConsumer<ModelKey<? extends TurtleUpgradeModel<?>>, TurtleUpgradeModel.Unbaked<?>> baker) {
|
||||||
|
unbaked.forEach(baker);
|
||||||
|
baker.accept(missingModelKey, TurtleUpgradeModel.sided(MissingBlockModel.LOCATION, MissingBlockModel.LOCATION));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.data.client;
|
package dan200.computercraft.data.client;
|
||||||
|
|
||||||
|
import com.mojang.math.Quadrant;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.client.item.model.TurtleOverlayModel;
|
import dan200.computercraft.client.item.model.TurtleOverlayModel;
|
||||||
@ -24,8 +25,13 @@ import dan200.computercraft.shared.turtle.TurtleOverlay;
|
|||||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlock;
|
import dan200.computercraft.shared.turtle.blocks.TurtleBlock;
|
||||||
import dan200.computercraft.shared.util.DirectionUtil;
|
import dan200.computercraft.shared.util.DirectionUtil;
|
||||||
import net.minecraft.client.data.models.BlockModelGenerators;
|
import net.minecraft.client.data.models.BlockModelGenerators;
|
||||||
import net.minecraft.client.data.models.blockstates.*;
|
import net.minecraft.client.data.models.MultiVariant;
|
||||||
|
import net.minecraft.client.data.models.blockstates.ConditionBuilder;
|
||||||
|
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.data.models.model.*;
|
||||||
|
import net.minecraft.client.renderer.block.model.VariantMutator;
|
||||||
import net.minecraft.client.renderer.item.EmptyModel;
|
import net.minecraft.client.renderer.item.EmptyModel;
|
||||||
import net.minecraft.client.renderer.item.properties.conditional.HasComponent;
|
import net.minecraft.client.renderer.item.properties.conditional.HasComponent;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
@ -33,7 +39,6 @@ import net.minecraft.core.component.DataComponents;
|
|||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
|
||||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||||
import net.minecraft.world.level.block.state.properties.Property;
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
|
|
||||||
@ -43,6 +48,7 @@ import java.util.Optional;
|
|||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static net.minecraft.client.data.models.BlockModelGenerators.*;
|
||||||
import static net.minecraft.client.data.models.model.ModelLocationUtils.getModelLocation;
|
import static net.minecraft.client.data.models.model.ModelLocationUtils.getModelLocation;
|
||||||
import static net.minecraft.client.data.models.model.TextureMapping.getBlockTexture;
|
import static net.minecraft.client.data.models.model.TextureMapping.getBlockTexture;
|
||||||
|
|
||||||
@ -116,15 +122,14 @@ public class BlockModelProvider {
|
|||||||
registerTurtleModem(generators, "block/turtle_modem_advanced", "block/wireless_modem_advanced_face");
|
registerTurtleModem(generators, "block/turtle_modem_advanced", "block/wireless_modem_advanced_face");
|
||||||
|
|
||||||
generators.blockStateOutput.accept(
|
generators.blockStateOutput.accept(
|
||||||
BlockModelGenerators.createSimpleBlock(ModRegistry.Blocks.LECTERN.get(), getModelLocation(Blocks.LECTERN))
|
createSimpleBlock(ModRegistry.Blocks.LECTERN.get(), plainVariant(getModelLocation(Blocks.LECTERN)))
|
||||||
.with(createHorizontalFacingDispatch())
|
.with(createHorizontalFacingDispatch())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void registerDiskDrive(BlockModelGenerators generators) {
|
private static void registerDiskDrive(BlockModelGenerators generators) {
|
||||||
var diskDrive = ModRegistry.Blocks.DISK_DRIVE.get();
|
var diskDrive = ModRegistry.Blocks.DISK_DRIVE.get();
|
||||||
generators.blockStateOutput.accept(MultiVariantGenerator.multiVariant(diskDrive)
|
generators.blockStateOutput.accept(MultiVariantGenerator.dispatch(diskDrive)
|
||||||
.with(createHorizontalFacingDispatch())
|
|
||||||
.with(createModelDispatch(DiskDriveBlock.STATE, value -> {
|
.with(createModelDispatch(DiskDriveBlock.STATE, value -> {
|
||||||
var textureSuffix = switch (value) {
|
var textureSuffix = switch (value) {
|
||||||
case EMPTY -> "_front";
|
case EMPTY -> "_front";
|
||||||
@ -137,14 +142,14 @@ public class BlockModelProvider {
|
|||||||
generators.modelOutput
|
generators.modelOutput
|
||||||
);
|
);
|
||||||
}))
|
}))
|
||||||
|
.with(createHorizontalFacingDispatch())
|
||||||
);
|
);
|
||||||
generators.registerSimpleItemModel(diskDrive, getModelLocation(diskDrive, "_empty"));
|
generators.registerSimpleItemModel(diskDrive, getModelLocation(diskDrive, "_empty"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void registerPrinter(BlockModelGenerators generators) {
|
private static void registerPrinter(BlockModelGenerators generators) {
|
||||||
var printer = ModRegistry.Blocks.PRINTER.get();
|
var printer = ModRegistry.Blocks.PRINTER.get();
|
||||||
generators.blockStateOutput.accept(MultiVariantGenerator.multiVariant(printer)
|
generators.blockStateOutput.accept(MultiVariantGenerator.dispatch(printer)
|
||||||
.with(createHorizontalFacingDispatch())
|
|
||||||
.with(createModelDispatch(PrinterBlock.TOP, PrinterBlock.BOTTOM, (top, bottom) -> {
|
.with(createModelDispatch(PrinterBlock.TOP, PrinterBlock.BOTTOM, (top, bottom) -> {
|
||||||
String model, texture;
|
String model, texture;
|
||||||
if (top && bottom) {
|
if (top && bottom) {
|
||||||
@ -165,13 +170,13 @@ public class BlockModelProvider {
|
|||||||
generators.modelOutput
|
generators.modelOutput
|
||||||
);
|
);
|
||||||
}))
|
}))
|
||||||
|
.with(createHorizontalFacingDispatch())
|
||||||
);
|
);
|
||||||
generators.registerSimpleItemModel(printer, getModelLocation(printer, "_empty"));
|
generators.registerSimpleItemModel(printer, getModelLocation(printer, "_empty"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void registerComputer(BlockModelGenerators generators, ComputerBlock<?> block) {
|
private static void registerComputer(BlockModelGenerators generators, ComputerBlock<?> block) {
|
||||||
generators.blockStateOutput.accept(MultiVariantGenerator.multiVariant(block)
|
generators.blockStateOutput.accept(MultiVariantGenerator.dispatch(block)
|
||||||
.with(createHorizontalFacingDispatch())
|
|
||||||
.with(createModelDispatch(ComputerBlock.STATE, state -> switch (state) {
|
.with(createModelDispatch(ComputerBlock.STATE, state -> switch (state) {
|
||||||
case OFF -> ModelTemplates.CUBE_ORIENTABLE.createWithSuffix(
|
case OFF -> ModelTemplates.CUBE_ORIENTABLE.createWithSuffix(
|
||||||
block, "_" + state.getSerializedName(),
|
block, "_" + state.getSerializedName(),
|
||||||
@ -184,6 +189,7 @@ public class BlockModelProvider {
|
|||||||
generators.modelOutput
|
generators.modelOutput
|
||||||
);
|
);
|
||||||
}))
|
}))
|
||||||
|
.with(createHorizontalFacingDispatch())
|
||||||
);
|
);
|
||||||
generators.registerSimpleItemModel(block, getModelLocation(block, "_blinking"));
|
generators.registerSimpleItemModel(block, getModelLocation(block, "_blinking"));
|
||||||
}
|
}
|
||||||
@ -193,7 +199,7 @@ public class BlockModelProvider {
|
|||||||
var particleModel = ModelTemplates.PARTICLE_ONLY.createWithSuffix(
|
var particleModel = ModelTemplates.PARTICLE_ONLY.createWithSuffix(
|
||||||
block, "_particle", TextureMapping.particle(getBlockTexture(block, "_front")), generators.modelOutput
|
block, "_particle", TextureMapping.particle(getBlockTexture(block, "_front")), generators.modelOutput
|
||||||
);
|
);
|
||||||
generators.blockStateOutput.accept(BlockModelGenerators.createSimpleBlock(block, particleModel));
|
generators.blockStateOutput.accept(createSimpleBlock(block, plainVariant(particleModel)));
|
||||||
|
|
||||||
// We then register the full model for use in items and the BE renderer.
|
// We then register the full model for use in items and the BE renderer.
|
||||||
var model = TURTLE.create(block, new TextureMapping()
|
var model = TURTLE.create(block, new TextureMapping()
|
||||||
@ -224,17 +230,17 @@ public class BlockModelProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void registerWirelessModem(BlockModelGenerators generators, WirelessModemBlock block) {
|
private static void registerWirelessModem(BlockModelGenerators generators, WirelessModemBlock block) {
|
||||||
generators.blockStateOutput.accept(MultiVariantGenerator.multiVariant(block)
|
generators.blockStateOutput.accept(MultiVariantGenerator.dispatch(block)
|
||||||
.with(createFacingDispatch())
|
|
||||||
.with(createModelDispatch(WirelessModemBlock.ON,
|
.with(createModelDispatch(WirelessModemBlock.ON,
|
||||||
on -> modemModel(generators, getModelLocation(block, on ? "_on" : "_off"), getBlockTexture(block, "_face" + (on ? "_on" : "")))
|
on -> modemModel(generators, getModelLocation(block, on ? "_on" : "_off"), getBlockTexture(block, "_face" + (on ? "_on" : "")))
|
||||||
)));
|
))
|
||||||
|
.with(createFacingDispatch()));
|
||||||
generators.registerSimpleItemModel(block, getModelLocation(block, "_off"));
|
generators.registerSimpleItemModel(block, getModelLocation(block, "_off"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void registerWiredModems(BlockModelGenerators generators) {
|
private static void registerWiredModems(BlockModelGenerators generators) {
|
||||||
var fullBlock = ModRegistry.Blocks.WIRED_MODEM_FULL.get();
|
var fullBlock = ModRegistry.Blocks.WIRED_MODEM_FULL.get();
|
||||||
generators.blockStateOutput.accept(MultiVariantGenerator.multiVariant(fullBlock)
|
generators.blockStateOutput.accept(MultiVariantGenerator.dispatch(fullBlock)
|
||||||
.with(createModelDispatch(WiredModemFullBlock.MODEM_ON, WiredModemFullBlock.PERIPHERAL_ON, (on, peripheral) -> {
|
.with(createModelDispatch(WiredModemFullBlock.MODEM_ON, WiredModemFullBlock.PERIPHERAL_ON, (on, peripheral) -> {
|
||||||
var suffix = (on ? "_on" : "_off") + (peripheral ? "_peripheral" : "");
|
var suffix = (on ? "_on" : "_off") + (peripheral ? "_peripheral" : "");
|
||||||
var faceTexture = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/wired_modem_face" + (peripheral ? "_peripheral" : "") + (on ? "_on" : ""));
|
var faceTexture = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/wired_modem_face" + (peripheral ? "_peripheral" : "") + (on ? "_on" : ""));
|
||||||
@ -281,10 +287,10 @@ public class BlockModelProvider {
|
|||||||
monitorModel(generators, block, "_u", 22, 5, 0, 38);
|
monitorModel(generators, block, "_u", 22, 5, 0, 38);
|
||||||
monitorModel(generators, block, "_ud", 21, 6, 0, 37);
|
monitorModel(generators, block, "_ud", 21, 6, 0, 37);
|
||||||
|
|
||||||
generators.blockStateOutput.accept(MultiVariantGenerator.multiVariant(block)
|
generators.blockStateOutput.accept(MultiVariantGenerator.dispatch(block)
|
||||||
|
.with(createModelDispatch(MonitorBlock.STATE, edge -> getModelLocation(block, edge == MonitorEdgeState.NONE ? "" : "_" + edge.getSerializedName())))
|
||||||
.with(createHorizontalFacingDispatch())
|
.with(createHorizontalFacingDispatch())
|
||||||
.with(createVerticalFacingDispatch(MonitorBlock.ORIENTATION))
|
.with(createVerticalFacingDispatch(MonitorBlock.ORIENTATION))
|
||||||
.with(createModelDispatch(MonitorBlock.STATE, edge -> getModelLocation(block, edge == MonitorEdgeState.NONE ? "" : "_" + edge.getSerializedName())))
|
|
||||||
);
|
);
|
||||||
generators.registerSimpleItemModel(block, monitorModel(generators, block, "_item", 15, 4, 0, 32));
|
generators.registerSimpleItemModel(block, monitorModel(generators, block, "_item", 15, 4, 0, 32));
|
||||||
}
|
}
|
||||||
@ -308,55 +314,54 @@ public class BlockModelProvider {
|
|||||||
var coreFacing = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/cable_core_facing");
|
var coreFacing = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/cable_core_facing");
|
||||||
// Up/Down
|
// Up/Down
|
||||||
generator.with(
|
generator.with(
|
||||||
Condition.or(
|
or(
|
||||||
cableNoNeighbour(Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST).term(CableBlock.UP, true),
|
cableNoNeighbour(Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST).term(CableBlock.UP, true),
|
||||||
cableNoNeighbour(Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST).term(CableBlock.DOWN, true)
|
cableNoNeighbour(Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST).term(CableBlock.DOWN, true)
|
||||||
),
|
),
|
||||||
Variant.variant().with(VariantProperties.MODEL, coreFacing).with(VariantProperties.X_ROT, VariantProperties.Rotation.R90)
|
plainVariant(coreFacing).with(VariantMutator.X_ROT.withValue(Quadrant.R90))
|
||||||
);
|
);
|
||||||
|
|
||||||
// North/South and no neighbours
|
// North/South and no neighbours
|
||||||
generator.with(
|
generator.with(
|
||||||
Condition.or(
|
or(
|
||||||
cableNoNeighbour(Direction.UP, Direction.DOWN, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST),
|
cableNoNeighbour(Direction.UP, Direction.DOWN, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST),
|
||||||
cableNoNeighbour(Direction.UP, Direction.DOWN, Direction.EAST, Direction.WEST).term(CableBlock.NORTH, true),
|
cableNoNeighbour(Direction.UP, Direction.DOWN, Direction.EAST, Direction.WEST).term(CableBlock.NORTH, true),
|
||||||
cableNoNeighbour(Direction.UP, Direction.DOWN, Direction.EAST, Direction.WEST).term(CableBlock.SOUTH, true)
|
cableNoNeighbour(Direction.UP, Direction.DOWN, Direction.EAST, Direction.WEST).term(CableBlock.SOUTH, true)
|
||||||
),
|
),
|
||||||
Variant.variant().with(VariantProperties.MODEL, coreFacing).with(VariantProperties.Y_ROT, VariantProperties.Rotation.R0)
|
plainVariant(coreFacing).with(VariantMutator.Y_ROT.withValue(Quadrant.R0))
|
||||||
);
|
);
|
||||||
|
|
||||||
// East/West
|
// East/West
|
||||||
generator.with(
|
generator.with(
|
||||||
Condition.or(
|
or(
|
||||||
cableNoNeighbour(Direction.NORTH, Direction.SOUTH, Direction.UP, Direction.DOWN).term(CableBlock.EAST, true),
|
cableNoNeighbour(Direction.NORTH, Direction.SOUTH, Direction.UP, Direction.DOWN).term(CableBlock.EAST, true),
|
||||||
cableNoNeighbour(Direction.NORTH, Direction.SOUTH, Direction.UP, Direction.DOWN).term(CableBlock.WEST, true)
|
cableNoNeighbour(Direction.NORTH, Direction.SOUTH, Direction.UP, Direction.DOWN).term(CableBlock.WEST, true)
|
||||||
),
|
),
|
||||||
Variant.variant().with(VariantProperties.MODEL, coreFacing).with(VariantProperties.Y_ROT, VariantProperties.Rotation.R90)
|
plainVariant(coreFacing).with(VariantMutator.Y_ROT.withValue(Quadrant.R90))
|
||||||
);
|
);
|
||||||
|
|
||||||
// Find all other possibilities and emit a "solid" core which doesn't have a facing direction.
|
// Find all other possibilities and emit a "solid" core which doesn't have a facing direction.
|
||||||
var core = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/cable_core_any");
|
var core = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/cable_core_any");
|
||||||
List<Condition.TerminalCondition> rightAngles = new ArrayList<>();
|
List<ConditionBuilder> rightAngles = new ArrayList<>();
|
||||||
for (var i = 0; i < DirectionUtil.FACINGS.length; i++) {
|
for (var i = 0; i < DirectionUtil.FACINGS.length; i++) {
|
||||||
for (var j = i; j < DirectionUtil.FACINGS.length; j++) {
|
for (var j = i; j < DirectionUtil.FACINGS.length; j++) {
|
||||||
if (DirectionUtil.FACINGS[i].getAxis() == DirectionUtil.FACINGS[j].getAxis()) continue;
|
if (DirectionUtil.FACINGS[i].getAxis() == DirectionUtil.FACINGS[j].getAxis()) continue;
|
||||||
|
|
||||||
rightAngles.add(new Condition.TerminalCondition()
|
rightAngles.add(condition()
|
||||||
.term(CableBlock.CABLE, true).term(CABLE_DIRECTIONS[i], true).term(CABLE_DIRECTIONS[j], true)
|
.term(CableBlock.CABLE, true).term(CABLE_DIRECTIONS[i], true).term(CABLE_DIRECTIONS[j], true)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
generator.with(Condition.or(rightAngles.toArray(new Condition[0])), Variant.variant().with(VariantProperties.MODEL, core));
|
generator.with(or(rightAngles.toArray(new ConditionBuilder[0])), plainVariant(core));
|
||||||
|
|
||||||
// Then emit the actual cable arms
|
// Then emit the actual cable arms
|
||||||
var arm = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/cable_arm");
|
var arm = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/cable_arm");
|
||||||
for (var direction : DirectionUtil.FACINGS) {
|
for (var direction : DirectionUtil.FACINGS) {
|
||||||
generator.with(
|
generator.with(
|
||||||
new Condition.TerminalCondition().term(CABLE_DIRECTIONS[direction.ordinal()], true),
|
condition().term(CABLE_DIRECTIONS[direction.ordinal()], true),
|
||||||
Variant.variant()
|
plainVariant(arm)
|
||||||
.with(VariantProperties.MODEL, arm)
|
.with(VariantMutator.X_ROT.withValue(toXAngle(direction.getOpposite())))
|
||||||
.with(VariantProperties.X_ROT, toXAngle(direction.getOpposite()))
|
.with(VariantMutator.Y_ROT.withValue(toYAngle(direction.getOpposite())))
|
||||||
.with(VariantProperties.Y_ROT, toYAngle(direction.getOpposite()))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,11 +371,10 @@ public class BlockModelProvider {
|
|||||||
for (var peripheral : BOOLEANS) {
|
for (var peripheral : BOOLEANS) {
|
||||||
var suffix = (on ? "_on" : "_off") + (peripheral ? "_peripheral" : "");
|
var suffix = (on ? "_on" : "_off") + (peripheral ? "_peripheral" : "");
|
||||||
generator.with(
|
generator.with(
|
||||||
new Condition.TerminalCondition().term(CableBlock.MODEM, CableModemVariant.from(direction, on, peripheral)),
|
condition().term(CableBlock.MODEM, CableModemVariant.from(direction, on, peripheral)),
|
||||||
Variant.variant()
|
plainVariant(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/wired_modem" + suffix))
|
||||||
.with(VariantProperties.MODEL, ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/wired_modem" + suffix))
|
.with(VariantMutator.X_ROT.withValue(toXAngle(direction.getOpposite())))
|
||||||
.with(VariantProperties.X_ROT, toXAngle(direction))
|
.with(VariantMutator.Y_ROT.withValue(toYAngle(direction.getOpposite())))
|
||||||
.with(VariantProperties.Y_ROT, toYAngle(direction))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -390,8 +394,8 @@ public class BlockModelProvider {
|
|||||||
private static final BooleanProperty[] CABLE_DIRECTIONS = { CableBlock.DOWN, CableBlock.UP, CableBlock.NORTH, CableBlock.SOUTH, CableBlock.WEST, CableBlock.EAST };
|
private static final BooleanProperty[] CABLE_DIRECTIONS = { CableBlock.DOWN, CableBlock.UP, CableBlock.NORTH, CableBlock.SOUTH, CableBlock.WEST, CableBlock.EAST };
|
||||||
private static final boolean[] BOOLEANS = new boolean[]{ false, true };
|
private static final boolean[] BOOLEANS = new boolean[]{ false, true };
|
||||||
|
|
||||||
private static Condition.TerminalCondition cableNoNeighbour(Direction... directions) {
|
private static ConditionBuilder cableNoNeighbour(Direction... directions) {
|
||||||
var condition = new Condition.TerminalCondition().term(CableBlock.CABLE, true);
|
var condition = condition().term(CableBlock.CABLE, true);
|
||||||
for (var direction : directions) condition.term(CABLE_DIRECTIONS[direction.ordinal()], false);
|
for (var direction : directions) condition.term(CABLE_DIRECTIONS[direction.ordinal()], false);
|
||||||
return condition;
|
return condition;
|
||||||
}
|
}
|
||||||
@ -418,66 +422,60 @@ public class BlockModelProvider {
|
|||||||
generators.registerSimpleItemModel(block, ModelLocationUtils.getModelLocation(block));
|
generators.registerSimpleItemModel(block, ModelLocationUtils.getModelLocation(block));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static VariantProperties.Rotation toXAngle(Direction direction) {
|
private static Quadrant toXAngle(Direction direction) {
|
||||||
return switch (direction) {
|
return switch (direction) {
|
||||||
default -> VariantProperties.Rotation.R0;
|
default -> Quadrant.R0;
|
||||||
case UP -> VariantProperties.Rotation.R270;
|
case UP -> Quadrant.R270;
|
||||||
case DOWN -> VariantProperties.Rotation.R90;
|
case DOWN -> Quadrant.R90;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static VariantProperties.Rotation toYAngle(Direction direction) {
|
private static Quadrant toYAngle(Direction direction) {
|
||||||
return switch (direction) {
|
return switch (direction) {
|
||||||
default -> VariantProperties.Rotation.R0;
|
default -> Quadrant.R0;
|
||||||
case NORTH -> VariantProperties.Rotation.R0;
|
case NORTH -> Quadrant.R0;
|
||||||
case SOUTH -> VariantProperties.Rotation.R180;
|
case SOUTH -> Quadrant.R180;
|
||||||
case EAST -> VariantProperties.Rotation.R90;
|
case EAST -> Quadrant.R90;
|
||||||
case WEST -> VariantProperties.Rotation.R270;
|
case WEST -> Quadrant.R270;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PropertyDispatch createHorizontalFacingDispatch() {
|
private static PropertyDispatch<VariantMutator> createHorizontalFacingDispatch() {
|
||||||
var dispatch = PropertyDispatch.property(BlockStateProperties.HORIZONTAL_FACING);
|
/*var dispatch = PropertyDispatch.modify(BlockStateProperties.HORIZONTAL_FACING);
|
||||||
for (var direction : BlockStateProperties.HORIZONTAL_FACING.getPossibleValues()) {
|
for (var direction : BlockStateProperties.HORIZONTAL_FACING.getPossibleValues()) {
|
||||||
dispatch.select(direction, Variant.variant().with(VariantProperties.Y_ROT, toYAngle(direction)));
|
dispatch.select(direction, Variant.variant().with(VariantProperties.Y_ROT, toYAngle(direction)));
|
||||||
}
|
}
|
||||||
return dispatch;
|
return dispatch;*/
|
||||||
|
return BlockModelGenerators.ROTATION_HORIZONTAL_FACING;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PropertyDispatch createVerticalFacingDispatch(Property<Direction> property) {
|
private static PropertyDispatch<VariantMutator> createVerticalFacingDispatch(Property<Direction> property) {
|
||||||
var dispatch = PropertyDispatch.property(property);
|
var dispatch = PropertyDispatch.modify(property);
|
||||||
for (var direction : property.getPossibleValues()) {
|
for (var direction : property.getPossibleValues()) {
|
||||||
dispatch.select(direction, Variant.variant().with(VariantProperties.X_ROT, toXAngle(direction)));
|
dispatch.select(direction, VariantMutator.X_ROT.withValue(toXAngle(direction)));
|
||||||
}
|
}
|
||||||
return dispatch;
|
return dispatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PropertyDispatch createFacingDispatch() {
|
private static PropertyDispatch<VariantMutator> createFacingDispatch() {
|
||||||
var dispatch = PropertyDispatch.property(BlockStateProperties.FACING);
|
return BlockModelGenerators.ROTATION_FACING;
|
||||||
for (var direction : BlockStateProperties.FACING.getPossibleValues()) {
|
|
||||||
dispatch.select(direction, Variant.variant()
|
|
||||||
.with(VariantProperties.Y_ROT, toYAngle(direction))
|
|
||||||
.with(VariantProperties.X_ROT, toXAngle(direction))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return dispatch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends Comparable<T>> PropertyDispatch createModelDispatch(Property<T> property, Function<T, ResourceLocation> makeModel) {
|
private static <T extends Comparable<T>> PropertyDispatch<MultiVariant> createModelDispatch(Property<T> property, Function<T, ResourceLocation> makeModel) {
|
||||||
var variant = PropertyDispatch.property(property);
|
var variant = PropertyDispatch.initial(property);
|
||||||
for (var value : property.getPossibleValues()) {
|
for (var value : property.getPossibleValues()) {
|
||||||
variant.select(value, Variant.variant().with(VariantProperties.MODEL, makeModel.apply(value)));
|
variant.select(value, plainVariant(makeModel.apply(value)));
|
||||||
}
|
}
|
||||||
return variant;
|
return variant;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends Comparable<T>, U extends Comparable<U>> PropertyDispatch createModelDispatch(
|
private static <T extends Comparable<T>, U extends Comparable<U>> PropertyDispatch<MultiVariant> createModelDispatch(
|
||||||
Property<T> propertyT, Property<U> propertyU, BiFunction<T, U, ResourceLocation> makeModel
|
Property<T> propertyT, Property<U> propertyU, BiFunction<T, U, ResourceLocation> makeModel
|
||||||
) {
|
) {
|
||||||
var variant = PropertyDispatch.properties(propertyT, propertyU);
|
var variant = PropertyDispatch.initial(propertyT, propertyU);
|
||||||
for (var valueT : propertyT.getPossibleValues()) {
|
for (var valueT : propertyT.getPossibleValues()) {
|
||||||
for (var valueU : propertyU.getPossibleValues()) {
|
for (var valueU : propertyU.getPossibleValues()) {
|
||||||
variant.select(valueT, valueU, Variant.variant().with(VariantProperties.MODEL, makeModel.apply(valueT, valueU)));
|
variant.select(valueT, valueU, plainVariant(makeModel.apply(valueT, valueU)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return variant;
|
return variant;
|
||||||
|
@ -28,7 +28,7 @@ public class BrewingStandPeripheral implements IPeripheral {
|
|||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final int getFuel() {
|
public final int getFuel() {
|
||||||
// Don't do it this way! Use an access widener/transformer to access the "fuel" field instead.
|
// Don't do it this way! Use an access widener/transformer to access the "fuel" field instead.
|
||||||
return brewingStand.saveWithoutMetadata(brewingStand.getLevel().registryAccess()).getInt("Fuel");
|
return brewingStand.saveWithoutMetadata(brewingStand.getLevel().registryAccess()).getByteOr("Fuel", (byte) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -23,7 +23,7 @@ public class FurnacePeripheral implements GenericPeripheral {
|
|||||||
@LuaFunction(mainThread = true)
|
@LuaFunction(mainThread = true)
|
||||||
public int getBurnTime(AbstractFurnaceBlockEntity furnace) {
|
public int getBurnTime(AbstractFurnaceBlockEntity furnace) {
|
||||||
// Don't do it this way! Use an access widener/transformer to access the "litTime" field instead.
|
// Don't do it this way! Use an access widener/transformer to access the "litTime" field instead.
|
||||||
return furnace.saveWithoutMetadata(furnace.getLevel().registryAccess()).getInt("BurnTime");
|
return furnace.saveWithoutMetadata(furnace.getLevel().registryAccess()).getShortOr("lit_time_remaining", (short) 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// @end region=body
|
// @end region=body
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"apply": {"model": "computercraft:block/cable_core_facing", "y": 0},
|
"apply": {"model": "computercraft:block/cable_core_facing"},
|
||||||
"when": {
|
"when": {
|
||||||
"OR": [
|
"OR": [
|
||||||
{
|
{
|
||||||
@ -55,70 +55,70 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"apply": {"model": "computercraft:block/cable_arm", "x": 270, "y": 0}, "when": {"down": "true"}},
|
{"apply": {"model": "computercraft:block/cable_arm", "x": 270}, "when": {"down": "true"}},
|
||||||
{"apply": {"model": "computercraft:block/cable_arm", "x": 90, "y": 0}, "when": {"up": "true"}},
|
{"apply": {"model": "computercraft:block/cable_arm", "x": 90}, "when": {"up": "true"}},
|
||||||
{"apply": {"model": "computercraft:block/cable_arm", "x": 0, "y": 180}, "when": {"north": "true"}},
|
{"apply": {"model": "computercraft:block/cable_arm", "y": 180}, "when": {"north": "true"}},
|
||||||
{"apply": {"model": "computercraft:block/cable_arm", "x": 0, "y": 0}, "when": {"south": "true"}},
|
{"apply": {"model": "computercraft:block/cable_arm"}, "when": {"south": "true"}},
|
||||||
{"apply": {"model": "computercraft:block/cable_arm", "x": 0, "y": 90}, "when": {"west": "true"}},
|
{"apply": {"model": "computercraft:block/cable_arm", "y": 90}, "when": {"west": "true"}},
|
||||||
{"apply": {"model": "computercraft:block/cable_arm", "x": 0, "y": 270}, "when": {"east": "true"}},
|
{"apply": {"model": "computercraft:block/cable_arm", "y": 270}, "when": {"east": "true"}},
|
||||||
{"apply": {"model": "computercraft:block/wired_modem_off", "x": 90, "y": 0}, "when": {"modem": "down_off"}},
|
{"apply": {"model": "computercraft:block/wired_modem_off", "x": 270}, "when": {"modem": "down_off"}},
|
||||||
{
|
{
|
||||||
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "x": 90, "y": 0},
|
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "x": 270},
|
||||||
"when": {"modem": "down_off_peripheral"}
|
"when": {"modem": "down_off_peripheral"}
|
||||||
},
|
},
|
||||||
{"apply": {"model": "computercraft:block/wired_modem_on", "x": 90, "y": 0}, "when": {"modem": "down_on"}},
|
{"apply": {"model": "computercraft:block/wired_modem_on", "x": 270}, "when": {"modem": "down_on"}},
|
||||||
{
|
{
|
||||||
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "x": 90, "y": 0},
|
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "x": 270},
|
||||||
"when": {"modem": "down_on_peripheral"}
|
"when": {"modem": "down_on_peripheral"}
|
||||||
},
|
},
|
||||||
{"apply": {"model": "computercraft:block/wired_modem_off", "x": 270, "y": 0}, "when": {"modem": "up_off"}},
|
{"apply": {"model": "computercraft:block/wired_modem_off", "x": 90}, "when": {"modem": "up_off"}},
|
||||||
{
|
{
|
||||||
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "x": 270, "y": 0},
|
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "x": 90},
|
||||||
"when": {"modem": "up_off_peripheral"}
|
"when": {"modem": "up_off_peripheral"}
|
||||||
},
|
},
|
||||||
{"apply": {"model": "computercraft:block/wired_modem_on", "x": 270, "y": 0}, "when": {"modem": "up_on"}},
|
{"apply": {"model": "computercraft:block/wired_modem_on", "x": 90}, "when": {"modem": "up_on"}},
|
||||||
{
|
{
|
||||||
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "x": 270, "y": 0},
|
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "x": 90},
|
||||||
"when": {"modem": "up_on_peripheral"}
|
"when": {"modem": "up_on_peripheral"}
|
||||||
},
|
},
|
||||||
{"apply": {"model": "computercraft:block/wired_modem_off", "x": 0, "y": 0}, "when": {"modem": "north_off"}},
|
{"apply": {"model": "computercraft:block/wired_modem_off", "y": 180}, "when": {"modem": "north_off"}},
|
||||||
{
|
{
|
||||||
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "x": 0, "y": 0},
|
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "y": 180},
|
||||||
"when": {"modem": "north_off_peripheral"}
|
"when": {"modem": "north_off_peripheral"}
|
||||||
},
|
},
|
||||||
{"apply": {"model": "computercraft:block/wired_modem_on", "x": 0, "y": 0}, "when": {"modem": "north_on"}},
|
{"apply": {"model": "computercraft:block/wired_modem_on", "y": 180}, "when": {"modem": "north_on"}},
|
||||||
{
|
{
|
||||||
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "x": 0, "y": 0},
|
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "y": 180},
|
||||||
"when": {"modem": "north_on_peripheral"}
|
"when": {"modem": "north_on_peripheral"}
|
||||||
},
|
},
|
||||||
{"apply": {"model": "computercraft:block/wired_modem_off", "x": 0, "y": 180}, "when": {"modem": "south_off"}},
|
{"apply": {"model": "computercraft:block/wired_modem_off"}, "when": {"modem": "south_off"}},
|
||||||
{
|
{
|
||||||
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "x": 0, "y": 180},
|
"apply": {"model": "computercraft:block/wired_modem_off_peripheral"},
|
||||||
"when": {"modem": "south_off_peripheral"}
|
"when": {"modem": "south_off_peripheral"}
|
||||||
},
|
},
|
||||||
{"apply": {"model": "computercraft:block/wired_modem_on", "x": 0, "y": 180}, "when": {"modem": "south_on"}},
|
{"apply": {"model": "computercraft:block/wired_modem_on"}, "when": {"modem": "south_on"}},
|
||||||
{
|
{
|
||||||
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "x": 0, "y": 180},
|
"apply": {"model": "computercraft:block/wired_modem_on_peripheral"},
|
||||||
"when": {"modem": "south_on_peripheral"}
|
"when": {"modem": "south_on_peripheral"}
|
||||||
},
|
},
|
||||||
{"apply": {"model": "computercraft:block/wired_modem_off", "x": 0, "y": 270}, "when": {"modem": "west_off"}},
|
{"apply": {"model": "computercraft:block/wired_modem_off", "y": 90}, "when": {"modem": "west_off"}},
|
||||||
{
|
{
|
||||||
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "x": 0, "y": 270},
|
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "y": 90},
|
||||||
"when": {"modem": "west_off_peripheral"}
|
"when": {"modem": "west_off_peripheral"}
|
||||||
},
|
},
|
||||||
{"apply": {"model": "computercraft:block/wired_modem_on", "x": 0, "y": 270}, "when": {"modem": "west_on"}},
|
{"apply": {"model": "computercraft:block/wired_modem_on", "y": 90}, "when": {"modem": "west_on"}},
|
||||||
{
|
{
|
||||||
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "x": 0, "y": 270},
|
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "y": 90},
|
||||||
"when": {"modem": "west_on_peripheral"}
|
"when": {"modem": "west_on_peripheral"}
|
||||||
},
|
},
|
||||||
{"apply": {"model": "computercraft:block/wired_modem_off", "x": 0, "y": 90}, "when": {"modem": "east_off"}},
|
{"apply": {"model": "computercraft:block/wired_modem_off", "y": 270}, "when": {"modem": "east_off"}},
|
||||||
{
|
{
|
||||||
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "x": 0, "y": 90},
|
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "y": 270},
|
||||||
"when": {"modem": "east_off_peripheral"}
|
"when": {"modem": "east_off_peripheral"}
|
||||||
},
|
},
|
||||||
{"apply": {"model": "computercraft:block/wired_modem_on", "x": 0, "y": 90}, "when": {"modem": "east_on"}},
|
{"apply": {"model": "computercraft:block/wired_modem_on", "y": 270}, "when": {"modem": "east_on"}},
|
||||||
{
|
{
|
||||||
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "x": 0, "y": 90},
|
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "y": 270},
|
||||||
"when": {"modem": "east_on_peripheral"}
|
"when": {"modem": "east_on_peripheral"}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
"facing=east,state=blinking": {"model": "computercraft:block/computer_advanced_blinking", "y": 90},
|
"facing=east,state=blinking": {"model": "computercraft:block/computer_advanced_blinking", "y": 90},
|
||||||
"facing=east,state=off": {"model": "computercraft:block/computer_advanced_off", "y": 90},
|
"facing=east,state=off": {"model": "computercraft:block/computer_advanced_off", "y": 90},
|
||||||
"facing=east,state=on": {"model": "computercraft:block/computer_advanced_on", "y": 90},
|
"facing=east,state=on": {"model": "computercraft:block/computer_advanced_on", "y": 90},
|
||||||
"facing=north,state=blinking": {"model": "computercraft:block/computer_advanced_blinking", "y": 0},
|
"facing=north,state=blinking": {"model": "computercraft:block/computer_advanced_blinking"},
|
||||||
"facing=north,state=off": {"model": "computercraft:block/computer_advanced_off", "y": 0},
|
"facing=north,state=off": {"model": "computercraft:block/computer_advanced_off"},
|
||||||
"facing=north,state=on": {"model": "computercraft:block/computer_advanced_on", "y": 0},
|
"facing=north,state=on": {"model": "computercraft:block/computer_advanced_on"},
|
||||||
"facing=south,state=blinking": {"model": "computercraft:block/computer_advanced_blinking", "y": 180},
|
"facing=south,state=blinking": {"model": "computercraft:block/computer_advanced_blinking", "y": 180},
|
||||||
"facing=south,state=off": {"model": "computercraft:block/computer_advanced_off", "y": 180},
|
"facing=south,state=off": {"model": "computercraft:block/computer_advanced_off", "y": 180},
|
||||||
"facing=south,state=on": {"model": "computercraft:block/computer_advanced_on", "y": 180},
|
"facing=south,state=on": {"model": "computercraft:block/computer_advanced_on", "y": 180},
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
"facing=east,state=blinking": {"model": "computercraft:block/computer_command_blinking", "y": 90},
|
"facing=east,state=blinking": {"model": "computercraft:block/computer_command_blinking", "y": 90},
|
||||||
"facing=east,state=off": {"model": "computercraft:block/computer_command_off", "y": 90},
|
"facing=east,state=off": {"model": "computercraft:block/computer_command_off", "y": 90},
|
||||||
"facing=east,state=on": {"model": "computercraft:block/computer_command_on", "y": 90},
|
"facing=east,state=on": {"model": "computercraft:block/computer_command_on", "y": 90},
|
||||||
"facing=north,state=blinking": {"model": "computercraft:block/computer_command_blinking", "y": 0},
|
"facing=north,state=blinking": {"model": "computercraft:block/computer_command_blinking"},
|
||||||
"facing=north,state=off": {"model": "computercraft:block/computer_command_off", "y": 0},
|
"facing=north,state=off": {"model": "computercraft:block/computer_command_off"},
|
||||||
"facing=north,state=on": {"model": "computercraft:block/computer_command_on", "y": 0},
|
"facing=north,state=on": {"model": "computercraft:block/computer_command_on"},
|
||||||
"facing=south,state=blinking": {"model": "computercraft:block/computer_command_blinking", "y": 180},
|
"facing=south,state=blinking": {"model": "computercraft:block/computer_command_blinking", "y": 180},
|
||||||
"facing=south,state=off": {"model": "computercraft:block/computer_command_off", "y": 180},
|
"facing=south,state=off": {"model": "computercraft:block/computer_command_off", "y": 180},
|
||||||
"facing=south,state=on": {"model": "computercraft:block/computer_command_on", "y": 180},
|
"facing=south,state=on": {"model": "computercraft:block/computer_command_on", "y": 180},
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
"facing=east,state=blinking": {"model": "computercraft:block/computer_normal_blinking", "y": 90},
|
"facing=east,state=blinking": {"model": "computercraft:block/computer_normal_blinking", "y": 90},
|
||||||
"facing=east,state=off": {"model": "computercraft:block/computer_normal_off", "y": 90},
|
"facing=east,state=off": {"model": "computercraft:block/computer_normal_off", "y": 90},
|
||||||
"facing=east,state=on": {"model": "computercraft:block/computer_normal_on", "y": 90},
|
"facing=east,state=on": {"model": "computercraft:block/computer_normal_on", "y": 90},
|
||||||
"facing=north,state=blinking": {"model": "computercraft:block/computer_normal_blinking", "y": 0},
|
"facing=north,state=blinking": {"model": "computercraft:block/computer_normal_blinking"},
|
||||||
"facing=north,state=off": {"model": "computercraft:block/computer_normal_off", "y": 0},
|
"facing=north,state=off": {"model": "computercraft:block/computer_normal_off"},
|
||||||
"facing=north,state=on": {"model": "computercraft:block/computer_normal_on", "y": 0},
|
"facing=north,state=on": {"model": "computercraft:block/computer_normal_on"},
|
||||||
"facing=south,state=blinking": {"model": "computercraft:block/computer_normal_blinking", "y": 180},
|
"facing=south,state=blinking": {"model": "computercraft:block/computer_normal_blinking", "y": 180},
|
||||||
"facing=south,state=off": {"model": "computercraft:block/computer_normal_off", "y": 180},
|
"facing=south,state=off": {"model": "computercraft:block/computer_normal_off", "y": 180},
|
||||||
"facing=south,state=on": {"model": "computercraft:block/computer_normal_on", "y": 180},
|
"facing=south,state=on": {"model": "computercraft:block/computer_normal_on", "y": 180},
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
"facing=east,state=empty": {"model": "computercraft:block/disk_drive_empty", "y": 90},
|
"facing=east,state=empty": {"model": "computercraft:block/disk_drive_empty", "y": 90},
|
||||||
"facing=east,state=full": {"model": "computercraft:block/disk_drive_full", "y": 90},
|
"facing=east,state=full": {"model": "computercraft:block/disk_drive_full", "y": 90},
|
||||||
"facing=east,state=invalid": {"model": "computercraft:block/disk_drive_invalid", "y": 90},
|
"facing=east,state=invalid": {"model": "computercraft:block/disk_drive_invalid", "y": 90},
|
||||||
"facing=north,state=empty": {"model": "computercraft:block/disk_drive_empty", "y": 0},
|
"facing=north,state=empty": {"model": "computercraft:block/disk_drive_empty"},
|
||||||
"facing=north,state=full": {"model": "computercraft:block/disk_drive_full", "y": 0},
|
"facing=north,state=full": {"model": "computercraft:block/disk_drive_full"},
|
||||||
"facing=north,state=invalid": {"model": "computercraft:block/disk_drive_invalid", "y": 0},
|
"facing=north,state=invalid": {"model": "computercraft:block/disk_drive_invalid"},
|
||||||
"facing=south,state=empty": {"model": "computercraft:block/disk_drive_empty", "y": 180},
|
"facing=south,state=empty": {"model": "computercraft:block/disk_drive_empty", "y": 180},
|
||||||
"facing=south,state=full": {"model": "computercraft:block/disk_drive_full", "y": 180},
|
"facing=south,state=full": {"model": "computercraft:block/disk_drive_full", "y": 180},
|
||||||
"facing=south,state=invalid": {"model": "computercraft:block/disk_drive_invalid", "y": 180},
|
"facing=south,state=invalid": {"model": "computercraft:block/disk_drive_invalid", "y": 180},
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"variants": {
|
"variants": {
|
||||||
"facing=east": {"model": "minecraft:block/lectern", "y": 90},
|
"facing=east": {"model": "minecraft:block/lectern", "y": 90},
|
||||||
"facing=north": {"model": "minecraft:block/lectern", "y": 0},
|
"facing=north": {"model": "minecraft:block/lectern"},
|
||||||
"facing=south": {"model": "minecraft:block/lectern", "y": 180},
|
"facing=south": {"model": "minecraft:block/lectern", "y": 180},
|
||||||
"facing=west": {"model": "minecraft:block/lectern", "y": 270}
|
"facing=west": {"model": "minecraft:block/lectern", "y": 270}
|
||||||
}
|
}
|
||||||
|
@ -20,26 +20,22 @@
|
|||||||
"facing=east,orientation=down,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 90, "y": 90},
|
"facing=east,orientation=down,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 90, "y": 90},
|
||||||
"facing=east,orientation=down,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 90, "y": 90},
|
"facing=east,orientation=down,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 90, "y": 90},
|
||||||
"facing=east,orientation=down,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 90, "y": 90},
|
"facing=east,orientation=down,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 90, "y": 90},
|
||||||
"facing=east,orientation=north,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=d": {"model": "computercraft:block/monitor_advanced_d", "y": 90},
|
||||||
"facing=east,orientation=north,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=l": {"model": "computercraft:block/monitor_advanced_l", "y": 90},
|
||||||
"facing=east,orientation=north,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "y": 90},
|
||||||
"facing=east,orientation=north,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "y": 90},
|
||||||
"facing=east,orientation=north,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "y": 90},
|
||||||
"facing=east,orientation=north,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "y": 90},
|
||||||
"facing=east,orientation=north,state=lrud": {
|
"facing=east,orientation=north,state=lrud": {"model": "computercraft:block/monitor_advanced_lrud", "y": 90},
|
||||||
"model": "computercraft:block/monitor_advanced_lrud",
|
"facing=east,orientation=north,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "y": 90},
|
||||||
"x": 0,
|
"facing=east,orientation=north,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "y": 90},
|
||||||
"y": 90
|
"facing=east,orientation=north,state=none": {"model": "computercraft:block/monitor_advanced", "y": 90},
|
||||||
},
|
"facing=east,orientation=north,state=r": {"model": "computercraft:block/monitor_advanced_r", "y": 90},
|
||||||
"facing=east,orientation=north,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "y": 90},
|
||||||
"facing=east,orientation=north,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "y": 90},
|
||||||
"facing=east,orientation=north,state=none": {"model": "computercraft:block/monitor_advanced", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "y": 90},
|
||||||
"facing=east,orientation=north,state=r": {"model": "computercraft:block/monitor_advanced_r", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=u": {"model": "computercraft:block/monitor_advanced_u", "y": 90},
|
||||||
"facing=east,orientation=north,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "y": 90},
|
||||||
"facing=east,orientation=north,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "x": 0, "y": 90},
|
|
||||||
"facing=east,orientation=north,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 0, "y": 90},
|
|
||||||
"facing=east,orientation=north,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 0, "y": 90},
|
|
||||||
"facing=east,orientation=north,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 0, "y": 90},
|
|
||||||
"facing=east,orientation=up,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 270, "y": 90},
|
"facing=east,orientation=up,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 270, "y": 90},
|
||||||
"facing=east,orientation=up,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 270, "y": 90},
|
"facing=east,orientation=up,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 270, "y": 90},
|
||||||
"facing=east,orientation=up,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 270, "y": 90},
|
"facing=east,orientation=up,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 270, "y": 90},
|
||||||
@ -56,62 +52,54 @@
|
|||||||
"facing=east,orientation=up,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 270, "y": 90},
|
"facing=east,orientation=up,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 270, "y": 90},
|
||||||
"facing=east,orientation=up,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 270, "y": 90},
|
"facing=east,orientation=up,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 270, "y": 90},
|
||||||
"facing=east,orientation=up,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 270, "y": 90},
|
"facing=east,orientation=up,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 270, "y": 90},
|
||||||
"facing=north,orientation=down,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 90},
|
||||||
"facing=north,orientation=down,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 90},
|
||||||
"facing=north,orientation=down,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 90},
|
||||||
"facing=north,orientation=down,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 90},
|
||||||
"facing=north,orientation=down,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "x": 90},
|
||||||
"facing=north,orientation=down,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "x": 90},
|
||||||
"facing=north,orientation=down,state=lrud": {
|
"facing=north,orientation=down,state=lrud": {"model": "computercraft:block/monitor_advanced_lrud", "x": 90},
|
||||||
"model": "computercraft:block/monitor_advanced_lrud",
|
"facing=north,orientation=down,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 90},
|
||||||
"x": 90,
|
"facing=north,orientation=down,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "x": 90},
|
||||||
"y": 0
|
"facing=north,orientation=down,state=none": {"model": "computercraft:block/monitor_advanced", "x": 90},
|
||||||
},
|
"facing=north,orientation=down,state=r": {"model": "computercraft:block/monitor_advanced_r", "x": 90},
|
||||||
"facing=north,orientation=down,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "x": 90},
|
||||||
"facing=north,orientation=down,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "x": 90},
|
||||||
"facing=north,orientation=down,state=none": {"model": "computercraft:block/monitor_advanced", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 90},
|
||||||
"facing=north,orientation=down,state=r": {"model": "computercraft:block/monitor_advanced_r", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 90},
|
||||||
"facing=north,orientation=down,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 90},
|
||||||
"facing=north,orientation=down,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "x": 90, "y": 0},
|
"facing=north,orientation=north,state=d": {"model": "computercraft:block/monitor_advanced_d"},
|
||||||
"facing=north,orientation=down,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 90, "y": 0},
|
"facing=north,orientation=north,state=l": {"model": "computercraft:block/monitor_advanced_l"},
|
||||||
"facing=north,orientation=down,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 90, "y": 0},
|
"facing=north,orientation=north,state=ld": {"model": "computercraft:block/monitor_advanced_ld"},
|
||||||
"facing=north,orientation=down,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 90, "y": 0},
|
"facing=north,orientation=north,state=lr": {"model": "computercraft:block/monitor_advanced_lr"},
|
||||||
"facing=north,orientation=north,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd"},
|
||||||
"facing=north,orientation=north,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=lru": {"model": "computercraft:block/monitor_advanced_lru"},
|
||||||
"facing=north,orientation=north,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=lrud": {"model": "computercraft:block/monitor_advanced_lrud"},
|
||||||
"facing=north,orientation=north,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=lu": {"model": "computercraft:block/monitor_advanced_lu"},
|
||||||
"facing=north,orientation=north,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=lud": {"model": "computercraft:block/monitor_advanced_lud"},
|
||||||
"facing=north,orientation=north,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=none": {"model": "computercraft:block/monitor_advanced"},
|
||||||
"facing=north,orientation=north,state=lrud": {
|
"facing=north,orientation=north,state=r": {"model": "computercraft:block/monitor_advanced_r"},
|
||||||
"model": "computercraft:block/monitor_advanced_lrud",
|
"facing=north,orientation=north,state=rd": {"model": "computercraft:block/monitor_advanced_rd"},
|
||||||
"x": 0,
|
"facing=north,orientation=north,state=ru": {"model": "computercraft:block/monitor_advanced_ru"},
|
||||||
"y": 0
|
"facing=north,orientation=north,state=rud": {"model": "computercraft:block/monitor_advanced_rud"},
|
||||||
},
|
"facing=north,orientation=north,state=u": {"model": "computercraft:block/monitor_advanced_u"},
|
||||||
"facing=north,orientation=north,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=ud": {"model": "computercraft:block/monitor_advanced_ud"},
|
||||||
"facing=north,orientation=north,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "x": 0, "y": 0},
|
"facing=north,orientation=up,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 270},
|
||||||
"facing=north,orientation=north,state=none": {"model": "computercraft:block/monitor_advanced", "x": 0, "y": 0},
|
"facing=north,orientation=up,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 270},
|
||||||
"facing=north,orientation=north,state=r": {"model": "computercraft:block/monitor_advanced_r", "x": 0, "y": 0},
|
"facing=north,orientation=up,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 270},
|
||||||
"facing=north,orientation=north,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "x": 0, "y": 0},
|
"facing=north,orientation=up,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 270},
|
||||||
"facing=north,orientation=north,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "x": 0, "y": 0},
|
"facing=north,orientation=up,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "x": 270},
|
||||||
"facing=north,orientation=north,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 0, "y": 0},
|
"facing=north,orientation=up,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "x": 270},
|
||||||
"facing=north,orientation=north,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 0, "y": 0},
|
"facing=north,orientation=up,state=lrud": {"model": "computercraft:block/monitor_advanced_lrud", "x": 270},
|
||||||
"facing=north,orientation=north,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 0, "y": 0},
|
"facing=north,orientation=up,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 270},
|
||||||
"facing=north,orientation=up,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "x": 270},
|
||||||
"facing=north,orientation=up,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=none": {"model": "computercraft:block/monitor_advanced", "x": 270},
|
||||||
"facing=north,orientation=up,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=r": {"model": "computercraft:block/monitor_advanced_r", "x": 270},
|
||||||
"facing=north,orientation=up,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "x": 270},
|
||||||
"facing=north,orientation=up,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "x": 270},
|
||||||
"facing=north,orientation=up,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 270},
|
||||||
"facing=north,orientation=up,state=lrud": {"model": "computercraft:block/monitor_advanced_lrud", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 270},
|
||||||
"facing=north,orientation=up,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 270},
|
||||||
"facing=north,orientation=up,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "x": 270, "y": 0},
|
|
||||||
"facing=north,orientation=up,state=none": {"model": "computercraft:block/monitor_advanced", "x": 270, "y": 0},
|
|
||||||
"facing=north,orientation=up,state=r": {"model": "computercraft:block/monitor_advanced_r", "x": 270, "y": 0},
|
|
||||||
"facing=north,orientation=up,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "x": 270, "y": 0},
|
|
||||||
"facing=north,orientation=up,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "x": 270, "y": 0},
|
|
||||||
"facing=north,orientation=up,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 270, "y": 0},
|
|
||||||
"facing=north,orientation=up,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 270, "y": 0},
|
|
||||||
"facing=north,orientation=up,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 270, "y": 0},
|
|
||||||
"facing=south,orientation=down,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 90, "y": 180},
|
"facing=south,orientation=down,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 90, "y": 180},
|
||||||
"facing=south,orientation=down,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 90, "y": 180},
|
"facing=south,orientation=down,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 90, "y": 180},
|
||||||
"facing=south,orientation=down,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 90, "y": 180},
|
"facing=south,orientation=down,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 90, "y": 180},
|
||||||
@ -148,42 +136,22 @@
|
|||||||
},
|
},
|
||||||
"facing=south,orientation=down,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 90, "y": 180},
|
"facing=south,orientation=down,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 90, "y": 180},
|
||||||
"facing=south,orientation=down,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 90, "y": 180},
|
"facing=south,orientation=down,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 90, "y": 180},
|
||||||
"facing=south,orientation=north,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=d": {"model": "computercraft:block/monitor_advanced_d", "y": 180},
|
||||||
"facing=south,orientation=north,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=l": {"model": "computercraft:block/monitor_advanced_l", "y": 180},
|
||||||
"facing=south,orientation=north,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "y": 180},
|
||||||
"facing=south,orientation=north,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "y": 180},
|
||||||
"facing=south,orientation=north,state=lrd": {
|
"facing=south,orientation=north,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "y": 180},
|
||||||
"model": "computercraft:block/monitor_advanced_lrd",
|
"facing=south,orientation=north,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "y": 180},
|
||||||
"x": 0,
|
"facing=south,orientation=north,state=lrud": {"model": "computercraft:block/monitor_advanced_lrud", "y": 180},
|
||||||
"y": 180
|
"facing=south,orientation=north,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "y": 180},
|
||||||
},
|
"facing=south,orientation=north,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "y": 180},
|
||||||
"facing=south,orientation=north,state=lru": {
|
"facing=south,orientation=north,state=none": {"model": "computercraft:block/monitor_advanced", "y": 180},
|
||||||
"model": "computercraft:block/monitor_advanced_lru",
|
"facing=south,orientation=north,state=r": {"model": "computercraft:block/monitor_advanced_r", "y": 180},
|
||||||
"x": 0,
|
"facing=south,orientation=north,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "y": 180},
|
||||||
"y": 180
|
"facing=south,orientation=north,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "y": 180},
|
||||||
},
|
"facing=south,orientation=north,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "y": 180},
|
||||||
"facing=south,orientation=north,state=lrud": {
|
"facing=south,orientation=north,state=u": {"model": "computercraft:block/monitor_advanced_u", "y": 180},
|
||||||
"model": "computercraft:block/monitor_advanced_lrud",
|
"facing=south,orientation=north,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "y": 180},
|
||||||
"x": 0,
|
|
||||||
"y": 180
|
|
||||||
},
|
|
||||||
"facing=south,orientation=north,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 0, "y": 180},
|
|
||||||
"facing=south,orientation=north,state=lud": {
|
|
||||||
"model": "computercraft:block/monitor_advanced_lud",
|
|
||||||
"x": 0,
|
|
||||||
"y": 180
|
|
||||||
},
|
|
||||||
"facing=south,orientation=north,state=none": {"model": "computercraft:block/monitor_advanced", "x": 0, "y": 180},
|
|
||||||
"facing=south,orientation=north,state=r": {"model": "computercraft:block/monitor_advanced_r", "x": 0, "y": 180},
|
|
||||||
"facing=south,orientation=north,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "x": 0, "y": 180},
|
|
||||||
"facing=south,orientation=north,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "x": 0, "y": 180},
|
|
||||||
"facing=south,orientation=north,state=rud": {
|
|
||||||
"model": "computercraft:block/monitor_advanced_rud",
|
|
||||||
"x": 0,
|
|
||||||
"y": 180
|
|
||||||
},
|
|
||||||
"facing=south,orientation=north,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 0, "y": 180},
|
|
||||||
"facing=south,orientation=north,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 0, "y": 180},
|
|
||||||
"facing=south,orientation=up,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 270, "y": 180},
|
"facing=south,orientation=up,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 270, "y": 180},
|
||||||
"facing=south,orientation=up,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 270, "y": 180},
|
"facing=south,orientation=up,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 270, "y": 180},
|
||||||
"facing=south,orientation=up,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 270, "y": 180},
|
"facing=south,orientation=up,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 270, "y": 180},
|
||||||
@ -224,26 +192,22 @@
|
|||||||
"facing=west,orientation=down,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 90, "y": 270},
|
"facing=west,orientation=down,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 90, "y": 270},
|
||||||
"facing=west,orientation=down,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 90, "y": 270},
|
"facing=west,orientation=down,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 90, "y": 270},
|
||||||
"facing=west,orientation=down,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 90, "y": 270},
|
"facing=west,orientation=down,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 90, "y": 270},
|
||||||
"facing=west,orientation=north,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=d": {"model": "computercraft:block/monitor_advanced_d", "y": 270},
|
||||||
"facing=west,orientation=north,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=l": {"model": "computercraft:block/monitor_advanced_l", "y": 270},
|
||||||
"facing=west,orientation=north,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "y": 270},
|
||||||
"facing=west,orientation=north,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "y": 270},
|
||||||
"facing=west,orientation=north,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "y": 270},
|
||||||
"facing=west,orientation=north,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "y": 270},
|
||||||
"facing=west,orientation=north,state=lrud": {
|
"facing=west,orientation=north,state=lrud": {"model": "computercraft:block/monitor_advanced_lrud", "y": 270},
|
||||||
"model": "computercraft:block/monitor_advanced_lrud",
|
"facing=west,orientation=north,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "y": 270},
|
||||||
"x": 0,
|
"facing=west,orientation=north,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "y": 270},
|
||||||
"y": 270
|
"facing=west,orientation=north,state=none": {"model": "computercraft:block/monitor_advanced", "y": 270},
|
||||||
},
|
"facing=west,orientation=north,state=r": {"model": "computercraft:block/monitor_advanced_r", "y": 270},
|
||||||
"facing=west,orientation=north,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "y": 270},
|
||||||
"facing=west,orientation=north,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "y": 270},
|
||||||
"facing=west,orientation=north,state=none": {"model": "computercraft:block/monitor_advanced", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "y": 270},
|
||||||
"facing=west,orientation=north,state=r": {"model": "computercraft:block/monitor_advanced_r", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=u": {"model": "computercraft:block/monitor_advanced_u", "y": 270},
|
||||||
"facing=west,orientation=north,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "y": 270},
|
||||||
"facing=west,orientation=north,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "x": 0, "y": 270},
|
|
||||||
"facing=west,orientation=north,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 0, "y": 270},
|
|
||||||
"facing=west,orientation=north,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 0, "y": 270},
|
|
||||||
"facing=west,orientation=north,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 0, "y": 270},
|
|
||||||
"facing=west,orientation=up,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 270, "y": 270},
|
"facing=west,orientation=up,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 270, "y": 270},
|
||||||
"facing=west,orientation=up,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 270, "y": 270},
|
"facing=west,orientation=up,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 270, "y": 270},
|
||||||
"facing=west,orientation=up,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 270, "y": 270},
|
"facing=west,orientation=up,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 270, "y": 270},
|
||||||
|
@ -16,22 +16,22 @@
|
|||||||
"facing=east,orientation=down,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 90, "y": 90},
|
"facing=east,orientation=down,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 90, "y": 90},
|
||||||
"facing=east,orientation=down,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 90, "y": 90},
|
"facing=east,orientation=down,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 90, "y": 90},
|
||||||
"facing=east,orientation=down,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 90, "y": 90},
|
"facing=east,orientation=down,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 90, "y": 90},
|
||||||
"facing=east,orientation=north,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=d": {"model": "computercraft:block/monitor_normal_d", "y": 90},
|
||||||
"facing=east,orientation=north,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=l": {"model": "computercraft:block/monitor_normal_l", "y": 90},
|
||||||
"facing=east,orientation=north,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=ld": {"model": "computercraft:block/monitor_normal_ld", "y": 90},
|
||||||
"facing=east,orientation=north,state=lr": {"model": "computercraft:block/monitor_normal_lr", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=lr": {"model": "computercraft:block/monitor_normal_lr", "y": 90},
|
||||||
"facing=east,orientation=north,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "y": 90},
|
||||||
"facing=east,orientation=north,state=lru": {"model": "computercraft:block/monitor_normal_lru", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=lru": {"model": "computercraft:block/monitor_normal_lru", "y": 90},
|
||||||
"facing=east,orientation=north,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "y": 90},
|
||||||
"facing=east,orientation=north,state=lu": {"model": "computercraft:block/monitor_normal_lu", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=lu": {"model": "computercraft:block/monitor_normal_lu", "y": 90},
|
||||||
"facing=east,orientation=north,state=lud": {"model": "computercraft:block/monitor_normal_lud", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=lud": {"model": "computercraft:block/monitor_normal_lud", "y": 90},
|
||||||
"facing=east,orientation=north,state=none": {"model": "computercraft:block/monitor_normal", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=none": {"model": "computercraft:block/monitor_normal", "y": 90},
|
||||||
"facing=east,orientation=north,state=r": {"model": "computercraft:block/monitor_normal_r", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=r": {"model": "computercraft:block/monitor_normal_r", "y": 90},
|
||||||
"facing=east,orientation=north,state=rd": {"model": "computercraft:block/monitor_normal_rd", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=rd": {"model": "computercraft:block/monitor_normal_rd", "y": 90},
|
||||||
"facing=east,orientation=north,state=ru": {"model": "computercraft:block/monitor_normal_ru", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=ru": {"model": "computercraft:block/monitor_normal_ru", "y": 90},
|
||||||
"facing=east,orientation=north,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=rud": {"model": "computercraft:block/monitor_normal_rud", "y": 90},
|
||||||
"facing=east,orientation=north,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=u": {"model": "computercraft:block/monitor_normal_u", "y": 90},
|
||||||
"facing=east,orientation=north,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 0, "y": 90},
|
"facing=east,orientation=north,state=ud": {"model": "computercraft:block/monitor_normal_ud", "y": 90},
|
||||||
"facing=east,orientation=up,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 270, "y": 90},
|
"facing=east,orientation=up,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 270, "y": 90},
|
||||||
"facing=east,orientation=up,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 270, "y": 90},
|
"facing=east,orientation=up,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 270, "y": 90},
|
||||||
"facing=east,orientation=up,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 270, "y": 90},
|
"facing=east,orientation=up,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 270, "y": 90},
|
||||||
@ -48,54 +48,54 @@
|
|||||||
"facing=east,orientation=up,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 270, "y": 90},
|
"facing=east,orientation=up,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 270, "y": 90},
|
||||||
"facing=east,orientation=up,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 270, "y": 90},
|
"facing=east,orientation=up,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 270, "y": 90},
|
||||||
"facing=east,orientation=up,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 270, "y": 90},
|
"facing=east,orientation=up,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 270, "y": 90},
|
||||||
"facing=north,orientation=down,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 90},
|
||||||
"facing=north,orientation=down,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 90},
|
||||||
"facing=north,orientation=down,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 90},
|
||||||
"facing=north,orientation=down,state=lr": {"model": "computercraft:block/monitor_normal_lr", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=lr": {"model": "computercraft:block/monitor_normal_lr", "x": 90},
|
||||||
"facing=north,orientation=down,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "x": 90},
|
||||||
"facing=north,orientation=down,state=lru": {"model": "computercraft:block/monitor_normal_lru", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=lru": {"model": "computercraft:block/monitor_normal_lru", "x": 90},
|
||||||
"facing=north,orientation=down,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "x": 90},
|
||||||
"facing=north,orientation=down,state=lu": {"model": "computercraft:block/monitor_normal_lu", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=lu": {"model": "computercraft:block/monitor_normal_lu", "x": 90},
|
||||||
"facing=north,orientation=down,state=lud": {"model": "computercraft:block/monitor_normal_lud", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=lud": {"model": "computercraft:block/monitor_normal_lud", "x": 90},
|
||||||
"facing=north,orientation=down,state=none": {"model": "computercraft:block/monitor_normal", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=none": {"model": "computercraft:block/monitor_normal", "x": 90},
|
||||||
"facing=north,orientation=down,state=r": {"model": "computercraft:block/monitor_normal_r", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=r": {"model": "computercraft:block/monitor_normal_r", "x": 90},
|
||||||
"facing=north,orientation=down,state=rd": {"model": "computercraft:block/monitor_normal_rd", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=rd": {"model": "computercraft:block/monitor_normal_rd", "x": 90},
|
||||||
"facing=north,orientation=down,state=ru": {"model": "computercraft:block/monitor_normal_ru", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=ru": {"model": "computercraft:block/monitor_normal_ru", "x": 90},
|
||||||
"facing=north,orientation=down,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 90},
|
||||||
"facing=north,orientation=down,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 90},
|
||||||
"facing=north,orientation=down,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 90, "y": 0},
|
"facing=north,orientation=down,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 90},
|
||||||
"facing=north,orientation=north,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=d": {"model": "computercraft:block/monitor_normal_d"},
|
||||||
"facing=north,orientation=north,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=l": {"model": "computercraft:block/monitor_normal_l"},
|
||||||
"facing=north,orientation=north,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=ld": {"model": "computercraft:block/monitor_normal_ld"},
|
||||||
"facing=north,orientation=north,state=lr": {"model": "computercraft:block/monitor_normal_lr", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=lr": {"model": "computercraft:block/monitor_normal_lr"},
|
||||||
"facing=north,orientation=north,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=lrd": {"model": "computercraft:block/monitor_normal_lrd"},
|
||||||
"facing=north,orientation=north,state=lru": {"model": "computercraft:block/monitor_normal_lru", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=lru": {"model": "computercraft:block/monitor_normal_lru"},
|
||||||
"facing=north,orientation=north,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=lrud": {"model": "computercraft:block/monitor_normal_lrud"},
|
||||||
"facing=north,orientation=north,state=lu": {"model": "computercraft:block/monitor_normal_lu", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=lu": {"model": "computercraft:block/monitor_normal_lu"},
|
||||||
"facing=north,orientation=north,state=lud": {"model": "computercraft:block/monitor_normal_lud", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=lud": {"model": "computercraft:block/monitor_normal_lud"},
|
||||||
"facing=north,orientation=north,state=none": {"model": "computercraft:block/monitor_normal", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=none": {"model": "computercraft:block/monitor_normal"},
|
||||||
"facing=north,orientation=north,state=r": {"model": "computercraft:block/monitor_normal_r", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=r": {"model": "computercraft:block/monitor_normal_r"},
|
||||||
"facing=north,orientation=north,state=rd": {"model": "computercraft:block/monitor_normal_rd", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=rd": {"model": "computercraft:block/monitor_normal_rd"},
|
||||||
"facing=north,orientation=north,state=ru": {"model": "computercraft:block/monitor_normal_ru", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=ru": {"model": "computercraft:block/monitor_normal_ru"},
|
||||||
"facing=north,orientation=north,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=rud": {"model": "computercraft:block/monitor_normal_rud"},
|
||||||
"facing=north,orientation=north,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=u": {"model": "computercraft:block/monitor_normal_u"},
|
||||||
"facing=north,orientation=north,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 0, "y": 0},
|
"facing=north,orientation=north,state=ud": {"model": "computercraft:block/monitor_normal_ud"},
|
||||||
"facing=north,orientation=up,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 270},
|
||||||
"facing=north,orientation=up,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 270},
|
||||||
"facing=north,orientation=up,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 270},
|
||||||
"facing=north,orientation=up,state=lr": {"model": "computercraft:block/monitor_normal_lr", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=lr": {"model": "computercraft:block/monitor_normal_lr", "x": 270},
|
||||||
"facing=north,orientation=up,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "x": 270},
|
||||||
"facing=north,orientation=up,state=lru": {"model": "computercraft:block/monitor_normal_lru", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=lru": {"model": "computercraft:block/monitor_normal_lru", "x": 270},
|
||||||
"facing=north,orientation=up,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "x": 270},
|
||||||
"facing=north,orientation=up,state=lu": {"model": "computercraft:block/monitor_normal_lu", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=lu": {"model": "computercraft:block/monitor_normal_lu", "x": 270},
|
||||||
"facing=north,orientation=up,state=lud": {"model": "computercraft:block/monitor_normal_lud", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=lud": {"model": "computercraft:block/monitor_normal_lud", "x": 270},
|
||||||
"facing=north,orientation=up,state=none": {"model": "computercraft:block/monitor_normal", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=none": {"model": "computercraft:block/monitor_normal", "x": 270},
|
||||||
"facing=north,orientation=up,state=r": {"model": "computercraft:block/monitor_normal_r", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=r": {"model": "computercraft:block/monitor_normal_r", "x": 270},
|
||||||
"facing=north,orientation=up,state=rd": {"model": "computercraft:block/monitor_normal_rd", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=rd": {"model": "computercraft:block/monitor_normal_rd", "x": 270},
|
||||||
"facing=north,orientation=up,state=ru": {"model": "computercraft:block/monitor_normal_ru", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=ru": {"model": "computercraft:block/monitor_normal_ru", "x": 270},
|
||||||
"facing=north,orientation=up,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 270},
|
||||||
"facing=north,orientation=up,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 270},
|
||||||
"facing=north,orientation=up,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 270, "y": 0},
|
"facing=north,orientation=up,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 270},
|
||||||
"facing=south,orientation=down,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 90, "y": 180},
|
"facing=south,orientation=down,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 90, "y": 180},
|
||||||
"facing=south,orientation=down,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 90, "y": 180},
|
"facing=south,orientation=down,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 90, "y": 180},
|
||||||
"facing=south,orientation=down,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 90, "y": 180},
|
"facing=south,orientation=down,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 90, "y": 180},
|
||||||
@ -116,26 +116,22 @@
|
|||||||
"facing=south,orientation=down,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 90, "y": 180},
|
"facing=south,orientation=down,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 90, "y": 180},
|
||||||
"facing=south,orientation=down,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 90, "y": 180},
|
"facing=south,orientation=down,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 90, "y": 180},
|
||||||
"facing=south,orientation=down,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 90, "y": 180},
|
"facing=south,orientation=down,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 90, "y": 180},
|
||||||
"facing=south,orientation=north,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=d": {"model": "computercraft:block/monitor_normal_d", "y": 180},
|
||||||
"facing=south,orientation=north,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=l": {"model": "computercraft:block/monitor_normal_l", "y": 180},
|
||||||
"facing=south,orientation=north,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=ld": {"model": "computercraft:block/monitor_normal_ld", "y": 180},
|
||||||
"facing=south,orientation=north,state=lr": {"model": "computercraft:block/monitor_normal_lr", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=lr": {"model": "computercraft:block/monitor_normal_lr", "y": 180},
|
||||||
"facing=south,orientation=north,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "y": 180},
|
||||||
"facing=south,orientation=north,state=lru": {"model": "computercraft:block/monitor_normal_lru", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=lru": {"model": "computercraft:block/monitor_normal_lru", "y": 180},
|
||||||
"facing=south,orientation=north,state=lrud": {
|
"facing=south,orientation=north,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "y": 180},
|
||||||
"model": "computercraft:block/monitor_normal_lrud",
|
"facing=south,orientation=north,state=lu": {"model": "computercraft:block/monitor_normal_lu", "y": 180},
|
||||||
"x": 0,
|
"facing=south,orientation=north,state=lud": {"model": "computercraft:block/monitor_normal_lud", "y": 180},
|
||||||
"y": 180
|
"facing=south,orientation=north,state=none": {"model": "computercraft:block/monitor_normal", "y": 180},
|
||||||
},
|
"facing=south,orientation=north,state=r": {"model": "computercraft:block/monitor_normal_r", "y": 180},
|
||||||
"facing=south,orientation=north,state=lu": {"model": "computercraft:block/monitor_normal_lu", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=rd": {"model": "computercraft:block/monitor_normal_rd", "y": 180},
|
||||||
"facing=south,orientation=north,state=lud": {"model": "computercraft:block/monitor_normal_lud", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=ru": {"model": "computercraft:block/monitor_normal_ru", "y": 180},
|
||||||
"facing=south,orientation=north,state=none": {"model": "computercraft:block/monitor_normal", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=rud": {"model": "computercraft:block/monitor_normal_rud", "y": 180},
|
||||||
"facing=south,orientation=north,state=r": {"model": "computercraft:block/monitor_normal_r", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=u": {"model": "computercraft:block/monitor_normal_u", "y": 180},
|
||||||
"facing=south,orientation=north,state=rd": {"model": "computercraft:block/monitor_normal_rd", "x": 0, "y": 180},
|
"facing=south,orientation=north,state=ud": {"model": "computercraft:block/monitor_normal_ud", "y": 180},
|
||||||
"facing=south,orientation=north,state=ru": {"model": "computercraft:block/monitor_normal_ru", "x": 0, "y": 180},
|
|
||||||
"facing=south,orientation=north,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 0, "y": 180},
|
|
||||||
"facing=south,orientation=north,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 0, "y": 180},
|
|
||||||
"facing=south,orientation=north,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 0, "y": 180},
|
|
||||||
"facing=south,orientation=up,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 270, "y": 180},
|
"facing=south,orientation=up,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 270, "y": 180},
|
||||||
"facing=south,orientation=up,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 270, "y": 180},
|
"facing=south,orientation=up,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 270, "y": 180},
|
||||||
"facing=south,orientation=up,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 270, "y": 180},
|
"facing=south,orientation=up,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 270, "y": 180},
|
||||||
@ -168,22 +164,22 @@
|
|||||||
"facing=west,orientation=down,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 90, "y": 270},
|
"facing=west,orientation=down,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 90, "y": 270},
|
||||||
"facing=west,orientation=down,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 90, "y": 270},
|
"facing=west,orientation=down,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 90, "y": 270},
|
||||||
"facing=west,orientation=down,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 90, "y": 270},
|
"facing=west,orientation=down,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 90, "y": 270},
|
||||||
"facing=west,orientation=north,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=d": {"model": "computercraft:block/monitor_normal_d", "y": 270},
|
||||||
"facing=west,orientation=north,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=l": {"model": "computercraft:block/monitor_normal_l", "y": 270},
|
||||||
"facing=west,orientation=north,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=ld": {"model": "computercraft:block/monitor_normal_ld", "y": 270},
|
||||||
"facing=west,orientation=north,state=lr": {"model": "computercraft:block/monitor_normal_lr", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=lr": {"model": "computercraft:block/monitor_normal_lr", "y": 270},
|
||||||
"facing=west,orientation=north,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "y": 270},
|
||||||
"facing=west,orientation=north,state=lru": {"model": "computercraft:block/monitor_normal_lru", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=lru": {"model": "computercraft:block/monitor_normal_lru", "y": 270},
|
||||||
"facing=west,orientation=north,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "y": 270},
|
||||||
"facing=west,orientation=north,state=lu": {"model": "computercraft:block/monitor_normal_lu", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=lu": {"model": "computercraft:block/monitor_normal_lu", "y": 270},
|
||||||
"facing=west,orientation=north,state=lud": {"model": "computercraft:block/monitor_normal_lud", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=lud": {"model": "computercraft:block/monitor_normal_lud", "y": 270},
|
||||||
"facing=west,orientation=north,state=none": {"model": "computercraft:block/monitor_normal", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=none": {"model": "computercraft:block/monitor_normal", "y": 270},
|
||||||
"facing=west,orientation=north,state=r": {"model": "computercraft:block/monitor_normal_r", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=r": {"model": "computercraft:block/monitor_normal_r", "y": 270},
|
||||||
"facing=west,orientation=north,state=rd": {"model": "computercraft:block/monitor_normal_rd", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=rd": {"model": "computercraft:block/monitor_normal_rd", "y": 270},
|
||||||
"facing=west,orientation=north,state=ru": {"model": "computercraft:block/monitor_normal_ru", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=ru": {"model": "computercraft:block/monitor_normal_ru", "y": 270},
|
||||||
"facing=west,orientation=north,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=rud": {"model": "computercraft:block/monitor_normal_rud", "y": 270},
|
||||||
"facing=west,orientation=north,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=u": {"model": "computercraft:block/monitor_normal_u", "y": 270},
|
||||||
"facing=west,orientation=north,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 0, "y": 270},
|
"facing=west,orientation=north,state=ud": {"model": "computercraft:block/monitor_normal_ud", "y": 270},
|
||||||
"facing=west,orientation=up,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 270, "y": 270},
|
"facing=west,orientation=up,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 270, "y": 270},
|
||||||
"facing=west,orientation=up,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 270, "y": 270},
|
"facing=west,orientation=up,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 270, "y": 270},
|
||||||
"facing=west,orientation=up,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 270, "y": 270},
|
"facing=west,orientation=up,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 270, "y": 270},
|
||||||
|
@ -2,16 +2,16 @@
|
|||||||
"variants": {
|
"variants": {
|
||||||
"bottom=false,facing=east,top=false": {"model": "computercraft:block/printer_empty", "y": 90},
|
"bottom=false,facing=east,top=false": {"model": "computercraft:block/printer_empty", "y": 90},
|
||||||
"bottom=false,facing=east,top=true": {"model": "computercraft:block/printer_top_full", "y": 90},
|
"bottom=false,facing=east,top=true": {"model": "computercraft:block/printer_top_full", "y": 90},
|
||||||
"bottom=false,facing=north,top=false": {"model": "computercraft:block/printer_empty", "y": 0},
|
"bottom=false,facing=north,top=false": {"model": "computercraft:block/printer_empty"},
|
||||||
"bottom=false,facing=north,top=true": {"model": "computercraft:block/printer_top_full", "y": 0},
|
"bottom=false,facing=north,top=true": {"model": "computercraft:block/printer_top_full"},
|
||||||
"bottom=false,facing=south,top=false": {"model": "computercraft:block/printer_empty", "y": 180},
|
"bottom=false,facing=south,top=false": {"model": "computercraft:block/printer_empty", "y": 180},
|
||||||
"bottom=false,facing=south,top=true": {"model": "computercraft:block/printer_top_full", "y": 180},
|
"bottom=false,facing=south,top=true": {"model": "computercraft:block/printer_top_full", "y": 180},
|
||||||
"bottom=false,facing=west,top=false": {"model": "computercraft:block/printer_empty", "y": 270},
|
"bottom=false,facing=west,top=false": {"model": "computercraft:block/printer_empty", "y": 270},
|
||||||
"bottom=false,facing=west,top=true": {"model": "computercraft:block/printer_top_full", "y": 270},
|
"bottom=false,facing=west,top=true": {"model": "computercraft:block/printer_top_full", "y": 270},
|
||||||
"bottom=true,facing=east,top=false": {"model": "computercraft:block/printer_bottom_full", "y": 90},
|
"bottom=true,facing=east,top=false": {"model": "computercraft:block/printer_bottom_full", "y": 90},
|
||||||
"bottom=true,facing=east,top=true": {"model": "computercraft:block/printer_both_full", "y": 90},
|
"bottom=true,facing=east,top=true": {"model": "computercraft:block/printer_both_full", "y": 90},
|
||||||
"bottom=true,facing=north,top=false": {"model": "computercraft:block/printer_bottom_full", "y": 0},
|
"bottom=true,facing=north,top=false": {"model": "computercraft:block/printer_bottom_full"},
|
||||||
"bottom=true,facing=north,top=true": {"model": "computercraft:block/printer_both_full", "y": 0},
|
"bottom=true,facing=north,top=true": {"model": "computercraft:block/printer_both_full"},
|
||||||
"bottom=true,facing=south,top=false": {"model": "computercraft:block/printer_bottom_full", "y": 180},
|
"bottom=true,facing=south,top=false": {"model": "computercraft:block/printer_bottom_full", "y": 180},
|
||||||
"bottom=true,facing=south,top=true": {"model": "computercraft:block/printer_both_full", "y": 180},
|
"bottom=true,facing=south,top=true": {"model": "computercraft:block/printer_both_full", "y": 180},
|
||||||
"bottom=true,facing=west,top=false": {"model": "computercraft:block/printer_bottom_full", "y": 270},
|
"bottom=true,facing=west,top=false": {"model": "computercraft:block/printer_bottom_full", "y": 270},
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
{
|
{
|
||||||
"variants": {
|
"variants": {
|
||||||
"facing=down,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "x": 90, "y": 0},
|
"facing=down,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "x": 90},
|
||||||
"facing=down,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 90, "y": 0},
|
"facing=down,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 90},
|
||||||
"facing=east,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "x": 0, "y": 90},
|
"facing=east,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "y": 90},
|
||||||
"facing=east,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 0, "y": 90},
|
"facing=east,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "y": 90},
|
||||||
"facing=north,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "x": 0, "y": 0},
|
"facing=north,on=false": {"model": "computercraft:block/wireless_modem_advanced_off"},
|
||||||
"facing=north,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 0, "y": 0},
|
"facing=north,on=true": {"model": "computercraft:block/wireless_modem_advanced_on"},
|
||||||
"facing=south,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "x": 0, "y": 180},
|
"facing=south,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "y": 180},
|
||||||
"facing=south,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 0, "y": 180},
|
"facing=south,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "y": 180},
|
||||||
"facing=up,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "x": 270, "y": 0},
|
"facing=up,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "x": 270},
|
||||||
"facing=up,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 270, "y": 0},
|
"facing=up,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 270},
|
||||||
"facing=west,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "x": 0, "y": 270},
|
"facing=west,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "y": 270},
|
||||||
"facing=west,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 0, "y": 270}
|
"facing=west,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "y": 270}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
{
|
{
|
||||||
"variants": {
|
"variants": {
|
||||||
"facing=down,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "x": 90, "y": 0},
|
"facing=down,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "x": 90},
|
||||||
"facing=down,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 90, "y": 0},
|
"facing=down,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 90},
|
||||||
"facing=east,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "x": 0, "y": 90},
|
"facing=east,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "y": 90},
|
||||||
"facing=east,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 0, "y": 90},
|
"facing=east,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "y": 90},
|
||||||
"facing=north,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "x": 0, "y": 0},
|
"facing=north,on=false": {"model": "computercraft:block/wireless_modem_normal_off"},
|
||||||
"facing=north,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 0, "y": 0},
|
"facing=north,on=true": {"model": "computercraft:block/wireless_modem_normal_on"},
|
||||||
"facing=south,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "x": 0, "y": 180},
|
"facing=south,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "y": 180},
|
||||||
"facing=south,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 0, "y": 180},
|
"facing=south,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "y": 180},
|
||||||
"facing=up,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "x": 270, "y": 0},
|
"facing=up,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "x": 270},
|
||||||
"facing=up,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 270, "y": 0},
|
"facing=up,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 270},
|
||||||
"facing=west,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "x": 0, "y": 270},
|
"facing=west,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "y": 270},
|
||||||
"facing=west,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 0, "y": 270}
|
"facing=west,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "y": 270}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,8 @@ class V1460Mixin {
|
|||||||
|
|
||||||
// Disk drives contain a single item
|
// Disk drives contain a single item
|
||||||
schema.register(map, "computercraft:disk_drive", () -> DSL.optionalFields(
|
schema.register(map, "computercraft:disk_drive", () -> DSL.optionalFields(
|
||||||
"Item", References.ITEM_STACK.in(schema)
|
"Item", References.ITEM_STACK.in(schema),
|
||||||
|
"CustomName", References.TEXT_COMPONENT.in(schema)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ import dan200.computercraft.shared.lectern.CustomLecternBlock;
|
|||||||
import dan200.computercraft.shared.peripheral.monitor.MonitorWatcher;
|
import dan200.computercraft.shared.peripheral.monitor.MonitorWatcher;
|
||||||
import dan200.computercraft.shared.util.DropConsumer;
|
import dan200.computercraft.shared.util.DropConsumer;
|
||||||
import dan200.computercraft.shared.util.TickScheduler;
|
import dan200.computercraft.shared.util.TickScheduler;
|
||||||
import net.minecraft.core.component.DataComponentType;
|
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
@ -29,7 +28,7 @@ import net.minecraft.world.InteractionResult;
|
|||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.*;
|
import net.minecraft.world.item.*;
|
||||||
import net.minecraft.world.item.component.TooltipProvider;
|
import net.minecraft.world.item.component.TooltipDisplay;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.LecternBlock;
|
import net.minecraft.world.level.block.LecternBlock;
|
||||||
@ -170,18 +169,12 @@ public final class CommonHooks {
|
|||||||
|
|
||||||
public static void onItemTooltip(ItemStack stack, Item.TooltipContext context, TooltipFlag flags, List<Component> out) {
|
public static void onItemTooltip(ItemStack stack, Item.TooltipContext context, TooltipFlag flags, List<Component> out) {
|
||||||
var appender = new TooltipAppender(out);
|
var appender = new TooltipAppender(out);
|
||||||
addToTooltip(stack, ModRegistry.DataComponents.PRINTOUT.get(), context, appender, flags);
|
|
||||||
addToTooltip(stack, ModRegistry.DataComponents.TREASURE_DISK.get(), context, appender, flags);
|
|
||||||
|
|
||||||
// Disk and computer IDs require some conditional logic, so we don't bother using TooltipProvider.
|
var display = stack.getOrDefault(DataComponents.TOOLTIP_DISPLAY, TooltipDisplay.DEFAULT);
|
||||||
|
stack.addToTooltip(ModRegistry.DataComponents.PRINTOUT.get(), context, display, appender, flags);
|
||||||
var diskId = stack.get(ModRegistry.DataComponents.DISK_ID.get());
|
stack.addToTooltip(ModRegistry.DataComponents.TREASURE_DISK.get(), context, display, appender, flags);
|
||||||
if (diskId != null && flags.isAdvanced()) diskId.addToTooltip("gui.computercraft.tooltip.disk_id", appender);
|
stack.addToTooltip(ModRegistry.DataComponents.COMPUTER_ID.get(), context, display, appender, flags);
|
||||||
|
stack.addToTooltip(ModRegistry.DataComponents.DISK_ID.get(), context, display, appender, flags);
|
||||||
var computerId = stack.get(ModRegistry.DataComponents.COMPUTER_ID.get());
|
|
||||||
if (computerId != null && (flags.isAdvanced() || !stack.has(DataComponents.CUSTOM_NAME))) {
|
|
||||||
computerId.addToTooltip("gui.computercraft.tooltip.computer_id", appender);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -200,9 +193,4 @@ public final class CommonHooks {
|
|||||||
out.add(index++, component);
|
out.add(index++, component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends TooltipProvider> void addToTooltip(ItemStack stack, DataComponentType<T> component, Item.TooltipContext context, Consumer<Component> out, TooltipFlag flags) {
|
|
||||||
var provider = stack.get(component);
|
|
||||||
if (provider != null) provider.addToTooltip(context, out, flags);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeType;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
import dan200.computercraft.core.util.Colour;
|
|
||||||
import dan200.computercraft.impl.PocketUpgrades;
|
import dan200.computercraft.impl.PocketUpgrades;
|
||||||
import dan200.computercraft.shared.command.UserLevel;
|
import dan200.computercraft.shared.command.UserLevel;
|
||||||
import dan200.computercraft.shared.command.arguments.ComputerArgumentType;
|
import dan200.computercraft.shared.command.arguments.ComputerArgumentType;
|
||||||
@ -113,7 +112,7 @@ import net.minecraft.resources.ResourceLocation;
|
|||||||
import net.minecraft.world.flag.FeatureFlags;
|
import net.minecraft.world.flag.FeatureFlags;
|
||||||
import net.minecraft.world.inventory.MenuType;
|
import net.minecraft.world.inventory.MenuType;
|
||||||
import net.minecraft.world.item.*;
|
import net.minecraft.world.item.*;
|
||||||
import net.minecraft.world.item.component.DyedItemColor;
|
import net.minecraft.world.item.component.TooltipDisplay;
|
||||||
import net.minecraft.world.item.crafting.CustomRecipe;
|
import net.minecraft.world.item.crafting.CustomRecipe;
|
||||||
import net.minecraft.world.item.crafting.Recipe;
|
import net.minecraft.world.item.crafting.Recipe;
|
||||||
import net.minecraft.world.item.crafting.RecipeSerializer;
|
import net.minecraft.world.item.crafting.RecipeSerializer;
|
||||||
@ -274,6 +273,13 @@ public final class ModRegistry {
|
|||||||
return new Item.Properties();
|
return new Item.Properties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Item.Properties dyeableProperties() {
|
||||||
|
return properties().component(
|
||||||
|
net.minecraft.core.component.DataComponents.TOOLTIP_DISPLAY,
|
||||||
|
TooltipDisplay.DEFAULT.withHidden(net.minecraft.core.component.DataComponents.DYED_COLOR, true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private static <T extends Item> RegistryEntry<T> register(String name, Function<Item.Properties, T> build, Supplier<Item.Properties> properties) {
|
private static <T extends Item> RegistryEntry<T> register(String name, Function<Item.Properties, T> build, Supplier<Item.Properties> properties) {
|
||||||
return REGISTRY.register(name, () -> build.apply(properties.get().setId(ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name)))));
|
return REGISTRY.register(name, () -> build.apply(properties.get().setId(ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name)))));
|
||||||
}
|
}
|
||||||
@ -282,26 +288,26 @@ public final class ModRegistry {
|
|||||||
return register(name, build, () -> properties);
|
return register(name, build, () -> properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <B extends Block, I extends Item> RegistryEntry<I> ofBlock(RegistryEntry<B> parent, BiFunction<B, Item.Properties, I> supplier) {
|
private static <B extends Block, I extends Item> RegistryEntry<I> ofBlock(RegistryEntry<B> parent, BiFunction<B, Item.Properties, I> supplier, Item.Properties properties) {
|
||||||
return register(parent.id().getPath(), p -> supplier.apply(parent.get(), p), properties().useBlockDescriptionPrefix());
|
return register(parent.id().getPath(), p -> supplier.apply(parent.get(), p), properties.useBlockDescriptionPrefix());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final RegistryEntry<BlockItem> COMPUTER_NORMAL = ofBlock(Blocks.COMPUTER_NORMAL, BlockItem::new);
|
public static final RegistryEntry<BlockItem> COMPUTER_NORMAL = ofBlock(Blocks.COMPUTER_NORMAL, BlockItem::new, properties());
|
||||||
public static final RegistryEntry<BlockItem> COMPUTER_ADVANCED = ofBlock(Blocks.COMPUTER_ADVANCED, BlockItem::new);
|
public static final RegistryEntry<BlockItem> COMPUTER_ADVANCED = ofBlock(Blocks.COMPUTER_ADVANCED, BlockItem::new, properties());
|
||||||
public static final RegistryEntry<GameMasterBlockItem> COMPUTER_COMMAND = ofBlock(Blocks.COMPUTER_COMMAND, GameMasterBlockItem::new);
|
public static final RegistryEntry<GameMasterBlockItem> COMPUTER_COMMAND = ofBlock(Blocks.COMPUTER_COMMAND, GameMasterBlockItem::new, properties());
|
||||||
|
|
||||||
public static final RegistryEntry<PocketComputerItem> POCKET_COMPUTER_NORMAL = register("pocket_computer_normal",
|
public static final RegistryEntry<PocketComputerItem> POCKET_COMPUTER_NORMAL = register("pocket_computer_normal",
|
||||||
p -> new PocketComputerItem(p, ComputerFamily.NORMAL), properties().stacksTo(1));
|
p -> new PocketComputerItem(p, ComputerFamily.NORMAL), dyeableProperties());
|
||||||
public static final RegistryEntry<PocketComputerItem> POCKET_COMPUTER_ADVANCED = register("pocket_computer_advanced",
|
public static final RegistryEntry<PocketComputerItem> POCKET_COMPUTER_ADVANCED = register("pocket_computer_advanced",
|
||||||
p -> new PocketComputerItem(p, ComputerFamily.ADVANCED), properties().stacksTo(1));
|
p -> new PocketComputerItem(p, ComputerFamily.ADVANCED), dyeableProperties());
|
||||||
|
|
||||||
public static final RegistryEntry<TurtleItem> TURTLE_NORMAL = ofBlock(Blocks.TURTLE_NORMAL, TurtleItem::new);
|
public static final RegistryEntry<TurtleItem> TURTLE_NORMAL = ofBlock(Blocks.TURTLE_NORMAL, TurtleItem::new, dyeableProperties());
|
||||||
public static final RegistryEntry<TurtleItem> TURTLE_ADVANCED = ofBlock(Blocks.TURTLE_ADVANCED, TurtleItem::new);
|
public static final RegistryEntry<TurtleItem> TURTLE_ADVANCED = ofBlock(Blocks.TURTLE_ADVANCED, TurtleItem::new, dyeableProperties());
|
||||||
|
|
||||||
public static final RegistryEntry<DiskItem> DISK =
|
public static final RegistryEntry<DiskItem> DISK =
|
||||||
register("disk", DiskItem::new, properties().stacksTo(1));
|
register("disk", DiskItem::new, dyeableProperties().stacksTo(1));
|
||||||
public static final RegistryEntry<DiskItem> TREASURE_DISK =
|
public static final RegistryEntry<DiskItem> TREASURE_DISK =
|
||||||
register("treasure_disk", DiskItem::new, properties().stacksTo(1));
|
register("treasure_disk", DiskItem::new, dyeableProperties().stacksTo(1));
|
||||||
|
|
||||||
private static Item.Properties printoutProperties() {
|
private static Item.Properties printoutProperties() {
|
||||||
return properties().stacksTo(1).component(DataComponents.PRINTOUT.get(), PrintoutData.EMPTY);
|
return properties().stacksTo(1).component(DataComponents.PRINTOUT.get(), PrintoutData.EMPTY);
|
||||||
@ -314,15 +320,15 @@ public final class ModRegistry {
|
|||||||
public static final RegistryEntry<PrintoutItem> PRINTED_BOOK = register("printed_book",
|
public static final RegistryEntry<PrintoutItem> PRINTED_BOOK = register("printed_book",
|
||||||
PrintoutItem::new, Items::printoutProperties);
|
PrintoutItem::new, Items::printoutProperties);
|
||||||
|
|
||||||
public static final RegistryEntry<BlockItem> SPEAKER = ofBlock(Blocks.SPEAKER, BlockItem::new);
|
public static final RegistryEntry<BlockItem> SPEAKER = ofBlock(Blocks.SPEAKER, BlockItem::new, properties());
|
||||||
public static final RegistryEntry<BlockItem> DISK_DRIVE = ofBlock(Blocks.DISK_DRIVE, BlockItem::new);
|
public static final RegistryEntry<BlockItem> DISK_DRIVE = ofBlock(Blocks.DISK_DRIVE, BlockItem::new, properties());
|
||||||
public static final RegistryEntry<BlockItem> PRINTER = ofBlock(Blocks.PRINTER, BlockItem::new);
|
public static final RegistryEntry<BlockItem> PRINTER = ofBlock(Blocks.PRINTER, BlockItem::new, properties());
|
||||||
public static final RegistryEntry<BlockItem> MONITOR_NORMAL = ofBlock(Blocks.MONITOR_NORMAL, BlockItem::new);
|
public static final RegistryEntry<BlockItem> MONITOR_NORMAL = ofBlock(Blocks.MONITOR_NORMAL, BlockItem::new, properties());
|
||||||
public static final RegistryEntry<BlockItem> MONITOR_ADVANCED = ofBlock(Blocks.MONITOR_ADVANCED, BlockItem::new);
|
public static final RegistryEntry<BlockItem> MONITOR_ADVANCED = ofBlock(Blocks.MONITOR_ADVANCED, BlockItem::new, properties());
|
||||||
public static final RegistryEntry<BlockItem> WIRELESS_MODEM_NORMAL = ofBlock(Blocks.WIRELESS_MODEM_NORMAL, BlockItem::new);
|
public static final RegistryEntry<BlockItem> WIRELESS_MODEM_NORMAL = ofBlock(Blocks.WIRELESS_MODEM_NORMAL, BlockItem::new, properties());
|
||||||
public static final RegistryEntry<BlockItem> WIRELESS_MODEM_ADVANCED = ofBlock(Blocks.WIRELESS_MODEM_ADVANCED, BlockItem::new);
|
public static final RegistryEntry<BlockItem> WIRELESS_MODEM_ADVANCED = ofBlock(Blocks.WIRELESS_MODEM_ADVANCED, BlockItem::new, properties());
|
||||||
public static final RegistryEntry<BlockItem> WIRED_MODEM_FULL = ofBlock(Blocks.WIRED_MODEM_FULL, BlockItem::new);
|
public static final RegistryEntry<BlockItem> WIRED_MODEM_FULL = ofBlock(Blocks.WIRED_MODEM_FULL, BlockItem::new, properties());
|
||||||
public static final RegistryEntry<BlockItem> REDSTONE_RELAY = ofBlock(Blocks.REDSTONE_RELAY, BlockItem::new);
|
public static final RegistryEntry<BlockItem> REDSTONE_RELAY = ofBlock(Blocks.REDSTONE_RELAY, BlockItem::new, properties());
|
||||||
|
|
||||||
public static final RegistryEntry<CableBlockItem.Cable> CABLE = register("cable",
|
public static final RegistryEntry<CableBlockItem.Cable> CABLE = register("cable",
|
||||||
p -> new CableBlockItem.Cable(Blocks.CABLE.get(), p), properties().useBlockDescriptionPrefix());
|
p -> new CableBlockItem.Cable(Blocks.CABLE.get(), p), properties().useBlockDescriptionPrefix());
|
||||||
@ -340,8 +346,8 @@ public final class ModRegistry {
|
|||||||
/**
|
/**
|
||||||
* The id of a computer.
|
* The id of a computer.
|
||||||
*/
|
*/
|
||||||
public static final RegistryEntry<DataComponentType<NonNegativeId>> COMPUTER_ID = register("computer_id", b -> b
|
public static final RegistryEntry<DataComponentType<NonNegativeId.Computer>> COMPUTER_ID = register("computer_id", b -> b
|
||||||
.persistent(NonNegativeId.CODEC).networkSynchronized(NonNegativeId.STREAM_CODEC)
|
.persistent(NonNegativeId.Computer.CODEC).networkSynchronized(NonNegativeId.Computer.STREAM_CODEC)
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -422,8 +428,8 @@ public final class ModRegistry {
|
|||||||
/**
|
/**
|
||||||
* The id of a disk.
|
* The id of a disk.
|
||||||
*/
|
*/
|
||||||
public static final RegistryEntry<DataComponentType<NonNegativeId>> DISK_ID = register("disk_id", b -> b
|
public static final RegistryEntry<DataComponentType<NonNegativeId.Disk>> DISK_ID = register("disk_id", b -> b
|
||||||
.persistent(NonNegativeId.CODEC).networkSynchronized(NonNegativeId.STREAM_CODEC)
|
.persistent(NonNegativeId.Disk.CODEC).networkSynchronized(NonNegativeId.Disk.STREAM_CODEC)
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -597,8 +603,8 @@ public final class ModRegistry {
|
|||||||
out.accept(Items.PRINTED_BOOK.get());
|
out.accept(Items.PRINTED_BOOK.get());
|
||||||
|
|
||||||
out.accept(Items.DISK_DRIVE.get());
|
out.accept(Items.DISK_DRIVE.get());
|
||||||
for (var colour = 0; colour < 16; colour++) {
|
for (var colour : DyeColor.values()) {
|
||||||
out.accept(DataComponentUtil.createStack(Items.DISK.get(), net.minecraft.core.component.DataComponents.DYED_COLOR, new DyedItemColor(Colour.VALUES[colour].getHex(), false)));
|
out.accept(DataComponentUtil.createDyedStack(Items.DISK.get(), colour.getTextureDiffuseColor()));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.build());
|
.build());
|
||||||
|
@ -182,10 +182,7 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
|
|||||||
output.append("\n");
|
output.append("\n");
|
||||||
|
|
||||||
var component = coloured(child.getName(), NAME);
|
var component = coloured(child.getName(), NAME);
|
||||||
component.getStyle().withClickEvent(new ClickEvent(
|
component.getStyle().withClickEvent(new ClickEvent.SuggestCommand("/" + command + " " + child.getName()));
|
||||||
ClickEvent.Action.SUGGEST_COMMAND,
|
|
||||||
"/" + command + " " + child.getName()
|
|
||||||
));
|
|
||||||
output.append(component);
|
output.append(component);
|
||||||
|
|
||||||
output.append(" - ").append(Component.translatable("commands." + id + "." + child.getName() + ".synopsis"));
|
output.append(" - ").append(Component.translatable("commands." + id + "." + child.getName() + ".synopsis"));
|
||||||
|
@ -49,7 +49,7 @@ public final class ChatHelpers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Component link(MutableComponent component, String command, Component toolTip) {
|
public static Component link(MutableComponent component, String command, Component toolTip) {
|
||||||
return link(component, new ClickEvent(ClickEvent.Action.RUN_COMMAND, command), toolTip);
|
return link(component, new ClickEvent.RunCommand(command), toolTip);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Component link(Component component, ClickEvent click, Component toolTip) {
|
public static Component link(Component component, ClickEvent click, Component toolTip) {
|
||||||
@ -57,7 +57,7 @@ public final class ChatHelpers {
|
|||||||
|
|
||||||
if (style.getColor() == null) style = style.withColor(ChatFormatting.YELLOW);
|
if (style.getColor() == null) style = style.withColor(ChatFormatting.YELLOW);
|
||||||
style = style.withClickEvent(click);
|
style = style.withClickEvent(click);
|
||||||
style = style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, toolTip));
|
style = style.withHoverEvent(new HoverEvent.ShowText(toolTip));
|
||||||
|
|
||||||
return component.copy().withStyle(style);
|
return component.copy().withStyle(style);
|
||||||
}
|
}
|
||||||
@ -68,8 +68,8 @@ public final class ChatHelpers {
|
|||||||
|
|
||||||
public static MutableComponent copy(String text) {
|
public static MutableComponent copy(String text) {
|
||||||
return Component.literal(text).withStyle(s -> s
|
return Component.literal(text).withStyle(s -> s
|
||||||
.withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, text))
|
.withClickEvent(new ClickEvent.CopyToClipboard(text))
|
||||||
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.translatable("gui.computercraft.tooltip.copy")))
|
.withHoverEvent(new HoverEvent.ShowText(Component.translatable("gui.computercraft.tooltip.copy")))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ package dan200.computercraft.shared.common;
|
|||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftTags;
|
import dan200.computercraft.api.ComputerCraftTags;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
|
||||||
import net.minecraft.core.HolderLookup;
|
import net.minecraft.core.HolderLookup;
|
||||||
import net.minecraft.core.NonNullList;
|
import net.minecraft.core.NonNullList;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
@ -60,7 +59,9 @@ public final class ClearColourRecipe extends CustomRecipe {
|
|||||||
|
|
||||||
if (colourable.isEmpty()) return ItemStack.EMPTY;
|
if (colourable.isEmpty()) return ItemStack.EMPTY;
|
||||||
|
|
||||||
return DataComponentUtil.createResult(colourable, DataComponents.DYED_COLOR, null);
|
var result = colourable.copyWithCount(1);
|
||||||
|
result.remove(DataComponents.DYED_COLOR);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -10,9 +10,7 @@ import dan200.computercraft.shared.util.ColourTracker;
|
|||||||
import dan200.computercraft.shared.util.ColourUtils;
|
import dan200.computercraft.shared.util.ColourUtils;
|
||||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||||
import net.minecraft.core.HolderLookup;
|
import net.minecraft.core.HolderLookup;
|
||||||
import net.minecraft.core.component.DataComponents;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.component.DyedItemColor;
|
|
||||||
import net.minecraft.world.item.crafting.CraftingBookCategory;
|
import net.minecraft.world.item.crafting.CraftingBookCategory;
|
||||||
import net.minecraft.world.item.crafting.CraftingInput;
|
import net.minecraft.world.item.crafting.CraftingInput;
|
||||||
import net.minecraft.world.item.crafting.CustomRecipe;
|
import net.minecraft.world.item.crafting.CustomRecipe;
|
||||||
@ -66,8 +64,7 @@ public final class ColourableRecipe extends CustomRecipe {
|
|||||||
|
|
||||||
return colourable.isEmpty()
|
return colourable.isEmpty()
|
||||||
? ItemStack.EMPTY
|
? ItemStack.EMPTY
|
||||||
: DataComponentUtil.createResult(colourable, DataComponents.DYED_COLOR, new DyedItemColor(tracker.getColour(), false));
|
: DataComponentUtil.setDyeColour(colourable.copyWithCount(1), tracker.getColour());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -6,7 +6,6 @@ package dan200.computercraft.shared.common;
|
|||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.world.Containers;
|
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
@ -60,12 +59,6 @@ public abstract class HorizontalContainerBlock extends BaseEntityBlock {
|
|||||||
return InteractionResult.CONSUME;
|
return InteractionResult.CONSUME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected final void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
|
|
||||||
Containers.dropContentsOnDestroy(state, newState, level, pos);
|
|
||||||
super.onRemove(state, level, pos, newState, isMoving);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final boolean hasAnalogOutputSignal(BlockState pState) {
|
protected final boolean hasAnalogOutputSignal(BlockState pState) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -21,10 +21,10 @@ import dan200.computercraft.shared.util.*;
|
|||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.HolderLookup;
|
import net.minecraft.core.HolderLookup;
|
||||||
|
import net.minecraft.core.component.DataComponentGetter;
|
||||||
import net.minecraft.core.component.DataComponentMap;
|
import net.minecraft.core.component.DataComponentMap;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.Tag;
|
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
import net.minecraft.world.LockCode;
|
import net.minecraft.world.LockCode;
|
||||||
@ -166,16 +166,16 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
|||||||
|
|
||||||
protected void loadServer(CompoundTag nbt, HolderLookup.Provider registries) {
|
protected void loadServer(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||||
// Load ID, label and power state
|
// Load ID, label and power state
|
||||||
computerID = nbt.contains(NBT_ID) ? nbt.getInt(NBT_ID) : -1;
|
computerID = nbt.getIntOr(NBT_ID, -1);
|
||||||
label = nbt.contains(NBT_LABEL) ? nbt.getString(NBT_LABEL) : null;
|
label = nbt.getStringOr(NBT_LABEL, null);
|
||||||
storageCapacity = nbt.contains(NBT_CAPACITY, Tag.TAG_ANY_NUMERIC) ? nbt.getLong(NBT_CAPACITY) : -1;
|
storageCapacity = nbt.getLongOr(NBT_CAPACITY, -1);
|
||||||
on = startOn = nbt.getBoolean(NBT_ON);
|
on = startOn = nbt.getBooleanOr(NBT_ON, false);
|
||||||
|
|
||||||
lockCode = LockCode.fromTag(nbt, registries);
|
lockCode = LockCode.fromTag(nbt, registries);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyImplicitComponents(DataComponentInput component) {
|
protected void applyImplicitComponents(DataComponentGetter component) {
|
||||||
super.applyImplicitComponents(component);
|
super.applyImplicitComponents(component);
|
||||||
label = DataComponentUtil.getCustomName(component.get(DataComponents.CUSTOM_NAME));
|
label = DataComponentUtil.getCustomName(component.get(DataComponents.CUSTOM_NAME));
|
||||||
computerID = NonNegativeId.getId(component.get(ModRegistry.DataComponents.COMPUTER_ID.get()));
|
computerID = NonNegativeId.getId(component.get(ModRegistry.DataComponents.COMPUTER_ID.get()));
|
||||||
@ -197,7 +197,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
|||||||
*/
|
*/
|
||||||
@OverridingMethodsMustInvokeSuper
|
@OverridingMethodsMustInvokeSuper
|
||||||
protected void collectSafeComponents(DataComponentMap.Builder builder) {
|
protected void collectSafeComponents(DataComponentMap.Builder builder) {
|
||||||
builder.set(ModRegistry.DataComponents.COMPUTER_ID.get(), NonNegativeId.of(computerID));
|
builder.set(ModRegistry.DataComponents.COMPUTER_ID.get(), computerID < 0 ? null : new NonNegativeId.Computer(computerID));
|
||||||
builder.set(DataComponents.CUSTOM_NAME, label == null ? null : Component.literal(label));
|
builder.set(DataComponents.CUSTOM_NAME, label == null ? null : Component.literal(label));
|
||||||
builder.set(ModRegistry.DataComponents.STORAGE_CAPACITY.get(), storageCapacity > 0 ? new StorageCapacity(storageCapacity) : null);
|
builder.set(ModRegistry.DataComponents.STORAGE_CAPACITY.get(), storageCapacity > 0 ? new StorageCapacity(storageCapacity) : null);
|
||||||
}
|
}
|
||||||
|
@ -96,30 +96,30 @@ public class NetworkedTerminal extends Terminal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void readFromNBT(CompoundTag nbt) {
|
public synchronized void readFromNBT(CompoundTag nbt) {
|
||||||
cursorX = nbt.getInt("term_cursorX");
|
cursorX = nbt.getIntOr("term_cursorX", 0);
|
||||||
cursorY = nbt.getInt("term_cursorY");
|
cursorY = nbt.getIntOr("term_cursorY", 0);
|
||||||
cursorBlink = nbt.getBoolean("term_cursorBlink");
|
cursorBlink = nbt.getBooleanOr("term_cursorBlink", false);
|
||||||
cursorColour = nbt.getInt("term_textColour");
|
cursorColour = nbt.getIntOr("term_textColour", 0);
|
||||||
cursorBackgroundColour = nbt.getInt("term_bgColour");
|
cursorBackgroundColour = nbt.getIntOr("term_bgColour", 0);
|
||||||
|
|
||||||
for (var n = 0; n < height; n++) {
|
for (var n = 0; n < height; n++) {
|
||||||
text[n].fill(' ');
|
text[n].fill(' ');
|
||||||
if (nbt.contains("term_text_" + n)) {
|
if (nbt.contains("term_text_" + n)) {
|
||||||
text[n].write(nbt.getString("term_text_" + n));
|
text[n].write(nbt.getStringOr("term_text_" + n, ""));
|
||||||
}
|
}
|
||||||
textColour[n].fill(BASE_16.charAt(cursorColour));
|
textColour[n].fill(BASE_16.charAt(cursorColour));
|
||||||
if (nbt.contains("term_textColour_" + n)) {
|
if (nbt.contains("term_textColour_" + n)) {
|
||||||
textColour[n].write(nbt.getString("term_textColour_" + n));
|
textColour[n].write(nbt.getStringOr("term_textColour_" + n, ""));
|
||||||
}
|
}
|
||||||
backgroundColour[n].fill(BASE_16.charAt(cursorBackgroundColour));
|
backgroundColour[n].fill(BASE_16.charAt(cursorBackgroundColour));
|
||||||
if (nbt.contains("term_textBgColour_" + n)) {
|
if (nbt.contains("term_textBgColour_" + n)) {
|
||||||
backgroundColour[n].write(nbt.getString("term_textBgColour_" + n));
|
backgroundColour[n].write(nbt.getStringOr("term_textBgColour_" + n, ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nbt.contains("term_palette")) {
|
if (nbt.contains("term_palette")) {
|
||||||
var rgb8 = nbt.getIntArray("term_palette");
|
var rgb8 = nbt.getIntArray("term_palette").orElse(null);
|
||||||
if (rgb8.length == Palette.PALETTE_SIZE) {
|
if (rgb8 != null && rgb8.length == Palette.PALETTE_SIZE) {
|
||||||
for (var i = 0; i < Palette.PALETTE_SIZE; i++) {
|
for (var i = 0; i < Palette.PALETTE_SIZE; i++) {
|
||||||
var colours = Palette.decodeRGB8(rgb8[i]);
|
var colours = Palette.decodeRGB8(rgb8[i]);
|
||||||
palette.setColour(i, colours[0], colours[1], colours[2]);
|
palette.setColour(i, colours[0], colours[1], colours[2]);
|
||||||
|
@ -61,7 +61,7 @@ public class ItemDetails {
|
|||||||
if (!enchants.isEmpty()) data.put("enchantments", enchants);
|
if (!enchants.isEmpty()) data.put("enchantments", enchants);
|
||||||
|
|
||||||
var unbreakable = stack.get(DataComponents.UNBREAKABLE);
|
var unbreakable = stack.get(DataComponents.UNBREAKABLE);
|
||||||
if (unbreakable != null && unbreakable.showInTooltip()) data.put("unbreakable", true);
|
if (unbreakable != null) data.put("unbreakable", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,18 +112,7 @@ public class CustomLecternBlock extends LecternBlock {
|
|||||||
super.tick(state, level, pos, random);
|
super.tick(state, level, pos, random);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
static void dropItem(Level level, BlockPos pos, BlockState state, ItemStack stack) {
|
||||||
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
|
|
||||||
if (state.is(newState.getBlock())) return;
|
|
||||||
|
|
||||||
if (level.getBlockEntity(pos) instanceof CustomLecternBlockEntity lectern) {
|
|
||||||
dropItem(level, pos, state, lectern.getItem().copy());
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onRemove(state, level, pos, newState, isMoving);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void dropItem(Level level, BlockPos pos, BlockState state, ItemStack stack) {
|
|
||||||
if (stack.isEmpty()) return;
|
if (stack.isEmpty()) return;
|
||||||
|
|
||||||
var direction = state.getValue(FACING);
|
var direction = state.getValue(FACING);
|
||||||
|
@ -16,7 +16,6 @@ import dan200.computercraft.shared.util.BlockEntityHelpers;
|
|||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.HolderLookup;
|
import net.minecraft.core.HolderLookup;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.Tag;
|
|
||||||
import net.minecraft.network.protocol.Packet;
|
import net.minecraft.network.protocol.Packet;
|
||||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||||
@ -34,6 +33,8 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||||||
import java.util.AbstractList;
|
import java.util.AbstractList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static dan200.computercraft.shared.lectern.CustomLecternBlock.dropItem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The block entity for our {@link CustomLecternBlock}.
|
* The block entity for our {@link CustomLecternBlock}.
|
||||||
*
|
*
|
||||||
@ -100,12 +101,17 @@ public final class CustomLecternBlockEntity extends BlockEntity {
|
|||||||
if (getLevel() != null) LecternBlock.signalPageChange(getLevel(), getBlockPos(), getBlockState());
|
if (getLevel() != null) LecternBlock.signalPageChange(getLevel(), getBlockPos(), getBlockState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preRemoveSideEffects(BlockPos pos, BlockState state) {
|
||||||
|
if (level != null) dropItem(level, pos, state, getItem().copy());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
|
public void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
|
||||||
super.loadAdditional(tag, registries);
|
super.loadAdditional(tag, registries);
|
||||||
|
|
||||||
item = tag.contains(NBT_ITEM, Tag.TAG_COMPOUND) ? ItemStack.parseOptional(registries, tag.getCompound(NBT_ITEM)) : ItemStack.EMPTY;
|
item = tag.getCompound(NBT_ITEM).flatMap(x -> ItemStack.parse(registries, x)).orElse(ItemStack.EMPTY);
|
||||||
page = tag.getInt(NBT_PAGE);
|
page = tag.getIntOr(NBT_PAGE, 0);
|
||||||
itemChanged();
|
itemChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import dan200.computercraft.api.media.IMedia;
|
|||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.config.ConfigSpec;
|
import dan200.computercraft.shared.config.ConfigSpec;
|
||||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||||
|
import dan200.computercraft.shared.util.IDAssigner;
|
||||||
import dan200.computercraft.shared.util.NonNegativeId;
|
import dan200.computercraft.shared.util.NonNegativeId;
|
||||||
import dan200.computercraft.shared.util.StorageCapacity;
|
import dan200.computercraft.shared.util.StorageCapacity;
|
||||||
import net.minecraft.core.HolderLookup;
|
import net.minecraft.core.HolderLookup;
|
||||||
@ -18,25 +19,28 @@ import net.minecraft.server.level.ServerLevel;
|
|||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.function.IntFunction;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Media that provides a {@link Mount}.
|
* Media that provides a {@link Mount}.
|
||||||
|
*
|
||||||
|
* @param <T> The type of media (disk/computer) we're mounting.
|
||||||
*/
|
*/
|
||||||
public final class MountMedia implements IMedia {
|
public final class MountMedia<T extends NonNegativeId> implements IMedia {
|
||||||
/**
|
/**
|
||||||
* A {@link MountMedia} implementation for {@linkplain ModRegistry.DataComponents#COMPUTER_ID computers}.
|
* A {@link MountMedia} implementation for {@linkplain ModRegistry.DataComponents#COMPUTER_ID computers}.
|
||||||
*/
|
*/
|
||||||
public static final IMedia COMPUTER = new MountMedia("computer", ModRegistry.DataComponents.COMPUTER_ID, false, ConfigSpec.computerSpaceLimit);
|
public static final IMedia COMPUTER = new MountMedia<>(IDAssigner.COMPUTER, ModRegistry.DataComponents.COMPUTER_ID, null, ConfigSpec.computerSpaceLimit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link MountMedia} implementation for {@linkplain ModRegistry.Items#DISK disks}.
|
* A {@link MountMedia} implementation for {@linkplain ModRegistry.Items#DISK disks}.
|
||||||
*/
|
*/
|
||||||
public static final IMedia DISK = new MountMedia("disk", ModRegistry.DataComponents.DISK_ID, true, ConfigSpec.floppySpaceLimit);
|
public static final IMedia DISK = new MountMedia<>("disk", ModRegistry.DataComponents.DISK_ID, NonNegativeId.Disk::new, ConfigSpec.floppySpaceLimit);
|
||||||
|
|
||||||
private final String subPath;
|
private final String subPath;
|
||||||
private final Supplier<DataComponentType<NonNegativeId>> id;
|
private final Supplier<DataComponentType<T>> id;
|
||||||
private final boolean createId;
|
private final @Nullable IntFunction<T> createId;
|
||||||
private final Supplier<Integer> defaultCapacity;
|
private final Supplier<Integer> defaultCapacity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,8 +53,8 @@ public final class MountMedia implements IMedia {
|
|||||||
*/
|
*/
|
||||||
public MountMedia(
|
public MountMedia(
|
||||||
String subPath,
|
String subPath,
|
||||||
Supplier<DataComponentType<NonNegativeId>> id,
|
Supplier<DataComponentType<T>> id,
|
||||||
boolean createId,
|
@Nullable IntFunction<T> createId,
|
||||||
Supplier<Integer> defaultCapacity
|
Supplier<Integer> defaultCapacity
|
||||||
) {
|
) {
|
||||||
this.subPath = subPath;
|
this.subPath = subPath;
|
||||||
@ -72,8 +76,8 @@ public final class MountMedia implements IMedia {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Mount createDataMount(ItemStack stack, ServerLevel level) {
|
public @Nullable Mount createDataMount(ItemStack stack, ServerLevel level) {
|
||||||
var id = createId
|
var id = createId != null
|
||||||
? NonNegativeId.getOrCreate(level.getServer(), stack, this.id.get(), subPath)
|
? NonNegativeId.getOrCreate(level.getServer(), stack, this.id.get(), createId, subPath)
|
||||||
: NonNegativeId.getId(stack.get(this.id.get()));
|
: NonNegativeId.getId(stack.get(this.id.get()));
|
||||||
if (id < 0) return null;
|
if (id < 0) return null;
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ public class PrintoutMenu extends AbstractContainerMenu {
|
|||||||
var currentItem = currentStack.getItem();
|
var currentItem = currentStack.getItem();
|
||||||
|
|
||||||
var slot = switch (hand) {
|
var slot = switch (hand) {
|
||||||
case MAIN_HAND -> player.getInventory().selected;
|
case MAIN_HAND -> player.getInventory().getSelectedSlot();
|
||||||
case OFF_HAND -> Inventory.SLOT_OFFHAND;
|
case OFF_HAND -> Inventory.SLOT_OFFHAND;
|
||||||
};
|
};
|
||||||
return new PrintoutMenu(
|
return new PrintoutMenu(
|
||||||
|
@ -9,6 +9,7 @@ import net.minecraft.world.InteractionResult;
|
|||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.context.UseOnContext;
|
import net.minecraft.world.item.context.UseOnContext;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An item that can be shift-right-clicked into a {@link DiskDriveBlock}.
|
* An item that can be shift-right-clicked into a {@link DiskDriveBlock}.
|
||||||
*/
|
*/
|
||||||
|
@ -11,6 +11,7 @@ import dan200.computercraft.api.media.PrintoutContents;
|
|||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.minecraft.core.component.DataComponentGetter;
|
||||||
import net.minecraft.core.component.DataComponentHolder;
|
import net.minecraft.core.component.DataComponentHolder;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
@ -77,7 +78,7 @@ public record PrintoutData(String title, List<Line> lines) implements PrintoutCo
|
|||||||
);
|
);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addToTooltip(Item.TooltipContext context, Consumer<Component> out, TooltipFlag flag) {
|
public void addToTooltip(Item.TooltipContext context, Consumer<Component> out, TooltipFlag flag, DataComponentGetter components) {
|
||||||
if (!title().isEmpty()) out.accept(Component.literal(title()));
|
if (!title().isEmpty()) out.accept(Component.literal(title()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import net.minecraft.world.entity.player.Player;
|
|||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
|
|
||||||
public class PrintoutItem extends Item {
|
public class PrintoutItem extends Item {
|
||||||
public PrintoutItem(Properties settings) {
|
public PrintoutItem(Properties settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
|
@ -7,6 +7,7 @@ package dan200.computercraft.shared.media.items;
|
|||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
|
import net.minecraft.core.component.DataComponentGetter;
|
||||||
import net.minecraft.core.component.DataComponentHolder;
|
import net.minecraft.core.component.DataComponentHolder;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
@ -44,7 +45,7 @@ public record TreasureDisk(String name, String path) implements TooltipProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addToTooltip(Item.TooltipContext context, Consumer<Component> out, TooltipFlag flags) {
|
public void addToTooltip(Item.TooltipContext context, Consumer<Component> out, TooltipFlag flags, DataComponentGetter components) {
|
||||||
out.accept(Component.literal(name()));
|
out.accept(Component.literal(name()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ import dan200.computercraft.shared.util.ColourTracker;
|
|||||||
import dan200.computercraft.shared.util.ColourUtils;
|
import dan200.computercraft.shared.util.ColourUtils;
|
||||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||||
import net.minecraft.core.HolderLookup;
|
import net.minecraft.core.HolderLookup;
|
||||||
import net.minecraft.core.component.DataComponents;
|
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
@ -24,7 +23,6 @@ import net.minecraft.world.entity.player.StackedItemContents;
|
|||||||
import net.minecraft.world.item.DyeColor;
|
import net.minecraft.world.item.DyeColor;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.Items;
|
import net.minecraft.world.item.Items;
|
||||||
import net.minecraft.world.item.component.DyedItemColor;
|
|
||||||
import net.minecraft.world.item.crafting.CraftingInput;
|
import net.minecraft.world.item.crafting.CraftingInput;
|
||||||
import net.minecraft.world.item.crafting.Ingredient;
|
import net.minecraft.world.item.crafting.Ingredient;
|
||||||
import net.minecraft.world.item.crafting.PlacementInfo;
|
import net.minecraft.world.item.crafting.PlacementInfo;
|
||||||
@ -70,15 +68,10 @@ public class DiskRecipe extends AbstractCraftingRecipe {
|
|||||||
var dyes = ColourUtils.DYES;
|
var dyes = ColourUtils.DYES;
|
||||||
List<RecipeDisplay> out = new ArrayList<>(dyes.size());
|
List<RecipeDisplay> out = new ArrayList<>(dyes.size());
|
||||||
for (var i = 0; i < dyes.size(); i++) {
|
for (var i = 0; i < dyes.size(); i++) {
|
||||||
var tracker = new ColourTracker();
|
|
||||||
tracker.addColour(DyeColor.byId(i));
|
|
||||||
|
|
||||||
out.add(new ShapelessCraftingRecipeDisplay(
|
out.add(new ShapelessCraftingRecipeDisplay(
|
||||||
Stream.concat(ingredients.stream(), Stream.of(Ingredient.of(BuiltInRegistries.ITEM.getOrThrow(dyes.get(i)))))
|
Stream.concat(ingredients.stream(), Stream.of(Ingredient.of(BuiltInRegistries.ITEM.getOrThrow(dyes.get(i)))))
|
||||||
.map(Ingredient::display).toList(),
|
.map(Ingredient::display).toList(),
|
||||||
new SlotDisplay.ItemStackSlotDisplay(DataComponentUtil.createStack(
|
new SlotDisplay.ItemStackSlotDisplay(DataComponentUtil.createDyedStack(ModRegistry.Items.DISK.get(), DyeColor.byId(i).getTextureDiffuseColor())),
|
||||||
ModRegistry.Items.DISK.get(), DataComponents.DYED_COLOR, new DyedItemColor(tracker.getColour(), false)
|
|
||||||
)),
|
|
||||||
new SlotDisplay.ItemSlotDisplay(Items.CRAFTING_TABLE)
|
new SlotDisplay.ItemSlotDisplay(Items.CRAFTING_TABLE)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -114,7 +107,7 @@ public class DiskRecipe extends AbstractCraftingRecipe {
|
|||||||
if (dye != null) tracker.addColour(dye);
|
if (dye != null) tracker.addColour(dye);
|
||||||
}
|
}
|
||||||
|
|
||||||
return DataComponentUtil.createStack(ModRegistry.Items.DISK.get(), DataComponents.DYED_COLOR, new DyedItemColor(tracker.hasColour() ? tracker.getColour() : Colour.BLUE.getHex(), false));
|
return DataComponentUtil.createDyedStack(ModRegistry.Items.DISK.get(), tracker.getColourOr(Colour.BLUE.getHex()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -116,7 +116,7 @@ public final class DiskDriveBlockEntity extends AbstractContainerBlockEntity imp
|
|||||||
@Override
|
@Override
|
||||||
public void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
|
public void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||||
super.loadAdditional(nbt, registries);
|
super.loadAdditional(nbt, registries);
|
||||||
setDiskStack(nbt.contains(NBT_ITEM) ? ItemStack.parseOptional(registries, nbt.getCompound(NBT_ITEM)) : ItemStack.EMPTY);
|
setDiskStack(nbt.getCompound(NBT_ITEM).flatMap(x -> ItemStack.parse(registries, x)).orElse(ItemStack.EMPTY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -12,7 +12,6 @@ import dan200.computercraft.shared.platform.ComponentAccess;
|
|||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.Tag;
|
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
@ -104,11 +103,8 @@ public final class WiredModemLocalPeripheral {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void read(CompoundTag tag, String suffix) {
|
public void read(CompoundTag tag, String suffix) {
|
||||||
id = tag.contains(NBT_PERIPHERAL_ID + suffix, Tag.TAG_ANY_NUMERIC)
|
id = tag.getIntOr(NBT_PERIPHERAL_ID + suffix, -1);
|
||||||
? tag.getInt(NBT_PERIPHERAL_ID + suffix) : -1;
|
type = tag.getStringOr(NBT_PERIPHERAL_TYPE + suffix, null);
|
||||||
|
|
||||||
type = tag.contains(NBT_PERIPHERAL_TYPE + suffix, Tag.TAG_STRING)
|
|
||||||
? tag.getString(NBT_PERIPHERAL_TYPE + suffix) : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -83,15 +83,6 @@ public class MonitorBlock extends HorizontalDirectionalBlock implements EntityBl
|
|||||||
.setValue(ORIENTATION, orientation);
|
.setValue(ORIENTATION, orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected final void onRemove(BlockState block, Level world, BlockPos pos, BlockState replace, boolean bool) {
|
|
||||||
if (block.getBlock() == replace.getBlock()) return;
|
|
||||||
|
|
||||||
var tile = world.getBlockEntity(pos);
|
|
||||||
super.onRemove(block, world, pos, replace, bool);
|
|
||||||
if (tile instanceof MonitorBlockEntity generic) generic.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rand) {
|
protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rand) {
|
||||||
var te = world.getBlockEntity(pos);
|
var te = world.getBlockEntity(pos);
|
||||||
|
@ -57,6 +57,12 @@ public class MonitorBlockEntity extends BlockEntity {
|
|||||||
private boolean needsUpdate = false;
|
private boolean needsUpdate = false;
|
||||||
private boolean needsValidating = false;
|
private boolean needsValidating = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this monitor is in the process of being removed (see {@link #preRemoveSideEffects(BlockPos, BlockState)},
|
||||||
|
* and so should be ignored.
|
||||||
|
*/
|
||||||
|
private boolean isRemoving = false;
|
||||||
|
|
||||||
// MonitorWatcher state.
|
// MonitorWatcher state.
|
||||||
boolean enqueued;
|
boolean enqueued;
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -82,13 +88,16 @@ public class MonitorBlockEntity extends BlockEntity {
|
|||||||
@Override
|
@Override
|
||||||
public void clearRemoved() {
|
public void clearRemoved() {
|
||||||
super.clearRemoved();
|
super.clearRemoved();
|
||||||
|
isRemoving = false;
|
||||||
needsValidating = true; // Same, tbh
|
needsValidating = true; // Same, tbh
|
||||||
TickScheduler.schedule(tickToken);
|
TickScheduler.schedule(tickToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy() {
|
@Override
|
||||||
// TODO: Call this before using the block
|
public void preRemoveSideEffects(BlockPos blockPos, BlockState blockState) {
|
||||||
if (!getLevel().isClientSide) contractNeighbours();
|
super.preRemoveSideEffects(blockPos, blockState);
|
||||||
|
isRemoving = true;
|
||||||
|
if (level != null && !getLevel().isClientSide) contractNeighbours();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -113,10 +122,10 @@ public class MonitorBlockEntity extends BlockEntity {
|
|||||||
var oldXIndex = xIndex;
|
var oldXIndex = xIndex;
|
||||||
var oldYIndex = yIndex;
|
var oldYIndex = yIndex;
|
||||||
|
|
||||||
xIndex = nbt.getInt(NBT_X);
|
xIndex = nbt.getIntOr(NBT_X, 0);
|
||||||
yIndex = nbt.getInt(NBT_Y);
|
yIndex = nbt.getIntOr(NBT_Y, 0);
|
||||||
width = nbt.getInt(NBT_WIDTH);
|
width = nbt.getIntOr(NBT_WIDTH, 1);
|
||||||
height = nbt.getInt(NBT_HEIGHT);
|
height = nbt.getIntOr(NBT_HEIGHT, 1);
|
||||||
|
|
||||||
if (level != null && level.isClientSide) onClientLoad(oldXIndex, oldYIndex);
|
if (level != null && level.isClientSide) onClientLoad(oldXIndex, oldYIndex);
|
||||||
}
|
}
|
||||||
@ -245,13 +254,11 @@ public class MonitorBlockEntity extends BlockEntity {
|
|||||||
public Direction getDirection() {
|
public Direction getDirection() {
|
||||||
// Ensure we're actually a monitor block. This _should_ always be the case, but sometimes there's
|
// Ensure we're actually a monitor block. This _should_ always be the case, but sometimes there's
|
||||||
// fun problems with the block being missing on the client.
|
// fun problems with the block being missing on the client.
|
||||||
var state = getBlockState();
|
return getBlockState().getValueOrElse(MonitorBlock.FACING, Direction.NORTH);
|
||||||
return state.hasProperty(MonitorBlock.FACING) ? state.getValue(MonitorBlock.FACING) : Direction.NORTH;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Direction getOrientation() {
|
public Direction getOrientation() {
|
||||||
var state = getBlockState();
|
return getBlockState().getValueOrElse(MonitorBlock.ORIENTATION, Direction.NORTH);
|
||||||
return state.hasProperty(MonitorBlock.ORIENTATION) ? state.getValue(MonitorBlock.ORIENTATION) : Direction.NORTH;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Direction getFront() {
|
public Direction getFront() {
|
||||||
@ -286,7 +293,10 @@ public class MonitorBlockEntity extends BlockEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean isCompatible(MonitorBlockEntity other) {
|
boolean isCompatible(MonitorBlockEntity other) {
|
||||||
return advanced == other.advanced && getOrientation() == other.getOrientation() && getDirection() == other.getDirection();
|
return !other.isRemoved() && !other.isRemoving
|
||||||
|
&& advanced == other.advanced
|
||||||
|
&& getOrientation() == other.getOrientation()
|
||||||
|
&& getDirection() == other.getDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -303,8 +313,7 @@ public class MonitorBlockEntity extends BlockEntity {
|
|||||||
var world = getLevel();
|
var world = getLevel();
|
||||||
if (world == null || !world.isLoaded(pos)) return MonitorState.UNLOADED;
|
if (world == null || !world.isLoaded(pos)) return MonitorState.UNLOADED;
|
||||||
|
|
||||||
var tile = world.getBlockEntity(pos);
|
if (!(world.getBlockEntity(pos) instanceof MonitorBlockEntity monitor)) return MonitorState.MISSING;
|
||||||
if (!(tile instanceof MonitorBlockEntity monitor)) return MonitorState.MISSING;
|
|
||||||
|
|
||||||
return isCompatible(monitor) ? MonitorState.present(monitor) : MonitorState.MISSING;
|
return isCompatible(monitor) ? MonitorState.present(monitor) : MonitorState.MISSING;
|
||||||
}
|
}
|
||||||
|
@ -60,8 +60,8 @@ public final class PrinterBlockEntity extends AbstractContainerBlockEntity imple
|
|||||||
|
|
||||||
// Read page
|
// Read page
|
||||||
synchronized (page) {
|
synchronized (page) {
|
||||||
printing = nbt.getBoolean(NBT_PRINTING);
|
printing = nbt.getBooleanOr(NBT_PRINTING, false);
|
||||||
pageTitle = nbt.getString(NBT_PAGE_TITLE);
|
pageTitle = nbt.getStringOr(NBT_PAGE_TITLE, "");
|
||||||
page.readFromNBT(nbt);
|
page.readFromNBT(nbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,8 @@ import dan200.computercraft.api.pocket.IPocketAccess;
|
|||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.impl.PocketUpgrades;
|
import dan200.computercraft.impl.PocketUpgrades;
|
||||||
import net.minecraft.core.NonNullList;
|
import net.minecraft.world.Container;
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
@ -69,10 +70,12 @@ public class PocketAPI implements ILuaAPI {
|
|||||||
|
|
||||||
// Attempt to find the upgrade, starting in the main segment, and then looking in the opposite
|
// Attempt to find the upgrade, starting in the main segment, and then looking in the opposite
|
||||||
// one. We start from the position the item is currently in and loop round to the start.
|
// one. We start from the position the item is currently in and loop round to the start.
|
||||||
var newUpgrade = findUpgrade(inventory.items, inventory.selected, previousUpgrade);
|
UpgradeData<IPocketUpgrade> newUpgrade = null;
|
||||||
if (newUpgrade == null) {
|
for (var i = 0; i < Inventory.INVENTORY_SIZE; i++) {
|
||||||
newUpgrade = findUpgrade(inventory.offhand, 0, previousUpgrade);
|
newUpgrade = findUpgrade(inventory, (i + inventory.getSelectedSlot()) % Inventory.INVENTORY_SIZE, previousUpgrade);
|
||||||
|
if (newUpgrade != null) break;
|
||||||
}
|
}
|
||||||
|
if (newUpgrade == null) newUpgrade = findUpgrade(inventory, Inventory.SLOT_OFFHAND, previousUpgrade);
|
||||||
if (newUpgrade == null) return new Object[]{ false, "Cannot find a valid upgrade" };
|
if (newUpgrade == null) return new Object[]{ false, "Cannot find a valid upgrade" };
|
||||||
|
|
||||||
// Remove the current upgrade
|
// Remove the current upgrade
|
||||||
@ -113,21 +116,18 @@ public class PocketAPI implements ILuaAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable UpgradeData<IPocketUpgrade> findUpgrade(NonNullList<ItemStack> inv, int start, @Nullable UpgradeData<IPocketUpgrade> previous) {
|
private @Nullable UpgradeData<IPocketUpgrade> findUpgrade(Container inv, int slot, @Nullable UpgradeData<IPocketUpgrade> previous) {
|
||||||
for (var i = 0; i < inv.size(); i++) {
|
var invStack = inv.getItem(slot);
|
||||||
var invStack = inv.get((i + start) % inv.size());
|
if (invStack.isEmpty()) return null;
|
||||||
if (!invStack.isEmpty()) {
|
|
||||||
var newUpgrade = PocketUpgrades.instance().get(pocket.getLevel().registryAccess(), invStack);
|
|
||||||
|
|
||||||
if (newUpgrade != null && !Objects.equals(newUpgrade, previous)) {
|
var newUpgrade = PocketUpgrades.instance().get(pocket.getLevel().registryAccess(), invStack);
|
||||||
// Consume an item from this stack and exit the loop
|
if (newUpgrade != null && !Objects.equals(newUpgrade, previous)) {
|
||||||
invStack = invStack.copy();
|
// Consume an item from this stack and exit the loop
|
||||||
invStack.shrink(1);
|
invStack = invStack.copy();
|
||||||
inv.set((i + start) % inv.size(), invStack.isEmpty() ? ItemStack.EMPTY : invStack);
|
invStack.shrink(1);
|
||||||
|
inv.setItem(slot, invStack.isEmpty() ? ItemStack.EMPTY : invStack);
|
||||||
|
|
||||||
return newUpgrade;
|
return newUpgrade;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -12,12 +12,12 @@ import dan200.computercraft.shared.computer.core.ServerComputer;
|
|||||||
import dan200.computercraft.shared.network.client.PocketComputerDataMessage;
|
import dan200.computercraft.shared.network.client.PocketComputerDataMessage;
|
||||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||||
|
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.component.DyedItemColor;
|
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
@ -93,7 +93,11 @@ public final class PocketBrain implements IPocketAccess {
|
|||||||
if (!dirty) return false;
|
if (!dirty) return false;
|
||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
|
|
||||||
stack.set(DataComponents.DYED_COLOR, colour == -1 ? null : new DyedItemColor(colour, false));
|
if (colour == -1) {
|
||||||
|
stack.remove(DataComponents.DYED_COLOR);
|
||||||
|
} else {
|
||||||
|
DataComponentUtil.setDyeColour(stack, colour);
|
||||||
|
}
|
||||||
PocketComputerItem.setUpgrade(stack, upgrade);
|
PocketComputerItem.setUpgrade(stack, upgrade);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ import net.minecraft.core.BlockPos;
|
|||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EquipmentSlot;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.item.ItemEntity;
|
import net.minecraft.world.entity.item.ItemEntity;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
@ -107,6 +109,24 @@ public sealed interface PocketHolder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pocket computer in a {@link LivingEntity}'s slot.
|
||||||
|
*
|
||||||
|
* @param entity The current player.
|
||||||
|
* @param slot The slot the pocket computer is in.
|
||||||
|
*/
|
||||||
|
record LivingEntityHolder(LivingEntity entity, EquipmentSlot slot) implements EntityHolder {
|
||||||
|
@Override
|
||||||
|
public boolean isValid(ServerComputer computer) {
|
||||||
|
return entity().isAlive() && PocketComputerItem.isServerComputer(computer, entity().getItemBySlot(slot()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setChanged() {
|
||||||
|
// TODO: What can we do?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pocket computer in an {@link ItemEntity}.
|
* A pocket computer in an {@link ItemEntity}.
|
||||||
*
|
*
|
||||||
|
@ -31,6 +31,8 @@ import net.minecraft.server.level.ServerPlayer;
|
|||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EquipmentSlot;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.item.ItemEntity;
|
import net.minecraft.world.entity.item.ItemEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
@ -102,16 +104,13 @@ public class PocketComputerItem extends Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void inventoryTick(ItemStack stack, Level world, Entity entity, int compartmentSlot, boolean selected) {
|
public void inventoryTick(ItemStack stack, ServerLevel level, Entity entity, @Nullable EquipmentSlot slot) {
|
||||||
// This (in vanilla at least) is only called for players. Don't bother to handle other entities.
|
if (entity instanceof ServerPlayer player) {
|
||||||
if (world.isClientSide || !(entity instanceof ServerPlayer player)) return;
|
var invSlot = InventoryUtil.findItemInInventory(player.getInventory(), stack);
|
||||||
|
if (invSlot != -1) tick(stack, new PocketHolder.PlayerHolder(player, invSlot), false);
|
||||||
// Find the actual slot the item exists in, aborting if it can't be found.
|
} else if (slot != null && entity instanceof LivingEntity living) {
|
||||||
var slot = InventoryUtil.getInventorySlotFromCompartment(player, compartmentSlot, stack);
|
tick(stack, new PocketHolder.LivingEntityHolder(living, slot), true);
|
||||||
if (slot < 0) return;
|
}
|
||||||
|
|
||||||
// If we're in the inventory, create a computer and keep it alive.
|
|
||||||
tick(stack, new PocketHolder.PlayerHolder(player, slot), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ForgeOverride
|
@ForgeOverride
|
||||||
@ -200,7 +199,7 @@ public class PocketComputerItem extends Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var computerID = NonNegativeId.getOrCreate(level.getServer(), stack, ModRegistry.DataComponents.COMPUTER_ID.get(), IDAssigner.COMPUTER);
|
var computerID = NonNegativeId.getOrCreate(level.getServer(), stack, ModRegistry.DataComponents.COMPUTER_ID.get(), NonNegativeId.Computer::new, IDAssigner.COMPUTER);
|
||||||
var brain = new PocketBrain(
|
var brain = new PocketBrain(
|
||||||
holder, getUpgradeWithData(stack), DyedItemColor.getOrDefault(stack, -1),
|
holder, getUpgradeWithData(stack), DyedItemColor.getOrDefault(stack, -1),
|
||||||
ServerComputer.properties(computerID, getFamily())
|
ServerComputer.properties(computerID, getFamily())
|
||||||
|
@ -7,13 +7,13 @@ package dan200.computercraft.shared.turtle;
|
|||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
import dan200.computercraft.shared.platform.ContainerTransfer;
|
import dan200.computercraft.shared.platform.ContainerTransfer;
|
||||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
|
import dan200.computercraft.shared.turtle.core.TurtlePlayer;
|
||||||
import dan200.computercraft.shared.util.DropConsumer;
|
import dan200.computercraft.shared.util.DropConsumer;
|
||||||
import dan200.computercraft.shared.util.InventoryUtil;
|
import dan200.computercraft.shared.util.InventoryUtil;
|
||||||
import dan200.computercraft.shared.util.WorldUtil;
|
import dan200.computercraft.shared.util.WorldUtil;
|
||||||
|
import net.minecraft.world.Container;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
public class TurtleUtil {
|
public class TurtleUtil {
|
||||||
/**
|
/**
|
||||||
* Get a view of the turtle's inventory starting at the currently selected slot. This should be used when
|
* Get a view of the turtle's inventory starting at the currently selected slot. This should be used when
|
||||||
@ -43,6 +43,10 @@ public class TurtleUtil {
|
|||||||
* @param stack The stack to store.
|
* @param stack The stack to store.
|
||||||
*/
|
*/
|
||||||
public static void storeItemOrDrop(ITurtleAccess turtle, ItemStack stack) {
|
public static void storeItemOrDrop(ITurtleAccess turtle, ItemStack stack) {
|
||||||
|
storeItemOrDrop(turtle, turtle.getInventory(), stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void storeItemOrDrop(ITurtleAccess turtle, Container container, ItemStack stack) {
|
||||||
if (stack.isEmpty()) return;
|
if (stack.isEmpty()) return;
|
||||||
if (turtle.isRemoved()) {
|
if (turtle.isRemoved()) {
|
||||||
WorldUtil.dropItemStack(turtle.getLevel(), turtle.getPosition(), null, stack);
|
WorldUtil.dropItemStack(turtle.getLevel(), turtle.getPosition(), null, stack);
|
||||||
@ -50,18 +54,32 @@ public class TurtleUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Put the remainder back in the turtle
|
// Put the remainder back in the turtle
|
||||||
var remainder = InventoryUtil.storeItemsFromOffset(turtle.getInventory(), stack, turtle.getSelectedSlot());
|
var remainder = InventoryUtil.storeItemsFromOffset(container, stack, turtle.getSelectedSlot());
|
||||||
if (remainder.isEmpty()) return;
|
if (remainder.isEmpty()) return;
|
||||||
|
|
||||||
WorldUtil.dropItemStack(turtle.getLevel(), turtle.getPosition(), turtle.getDirection().getOpposite(), remainder);
|
WorldUtil.dropItemStack(turtle.getLevel(), turtle.getPosition(), turtle.getDirection().getOpposite(), remainder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Function<ItemStack, ItemStack> dropConsumer(ITurtleAccess turtle) {
|
/**
|
||||||
return stack -> turtle.isRemoved() ? stack : InventoryUtil.storeItemsFromOffset(turtle.getInventory(), stack, turtle.getSelectedSlot());
|
* Stop a {@link DropConsumer}, and sync the items back to the inventory.
|
||||||
|
*
|
||||||
|
* @param turtle The turtle to store drops to.
|
||||||
|
*/
|
||||||
|
public static void stopConsuming(ITurtleAccess turtle) {
|
||||||
|
for (var stack : DropConsumer.stop()) storeItemOrDrop(turtle, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void stopConsuming(ITurtleAccess turtle) {
|
/**
|
||||||
var direction = turtle.isRemoved() ? null : turtle.getDirection().getOpposite();
|
* Stop a {@link DropConsumer}, and sync the items back to the {@link TurtlePlayer} inventory.
|
||||||
DropConsumer.clearAndDrop(turtle.getLevel(), turtle.getPosition(), direction);
|
* <p>
|
||||||
|
* When using {@link TurtlePlayer#loadInventory(ITurtleAccess)}/{@link TurtlePlayer#unloadInventory(ITurtleAccess)},
|
||||||
|
* changes to the turtle's inventory are overridden. This means items must be stored to the <em>player's</em>
|
||||||
|
* inventory, not the turtle's.
|
||||||
|
*
|
||||||
|
* @param turtle The turtle performing this action.
|
||||||
|
* @param player The turtle player to store items back to.
|
||||||
|
*/
|
||||||
|
public static void stopConsumingPlayer(ITurtleAccess turtle, TurtlePlayer player) {
|
||||||
|
for (var stack : DropConsumer.stop()) storeItemOrDrop(turtle, player.player().getInventory(), stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ import net.minecraft.core.BlockPos;
|
|||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.util.RandomSource;
|
import net.minecraft.util.RandomSource;
|
||||||
import net.minecraft.world.Containers;
|
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
@ -122,21 +121,6 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
|
|||||||
return super.updateShape(state, level, ticker, pos, side, otherPos, neighborState, randomSource);
|
return super.updateShape(state, level, ticker, pos, side, otherPos, neighborState, randomSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected final void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
|
|
||||||
if (state.is(newState.getBlock())) return;
|
|
||||||
|
|
||||||
// Most blocks drop items and then remove the BE. However, if a turtle is consuming drops right now, that can
|
|
||||||
// lead to loops where it tries to insert an item back into the inventory. To prevent this, take a reference to
|
|
||||||
// the turtle BE now, remove it, and then drop the items.
|
|
||||||
var turtle = !level.isClientSide && level.getBlockEntity(pos) instanceof TurtleBlockEntity t && !t.hasMoved()
|
|
||||||
? t : null;
|
|
||||||
|
|
||||||
super.onRemove(state, level, pos, newState, isMoving);
|
|
||||||
|
|
||||||
if (turtle != null) Containers.dropContents(level, pos, turtle);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity entity, ItemStack stack) {
|
public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity entity, ItemStack stack) {
|
||||||
super.setPlacedBy(level, pos, state, entity, stack);
|
super.setPlacedBy(level, pos, state, entity, stack);
|
||||||
|
@ -28,6 +28,7 @@ import net.minecraft.core.BlockPos;
|
|||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.HolderLookup;
|
import net.minecraft.core.HolderLookup;
|
||||||
import net.minecraft.core.NonNullList;
|
import net.minecraft.core.NonNullList;
|
||||||
|
import net.minecraft.core.component.DataComponentGetter;
|
||||||
import net.minecraft.core.component.DataComponentMap;
|
import net.minecraft.core.component.DataComponentMap;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
@ -40,6 +41,7 @@ import net.minecraft.world.entity.player.Player;
|
|||||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.component.DyedItemColor;
|
import net.minecraft.world.item.component.DyedItemColor;
|
||||||
|
import net.minecraft.world.item.component.TooltipDisplay;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
@ -119,6 +121,11 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
|
|||||||
protected void updateBlockState(ComputerState newState) {
|
protected void updateBlockState(ComputerState newState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preRemoveSideEffects(BlockPos blockPos, BlockState blockState) {
|
||||||
|
if (!hasMoved()) super.preRemoveSideEffects(blockPos, blockState);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void neighborChanged() {
|
public void neighborChanged() {
|
||||||
if (moveState == MoveState.NOT_MOVED) super.neighborChanged();
|
if (moveState == MoveState.NOT_MOVED) super.neighborChanged();
|
||||||
@ -157,7 +164,7 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyImplicitComponents(DataComponentInput component) {
|
protected void applyImplicitComponents(DataComponentGetter component) {
|
||||||
super.applyImplicitComponents(component);
|
super.applyImplicitComponents(component);
|
||||||
|
|
||||||
var colour = component.get(DataComponents.DYED_COLOR);
|
var colour = component.get(DataComponents.DYED_COLOR);
|
||||||
@ -173,7 +180,10 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
|
|||||||
protected void collectSafeComponents(DataComponentMap.Builder builder) {
|
protected void collectSafeComponents(DataComponentMap.Builder builder) {
|
||||||
super.collectSafeComponents(builder);
|
super.collectSafeComponents(builder);
|
||||||
|
|
||||||
builder.set(DataComponents.DYED_COLOR, brain.getColour() == -1 ? null : new DyedItemColor(brain.getColour(), false));
|
if (brain.getColour() != -1) {
|
||||||
|
builder.set(DataComponents.DYED_COLOR, new DyedItemColor(brain.getColour()));
|
||||||
|
builder.set(DataComponents.TOOLTIP_DISPLAY, TooltipDisplay.DEFAULT.withHidden(DataComponents.DYED_COLOR, true));
|
||||||
|
}
|
||||||
builder.set(ModRegistry.DataComponents.OVERLAY.get(), brain.getOverlay());
|
builder.set(ModRegistry.DataComponents.OVERLAY.get(), brain.getOverlay());
|
||||||
builder.set(ModRegistry.DataComponents.FUEL.get(), brain.getFuelLevel());
|
builder.set(ModRegistry.DataComponents.FUEL.get(), brain.getFuelLevel());
|
||||||
builder.set(ModRegistry.DataComponents.LEFT_TURTLE_UPGRADE.get(), withPersistedData(brain.getUpgradeWithData(TurtleSide.LEFT)));
|
builder.set(ModRegistry.DataComponents.LEFT_TURTLE_UPGRADE.get(), withPersistedData(brain.getUpgradeWithData(TurtleSide.LEFT)));
|
||||||
@ -300,7 +310,7 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
|
|||||||
@Override
|
@Override
|
||||||
public void loadClient(CompoundTag nbt, HolderLookup.Provider registries) {
|
public void loadClient(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||||
super.loadClient(nbt, registries);
|
super.loadClient(nbt, registries);
|
||||||
label = nbt.contains(NBT_LABEL) ? nbt.getString(NBT_LABEL) : null;
|
label = nbt.getStringOr(NBT_LABEL, null);
|
||||||
brain.readDescription(nbt, registries);
|
brain.readDescription(nbt, registries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,6 @@ import net.minecraft.core.HolderLookup;
|
|||||||
import net.minecraft.core.component.DataComponentPatch;
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
import net.minecraft.core.particles.ParticleTypes;
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.Tag;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.tags.FluidTags;
|
import net.minecraft.tags.FluidTags;
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
@ -133,8 +132,8 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
*/
|
*/
|
||||||
private void readCommon(CompoundTag nbt, HolderLookup.Provider registries) {
|
private void readCommon(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||||
// Read fields
|
// Read fields
|
||||||
colourHex = nbt.contains(NBT_COLOUR) ? nbt.getInt(NBT_COLOUR) : -1;
|
colourHex = nbt.getIntOr(NBT_COLOUR, -1);
|
||||||
fuelLevel = nbt.contains(NBT_FUEL) ? nbt.getInt(NBT_FUEL) : 0;
|
fuelLevel = nbt.getIntOr(NBT_FUEL, 0);
|
||||||
overlay = nbt.contains(NBT_OVERLAY) ? NBTUtil.decodeFrom(TurtleOverlay.CODEC, registries, nbt, NBT_OVERLAY) : null;
|
overlay = nbt.contains(NBT_OVERLAY) ? NBTUtil.decodeFrom(TurtleOverlay.CODEC, registries, nbt, NBT_OVERLAY) : null;
|
||||||
|
|
||||||
// Read upgrades
|
// Read upgrades
|
||||||
@ -145,7 +144,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
private void writeCommon(CompoundTag nbt, HolderLookup.Provider registries) {
|
private void writeCommon(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||||
nbt.putInt(NBT_FUEL, fuelLevel);
|
nbt.putInt(NBT_FUEL, fuelLevel);
|
||||||
if (colourHex != -1) nbt.putInt(NBT_COLOUR, colourHex);
|
if (colourHex != -1) nbt.putInt(NBT_COLOUR, colourHex);
|
||||||
if (overlay != null) NBTUtil.encodeTo(TurtleOverlay.CODEC, registries, nbt, NBT_OVERLAY, overlay);
|
NBTUtil.encodeTo(TurtleOverlay.CODEC, registries, nbt, NBT_OVERLAY, overlay);
|
||||||
|
|
||||||
// Write upgrades
|
// Write upgrades
|
||||||
NBTUtil.encodeTo(TurtleUpgrades.instance().upgradeDataCodec(), registries, nbt, NBT_LEFT_UPGRADE, getUpgradeWithData(TurtleSide.LEFT));
|
NBTUtil.encodeTo(TurtleUpgrades.instance().upgradeDataCodec(), registries, nbt, NBT_LEFT_UPGRADE, getUpgradeWithData(TurtleSide.LEFT));
|
||||||
@ -156,14 +155,14 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
readCommon(nbt, registries);
|
readCommon(nbt, registries);
|
||||||
|
|
||||||
// Read state
|
// Read state
|
||||||
selectedSlot = nbt.getInt(NBT_SLOT);
|
selectedSlot = nbt.getIntOr(NBT_SLOT, 0);
|
||||||
|
|
||||||
// Read owner
|
// Read owner
|
||||||
if (nbt.contains("Owner", Tag.TAG_COMPOUND)) {
|
var owner = nbt.getCompound("Owner").orElse(null);
|
||||||
var owner = nbt.getCompound("Owner");
|
if (owner != null) {
|
||||||
owningPlayer = new GameProfile(
|
owningPlayer = new GameProfile(
|
||||||
new UUID(owner.getLong("UpperId"), owner.getLong("LowerId")),
|
new UUID(owner.getLongOr("UpperId", 0), owner.getLongOr("LowerId", 0)),
|
||||||
owner.getString("Name")
|
owner.getStringOr("Name", "")
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
owningPlayer = null;
|
owningPlayer = null;
|
||||||
@ -191,7 +190,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
readCommon(nbt, registries);
|
readCommon(nbt, registries);
|
||||||
|
|
||||||
// Animation
|
// Animation
|
||||||
var anim = TurtleAnimation.values()[nbt.getInt("Animation")];
|
var anim = TurtleAnimation.values()[nbt.getIntOr("Animation", 0)];
|
||||||
if (anim != animation &&
|
if (anim != animation &&
|
||||||
anim != TurtleAnimation.WAIT &&
|
anim != TurtleAnimation.WAIT &&
|
||||||
anim != TurtleAnimation.SHORT_WAIT &&
|
anim != TurtleAnimation.SHORT_WAIT &&
|
||||||
|
@ -13,7 +13,6 @@ import dan200.computercraft.api.turtle.TurtleCommandResult;
|
|||||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
import dan200.computercraft.shared.turtle.TurtleUtil;
|
import dan200.computercraft.shared.turtle.TurtleUtil;
|
||||||
import dan200.computercraft.shared.util.DropConsumer;
|
import dan200.computercraft.shared.util.DropConsumer;
|
||||||
import dan200.computercraft.shared.util.InventoryUtil;
|
|
||||||
import dan200.computercraft.shared.util.WorldUtil;
|
import dan200.computercraft.shared.util.WorldUtil;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
@ -106,9 +105,9 @@ public class TurtlePlaceCommand implements TurtleCommand {
|
|||||||
var hitEntity = entityHit.getEntity();
|
var hitEntity = entityHit.getEntity();
|
||||||
var hitPos = entityHit.getLocation();
|
var hitPos = entityHit.getLocation();
|
||||||
|
|
||||||
DropConsumer.set(hitEntity, drop -> InventoryUtil.storeItemsFromOffset(turtlePlayer.player().getInventory(), drop, 1));
|
DropConsumer.set(hitEntity);
|
||||||
var placed = PlatformHelper.get().interactWithEntity(turtlePlayer.player(), hitEntity, hitPos);
|
var placed = PlatformHelper.get().interactWithEntity(turtlePlayer.player(), hitEntity, hitPos);
|
||||||
TurtleUtil.stopConsuming(turtle);
|
TurtleUtil.stopConsumingPlayer(turtle, turtlePlayer);
|
||||||
return placed;
|
return placed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ public final class TurtlePlayer {
|
|||||||
|
|
||||||
public void loadInventory(ItemStack stack) {
|
public void loadInventory(ItemStack stack) {
|
||||||
player.getInventory().clearContent();
|
player.getInventory().clearContent();
|
||||||
player.getInventory().selected = 0;
|
player.getInventory().setSelectedSlot(0);
|
||||||
player.getInventory().setItem(0, stack);
|
player.getInventory().setItem(0, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ public final class TurtlePlayer {
|
|||||||
var slots = turtleInventory.getContainerSize();
|
var slots = turtleInventory.getContainerSize();
|
||||||
|
|
||||||
// Load up the fake inventory
|
// Load up the fake inventory
|
||||||
inventory.selected = 0;
|
inventory.setSelectedSlot(0);
|
||||||
for (var i = 0; i < slots; i++) {
|
for (var i = 0; i < slots; i++) {
|
||||||
inventory.setItem(i, turtleInventory.getItem((currentSlot + i) % slots));
|
inventory.setItem(i, turtleInventory.getItem((currentSlot + i) % slots));
|
||||||
}
|
}
|
||||||
@ -160,7 +160,7 @@ public final class TurtlePlayer {
|
|||||||
var slots = turtleInventory.getContainerSize();
|
var slots = turtleInventory.getContainerSize();
|
||||||
|
|
||||||
// Load up the fake inventory
|
// Load up the fake inventory
|
||||||
inventory.selected = 0;
|
inventory.setSelectedSlot(0);
|
||||||
for (var i = 0; i < slots; i++) {
|
for (var i = 0; i < slots; i++) {
|
||||||
turtleInventory.setItem((currentSlot + i) % slots, inventory.getItem(i));
|
turtleInventory.setItem((currentSlot + i) % slots, inventory.getItem(i));
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ public class TurtleTool extends AbstractTurtleUpgrade {
|
|||||||
var hitEntity = entityHit.getEntity();
|
var hitEntity = entityHit.getEntity();
|
||||||
|
|
||||||
// Start claiming entity drops
|
// Start claiming entity drops
|
||||||
DropConsumer.set(hitEntity, TurtleUtil.dropConsumer(turtle));
|
DropConsumer.set(hitEntity);
|
||||||
|
|
||||||
// Attack the entity
|
// Attack the entity
|
||||||
var result = PlatformHelper.get().canAttackEntity(player, hitEntity);
|
var result = PlatformHelper.get().canAttackEntity(player, hitEntity);
|
||||||
@ -285,7 +285,7 @@ public class TurtleTool extends AbstractTurtleUpgrade {
|
|||||||
if (!breakable.isSuccess()) return breakable;
|
if (!breakable.isSuccess()) return breakable;
|
||||||
|
|
||||||
// And break it!
|
// And break it!
|
||||||
DropConsumer.set(level, blockPosition, TurtleUtil.dropConsumer(turtle));
|
DropConsumer.set(level, blockPosition);
|
||||||
var broken = !turtlePlayer.isBlockProtected(level, blockPosition) && turtlePlayer.player().gameMode.destroyBlock(blockPosition);
|
var broken = !turtlePlayer.isBlockProtected(level, blockPosition) && turtlePlayer.player().gameMode.destroyBlock(blockPosition);
|
||||||
TurtleUtil.stopConsuming(turtle);
|
TurtleUtil.stopConsuming(turtle);
|
||||||
|
|
||||||
|
@ -53,4 +53,8 @@ public class ColourTracker {
|
|||||||
|
|
||||||
return (avgR << 16) | (avgG << 8) | avgB;
|
return (avgR << 16) | (avgG << 8) | avgB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getColourOr(int fallback) {
|
||||||
|
return hasColour() ? getColour() : fallback;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import net.minecraft.core.component.DataComponentType;
|
|||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.component.DyedItemColor;
|
||||||
import net.minecraft.world.level.ItemLike;
|
import net.minecraft.world.level.ItemLike;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
@ -38,14 +39,26 @@ public class DataComponentUtil {
|
|||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> ItemStack createResult(ItemStack stack, DataComponentType<T> type, @Nullable T value) {
|
|
||||||
return set(stack.copyWithCount(1), type, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> ItemStack createStack(ItemLike item, DataComponentType<T> type, @Nullable T value) {
|
public static <T> ItemStack createStack(ItemLike item, DataComponentType<T> type, @Nullable T value) {
|
||||||
return set(new ItemStack(item), type, value);
|
return set(new ItemStack(item), type, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a stack dyed with a particular colour, but with the colour hidden from the tooltip.
|
||||||
|
*
|
||||||
|
* @param item The item to create the stack from.
|
||||||
|
* @param colour The stack's colour.
|
||||||
|
* @return The newly created stack.
|
||||||
|
*/
|
||||||
|
public static ItemStack createDyedStack(ItemLike item, int colour) {
|
||||||
|
return setDyeColour(new ItemStack(item), colour);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemStack setDyeColour(ItemStack stack, int colour) {
|
||||||
|
stack.set(DataComponents.DYED_COLOR, new DyedItemColor(colour));
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check a component is present in a {@link DataComponentPatch} and matches the supplied predicate.
|
* Check a component is present in a {@link DataComponentPatch} and matches the supplied predicate.
|
||||||
*
|
*
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package dan200.computercraft.shared.util;
|
package dan200.computercraft.shared.util;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.item.ItemEntity;
|
import net.minecraft.world.entity.item.ItemEntity;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
@ -15,7 +14,6 @@ import org.jspecify.annotations.Nullable;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
||||||
|
|
||||||
@ -23,34 +21,30 @@ public final class DropConsumer {
|
|||||||
private DropConsumer() {
|
private DropConsumer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @Nullable Function<ItemStack, ItemStack> dropConsumer;
|
private static @Nullable List<ItemStack> drops;
|
||||||
private static @Nullable List<ItemStack> remainingDrops;
|
|
||||||
private static @Nullable Level dropWorld;
|
private static @Nullable Level dropWorld;
|
||||||
private static @Nullable AABB dropBounds;
|
private static @Nullable AABB dropBounds;
|
||||||
private static @Nullable Entity dropEntity;
|
private static @Nullable Entity dropEntity;
|
||||||
|
|
||||||
public static void set(Entity entity, Function<ItemStack, ItemStack> consumer) {
|
public static void set(Entity entity) {
|
||||||
dropConsumer = consumer;
|
drops = new ArrayList<>();
|
||||||
remainingDrops = new ArrayList<>();
|
|
||||||
dropEntity = entity;
|
dropEntity = entity;
|
||||||
dropWorld = entity.level();
|
dropWorld = entity.level();
|
||||||
dropBounds = new AABB(entity.blockPosition()).inflate(2, 2, 2);
|
dropBounds = new AABB(entity.blockPosition()).inflate(2, 2, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void set(Level world, BlockPos pos, Function<ItemStack, ItemStack> consumer) {
|
public static void set(Level world, BlockPos pos) {
|
||||||
dropConsumer = consumer;
|
drops = new ArrayList<>(2);
|
||||||
remainingDrops = new ArrayList<>(2);
|
|
||||||
dropEntity = null;
|
dropEntity = null;
|
||||||
dropWorld = world;
|
dropWorld = world;
|
||||||
dropBounds = new AABB(pos).inflate(2, 2, 2);
|
dropBounds = new AABB(pos).inflate(2, 2, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<ItemStack> clear() {
|
public static List<ItemStack> stop() {
|
||||||
var remainingStacks = remainingDrops;
|
var remainingStacks = drops;
|
||||||
if (remainingStacks == null) throw new IllegalStateException("Not currently capturing");
|
if (remainingStacks == null) throw new IllegalStateException("Not currently capturing");
|
||||||
|
|
||||||
dropConsumer = null;
|
drops = null;
|
||||||
remainingDrops = null;
|
|
||||||
dropEntity = null;
|
dropEntity = null;
|
||||||
dropWorld = null;
|
dropWorld = null;
|
||||||
dropBounds = null;
|
dropBounds = null;
|
||||||
@ -58,14 +52,8 @@ public final class DropConsumer {
|
|||||||
return remainingStacks;
|
return remainingStacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void clearAndDrop(Level world, BlockPos pos, @Nullable Direction direction) {
|
|
||||||
var remainingDrops = clear();
|
|
||||||
for (var remaining : remainingDrops) WorldUtil.dropItemStack(world, pos, direction, remaining);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void handleDrops(ItemStack stack) {
|
private static void handleDrops(ItemStack stack) {
|
||||||
var remaining = assertNonNull(dropConsumer).apply(stack);
|
assertNonNull(drops).add(stack);
|
||||||
if (!remaining.isEmpty()) assertNonNull(remainingDrops).add(remaining);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean onEntitySpawn(Entity entity) {
|
public static boolean onEntitySpawn(Entity entity) {
|
||||||
|
@ -9,12 +9,9 @@ import net.minecraft.core.Direction;
|
|||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.player.Inventory;
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.Item;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.minecraft.world.phys.EntityHitResult;
|
import net.minecraft.world.phys.EntityHitResult;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
@ -32,30 +29,22 @@ public final class InventoryUtil {
|
|||||||
*/
|
*/
|
||||||
public static int getHandSlot(Player player, InteractionHand hand) {
|
public static int getHandSlot(Player player, InteractionHand hand) {
|
||||||
return switch (hand) {
|
return switch (hand) {
|
||||||
case MAIN_HAND -> player.getInventory().selected;
|
case MAIN_HAND -> player.getInventory().getSelectedSlot();
|
||||||
case OFF_HAND -> Inventory.SLOT_OFFHAND;
|
case OFF_HAND -> Inventory.SLOT_OFFHAND;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map a slot inside a player's compartment to a slot in the full player's inventory.
|
* Find an item inside a container.
|
||||||
* <p>
|
|
||||||
* {@link Inventory#tick()} passes in a slot to {@link Item#inventoryTick(ItemStack, Level, Entity, int, boolean)}.
|
|
||||||
* However, this slot corresponds to the index within the current compartment (items, armour, offhand) and not
|
|
||||||
* the actual slot.
|
|
||||||
* <p>
|
|
||||||
* This method searches the relevant compartments (inventory and offhand, skipping armour) for the stack, returning
|
|
||||||
* its slot if found.
|
|
||||||
*
|
*
|
||||||
* @param player The player holding the item.
|
* @param container The container to search in.
|
||||||
* @param slot The slot inside the compartment.
|
* @param stack The item to find.
|
||||||
* @param stack The stack being ticked.
|
* @return The container slot, or {@code -1} if the item could not be found in the container.
|
||||||
* @return The inventory slot, or {@code -1} if the item could not be found in the inventory.
|
|
||||||
*/
|
*/
|
||||||
public static int getInventorySlotFromCompartment(Player player, int slot, ItemStack stack) {
|
public static int findItemInInventory(Container container, ItemStack stack) {
|
||||||
if (stack.isEmpty()) throw new IllegalArgumentException("Cannot search for empty stack");
|
for (int i = 0, size = container.getContainerSize(); i < size; i++) {
|
||||||
if (player.getInventory().getItem(slot) == stack) return slot;
|
if (container.getItem(i) == stack) return i;
|
||||||
if (player.getInventory().getItem(Inventory.SLOT_OFFHAND) == stack) return Inventory.SLOT_OFFHAND;
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,32 +31,26 @@ public final class NBTUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static <T> @Nullable T decodeFrom(Codec<T> codec, HolderLookup.Provider registries, CompoundTag tag, String key) {
|
public static <T> @Nullable T decodeFrom(Codec<T> codec, HolderLookup.Provider registries, CompoundTag tag, String key) {
|
||||||
var childTag = tag.get(key);
|
return tag.read(key, codec, registries.createSerializationContext(NbtOps.INSTANCE)).orElse(null);
|
||||||
return childTag == null ? null : codec.parse(registries.createSerializationContext(NbtOps.INSTANCE), childTag)
|
|
||||||
.resultOrPartial(e -> LOG.warn("Failed to parse NBT: {}", e))
|
|
||||||
.orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> void encodeTo(Codec<T> codec, HolderLookup.Provider registries, CompoundTag destination, String key, @Nullable T value) {
|
public static <T> void encodeTo(Codec<T> codec, HolderLookup.Provider registries, CompoundTag destination, String key, @Nullable T value) {
|
||||||
if (value == null) return;
|
destination.storeNullable(key, codec, registries.createSerializationContext(NbtOps.INSTANCE), value);
|
||||||
codec.encodeStart(registries.createSerializationContext(NbtOps.INSTANCE), value)
|
|
||||||
.resultOrPartial(e -> LOG.warn("Failed to save NBT: {}", e))
|
|
||||||
.ifPresent(x -> destination.put(key, x));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @Nullable Object toLua(@Nullable Tag tag) {
|
public static @Nullable Object toLua(@Nullable Tag tag) {
|
||||||
if (tag == null) return null;
|
if (tag == null) return null;
|
||||||
|
|
||||||
return switch (tag.getId()) {
|
return switch (tag.getId()) {
|
||||||
case Tag.TAG_BYTE, Tag.TAG_SHORT, Tag.TAG_INT, Tag.TAG_LONG -> ((NumericTag) tag).getAsLong();
|
case Tag.TAG_BYTE, Tag.TAG_SHORT, Tag.TAG_INT, Tag.TAG_LONG -> ((NumericTag) tag).longValue();
|
||||||
case Tag.TAG_FLOAT, Tag.TAG_DOUBLE -> ((NumericTag) tag).getAsDouble();
|
case Tag.TAG_FLOAT, Tag.TAG_DOUBLE -> ((NumericTag) tag).doubleValue();
|
||||||
case Tag.TAG_STRING -> tag.getAsString();
|
case Tag.TAG_STRING -> ((StringTag) tag).value();
|
||||||
case Tag.TAG_COMPOUND -> {
|
case Tag.TAG_COMPOUND -> {
|
||||||
var compound = (CompoundTag) tag;
|
var compound = (CompoundTag) tag;
|
||||||
Map<String, Object> map = new HashMap<>(compound.size());
|
Map<String, Object> map = new HashMap<>(compound.size());
|
||||||
for (var key : compound.getAllKeys()) {
|
for (var entry : compound.entrySet()) {
|
||||||
var value = toLua(compound.get(key));
|
var value = toLua(entry.getValue());
|
||||||
if (value != null) map.put(key, value);
|
if (value != null) map.put(entry.getKey(), value);
|
||||||
}
|
}
|
||||||
yield map;
|
yield map;
|
||||||
}
|
}
|
||||||
@ -110,7 +104,7 @@ public final class NBTUtil {
|
|||||||
|
|
||||||
private static void writeTag(DataOutput output, Tag tag) throws IOException {
|
private static void writeTag(DataOutput output, Tag tag) throws IOException {
|
||||||
if (tag instanceof CompoundTag compound) {
|
if (tag instanceof CompoundTag compound) {
|
||||||
var keys = compound.getAllKeys().toArray(new String[0]);
|
var keys = compound.keySet().toArray(new String[0]);
|
||||||
Arrays.sort(keys);
|
Arrays.sort(keys);
|
||||||
for (var key : keys) writeNamedTag(output, key, Nullability.assertNonNull(compound.get(key)));
|
for (var key : keys) writeNamedTag(output, key, Nullability.assertNonNull(compound.get(key)));
|
||||||
|
|
||||||
|
@ -8,51 +8,101 @@ import com.mojang.serialization.Codec;
|
|||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.core.component.DataComponentGetter;
|
||||||
import net.minecraft.core.component.DataComponentType;
|
import net.minecraft.core.component.DataComponentType;
|
||||||
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
import net.minecraft.network.codec.StreamCodec;
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.util.ExtraCodecs;
|
import net.minecraft.util.ExtraCodecs;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
|
import net.minecraft.world.item.component.TooltipProvider;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A non-negative integer id, used for computer and disk ids.
|
* A non-negative integer id, used for computer and disk ids.
|
||||||
*
|
*
|
||||||
* @param id The id of this entity.
|
|
||||||
* @see dan200.computercraft.shared.ModRegistry.DataComponents#COMPUTER_ID
|
* @see dan200.computercraft.shared.ModRegistry.DataComponents#COMPUTER_ID
|
||||||
* @see dan200.computercraft.shared.ModRegistry.DataComponents#DISK_ID
|
* @see dan200.computercraft.shared.ModRegistry.DataComponents#DISK_ID
|
||||||
*/
|
*/
|
||||||
public record NonNegativeId(int id) {
|
public abstract class NonNegativeId implements TooltipProvider {
|
||||||
public static final Codec<NonNegativeId> CODEC = ExtraCodecs.NON_NEGATIVE_INT.xmap(NonNegativeId::new, NonNegativeId::id);
|
private final int id;
|
||||||
|
|
||||||
public static final StreamCodec<ByteBuf, NonNegativeId> STREAM_CODEC = ByteBufCodecs.VAR_INT.map(NonNegativeId::new, NonNegativeId::id);
|
protected NonNegativeId(int id) {
|
||||||
|
|
||||||
public NonNegativeId {
|
|
||||||
if (id < 0) throw new IllegalArgumentException("ID must be >= 0");
|
if (id < 0) throw new IllegalArgumentException("ID must be >= 0");
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the internal id.
|
||||||
|
*
|
||||||
|
* @return The internal id.
|
||||||
|
*/
|
||||||
|
public int id() {
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getId(@Nullable NonNegativeId id) {
|
public static int getId(@Nullable NonNegativeId id) {
|
||||||
return id == null ? -1 : id.id();
|
return id == null ? -1 : id.id();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @Nullable NonNegativeId of(int id) {
|
public static <T extends NonNegativeId> int getOrCreate(MinecraftServer server, ItemStack stack, DataComponentType<T> component, IntFunction<T> create, String type) {
|
||||||
return id >= 0 ? new NonNegativeId(id) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getOrCreate(MinecraftServer server, ItemStack stack, DataComponentType<NonNegativeId> component, String type) {
|
|
||||||
var id = stack.get(component);
|
var id = stack.get(component);
|
||||||
if (id != null) return id.id();
|
if (id != null) return id.id();
|
||||||
|
|
||||||
var diskID = ComputerCraftAPI.createUniqueNumberedSaveDir(server, type);
|
var newId = ComputerCraftAPI.createUniqueNumberedSaveDir(server, type);
|
||||||
stack.set(component, new NonNegativeId(diskID));
|
stack.set(component, create.apply(newId));
|
||||||
return diskID;
|
return newId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addToTooltip(String translation, Consumer<Component> out) {
|
protected void addToTooltip(String translation, Consumer<Component> out) {
|
||||||
out.accept(Component.translatable(translation, id()).withStyle(ChatFormatting.GRAY));
|
out.accept(Component.translatable(translation, id()).withStyle(ChatFormatting.GRAY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("EqualsGetClass") // We want to distinguish different subclasses.
|
||||||
|
public final boolean equals(Object o) {
|
||||||
|
return this == o || (o != null && getClass() == o.getClass() && id == ((NonNegativeId) o).id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Computer extends NonNegativeId {
|
||||||
|
public static final Codec<Computer> CODEC = ExtraCodecs.NON_NEGATIVE_INT.xmap(Computer::new, NonNegativeId::id);
|
||||||
|
public static final StreamCodec<ByteBuf, Computer> STREAM_CODEC = ByteBufCodecs.VAR_INT.map(Computer::new, NonNegativeId::id);
|
||||||
|
|
||||||
|
public Computer(int id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addToTooltip(Item.TooltipContext tooltipContext, Consumer<Component> out, TooltipFlag flags, DataComponentGetter stack) {
|
||||||
|
if (flags.isAdvanced() || stack.get(DataComponents.CUSTOM_NAME) == null) {
|
||||||
|
addToTooltip("gui.computercraft.tooltip.computer_id", out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Disk extends NonNegativeId {
|
||||||
|
public static final Codec<Disk> CODEC = ExtraCodecs.NON_NEGATIVE_INT.xmap(Disk::new, NonNegativeId::id);
|
||||||
|
public static final StreamCodec<ByteBuf, Disk> STREAM_CODEC = ByteBufCodecs.VAR_INT.map(Disk::new, NonNegativeId::id);
|
||||||
|
|
||||||
|
public Disk(int id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addToTooltip(Item.TooltipContext tooltipContext, Consumer<Component> out, TooltipFlag flags, DataComponentGetter stack) {
|
||||||
|
if (flags.isAdvanced()) addToTooltip("gui.computercraft.tooltip.disk_id", out);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,12 @@ accessible class net/minecraft/data/tags/TagsProvider$TagAppender
|
|||||||
accessible field net/minecraft/client/data/models/BlockModelGenerators blockStateOutput Ljava/util/function/Consumer;
|
accessible field net/minecraft/client/data/models/BlockModelGenerators blockStateOutput Ljava/util/function/Consumer;
|
||||||
accessible field net/minecraft/client/data/models/BlockModelGenerators itemModelOutput Lnet/minecraft/client/data/models/ItemModelOutput;
|
accessible field net/minecraft/client/data/models/BlockModelGenerators itemModelOutput Lnet/minecraft/client/data/models/ItemModelOutput;
|
||||||
accessible field net/minecraft/client/data/models/BlockModelGenerators modelOutput Ljava/util/function/BiConsumer;
|
accessible field net/minecraft/client/data/models/BlockModelGenerators modelOutput Ljava/util/function/BiConsumer;
|
||||||
|
accessible method net/minecraft/client/data/models/BlockModelGenerators condition ()Lnet/minecraft/client/data/models/blockstates/ConditionBuilder;
|
||||||
accessible method net/minecraft/client/data/models/BlockModelGenerators createHorizontallyRotatedBlock (Lnet/minecraft/world/level/block/Block;Lnet/minecraft/client/data/models/model/TexturedModel$Provider;)V
|
accessible method net/minecraft/client/data/models/BlockModelGenerators createHorizontallyRotatedBlock (Lnet/minecraft/world/level/block/Block;Lnet/minecraft/client/data/models/model/TexturedModel$Provider;)V
|
||||||
accessible method net/minecraft/client/data/models/BlockModelGenerators createParticleOnlyBlock (Lnet/minecraft/world/level/block/Block;)V
|
accessible method net/minecraft/client/data/models/BlockModelGenerators createParticleOnlyBlock (Lnet/minecraft/world/level/block/Block;)V
|
||||||
accessible method net/minecraft/client/data/models/BlockModelGenerators createSimpleBlock (Lnet/minecraft/world/level/block/Block;Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/data/models/blockstates/MultiVariantGenerator;
|
accessible method net/minecraft/client/data/models/BlockModelGenerators createSimpleBlock (Lnet/minecraft/world/level/block/Block;Lnet/minecraft/client/data/models/MultiVariant;)Lnet/minecraft/client/data/models/blockstates/MultiVariantGenerator;
|
||||||
|
accessible method net/minecraft/client/data/models/BlockModelGenerators or ([Lnet/minecraft/client/data/models/blockstates/ConditionBuilder;)Lnet/minecraft/client/renderer/block/model/multipart/Condition;
|
||||||
|
accessible method net/minecraft/client/data/models/BlockModelGenerators plainVariant (Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/data/models/MultiVariant;
|
||||||
accessible method net/minecraft/client/data/models/BlockModelGenerators registerSimpleItemModel (Lnet/minecraft/world/item/Item;Lnet/minecraft/resources/ResourceLocation;)V
|
accessible method net/minecraft/client/data/models/BlockModelGenerators registerSimpleItemModel (Lnet/minecraft/world/item/Item;Lnet/minecraft/resources/ResourceLocation;)V
|
||||||
accessible method net/minecraft/client/data/models/BlockModelGenerators registerSimpleItemModel (Lnet/minecraft/world/level/block/Block;Lnet/minecraft/resources/ResourceLocation;)V
|
accessible method net/minecraft/client/data/models/BlockModelGenerators registerSimpleItemModel (Lnet/minecraft/world/level/block/Block;Lnet/minecraft/resources/ResourceLocation;)V
|
||||||
accessible field net/minecraft/client/data/models/ItemModelGenerators itemModelOutput Lnet/minecraft/client/data/models/ItemModelOutput;
|
accessible field net/minecraft/client/data/models/ItemModelGenerators itemModelOutput Lnet/minecraft/client/data/models/ItemModelOutput;
|
||||||
|
@ -10,12 +10,8 @@ accessWidener v1 named
|
|||||||
accessible class net/minecraft/world/level/block/entity/BlockEntityType$BlockEntitySupplier
|
accessible class net/minecraft/world/level/block/entity/BlockEntityType$BlockEntitySupplier
|
||||||
accessible method net/minecraft/world/level/block/entity/BlockEntityType <init> (Lnet/minecraft/world/level/block/entity/BlockEntityType$BlockEntitySupplier;Ljava/util/Set;)V
|
accessible method net/minecraft/world/level/block/entity/BlockEntityType <init> (Lnet/minecraft/world/level/block/entity/BlockEntityType$BlockEntitySupplier;Ljava/util/Set;)V
|
||||||
|
|
||||||
accessible method net/minecraft/client/renderer/RenderType create (Ljava/lang/String;Lcom/mojang/blaze3d/vertex/VertexFormat;Lcom/mojang/blaze3d/vertex/VertexFormat$Mode;IZZLnet/minecraft/client/renderer/RenderType$CompositeState;)Lnet/minecraft/client/renderer/RenderType$CompositeRenderType;
|
|
||||||
accessible method net/minecraft/world/level/storage/LevelResource <init> (Ljava/lang/String;)V
|
accessible method net/minecraft/world/level/storage/LevelResource <init> (Ljava/lang/String;)V
|
||||||
|
|
||||||
# DirectVertexBuffer
|
|
||||||
accessible field com/mojang/blaze3d/vertex/VertexBuffer indexCount I
|
|
||||||
|
|
||||||
# ClientTableFormatter
|
# ClientTableFormatter
|
||||||
accessible field net/minecraft/client/gui/components/ChatComponent allMessages Ljava/util/List;
|
accessible field net/minecraft/client/gui/components/ChatComponent allMessages Ljava/util/List;
|
||||||
|
|
||||||
@ -30,3 +26,7 @@ accessible field net/minecraft/client/sounds/SoundEngine executor Lnet/minecraft
|
|||||||
|
|
||||||
# Turtle model
|
# Turtle model
|
||||||
accessible class net/minecraft/util/datafix/fixes/ItemStackComponentizationFix$ItemStackData
|
accessible class net/minecraft/util/datafix/fixes/ItemStackComponentizationFix$ItemStackData
|
||||||
|
|
||||||
|
# TODO(1.21.5): Add these to Fabric.
|
||||||
|
accessible field net/minecraft/client/data/models/BlockModelGenerators ROTATION_FACING Lnet/minecraft/client/data/models/blockstates/PropertyDispatch;
|
||||||
|
accessible field net/minecraft/client/data/models/BlockModelGenerators ROTATION_HORIZONTAL_FACING Lnet/minecraft/client/data/models/blockstates/PropertyDispatch;
|
||||||
|
@ -9,12 +9,13 @@ import net.minecraft.Util;
|
|||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.ListTag;
|
import net.minecraft.nbt.ListTag;
|
||||||
import net.minecraft.nbt.NbtIo;
|
import net.minecraft.nbt.NbtIo;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -57,7 +58,7 @@ public class NBTUtilTest {
|
|||||||
var nbt1 = makeCompoundTag(false);
|
var nbt1 = makeCompoundTag(false);
|
||||||
var nbt2 = makeCompoundTag(true);
|
var nbt2 = makeCompoundTag(true);
|
||||||
assertNotEquals(
|
assertNotEquals(
|
||||||
List.copyOf(nbt1.getAllKeys()), List.copyOf(nbt2.getAllKeys()),
|
List.copyOf(nbt1.keySet()), List.copyOf(nbt2.keySet()),
|
||||||
"Expected makeCompoundTag to return keys with different orders."
|
"Expected makeCompoundTag to return keys with different orders."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -100,7 +101,7 @@ public class NBTUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Equivalent to {@link NBTUtil#getNBTHash(CompoundTag)}, but using the default {@link NbtIo#write(CompoundTag, File)} method.
|
* Equivalent to {@link NBTUtil#getNBTHash(Tag)}, but using the default {@link NbtIo#write(CompoundTag, Path)} method.
|
||||||
*
|
*
|
||||||
* @param tag The tag to hash.
|
* @param tag The tag to hash.
|
||||||
* @return The resulting hash.
|
* @return The resulting hash.
|
||||||
|
@ -8,9 +8,7 @@ import com.mojang.blaze3d.ProjectionType;
|
|||||||
import com.mojang.blaze3d.pipeline.TextureTarget;
|
import com.mojang.blaze3d.pipeline.TextureTarget;
|
||||||
import com.mojang.blaze3d.platform.NativeImage;
|
import com.mojang.blaze3d.platform.NativeImage;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
import org.lwjgl.opengl.GL11;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@ -23,19 +21,19 @@ public class ImageRenderer implements AutoCloseable {
|
|||||||
public static final int WIDTH = 64;
|
public static final int WIDTH = 64;
|
||||||
public static final int HEIGHT = 64;
|
public static final int HEIGHT = 64;
|
||||||
|
|
||||||
private final TextureTarget framebuffer = new TextureTarget(WIDTH, HEIGHT, true);
|
private final TextureTarget framebuffer = new TextureTarget("Export", WIDTH, HEIGHT, true);
|
||||||
private final NativeImage image = new NativeImage(WIDTH, HEIGHT, true);
|
private final NativeImage image = new NativeImage(WIDTH, HEIGHT, true);
|
||||||
|
|
||||||
public ImageRenderer() {
|
public ImageRenderer() {
|
||||||
framebuffer.setClearColor(0, 0, 0, 0);
|
// framebuffer.setFilterMode(0, 0, 0, 0);
|
||||||
framebuffer.clear();
|
// framebuffer.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void captureRender(Path output, Runnable render) throws IOException {
|
public void captureRender(Path output, Runnable render) throws IOException {
|
||||||
Files.createDirectories(output.getParent());
|
Files.createDirectories(output.getParent());
|
||||||
|
|
||||||
RenderSystem.clear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
// RenderSystem.clear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
||||||
framebuffer.bindWrite(true);
|
// framebuffer.bindWrite(true);
|
||||||
|
|
||||||
// Setup rendering state
|
// Setup rendering state
|
||||||
RenderSystem.backupProjectionMatrix();
|
RenderSystem.backupProjectionMatrix();
|
||||||
@ -53,14 +51,14 @@ public class ImageRenderer implements AutoCloseable {
|
|||||||
RenderSystem.restoreProjectionMatrix();
|
RenderSystem.restoreProjectionMatrix();
|
||||||
transform.popMatrix();
|
transform.popMatrix();
|
||||||
|
|
||||||
framebuffer.unbindWrite();
|
// framebuffer.unbindWrite();
|
||||||
Minecraft.getInstance().getMainRenderTarget().bindWrite(true);
|
// Minecraft.getInstance().getMainRenderTarget().bindWrite(true);
|
||||||
|
|
||||||
// And save the image
|
// And save the image
|
||||||
framebuffer.bindRead();
|
// framebuffer.bindRead();
|
||||||
image.downloadTexture(0, false);
|
// image.downloadTexture(0, false);
|
||||||
image.flipY();
|
// image.flipY();
|
||||||
framebuffer.unbindRead();
|
// framebuffer.unbindRead();
|
||||||
|
|
||||||
image.writeToFile(output);
|
image.writeToFile(output);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package dan200.computercraft.gametest.api;
|
package dan200.computercraft.gametest.api;
|
||||||
|
|
||||||
import dan200.computercraft.gametest.core.TestAPI;
|
import dan200.computercraft.gametest.core.TestAPI;
|
||||||
import net.minecraft.gametest.framework.GameTestAssertException;
|
|
||||||
import net.minecraft.gametest.framework.GameTestSequence;
|
import net.minecraft.gametest.framework.GameTestSequence;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
@ -32,9 +31,9 @@ public class ComputerState {
|
|||||||
return markers.contains(marker);
|
return markers.contains(marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void check(String marker) {
|
public @Nullable String check(String marker) {
|
||||||
if (!markers.contains(marker)) throw new IllegalStateException("Not yet at " + marker);
|
if (!markers.contains(marker)) throw new IllegalStateException("Not yet at " + marker);
|
||||||
if (error != null) throw new GameTestAssertException(error);
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @Nullable ComputerState get(String label) {
|
public static @Nullable ComputerState get(String label) {
|
||||||
|
@ -6,7 +6,6 @@ package dan200.computercraft.gametest.core;
|
|||||||
|
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.mixin.gametest.TestCommandAccessor;
|
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.util.NonNegativeId;
|
import dan200.computercraft.shared.util.NonNegativeId;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
@ -15,14 +14,14 @@ import net.minecraft.commands.CommandSourceStack;
|
|||||||
import net.minecraft.commands.arguments.item.ItemArgument;
|
import net.minecraft.commands.arguments.item.ItemArgument;
|
||||||
import net.minecraft.commands.arguments.item.ItemInput;
|
import net.minecraft.commands.arguments.item.ItemInput;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.gametest.framework.GameTestRegistry;
|
|
||||||
import net.minecraft.gametest.framework.StructureUtils;
|
import net.minecraft.gametest.framework.StructureUtils;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.world.entity.EntityType;
|
import net.minecraft.world.entity.EntityType;
|
||||||
import net.minecraft.world.entity.decoration.ArmorStand;
|
import net.minecraft.world.entity.decoration.ArmorStand;
|
||||||
import net.minecraft.world.level.block.entity.StructureBlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.world.level.block.entity.TestInstanceBlockEntity;
|
||||||
import net.minecraft.world.level.storage.LevelResource;
|
import net.minecraft.world.level.storage.LevelResource;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -41,38 +40,18 @@ class CCTestCommand {
|
|||||||
|
|
||||||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext buildContext) {
|
public static void register(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext buildContext) {
|
||||||
dispatcher.register(choice("cctest")
|
dispatcher.register(choice("cctest")
|
||||||
.then(literal("import").executes(context -> {
|
|
||||||
importFiles(context.getSource().getServer());
|
|
||||||
return 0;
|
|
||||||
}))
|
|
||||||
.then(literal("export").executes(context -> {
|
|
||||||
exportFiles(context.getSource().getServer());
|
|
||||||
|
|
||||||
for (var function : GameTestRegistry.getAllTestFunctions()) {
|
|
||||||
TestCommandAccessor.callExportTestStructure(context.getSource(), function.structureName());
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}))
|
|
||||||
.then(literal("regen-structures").executes(context -> {
|
|
||||||
for (var function : GameTestRegistry.getAllTestFunctions()) {
|
|
||||||
dispatcher.execute("test import " + function.structureName(), context.getSource());
|
|
||||||
TestCommandAccessor.callExportTestStructure(context.getSource(), function.structureName());
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}))
|
|
||||||
|
|
||||||
.then(literal("marker").executes(context -> {
|
.then(literal("marker").executes(context -> {
|
||||||
var player = context.getSource().getPlayerOrException();
|
var player = context.getSource().getPlayerOrException();
|
||||||
var pos = StructureUtils.findNearestStructureBlock(player.blockPosition(), 15, player.serverLevel()).orElse(null);
|
var pos = StructureUtils.findNearestTest(player.blockPosition(), 15, player.serverLevel()).orElse(null);
|
||||||
if (pos == null) return error(context.getSource(), "No nearby test");
|
if (pos == null) return error(context.getSource(), "No nearby test");
|
||||||
|
|
||||||
var structureBlock = (StructureBlockEntity) player.level().getBlockEntity(pos);
|
var test = player.level().getBlockEntity(pos, BlockEntityType.TEST_INSTANCE_BLOCK)
|
||||||
if (structureBlock == null) return error(context.getSource(), "No nearby structure block");
|
.flatMap(TestInstanceBlockEntity::test).orElse(null);
|
||||||
var info = GameTestRegistry.getTestFunction(structureBlock.getMetaData());
|
if (test == null) return error(context.getSource(), "No nearby structure block");
|
||||||
|
|
||||||
// Kill the existing armor stand
|
// Kill the existing armor stand
|
||||||
var level = player.serverLevel();
|
var level = player.serverLevel();
|
||||||
level.getEntities(EntityType.ARMOR_STAND, x -> x.isAlive() && x.getName().getString().equals(info.testName()))
|
level.getEntities(EntityType.ARMOR_STAND, x -> x.isAlive() && x.getName().getString().equals(test.location().getPath()))
|
||||||
.forEach(e -> e.kill(level));
|
.forEach(e -> e.kill(level));
|
||||||
|
|
||||||
// And create a new one
|
// And create a new one
|
||||||
@ -82,7 +61,7 @@ class CCTestCommand {
|
|||||||
var armorStand = new ArmorStand(EntityType.ARMOR_STAND, level);
|
var armorStand = new ArmorStand(EntityType.ARMOR_STAND, level);
|
||||||
armorStand.readAdditionalSaveData(nbt);
|
armorStand.readAdditionalSaveData(nbt);
|
||||||
armorStand.copyPosition(player);
|
armorStand.copyPosition(player);
|
||||||
armorStand.setCustomName(Component.literal(info.testName()));
|
armorStand.setCustomName(Component.literal(test.location().getPath()));
|
||||||
level.addFreshEntity(armorStand);
|
level.addFreshEntity(armorStand);
|
||||||
return 0;
|
return 0;
|
||||||
}))
|
}))
|
||||||
@ -91,16 +70,16 @@ class CCTestCommand {
|
|||||||
var item = context.getArgument("item", ItemInput.class);
|
var item = context.getArgument("item", ItemInput.class);
|
||||||
|
|
||||||
var player = context.getSource().getPlayerOrException();
|
var player = context.getSource().getPlayerOrException();
|
||||||
var pos = StructureUtils.findNearestStructureBlock(player.blockPosition(), 15, player.serverLevel()).orElse(null);
|
var pos = StructureUtils.findNearestTest(player.blockPosition(), 15, player.serverLevel()).orElse(null);
|
||||||
if (pos == null) return error(context.getSource(), "No nearby test");
|
if (pos == null) return error(context.getSource(), "No nearby test");
|
||||||
|
|
||||||
var structureBlock = (StructureBlockEntity) player.level().getBlockEntity(pos);
|
var test = player.level().getBlockEntity(pos, BlockEntityType.TEST_INSTANCE_BLOCK)
|
||||||
if (structureBlock == null) return error(context.getSource(), "No nearby structure block");
|
.flatMap(TestInstanceBlockEntity::test).orElse(null);
|
||||||
var info = GameTestRegistry.getTestFunction(structureBlock.getMetaData());
|
if (test == null) return error(context.getSource(), "No nearby structure block");
|
||||||
|
|
||||||
var stack = item.createItemStack(1, false);
|
var stack = item.createItemStack(1, false);
|
||||||
stack.set(ModRegistry.DataComponents.COMPUTER_ID.get(), new NonNegativeId(1));
|
stack.set(ModRegistry.DataComponents.COMPUTER_ID.get(), new NonNegativeId.Computer(1));
|
||||||
stack.set(DataComponents.CUSTOM_NAME, Component.literal(info.testName()));
|
stack.set(DataComponents.CUSTOM_NAME, Component.literal(test.location().getPath()));
|
||||||
if (!player.getInventory().add(stack)) {
|
if (!player.getInventory().add(stack)) {
|
||||||
var itemEntity = player.drop(stack, false);
|
var itemEntity = player.drop(stack, false);
|
||||||
if (itemEntity != null) {
|
if (itemEntity != null) {
|
||||||
|
@ -11,5 +11,5 @@ import org.spongepowered.asm.mixin.gen.Invoker;
|
|||||||
@Mixin(GameTestInfo.class)
|
@Mixin(GameTestInfo.class)
|
||||||
public interface GameTestInfoAccessor {
|
public interface GameTestInfoAccessor {
|
||||||
@Invoker("getTick")
|
@Invoker("getTick")
|
||||||
long computercraft$getTick();
|
int computercraft$getTick();
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user