mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-08-24 22:42:18 +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
|
||||
|
||||
# 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
|
||||
# MC version is specified in gradle.properties, as we need that in settings.gradle.
|
||||
# Remember to update corresponding versions in fabric.mod.json/neoforge.mods.toml
|
||||
fabric-api = "0.118.0+1.21.4"
|
||||
fabric-api = "0.120.0+1.21.5"
|
||||
fabric-loader = "0.16.10"
|
||||
neoForge = "21.4.101-beta"
|
||||
neoForge = "21.5.49-beta"
|
||||
neoMergeTool = "2.0.0"
|
||||
mixin = "0.8.5"
|
||||
parchment = "2024.12.07"
|
||||
parchmentMc = "1.21.4"
|
||||
yarn = "1.21.4+build.1"
|
||||
parchment = "2025.04.19"
|
||||
parchmentMc = "1.21.5"
|
||||
yarn = "1.21.5+build.1"
|
||||
|
||||
# Core dependencies (these versions are tied to the version Minecraft uses)
|
||||
fastutil = "8.5.15"
|
||||
guava = "33.3.1-jre"
|
||||
netty = "4.1.115.Final"
|
||||
netty = "4.1.118.Final"
|
||||
slf4j = "2.0.16"
|
||||
|
||||
# Core dependencies (independent of Minecraft)
|
||||
@ -38,14 +38,14 @@ nightConfig = "3.8.1"
|
||||
# Minecraft mods
|
||||
emi = "1.1.7+1.21"
|
||||
fabricPermissions = "0.3.3"
|
||||
iris-fabric = "1.8.8+1.21.4-fabric"
|
||||
iris-forge = "1.8.8+1.21.4-neoforge"
|
||||
iris-fabric = "1.8.11+1.21.5-fabric"
|
||||
iris-forge = "1.8.11+1.21.5-neoforge"
|
||||
jei = "19.8.2.99"
|
||||
modmenu = "13.0.2"
|
||||
moreRed = "6.0.0.3"
|
||||
rei = "18.0.800"
|
||||
sodium-fabric = "mc1.21.4-0.6.10-fabric"
|
||||
sodium-forge = "mc1.21.4-0.6.10-neoforge"
|
||||
sodium-fabric = "mc1.21.5-0.6.12-fabric"
|
||||
sodium-forge = "mc1.21.5-0.6.12-neoforge"
|
||||
mixinExtra = "0.3.5"
|
||||
create-forge = "6.0.0-6"
|
||||
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"
|
||||
lwjgl = "3.3.3"
|
||||
minotaur = "2.8.7"
|
||||
modDevGradle = "2.0.78"
|
||||
modDevGradle = "2.0.82"
|
||||
nullAway = "0.12.4"
|
||||
shadow = "8.3.1"
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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>
|
||||
* This interface is largely intended to be used from multi-loader code, to allow sharing registration code between
|
||||
* multiple loaders.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RegisterTurtleUpgradeModeller {
|
||||
public interface RegisterTurtleUpgradeModel {
|
||||
/**
|
||||
* Register a {@link TurtleUpgradeModeller}.
|
||||
* Register a {@link TurtleUpgradeModel}.
|
||||
*
|
||||
* @param type The turtle upgrade type.
|
||||
* @param modeller The upgrade modeller.
|
||||
* @param <T> The type of the turtle upgrade.
|
||||
* @param type The turtle upgrade type.
|
||||
* @param mode The unbaked upgrade model.
|
||||
* @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>
|
||||
* 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>
|
||||
* {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_modellers}
|
||||
* {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_model}
|
||||
*
|
||||
* <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>
|
||||
* 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.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
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
|
||||
if (state.getBlock() != ModRegistry.Blocks.CABLE.get()
|
||||
|| !state.getValue(CableBlock.CABLE)
|
||||
|| state.getValue(CableBlock.MODEM) == CableModemVariant.None
|
||||
) {
|
||||
return null;
|
||||
return state;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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()))
|
||||
? state.getBlock().defaultBlockState().setValue(CableBlock.MODEM, state.getValue(CableBlock.MODEM))
|
||||
|
@ -6,19 +6,21 @@ package dan200.computercraft.client;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.client.turtle.RegisterTurtleUpgradeModeller;
|
||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
||||
import dan200.computercraft.api.client.StandaloneModel;
|
||||
import dan200.computercraft.api.client.turtle.RegisterTurtleUpgradeModel;
|
||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModel;
|
||||
import dan200.computercraft.client.gui.*;
|
||||
import dan200.computercraft.client.item.colour.PocketComputerLight;
|
||||
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.TurtleShowElfOverlay;
|
||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||
import dan200.computercraft.client.platform.ModelKey;
|
||||
import dan200.computercraft.client.render.CustomLecternRenderer;
|
||||
import dan200.computercraft.client.render.TurtleBlockEntityRenderer;
|
||||
import dan200.computercraft.client.render.monitor.MonitorBlockEntityRenderer;
|
||||
import dan200.computercraft.client.turtle.TurtleModemModeller;
|
||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
||||
import dan200.computercraft.client.turtle.TurtleModemModel;
|
||||
import dan200.computercraft.client.turtle.TurtleUpgradeModels;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||
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.properties.conditional.ConditionalItemModelProperty;
|
||||
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.server.packs.resources.PreparableReloadListener;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
|
||||
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.Consumer;
|
||||
|
||||
/**
|
||||
* Registers client-side objects, such as {@link BlockEntityRendererProvider}s and
|
||||
@ -53,6 +59,19 @@ public final class 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.
|
||||
*/
|
||||
@ -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);
|
||||
}
|
||||
|
||||
public static void registerTurtleModellers(RegisterTurtleUpgradeModeller register) {
|
||||
register.register(ModRegistry.TurtleUpgradeTypes.SPEAKER.get(), TurtleUpgradeModeller.sided(
|
||||
public static void registerTurtleModels(RegisterTurtleUpgradeModel register) {
|
||||
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_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_right")
|
||||
));
|
||||
register.register(ModRegistry.TurtleUpgradeTypes.WIRELESS_MODEM.get(), new TurtleModemModeller());
|
||||
register.register(ModRegistry.TurtleUpgradeTypes.TOOL.get(), TurtleUpgradeModeller.flatItem());
|
||||
register.register(ModRegistry.TurtleUpgradeTypes.WIRELESS_MODEM.get(), TurtleModemModel.UNBAKED);
|
||||
register.register(ModRegistry.TurtleUpgradeTypes.TOOL.get(), TurtleUpgradeModel.flatItem());
|
||||
}
|
||||
|
||||
public static void registerReloadListeners(BiConsumer<ResourceLocation, PreparableReloadListener> register, Minecraft minecraft) {
|
||||
@ -100,17 +119,22 @@ public final class ClientRegistry {
|
||||
TurtleBlockEntityRenderer.NORMAL_TURTLE_MODEL,
|
||||
TurtleBlockEntityRenderer.ADVANCED_TURTLE_MODEL,
|
||||
TurtleBlockEntityRenderer.COLOUR_TURTLE_MODEL,
|
||||
MissingBlockModel.LOCATION,
|
||||
};
|
||||
|
||||
public static void registerExtraModels(Consumer<ResourceLocation> register, Collection<ResourceLocation> extraModels) {
|
||||
for (var model : EXTRA_MODELS) register.accept(model);
|
||||
extraModels.forEach(register);
|
||||
TurtleUpgradeModellers.getDependencies().forEach(register);
|
||||
public static void registerExtraModels(
|
||||
BiConsumer<ModelKey<StandaloneModel>, ResourceLocation> registerBasic,
|
||||
BiConsumer<ModelKey<? extends TurtleUpgradeModel<?>>, TurtleUpgradeModel.Unbaked<?>> registerTurtle,
|
||||
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) {
|
||||
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) {
|
||||
|
@ -72,8 +72,8 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
||||
public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
|
||||
var direction = scrollHandler.onMouseScroll(scrollX, scrollY);
|
||||
var inventory = Objects.requireNonNull(minecraft().player).getInventory();
|
||||
inventory.setSelectedHotbarSlot(ScrollWheelHandler.getNextScrollWheelSelection(
|
||||
direction.y == 0 ? -direction.x : direction.y, inventory.selected, Inventory.getSelectionSize()
|
||||
inventory.setSelectedSlot(ScrollWheelHandler.getNextScrollWheelSelection(
|
||||
direction.y == 0 ? -direction.x : direction.y, inventory.getSelectedSlot(), Inventory.getSelectionSize()
|
||||
));
|
||||
|
||||
return super.mouseScrolled(mouseX, mouseY, scrollX, scrollY);
|
||||
|
@ -38,7 +38,7 @@ public class IrisShaderMod implements ShaderMod.Provider {
|
||||
: 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 @Nullable ByteBuffer buffer;
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
package dan200.computercraft.client.integration;
|
||||
|
||||
import com.mojang.blaze3d.vertex.ByteBufferBuilder;
|
||||
import com.mojang.blaze3d.vertex.VertexBuffer;
|
||||
import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer;
|
||||
|
||||
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 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.codecs.RecordCodecBuilder;
|
||||
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.items.TurtleItem;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@ -39,8 +39,9 @@ public record TurtleOverlayModel(ItemTransforms transforms) implements ItemModel
|
||||
var overlay = TurtleItem.getOverlay(stack);
|
||||
if (overlay == null) return;
|
||||
|
||||
var model = ClientPlatformHelper.get().getModel(Minecraft.getInstance().getModelManager(), overlay.model());
|
||||
BakedModelWithTransform.addLayer(state, model, transforms());
|
||||
var layer = state.newLayer();
|
||||
ClientRegistry.getModel(Minecraft.getInstance().getModelManager(), overlay.model()).setupItemLayer(layer);
|
||||
layer.setTransform(transforms().getTransform(context));
|
||||
}
|
||||
|
||||
public record Unbaked(ResourceLocation base) implements ItemModel.Unbaked {
|
||||
@ -51,7 +52,7 @@ public record TurtleOverlayModel(ItemTransforms transforms) implements ItemModel
|
||||
|
||||
@Override
|
||||
public ItemModel bake(BakingContext bakingContext) {
|
||||
return new TurtleOverlayModel(bakingContext.bake(base).getTransforms());
|
||||
return new TurtleOverlayModel(bakingContext.blockModelBaker().getModel(base).getTopTransforms());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -4,23 +4,17 @@
|
||||
|
||||
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.codecs.RecordCodecBuilder;
|
||||
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.client.turtle.TurtleUpgradeModellers;
|
||||
import dan200.computercraft.client.turtle.TurtleUpgradeModels;
|
||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||
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.ItemModelResolver;
|
||||
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.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
@ -28,12 +22,12 @@ import net.minecraft.world.item.ItemStack;
|
||||
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 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 MapCodec<Unbaked> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
TurtleSide.CODEC.fieldOf("side").forGetter(Unbaked::side),
|
||||
@ -41,21 +35,11 @@ public record TurtleUpgradeModel(TurtleSide side, BakedModel base) implements It
|
||||
).apply(instance, Unbaked::new));
|
||||
|
||||
@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);
|
||||
if (upgrade == null) return;
|
||||
|
||||
switch (TurtleUpgradeModellers.getModel(upgrade.upgrade(), upgrade.data(), side)) {
|
||||
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());
|
||||
}
|
||||
TurtleUpgradeModels.getModeller(upgrade.upgrade()).renderForItem(upgrade.upgrade(), side, upgrade.data(), state, resolver, base.getTransform(context), seed);
|
||||
}
|
||||
|
||||
public record Unbaked(TurtleSide side, ResourceLocation base) implements ItemModel.Unbaked {
|
||||
@ -66,29 +50,12 @@ public record TurtleUpgradeModel(TurtleSide side, BakedModel base) implements It
|
||||
|
||||
@Override
|
||||
public ItemModel bake(BakingContext bakingContext) {
|
||||
return new TurtleUpgradeModel(side, bakingContext.bake(base));
|
||||
return new TurtleUpgradeModel(side, bakingContext.blockModelBaker().getModel(base).getTopTransforms());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolveDependencies(Resolver resolver) {
|
||||
resolver.resolve(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;
|
||||
resolver.markDependency(base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
package dan200.computercraft.client.item.properties;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.client.pocket.ClientPocketComputers;
|
||||
@ -38,6 +39,11 @@ public final class PocketComputerStateProperty implements SelectItemModelPropert
|
||||
return computer == null ? ComputerState.OFF : computer.getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Codec<ComputerState> valueCodec() {
|
||||
return ComputerState.CODEC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type<? extends SelectItemModelProperty<ComputerState>, ComputerState> type() {
|
||||
return TYPE;
|
||||
|
@ -4,25 +4,40 @@
|
||||
|
||||
package dan200.computercraft.client.platform;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import dan200.computercraft.impl.Services;
|
||||
import net.minecraft.client.resources.model.ModelDebugName;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public interface ClientPlatformHelper extends dan200.computercraft.impl.client.ClientPlatformHelper {
|
||||
public interface ClientPlatformHelper {
|
||||
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 buffers The current pool of render buffers.
|
||||
* @param model The model 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.
|
||||
* @param id An identifier for this model key.
|
||||
* @param name The debug name for this model key.
|
||||
* @param <T> The type of baked model.
|
||||
* @return The newly created model key.
|
||||
*/
|
||||
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 net.minecraft.client.renderer.MultiBufferSource;
|
||||
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.BlockEntityRendererProvider;
|
||||
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> {
|
||||
private static final int POCKET_TERMINAL_RENDER_DISTANCE = 32;
|
||||
|
||||
private final BlockEntityRenderDispatcher berDispatcher;
|
||||
private final LecternPrintoutModel printoutModel;
|
||||
private final LecternPocketModel pocketModel;
|
||||
|
||||
public CustomLecternRenderer(BlockEntityRendererProvider.Context context) {
|
||||
berDispatcher = context.getBlockEntityRenderDispatcher();
|
||||
|
||||
printoutModel = new LecternPrintoutModel();
|
||||
pocketModel = new LecternPocketModel();
|
||||
}
|
||||
|
||||
@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.translate(0.5f, 1.0625f, 0.5f);
|
||||
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.
|
||||
var terminal = computer == null ? null : computer.getTerminal();
|
||||
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);
|
||||
} else {
|
||||
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.math.Axis;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.client.TransformedModel;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
||||
import dan200.computercraft.client.ClientRegistry;
|
||||
import dan200.computercraft.client.turtle.TurtleUpgradeModels;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
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.BlockEntityRenderer;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.ARGB;
|
||||
import net.minecraft.util.CommonColors;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBlockEntity> {
|
||||
@ -45,7 +42,7 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
|
||||
}
|
||||
|
||||
@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();
|
||||
|
||||
// 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.translate(0.0f, -0.5f, -0.5f);
|
||||
|
||||
switch (TurtleUpgradeModellers.getModel(upgrade, turtle.getAccess(), side)) {
|
||||
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);
|
||||
}
|
||||
TurtleUpgradeModels.getModeller(upgrade).renderForLevel(upgrade, turtle.getAccess(), side, turtle.getAccess().getUpgradeData(side), transform, buffers, lightmapCoord, overlayLight);
|
||||
|
||||
|
||||
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) {
|
||||
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;
|
||||
|
||||
import com.mojang.blaze3d.buffers.BufferType;
|
||||
import com.mojang.blaze3d.buffers.BufferUsage;
|
||||
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 dan200.computercraft.annotations.ForgeOverride;
|
||||
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.MonitorBlockEntity;
|
||||
import dan200.computercraft.shared.util.DirectionUtil;
|
||||
import net.minecraft.client.renderer.CompiledShaderProgram;
|
||||
import net.minecraft.client.renderer.FogParameters;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
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_WIDTH;
|
||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
||||
|
||||
public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBlockEntity> {
|
||||
/**
|
||||
@ -45,7 +48,7 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
||||
}
|
||||
|
||||
@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
|
||||
var originTerminal = monitor.getOriginClientMonitor();
|
||||
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
|
||||
) {
|
||||
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) {
|
||||
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
|
||||
// a starting and ending offset, and so need to use two buffers instead.
|
||||
DirectFixedWidthFontRenderer.drawTerminalBackground(sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin);
|
||||
var vertexCountAfterBackground = sink.vertexCount();
|
||||
|
||||
renderToBuffer(backgroundBuffer, size, sink ->
|
||||
DirectFixedWidthFontRenderer.drawTerminalBackground(sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin));
|
||||
DirectFixedWidthFontRenderer.drawTerminalForeground(sink, 0, 0, terminal);
|
||||
var vertexCountAfterForeground = sink.vertexCount();
|
||||
|
||||
renderToBuffer(foregroundBuffer, size + 4, sink -> {
|
||||
DirectFixedWidthFontRenderer.drawTerminalForeground(sink, 0, 0, terminal);
|
||||
// If the cursor is visible, we append it to the end of our buffer. When rendering, we can either
|
||||
// render n or n+1 quads and so toggle the cursor on and off.
|
||||
DirectFixedWidthFontRenderer.drawCursor(sink, 0, 0, terminal);
|
||||
});
|
||||
DirectFixedWidthFontRenderer.drawCursor(sink, 0, 0, terminal);
|
||||
var vertexCountAfterCursor = sink.vertexCount();
|
||||
|
||||
if (vertexCountAfterCursor > maxVertexCount) {
|
||||
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
|
||||
// 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.
|
||||
@ -152,69 +192,52 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
||||
var oldFog = RenderSystem.getShaderFog();
|
||||
RenderSystem.setShaderFog(FogParameters.NO_FOG);
|
||||
|
||||
FixedWidthFontRenderer.TERMINAL_TEXT.setupRenderState();
|
||||
|
||||
// Compose the existing model view matrix with our transformation matrix.
|
||||
var modelView = new Matrix4f(RenderSystem.getModelViewMatrix()).mul(matrix);
|
||||
RenderSystem.getModelViewStack().pushMatrix();
|
||||
RenderSystem.getModelViewStack().mul(matrix);
|
||||
|
||||
// Render background geometry
|
||||
backgroundBuffer.bind();
|
||||
backgroundBuffer.drawWithShader(modelView, RenderSystem.getProjectionMatrix(), RenderSystem.getShader());
|
||||
|
||||
// Render foreground geometry with glPolygonOffset enabled.
|
||||
RenderSystem.polygonOffset(-1.0f, -10.0f);
|
||||
RenderSystem.enablePolygonOffset();
|
||||
|
||||
foregroundBuffer.bind();
|
||||
drawWithShader(renderState, FixedWidthFontRenderer.TERMINAL_TEXT, 0, renderState.indexAfterBackground);
|
||||
drawWithShader(
|
||||
foregroundBuffer, modelView, RenderSystem.getProjectionMatrix(), RenderSystem.getShader(),
|
||||
// Skip the cursor quad if it is not visible this frame.
|
||||
FixedWidthFontRenderer.isCursorVisible(terminal) && !FrameInfo.getGlobalCursorBlink()
|
||||
? foregroundBuffer.indexCount - FixedWidthFontRenderer.TERMINAL_TEXT.mode().indexCount(4)
|
||||
: foregroundBuffer.indexCount
|
||||
renderState, FixedWidthFontRenderer.TERMINAL_TEXT_OFFSET, renderState.indexAfterBackground,
|
||||
(
|
||||
FixedWidthFontRenderer.isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink()
|
||||
? renderState.indexAfterCursor : renderState.indexAfterForeground
|
||||
) - renderState.indexAfterBackground
|
||||
);
|
||||
|
||||
// Clear state
|
||||
RenderSystem.polygonOffset(0.0f, -0.0f);
|
||||
RenderSystem.disablePolygonOffset();
|
||||
FixedWidthFontRenderer.TERMINAL_TEXT.clearRenderState();
|
||||
VertexBuffer.unbind();
|
||||
|
||||
RenderSystem.getModelViewStack().popMatrix();
|
||||
RenderSystem.setShaderFog(oldFog);
|
||||
}
|
||||
|
||||
private static void renderToBuffer(VertexBuffer vbo, int size, Consumer<DirectFixedWidthFontRenderer.QuadEmitter> draw) {
|
||||
var sink = ShaderMod.get().getQuadEmitter(size, backingBufferBuilder);
|
||||
draw.accept(sink);
|
||||
private static void drawWithShader(MonitorRenderState renderState, RenderType renderType, int indexOffset, int indexCount) {
|
||||
if (renderState.vertexBuffer == null) {
|
||||
throw new IllegalStateException("MonitorRenderState has not been initialised");
|
||||
}
|
||||
if (indexCount == 0) return;
|
||||
|
||||
var result = backingBufferBuilder.build();
|
||||
if (result == null) {
|
||||
// If we have nothing to draw, just mark it as empty. We'll skip drawing in drawWithShader.
|
||||
vbo.indexCount = 0;
|
||||
return;
|
||||
renderType.setupRenderState();
|
||||
|
||||
var autoStorageBuffer = RenderSystem.getSequentialBuffer(renderType.mode());
|
||||
var indexBuffer = autoStorageBuffer.getBuffer(indexOffset + indexCount);
|
||||
|
||||
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();
|
||||
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;
|
||||
}
|
||||
renderType.clearRenderState();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5,8 +5,7 @@
|
||||
package dan200.computercraft.client.render.monitor;
|
||||
|
||||
import com.google.errorprone.annotations.concurrent.GuardedBy;
|
||||
import com.mojang.blaze3d.buffers.BufferUsage;
|
||||
import com.mojang.blaze3d.vertex.VertexBuffer;
|
||||
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||
import net.minecraft.core.BlockPos;
|
||||
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
|
||||
* 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")
|
||||
private static final Set<MonitorRenderState> allMonitors = new HashSet<>();
|
||||
|
||||
public long lastRenderFrame = -1;
|
||||
public @Nullable BlockPos lastRenderPos = null;
|
||||
long lastRenderFrame = -1;
|
||||
@Nullable
|
||||
BlockPos lastRenderPos = null;
|
||||
|
||||
public @Nullable VertexBuffer backgroundBuffer;
|
||||
public @Nullable VertexBuffer foregroundBuffer;
|
||||
@Nullable
|
||||
GpuBuffer vertexBuffer;
|
||||
|
||||
/**
|
||||
* Create the appropriate buffer if needed.
|
||||
*
|
||||
* @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;
|
||||
int indexAfterBackground;
|
||||
int indexAfterForeground;
|
||||
int indexAfterCursor;
|
||||
|
||||
deleteBuffers();
|
||||
backgroundBuffer = new VertexBuffer(BufferUsage.STATIC_WRITE);
|
||||
foregroundBuffer = new VertexBuffer(BufferUsage.STATIC_WRITE);
|
||||
addMonitor();
|
||||
return true;
|
||||
}
|
||||
void register() {
|
||||
if (vertexBuffer != null) return;
|
||||
|
||||
private void addMonitor() {
|
||||
synchronized (allMonitors) {
|
||||
allMonitors.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteBuffers() {
|
||||
if (backgroundBuffer != null) {
|
||||
backgroundBuffer.close();
|
||||
backgroundBuffer = null;
|
||||
}
|
||||
|
||||
if (foregroundBuffer != null) {
|
||||
foregroundBuffer.close();
|
||||
foregroundBuffer = null;
|
||||
if (vertexBuffer != null) {
|
||||
vertexBuffer.close();
|
||||
vertexBuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (backgroundBuffer != null) {
|
||||
if (vertexBuffer != null) {
|
||||
synchronized (allMonitors) {
|
||||
allMonitors.remove(this);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ import static org.lwjgl.system.MemoryUtil.*;
|
||||
* <p>
|
||||
* 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}.
|
||||
*
|
||||
* <p>
|
||||
* <strong>IMPORTANT: </strong> When making changes to this class, please check if you need to make the same changes to
|
||||
* {@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) {
|
||||
buffer.vertexCount += 4;
|
||||
buffer.quad(x1, y1, x2, y2, z, colour, u1, v1, u2, v2);
|
||||
}
|
||||
|
||||
public interface QuadEmitter {
|
||||
VertexFormat format();
|
||||
public abstract static class QuadEmitter {
|
||||
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
|
||||
public VertexFormat 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_OFFSET = RenderType.textPolygonOffset(FONT);
|
||||
|
||||
public static final int FONT_HEIGHT = 9;
|
||||
public static final int FONT_WIDTH = 6;
|
||||
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;
|
||||
|
||||
import com.mojang.math.Quadrant;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
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.util.DirectionUtil;
|
||||
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.renderer.block.model.VariantMutator;
|
||||
import net.minecraft.client.renderer.item.EmptyModel;
|
||||
import net.minecraft.client.renderer.item.properties.conditional.HasComponent;
|
||||
import net.minecraft.core.Direction;
|
||||
@ -33,7 +39,6 @@ import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
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.Property;
|
||||
|
||||
@ -43,6 +48,7 @@ import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
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.TextureMapping.getBlockTexture;
|
||||
|
||||
@ -116,15 +122,14 @@ public class BlockModelProvider {
|
||||
registerTurtleModem(generators, "block/turtle_modem_advanced", "block/wireless_modem_advanced_face");
|
||||
|
||||
generators.blockStateOutput.accept(
|
||||
BlockModelGenerators.createSimpleBlock(ModRegistry.Blocks.LECTERN.get(), getModelLocation(Blocks.LECTERN))
|
||||
createSimpleBlock(ModRegistry.Blocks.LECTERN.get(), plainVariant(getModelLocation(Blocks.LECTERN)))
|
||||
.with(createHorizontalFacingDispatch())
|
||||
);
|
||||
}
|
||||
|
||||
private static void registerDiskDrive(BlockModelGenerators generators) {
|
||||
var diskDrive = ModRegistry.Blocks.DISK_DRIVE.get();
|
||||
generators.blockStateOutput.accept(MultiVariantGenerator.multiVariant(diskDrive)
|
||||
.with(createHorizontalFacingDispatch())
|
||||
generators.blockStateOutput.accept(MultiVariantGenerator.dispatch(diskDrive)
|
||||
.with(createModelDispatch(DiskDriveBlock.STATE, value -> {
|
||||
var textureSuffix = switch (value) {
|
||||
case EMPTY -> "_front";
|
||||
@ -137,14 +142,14 @@ public class BlockModelProvider {
|
||||
generators.modelOutput
|
||||
);
|
||||
}))
|
||||
.with(createHorizontalFacingDispatch())
|
||||
);
|
||||
generators.registerSimpleItemModel(diskDrive, getModelLocation(diskDrive, "_empty"));
|
||||
}
|
||||
|
||||
private static void registerPrinter(BlockModelGenerators generators) {
|
||||
var printer = ModRegistry.Blocks.PRINTER.get();
|
||||
generators.blockStateOutput.accept(MultiVariantGenerator.multiVariant(printer)
|
||||
.with(createHorizontalFacingDispatch())
|
||||
generators.blockStateOutput.accept(MultiVariantGenerator.dispatch(printer)
|
||||
.with(createModelDispatch(PrinterBlock.TOP, PrinterBlock.BOTTOM, (top, bottom) -> {
|
||||
String model, texture;
|
||||
if (top && bottom) {
|
||||
@ -165,13 +170,13 @@ public class BlockModelProvider {
|
||||
generators.modelOutput
|
||||
);
|
||||
}))
|
||||
.with(createHorizontalFacingDispatch())
|
||||
);
|
||||
generators.registerSimpleItemModel(printer, getModelLocation(printer, "_empty"));
|
||||
}
|
||||
|
||||
private static void registerComputer(BlockModelGenerators generators, ComputerBlock<?> block) {
|
||||
generators.blockStateOutput.accept(MultiVariantGenerator.multiVariant(block)
|
||||
.with(createHorizontalFacingDispatch())
|
||||
generators.blockStateOutput.accept(MultiVariantGenerator.dispatch(block)
|
||||
.with(createModelDispatch(ComputerBlock.STATE, state -> switch (state) {
|
||||
case OFF -> ModelTemplates.CUBE_ORIENTABLE.createWithSuffix(
|
||||
block, "_" + state.getSerializedName(),
|
||||
@ -184,6 +189,7 @@ public class BlockModelProvider {
|
||||
generators.modelOutput
|
||||
);
|
||||
}))
|
||||
.with(createHorizontalFacingDispatch())
|
||||
);
|
||||
generators.registerSimpleItemModel(block, getModelLocation(block, "_blinking"));
|
||||
}
|
||||
@ -193,7 +199,7 @@ public class BlockModelProvider {
|
||||
var particleModel = ModelTemplates.PARTICLE_ONLY.createWithSuffix(
|
||||
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.
|
||||
var model = TURTLE.create(block, new TextureMapping()
|
||||
@ -224,17 +230,17 @@ public class BlockModelProvider {
|
||||
}
|
||||
|
||||
private static void registerWirelessModem(BlockModelGenerators generators, WirelessModemBlock block) {
|
||||
generators.blockStateOutput.accept(MultiVariantGenerator.multiVariant(block)
|
||||
.with(createFacingDispatch())
|
||||
generators.blockStateOutput.accept(MultiVariantGenerator.dispatch(block)
|
||||
.with(createModelDispatch(WirelessModemBlock.ON,
|
||||
on -> modemModel(generators, getModelLocation(block, on ? "_on" : "_off"), getBlockTexture(block, "_face" + (on ? "_on" : "")))
|
||||
)));
|
||||
))
|
||||
.with(createFacingDispatch()));
|
||||
generators.registerSimpleItemModel(block, getModelLocation(block, "_off"));
|
||||
}
|
||||
|
||||
private static void registerWiredModems(BlockModelGenerators generators) {
|
||||
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) -> {
|
||||
var suffix = (on ? "_on" : "_off") + (peripheral ? "_peripheral" : "");
|
||||
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, "_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(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));
|
||||
}
|
||||
@ -308,55 +314,54 @@ public class BlockModelProvider {
|
||||
var coreFacing = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/cable_core_facing");
|
||||
// Up/Down
|
||||
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.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
|
||||
generator.with(
|
||||
Condition.or(
|
||||
or(
|
||||
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.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
|
||||
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.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.
|
||||
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 j = i; j < DirectionUtil.FACINGS.length; j++) {
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
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
|
||||
var arm = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/cable_arm");
|
||||
for (var direction : DirectionUtil.FACINGS) {
|
||||
generator.with(
|
||||
new Condition.TerminalCondition().term(CABLE_DIRECTIONS[direction.ordinal()], true),
|
||||
Variant.variant()
|
||||
.with(VariantProperties.MODEL, arm)
|
||||
.with(VariantProperties.X_ROT, toXAngle(direction.getOpposite()))
|
||||
.with(VariantProperties.Y_ROT, toYAngle(direction.getOpposite()))
|
||||
condition().term(CABLE_DIRECTIONS[direction.ordinal()], true),
|
||||
plainVariant(arm)
|
||||
.with(VariantMutator.X_ROT.withValue(toXAngle(direction.getOpposite())))
|
||||
.with(VariantMutator.Y_ROT.withValue(toYAngle(direction.getOpposite())))
|
||||
);
|
||||
}
|
||||
|
||||
@ -366,11 +371,10 @@ public class BlockModelProvider {
|
||||
for (var peripheral : BOOLEANS) {
|
||||
var suffix = (on ? "_on" : "_off") + (peripheral ? "_peripheral" : "");
|
||||
generator.with(
|
||||
new Condition.TerminalCondition().term(CableBlock.MODEM, CableModemVariant.from(direction, on, peripheral)),
|
||||
Variant.variant()
|
||||
.with(VariantProperties.MODEL, ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/wired_modem" + suffix))
|
||||
.with(VariantProperties.X_ROT, toXAngle(direction))
|
||||
.with(VariantProperties.Y_ROT, toYAngle(direction))
|
||||
condition().term(CableBlock.MODEM, CableModemVariant.from(direction, on, peripheral)),
|
||||
plainVariant(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/wired_modem" + suffix))
|
||||
.with(VariantMutator.X_ROT.withValue(toXAngle(direction.getOpposite())))
|
||||
.with(VariantMutator.Y_ROT.withValue(toYAngle(direction.getOpposite())))
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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 boolean[] BOOLEANS = new boolean[]{ false, true };
|
||||
|
||||
private static Condition.TerminalCondition cableNoNeighbour(Direction... directions) {
|
||||
var condition = new Condition.TerminalCondition().term(CableBlock.CABLE, true);
|
||||
private static ConditionBuilder cableNoNeighbour(Direction... directions) {
|
||||
var condition = condition().term(CableBlock.CABLE, true);
|
||||
for (var direction : directions) condition.term(CABLE_DIRECTIONS[direction.ordinal()], false);
|
||||
return condition;
|
||||
}
|
||||
@ -418,66 +422,60 @@ public class BlockModelProvider {
|
||||
generators.registerSimpleItemModel(block, ModelLocationUtils.getModelLocation(block));
|
||||
}
|
||||
|
||||
private static VariantProperties.Rotation toXAngle(Direction direction) {
|
||||
private static Quadrant toXAngle(Direction direction) {
|
||||
return switch (direction) {
|
||||
default -> VariantProperties.Rotation.R0;
|
||||
case UP -> VariantProperties.Rotation.R270;
|
||||
case DOWN -> VariantProperties.Rotation.R90;
|
||||
default -> Quadrant.R0;
|
||||
case UP -> Quadrant.R270;
|
||||
case DOWN -> Quadrant.R90;
|
||||
};
|
||||
}
|
||||
|
||||
private static VariantProperties.Rotation toYAngle(Direction direction) {
|
||||
private static Quadrant toYAngle(Direction direction) {
|
||||
return switch (direction) {
|
||||
default -> VariantProperties.Rotation.R0;
|
||||
case NORTH -> VariantProperties.Rotation.R0;
|
||||
case SOUTH -> VariantProperties.Rotation.R180;
|
||||
case EAST -> VariantProperties.Rotation.R90;
|
||||
case WEST -> VariantProperties.Rotation.R270;
|
||||
default -> Quadrant.R0;
|
||||
case NORTH -> Quadrant.R0;
|
||||
case SOUTH -> Quadrant.R180;
|
||||
case EAST -> Quadrant.R90;
|
||||
case WEST -> Quadrant.R270;
|
||||
};
|
||||
}
|
||||
|
||||
private static PropertyDispatch createHorizontalFacingDispatch() {
|
||||
var dispatch = PropertyDispatch.property(BlockStateProperties.HORIZONTAL_FACING);
|
||||
private static PropertyDispatch<VariantMutator> createHorizontalFacingDispatch() {
|
||||
/*var dispatch = PropertyDispatch.modify(BlockStateProperties.HORIZONTAL_FACING);
|
||||
for (var direction : BlockStateProperties.HORIZONTAL_FACING.getPossibleValues()) {
|
||||
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) {
|
||||
var dispatch = PropertyDispatch.property(property);
|
||||
private static PropertyDispatch<VariantMutator> createVerticalFacingDispatch(Property<Direction> property) {
|
||||
var dispatch = PropertyDispatch.modify(property);
|
||||
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;
|
||||
}
|
||||
|
||||
private static PropertyDispatch createFacingDispatch() {
|
||||
var dispatch = PropertyDispatch.property(BlockStateProperties.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 PropertyDispatch<VariantMutator> createFacingDispatch() {
|
||||
return BlockModelGenerators.ROTATION_FACING;
|
||||
}
|
||||
|
||||
private static <T extends Comparable<T>> PropertyDispatch createModelDispatch(Property<T> property, Function<T, ResourceLocation> makeModel) {
|
||||
var variant = PropertyDispatch.property(property);
|
||||
private static <T extends Comparable<T>> PropertyDispatch<MultiVariant> createModelDispatch(Property<T> property, Function<T, ResourceLocation> makeModel) {
|
||||
var variant = PropertyDispatch.initial(property);
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
) {
|
||||
var variant = PropertyDispatch.properties(propertyT, propertyU);
|
||||
var variant = PropertyDispatch.initial(propertyT, propertyU);
|
||||
for (var valueT : propertyT.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;
|
||||
|
@ -28,7 +28,7 @@ public class BrewingStandPeripheral implements IPeripheral {
|
||||
@LuaFunction
|
||||
public final int getFuel() {
|
||||
// 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
|
||||
|
@ -23,7 +23,7 @@ public class FurnacePeripheral implements GenericPeripheral {
|
||||
@LuaFunction(mainThread = true)
|
||||
public int getBurnTime(AbstractFurnaceBlockEntity furnace) {
|
||||
// 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
|
||||
|
@ -10,7 +10,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"apply": {"model": "computercraft:block/cable_core_facing", "y": 0},
|
||||
"apply": {"model": "computercraft:block/cable_core_facing"},
|
||||
"when": {
|
||||
"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": 90, "y": 0}, "when": {"up": "true"}},
|
||||
{"apply": {"model": "computercraft:block/cable_arm", "x": 0, "y": 180}, "when": {"north": "true"}},
|
||||
{"apply": {"model": "computercraft:block/cable_arm", "x": 0, "y": 0}, "when": {"south": "true"}},
|
||||
{"apply": {"model": "computercraft:block/cable_arm", "x": 0, "y": 90}, "when": {"west": "true"}},
|
||||
{"apply": {"model": "computercraft:block/cable_arm", "x": 0, "y": 270}, "when": {"east": "true"}},
|
||||
{"apply": {"model": "computercraft:block/wired_modem_off", "x": 90, "y": 0}, "when": {"modem": "down_off"}},
|
||||
{"apply": {"model": "computercraft:block/cable_arm", "x": 270}, "when": {"down": "true"}},
|
||||
{"apply": {"model": "computercraft:block/cable_arm", "x": 90}, "when": {"up": "true"}},
|
||||
{"apply": {"model": "computercraft:block/cable_arm", "y": 180}, "when": {"north": "true"}},
|
||||
{"apply": {"model": "computercraft:block/cable_arm"}, "when": {"south": "true"}},
|
||||
{"apply": {"model": "computercraft:block/cable_arm", "y": 90}, "when": {"west": "true"}},
|
||||
{"apply": {"model": "computercraft:block/cable_arm", "y": 270}, "when": {"east": "true"}},
|
||||
{"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"}
|
||||
},
|
||||
{"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"}
|
||||
},
|
||||
{"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"}
|
||||
},
|
||||
{"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"}
|
||||
},
|
||||
{"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"}
|
||||
},
|
||||
{"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"}
|
||||
},
|
||||
{"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"}
|
||||
},
|
||||
{"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"}
|
||||
},
|
||||
{"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"}
|
||||
},
|
||||
{"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"}
|
||||
},
|
||||
{"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"}
|
||||
},
|
||||
{"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"}
|
||||
}
|
||||
]
|
||||
|
@ -3,9 +3,9 @@
|
||||
"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=on": {"model": "computercraft:block/computer_advanced_on", "y": 90},
|
||||
"facing=north,state=blinking": {"model": "computercraft:block/computer_advanced_blinking", "y": 0},
|
||||
"facing=north,state=off": {"model": "computercraft:block/computer_advanced_off", "y": 0},
|
||||
"facing=north,state=on": {"model": "computercraft:block/computer_advanced_on", "y": 0},
|
||||
"facing=north,state=blinking": {"model": "computercraft:block/computer_advanced_blinking"},
|
||||
"facing=north,state=off": {"model": "computercraft:block/computer_advanced_off"},
|
||||
"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=off": {"model": "computercraft:block/computer_advanced_off", "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=off": {"model": "computercraft:block/computer_command_off", "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=off": {"model": "computercraft:block/computer_command_off", "y": 0},
|
||||
"facing=north,state=on": {"model": "computercraft:block/computer_command_on", "y": 0},
|
||||
"facing=north,state=blinking": {"model": "computercraft:block/computer_command_blinking"},
|
||||
"facing=north,state=off": {"model": "computercraft:block/computer_command_off"},
|
||||
"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=off": {"model": "computercraft:block/computer_command_off", "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=off": {"model": "computercraft:block/computer_normal_off", "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=off": {"model": "computercraft:block/computer_normal_off", "y": 0},
|
||||
"facing=north,state=on": {"model": "computercraft:block/computer_normal_on", "y": 0},
|
||||
"facing=north,state=blinking": {"model": "computercraft:block/computer_normal_blinking"},
|
||||
"facing=north,state=off": {"model": "computercraft:block/computer_normal_off"},
|
||||
"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=off": {"model": "computercraft:block/computer_normal_off", "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=full": {"model": "computercraft:block/disk_drive_full", "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=full": {"model": "computercraft:block/disk_drive_full", "y": 0},
|
||||
"facing=north,state=invalid": {"model": "computercraft:block/disk_drive_invalid", "y": 0},
|
||||
"facing=north,state=empty": {"model": "computercraft:block/disk_drive_empty"},
|
||||
"facing=north,state=full": {"model": "computercraft:block/disk_drive_full"},
|
||||
"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=full": {"model": "computercraft:block/disk_drive_full", "y": 180},
|
||||
"facing=south,state=invalid": {"model": "computercraft:block/disk_drive_invalid", "y": 180},
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"variants": {
|
||||
"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=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=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=north,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=lrud": {
|
||||
"model": "computercraft:block/monitor_advanced_lrud",
|
||||
"x": 0,
|
||||
"y": 90
|
||||
},
|
||||
"facing=east,orientation=north,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=none": {"model": "computercraft:block/monitor_advanced", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=r": {"model": "computercraft:block/monitor_advanced_r", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "x": 0, "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=north,state=d": {"model": "computercraft:block/monitor_advanced_d", "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", "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", "y": 90},
|
||||
"facing=east,orientation=north,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "y": 90},
|
||||
"facing=east,orientation=north,state=lrud": {"model": "computercraft:block/monitor_advanced_lrud", "y": 90},
|
||||
"facing=east,orientation=north,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "y": 90},
|
||||
"facing=east,orientation=north,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "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=rd": {"model": "computercraft:block/monitor_advanced_rd", "y": 90},
|
||||
"facing=east,orientation=north,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "y": 90},
|
||||
"facing=east,orientation=north,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "y": 90},
|
||||
"facing=east,orientation=north,state=u": {"model": "computercraft:block/monitor_advanced_u", "y": 90},
|
||||
"facing=east,orientation=north,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "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=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=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=north,orientation=down,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=lrud": {
|
||||
"model": "computercraft:block/monitor_advanced_lrud",
|
||||
"x": 90,
|
||||
"y": 0
|
||||
},
|
||||
"facing=north,orientation=down,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 90, "y": 0},
|
||||
"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, "y": 0},
|
||||
"facing=north,orientation=down,state=r": {"model": "computercraft:block/monitor_advanced_r", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 90, "y": 0},
|
||||
"facing=north,orientation=north,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=lrud": {
|
||||
"model": "computercraft:block/monitor_advanced_lrud",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"facing=north,orientation=north,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=none": {"model": "computercraft:block/monitor_advanced", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=r": {"model": "computercraft:block/monitor_advanced_r", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 0, "y": 0},
|
||||
"facing=north,orientation=up,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=lrud": {"model": "computercraft:block/monitor_advanced_lrud", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 270, "y": 0},
|
||||
"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=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},
|
||||
"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},
|
||||
"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},
|
||||
"facing=north,orientation=down,state=lrud": {"model": "computercraft:block/monitor_advanced_lrud", "x": 90},
|
||||
"facing=north,orientation=down,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 90},
|
||||
"facing=north,orientation=down,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "x": 90},
|
||||
"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=rd": {"model": "computercraft:block/monitor_advanced_rd", "x": 90},
|
||||
"facing=north,orientation=down,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "x": 90},
|
||||
"facing=north,orientation=down,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 90},
|
||||
"facing=north,orientation=down,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 90},
|
||||
"facing=north,orientation=down,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 90},
|
||||
"facing=north,orientation=north,state=d": {"model": "computercraft:block/monitor_advanced_d"},
|
||||
"facing=north,orientation=north,state=l": {"model": "computercraft:block/monitor_advanced_l"},
|
||||
"facing=north,orientation=north,state=ld": {"model": "computercraft:block/monitor_advanced_ld"},
|
||||
"facing=north,orientation=north,state=lr": {"model": "computercraft:block/monitor_advanced_lr"},
|
||||
"facing=north,orientation=north,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd"},
|
||||
"facing=north,orientation=north,state=lru": {"model": "computercraft:block/monitor_advanced_lru"},
|
||||
"facing=north,orientation=north,state=lrud": {"model": "computercraft:block/monitor_advanced_lrud"},
|
||||
"facing=north,orientation=north,state=lu": {"model": "computercraft:block/monitor_advanced_lu"},
|
||||
"facing=north,orientation=north,state=lud": {"model": "computercraft:block/monitor_advanced_lud"},
|
||||
"facing=north,orientation=north,state=none": {"model": "computercraft:block/monitor_advanced"},
|
||||
"facing=north,orientation=north,state=r": {"model": "computercraft:block/monitor_advanced_r"},
|
||||
"facing=north,orientation=north,state=rd": {"model": "computercraft:block/monitor_advanced_rd"},
|
||||
"facing=north,orientation=north,state=ru": {"model": "computercraft:block/monitor_advanced_ru"},
|
||||
"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=ud": {"model": "computercraft:block/monitor_advanced_ud"},
|
||||
"facing=north,orientation=up,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 270},
|
||||
"facing=north,orientation=up,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 270},
|
||||
"facing=north,orientation=up,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 270},
|
||||
"facing=north,orientation=up,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 270},
|
||||
"facing=north,orientation=up,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "x": 270},
|
||||
"facing=north,orientation=up,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "x": 270},
|
||||
"facing=north,orientation=up,state=lrud": {"model": "computercraft:block/monitor_advanced_lrud", "x": 270},
|
||||
"facing=north,orientation=up,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 270},
|
||||
"facing=north,orientation=up,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "x": 270},
|
||||
"facing=north,orientation=up,state=none": {"model": "computercraft:block/monitor_advanced", "x": 270},
|
||||
"facing=north,orientation=up,state=r": {"model": "computercraft:block/monitor_advanced_r", "x": 270},
|
||||
"facing=north,orientation=up,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "x": 270},
|
||||
"facing=north,orientation=up,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "x": 270},
|
||||
"facing=north,orientation=up,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "x": 270},
|
||||
"facing=north,orientation=up,state=u": {"model": "computercraft:block/monitor_advanced_u", "x": 270},
|
||||
"facing=north,orientation=up,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "x": 270},
|
||||
"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=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=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=l": {"model": "computercraft:block/monitor_advanced_l", "x": 0, "y": 180},
|
||||
"facing=south,orientation=north,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 0, "y": 180},
|
||||
"facing=south,orientation=north,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 0, "y": 180},
|
||||
"facing=south,orientation=north,state=lrd": {
|
||||
"model": "computercraft:block/monitor_advanced_lrd",
|
||||
"x": 0,
|
||||
"y": 180
|
||||
},
|
||||
"facing=south,orientation=north,state=lru": {
|
||||
"model": "computercraft:block/monitor_advanced_lru",
|
||||
"x": 0,
|
||||
"y": 180
|
||||
},
|
||||
"facing=south,orientation=north,state=lrud": {
|
||||
"model": "computercraft:block/monitor_advanced_lrud",
|
||||
"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=north,state=d": {"model": "computercraft:block/monitor_advanced_d", "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", "y": 180},
|
||||
"facing=south,orientation=north,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "y": 180},
|
||||
"facing=south,orientation=north,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "y": 180},
|
||||
"facing=south,orientation=north,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "y": 180},
|
||||
"facing=south,orientation=north,state=lrud": {"model": "computercraft:block/monitor_advanced_lrud", "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=none": {"model": "computercraft:block/monitor_advanced", "y": 180},
|
||||
"facing=south,orientation=north,state=r": {"model": "computercraft:block/monitor_advanced_r", "y": 180},
|
||||
"facing=south,orientation=north,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "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=u": {"model": "computercraft:block/monitor_advanced_u", "y": 180},
|
||||
"facing=south,orientation=north,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "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=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=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=north,state=d": {"model": "computercraft:block/monitor_advanced_d", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=l": {"model": "computercraft:block/monitor_advanced_l", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=ld": {"model": "computercraft:block/monitor_advanced_ld", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=lr": {"model": "computercraft:block/monitor_advanced_lr", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=lrd": {"model": "computercraft:block/monitor_advanced_lrd", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=lrud": {
|
||||
"model": "computercraft:block/monitor_advanced_lrud",
|
||||
"x": 0,
|
||||
"y": 270
|
||||
},
|
||||
"facing=west,orientation=north,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=none": {"model": "computercraft:block/monitor_advanced", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=r": {"model": "computercraft:block/monitor_advanced_r", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=rd": {"model": "computercraft:block/monitor_advanced_rd", "x": 0, "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=north,state=d": {"model": "computercraft:block/monitor_advanced_d", "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", "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", "y": 270},
|
||||
"facing=west,orientation=north,state=lru": {"model": "computercraft:block/monitor_advanced_lru", "y": 270},
|
||||
"facing=west,orientation=north,state=lrud": {"model": "computercraft:block/monitor_advanced_lrud", "y": 270},
|
||||
"facing=west,orientation=north,state=lu": {"model": "computercraft:block/monitor_advanced_lu", "y": 270},
|
||||
"facing=west,orientation=north,state=lud": {"model": "computercraft:block/monitor_advanced_lud", "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=rd": {"model": "computercraft:block/monitor_advanced_rd", "y": 270},
|
||||
"facing=west,orientation=north,state=ru": {"model": "computercraft:block/monitor_advanced_ru", "y": 270},
|
||||
"facing=west,orientation=north,state=rud": {"model": "computercraft:block/monitor_advanced_rud", "y": 270},
|
||||
"facing=west,orientation=north,state=u": {"model": "computercraft:block/monitor_advanced_u", "y": 270},
|
||||
"facing=west,orientation=north,state=ud": {"model": "computercraft:block/monitor_advanced_ud", "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=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=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=north,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=lr": {"model": "computercraft:block/monitor_normal_lr", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=lru": {"model": "computercraft:block/monitor_normal_lru", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=lu": {"model": "computercraft:block/monitor_normal_lu", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=lud": {"model": "computercraft:block/monitor_normal_lud", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=none": {"model": "computercraft:block/monitor_normal", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=r": {"model": "computercraft:block/monitor_normal_r", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=rd": {"model": "computercraft:block/monitor_normal_rd", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=ru": {"model": "computercraft:block/monitor_normal_ru", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 0, "y": 90},
|
||||
"facing=east,orientation=north,state=ud": {"model": "computercraft:block/monitor_normal_ud", "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", "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", "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", "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", "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", "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", "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", "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", "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=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=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=north,orientation=down,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=lr": {"model": "computercraft:block/monitor_normal_lr", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=lru": {"model": "computercraft:block/monitor_normal_lru", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=lu": {"model": "computercraft:block/monitor_normal_lu", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=lud": {"model": "computercraft:block/monitor_normal_lud", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=none": {"model": "computercraft:block/monitor_normal", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=r": {"model": "computercraft:block/monitor_normal_r", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=rd": {"model": "computercraft:block/monitor_normal_rd", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=ru": {"model": "computercraft:block/monitor_normal_ru", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 90, "y": 0},
|
||||
"facing=north,orientation=down,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 90, "y": 0},
|
||||
"facing=north,orientation=north,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=lr": {"model": "computercraft:block/monitor_normal_lr", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=lru": {"model": "computercraft:block/monitor_normal_lru", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=lu": {"model": "computercraft:block/monitor_normal_lu", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=lud": {"model": "computercraft:block/monitor_normal_lud", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=none": {"model": "computercraft:block/monitor_normal", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=r": {"model": "computercraft:block/monitor_normal_r", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=rd": {"model": "computercraft:block/monitor_normal_rd", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=ru": {"model": "computercraft:block/monitor_normal_ru", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 0, "y": 0},
|
||||
"facing=north,orientation=north,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 0, "y": 0},
|
||||
"facing=north,orientation=up,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=lr": {"model": "computercraft:block/monitor_normal_lr", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=lru": {"model": "computercraft:block/monitor_normal_lru", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=lu": {"model": "computercraft:block/monitor_normal_lu", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=lud": {"model": "computercraft:block/monitor_normal_lud", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=none": {"model": "computercraft:block/monitor_normal", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=r": {"model": "computercraft:block/monitor_normal_r", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=rd": {"model": "computercraft:block/monitor_normal_rd", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=ru": {"model": "computercraft:block/monitor_normal_ru", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 270, "y": 0},
|
||||
"facing=north,orientation=up,state=ud": {"model": "computercraft:block/monitor_normal_ud", "x": 270, "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},
|
||||
"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},
|
||||
"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},
|
||||
"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},
|
||||
"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},
|
||||
"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},
|
||||
"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},
|
||||
"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},
|
||||
"facing=north,orientation=north,state=d": {"model": "computercraft:block/monitor_normal_d"},
|
||||
"facing=north,orientation=north,state=l": {"model": "computercraft:block/monitor_normal_l"},
|
||||
"facing=north,orientation=north,state=ld": {"model": "computercraft:block/monitor_normal_ld"},
|
||||
"facing=north,orientation=north,state=lr": {"model": "computercraft:block/monitor_normal_lr"},
|
||||
"facing=north,orientation=north,state=lrd": {"model": "computercraft:block/monitor_normal_lrd"},
|
||||
"facing=north,orientation=north,state=lru": {"model": "computercraft:block/monitor_normal_lru"},
|
||||
"facing=north,orientation=north,state=lrud": {"model": "computercraft:block/monitor_normal_lrud"},
|
||||
"facing=north,orientation=north,state=lu": {"model": "computercraft:block/monitor_normal_lu"},
|
||||
"facing=north,orientation=north,state=lud": {"model": "computercraft:block/monitor_normal_lud"},
|
||||
"facing=north,orientation=north,state=none": {"model": "computercraft:block/monitor_normal"},
|
||||
"facing=north,orientation=north,state=r": {"model": "computercraft:block/monitor_normal_r"},
|
||||
"facing=north,orientation=north,state=rd": {"model": "computercraft:block/monitor_normal_rd"},
|
||||
"facing=north,orientation=north,state=ru": {"model": "computercraft:block/monitor_normal_ru"},
|
||||
"facing=north,orientation=north,state=rud": {"model": "computercraft:block/monitor_normal_rud"},
|
||||
"facing=north,orientation=north,state=u": {"model": "computercraft:block/monitor_normal_u"},
|
||||
"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},
|
||||
"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},
|
||||
"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},
|
||||
"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},
|
||||
"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},
|
||||
"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},
|
||||
"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},
|
||||
"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},
|
||||
"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=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},
|
||||
@ -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=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=north,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 0, "y": 180},
|
||||
"facing=south,orientation=north,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 0, "y": 180},
|
||||
"facing=south,orientation=north,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 0, "y": 180},
|
||||
"facing=south,orientation=north,state=lr": {"model": "computercraft:block/monitor_normal_lr", "x": 0, "y": 180},
|
||||
"facing=south,orientation=north,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "x": 0, "y": 180},
|
||||
"facing=south,orientation=north,state=lru": {"model": "computercraft:block/monitor_normal_lru", "x": 0, "y": 180},
|
||||
"facing=south,orientation=north,state=lrud": {
|
||||
"model": "computercraft:block/monitor_normal_lrud",
|
||||
"x": 0,
|
||||
"y": 180
|
||||
},
|
||||
"facing=south,orientation=north,state=lu": {"model": "computercraft:block/monitor_normal_lu", "x": 0, "y": 180},
|
||||
"facing=south,orientation=north,state=lud": {"model": "computercraft:block/monitor_normal_lud", "x": 0, "y": 180},
|
||||
"facing=south,orientation=north,state=none": {"model": "computercraft:block/monitor_normal", "x": 0, "y": 180},
|
||||
"facing=south,orientation=north,state=r": {"model": "computercraft:block/monitor_normal_r", "x": 0, "y": 180},
|
||||
"facing=south,orientation=north,state=rd": {"model": "computercraft:block/monitor_normal_rd", "x": 0, "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=north,state=d": {"model": "computercraft:block/monitor_normal_d", "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", "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", "y": 180},
|
||||
"facing=south,orientation=north,state=lru": {"model": "computercraft:block/monitor_normal_lru", "y": 180},
|
||||
"facing=south,orientation=north,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "y": 180},
|
||||
"facing=south,orientation=north,state=lu": {"model": "computercraft:block/monitor_normal_lu", "y": 180},
|
||||
"facing=south,orientation=north,state=lud": {"model": "computercraft:block/monitor_normal_lud", "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=rd": {"model": "computercraft:block/monitor_normal_rd", "y": 180},
|
||||
"facing=south,orientation=north,state=ru": {"model": "computercraft:block/monitor_normal_ru", "y": 180},
|
||||
"facing=south,orientation=north,state=rud": {"model": "computercraft:block/monitor_normal_rud", "y": 180},
|
||||
"facing=south,orientation=north,state=u": {"model": "computercraft:block/monitor_normal_u", "y": 180},
|
||||
"facing=south,orientation=north,state=ud": {"model": "computercraft:block/monitor_normal_ud", "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=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=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=north,state=d": {"model": "computercraft:block/monitor_normal_d", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=l": {"model": "computercraft:block/monitor_normal_l", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=lr": {"model": "computercraft:block/monitor_normal_lr", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=lrd": {"model": "computercraft:block/monitor_normal_lrd", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=lru": {"model": "computercraft:block/monitor_normal_lru", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=lrud": {"model": "computercraft:block/monitor_normal_lrud", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=lu": {"model": "computercraft:block/monitor_normal_lu", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=lud": {"model": "computercraft:block/monitor_normal_lud", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=none": {"model": "computercraft:block/monitor_normal", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=r": {"model": "computercraft:block/monitor_normal_r", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=rd": {"model": "computercraft:block/monitor_normal_rd", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=ru": {"model": "computercraft:block/monitor_normal_ru", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=rud": {"model": "computercraft:block/monitor_normal_rud", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=u": {"model": "computercraft:block/monitor_normal_u", "x": 0, "y": 270},
|
||||
"facing=west,orientation=north,state=ud": {"model": "computercraft:block/monitor_normal_ud", "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", "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", "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", "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", "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", "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", "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", "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", "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=ld": {"model": "computercraft:block/monitor_normal_ld", "x": 270, "y": 270},
|
||||
|
@ -2,16 +2,16 @@
|
||||
"variants": {
|
||||
"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=north,top=false": {"model": "computercraft:block/printer_empty", "y": 0},
|
||||
"bottom=false,facing=north,top=true": {"model": "computercraft:block/printer_top_full", "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"},
|
||||
"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=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=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=north,top=false": {"model": "computercraft:block/printer_bottom_full", "y": 0},
|
||||
"bottom=true,facing=north,top=true": {"model": "computercraft:block/printer_both_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"},
|
||||
"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=west,top=false": {"model": "computercraft:block/printer_bottom_full", "y": 270},
|
||||
|
@ -1,16 +1,16 @@
|
||||
{
|
||||
"variants": {
|
||||
"facing=down,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "x": 90, "y": 0},
|
||||
"facing=down,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 90, "y": 0},
|
||||
"facing=east,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "x": 0, "y": 90},
|
||||
"facing=east,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 0, "y": 90},
|
||||
"facing=north,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "x": 0, "y": 0},
|
||||
"facing=north,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 0, "y": 0},
|
||||
"facing=south,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "x": 0, "y": 180},
|
||||
"facing=south,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 0, "y": 180},
|
||||
"facing=up,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "x": 270, "y": 0},
|
||||
"facing=up,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 270, "y": 0},
|
||||
"facing=west,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "x": 0, "y": 270},
|
||||
"facing=west,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 0, "y": 270}
|
||||
"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},
|
||||
"facing=east,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "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"},
|
||||
"facing=north,on=true": {"model": "computercraft:block/wireless_modem_advanced_on"},
|
||||
"facing=south,on=false": {"model": "computercraft:block/wireless_modem_advanced_off", "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},
|
||||
"facing=up,on=true": {"model": "computercraft:block/wireless_modem_advanced_on", "x": 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", "y": 270}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
{
|
||||
"variants": {
|
||||
"facing=down,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "x": 90, "y": 0},
|
||||
"facing=down,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 90, "y": 0},
|
||||
"facing=east,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "x": 0, "y": 90},
|
||||
"facing=east,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 0, "y": 90},
|
||||
"facing=north,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "x": 0, "y": 0},
|
||||
"facing=north,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 0, "y": 0},
|
||||
"facing=south,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "x": 0, "y": 180},
|
||||
"facing=south,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 0, "y": 180},
|
||||
"facing=up,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "x": 270, "y": 0},
|
||||
"facing=up,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 270, "y": 0},
|
||||
"facing=west,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "x": 0, "y": 270},
|
||||
"facing=west,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 0, "y": 270}
|
||||
"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},
|
||||
"facing=east,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "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"},
|
||||
"facing=north,on=true": {"model": "computercraft:block/wireless_modem_normal_on"},
|
||||
"facing=south,on=false": {"model": "computercraft:block/wireless_modem_normal_off", "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},
|
||||
"facing=up,on=true": {"model": "computercraft:block/wireless_modem_normal_on", "x": 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", "y": 270}
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,8 @@ class V1460Mixin {
|
||||
|
||||
// Disk drives contain a single item
|
||||
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.util.DropConsumer;
|
||||
import dan200.computercraft.shared.util.TickScheduler;
|
||||
import net.minecraft.core.component.DataComponentType;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
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.player.Player;
|
||||
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.block.Blocks;
|
||||
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) {
|
||||
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 diskId = stack.get(ModRegistry.DataComponents.DISK_ID.get());
|
||||
if (diskId != null && flags.isAdvanced()) diskId.addToTooltip("gui.computercraft.tooltip.disk_id", appender);
|
||||
|
||||
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);
|
||||
}
|
||||
var display = stack.getOrDefault(DataComponents.TOOLTIP_DISPLAY, TooltipDisplay.DEFAULT);
|
||||
stack.addToTooltip(ModRegistry.DataComponents.PRINTOUT.get(), context, display, appender, flags);
|
||||
stack.addToTooltip(ModRegistry.DataComponents.TREASURE_DISK.get(), context, display, appender, flags);
|
||||
stack.addToTooltip(ModRegistry.DataComponents.COMPUTER_ID.get(), context, display, appender, flags);
|
||||
stack.addToTooltip(ModRegistry.DataComponents.DISK_ID.get(), context, display, appender, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -200,9 +193,4 @@ public final class CommonHooks {
|
||||
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.UpgradeData;
|
||||
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||
import dan200.computercraft.core.util.Colour;
|
||||
import dan200.computercraft.impl.PocketUpgrades;
|
||||
import dan200.computercraft.shared.command.UserLevel;
|
||||
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.inventory.MenuType;
|
||||
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.Recipe;
|
||||
import net.minecraft.world.item.crafting.RecipeSerializer;
|
||||
@ -274,6 +273,13 @@ public final class ModRegistry {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
private static <B extends Block, I extends Item> RegistryEntry<I> ofBlock(RegistryEntry<B> parent, BiFunction<B, Item.Properties, I> supplier) {
|
||||
return register(parent.id().getPath(), p -> supplier.apply(parent.get(), p), properties().useBlockDescriptionPrefix());
|
||||
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());
|
||||
}
|
||||
|
||||
public static final RegistryEntry<BlockItem> COMPUTER_NORMAL = ofBlock(Blocks.COMPUTER_NORMAL, BlockItem::new);
|
||||
public static final RegistryEntry<BlockItem> COMPUTER_ADVANCED = ofBlock(Blocks.COMPUTER_ADVANCED, BlockItem::new);
|
||||
public static final RegistryEntry<GameMasterBlockItem> COMPUTER_COMMAND = ofBlock(Blocks.COMPUTER_COMMAND, GameMasterBlockItem::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, properties());
|
||||
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",
|
||||
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",
|
||||
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_ADVANCED = ofBlock(Blocks.TURTLE_ADVANCED, 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, dyeableProperties());
|
||||
|
||||
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 =
|
||||
register("treasure_disk", DiskItem::new, properties().stacksTo(1));
|
||||
register("treasure_disk", DiskItem::new, dyeableProperties().stacksTo(1));
|
||||
|
||||
private static Item.Properties printoutProperties() {
|
||||
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",
|
||||
PrintoutItem::new, Items::printoutProperties);
|
||||
|
||||
public static final RegistryEntry<BlockItem> SPEAKER = ofBlock(Blocks.SPEAKER, BlockItem::new);
|
||||
public static final RegistryEntry<BlockItem> DISK_DRIVE = ofBlock(Blocks.DISK_DRIVE, BlockItem::new);
|
||||
public static final RegistryEntry<BlockItem> PRINTER = ofBlock(Blocks.PRINTER, BlockItem::new);
|
||||
public static final RegistryEntry<BlockItem> MONITOR_NORMAL = ofBlock(Blocks.MONITOR_NORMAL, BlockItem::new);
|
||||
public static final RegistryEntry<BlockItem> MONITOR_ADVANCED = ofBlock(Blocks.MONITOR_ADVANCED, BlockItem::new);
|
||||
public static final RegistryEntry<BlockItem> WIRELESS_MODEM_NORMAL = ofBlock(Blocks.WIRELESS_MODEM_NORMAL, BlockItem::new);
|
||||
public static final RegistryEntry<BlockItem> WIRELESS_MODEM_ADVANCED = ofBlock(Blocks.WIRELESS_MODEM_ADVANCED, BlockItem::new);
|
||||
public static final RegistryEntry<BlockItem> WIRED_MODEM_FULL = ofBlock(Blocks.WIRED_MODEM_FULL, BlockItem::new);
|
||||
public static final RegistryEntry<BlockItem> REDSTONE_RELAY = ofBlock(Blocks.REDSTONE_RELAY, 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, properties());
|
||||
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, properties());
|
||||
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, properties());
|
||||
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, properties());
|
||||
public static final RegistryEntry<BlockItem> REDSTONE_RELAY = ofBlock(Blocks.REDSTONE_RELAY, BlockItem::new, properties());
|
||||
|
||||
public static final RegistryEntry<CableBlockItem.Cable> CABLE = register("cable",
|
||||
p -> new CableBlockItem.Cable(Blocks.CABLE.get(), p), properties().useBlockDescriptionPrefix());
|
||||
@ -340,8 +346,8 @@ public final class ModRegistry {
|
||||
/**
|
||||
* The id of a computer.
|
||||
*/
|
||||
public static final RegistryEntry<DataComponentType<NonNegativeId>> COMPUTER_ID = register("computer_id", b -> b
|
||||
.persistent(NonNegativeId.CODEC).networkSynchronized(NonNegativeId.STREAM_CODEC)
|
||||
public static final RegistryEntry<DataComponentType<NonNegativeId.Computer>> COMPUTER_ID = register("computer_id", b -> b
|
||||
.persistent(NonNegativeId.Computer.CODEC).networkSynchronized(NonNegativeId.Computer.STREAM_CODEC)
|
||||
);
|
||||
|
||||
/**
|
||||
@ -422,8 +428,8 @@ public final class ModRegistry {
|
||||
/**
|
||||
* The id of a disk.
|
||||
*/
|
||||
public static final RegistryEntry<DataComponentType<NonNegativeId>> DISK_ID = register("disk_id", b -> b
|
||||
.persistent(NonNegativeId.CODEC).networkSynchronized(NonNegativeId.STREAM_CODEC)
|
||||
public static final RegistryEntry<DataComponentType<NonNegativeId.Disk>> DISK_ID = register("disk_id", b -> b
|
||||
.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.DISK_DRIVE.get());
|
||||
for (var colour = 0; colour < 16; colour++) {
|
||||
out.accept(DataComponentUtil.createStack(Items.DISK.get(), net.minecraft.core.component.DataComponents.DYED_COLOR, new DyedItemColor(Colour.VALUES[colour].getHex(), false)));
|
||||
for (var colour : DyeColor.values()) {
|
||||
out.accept(DataComponentUtil.createDyedStack(Items.DISK.get(), colour.getTextureDiffuseColor()));
|
||||
}
|
||||
})
|
||||
.build());
|
||||
|
@ -182,10 +182,7 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
|
||||
output.append("\n");
|
||||
|
||||
var component = coloured(child.getName(), NAME);
|
||||
component.getStyle().withClickEvent(new ClickEvent(
|
||||
ClickEvent.Action.SUGGEST_COMMAND,
|
||||
"/" + command + " " + child.getName()
|
||||
));
|
||||
component.getStyle().withClickEvent(new ClickEvent.SuggestCommand("/" + command + " " + child.getName()));
|
||||
output.append(component);
|
||||
|
||||
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) {
|
||||
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) {
|
||||
@ -57,7 +57,7 @@ public final class ChatHelpers {
|
||||
|
||||
if (style.getColor() == null) style = style.withColor(ChatFormatting.YELLOW);
|
||||
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);
|
||||
}
|
||||
@ -68,8 +68,8 @@ public final class ChatHelpers {
|
||||
|
||||
public static MutableComponent copy(String text) {
|
||||
return Component.literal(text).withStyle(s -> s
|
||||
.withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, text))
|
||||
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.translatable("gui.computercraft.tooltip.copy")))
|
||||
.withClickEvent(new ClickEvent.CopyToClipboard(text))
|
||||
.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.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
@ -60,7 +59,9 @@ public final class ClearColourRecipe extends CustomRecipe {
|
||||
|
||||
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
|
||||
|
@ -10,9 +10,7 @@ import dan200.computercraft.shared.util.ColourTracker;
|
||||
import dan200.computercraft.shared.util.ColourUtils;
|
||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
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.CraftingInput;
|
||||
import net.minecraft.world.item.crafting.CustomRecipe;
|
||||
@ -66,8 +64,7 @@ public final class ColourableRecipe extends CustomRecipe {
|
||||
|
||||
return colourable.isEmpty()
|
||||
? ItemStack.EMPTY
|
||||
: DataComponentUtil.createResult(colourable, DataComponents.DYED_COLOR, new DyedItemColor(tracker.getColour(), false));
|
||||
|
||||
: DataComponentUtil.setDyeColour(colourable.copyWithCount(1), tracker.getColour());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6,7 +6,6 @@ package dan200.computercraft.shared.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.Containers;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
@ -60,12 +59,6 @@ public abstract class HorizontalContainerBlock extends BaseEntityBlock {
|
||||
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
|
||||
protected final boolean hasAnalogOutputSignal(BlockState pState) {
|
||||
return true;
|
||||
|
@ -21,10 +21,10 @@ import dan200.computercraft.shared.util.*;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.component.DataComponentGetter;
|
||||
import net.minecraft.core.component.DataComponentMap;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.LockCode;
|
||||
@ -166,16 +166,16 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
||||
|
||||
protected void loadServer(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||
// Load ID, label and power state
|
||||
computerID = nbt.contains(NBT_ID) ? nbt.getInt(NBT_ID) : -1;
|
||||
label = nbt.contains(NBT_LABEL) ? nbt.getString(NBT_LABEL) : null;
|
||||
storageCapacity = nbt.contains(NBT_CAPACITY, Tag.TAG_ANY_NUMERIC) ? nbt.getLong(NBT_CAPACITY) : -1;
|
||||
on = startOn = nbt.getBoolean(NBT_ON);
|
||||
computerID = nbt.getIntOr(NBT_ID, -1);
|
||||
label = nbt.getStringOr(NBT_LABEL, null);
|
||||
storageCapacity = nbt.getLongOr(NBT_CAPACITY, -1);
|
||||
on = startOn = nbt.getBooleanOr(NBT_ON, false);
|
||||
|
||||
lockCode = LockCode.fromTag(nbt, registries);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyImplicitComponents(DataComponentInput component) {
|
||||
protected void applyImplicitComponents(DataComponentGetter component) {
|
||||
super.applyImplicitComponents(component);
|
||||
label = DataComponentUtil.getCustomName(component.get(DataComponents.CUSTOM_NAME));
|
||||
computerID = NonNegativeId.getId(component.get(ModRegistry.DataComponents.COMPUTER_ID.get()));
|
||||
@ -197,7 +197,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
||||
*/
|
||||
@OverridingMethodsMustInvokeSuper
|
||||
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(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) {
|
||||
cursorX = nbt.getInt("term_cursorX");
|
||||
cursorY = nbt.getInt("term_cursorY");
|
||||
cursorBlink = nbt.getBoolean("term_cursorBlink");
|
||||
cursorColour = nbt.getInt("term_textColour");
|
||||
cursorBackgroundColour = nbt.getInt("term_bgColour");
|
||||
cursorX = nbt.getIntOr("term_cursorX", 0);
|
||||
cursorY = nbt.getIntOr("term_cursorY", 0);
|
||||
cursorBlink = nbt.getBooleanOr("term_cursorBlink", false);
|
||||
cursorColour = nbt.getIntOr("term_textColour", 0);
|
||||
cursorBackgroundColour = nbt.getIntOr("term_bgColour", 0);
|
||||
|
||||
for (var n = 0; n < height; n++) {
|
||||
text[n].fill(' ');
|
||||
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));
|
||||
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));
|
||||
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")) {
|
||||
var rgb8 = nbt.getIntArray("term_palette");
|
||||
if (rgb8.length == Palette.PALETTE_SIZE) {
|
||||
var rgb8 = nbt.getIntArray("term_palette").orElse(null);
|
||||
if (rgb8 != null && rgb8.length == Palette.PALETTE_SIZE) {
|
||||
for (var i = 0; i < Palette.PALETTE_SIZE; i++) {
|
||||
var colours = Palette.decodeRGB8(rgb8[i]);
|
||||
palette.setColour(i, colours[0], colours[1], colours[2]);
|
||||
|
@ -61,7 +61,7 @@ public class ItemDetails {
|
||||
if (!enchants.isEmpty()) data.put("enchantments", enchants);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
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) {
|
||||
static void dropItem(Level level, BlockPos pos, BlockState state, ItemStack stack) {
|
||||
if (stack.isEmpty()) return;
|
||||
|
||||
var direction = state.getValue(FACING);
|
||||
|
@ -16,7 +16,6 @@ import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
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.List;
|
||||
|
||||
import static dan200.computercraft.shared.lectern.CustomLecternBlock.dropItem;
|
||||
|
||||
/**
|
||||
* 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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemoveSideEffects(BlockPos pos, BlockState state) {
|
||||
if (level != null) dropItem(level, pos, state, getItem().copy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
|
||||
super.loadAdditional(tag, registries);
|
||||
|
||||
item = tag.contains(NBT_ITEM, Tag.TAG_COMPOUND) ? ItemStack.parseOptional(registries, tag.getCompound(NBT_ITEM)) : ItemStack.EMPTY;
|
||||
page = tag.getInt(NBT_PAGE);
|
||||
item = tag.getCompound(NBT_ITEM).flatMap(x -> ItemStack.parse(registries, x)).orElse(ItemStack.EMPTY);
|
||||
page = tag.getIntOr(NBT_PAGE, 0);
|
||||
itemChanged();
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import dan200.computercraft.api.media.IMedia;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.config.ConfigSpec;
|
||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||
import dan200.computercraft.shared.util.IDAssigner;
|
||||
import dan200.computercraft.shared.util.NonNegativeId;
|
||||
import dan200.computercraft.shared.util.StorageCapacity;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
@ -18,25 +19,28 @@ import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
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}.
|
||||
*/
|
||||
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 Supplier<DataComponentType<NonNegativeId>> id;
|
||||
private final boolean createId;
|
||||
private final Supplier<DataComponentType<T>> id;
|
||||
private final @Nullable IntFunction<T> createId;
|
||||
private final Supplier<Integer> defaultCapacity;
|
||||
|
||||
/**
|
||||
@ -49,8 +53,8 @@ public final class MountMedia implements IMedia {
|
||||
*/
|
||||
public MountMedia(
|
||||
String subPath,
|
||||
Supplier<DataComponentType<NonNegativeId>> id,
|
||||
boolean createId,
|
||||
Supplier<DataComponentType<T>> id,
|
||||
@Nullable IntFunction<T> createId,
|
||||
Supplier<Integer> defaultCapacity
|
||||
) {
|
||||
this.subPath = subPath;
|
||||
@ -72,8 +76,8 @@ public final class MountMedia implements IMedia {
|
||||
|
||||
@Override
|
||||
public @Nullable Mount createDataMount(ItemStack stack, ServerLevel level) {
|
||||
var id = createId
|
||||
? NonNegativeId.getOrCreate(level.getServer(), stack, this.id.get(), subPath)
|
||||
var id = createId != null
|
||||
? NonNegativeId.getOrCreate(level.getServer(), stack, this.id.get(), createId, subPath)
|
||||
: NonNegativeId.getId(stack.get(this.id.get()));
|
||||
if (id < 0) return null;
|
||||
|
||||
|
@ -81,7 +81,7 @@ public class PrintoutMenu extends AbstractContainerMenu {
|
||||
var currentItem = currentStack.getItem();
|
||||
|
||||
var slot = switch (hand) {
|
||||
case MAIN_HAND -> player.getInventory().selected;
|
||||
case MAIN_HAND -> player.getInventory().getSelectedSlot();
|
||||
case OFF_HAND -> Inventory.SLOT_OFFHAND;
|
||||
};
|
||||
return new PrintoutMenu(
|
||||
|
@ -9,6 +9,7 @@ import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.context.UseOnContext;
|
||||
|
||||
|
||||
/**
|
||||
* 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.shared.ModRegistry;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.core.component.DataComponentGetter;
|
||||
import net.minecraft.core.component.DataComponentHolder;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
@ -77,7 +78,7 @@ public record PrintoutData(String title, List<Line> lines) implements PrintoutCo
|
||||
);
|
||||
|
||||
@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()));
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
|
||||
public class PrintoutItem extends Item {
|
||||
public PrintoutItem(Properties settings) {
|
||||
super(settings);
|
||||
|
@ -7,6 +7,7 @@ package dan200.computercraft.shared.media.items;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import net.minecraft.core.component.DataComponentGetter;
|
||||
import net.minecraft.core.component.DataComponentHolder;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
@ -44,7 +45,7 @@ public record TreasureDisk(String name, String path) implements TooltipProvider
|
||||
}
|
||||
|
||||
@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()));
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import dan200.computercraft.shared.util.ColourTracker;
|
||||
import dan200.computercraft.shared.util.ColourUtils;
|
||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
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.ItemStack;
|
||||
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.Ingredient;
|
||||
import net.minecraft.world.item.crafting.PlacementInfo;
|
||||
@ -70,15 +68,10 @@ public class DiskRecipe extends AbstractCraftingRecipe {
|
||||
var dyes = ColourUtils.DYES;
|
||||
List<RecipeDisplay> out = new ArrayList<>(dyes.size());
|
||||
for (var i = 0; i < dyes.size(); i++) {
|
||||
var tracker = new ColourTracker();
|
||||
tracker.addColour(DyeColor.byId(i));
|
||||
|
||||
out.add(new ShapelessCraftingRecipeDisplay(
|
||||
Stream.concat(ingredients.stream(), Stream.of(Ingredient.of(BuiltInRegistries.ITEM.getOrThrow(dyes.get(i)))))
|
||||
.map(Ingredient::display).toList(),
|
||||
new SlotDisplay.ItemStackSlotDisplay(DataComponentUtil.createStack(
|
||||
ModRegistry.Items.DISK.get(), DataComponents.DYED_COLOR, new DyedItemColor(tracker.getColour(), false)
|
||||
)),
|
||||
new SlotDisplay.ItemStackSlotDisplay(DataComponentUtil.createDyedStack(ModRegistry.Items.DISK.get(), DyeColor.byId(i).getTextureDiffuseColor())),
|
||||
new SlotDisplay.ItemSlotDisplay(Items.CRAFTING_TABLE)
|
||||
));
|
||||
}
|
||||
@ -114,7 +107,7 @@ public class DiskRecipe extends AbstractCraftingRecipe {
|
||||
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
|
||||
|
@ -116,7 +116,7 @@ public final class DiskDriveBlockEntity extends AbstractContainerBlockEntity imp
|
||||
@Override
|
||||
public void loadAdditional(CompoundTag nbt, HolderLookup.Provider 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
|
||||
|
@ -12,7 +12,6 @@ import dan200.computercraft.shared.platform.ComponentAccess;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@ -104,11 +103,8 @@ public final class WiredModemLocalPeripheral {
|
||||
}
|
||||
|
||||
public void read(CompoundTag tag, String suffix) {
|
||||
id = tag.contains(NBT_PERIPHERAL_ID + suffix, Tag.TAG_ANY_NUMERIC)
|
||||
? tag.getInt(NBT_PERIPHERAL_ID + suffix) : -1;
|
||||
|
||||
type = tag.contains(NBT_PERIPHERAL_TYPE + suffix, Tag.TAG_STRING)
|
||||
? tag.getString(NBT_PERIPHERAL_TYPE + suffix) : null;
|
||||
id = tag.getIntOr(NBT_PERIPHERAL_ID + suffix, -1);
|
||||
type = tag.getStringOr(NBT_PERIPHERAL_TYPE + suffix, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -83,15 +83,6 @@ public class MonitorBlock extends HorizontalDirectionalBlock implements EntityBl
|
||||
.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
|
||||
protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rand) {
|
||||
var te = world.getBlockEntity(pos);
|
||||
|
@ -57,6 +57,12 @@ public class MonitorBlockEntity extends BlockEntity {
|
||||
private boolean needsUpdate = 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.
|
||||
boolean enqueued;
|
||||
@Nullable
|
||||
@ -82,13 +88,16 @@ public class MonitorBlockEntity extends BlockEntity {
|
||||
@Override
|
||||
public void clearRemoved() {
|
||||
super.clearRemoved();
|
||||
isRemoving = false;
|
||||
needsValidating = true; // Same, tbh
|
||||
TickScheduler.schedule(tickToken);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
// TODO: Call this before using the block
|
||||
if (!getLevel().isClientSide) contractNeighbours();
|
||||
@Override
|
||||
public void preRemoveSideEffects(BlockPos blockPos, BlockState blockState) {
|
||||
super.preRemoveSideEffects(blockPos, blockState);
|
||||
isRemoving = true;
|
||||
if (level != null && !getLevel().isClientSide) contractNeighbours();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -113,10 +122,10 @@ public class MonitorBlockEntity extends BlockEntity {
|
||||
var oldXIndex = xIndex;
|
||||
var oldYIndex = yIndex;
|
||||
|
||||
xIndex = nbt.getInt(NBT_X);
|
||||
yIndex = nbt.getInt(NBT_Y);
|
||||
width = nbt.getInt(NBT_WIDTH);
|
||||
height = nbt.getInt(NBT_HEIGHT);
|
||||
xIndex = nbt.getIntOr(NBT_X, 0);
|
||||
yIndex = nbt.getIntOr(NBT_Y, 0);
|
||||
width = nbt.getIntOr(NBT_WIDTH, 1);
|
||||
height = nbt.getIntOr(NBT_HEIGHT, 1);
|
||||
|
||||
if (level != null && level.isClientSide) onClientLoad(oldXIndex, oldYIndex);
|
||||
}
|
||||
@ -245,13 +254,11 @@ public class MonitorBlockEntity extends BlockEntity {
|
||||
public Direction getDirection() {
|
||||
// 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.
|
||||
var state = getBlockState();
|
||||
return state.hasProperty(MonitorBlock.FACING) ? state.getValue(MonitorBlock.FACING) : Direction.NORTH;
|
||||
return getBlockState().getValueOrElse(MonitorBlock.FACING, Direction.NORTH);
|
||||
}
|
||||
|
||||
public Direction getOrientation() {
|
||||
var state = getBlockState();
|
||||
return state.hasProperty(MonitorBlock.ORIENTATION) ? state.getValue(MonitorBlock.ORIENTATION) : Direction.NORTH;
|
||||
return getBlockState().getValueOrElse(MonitorBlock.ORIENTATION, Direction.NORTH);
|
||||
}
|
||||
|
||||
public Direction getFront() {
|
||||
@ -286,7 +293,10 @@ public class MonitorBlockEntity extends BlockEntity {
|
||||
}
|
||||
|
||||
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();
|
||||
if (world == null || !world.isLoaded(pos)) return MonitorState.UNLOADED;
|
||||
|
||||
var tile = world.getBlockEntity(pos);
|
||||
if (!(tile instanceof MonitorBlockEntity monitor)) return MonitorState.MISSING;
|
||||
if (!(world.getBlockEntity(pos) instanceof MonitorBlockEntity monitor)) return MonitorState.MISSING;
|
||||
|
||||
return isCompatible(monitor) ? MonitorState.present(monitor) : MonitorState.MISSING;
|
||||
}
|
||||
|
@ -60,8 +60,8 @@ public final class PrinterBlockEntity extends AbstractContainerBlockEntity imple
|
||||
|
||||
// Read page
|
||||
synchronized (page) {
|
||||
printing = nbt.getBoolean(NBT_PRINTING);
|
||||
pageTitle = nbt.getString(NBT_PAGE_TITLE);
|
||||
printing = nbt.getBooleanOr(NBT_PRINTING, false);
|
||||
pageTitle = nbt.getStringOr(NBT_PAGE_TITLE, "");
|
||||
page.readFromNBT(nbt);
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,8 @@ import dan200.computercraft.api.pocket.IPocketAccess;
|
||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||
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.item.ItemStack;
|
||||
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
|
||||
// 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);
|
||||
if (newUpgrade == null) {
|
||||
newUpgrade = findUpgrade(inventory.offhand, 0, previousUpgrade);
|
||||
UpgradeData<IPocketUpgrade> newUpgrade = null;
|
||||
for (var i = 0; i < Inventory.INVENTORY_SIZE; i++) {
|
||||
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" };
|
||||
|
||||
// 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) {
|
||||
for (var i = 0; i < inv.size(); i++) {
|
||||
var invStack = inv.get((i + start) % inv.size());
|
||||
if (!invStack.isEmpty()) {
|
||||
var newUpgrade = PocketUpgrades.instance().get(pocket.getLevel().registryAccess(), invStack);
|
||||
private @Nullable UpgradeData<IPocketUpgrade> findUpgrade(Container inv, int slot, @Nullable UpgradeData<IPocketUpgrade> previous) {
|
||||
var invStack = inv.getItem(slot);
|
||||
if (invStack.isEmpty()) return null;
|
||||
|
||||
if (newUpgrade != null && !Objects.equals(newUpgrade, previous)) {
|
||||
// Consume an item from this stack and exit the loop
|
||||
invStack = invStack.copy();
|
||||
invStack.shrink(1);
|
||||
inv.set((i + start) % inv.size(), invStack.isEmpty() ? ItemStack.EMPTY : invStack);
|
||||
var newUpgrade = PocketUpgrades.instance().get(pocket.getLevel().registryAccess(), invStack);
|
||||
if (newUpgrade != null && !Objects.equals(newUpgrade, previous)) {
|
||||
// Consume an item from this stack and exit the loop
|
||||
invStack = invStack.copy();
|
||||
invStack.shrink(1);
|
||||
inv.setItem(slot, invStack.isEmpty() ? ItemStack.EMPTY : invStack);
|
||||
|
||||
return newUpgrade;
|
||||
}
|
||||
}
|
||||
return newUpgrade;
|
||||
}
|
||||
|
||||
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.server.ServerNetworking;
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||
import net.minecraft.core.component.DataComponentPatch;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.component.DyedItemColor;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@ -93,7 +93,11 @@ public final class PocketBrain implements IPocketAccess {
|
||||
if (!dirty) return 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);
|
||||
return true;
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
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.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}.
|
||||
*
|
||||
|
@ -31,6 +31,8 @@ import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
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.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
@ -102,16 +104,13 @@ public class PocketComputerItem extends Item {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inventoryTick(ItemStack stack, Level world, Entity entity, int compartmentSlot, boolean selected) {
|
||||
// This (in vanilla at least) is only called for players. Don't bother to handle other entities.
|
||||
if (world.isClientSide || !(entity instanceof ServerPlayer player)) return;
|
||||
|
||||
// Find the actual slot the item exists in, aborting if it can't be found.
|
||||
var slot = InventoryUtil.getInventorySlotFromCompartment(player, compartmentSlot, stack);
|
||||
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);
|
||||
public void inventoryTick(ItemStack stack, ServerLevel level, Entity entity, @Nullable EquipmentSlot slot) {
|
||||
if (entity instanceof ServerPlayer player) {
|
||||
var invSlot = InventoryUtil.findItemInInventory(player.getInventory(), stack);
|
||||
if (invSlot != -1) tick(stack, new PocketHolder.PlayerHolder(player, invSlot), false);
|
||||
} else if (slot != null && entity instanceof LivingEntity living) {
|
||||
tick(stack, new PocketHolder.LivingEntityHolder(living, slot), true);
|
||||
}
|
||||
}
|
||||
|
||||
@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(
|
||||
holder, getUpgradeWithData(stack), DyedItemColor.getOrDefault(stack, -1),
|
||||
ServerComputer.properties(computerID, getFamily())
|
||||
|
@ -7,13 +7,13 @@ package dan200.computercraft.shared.turtle;
|
||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||
import dan200.computercraft.shared.platform.ContainerTransfer;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.turtle.core.TurtlePlayer;
|
||||
import dan200.computercraft.shared.util.DropConsumer;
|
||||
import dan200.computercraft.shared.util.InventoryUtil;
|
||||
import dan200.computercraft.shared.util.WorldUtil;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class TurtleUtil {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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 (turtle.isRemoved()) {
|
||||
WorldUtil.dropItemStack(turtle.getLevel(), turtle.getPosition(), null, stack);
|
||||
@ -50,18 +54,32 @@ public class TurtleUtil {
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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();
|
||||
DropConsumer.clearAndDrop(turtle.getLevel(), turtle.getPosition(), direction);
|
||||
/**
|
||||
* Stop a {@link DropConsumer}, and sync the items back to the {@link TurtlePlayer} inventory.
|
||||
* <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.component.DataComponents;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.Containers;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
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);
|
||||
}
|
||||
|
||||
@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
|
||||
public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity entity, ItemStack 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.HolderLookup;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.core.component.DataComponentGetter;
|
||||
import net.minecraft.core.component.DataComponentMap;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
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.item.ItemStack;
|
||||
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.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
@ -119,6 +121,11 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
|
||||
protected void updateBlockState(ComputerState newState) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemoveSideEffects(BlockPos blockPos, BlockState blockState) {
|
||||
if (!hasMoved()) super.preRemoveSideEffects(blockPos, blockState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void neighborChanged() {
|
||||
if (moveState == MoveState.NOT_MOVED) super.neighborChanged();
|
||||
@ -157,7 +164,7 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyImplicitComponents(DataComponentInput component) {
|
||||
protected void applyImplicitComponents(DataComponentGetter component) {
|
||||
super.applyImplicitComponents(component);
|
||||
|
||||
var colour = component.get(DataComponents.DYED_COLOR);
|
||||
@ -173,7 +180,10 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
|
||||
protected void collectSafeComponents(DataComponentMap.Builder 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.FUEL.get(), brain.getFuelLevel());
|
||||
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
|
||||
public void loadClient(CompoundTag nbt, HolderLookup.Provider 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);
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,6 @@ import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.component.DataComponentPatch;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.world.Container;
|
||||
@ -133,8 +132,8 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
*/
|
||||
private void readCommon(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||
// Read fields
|
||||
colourHex = nbt.contains(NBT_COLOUR) ? nbt.getInt(NBT_COLOUR) : -1;
|
||||
fuelLevel = nbt.contains(NBT_FUEL) ? nbt.getInt(NBT_FUEL) : 0;
|
||||
colourHex = nbt.getIntOr(NBT_COLOUR, -1);
|
||||
fuelLevel = nbt.getIntOr(NBT_FUEL, 0);
|
||||
overlay = nbt.contains(NBT_OVERLAY) ? NBTUtil.decodeFrom(TurtleOverlay.CODEC, registries, nbt, NBT_OVERLAY) : null;
|
||||
|
||||
// Read upgrades
|
||||
@ -145,7 +144,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
private void writeCommon(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||
nbt.putInt(NBT_FUEL, fuelLevel);
|
||||
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
|
||||
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);
|
||||
|
||||
// Read state
|
||||
selectedSlot = nbt.getInt(NBT_SLOT);
|
||||
selectedSlot = nbt.getIntOr(NBT_SLOT, 0);
|
||||
|
||||
// Read owner
|
||||
if (nbt.contains("Owner", Tag.TAG_COMPOUND)) {
|
||||
var owner = nbt.getCompound("Owner");
|
||||
var owner = nbt.getCompound("Owner").orElse(null);
|
||||
if (owner != null) {
|
||||
owningPlayer = new GameProfile(
|
||||
new UUID(owner.getLong("UpperId"), owner.getLong("LowerId")),
|
||||
owner.getString("Name")
|
||||
new UUID(owner.getLongOr("UpperId", 0), owner.getLongOr("LowerId", 0)),
|
||||
owner.getStringOr("Name", "")
|
||||
);
|
||||
} else {
|
||||
owningPlayer = null;
|
||||
@ -191,7 +190,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
readCommon(nbt, registries);
|
||||
|
||||
// Animation
|
||||
var anim = TurtleAnimation.values()[nbt.getInt("Animation")];
|
||||
var anim = TurtleAnimation.values()[nbt.getIntOr("Animation", 0)];
|
||||
if (anim != animation &&
|
||||
anim != TurtleAnimation.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.turtle.TurtleUtil;
|
||||
import dan200.computercraft.shared.util.DropConsumer;
|
||||
import dan200.computercraft.shared.util.InventoryUtil;
|
||||
import dan200.computercraft.shared.util.WorldUtil;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@ -106,9 +105,9 @@ public class TurtlePlaceCommand implements TurtleCommand {
|
||||
var hitEntity = entityHit.getEntity();
|
||||
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);
|
||||
TurtleUtil.stopConsuming(turtle);
|
||||
TurtleUtil.stopConsumingPlayer(turtle, turtlePlayer);
|
||||
return placed;
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ public final class TurtlePlayer {
|
||||
|
||||
public void loadInventory(ItemStack stack) {
|
||||
player.getInventory().clearContent();
|
||||
player.getInventory().selected = 0;
|
||||
player.getInventory().setSelectedSlot(0);
|
||||
player.getInventory().setItem(0, stack);
|
||||
}
|
||||
|
||||
@ -145,7 +145,7 @@ public final class TurtlePlayer {
|
||||
var slots = turtleInventory.getContainerSize();
|
||||
|
||||
// Load up the fake inventory
|
||||
inventory.selected = 0;
|
||||
inventory.setSelectedSlot(0);
|
||||
for (var i = 0; i < slots; i++) {
|
||||
inventory.setItem(i, turtleInventory.getItem((currentSlot + i) % slots));
|
||||
}
|
||||
@ -160,7 +160,7 @@ public final class TurtlePlayer {
|
||||
var slots = turtleInventory.getContainerSize();
|
||||
|
||||
// Load up the fake inventory
|
||||
inventory.selected = 0;
|
||||
inventory.setSelectedSlot(0);
|
||||
for (var i = 0; i < slots; i++) {
|
||||
turtleInventory.setItem((currentSlot + i) % slots, inventory.getItem(i));
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ public class TurtleTool extends AbstractTurtleUpgrade {
|
||||
var hitEntity = entityHit.getEntity();
|
||||
|
||||
// Start claiming entity drops
|
||||
DropConsumer.set(hitEntity, TurtleUtil.dropConsumer(turtle));
|
||||
DropConsumer.set(hitEntity);
|
||||
|
||||
// Attack the entity
|
||||
var result = PlatformHelper.get().canAttackEntity(player, hitEntity);
|
||||
@ -285,7 +285,7 @@ public class TurtleTool extends AbstractTurtleUpgrade {
|
||||
if (!breakable.isSuccess()) return breakable;
|
||||
|
||||
// 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);
|
||||
TurtleUtil.stopConsuming(turtle);
|
||||
|
||||
|
@ -53,4 +53,8 @@ public class ColourTracker {
|
||||
|
||||
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.network.chat.Component;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.component.DyedItemColor;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@ -38,14 +39,26 @@ public class DataComponentUtil {
|
||||
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) {
|
||||
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.
|
||||
*
|
||||
|
@ -5,7 +5,6 @@
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
@ -15,7 +14,6 @@ import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
||||
|
||||
@ -23,34 +21,30 @@ public final class DropConsumer {
|
||||
private DropConsumer() {
|
||||
}
|
||||
|
||||
private static @Nullable Function<ItemStack, ItemStack> dropConsumer;
|
||||
private static @Nullable List<ItemStack> remainingDrops;
|
||||
private static @Nullable List<ItemStack> drops;
|
||||
private static @Nullable Level dropWorld;
|
||||
private static @Nullable AABB dropBounds;
|
||||
private static @Nullable Entity dropEntity;
|
||||
|
||||
public static void set(Entity entity, Function<ItemStack, ItemStack> consumer) {
|
||||
dropConsumer = consumer;
|
||||
remainingDrops = new ArrayList<>();
|
||||
public static void set(Entity entity) {
|
||||
drops = new ArrayList<>();
|
||||
dropEntity = entity;
|
||||
dropWorld = entity.level();
|
||||
dropBounds = new AABB(entity.blockPosition()).inflate(2, 2, 2);
|
||||
}
|
||||
|
||||
public static void set(Level world, BlockPos pos, Function<ItemStack, ItemStack> consumer) {
|
||||
dropConsumer = consumer;
|
||||
remainingDrops = new ArrayList<>(2);
|
||||
public static void set(Level world, BlockPos pos) {
|
||||
drops = new ArrayList<>(2);
|
||||
dropEntity = null;
|
||||
dropWorld = world;
|
||||
dropBounds = new AABB(pos).inflate(2, 2, 2);
|
||||
}
|
||||
|
||||
public static List<ItemStack> clear() {
|
||||
var remainingStacks = remainingDrops;
|
||||
public static List<ItemStack> stop() {
|
||||
var remainingStacks = drops;
|
||||
if (remainingStacks == null) throw new IllegalStateException("Not currently capturing");
|
||||
|
||||
dropConsumer = null;
|
||||
remainingDrops = null;
|
||||
drops = null;
|
||||
dropEntity = null;
|
||||
dropWorld = null;
|
||||
dropBounds = null;
|
||||
@ -58,14 +52,8 @@ public final class DropConsumer {
|
||||
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) {
|
||||
var remaining = assertNonNull(dropConsumer).apply(stack);
|
||||
if (!remaining.isEmpty()) assertNonNull(remainingDrops).add(remaining);
|
||||
assertNonNull(drops).add(stack);
|
||||
}
|
||||
|
||||
public static boolean onEntitySpawn(Entity entity) {
|
||||
|
@ -9,12 +9,9 @@ import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.EntityHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@ -32,30 +29,22 @@ public final class InventoryUtil {
|
||||
*/
|
||||
public static int getHandSlot(Player player, InteractionHand hand) {
|
||||
return switch (hand) {
|
||||
case MAIN_HAND -> player.getInventory().selected;
|
||||
case MAIN_HAND -> player.getInventory().getSelectedSlot();
|
||||
case OFF_HAND -> Inventory.SLOT_OFFHAND;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a slot inside a player's compartment to a slot in the full player's inventory.
|
||||
* <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.
|
||||
* Find an item inside a container.
|
||||
*
|
||||
* @param player The player holding the item.
|
||||
* @param slot The slot inside the compartment.
|
||||
* @param stack The stack being ticked.
|
||||
* @return The inventory slot, or {@code -1} if the item could not be found in the inventory.
|
||||
* @param container The container to search in.
|
||||
* @param stack The item to find.
|
||||
* @return The container slot, or {@code -1} if the item could not be found in the container.
|
||||
*/
|
||||
public static int getInventorySlotFromCompartment(Player player, int slot, ItemStack stack) {
|
||||
if (stack.isEmpty()) throw new IllegalArgumentException("Cannot search for empty stack");
|
||||
if (player.getInventory().getItem(slot) == stack) return slot;
|
||||
if (player.getInventory().getItem(Inventory.SLOT_OFFHAND) == stack) return Inventory.SLOT_OFFHAND;
|
||||
public static int findItemInInventory(Container container, ItemStack stack) {
|
||||
for (int i = 0, size = container.getContainerSize(); i < size; i++) {
|
||||
if (container.getItem(i) == stack) return i;
|
||||
}
|
||||
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) {
|
||||
var childTag = tag.get(key);
|
||||
return childTag == null ? null : codec.parse(registries.createSerializationContext(NbtOps.INSTANCE), childTag)
|
||||
.resultOrPartial(e -> LOG.warn("Failed to parse NBT: {}", e))
|
||||
.orElse(null);
|
||||
return tag.read(key, codec, registries.createSerializationContext(NbtOps.INSTANCE)).orElse(null);
|
||||
}
|
||||
|
||||
public static <T> void encodeTo(Codec<T> codec, HolderLookup.Provider registries, CompoundTag destination, String key, @Nullable T value) {
|
||||
if (value == null) return;
|
||||
codec.encodeStart(registries.createSerializationContext(NbtOps.INSTANCE), value)
|
||||
.resultOrPartial(e -> LOG.warn("Failed to save NBT: {}", e))
|
||||
.ifPresent(x -> destination.put(key, x));
|
||||
destination.storeNullable(key, codec, registries.createSerializationContext(NbtOps.INSTANCE), value);
|
||||
}
|
||||
|
||||
public static @Nullable Object toLua(@Nullable Tag tag) {
|
||||
if (tag == null) return null;
|
||||
|
||||
return switch (tag.getId()) {
|
||||
case Tag.TAG_BYTE, Tag.TAG_SHORT, Tag.TAG_INT, Tag.TAG_LONG -> ((NumericTag) tag).getAsLong();
|
||||
case Tag.TAG_FLOAT, Tag.TAG_DOUBLE -> ((NumericTag) tag).getAsDouble();
|
||||
case Tag.TAG_STRING -> tag.getAsString();
|
||||
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).doubleValue();
|
||||
case Tag.TAG_STRING -> ((StringTag) tag).value();
|
||||
case Tag.TAG_COMPOUND -> {
|
||||
var compound = (CompoundTag) tag;
|
||||
Map<String, Object> map = new HashMap<>(compound.size());
|
||||
for (var key : compound.getAllKeys()) {
|
||||
var value = toLua(compound.get(key));
|
||||
if (value != null) map.put(key, value);
|
||||
for (var entry : compound.entrySet()) {
|
||||
var value = toLua(entry.getValue());
|
||||
if (value != null) map.put(entry.getKey(), value);
|
||||
}
|
||||
yield map;
|
||||
}
|
||||
@ -110,7 +104,7 @@ public final class NBTUtil {
|
||||
|
||||
private static void writeTag(DataOutput output, Tag tag) throws IOException {
|
||||
if (tag instanceof CompoundTag compound) {
|
||||
var keys = compound.getAllKeys().toArray(new String[0]);
|
||||
var keys = compound.keySet().toArray(new String[0]);
|
||||
Arrays.sort(keys);
|
||||
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 io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.component.DataComponentGetter;
|
||||
import net.minecraft.core.component.DataComponentType;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import net.minecraft.world.item.Item;
|
||||
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 java.util.function.Consumer;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
/**
|
||||
* 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#DISK_ID
|
||||
*/
|
||||
public record NonNegativeId(int id) {
|
||||
public static final Codec<NonNegativeId> CODEC = ExtraCodecs.NON_NEGATIVE_INT.xmap(NonNegativeId::new, NonNegativeId::id);
|
||||
public abstract class NonNegativeId implements TooltipProvider {
|
||||
private final int id;
|
||||
|
||||
public static final StreamCodec<ByteBuf, NonNegativeId> STREAM_CODEC = ByteBufCodecs.VAR_INT.map(NonNegativeId::new, NonNegativeId::id);
|
||||
|
||||
public NonNegativeId {
|
||||
protected NonNegativeId(int id) {
|
||||
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) {
|
||||
return id == null ? -1 : id.id();
|
||||
}
|
||||
|
||||
public static @Nullable NonNegativeId of(int id) {
|
||||
return id >= 0 ? new NonNegativeId(id) : null;
|
||||
}
|
||||
|
||||
public static int getOrCreate(MinecraftServer server, ItemStack stack, DataComponentType<NonNegativeId> component, String type) {
|
||||
public static <T extends NonNegativeId> int getOrCreate(MinecraftServer server, ItemStack stack, DataComponentType<T> component, IntFunction<T> create, String type) {
|
||||
var id = stack.get(component);
|
||||
if (id != null) return id.id();
|
||||
|
||||
var diskID = ComputerCraftAPI.createUniqueNumberedSaveDir(server, type);
|
||||
stack.set(component, new NonNegativeId(diskID));
|
||||
return diskID;
|
||||
var newId = ComputerCraftAPI.createUniqueNumberedSaveDir(server, type);
|
||||
stack.set(component, create.apply(newId));
|
||||
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));
|
||||
}
|
||||
|
||||
@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 itemModelOutput Lnet/minecraft/client/data/models/ItemModelOutput;
|
||||
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 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/level/block/Block;Lnet/minecraft/resources/ResourceLocation;)V
|
||||
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 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
|
||||
|
||||
# DirectVertexBuffer
|
||||
accessible field com/mojang/blaze3d/vertex/VertexBuffer indexCount I
|
||||
|
||||
# ClientTableFormatter
|
||||
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
|
||||
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.ListTag;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
@ -57,7 +58,7 @@ public class NBTUtilTest {
|
||||
var nbt1 = makeCompoundTag(false);
|
||||
var nbt2 = makeCompoundTag(true);
|
||||
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."
|
||||
);
|
||||
}
|
||||
@ -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.
|
||||
* @return The resulting hash.
|
||||
|
@ -8,9 +8,7 @@ import com.mojang.blaze3d.ProjectionType;
|
||||
import com.mojang.blaze3d.pipeline.TextureTarget;
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import org.joml.Matrix4f;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@ -23,19 +21,19 @@ public class ImageRenderer implements AutoCloseable {
|
||||
public static final int WIDTH = 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);
|
||||
|
||||
public ImageRenderer() {
|
||||
framebuffer.setClearColor(0, 0, 0, 0);
|
||||
framebuffer.clear();
|
||||
// framebuffer.setFilterMode(0, 0, 0, 0);
|
||||
// framebuffer.clear();
|
||||
}
|
||||
|
||||
public void captureRender(Path output, Runnable render) throws IOException {
|
||||
Files.createDirectories(output.getParent());
|
||||
|
||||
RenderSystem.clear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
||||
framebuffer.bindWrite(true);
|
||||
// RenderSystem.clear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
||||
// framebuffer.bindWrite(true);
|
||||
|
||||
// Setup rendering state
|
||||
RenderSystem.backupProjectionMatrix();
|
||||
@ -53,14 +51,14 @@ public class ImageRenderer implements AutoCloseable {
|
||||
RenderSystem.restoreProjectionMatrix();
|
||||
transform.popMatrix();
|
||||
|
||||
framebuffer.unbindWrite();
|
||||
Minecraft.getInstance().getMainRenderTarget().bindWrite(true);
|
||||
// framebuffer.unbindWrite();
|
||||
// Minecraft.getInstance().getMainRenderTarget().bindWrite(true);
|
||||
|
||||
// And save the image
|
||||
framebuffer.bindRead();
|
||||
image.downloadTexture(0, false);
|
||||
image.flipY();
|
||||
framebuffer.unbindRead();
|
||||
// framebuffer.bindRead();
|
||||
// image.downloadTexture(0, false);
|
||||
// image.flipY();
|
||||
// framebuffer.unbindRead();
|
||||
|
||||
image.writeToFile(output);
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
package dan200.computercraft.gametest.api;
|
||||
|
||||
import dan200.computercraft.gametest.core.TestAPI;
|
||||
import net.minecraft.gametest.framework.GameTestAssertException;
|
||||
import net.minecraft.gametest.framework.GameTestSequence;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@ -32,9 +31,9 @@ public class ComputerState {
|
||||
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 (error != null) throw new GameTestAssertException(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
public static @Nullable ComputerState get(String label) {
|
||||
|
@ -6,7 +6,6 @@ package dan200.computercraft.gametest.core;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.mixin.gametest.TestCommandAccessor;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.util.NonNegativeId;
|
||||
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.ItemInput;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.gametest.framework.GameTestRegistry;
|
||||
import net.minecraft.gametest.framework.StructureUtils;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
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 java.io.IOException;
|
||||
@ -41,38 +40,18 @@ class CCTestCommand {
|
||||
|
||||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext buildContext) {
|
||||
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 -> {
|
||||
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");
|
||||
|
||||
var structureBlock = (StructureBlockEntity) player.level().getBlockEntity(pos);
|
||||
if (structureBlock == null) return error(context.getSource(), "No nearby structure block");
|
||||
var info = GameTestRegistry.getTestFunction(structureBlock.getMetaData());
|
||||
var test = player.level().getBlockEntity(pos, BlockEntityType.TEST_INSTANCE_BLOCK)
|
||||
.flatMap(TestInstanceBlockEntity::test).orElse(null);
|
||||
if (test == null) return error(context.getSource(), "No nearby structure block");
|
||||
|
||||
// Kill the existing armor stand
|
||||
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));
|
||||
|
||||
// And create a new one
|
||||
@ -82,7 +61,7 @@ class CCTestCommand {
|
||||
var armorStand = new ArmorStand(EntityType.ARMOR_STAND, level);
|
||||
armorStand.readAdditionalSaveData(nbt);
|
||||
armorStand.copyPosition(player);
|
||||
armorStand.setCustomName(Component.literal(info.testName()));
|
||||
armorStand.setCustomName(Component.literal(test.location().getPath()));
|
||||
level.addFreshEntity(armorStand);
|
||||
return 0;
|
||||
}))
|
||||
@ -91,16 +70,16 @@ class CCTestCommand {
|
||||
var item = context.getArgument("item", ItemInput.class);
|
||||
|
||||
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");
|
||||
|
||||
var structureBlock = (StructureBlockEntity) player.level().getBlockEntity(pos);
|
||||
if (structureBlock == null) return error(context.getSource(), "No nearby structure block");
|
||||
var info = GameTestRegistry.getTestFunction(structureBlock.getMetaData());
|
||||
var test = player.level().getBlockEntity(pos, BlockEntityType.TEST_INSTANCE_BLOCK)
|
||||
.flatMap(TestInstanceBlockEntity::test).orElse(null);
|
||||
if (test == null) return error(context.getSource(), "No nearby structure block");
|
||||
|
||||
var stack = item.createItemStack(1, false);
|
||||
stack.set(ModRegistry.DataComponents.COMPUTER_ID.get(), new NonNegativeId(1));
|
||||
stack.set(DataComponents.CUSTOM_NAME, Component.literal(info.testName()));
|
||||
stack.set(ModRegistry.DataComponents.COMPUTER_ID.get(), new NonNegativeId.Computer(1));
|
||||
stack.set(DataComponents.CUSTOM_NAME, Component.literal(test.location().getPath()));
|
||||
if (!player.getInventory().add(stack)) {
|
||||
var itemEntity = player.drop(stack, false);
|
||||
if (itemEntity != null) {
|
||||
|
@ -11,5 +11,5 @@ import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
@Mixin(GameTestInfo.class)
|
||||
public interface GameTestInfoAccessor {
|
||||
@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