mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-31 21:52:59 +00:00
Merge branch 'mc-1.20.x' into mc-1.20.y
This commit is contained in:
@@ -9,6 +9,7 @@ import dan200.computercraft.client.gui.widgets.DynamicImageButton;
|
||||
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
||||
import dan200.computercraft.client.network.ClientNetworking;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.util.Nullability;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.InputHandler;
|
||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||
@@ -18,6 +19,7 @@ import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.network.server.UploadFileMessage;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||
@@ -96,8 +98,8 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
getTerminal().update();
|
||||
|
||||
if (uploadNagDeadline != Long.MAX_VALUE && Util.getNanos() >= uploadNagDeadline) {
|
||||
new ItemToast(minecraft, displayStack, NO_RESPONSE_TITLE, NO_RESPONSE_MSG, ItemToast.TRANSFER_NO_RESPONSE_TOKEN)
|
||||
.showOrReplace(minecraft.getToasts());
|
||||
new ItemToast(minecraft(), displayStack, NO_RESPONSE_TITLE, NO_RESPONSE_MSG, ItemToast.TRANSFER_NO_RESPONSE_TOKEN)
|
||||
.showOrReplace(minecraft().getToasts());
|
||||
uploadNagDeadline = Long.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -206,7 +208,7 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
return;
|
||||
}
|
||||
|
||||
if (toUpload.size() > 0) UploadFileMessage.send(menu, toUpload, ClientNetworking::sendToServer);
|
||||
if (!toUpload.isEmpty()) UploadFileMessage.send(menu, toUpload, ClientNetworking::sendToServer);
|
||||
}
|
||||
|
||||
public void uploadResult(UploadResult result, @Nullable Component message) {
|
||||
@@ -222,9 +224,13 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
}
|
||||
|
||||
private void alert(Component title, Component message) {
|
||||
OptionScreen.show(minecraft, title, message,
|
||||
List.of(OptionScreen.newButton(OK, b -> minecraft.setScreen(this))),
|
||||
() -> minecraft.setScreen(this)
|
||||
OptionScreen.show(minecraft(), title, message,
|
||||
List.of(OptionScreen.newButton(OK, b -> minecraft().setScreen(this))),
|
||||
() -> minecraft().setScreen(this)
|
||||
);
|
||||
}
|
||||
|
||||
private Minecraft minecraft() {
|
||||
return Nullability.assertNonNull(minecraft);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ package dan200.computercraft.client.gui;
|
||||
|
||||
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.util.Nullability;
|
||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.gui.screens.inventory.MenuAccess;
|
||||
@@ -16,6 +18,7 @@ import net.minecraft.world.entity.player.Inventory;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
|
||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
||||
|
||||
@@ -44,8 +47,8 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
||||
protected void init() {
|
||||
// First ensure we're still grabbing the mouse, so the user can look around. Then reset bits of state that
|
||||
// grabbing unsets.
|
||||
minecraft.mouseHandler.grabMouse();
|
||||
minecraft.screen = this;
|
||||
minecraft().mouseHandler.grabMouse();
|
||||
minecraft().screen = this;
|
||||
KeyMapping.releaseAll();
|
||||
|
||||
super.init();
|
||||
@@ -64,13 +67,13 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
||||
|
||||
@Override
|
||||
public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
|
||||
minecraft.player.getInventory().swapPaint(scrollX);
|
||||
Objects.requireNonNull(minecraft().player).getInventory().swapPaint(scrollY);
|
||||
return super.mouseScrolled(mouseX, mouseY, scrollX, scrollY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
minecraft.player.closeContainer();
|
||||
Objects.requireNonNull(minecraft().player).closeContainer();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@@ -93,12 +96,16 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
||||
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
|
||||
super.render(graphics, mouseX, mouseY, partialTicks);
|
||||
|
||||
var font = minecraft.font;
|
||||
var font = minecraft().font;
|
||||
var lines = font.split(Component.translatable("gui.computercraft.pocket_computer_overlay"), (int) (width * 0.8));
|
||||
var y = 10;
|
||||
for (var line : lines) {
|
||||
graphics.drawString(font, line, (width / 2) - (minecraft.font.width(line) / 2), y, 0xFFFFFF, true);
|
||||
graphics.drawString(font, line, (width / 2) - (font.width(line) / 2), y, 0xFFFFFF, true);
|
||||
y += 9;
|
||||
}
|
||||
}
|
||||
|
||||
private Minecraft minecraft() {
|
||||
return Nullability.assertNonNull(minecraft);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,13 +66,13 @@ public class PrintoutScreen extends AbstractContainerScreen<HeldItemMenu> {
|
||||
@Override
|
||||
public boolean mouseScrolled(double x, double y, double deltaX, double deltaY) {
|
||||
if (super.mouseScrolled(x, y, deltaX, deltaY)) return true;
|
||||
if (deltaX < 0) {
|
||||
if (deltaY < 0) {
|
||||
// Scroll up goes to the next page
|
||||
if (page < pages - 1) page++;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (deltaX > 0) {
|
||||
if (deltaY > 0) {
|
||||
// Scroll down goes to the previous page
|
||||
if (page > 0) page--;
|
||||
return true;
|
||||
|
||||
@@ -195,16 +195,16 @@ public class TerminalWidget extends AbstractWidget {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseScrolled(double mouseX, double mouseY, double delta, double deltaY) {
|
||||
public boolean mouseScrolled(double mouseX, double mouseY, double deltaX, double deltaY) {
|
||||
if (!inTermRegion(mouseX, mouseY)) return false;
|
||||
if (!hasMouseSupport() || delta == 0) return false;
|
||||
if (!hasMouseSupport() || deltaY == 0) return false;
|
||||
|
||||
var charX = (int) ((mouseX - innerX) / FONT_WIDTH);
|
||||
var charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
|
||||
charX = Math.min(Math.max(charX, 0), terminal.getWidth() - 1);
|
||||
charY = Math.min(Math.max(charY, 0), terminal.getHeight() - 1);
|
||||
|
||||
computer.mouseScroll(delta < 0 ? 1 : -1, charX + 1, charY + 1);
|
||||
computer.mouseScroll(deltaY < 0 ? 1 : -1, charX + 1, charY + 1);
|
||||
|
||||
lastMouseX = charX;
|
||||
lastMouseY = charY;
|
||||
|
||||
@@ -6,7 +6,6 @@ package dan200.computercraft.client.pocket;
|
||||
|
||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
|
||||
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||
import dan200.computercraft.shared.network.client.PocketComputerDataMessage;
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
@@ -47,13 +46,10 @@ public final class ClientPocketComputers {
|
||||
public static void setState(UUID instanceId, ComputerState state, int lightColour, TerminalState terminalData) {
|
||||
var computer = instances.get(instanceId);
|
||||
if (computer == null) {
|
||||
var terminal = new NetworkedTerminal(terminalData.width, terminalData.height, terminalData.colour);
|
||||
instances.put(instanceId, computer = new PocketComputerData(state, lightColour, terminal));
|
||||
instances.put(instanceId, new PocketComputerData(state, lightColour, terminalData));
|
||||
} else {
|
||||
computer.setState(state, lightColour);
|
||||
computer.setState(state, lightColour, terminalData);
|
||||
}
|
||||
|
||||
if (terminalData.hasTerminal()) terminalData.apply(computer.getTerminal());
|
||||
}
|
||||
|
||||
public static @Nullable PocketComputerData get(ItemStack stack) {
|
||||
|
||||
@@ -6,8 +6,11 @@ package dan200.computercraft.client.pocket;
|
||||
|
||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
|
||||
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||
import dan200.computercraft.shared.pocket.core.PocketServerComputer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Clientside data about a pocket computer.
|
||||
* <p>
|
||||
@@ -19,21 +22,21 @@ import dan200.computercraft.shared.pocket.core.PocketServerComputer;
|
||||
* @see PocketServerComputer The server-side pocket computer.
|
||||
*/
|
||||
public final class PocketComputerData {
|
||||
private final NetworkedTerminal terminal;
|
||||
private @Nullable NetworkedTerminal terminal;
|
||||
private ComputerState state;
|
||||
private int lightColour;
|
||||
|
||||
PocketComputerData(ComputerState state, int lightColour, NetworkedTerminal terminal) {
|
||||
PocketComputerData(ComputerState state, int lightColour, TerminalState terminalData) {
|
||||
this.state = state;
|
||||
this.lightColour = lightColour;
|
||||
this.terminal = terminal;
|
||||
if (terminalData.hasTerminal()) terminal = terminalData.create();
|
||||
}
|
||||
|
||||
public int getLightState() {
|
||||
return state != ComputerState.OFF ? lightColour : -1;
|
||||
}
|
||||
|
||||
public NetworkedTerminal getTerminal() {
|
||||
public @Nullable NetworkedTerminal getTerminal() {
|
||||
return terminal;
|
||||
}
|
||||
|
||||
@@ -41,8 +44,16 @@ public final class PocketComputerData {
|
||||
return state;
|
||||
}
|
||||
|
||||
void setState(ComputerState state, int lightColour) {
|
||||
void setState(ComputerState state, int lightColour, TerminalState terminalData) {
|
||||
this.state = state;
|
||||
this.lightColour = lightColour;
|
||||
|
||||
if (terminalData.hasTerminal()) {
|
||||
if (terminal == null) {
|
||||
terminal = terminalData.create();
|
||||
} else {
|
||||
terminalData.apply(terminal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A base class for items which have map-like rendering when held in the hand.
|
||||
*
|
||||
@@ -35,7 +37,7 @@ public abstract class ItemMapLikeRenderer {
|
||||
protected abstract void renderItem(PoseStack transform, MultiBufferSource render, ItemStack stack, int light);
|
||||
|
||||
public void renderItemFirstPerson(PoseStack transform, MultiBufferSource render, int lightTexture, InteractionHand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack) {
|
||||
Player player = Minecraft.getInstance().player;
|
||||
Player player = Objects.requireNonNull(Minecraft.getInstance().player);
|
||||
|
||||
transform.pushPose();
|
||||
if (hand == InteractionHand.MAIN_HAND && player.getOffhandItem().isEmpty()) {
|
||||
|
||||
@@ -55,7 +55,7 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
|
||||
// Render the label
|
||||
var label = turtle.getLabel();
|
||||
var hit = renderer.cameraHitResult;
|
||||
if (label != null && hit.getType() == HitResult.Type.BLOCK && turtle.getBlockPos().equals(((BlockHitResult) hit).getBlockPos())) {
|
||||
if (label != null && hit != null && hit.getType() == HitResult.Type.BLOCK && turtle.getBlockPos().equals(((BlockHitResult) hit).getBlockPos())) {
|
||||
var mc = Minecraft.getInstance();
|
||||
var font = this.font;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import dan200.computercraft.api.ComputerCraftTags;
|
||||
import dan200.computercraft.impl.RegistryHelper;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import net.minecraft.core.Registry;
|
||||
import dan200.computercraft.shared.integration.ExternalModTags;
|
||||
import net.minecraft.data.tags.ItemTagsProvider;
|
||||
import net.minecraft.data.tags.TagsProvider;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
@@ -82,6 +83,12 @@ class TagProvider {
|
||||
);
|
||||
|
||||
tags.tag(BlockTags.WITHER_IMMUNE).add(ModRegistry.Blocks.COMPUTER_COMMAND.get());
|
||||
|
||||
tags.tag(ExternalModTags.Blocks.CREATE_BRITTLE).add(
|
||||
ModRegistry.Blocks.CABLE.get(),
|
||||
ModRegistry.Blocks.WIRELESS_MODEM_NORMAL.get(),
|
||||
ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED.get()
|
||||
);
|
||||
}
|
||||
|
||||
public static void itemTags(ItemTagConsumer tags) {
|
||||
|
||||
@@ -223,7 +223,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
||||
var offsetSide = dir.getOpposite();
|
||||
var localDir = remapToLocalSide(dir);
|
||||
|
||||
computer.setRedstoneInput(localDir, RedstoneUtil.getRedstoneInput(level, targetPos, dir));
|
||||
computer.setRedstoneInput(localDir, RedstoneUtil.getRedstoneInput(getLevel(), targetPos, dir));
|
||||
computer.setBundledRedstoneInput(localDir, BundledRedstone.getOutput(getLevel(), targetPos, offsetSide));
|
||||
}
|
||||
|
||||
|
||||
@@ -28,13 +28,14 @@ public class ServerComputerRegistry {
|
||||
}
|
||||
|
||||
void update() {
|
||||
var it = getComputers().iterator();
|
||||
var it = computersByInstanceUuid.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
var computer = it.next();
|
||||
if (computer.hasTimedOut()) {
|
||||
computer.unload();
|
||||
computer.onRemoved();
|
||||
it.remove();
|
||||
computersByInstanceUuid.remove(computer.getInstanceUUID());
|
||||
} else {
|
||||
computer.tickServer();
|
||||
}
|
||||
|
||||
@@ -18,10 +18,9 @@ import javax.annotation.Nullable;
|
||||
* states, etc...
|
||||
*/
|
||||
public class TerminalState {
|
||||
public final boolean colour;
|
||||
|
||||
public final int width;
|
||||
public final int height;
|
||||
private final boolean colour;
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
@Nullable
|
||||
private final ByteBuf buffer;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.integration;
|
||||
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
/**
|
||||
* Tags defined by external mods.
|
||||
*/
|
||||
public final class ExternalModTags {
|
||||
private ExternalModTags() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Block tags defined by external mods.
|
||||
*/
|
||||
public static final class Blocks {
|
||||
private Blocks() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create's "brittle" tag, used to determine if this block needs to be moved before its neighbours.
|
||||
*
|
||||
* @see <a href="https://github.com/Creators-of-Create/Create/blob/mc1.20.1/dev/src/main/java/com/simibubi/create/content/contraptions/BlockMovementChecks.java">{@code BlockMovementChecks}</a>
|
||||
*/
|
||||
public static final TagKey<Block> CREATE_BRITTLE = make("create", "brittle");
|
||||
|
||||
private static TagKey<Block> make(String mod, String name) {
|
||||
return TagKey.create(Registries.BLOCK, new ResourceLocation(mod, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -303,7 +303,7 @@ public final class DiskDriveBlockEntity extends AbstractContainerBlockEntity {
|
||||
|
||||
// Set the id (if needed) and write it back to the media stack.
|
||||
var stack = media.stack().copy();
|
||||
mount = media.media().createDataMount(stack, (ServerLevel) level);
|
||||
mount = media.media().createDataMount(stack, (ServerLevel) getLevel());
|
||||
updateMediaStack(stack, immediate);
|
||||
|
||||
return mount;
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
|
||||
package dan200.computercraft.shared.peripheral.modem;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
|
||||
@@ -22,4 +25,17 @@ public final class ModemShapes {
|
||||
var direction = facing.ordinal();
|
||||
return direction < BOXES.length ? BOXES[direction] : Shapes.block();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a block can support a modem.
|
||||
*
|
||||
* @param level The current level.
|
||||
* @param pos The position of the adjacent block.
|
||||
* @param side The side the modem will be placed against.
|
||||
* @return Whether this block can support a modem.
|
||||
*/
|
||||
public static boolean canSupport(LevelReader level, BlockPos pos, Direction side) {
|
||||
// TODO(1.20.4): Check the side is a full-block instead.
|
||||
return Block.canSupportCenter(level, pos, side);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package dan200.computercraft.shared.peripheral.modem.wired;
|
||||
|
||||
import dan200.computercraft.annotations.ForgeOverride;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.peripheral.modem.ModemShapes;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.util.WaterloggableHelpers;
|
||||
import dan200.computercraft.shared.util.WorldUtil;
|
||||
@@ -183,7 +184,7 @@ public class CableBlock extends Block implements SimpleWaterloggedBlock, EntityB
|
||||
|
||||
// Pop our modem if needed.
|
||||
var dir = state.getValue(MODEM).getFacing();
|
||||
if (dir != null && dir.equals(side) && !canSupportCenter(level, otherPos, side.getOpposite())) {
|
||||
if (dir != null && dir.equals(side) && !ModemShapes.canSupport(level, otherPos, side.getOpposite())) {
|
||||
// If we've no cable, follow normal Minecraft logic and just remove the block.
|
||||
if (!state.getValue(CABLE)) return getFluidState(state).createLegacyBlock();
|
||||
|
||||
@@ -212,7 +213,7 @@ public class CableBlock extends Block implements SimpleWaterloggedBlock, EntityB
|
||||
var facing = state.getValue(MODEM).getFacing();
|
||||
if (facing == null) return true;
|
||||
|
||||
return canSupportCenter(world, pos.relative(facing), facing.getOpposite());
|
||||
return ModemShapes.canSupport(world, pos.relative(facing), facing.getOpposite());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -107,7 +107,7 @@ public class CableBlockEntity extends BlockEntity {
|
||||
|
||||
void neighborChanged(BlockPos neighbour) {
|
||||
var dir = getModemDirection();
|
||||
if (!level.isClientSide && dir != null && getBlockPos().relative(dir).equals(neighbour) && isPeripheralOn()) {
|
||||
if (!getLevel().isClientSide && dir != null && getBlockPos().relative(dir).equals(neighbour) && isPeripheralOn()) {
|
||||
queueRefreshPeripheral();
|
||||
}
|
||||
}
|
||||
@@ -163,7 +163,7 @@ public class CableBlockEntity extends BlockEntity {
|
||||
.from(oldVariant.getFacing(), modem.getModemState().isOpen(), peripheral.hasPeripheral());
|
||||
|
||||
if (oldVariant != newVariant) {
|
||||
level.setBlockAndUpdate(getBlockPos(), state.setValue(CableBlock.MODEM, newVariant));
|
||||
getLevel().setBlockAndUpdate(getBlockPos(), state.setValue(CableBlock.MODEM, newVariant));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ public class WirelessModemBlock extends DirectionalBlock implements SimpleWaterl
|
||||
@Deprecated
|
||||
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
|
||||
var facing = state.getValue(FACING);
|
||||
return canSupportCenter(world, pos.relative(facing), facing.getOpposite());
|
||||
return ModemShapes.canSupport(world, pos.relative(facing), facing.getOpposite());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -56,8 +56,11 @@ public final class ClientMonitor {
|
||||
|
||||
void read(TerminalState state) {
|
||||
if (state.hasTerminal()) {
|
||||
if (terminal == null) terminal = new NetworkedTerminal(state.width, state.height, state.colour);
|
||||
state.apply(terminal);
|
||||
if (terminal == null) {
|
||||
terminal = state.create();
|
||||
} else {
|
||||
state.apply(terminal);
|
||||
}
|
||||
terminalChanged = true;
|
||||
} else {
|
||||
if (terminal != null) {
|
||||
|
||||
@@ -174,7 +174,7 @@ public class MonitorBlockEntity extends BlockEntity {
|
||||
} else {
|
||||
// Otherwise fetch the origin and attempt to get its monitor
|
||||
// Note this may load chunks, but we don't really have a choice here.
|
||||
var te = level.getBlockEntity(toWorldPos(0, 0));
|
||||
var te = getLevel().getBlockEntity(toWorldPos(0, 0));
|
||||
if (!(te instanceof MonitorBlockEntity monitor)) return null;
|
||||
|
||||
return serverMonitor = monitor.createServerMonitor();
|
||||
@@ -416,7 +416,7 @@ public class MonitorBlockEntity extends BlockEntity {
|
||||
|
||||
@Nullable
|
||||
private MonitorBlockEntity tryResizeAt(BlockPos pos, int width, int height) {
|
||||
var tile = level.getBlockEntity(pos);
|
||||
var tile = getLevel().getBlockEntity(pos);
|
||||
if (tile instanceof MonitorBlockEntity monitor && isCompatible(monitor)) {
|
||||
monitor.resize(width, height);
|
||||
return monitor;
|
||||
|
||||
@@ -19,15 +19,16 @@ import dan200.computercraft.shared.network.client.SpeakerPlayClientMessage;
|
||||
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
import dan200.computercraft.shared.util.PauseAwareTimer;
|
||||
import net.minecraft.ResourceLocationException;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.protocol.game.ClientboundSoundPacket;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.item.RecordItem;
|
||||
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@@ -252,15 +253,15 @@ public abstract class SpeakerPeripheral implements IPeripheral {
|
||||
var volume = (float) clampVolume(checkFinite(1, volumeA.orElse(1.0)));
|
||||
var pitch = (float) checkFinite(2, pitchA.orElse(1.0));
|
||||
|
||||
ResourceLocation identifier;
|
||||
try {
|
||||
identifier = new ResourceLocation(name);
|
||||
} catch (ResourceLocationException e) {
|
||||
throw new LuaException("Malformed sound name '" + name + "' ");
|
||||
}
|
||||
var identifier = ResourceLocation.tryParse(name);
|
||||
if (identifier == null) throw new LuaException("Malformed sound name '" + name + "' ");
|
||||
|
||||
// Prevent playing music discs.
|
||||
var soundEvent = BuiltInRegistries.SOUND_EVENT.get(identifier);
|
||||
if (soundEvent != null && RecordItem.getBySound(soundEvent) != null) return false;
|
||||
|
||||
synchronized (lock) {
|
||||
if (dfpwmState != null && dfpwmState.isPlaying()) return false;
|
||||
if (pendingSound != null || (dfpwmState != null && dfpwmState.isPlaying())) return false;
|
||||
dfpwmState = null;
|
||||
pendingSound = new PendingSound<>(identifier, volume, pitch);
|
||||
return true;
|
||||
|
||||
@@ -165,7 +165,7 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
|
||||
|
||||
public void setDirection(Direction dir) {
|
||||
if (dir.getAxis() == Direction.Axis.Y) dir = Direction.NORTH;
|
||||
level.setBlockAndUpdate(worldPosition, getBlockState().setValue(TurtleBlock.FACING, dir));
|
||||
getLevel().setBlockAndUpdate(worldPosition, getBlockState().setValue(TurtleBlock.FACING, dir));
|
||||
|
||||
updateRedstone();
|
||||
updateInputsImmediately();
|
||||
|
||||
@@ -11,7 +11,8 @@ import org.junit.jupiter.api.RepeatedTest;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
/**
|
||||
* Tests {@link TerminalState} round tripping works as expected.
|
||||
@@ -42,6 +43,7 @@ public class TerminalStateTest {
|
||||
private static void checkEqual(Terminal expected, Terminal actual) {
|
||||
assertNotNull(expected, "Expected cannot be null");
|
||||
assertNotNull(actual, "Actual cannot be null");
|
||||
assertEquals(expected.isColour(), actual.isColour(), "isColour must match");
|
||||
assertEquals(expected.getHeight(), actual.getHeight(), "Heights must match");
|
||||
assertEquals(expected.getWidth(), actual.getWidth(), "Widths must match");
|
||||
|
||||
@@ -51,13 +53,6 @@ public class TerminalStateTest {
|
||||
}
|
||||
|
||||
private static NetworkedTerminal read(FriendlyByteBuf buffer) {
|
||||
var state = new TerminalState(buffer);
|
||||
assertTrue(state.colour);
|
||||
|
||||
if (!state.hasTerminal()) return null;
|
||||
|
||||
var other = new NetworkedTerminal(state.width, state.height, true);
|
||||
state.apply(other);
|
||||
return other;
|
||||
return new TerminalState(buffer).create();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.io.Writer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -82,7 +83,7 @@ public class Exporter {
|
||||
}
|
||||
|
||||
// Now find all CC recipes.
|
||||
var level = Minecraft.getInstance().level;
|
||||
var level = Objects.requireNonNull(Minecraft.getInstance().level);
|
||||
for (var recipe : level.getRecipeManager().getAllRecipesFor(RecipeType.CRAFTING)) {
|
||||
var result = recipe.value().getResultItem(level.registryAccess());
|
||||
if (!RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, result.getItem()).getNamespace().equals(ComputerCraftAPI.MOD_ID)) {
|
||||
|
||||
@@ -41,7 +41,7 @@ class Pocket_Computer_Test {
|
||||
val pocketComputer = ClientPocketComputers.get(minecraft.player!!.mainHandItem)!!
|
||||
assertEquals(ComputerState.ON, pocketComputer.state)
|
||||
|
||||
val term = pocketComputer.terminal
|
||||
val term = pocketComputer.terminal!!
|
||||
assertEquals("Hello, world!", term.getLine(0).toString().trim(), "Terminal contents is synced")
|
||||
}
|
||||
// Update the terminal contents again.
|
||||
@@ -57,7 +57,7 @@ class Pocket_Computer_Test {
|
||||
val pocketComputer = ClientPocketComputers.get(minecraft.player!!.mainHandItem)!!
|
||||
assertEquals(ComputerState.BLINKING, pocketComputer.state)
|
||||
|
||||
val term = pocketComputer.terminal
|
||||
val term = pocketComputer.terminal!!
|
||||
assertEquals("Updated text :)", term.getLine(0).toString().trim(), "Terminal contents is synced")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.gametest
|
||||
|
||||
import dan200.computercraft.gametest.api.sequence
|
||||
import dan200.computercraft.gametest.api.thenOnComputer
|
||||
import dan200.computercraft.gametest.api.tryMultipleTimes
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral
|
||||
import dan200.computercraft.test.core.assertArrayEquals
|
||||
import net.minecraft.gametest.framework.GameTest
|
||||
import net.minecraft.gametest.framework.GameTestHelper
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
|
||||
class Speaker_Test {
|
||||
/**
|
||||
* [SpeakerPeripheral.playSound] fails if there is already a sound queued.
|
||||
*/
|
||||
@GameTest
|
||||
fun Fails_to_play_multiple_sounds(helper: GameTestHelper) = helper.sequence {
|
||||
thenOnComputer {
|
||||
callPeripheral("right", "playSound", SoundEvents.NOTE_BLOCK_HARP.key().location().toString())
|
||||
.assertArrayEquals(true)
|
||||
|
||||
tryMultipleTimes(2) { // We could technically call this a tick later, so try twice
|
||||
callPeripheral("right", "playSound", SoundEvents.NOTE_BLOCK_HARP.key().location().toString())
|
||||
.assertArrayEquals(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [SpeakerPeripheral.playSound] will not play records.
|
||||
*/
|
||||
@GameTest
|
||||
fun Will_not_play_record(helper: GameTestHelper) = helper.sequence {
|
||||
thenOnComputer {
|
||||
callPeripheral("right", "playSound", SoundEvents.MUSIC_DISC_PIGSTEP.location.toString())
|
||||
.assertArrayEquals(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -323,3 +323,16 @@ fun GameTestHelper.placeItemAt(stack: ItemStack, pos: BlockPos, direction: Direc
|
||||
val hit = BlockHitResult(Vec3.atCenterOf(absolutePos), direction, absolutePos, false)
|
||||
stack.useOn(UseOnContext(player, InteractionHand.MAIN_HAND, hit))
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a function multiple times until it succeeds.
|
||||
*/
|
||||
inline fun tryMultipleTimes(count: Int, action: () -> Unit) {
|
||||
for (remaining in count - 1 downTo 0) {
|
||||
try {
|
||||
action()
|
||||
} catch (e: AssertionError) {
|
||||
if (remaining == 0) throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ object TestHooks {
|
||||
Printer_Test::class.java,
|
||||
Printout_Test::class.java,
|
||||
Recipe_Test::class.java,
|
||||
Speaker_Test::class.java,
|
||||
Turtle_Test::class.java,
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
{
|
||||
DataVersion: 3465,
|
||||
size: [5, 5, 5],
|
||||
data: [
|
||||
{pos: [0, 0, 0], state: "minecraft:polished_andesite"},
|
||||
{pos: [0, 0, 1], state: "minecraft:polished_andesite"},
|
||||
{pos: [0, 0, 2], state: "minecraft:polished_andesite"},
|
||||
{pos: [0, 0, 3], state: "minecraft:polished_andesite"},
|
||||
{pos: [0, 0, 4], state: "minecraft:polished_andesite"},
|
||||
{pos: [1, 0, 0], state: "minecraft:polished_andesite"},
|
||||
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
||||
{pos: [1, 0, 2], state: "minecraft:polished_andesite"},
|
||||
{pos: [1, 0, 3], state: "minecraft:polished_andesite"},
|
||||
{pos: [1, 0, 4], state: "minecraft:polished_andesite"},
|
||||
{pos: [2, 0, 0], state: "minecraft:polished_andesite"},
|
||||
{pos: [2, 0, 1], state: "minecraft:polished_andesite"},
|
||||
{pos: [2, 0, 2], state: "minecraft:polished_andesite"},
|
||||
{pos: [2, 0, 3], state: "minecraft:polished_andesite"},
|
||||
{pos: [2, 0, 4], state: "minecraft:polished_andesite"},
|
||||
{pos: [3, 0, 0], state: "minecraft:polished_andesite"},
|
||||
{pos: [3, 0, 1], state: "minecraft:polished_andesite"},
|
||||
{pos: [3, 0, 2], state: "minecraft:polished_andesite"},
|
||||
{pos: [3, 0, 3], state: "minecraft:polished_andesite"},
|
||||
{pos: [3, 0, 4], state: "minecraft:polished_andesite"},
|
||||
{pos: [4, 0, 0], state: "minecraft:polished_andesite"},
|
||||
{pos: [4, 0, 1], state: "minecraft:polished_andesite"},
|
||||
{pos: [4, 0, 2], state: "minecraft:polished_andesite"},
|
||||
{pos: [4, 0, 3], state: "minecraft:polished_andesite"},
|
||||
{pos: [4, 0, 4], state: "minecraft:polished_andesite"},
|
||||
{pos: [0, 1, 0], state: "minecraft:air"},
|
||||
{pos: [0, 1, 1], state: "minecraft:air"},
|
||||
{pos: [0, 1, 2], state: "minecraft:air"},
|
||||
{pos: [0, 1, 3], state: "minecraft:air"},
|
||||
{pos: [0, 1, 4], state: "minecraft:air"},
|
||||
{pos: [1, 1, 0], state: "minecraft:air"},
|
||||
{pos: [1, 1, 1], state: "minecraft:air"},
|
||||
{pos: [1, 1, 2], state: "computercraft:speaker{facing:north}", nbt: {id: "computercraft:speaker"}},
|
||||
{pos: [1, 1, 3], state: "minecraft:air"},
|
||||
{pos: [1, 1, 4], state: "minecraft:air"},
|
||||
{pos: [2, 1, 0], state: "minecraft:air"},
|
||||
{pos: [2, 1, 1], state: "minecraft:air"},
|
||||
{pos: [2, 1, 2], state: "computercraft:computer_normal{facing:north,state:on}", nbt: {ComputerId: 1, Label: "speaker_test.fails_to_play_multiple_sounds", On: 1b, id: "computercraft:computer_normal"}},
|
||||
{pos: [2, 1, 3], state: "minecraft:air"},
|
||||
{pos: [2, 1, 4], state: "minecraft:air"},
|
||||
{pos: [3, 1, 0], state: "minecraft:air"},
|
||||
{pos: [3, 1, 1], state: "minecraft:air"},
|
||||
{pos: [3, 1, 2], state: "minecraft:air"},
|
||||
{pos: [3, 1, 3], state: "minecraft:air"},
|
||||
{pos: [3, 1, 4], state: "minecraft:air"},
|
||||
{pos: [4, 1, 0], state: "minecraft:air"},
|
||||
{pos: [4, 1, 1], state: "minecraft:air"},
|
||||
{pos: [4, 1, 2], state: "minecraft:air"},
|
||||
{pos: [4, 1, 3], state: "minecraft:air"},
|
||||
{pos: [4, 1, 4], state: "minecraft:air"},
|
||||
{pos: [0, 2, 0], state: "minecraft:air"},
|
||||
{pos: [0, 2, 1], state: "minecraft:air"},
|
||||
{pos: [0, 2, 2], state: "minecraft:air"},
|
||||
{pos: [0, 2, 3], state: "minecraft:air"},
|
||||
{pos: [0, 2, 4], state: "minecraft:air"},
|
||||
{pos: [1, 2, 0], state: "minecraft:air"},
|
||||
{pos: [1, 2, 1], state: "minecraft:air"},
|
||||
{pos: [1, 2, 2], state: "minecraft:air"},
|
||||
{pos: [1, 2, 3], state: "minecraft:air"},
|
||||
{pos: [1, 2, 4], state: "minecraft:air"},
|
||||
{pos: [2, 2, 0], state: "minecraft:air"},
|
||||
{pos: [2, 2, 1], state: "minecraft:air"},
|
||||
{pos: [2, 2, 2], state: "minecraft:air"},
|
||||
{pos: [2, 2, 3], state: "minecraft:air"},
|
||||
{pos: [2, 2, 4], state: "minecraft:air"},
|
||||
{pos: [3, 2, 0], state: "minecraft:air"},
|
||||
{pos: [3, 2, 1], state: "minecraft:air"},
|
||||
{pos: [3, 2, 2], state: "minecraft:air"},
|
||||
{pos: [3, 2, 3], state: "minecraft:air"},
|
||||
{pos: [3, 2, 4], state: "minecraft:air"},
|
||||
{pos: [4, 2, 0], state: "minecraft:air"},
|
||||
{pos: [4, 2, 1], state: "minecraft:air"},
|
||||
{pos: [4, 2, 2], state: "minecraft:air"},
|
||||
{pos: [4, 2, 3], state: "minecraft:air"},
|
||||
{pos: [4, 2, 4], state: "minecraft:air"},
|
||||
{pos: [0, 3, 0], state: "minecraft:air"},
|
||||
{pos: [0, 3, 1], state: "minecraft:air"},
|
||||
{pos: [0, 3, 2], state: "minecraft:air"},
|
||||
{pos: [0, 3, 3], state: "minecraft:air"},
|
||||
{pos: [0, 3, 4], state: "minecraft:air"},
|
||||
{pos: [1, 3, 0], state: "minecraft:air"},
|
||||
{pos: [1, 3, 1], state: "minecraft:air"},
|
||||
{pos: [1, 3, 2], state: "minecraft:air"},
|
||||
{pos: [1, 3, 3], state: "minecraft:air"},
|
||||
{pos: [1, 3, 4], state: "minecraft:air"},
|
||||
{pos: [2, 3, 0], state: "minecraft:air"},
|
||||
{pos: [2, 3, 1], state: "minecraft:air"},
|
||||
{pos: [2, 3, 2], state: "minecraft:air"},
|
||||
{pos: [2, 3, 3], state: "minecraft:air"},
|
||||
{pos: [2, 3, 4], state: "minecraft:air"},
|
||||
{pos: [3, 3, 0], state: "minecraft:air"},
|
||||
{pos: [3, 3, 1], state: "minecraft:air"},
|
||||
{pos: [3, 3, 2], state: "minecraft:air"},
|
||||
{pos: [3, 3, 3], state: "minecraft:air"},
|
||||
{pos: [3, 3, 4], state: "minecraft:air"},
|
||||
{pos: [4, 3, 0], state: "minecraft:air"},
|
||||
{pos: [4, 3, 1], state: "minecraft:air"},
|
||||
{pos: [4, 3, 2], state: "minecraft:air"},
|
||||
{pos: [4, 3, 3], state: "minecraft:air"},
|
||||
{pos: [4, 3, 4], state: "minecraft:air"},
|
||||
{pos: [0, 4, 0], state: "minecraft:air"},
|
||||
{pos: [0, 4, 1], state: "minecraft:air"},
|
||||
{pos: [0, 4, 2], state: "minecraft:air"},
|
||||
{pos: [0, 4, 3], state: "minecraft:air"},
|
||||
{pos: [0, 4, 4], state: "minecraft:air"},
|
||||
{pos: [1, 4, 0], state: "minecraft:air"},
|
||||
{pos: [1, 4, 1], state: "minecraft:air"},
|
||||
{pos: [1, 4, 2], state: "minecraft:air"},
|
||||
{pos: [1, 4, 3], state: "minecraft:air"},
|
||||
{pos: [1, 4, 4], state: "minecraft:air"},
|
||||
{pos: [2, 4, 0], state: "minecraft:air"},
|
||||
{pos: [2, 4, 1], state: "minecraft:air"},
|
||||
{pos: [2, 4, 2], state: "minecraft:air"},
|
||||
{pos: [2, 4, 3], state: "minecraft:air"},
|
||||
{pos: [2, 4, 4], state: "minecraft:air"},
|
||||
{pos: [3, 4, 0], state: "minecraft:air"},
|
||||
{pos: [3, 4, 1], state: "minecraft:air"},
|
||||
{pos: [3, 4, 2], state: "minecraft:air"},
|
||||
{pos: [3, 4, 3], state: "minecraft:air"},
|
||||
{pos: [3, 4, 4], state: "minecraft:air"},
|
||||
{pos: [4, 4, 0], state: "minecraft:air"},
|
||||
{pos: [4, 4, 1], state: "minecraft:air"},
|
||||
{pos: [4, 4, 2], state: "minecraft:air"},
|
||||
{pos: [4, 4, 3], state: "minecraft:air"},
|
||||
{pos: [4, 4, 4], state: "minecraft:air"}
|
||||
],
|
||||
entities: [],
|
||||
palette: [
|
||||
"minecraft:polished_andesite",
|
||||
"minecraft:air",
|
||||
"computercraft:speaker{facing:north}",
|
||||
"computercraft:computer_normal{facing:north,state:on}"
|
||||
]
|
||||
}
|
||||
138
projects/common/src/testMod/resources/data/cctest/structures/speaker_test.will_not_play_record.snbt
generated
Normal file
138
projects/common/src/testMod/resources/data/cctest/structures/speaker_test.will_not_play_record.snbt
generated
Normal file
@@ -0,0 +1,138 @@
|
||||
{
|
||||
DataVersion: 3465,
|
||||
size: [5, 5, 5],
|
||||
data: [
|
||||
{pos: [0, 0, 0], state: "minecraft:polished_andesite"},
|
||||
{pos: [0, 0, 1], state: "minecraft:polished_andesite"},
|
||||
{pos: [0, 0, 2], state: "minecraft:polished_andesite"},
|
||||
{pos: [0, 0, 3], state: "minecraft:polished_andesite"},
|
||||
{pos: [0, 0, 4], state: "minecraft:polished_andesite"},
|
||||
{pos: [1, 0, 0], state: "minecraft:polished_andesite"},
|
||||
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
||||
{pos: [1, 0, 2], state: "minecraft:polished_andesite"},
|
||||
{pos: [1, 0, 3], state: "minecraft:polished_andesite"},
|
||||
{pos: [1, 0, 4], state: "minecraft:polished_andesite"},
|
||||
{pos: [2, 0, 0], state: "minecraft:polished_andesite"},
|
||||
{pos: [2, 0, 1], state: "minecraft:polished_andesite"},
|
||||
{pos: [2, 0, 2], state: "minecraft:polished_andesite"},
|
||||
{pos: [2, 0, 3], state: "minecraft:polished_andesite"},
|
||||
{pos: [2, 0, 4], state: "minecraft:polished_andesite"},
|
||||
{pos: [3, 0, 0], state: "minecraft:polished_andesite"},
|
||||
{pos: [3, 0, 1], state: "minecraft:polished_andesite"},
|
||||
{pos: [3, 0, 2], state: "minecraft:polished_andesite"},
|
||||
{pos: [3, 0, 3], state: "minecraft:polished_andesite"},
|
||||
{pos: [3, 0, 4], state: "minecraft:polished_andesite"},
|
||||
{pos: [4, 0, 0], state: "minecraft:polished_andesite"},
|
||||
{pos: [4, 0, 1], state: "minecraft:polished_andesite"},
|
||||
{pos: [4, 0, 2], state: "minecraft:polished_andesite"},
|
||||
{pos: [4, 0, 3], state: "minecraft:polished_andesite"},
|
||||
{pos: [4, 0, 4], state: "minecraft:polished_andesite"},
|
||||
{pos: [0, 1, 0], state: "minecraft:air"},
|
||||
{pos: [0, 1, 1], state: "minecraft:air"},
|
||||
{pos: [0, 1, 2], state: "minecraft:air"},
|
||||
{pos: [0, 1, 3], state: "minecraft:air"},
|
||||
{pos: [0, 1, 4], state: "minecraft:air"},
|
||||
{pos: [1, 1, 0], state: "minecraft:air"},
|
||||
{pos: [1, 1, 1], state: "minecraft:air"},
|
||||
{pos: [1, 1, 2], state: "computercraft:speaker{facing:north}", nbt: {id: "computercraft:speaker"}},
|
||||
{pos: [1, 1, 3], state: "minecraft:air"},
|
||||
{pos: [1, 1, 4], state: "minecraft:air"},
|
||||
{pos: [2, 1, 0], state: "minecraft:air"},
|
||||
{pos: [2, 1, 1], state: "minecraft:air"},
|
||||
{pos: [2, 1, 2], state: "computercraft:computer_normal{facing:north,state:on}", nbt: {ComputerId: 1, Label: "speaker_test.will_not_play_record", On: 1b, id: "computercraft:computer_normal"}},
|
||||
{pos: [2, 1, 3], state: "minecraft:air"},
|
||||
{pos: [2, 1, 4], state: "minecraft:air"},
|
||||
{pos: [3, 1, 0], state: "minecraft:air"},
|
||||
{pos: [3, 1, 1], state: "minecraft:air"},
|
||||
{pos: [3, 1, 2], state: "minecraft:air"},
|
||||
{pos: [3, 1, 3], state: "minecraft:air"},
|
||||
{pos: [3, 1, 4], state: "minecraft:air"},
|
||||
{pos: [4, 1, 0], state: "minecraft:air"},
|
||||
{pos: [4, 1, 1], state: "minecraft:air"},
|
||||
{pos: [4, 1, 2], state: "minecraft:air"},
|
||||
{pos: [4, 1, 3], state: "minecraft:air"},
|
||||
{pos: [4, 1, 4], state: "minecraft:air"},
|
||||
{pos: [0, 2, 0], state: "minecraft:air"},
|
||||
{pos: [0, 2, 1], state: "minecraft:air"},
|
||||
{pos: [0, 2, 2], state: "minecraft:air"},
|
||||
{pos: [0, 2, 3], state: "minecraft:air"},
|
||||
{pos: [0, 2, 4], state: "minecraft:air"},
|
||||
{pos: [1, 2, 0], state: "minecraft:air"},
|
||||
{pos: [1, 2, 1], state: "minecraft:air"},
|
||||
{pos: [1, 2, 2], state: "minecraft:air"},
|
||||
{pos: [1, 2, 3], state: "minecraft:air"},
|
||||
{pos: [1, 2, 4], state: "minecraft:air"},
|
||||
{pos: [2, 2, 0], state: "minecraft:air"},
|
||||
{pos: [2, 2, 1], state: "minecraft:air"},
|
||||
{pos: [2, 2, 2], state: "minecraft:air"},
|
||||
{pos: [2, 2, 3], state: "minecraft:air"},
|
||||
{pos: [2, 2, 4], state: "minecraft:air"},
|
||||
{pos: [3, 2, 0], state: "minecraft:air"},
|
||||
{pos: [3, 2, 1], state: "minecraft:air"},
|
||||
{pos: [3, 2, 2], state: "minecraft:air"},
|
||||
{pos: [3, 2, 3], state: "minecraft:air"},
|
||||
{pos: [3, 2, 4], state: "minecraft:air"},
|
||||
{pos: [4, 2, 0], state: "minecraft:air"},
|
||||
{pos: [4, 2, 1], state: "minecraft:air"},
|
||||
{pos: [4, 2, 2], state: "minecraft:air"},
|
||||
{pos: [4, 2, 3], state: "minecraft:air"},
|
||||
{pos: [4, 2, 4], state: "minecraft:air"},
|
||||
{pos: [0, 3, 0], state: "minecraft:air"},
|
||||
{pos: [0, 3, 1], state: "minecraft:air"},
|
||||
{pos: [0, 3, 2], state: "minecraft:air"},
|
||||
{pos: [0, 3, 3], state: "minecraft:air"},
|
||||
{pos: [0, 3, 4], state: "minecraft:air"},
|
||||
{pos: [1, 3, 0], state: "minecraft:air"},
|
||||
{pos: [1, 3, 1], state: "minecraft:air"},
|
||||
{pos: [1, 3, 2], state: "minecraft:air"},
|
||||
{pos: [1, 3, 3], state: "minecraft:air"},
|
||||
{pos: [1, 3, 4], state: "minecraft:air"},
|
||||
{pos: [2, 3, 0], state: "minecraft:air"},
|
||||
{pos: [2, 3, 1], state: "minecraft:air"},
|
||||
{pos: [2, 3, 2], state: "minecraft:air"},
|
||||
{pos: [2, 3, 3], state: "minecraft:air"},
|
||||
{pos: [2, 3, 4], state: "minecraft:air"},
|
||||
{pos: [3, 3, 0], state: "minecraft:air"},
|
||||
{pos: [3, 3, 1], state: "minecraft:air"},
|
||||
{pos: [3, 3, 2], state: "minecraft:air"},
|
||||
{pos: [3, 3, 3], state: "minecraft:air"},
|
||||
{pos: [3, 3, 4], state: "minecraft:air"},
|
||||
{pos: [4, 3, 0], state: "minecraft:air"},
|
||||
{pos: [4, 3, 1], state: "minecraft:air"},
|
||||
{pos: [4, 3, 2], state: "minecraft:air"},
|
||||
{pos: [4, 3, 3], state: "minecraft:air"},
|
||||
{pos: [4, 3, 4], state: "minecraft:air"},
|
||||
{pos: [0, 4, 0], state: "minecraft:air"},
|
||||
{pos: [0, 4, 1], state: "minecraft:air"},
|
||||
{pos: [0, 4, 2], state: "minecraft:air"},
|
||||
{pos: [0, 4, 3], state: "minecraft:air"},
|
||||
{pos: [0, 4, 4], state: "minecraft:air"},
|
||||
{pos: [1, 4, 0], state: "minecraft:air"},
|
||||
{pos: [1, 4, 1], state: "minecraft:air"},
|
||||
{pos: [1, 4, 2], state: "minecraft:air"},
|
||||
{pos: [1, 4, 3], state: "minecraft:air"},
|
||||
{pos: [1, 4, 4], state: "minecraft:air"},
|
||||
{pos: [2, 4, 0], state: "minecraft:air"},
|
||||
{pos: [2, 4, 1], state: "minecraft:air"},
|
||||
{pos: [2, 4, 2], state: "minecraft:air"},
|
||||
{pos: [2, 4, 3], state: "minecraft:air"},
|
||||
{pos: [2, 4, 4], state: "minecraft:air"},
|
||||
{pos: [3, 4, 0], state: "minecraft:air"},
|
||||
{pos: [3, 4, 1], state: "minecraft:air"},
|
||||
{pos: [3, 4, 2], state: "minecraft:air"},
|
||||
{pos: [3, 4, 3], state: "minecraft:air"},
|
||||
{pos: [3, 4, 4], state: "minecraft:air"},
|
||||
{pos: [4, 4, 0], state: "minecraft:air"},
|
||||
{pos: [4, 4, 1], state: "minecraft:air"},
|
||||
{pos: [4, 4, 2], state: "minecraft:air"},
|
||||
{pos: [4, 4, 3], state: "minecraft:air"},
|
||||
{pos: [4, 4, 4], state: "minecraft:air"}
|
||||
],
|
||||
entities: [],
|
||||
palette: [
|
||||
"minecraft:polished_andesite",
|
||||
"minecraft:air",
|
||||
"computercraft:speaker{facing:north}",
|
||||
"computercraft:computer_normal{facing:north,state:on}"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user