1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-08-28 16:22:18 +00:00

Merge pull request #38 from Jummit/port-10

Port all recent commits
This commit is contained in:
Merith 2021-06-03 07:58:58 -07:00 committed by GitHub
commit 01d7aaf062
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 402 additions and 264 deletions

View File

@ -50,7 +50,7 @@ dependencies {
compile 'javax.vecmath:vecmath:1.5.2'
shade 'org.squiddev:Cobalt:0.5.1-SNAPSHOT'
shade 'org.squiddev:Cobalt:0.5.2-SNAPSHOT'
modRuntime "me.shedaniel:RoughlyEnoughItems-api:5.8.9"
modRuntime "me.shedaniel:RoughlyEnoughItems:5.8.9"

View File

@ -2,7 +2,7 @@
org.gradle.jvmargs=-Xmx1G
# Mod properties
mod_version=1.95.3-beta
mod_version=1.96.0-beta
# Minecraft properties
mc_version=1.16.5

View File

@ -21,7 +21,6 @@ import dan200.computercraft.api.turtle.event.TurtleAction;
import dan200.computercraft.core.apis.http.options.Action;
import dan200.computercraft.core.apis.http.options.AddressRule;
import dan200.computercraft.core.apis.http.websocket.Websocket;
import dan200.computercraft.core.asm.GenericSource;
import dan200.computercraft.shared.common.ColourableRecipe;
import dan200.computercraft.shared.computer.core.ClientComputerRegistry;
import dan200.computercraft.shared.computer.core.ServerComputerRegistry;
@ -39,7 +38,6 @@ import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
import dan200.computercraft.shared.util.Config;
import dan200.computercraft.shared.util.ImpostorRecipe;
import dan200.computercraft.shared.util.ImpostorShapelessRecipe;
import dan200.computercraft.shared.util.ServiceUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -132,7 +130,6 @@ public final class ComputerCraft implements ModInitializer {
Registry.register(Registry.LOOT_CONDITION_TYPE, new Identifier(ComputerCraft.MOD_ID, "player_creative"), PlayerCreativeLootCondition.TYPE);
Registry.register(Registry.LOOT_CONDITION_TYPE, new Identifier(ComputerCraft.MOD_ID, "has_id"), HasComputerIdLootCondition.TYPE);
init();
GenericSource.setup( () -> ServiceUtil.loadServices( GenericSource.class ));
FabricLoader.getInstance().getModContainer(MOD_ID).ifPresent(modContainer -> {
ResourceManagerHelper.registerBuiltinResourcePack(new Identifier(MOD_ID, "classic"), modContainer, ResourcePackActivationType.NORMAL);
ResourceManagerHelper.registerBuiltinResourcePack(new Identifier(MOD_ID, "overhaul"), modContainer, ResourcePackActivationType.NORMAL);

View File

@ -16,6 +16,7 @@ import javax.annotation.Nullable;
import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.GenericSource;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.media.IMediaProvider;
import dan200.computercraft.api.network.IPacketNetwork;
@ -26,6 +27,7 @@ import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.core.apis.ApiFactories;
import dan200.computercraft.core.asm.GenericMethod;
import dan200.computercraft.core.filesystem.FileMount;
import dan200.computercraft.core.filesystem.ResourceMount;
import dan200.computercraft.mixin.MinecraftServerAccess;
@ -143,6 +145,12 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI {
PocketUpgrades.register(upgrade);
}
@Override
public void registerGenericSource( @Nonnull GenericSource source )
{
GenericMethod.register( source );
}
@Nonnull
@Override
public IPacketNetwork getWirelessNetwork() {

View File

@ -11,6 +11,7 @@ import javax.annotation.Nullable;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.GenericSource;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.media.IMediaProvider;
@ -136,6 +137,17 @@ public final class ComputerCraftAPI {
getInstance().registerPeripheralProvider(provider);
}
/**
* Registers a method source for generic peripherals.
*
* @param source The method source to register.
* @see GenericSource
*/
public static void registerGenericSource( @Nonnull GenericSource source )
{
getInstance().registerGenericSource( source );
}
/**
* Registers a new turtle turtle for use in ComputerCraft. After calling this, users should be able to craft Turtles with your new turtle. It is
* recommended to call this during the load() method of your mod.
@ -238,6 +250,8 @@ public final class ComputerCraftAPI {
void registerPeripheralProvider(@Nonnull IPeripheralProvider provider);
void registerGenericSource( @Nonnull GenericSource source );
void registerTurtleUpgrade(@Nonnull ITurtleUpgrade upgrade);
void registerBundledRedstoneProvider(@Nonnull IBundledRedstoneProvider provider);

View File

@ -0,0 +1,58 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. 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.lua;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralProvider;
import dan200.computercraft.core.asm.LuaMethod;
import net.minecraft.util.Identifier;
import javax.annotation.Nonnull;
/**
* A generic source of {@link LuaMethod} functions.
*
* Unlike normal objects ({@link IDynamicLuaObject} or {@link IPeripheral}), methods do not target this object but
* instead are defined as {@code static} and accept their target as the first parameter. This allows you to inject
* methods onto objects you do not own, as well as declaring methods for a specific "trait" (for instance, a
* {@link Capability}).
*
* Currently the "generic peripheral" system is incompatible with normal peripherals. Normal {@link IPeripheralProvider}
* or {@link IPeripheral} implementations take priority. Tile entities which use this system are given a peripheral name
* determined by their id, rather than any peripheral provider. This will hopefully change in the future, once a suitable
* design has been established.
*
* For example, the main CC: Tweaked mod defines a generic source for inventories, which works on {@link IItemHandler}s:
*
* <pre>{@code
* public class InventoryMethods implements GenericSource {
* \@LuaFunction( mainThread = true )
* public static int size(IItemHandler inventory) {
* return inventory.getSlots();
* }
*
* // ...
* }
* }</pre>
*
* @see ComputerCraftAPI#registerGenericSource(GenericSource)
* @see ComputerCraftAPI#registerGenericCapability(Capability) New capabilities (those not built into Forge) must be
* explicitly given to the generic peripheral system, as there is no way to enumerate all capabilities.
*/
public interface GenericSource
{
/**
* A unique identifier for this generic source.
*
* This is currently unused, but may be used in the future to allow disabling specific sources. It is recommended
* to return an identifier using your mod's ID.
*
* @return This source's identifier.
*/
@Nonnull
Identifier id();
}

View File

@ -38,7 +38,10 @@ public class ComputerBorderRenderer {
private static final int CORNER_LEFT_X = BORDER;
private static final int CORNER_RIGHT_X = CORNER_LEFT_X + BORDER;
private static final int BORDER_RIGHT_X = 36;
private static final int GAP = 4;
private static final int LIGHT_BORDER_Y = 56;
private static final int LIGHT_CORNER_Y = 80;
public static final int LIGHT_HEIGHT = 8;
private static final float TEX_SCALE = 1 / 256.0f;
static {
@ -89,15 +92,16 @@ public class ComputerBorderRenderer {
}
public static void render(Matrix4f transform, VertexConsumer buffer, int x, int y, int z, int width, int height, float r, float g, float b) {
render(transform, buffer, x, y, z, width, height, 0, r, g, b);
render( transform, buffer, x, y, z, width, height, false, r, g, b );
}
public static void render(Matrix4f transform, VertexConsumer buffer, int x, int y, int z, int width, int height, int borderHeight, float r, float g,
float b) {
new ComputerBorderRenderer(transform, buffer, z, r, g, b).doRender(x, y, width, height, borderHeight);
public static void render( Matrix4f transform, VertexConsumer buffer, int x, int y, int z, int width, int height, boolean withLight, float r, float g, float b )
{
new ComputerBorderRenderer( transform, buffer, z, r, g, b ).doRender( x, y, width, height, withLight );
}
public void doRender(int x, int y, int width, int height, int bottomHeight) {
public void doRender( int x, int y, int width, int height, boolean withLight )
{
int endX = x + width;
int endY = y + height;
@ -112,24 +116,17 @@ public class ComputerBorderRenderer {
// Bottom bar. We allow for drawing a stretched version, which allows for additional elements (such as the
// pocket computer's lights).
if (bottomHeight <= 0) {
if( withLight )
{
renderTexture( x, endY, 0, LIGHT_BORDER_Y, endX - x, BORDER + LIGHT_HEIGHT, BORDER, BORDER + LIGHT_HEIGHT );
renderTexture( x - BORDER, endY, CORNER_LEFT_X, LIGHT_CORNER_Y, BORDER, BORDER + LIGHT_HEIGHT );
renderTexture( endX, endY, CORNER_RIGHT_X, LIGHT_CORNER_Y, BORDER, BORDER + LIGHT_HEIGHT );
}
else
{
this.renderLine(x, endY, 0, BORDER, endX - x, BORDER);
this.renderCorner(x - BORDER, endY, CORNER_LEFT_X, CORNER_BOTTOM_Y);
this.renderCorner(endX, endY, CORNER_RIGHT_X, CORNER_BOTTOM_Y);
} else {
// Bottom left, middle, right. We do this in three portions: the top inner corners, an extended region for
// lights, and then the bottom outer corners.
this.renderTexture(x - BORDER, endY, CORNER_LEFT_X, CORNER_BOTTOM_Y, BORDER, BORDER / 2);
this.renderTexture(x, endY, 0, BORDER, width, BORDER / 2, BORDER, BORDER / 2);
this.renderTexture(endX, endY, CORNER_RIGHT_X, CORNER_BOTTOM_Y, BORDER, BORDER / 2);
this.renderTexture(x - BORDER, endY + BORDER / 2, CORNER_LEFT_X, CORNER_BOTTOM_Y + GAP, BORDER, bottomHeight, BORDER, GAP);
this.renderTexture(x, endY + BORDER / 2, 0, BORDER + GAP, width, bottomHeight, BORDER, GAP);
this.renderTexture(endX, endY + BORDER / 2, CORNER_RIGHT_X, CORNER_BOTTOM_Y + GAP, BORDER, bottomHeight, BORDER, GAP);
this.renderTexture(x - BORDER, endY + bottomHeight + BORDER / 2, CORNER_LEFT_X, CORNER_BOTTOM_Y + BORDER / 2, BORDER, BORDER / 2);
this.renderTexture(x, endY + bottomHeight + BORDER / 2, 0, BORDER + BORDER / 2, width, BORDER / 2);
this.renderTexture(endX, endY + bottomHeight + BORDER / 2, CORNER_RIGHT_X, CORNER_BOTTOM_Y + BORDER / 2, BORDER, BORDER / 2);
}
}

View File

@ -6,6 +6,7 @@
package dan200.computercraft.client.render;
import static dan200.computercraft.client.render.ComputerBorderRenderer.*;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
@ -31,12 +32,13 @@ import net.minecraft.client.util.math.Vector3f;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.Matrix4f;
import static dan200.computercraft.client.render.ComputerBorderRenderer.*;
/**
* Emulates map rendering for pocket computers.
*/
public final class ItemPocketRenderer extends ItemMapLikeRenderer {
public static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer();
private static final int LIGHT_HEIGHT = 8;
private ItemPocketRenderer() {
}
@ -108,7 +110,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer {
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, VertexFormats.POSITION_COLOR_TEXTURE);
ComputerBorderRenderer.render(transform, buffer, 0, 0, 0, width, height, LIGHT_HEIGHT, r, g, b);
ComputerBorderRenderer.render(transform, buffer, 0, 0, 0, width, height, true, r, g, b);
tessellator.draw();
}

View File

@ -36,10 +36,7 @@ import com.google.common.cache.LoadingCache;
import com.google.common.primitives.Primitives;
import com.google.common.reflect.TypeToken;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.IArguments;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.lua.*;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
@ -120,10 +117,9 @@ public final class Generator<T> {
this.addMethod(methods, method, annotation, instance);
}
for (GenericSource.GenericMethod method : GenericSource.GenericMethod.all()) {
if (!method.target.isAssignableFrom(klass)) {
continue;
}
for( GenericMethod method : GenericMethod.all() )
{
if( !method.target.isAssignableFrom( klass ) ) continue;
T instance = this.methodCache.getUnchecked(method.method)
.orElse(null);

View File

@ -0,0 +1,90 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.asm;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.GenericSource;
import dan200.computercraft.api.lua.LuaFunction;
import javax.annotation.Nonnull;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* A generic method is a method belonging to a {@link GenericSource} with a known target.
*/
public class GenericMethod
{
final Method method;
final LuaFunction annotation;
final Class<?> target;
private static final List<GenericSource> sources = new ArrayList<>();
private static List<GenericMethod> cache;
GenericMethod( Method method, LuaFunction annotation, Class<?> target )
{
this.method = method;
this.annotation = annotation;
this.target = target;
}
/**
* Find all public static methods annotated with {@link LuaFunction} which belong to a {@link GenericSource}.
*
* @return All available generic methods.
*/
static List<GenericMethod> all()
{
if( cache != null ) return cache;
return cache = sources.stream()
.flatMap( x -> Arrays.stream( x.getClass().getDeclaredMethods() ) )
.map( method ->
{
LuaFunction annotation = method.getAnnotation( LuaFunction.class );
if( annotation == null ) return null;
if( !Modifier.isStatic( method.getModifiers() ) )
{
ComputerCraft.log.error( "GenericSource method {}.{} should be static.", method.getDeclaringClass(), method.getName() );
return null;
}
Type[] types = method.getGenericParameterTypes();
if( types.length == 0 )
{
ComputerCraft.log.error( "GenericSource method {}.{} has no parameters.", method.getDeclaringClass(), method.getName() );
return null;
}
Class<?> target = Reflect.getRawType( method, types[0], false );
if( target == null ) return null;
return new GenericMethod( method, annotation, target );
} )
.filter( Objects::nonNull )
.collect( Collectors.toList() );
}
public static synchronized void register( @Nonnull GenericSource source )
{
Objects.requireNonNull( source, "Source cannot be null" );
if( cache != null )
{
ComputerCraft.log.warn( "Registering a generic source {} after cache has been built. This source will be ignored.", cache );
}
sources.add( source );
}
}

View File

@ -1,114 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.asm;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.LuaFunction;
import net.minecraft.util.Identifier;
/**
* A generic source of {@link LuaMethod} functions. This allows for injecting methods onto objects you do not own.
*
* Unlike conventional Lua objects, the annotated methods should be {@code static}, with their target as the first parameter.
*/
public interface GenericSource {
/**
* Register a stream of generic sources.
*
* @param sources The source of generic methods.
*/
static void setup(Supplier<Stream<GenericSource>> sources) {
GenericMethod.sources = sources;
}
/**
* A unique identifier for this generic source. This may be used in the future to allow disabling specific sources.
*
* @return This source's identifier.
*/
@Nonnull
Identifier id();
/**
* A generic method is a method belonging to a {@link GenericSource} with a known target.
*/
class GenericMethod {
static Supplier<Stream<GenericSource>> sources;
private static List<GenericMethod> cache;
final Method method;
final LuaFunction annotation;
final Class<?> target;
GenericMethod(Method method, LuaFunction annotation, Class<?> target) {
this.method = method;
this.annotation = annotation;
this.target = target;
}
/**
* Find all public static methods annotated with {@link LuaFunction} which belong to a {@link GenericSource}.
*
* @return All available generic methods.
*/
static List<GenericMethod> all() {
if (cache != null) {
return cache;
}
if (sources == null) {
ComputerCraft.log.warn("Getting GenericMethods without a provider");
return cache = Collections.emptyList();
}
return cache = sources.get()
.flatMap(x -> Arrays.stream(x.getClass()
.getDeclaredMethods()))
.map(method -> {
LuaFunction annotation = method.getAnnotation(LuaFunction.class);
if (annotation == null) {
return null;
}
if (!Modifier.isStatic(method.getModifiers())) {
ComputerCraft.log.error("GenericSource method {}.{} should be static.",
method.getDeclaringClass(),
method.getName());
return null;
}
Type[] types = method.getGenericParameterTypes();
if (types.length == 0) {
ComputerCraft.log.error("GenericSource method {}.{} has no parameters.",
method.getDeclaringClass(),
method.getName());
return null;
}
Class<?> target = Reflect.getRawType(method, types[0], false);
if (target == null) {
return null;
}
return new GenericMethod(method, annotation, target);
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}
}

View File

@ -31,7 +31,7 @@ import com.google.common.io.ByteStreams;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.core.apis.handles.ArrayByteChannel;
import dan200.computercraft.shared.util.IoUtil;
import net.minecraft.resource.ReloadableResourceManager;
import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourceManager;
@ -108,8 +108,8 @@ public final class ResourceMount implements IMount {
if( !hasAny )
{
ComputerCraft.log.warn("Cannot find any files under /data/{}/{} for resource mount.", namespace, subPath);
if( newRoot != null )
ComputerCraft.log.warn( "Cannot find any files under /data/{}/{} for resource mount.", namespace, subPath );
if( existingNamespace != null )
{
ComputerCraft.log.warn("There are files under /data/{}/{} though. Did you get the wrong namespace?", existingNamespace, subPath);
}
@ -186,13 +186,19 @@ public final class ResourceMount implements IMount {
return new ArrayByteChannel(contents);
}
try (InputStream stream = this.manager.getResource(file.identifier)
.getInputStream()) {
if (stream.available() > MAX_CACHED_SIZE) {
return Channels.newChannel(stream);
}
try
{
InputStream stream = manager.getResource( file.identifier ).getInputStream();
if( stream.available() > MAX_CACHED_SIZE ) return Channels.newChannel( stream );
contents = ByteStreams.toByteArray(stream);
try
{
contents = ByteStreams.toByteArray( stream );
}
finally
{
IoUtil.closeQuietly( stream );
}
CONTENTS_CACHE.put(file, contents);
return new ArrayByteChannel(contents);
} catch (FileNotFoundException ignored) {

View File

@ -72,10 +72,11 @@ public final class ColourableRecipe extends SpecialCraftingRecipe {
}
}
if (colourable.isEmpty()) {
return ItemStack.EMPTY;
}
return ((IColouredItem) colourable.getItem()).withColour(colourable, tracker.getColour());
if( colourable.isEmpty() ) return ItemStack.EMPTY;
ItemStack stack = ((IColouredItem) colourable.getItem()).withColour( colourable, tracker.getColour() );
stack.setCount( 1 );
return stack;
}
@Override

View File

@ -5,30 +5,20 @@
*/
package dan200.computercraft.shared.peripheral.generic.methods;
import com.google.auto.service.AutoService;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.GenericSource;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.asm.GenericSource;
import dan200.computercraft.shared.peripheral.generic.data.ItemData;
import dan200.computercraft.shared.util.InventoryUtil;
import dan200.computercraft.shared.util.ItemStorage;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ChestBlock;
import net.minecraft.block.InventoryProvider;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.ChestBlockEntity;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Identifier;
import net.minecraft.util.Nameable;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -43,14 +33,13 @@ import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHel
*
* @cc.module inventory
*/
@AutoService( GenericSource.class )
public class InventoryMethods implements GenericSource
{
@Nonnull
@Override
public Identifier id()
{
return new Identifier(ComputerCraft.MOD_ID, "inventory" );
return new Identifier( ComputerCraft.MOD_ID, "inventory" );
}
/**
@ -85,8 +74,9 @@ public class InventoryMethods implements GenericSource
* List all items in this inventory. This returns a table, with an entry for each slot.
*
* Each item in the inventory is represented by a table containing some basic information, much like
* @link dan200.computercraft.shared.turtle.apis.TurtleAPI#getItemDetail includes. More information can be fetched
* with {@link #getItemDetail}.
* {@link dan200.computercraft.shared.turtle.apis.TurtleAPI#getItemDetail} includes. More information can be fetched
* with {@link #getItemDetail}. The table contains the item `name`, the `count` and an a (potentially nil) hash of
* the item's `nbt.` This NBT data doesn't contain anything useful, but allows you to distinguish identical items.
*
* The returned table is sparse, and so empty slots will be `nil` - it is recommended to loop over using `pairs`
* rather than `ipairs`.
@ -94,6 +84,14 @@ public class InventoryMethods implements GenericSource
* @param inventory The current inventory.
* @return All items in this inventory.
* @cc.treturn { (table|nil)... } All items in this inventory.
* @cc.usage Find an adjacent chest and print all items in it.
*
* <pre>{@code
* local chest = peripheral.find("minecraft:chest")
* for slot, item in pairs(chest.list()) do
* print(("%d x %s in slot %d"):format(item.count, item.name, slot))
* end
* }</pre>
*/
@LuaFunction( mainThread = true )
public static Map<Integer, Map<String, ?>> list( Inventory inventory )
@ -114,11 +112,32 @@ public class InventoryMethods implements GenericSource
/**
* Get detailed information about an item.
*
* The returned information contains the same information as each item in
* {@link #list}, as well as additional details like the display name
* (`displayName`) and item durability (`damage`, `maxDamage`, `durability`).
*
* Some items include more information (such as enchantments) - it is
* recommended to print it out using @{textutils.serialize} or in the Lua
* REPL, to explore what is available.
*
* @param inventory The current inventory.
* @param slot The slot to get information about.
* @return Information about the item in this slot, or {@code nil} if not present.
* @throws LuaException If the slot is out of range.
* @cc.treturn table Information about the item in this slot, or {@code nil} if not present.
* @cc.usage Print some information about the first in a chest.
*
* <pre>{@code
* local chest = peripheral.find("minecraft:chest")
* local item = chest.getItemDetail(1)
* if not item then print("No item") return end
*
* print(("%s (%s)"):format(item.displayName, item.name))
* print(("Count: %d/%d"):format(item.count, item.maxCount))
* if item.damage then
* print(("Damage: %d/%d"):format(item.damage, item.maxDamage))
* end
* }</pre>
*/
@Nullable
@LuaFunction( mainThread = true )
@ -132,6 +151,33 @@ public class InventoryMethods implements GenericSource
return stack.isEmpty() ? null : ItemData.fill( new HashMap<>(), stack );
}
/**
* Get the maximum number of items which can be stored in this slot.
*
* Typically this will be limited to 64 items. However, some inventories (such as barrels or caches) can store
* hundreds or thousands of items in one slot.
*
* @param inventory Inventory to probe.
* @param slot The slot
* @return The maximum number of items in this slot.
* @throws LuaException If the slot is out of range.
* @cc.usage Count the maximum number of items an adjacent chest can hold.
* <pre>{@code
* local chest = peripheral.find("minecraft:chest")
* local total = 0
* for i = 1, chest.size() do
* total = total + chest.getItemLimit(i)
* end
* print(total)
* }</pre>
*/
@LuaFunction( mainThread = true )
public static int getItemLimit( Inventory inventory, int slot ) throws LuaException
{
assertBetween( slot, 1, inventory.size(), "Slot out of range (%s)" );
return inventory.getMaxCountPerStack();
}
/**
* Push items from one inventory to another connected one.
*

View File

@ -9,6 +9,7 @@ package dan200.computercraft.shared.peripheral.monitor;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import dan200.computercraft.api.turtle.FakePlayer;
import dan200.computercraft.shared.common.BlockGeneric;
import net.minecraft.block.Block;
@ -71,9 +72,14 @@ public class BlockMonitor extends BlockGeneric {
BlockEntity entity = world.getBlockEntity(pos);
if (entity instanceof TileMonitor && !world.isClient) {
TileMonitor monitor = (TileMonitor) entity;
monitor.contractNeighbours();
monitor.contract();
monitor.expand();
// Defer the block update if we're being placed by another TE. See #691
if ( livingEntity == null || livingEntity instanceof FakePlayer )
{
monitor.updateNeighborsDeferred();
return;
}
monitor.updateNeighbors();
}
}

View File

@ -54,6 +54,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile {
private ServerMonitor m_serverMonitor;
private ClientMonitor m_clientMonitor;
private MonitorPeripheral peripheral;
private boolean needsUpdate = false;
private boolean m_destroyed = false;
private boolean visiting = false;
private int m_width = 1;
@ -98,6 +99,12 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile {
@Override
public void blockTick() {
if ( needsUpdate )
{
needsUpdate = false;
updateNeighbors();
}
if (this.m_xIndex != 0 || this.m_yIndex != 0 || this.m_serverMonitor == null) {
return;
}
@ -530,6 +537,18 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile {
return true;
}
void updateNeighborsDeferred()
{
needsUpdate = true;
}
void updateNeighbors()
{
contractNeighbours();
contract();
expand();
}
@SuppressWarnings ("StatementWithEmptyBody")
void expand() {
while (this.mergeLeft() || this.mergeRight() || this.mergeUp() || this.mergeDown()) {

View File

@ -661,6 +661,18 @@ public class TurtleAPI implements ILuaAPI {
* @return The turtle command result.
* @cc.treturn boolean Whether there is a block in front of the turtle.
* @cc.treturn table|string Information about the block in front, or a message explaining that there is no block.
* @cc.usage <pre>{@code
* local has_block, data = turtle.inspect()
* if has_block then
* print(textutils.serialize(data))
* -- {
* -- name = "minecraft:oak_log",
* -- state = { axis = "x" },
* -- tags = { ["minecraft:logs"] = true, ... },
* -- }
* else
* print("No block in front of the turtle")
* end}</pre>
*/
@LuaFunction
public final MethodResult inspect() {
@ -700,6 +712,7 @@ public class TurtleAPI implements ILuaAPI {
* cost of taking longer to run.
* @return The command result.
* @throws LuaException If the slot is out of range.
* @see InventoryMethods#getItemDetail Describes the information returned by a detailed query.
* @cc.treturn nil|table Information about the given slot, or {@code nil} if it is empty.
* @cc.usage Print the current slot, assuming it contains 13 dirt.
*

View File

@ -1,29 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.util;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.ComputerCraftAPI;
import org.objectweb.asm.Type;
import java.util.List;
import java.util.ServiceLoader;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public final class ServiceUtil
{
private static final Type AUTO_SERVICE = Type.getType( "Lcom/google/auto/service/AutoService;" );
private ServiceUtil()
{
}
public static <T> Stream<T> loadServices( Class<T> target )
{
return StreamSupport.stream( ServiceLoader.load( target, ServiceUtil.class.getClassLoader() ).spliterator(), false );
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 347 B

View File

@ -16,22 +16,7 @@ end
if _VERSION == "Lua 5.1" then
-- If we're on Lua 5.1, install parts of the Lua 5.2/5.3 API so that programs can be written against it
local type = type
local nativeload = load
local nativeloadstring = loadstring
local nativesetfenv = setfenv
-- Historically load/loadstring would handle the chunk name as if it has
-- been prefixed with "=". We emulate that behaviour here.
local function prefix(chunkname)
if type(chunkname) ~= "string" then return chunkname end
local head = chunkname:sub(1, 1)
if head == "=" or head == "@" then
return chunkname
else
return "=" .. chunkname
end
end
function load(x, name, mode, env)
expect(1, x, "function", "string")
@ -40,29 +25,11 @@ if _VERSION == "Lua 5.1" then
expect(4, env, "table", "nil")
local ok, p1, p2 = pcall(function()
if type(x) == "string" then
local result, err = nativeloadstring(x, name)
if result then
if env then
env._ENV = env
nativesetfenv(result, env)
end
return result
else
return nil, err
end
else
local result, err = nativeload(x, name)
if result then
if env then
env._ENV = env
nativesetfenv(result, env)
end
return result
else
return nil, err
end
local result, err = nativeload(x, name, mode, env)
if result and env then
env._ENV = env
end
return result, err
end)
if ok then
return p1, p2
@ -81,7 +48,7 @@ if _VERSION == "Lua 5.1" then
math.log10 = nil
table.maxn = nil
else
loadstring = function(string, chunkname) return nativeloadstring(string, prefix(chunkname)) end
loadstring = function(string, chunkname) return nativeload(string, chunkname) end
-- Inject a stub for the old bit library
_G.bit = {

View File

@ -1,4 +1,22 @@
New features in CC: Restitched 1.95.3
# New features in CC: Restitched 1.96.0
* Use lightGrey for folders within the "list" program.
* Add getLimit to inventory peripherals.
* Expose the generic peripheral system to the public API.
* Add cc.expect.range (Lupus590).
* Allow calling cc.expect directly (MCJack123).
* Numerous improvements to documentation.
And several bug fixes:
* Fix paintutils.drawLine incorrectly sorting coordinates (lilyzeiset).
* Improve JEI's handling of turtle/pocket upgrade recipes.
* Correctly handle sparse arrays in cc.pretty.
* Fix crashes when a turtle places a monitor (baeuric).
* Fix very large resource files being considered empty.
* Allow turtles to use compostors.
* Fix dupe bug when colouring turtles.
# New features in CC: Restitched 1.95.3
Several bug fixes:
* Correctly serialise sparse arrays into JSON (livegamer999)

View File

@ -1,9 +1,19 @@
New features in CC: Restitched 1.95.3
New features in CC: Restitched 1.96.0
Several bug fixes:
* Correctly serialise sparse arrays into JSON (livegamer999)
* Fix rs.getBundledInput returning the output instead (SkyTheCodeMaster)
* Programs run via edit are now a little better behaved (Wojbie)
* Add User-Agent to a websocket's headers.
* Use lightGrey for folders within the "list" program.
* Add getLimit to inventory peripherals.
* Expose the generic peripheral system to the public API.
* Add cc.expect.range (Lupus590).
* Allow calling cc.expect directly (MCJack123).
* Numerous improvements to documentation.
And several bug fixes:
* Fix paintutils.drawLine incorrectly sorting coordinates (lilyzeiset).
* Improve JEI's handling of turtle/pocket upgrade recipes.
* Correctly handle sparse arrays in cc.pretty.
* Fix crashes when a turtle places a monitor (baeuric).
* Fix very large resource files being considered empty.
* Allow turtles to use compostors.
* Fix dupe bug when colouring turtles.
Type "help changelog" to see the full version history.

View File

@ -88,7 +88,34 @@ local function field(tbl, index, ...)
end
end
return {
local function is_nan(num)
return num ~= num
end
--- Expect a number to be within a specific range.
--
-- @tparam number num, The value to check.
-- @tparam number min The minimum value, if nil then `-math.huge` is used.
-- @tparam number max The maximum value, if nil then `math.huge` is used.
-- @return The given `value`.
-- @throws If the value is outside of the allowed range.
local function range(num, min, max)
expect(1, num, "number")
min = expect(2, min, "number", "nil") or -math.huge
max = expect(3, max, "number", "nil") or math.huge
if min > max then
error("min must be less than or equal to max)", 2)
end
if is_nan(num) or num < min or num > max then
error(("number outside of range (expected %s to be within %s and %s)"):format(num, min, max), 3)
end
return num
end
return setmetatable({
expect = expect,
field = field,
}
range = range,
}, { __call = function(_, ...) return expect(...) end })

View File

@ -409,18 +409,24 @@ local function pretty_impl(obj, options, tracking)
local doc = setmetatable({ tag = "concat", n = 1, space_line }, Doc)
local length, keys, keysn = #obj, {}, 1
for k in pairs(obj) do keys[keysn], keysn = k, keysn + 1 end
for k in pairs(obj) do
if type(k) ~= "number" or k % 1 ~= 0 or k < 1 or k > length then
keys[keysn], keysn = k, keysn + 1
end
end
table.sort(keys, key_compare)
for i = 1, keysn - 1 do
for i = 1, length do
if i > 1 then append(doc, comma) append(doc, space_line) end
append(doc, pretty_impl(obj[i], options, tracking))
end
for i = 1, keysn - 1 do
if i > 1 or length >= 1 then append(doc, comma) append(doc, space_line) end
local k = keys[i]
local v = obj[k]
local ty = type(k)
if ty == "number" and k % 1 == 0 and k >= 1 and k <= length then
append(doc, pretty_impl(v, options, tracking))
elseif ty == "string" and not keywords[k] and k:match("^[%a_][%a%d_]*$") then
if type(k) == "string" and not keywords[k] and k:match("^[%a_][%a%d_]*$") then
append(doc, text(k .. " = "))
append(doc, pretty_impl(v, options, tracking))
else

View File

@ -33,5 +33,5 @@ table.sort(tFiles)
if term.isColour() then
textutils.pagedTabulate(colors.green, tDirs, colors.white, tFiles)
else
textutils.pagedTabulate(tDirs, tFiles)
textutils.pagedTabulate(colors.lightGray, tDirs, colors.white, tFiles)
end