mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-12-14 12:10:30 +00:00
Merge branch 'mc-1.16.x' into mc-1.18.x
This commit is contained in:
commit
83a1af6526
17
build.gradle
17
build.gradle
@ -88,6 +88,23 @@ minecraft {
|
|||||||
args '--mod', 'computercraft', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
|
args '--mod', 'computercraft', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testClient {
|
||||||
|
workingDirectory project.file('test-files/client')
|
||||||
|
parent runs.client
|
||||||
|
|
||||||
|
mods {
|
||||||
|
cctest {
|
||||||
|
source sourceSets.testMod
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazyToken('minecraft_classpath') {
|
||||||
|
(configurations.shade.copyRecursive().resolve() + configurations.testModExtra.copyRecursive().resolve())
|
||||||
|
.collect { it.absolutePath }
|
||||||
|
.join(File.pathSeparator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gameTestServer {
|
gameTestServer {
|
||||||
workingDirectory project.file('test-files/server')
|
workingDirectory project.file('test-files/server')
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
package dan200.computercraft;
|
package dan200.computercraft;
|
||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI;
|
||||||
|
import dan200.computercraft.api.detail.IDetailProvider;
|
||||||
import dan200.computercraft.api.filesystem.IMount;
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||||
import dan200.computercraft.api.lua.GenericSource;
|
import dan200.computercraft.api.lua.GenericSource;
|
||||||
@ -24,6 +25,7 @@ import dan200.computercraft.shared.BundledRedstone;
|
|||||||
import dan200.computercraft.shared.MediaProviders;
|
import dan200.computercraft.shared.MediaProviders;
|
||||||
import dan200.computercraft.shared.Peripherals;
|
import dan200.computercraft.shared.Peripherals;
|
||||||
import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider;
|
import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider;
|
||||||
|
import dan200.computercraft.shared.peripheral.generic.data.DetailProviders;
|
||||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
|
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
|
||||||
import dan200.computercraft.shared.util.IDAssigner;
|
import dan200.computercraft.shared.util.IDAssigner;
|
||||||
import dan200.computercraft.shared.wired.WiredNode;
|
import dan200.computercraft.shared.wired.WiredNode;
|
||||||
@ -155,6 +157,12 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
|
|||||||
ApiFactories.register( factory );
|
ApiFactories.register( factory );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void registerDetailProvider( @Nonnull Class<T> type, @Nonnull IDetailProvider<T> provider )
|
||||||
|
{
|
||||||
|
DetailProviders.registerProvider( type, provider );
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element )
|
public IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element )
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
package dan200.computercraft.api;
|
package dan200.computercraft.api;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.detail.BlockReference;
|
||||||
|
import dan200.computercraft.api.detail.IDetailProvider;
|
||||||
import dan200.computercraft.api.filesystem.IMount;
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||||
import dan200.computercraft.api.lua.GenericSource;
|
import dan200.computercraft.api.lua.GenericSource;
|
||||||
@ -20,10 +22,12 @@ import dan200.computercraft.api.peripheral.IPeripheralProvider;
|
|||||||
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
|
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraftforge.common.capabilities.Capability;
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
import net.minecraftforge.common.util.LazyOptional;
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -196,6 +200,20 @@ public final class ComputerCraftAPI
|
|||||||
getInstance().registerAPIFactory( factory );
|
getInstance().registerAPIFactory( factory );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a detail provider to provide additional details for blocks, fluids and items when inspected by methods
|
||||||
|
* such as {@code turtle.getItemDetail()} or {@code turtle.inspect()}.
|
||||||
|
*
|
||||||
|
* @param type The type of object that this provider can provide details for. Should be {@link BlockReference},
|
||||||
|
* {@link FluidStack} or {@link ItemStack}.
|
||||||
|
* @param provider The detail provider to register.
|
||||||
|
* @param <T> The type of object that this provider can provide details for.
|
||||||
|
*/
|
||||||
|
public static <T> void registerDetailProvider( @Nonnull Class<T> type, @Nonnull IDetailProvider<T> provider )
|
||||||
|
{
|
||||||
|
getInstance().registerDetailProvider( type, provider );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new wired node for a given wired element.
|
* Construct a new wired node for a given wired element.
|
||||||
*
|
*
|
||||||
@ -272,6 +290,8 @@ public final class ComputerCraftAPI
|
|||||||
|
|
||||||
void registerAPIFactory( @Nonnull ILuaAPIFactory factory );
|
void registerAPIFactory( @Nonnull ILuaAPIFactory factory );
|
||||||
|
|
||||||
|
<T> void registerDetailProvider( @Nonnull Class<T> type, @Nonnull IDetailProvider<T> provider );
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element );
|
IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element );
|
||||||
|
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2022. This API may be redistributed unmodified and in full only.
|
||||||
|
* For help using the API, and posting your mods, visit the forums at computercraft.info.
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.api.detail;
|
||||||
|
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An item detail provider for {@link ItemStack}'s whose {@link Item} has a specific type.
|
||||||
|
*
|
||||||
|
* @param <T> The type the stack's item must have.
|
||||||
|
*/
|
||||||
|
public abstract class BasicItemDetailProvider<T> implements IDetailProvider<ItemStack>
|
||||||
|
{
|
||||||
|
private final Class<T> itemType;
|
||||||
|
private final String namespace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new item detail provider. Meta will be inserted into a new sub-map named as per {@code namespace}.
|
||||||
|
*
|
||||||
|
* @param itemType The type the stack's item must have.
|
||||||
|
* @param namespace The namespace to use for this provider.
|
||||||
|
*/
|
||||||
|
public BasicItemDetailProvider( String namespace, @Nonnull Class<T> itemType )
|
||||||
|
{
|
||||||
|
Objects.requireNonNull( itemType );
|
||||||
|
this.itemType = itemType;
|
||||||
|
this.namespace = namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new item detail provider. Meta will be inserted directly into the results.
|
||||||
|
*
|
||||||
|
* @param itemType The type the stack's item must have.
|
||||||
|
*/
|
||||||
|
public BasicItemDetailProvider( @Nonnull Class<T> itemType )
|
||||||
|
{
|
||||||
|
this( null, itemType );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide additional details for the given {@link Item} and {@link ItemStack}. This method is called by
|
||||||
|
* {@code turtle.getItemDetail()}. New properties should be added to the given {@link Map}, {@code data}.
|
||||||
|
*
|
||||||
|
* This method is always called on the server thread, so it is safe to interact with the world here, but you should
|
||||||
|
* take care to avoid long blocking operations as this will stall the server and other computers.
|
||||||
|
*
|
||||||
|
* @param data The full details to be returned for this item stack. New properties should be added to this map.
|
||||||
|
* @param stack The item stack to provide details for.
|
||||||
|
* @param item The item to provide details for.
|
||||||
|
*/
|
||||||
|
public abstract void provideDetails( @Nonnull Map<? super String, Object> data, @Nonnull ItemStack stack,
|
||||||
|
@Nonnull T item );
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void provideDetails( @Nonnull Map<? super String, Object> data, @Nonnull ItemStack stack )
|
||||||
|
{
|
||||||
|
Item item = stack.getItem();
|
||||||
|
if( !itemType.isInstance( item ) ) return;
|
||||||
|
|
||||||
|
// If `namespace` is specified, insert into a new data map instead of the existing one.
|
||||||
|
Map<? super String, Object> child = namespace == null ? data : new HashMap<>();
|
||||||
|
|
||||||
|
provideDetails( child, stack, itemType.cast( item ) );
|
||||||
|
|
||||||
|
if( namespace != null )
|
||||||
|
{
|
||||||
|
data.put( namespace, child );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2022. This API may be redistributed unmodified and in full only.
|
||||||
|
* For help using the API, and posting your mods, visit the forums at computercraft.info.
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.api.detail;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to a block in the world, used by block detail providers.
|
||||||
|
*
|
||||||
|
* @param level The level the block exists in.
|
||||||
|
* @param pos The position of the block.
|
||||||
|
* @param state The block state at this position.
|
||||||
|
* @param blockEntity The block entity at this position, if it exists.
|
||||||
|
*/
|
||||||
|
public record BlockReference(
|
||||||
|
@Nonnull Level level,
|
||||||
|
@Nonnull BlockPos pos,
|
||||||
|
@Nonnull BlockState state,
|
||||||
|
@Nullable BlockEntity blockEntity
|
||||||
|
)
|
||||||
|
{
|
||||||
|
public BlockReference( Level level, BlockPos pos )
|
||||||
|
{
|
||||||
|
this( level, pos, level.getBlockState( pos ), level.getBlockEntity( pos ) );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2022. This API may be redistributed unmodified and in full only.
|
||||||
|
* For help using the API, and posting your mods, visit the forums at computercraft.info.
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.api.detail;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface is used to provide details about a block, fluid, or item.
|
||||||
|
*
|
||||||
|
* @param <T> The type of object that this provider can provide details for.
|
||||||
|
* @see dan200.computercraft.api.ComputerCraftAPI#registerDetailProvider(Class, IDetailProvider)
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface IDetailProvider<T>
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Provide additional details for the given object. This method is called by functions such as
|
||||||
|
* {@code turtle.getItemDetail()} and {@code turtle.inspect()}. New properties should be added to the given
|
||||||
|
* {@link Map}, {@code data}.
|
||||||
|
*
|
||||||
|
* This method is always called on the server thread, so it is safe to interact with the world here, but you should
|
||||||
|
* take care to avoid long blocking operations as this will stall the server and other computers.
|
||||||
|
*
|
||||||
|
* @param data The full details to be returned. New properties should be added to this map.
|
||||||
|
* @param object The object to provide details for.
|
||||||
|
*/
|
||||||
|
void provideDetails( @Nonnull Map<? super String, Object> data, @Nonnull T object );
|
||||||
|
}
|
@ -58,7 +58,7 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
|
|||||||
protected abstract WidgetTerminal createTerminal();
|
protected abstract WidgetTerminal createTerminal();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final void init()
|
protected void init()
|
||||||
{
|
{
|
||||||
super.init();
|
super.init();
|
||||||
minecraft.keyboardHandler.setSendRepeatsToGui( true );
|
minecraft.keyboardHandler.setSendRepeatsToGui( true );
|
||||||
@ -69,21 +69,21 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void removed()
|
public void removed()
|
||||||
{
|
{
|
||||||
super.removed();
|
super.removed();
|
||||||
minecraft.keyboardHandler.setSendRepeatsToGui( false );
|
minecraft.keyboardHandler.setSendRepeatsToGui( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void containerTick()
|
public void containerTick()
|
||||||
{
|
{
|
||||||
super.containerTick();
|
super.containerTick();
|
||||||
terminal.update();
|
terminal.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean keyPressed( int key, int scancode, int modifiers )
|
public boolean keyPressed( int key, int scancode, int modifiers )
|
||||||
{
|
{
|
||||||
// Forward the tab key to the terminal, rather than moving between controls.
|
// Forward the tab key to the terminal, rather than moving between controls.
|
||||||
if( key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal )
|
if( key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal )
|
||||||
@ -96,7 +96,7 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void render( @Nonnull PoseStack stack, int mouseX, int mouseY, float partialTicks )
|
public void render( @Nonnull PoseStack stack, int mouseX, int mouseY, float partialTicks )
|
||||||
{
|
{
|
||||||
renderBackground( stack );
|
renderBackground( stack );
|
||||||
super.render( stack, mouseX, mouseY, partialTicks );
|
super.render( stack, mouseX, mouseY, partialTicks );
|
||||||
@ -114,7 +114,7 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY )
|
public boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY )
|
||||||
{
|
{
|
||||||
return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY ))
|
return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY ))
|
||||||
|| super.mouseDragged( x, y, button, deltaX, deltaY );
|
|| super.mouseDragged( x, y, button, deltaX, deltaY );
|
||||||
|
@ -6,7 +6,10 @@
|
|||||||
package dan200.computercraft.core.lua;
|
package dan200.computercraft.core.lua;
|
||||||
|
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
import dan200.computercraft.api.lua.*;
|
import dan200.computercraft.api.lua.IDynamicLuaObject;
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
|
import dan200.computercraft.api.lua.ILuaFunction;
|
||||||
import dan200.computercraft.core.asm.LuaMethod;
|
import dan200.computercraft.core.asm.LuaMethod;
|
||||||
import dan200.computercraft.core.asm.ObjectSource;
|
import dan200.computercraft.core.asm.ObjectSource;
|
||||||
import dan200.computercraft.core.computer.Computer;
|
import dan200.computercraft.core.computer.Computer;
|
||||||
@ -14,7 +17,6 @@ import dan200.computercraft.core.computer.TimeoutState;
|
|||||||
import dan200.computercraft.core.tracking.Tracking;
|
import dan200.computercraft.core.tracking.Tracking;
|
||||||
import dan200.computercraft.core.tracking.TrackingField;
|
import dan200.computercraft.core.tracking.TrackingField;
|
||||||
import dan200.computercraft.shared.util.ThreadUtils;
|
import dan200.computercraft.shared.util.ThreadUtils;
|
||||||
import org.squiddev.cobalt.LuaTable;
|
|
||||||
import org.squiddev.cobalt.*;
|
import org.squiddev.cobalt.*;
|
||||||
import org.squiddev.cobalt.compiler.CompileException;
|
import org.squiddev.cobalt.compiler.CompileException;
|
||||||
import org.squiddev.cobalt.compiler.LoadState;
|
import org.squiddev.cobalt.compiler.LoadState;
|
||||||
|
@ -6,7 +6,10 @@
|
|||||||
package dan200.computercraft.core.lua;
|
package dan200.computercraft.core.lua;
|
||||||
|
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
import dan200.computercraft.api.lua.*;
|
import dan200.computercraft.api.lua.ILuaCallback;
|
||||||
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
|
import dan200.computercraft.api.lua.MethodResult;
|
||||||
import dan200.computercraft.core.asm.LuaMethod;
|
import dan200.computercraft.core.asm.LuaMethod;
|
||||||
import org.squiddev.cobalt.*;
|
import org.squiddev.cobalt.*;
|
||||||
import org.squiddev.cobalt.debug.DebugFrame;
|
import org.squiddev.cobalt.debug.DebugFrame;
|
||||||
|
@ -8,6 +8,7 @@ package dan200.computercraft.shared.computer.apis;
|
|||||||
import com.mojang.brigadier.tree.CommandNode;
|
import com.mojang.brigadier.tree.CommandNode;
|
||||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.api.detail.BlockReference;
|
||||||
import dan200.computercraft.api.lua.*;
|
import dan200.computercraft.api.lua.*;
|
||||||
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
|
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
|
||||||
import dan200.computercraft.shared.peripheral.generic.data.BlockData;
|
import dan200.computercraft.shared.peripheral.generic.data.BlockData;
|
||||||
@ -21,7 +22,6 @@ import net.minecraft.resources.ResourceLocation;
|
|||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -76,10 +76,10 @@ public class CommandAPI implements ILuaAPI
|
|||||||
private static Map<?, ?> getBlockInfo( Level world, BlockPos pos )
|
private static Map<?, ?> getBlockInfo( Level world, BlockPos pos )
|
||||||
{
|
{
|
||||||
// Get the details of the block
|
// Get the details of the block
|
||||||
BlockState state = world.getBlockState( pos );
|
BlockReference block = new BlockReference( world, pos );
|
||||||
Map<String, Object> table = BlockData.fill( new HashMap<>(), state );
|
Map<String, Object> table = BlockData.fill( new HashMap<>(), block );
|
||||||
|
|
||||||
BlockEntity tile = world.getBlockEntity( pos );
|
BlockEntity tile = block.blockEntity();
|
||||||
if( tile != null ) table.put( "nbt", NBTUtil.toLua( tile.saveWithFullMetadata() ) );
|
if( tile != null ) table.put( "nbt", NBTUtil.toLua( tile.saveWithFullMetadata() ) );
|
||||||
|
|
||||||
return table;
|
return table;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.peripheral.generic.data;
|
package dan200.computercraft.shared.peripheral.generic.data;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.detail.BlockReference;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.block.state.properties.Property;
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
|
|
||||||
@ -15,8 +16,10 @@ import java.util.Map;
|
|||||||
public class BlockData
|
public class BlockData
|
||||||
{
|
{
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public static <T extends Map<? super String, Object>> T fill( @Nonnull T data, @Nonnull BlockState state )
|
public static <T extends Map<? super String, Object>> T fill( @Nonnull T data, @Nonnull BlockReference block )
|
||||||
{
|
{
|
||||||
|
BlockState state = block.state();
|
||||||
|
|
||||||
data.put( "name", DataHelpers.getId( state.getBlock() ) );
|
data.put( "name", DataHelpers.getId( state.getBlock() ) );
|
||||||
|
|
||||||
Map<Object, Object> stateTable = new HashMap<>();
|
Map<Object, Object> stateTable = new HashMap<>();
|
||||||
@ -28,6 +31,8 @@ public class BlockData
|
|||||||
data.put( "state", stateTable );
|
data.put( "state", stateTable );
|
||||||
data.put( "tags", DataHelpers.getTags( state.getTags() ) );
|
data.put( "tags", DataHelpers.getTags( state.getTags() ) );
|
||||||
|
|
||||||
|
DetailProviders.fillData( BlockReference.class, data, block );
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.shared.peripheral.generic.data;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.detail.BlockReference;
|
||||||
|
import dan200.computercraft.api.detail.IDetailProvider;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public final class DetailProviders
|
||||||
|
{
|
||||||
|
private static final Map<Class<?>, Collection<IDetailProvider<?>>> allProviders = new HashMap<>();
|
||||||
|
|
||||||
|
public static synchronized <T> void registerProvider( Class<T> type, IDetailProvider<T> provider )
|
||||||
|
{
|
||||||
|
Objects.requireNonNull( type, "type cannot be null" );
|
||||||
|
Objects.requireNonNull( provider, "provider cannot be null" );
|
||||||
|
|
||||||
|
if( type != BlockReference.class && type != ItemStack.class && type != FluidStack.class )
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException( "type must be assignable from BlockReference, ItemStack or FluidStack" );
|
||||||
|
}
|
||||||
|
|
||||||
|
allProviders.computeIfAbsent( type, k -> new LinkedHashSet<>() ).add( provider );
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings( "unchecked" )
|
||||||
|
public static <T> void fillData( Class<T> type, Map<? super String, Object> data, T value )
|
||||||
|
{
|
||||||
|
Collection<IDetailProvider<T>> providers = (Collection<IDetailProvider<T>>) (Object) allProviders.get( type );
|
||||||
|
if( providers == null ) return;
|
||||||
|
|
||||||
|
for( IDetailProvider<T> provider : providers )
|
||||||
|
{
|
||||||
|
provider.provideDetails( data, value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,10 +24,13 @@ public class FluidData
|
|||||||
public static <T extends Map<? super String, Object>> T fill( @Nonnull T data, @Nonnull FluidStack stack )
|
public static <T extends Map<? super String, Object>> T fill( @Nonnull T data, @Nonnull FluidStack stack )
|
||||||
{
|
{
|
||||||
fillBasic( data, stack );
|
fillBasic( data, stack );
|
||||||
|
|
||||||
// FluidStack doesn't have a getTags method, so we need to use the deprecated builtInRegistryHolder.
|
// FluidStack doesn't have a getTags method, so we need to use the deprecated builtInRegistryHolder.
|
||||||
@SuppressWarnings( "deprecation" )
|
@SuppressWarnings( "deprecation" )
|
||||||
var holder = stack.getFluid().builtInRegistryHolder();
|
var holder = stack.getFluid().builtInRegistryHolder();
|
||||||
data.put( "tags", DataHelpers.getTags( holder ) );
|
data.put( "tags", DataHelpers.getTags( holder ) );
|
||||||
|
|
||||||
|
DetailProviders.fillData( FluidStack.class, data, stack );
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,8 @@ public class ItemData
|
|||||||
data.put( "unbreakable", true );
|
data.put( "unbreakable", true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DetailProviders.fillData( ItemStack.class, data, stack );
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ package dan200.computercraft.shared.peripheral.printer;
|
|||||||
|
|
||||||
import dan200.computercraft.shared.Registry;
|
import dan200.computercraft.shared.Registry;
|
||||||
import dan200.computercraft.shared.util.SingleIntArray;
|
import dan200.computercraft.shared.util.SingleIntArray;
|
||||||
|
import dan200.computercraft.shared.util.ValidatingSlot;
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
import net.minecraft.world.SimpleContainer;
|
import net.minecraft.world.SimpleContainer;
|
||||||
import net.minecraft.world.entity.player.Inventory;
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
@ -33,13 +34,16 @@ public class ContainerPrinter extends AbstractContainerMenu
|
|||||||
addDataSlots( properties );
|
addDataSlots( properties );
|
||||||
|
|
||||||
// Ink slot
|
// Ink slot
|
||||||
addSlot( new Slot( inventory, 0, 13, 35 ) );
|
addSlot( new ValidatingSlot( inventory, 0, 13, 35, TilePrinter::isInk ) );
|
||||||
|
|
||||||
// In-tray
|
// In-tray
|
||||||
for( int x = 0; x < 6; x++ ) addSlot( new Slot( inventory, x + 1, 61 + x * 18, 22 ) );
|
for( int x = 0; x < 6; x++ )
|
||||||
|
{
|
||||||
|
addSlot( new ValidatingSlot( inventory, x + 1, 61 + x * 18, 22, TilePrinter::isPaper ) );
|
||||||
|
}
|
||||||
|
|
||||||
// Out-tray
|
// Out-tray
|
||||||
for( int x = 0; x < 6; x++ ) addSlot( new Slot( inventory, x + 7, 61 + x * 18, 49 ) );
|
for( int x = 0; x < 6; x++ ) addSlot( new ValidatingSlot( inventory, x + 7, 61 + x * 18, 49, o -> false ) );
|
||||||
|
|
||||||
// Player inv
|
// Player inv
|
||||||
for( int y = 0; y < 3; y++ )
|
for( int y = 0; y < 3; y++ )
|
||||||
|
@ -308,7 +308,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
|
|||||||
return ColourUtils.getStackColour( stack ) != null;
|
return ColourUtils.getStackColour( stack ) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isPaper( @Nonnull ItemStack stack )
|
static boolean isPaper( @Nonnull ItemStack stack )
|
||||||
{
|
{
|
||||||
Item item = stack.getItem();
|
Item item = stack.getItem();
|
||||||
return item == Items.PAPER
|
return item == Items.PAPER
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.turtle.core;
|
package dan200.computercraft.shared.turtle.core;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.detail.BlockReference;
|
||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
import dan200.computercraft.api.turtle.ITurtleCommand;
|
import dan200.computercraft.api.turtle.ITurtleCommand;
|
||||||
import dan200.computercraft.api.turtle.TurtleCommandResult;
|
import dan200.computercraft.api.turtle.TurtleCommandResult;
|
||||||
@ -12,7 +13,6 @@ import dan200.computercraft.shared.peripheral.generic.data.BlockData;
|
|||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -39,10 +39,10 @@ public class TurtleInspectCommand implements ITurtleCommand
|
|||||||
BlockPos oldPosition = turtle.getPosition();
|
BlockPos oldPosition = turtle.getPosition();
|
||||||
BlockPos newPosition = oldPosition.relative( direction );
|
BlockPos newPosition = oldPosition.relative( direction );
|
||||||
|
|
||||||
BlockState state = world.getBlockState( newPosition );
|
BlockReference block = new BlockReference( world, newPosition );
|
||||||
if( state.isAir() ) return TurtleCommandResult.failure( "No block to inspect" );
|
if( block.state().isAir() ) return TurtleCommandResult.failure( "No block to inspect" );
|
||||||
|
|
||||||
Map<String, Object> table = BlockData.fill( new HashMap<>(), state );
|
Map<String, Object> table = BlockData.fill( new HashMap<>(), block );
|
||||||
|
|
||||||
return TurtleCommandResult.success( new Object[] { table } );
|
return TurtleCommandResult.success( new Object[] { table } );
|
||||||
|
|
||||||
|
@ -10,17 +10,21 @@ import net.minecraft.world.inventory.Slot;
|
|||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class ValidatingSlot extends Slot
|
public class ValidatingSlot extends Slot
|
||||||
{
|
{
|
||||||
public ValidatingSlot( Container inventoryIn, int index, int xPosition, int yPosition )
|
private final Predicate<ItemStack> predicate;
|
||||||
|
|
||||||
|
public ValidatingSlot( Container inventoryIn, int index, int xPosition, int yPosition, Predicate<ItemStack> predicate )
|
||||||
{
|
{
|
||||||
super( inventoryIn, index, xPosition, yPosition );
|
super( inventoryIn, index, xPosition, yPosition );
|
||||||
|
this.predicate = predicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mayPlace( @Nonnull ItemStack stack )
|
public boolean mayPlace( @Nonnull ItemStack stack )
|
||||||
{
|
{
|
||||||
return true; // inventory.isItemValidForSlot( slotNumber, stack );
|
return predicate.test( stack );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ class AsyncRunner : NullApiEnvironment() {
|
|||||||
private val empty: Array<Any?> = arrayOf()
|
private val empty: Array<Any?> = arrayOf()
|
||||||
|
|
||||||
@OptIn(ExperimentalTime::class)
|
@OptIn(ExperimentalTime::class)
|
||||||
fun runTest(timeout: Duration = Duration.seconds(5), fn: suspend AsyncRunner.() -> Unit) {
|
fun runTest(timeout: Duration = 5.seconds, fn: suspend AsyncRunner.() -> Unit) {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val runner = AsyncRunner()
|
val runner = AsyncRunner()
|
||||||
try {
|
try {
|
||||||
|
@ -85,7 +85,7 @@ public class ComputerThreadTest
|
|||||||
assertEquals( budget, TimeUnit.MILLISECONDS.toNanos( 25 ), "Budget should be 25ms" );
|
assertEquals( budget, TimeUnit.MILLISECONDS.toNanos( 25 ), "Budget should be 25ms" );
|
||||||
|
|
||||||
long delay = ConcurrentHelpers.waitUntil( timeout::isPaused );
|
long delay = ConcurrentHelpers.waitUntil( timeout::isPaused );
|
||||||
assertThat( "Paused within 25ms", delay * 1e-9, closeTo( 0.03, 0.015 ) );
|
assertThat( "Paused within 25ms", delay * 1e-9, closeTo( 0.03, 0.02 ) );
|
||||||
|
|
||||||
computer.shutdown();
|
computer.shutdown();
|
||||||
return MachineResult.OK;
|
return MachineResult.OK;
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package dan200.computercraft.ingame
|
package dan200.computercraft.ingame
|
||||||
|
|
||||||
import dan200.computercraft.ComputerCraft
|
import dan200.computercraft.ComputerCraft
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI
|
||||||
|
import dan200.computercraft.api.detail.BasicItemDetailProvider
|
||||||
import dan200.computercraft.ingame.api.Timeouts.COMPUTER_TIMEOUT
|
import dan200.computercraft.ingame.api.Timeouts.COMPUTER_TIMEOUT
|
||||||
import dan200.computercraft.ingame.api.sequence
|
import dan200.computercraft.ingame.api.sequence
|
||||||
import dan200.computercraft.ingame.api.thenComputerOk
|
import dan200.computercraft.ingame.api.thenComputerOk
|
||||||
|
import dan200.computercraft.shared.media.items.ItemPrintout
|
||||||
import net.minecraft.gametest.framework.GameTest
|
import net.minecraft.gametest.framework.GameTest
|
||||||
import net.minecraft.gametest.framework.GameTestHelper
|
import net.minecraft.gametest.framework.GameTestHelper
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraftforge.gametest.GameTestHolder
|
import net.minecraftforge.gametest.GameTestHolder
|
||||||
|
|
||||||
@GameTestHolder(ComputerCraft.MOD_ID)
|
@GameTestHolder(ComputerCraft.MOD_ID)
|
||||||
@ -75,4 +79,25 @@ class Turtle_Test {
|
|||||||
*/
|
*/
|
||||||
@GameTest(required = false)
|
@GameTest(required = false)
|
||||||
fun Cleaned_with_cauldrons(helper: GameTestHelper) = helper.sequence { thenComputerOk() }
|
fun Cleaned_with_cauldrons(helper: GameTestHelper) = helper.sequence { thenComputerOk() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks turtles can use IDetailProviders by getting details for a printed page.
|
||||||
|
*/
|
||||||
|
@GameTest(timeoutTicks = COMPUTER_TIMEOUT)
|
||||||
|
fun Item_detail_provider(helper: GameTestHelper) = helper.sequence {
|
||||||
|
this
|
||||||
|
.thenComputerOk(marker = "initial")
|
||||||
|
.thenExecute {
|
||||||
|
// Register a dummy provider for printout items
|
||||||
|
ComputerCraftAPI.registerDetailProvider(
|
||||||
|
ItemStack::class.java,
|
||||||
|
object : BasicItemDetailProvider<ItemPrintout>("printout", ItemPrintout::class.java) {
|
||||||
|
override fun provideDetails(data: MutableMap<in String, Any>, stack: ItemStack, item: ItemPrintout) {
|
||||||
|
data["type"] = item.type.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.thenComputerOk()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,9 +29,11 @@ object Times {
|
|||||||
* Custom timeouts for various test types.
|
* Custom timeouts for various test types.
|
||||||
*/
|
*/
|
||||||
object Timeouts {
|
object Timeouts {
|
||||||
const val COMPUTER_TIMEOUT: Int = 200
|
private const val SECOND: Int = 20
|
||||||
|
|
||||||
const val CLIENT_TIMEOUT: Int = 400
|
const val COMPUTER_TIMEOUT: Int = SECOND * 15
|
||||||
|
|
||||||
|
const val CLIENT_TIMEOUT: Int = SECOND * 20
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
package dan200.computercraft.ingame.mod;
|
package dan200.computercraft.ingame.mod;
|
||||||
|
|
||||||
import com.google.common.io.MoreFiles;
|
import com.google.common.io.MoreFiles;
|
||||||
|
import com.google.common.io.RecursiveDeleteOption;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.FileVisitResult;
|
import java.nio.file.FileVisitResult;
|
||||||
@ -55,7 +56,7 @@ final class Copier extends SimpleFileVisitor<Path>
|
|||||||
|
|
||||||
public static void replicate( Path from, Path to, Predicate<Path> check ) throws IOException
|
public static void replicate( Path from, Path to, Predicate<Path> check ) throws IOException
|
||||||
{
|
{
|
||||||
if( Files.exists( to ) ) MoreFiles.deleteRecursively( to );
|
if( Files.exists( to ) ) MoreFiles.deleteRecursively( to, RecursiveDeleteOption.ALLOW_INSECURE );
|
||||||
Files.walkFileTree( from, new Copier( from, to, check ) );
|
Files.walkFileTree( from, new Copier( from, to, check ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,14 @@ if label == nil then return test.fail("Label a computer to use it.") end
|
|||||||
local fn, err = loadfile("tests/" .. label .. ".lua", nil, _ENV)
|
local fn, err = loadfile("tests/" .. label .. ".lua", nil, _ENV)
|
||||||
if not fn then return test.fail(err) end
|
if not fn then return test.fail(err) end
|
||||||
|
|
||||||
|
local source = "@" .. label .. ".lua"
|
||||||
|
debug.sethook(function()
|
||||||
|
local i = debug.getinfo(2, "lS")
|
||||||
|
if i.source == source and i.currentline then
|
||||||
|
test.log("At line " .. i.currentline)
|
||||||
|
end
|
||||||
|
end, "l")
|
||||||
|
|
||||||
local ok, err = pcall(fn)
|
local ok, err = pcall(fn)
|
||||||
if not ok then return test.fail(err) end
|
if not ok then return test.fail(err) end
|
||||||
|
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
test.ok("initial")
|
||||||
|
|
||||||
|
local details = turtle.getItemDetail(1, true)
|
||||||
|
|
||||||
|
test.assert(details, "Has details")
|
||||||
|
test.assert(details.printout, "Has printout meta")
|
||||||
|
test.eq("PAGE", details.printout.type)
|
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
DataVersion: 2975,
|
||||||
|
size: [3, 3, 3],
|
||||||
|
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: [1, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 2], 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: [0, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 0], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 0, Fuel: 0, Items: [{Count: 1b, Slot: 0b, id: "computercraft:printed_page", tag: {Color0: "fffffffffffffffffffffffff", Color1: "fffffffffffffffffffffffff", Color10: "fffffffffffffffffffffffff", Color11: "fffffffffffffffffffffffff", Color12: "fffffffffffffffffffffffff", Color13: "fffffffffffffffffffffffff", Color14: "fffffffffffffffffffffffff", Color15: "fffffffffffffffffffffffff", Color16: "fffffffffffffffffffffffff", Color17: "fffffffffffffffffffffffff", Color18: "fffffffffffffffffffffffff", Color19: "fffffffffffffffffffffffff", Color2: "fffffffffffffffffffffffff", Color20: "fffffffffffffffffffffffff", Color3: "fffffffffffffffffffffffff", Color4: "fffffffffffffffffffffffff", Color5: "fffffffffffffffffffffffff", Color6: "fffffffffffffffffffffffff", Color7: "fffffffffffffffffffffffff", Color8: "fffffffffffffffffffffffff", Color9: "fffffffffffffffffffffffff", Pages: 1, Text0: "Example ", Text1: " ", Text10: " ", Text11: " ", Text12: " ", Text13: " ", Text14: " ", Text15: " ", Text16: " ", Text17: " ", Text18: " ", Text19: " ", Text2: " ", Text20: " ", Text3: " ", Text4: " ", Text5: " ", Text6: " ", Text7: " ", Text8: " ", Text9: " ", Title: "Example page"}}], Label: "turtle_test.item_detail_provider", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}},
|
||||||
|
{pos: [1, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 2], 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: [1, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 2], state: "minecraft:air"}
|
||||||
|
],
|
||||||
|
entities: [],
|
||||||
|
palette: [
|
||||||
|
"minecraft:polished_andesite",
|
||||||
|
"minecraft:air",
|
||||||
|
"computercraft:turtle_normal{facing:south,waterlogged:false}"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user