1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-23 01:47:38 +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
27 changed files with 402 additions and 264 deletions

View File

@@ -50,7 +50,7 @@ dependencies {
compile 'javax.vecmath:vecmath:1.5.2' 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-api:5.8.9"
modRuntime "me.shedaniel:RoughlyEnoughItems:5.8.9" modRuntime "me.shedaniel:RoughlyEnoughItems:5.8.9"

View File

@@ -2,7 +2,7 @@
org.gradle.jvmargs=-Xmx1G org.gradle.jvmargs=-Xmx1G
# Mod properties # Mod properties
mod_version=1.95.3-beta mod_version=1.96.0-beta
# Minecraft properties # Minecraft properties
mc_version=1.16.5 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.Action;
import dan200.computercraft.core.apis.http.options.AddressRule; import dan200.computercraft.core.apis.http.options.AddressRule;
import dan200.computercraft.core.apis.http.websocket.Websocket; import dan200.computercraft.core.apis.http.websocket.Websocket;
import dan200.computercraft.core.asm.GenericSource;
import dan200.computercraft.shared.common.ColourableRecipe; import dan200.computercraft.shared.common.ColourableRecipe;
import dan200.computercraft.shared.computer.core.ClientComputerRegistry; import dan200.computercraft.shared.computer.core.ClientComputerRegistry;
import dan200.computercraft.shared.computer.core.ServerComputerRegistry; 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.Config;
import dan200.computercraft.shared.util.ImpostorRecipe; import dan200.computercraft.shared.util.ImpostorRecipe;
import dan200.computercraft.shared.util.ImpostorShapelessRecipe; import dan200.computercraft.shared.util.ImpostorShapelessRecipe;
import dan200.computercraft.shared.util.ServiceUtil;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 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, "player_creative"), PlayerCreativeLootCondition.TYPE);
Registry.register(Registry.LOOT_CONDITION_TYPE, new Identifier(ComputerCraft.MOD_ID, "has_id"), HasComputerIdLootCondition.TYPE); Registry.register(Registry.LOOT_CONDITION_TYPE, new Identifier(ComputerCraft.MOD_ID, "has_id"), HasComputerIdLootCondition.TYPE);
init(); init();
GenericSource.setup( () -> ServiceUtil.loadServices( GenericSource.class ));
FabricLoader.getInstance().getModContainer(MOD_ID).ifPresent(modContainer -> { FabricLoader.getInstance().getModContainer(MOD_ID).ifPresent(modContainer -> {
ResourceManagerHelper.registerBuiltinResourcePack(new Identifier(MOD_ID, "classic"), modContainer, ResourcePackActivationType.NORMAL); ResourceManagerHelper.registerBuiltinResourcePack(new Identifier(MOD_ID, "classic"), modContainer, ResourcePackActivationType.NORMAL);
ResourceManagerHelper.registerBuiltinResourcePack(new Identifier(MOD_ID, "overhaul"), 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.ComputerCraftAPI.IComputerCraftAPI;
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.ILuaAPIFactory; import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.media.IMediaProvider; import dan200.computercraft.api.media.IMediaProvider;
import dan200.computercraft.api.network.IPacketNetwork; 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.redstone.IBundledRedstoneProvider;
import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.core.apis.ApiFactories; import dan200.computercraft.core.apis.ApiFactories;
import dan200.computercraft.core.asm.GenericMethod;
import dan200.computercraft.core.filesystem.FileMount; import dan200.computercraft.core.filesystem.FileMount;
import dan200.computercraft.core.filesystem.ResourceMount; import dan200.computercraft.core.filesystem.ResourceMount;
import dan200.computercraft.mixin.MinecraftServerAccess; import dan200.computercraft.mixin.MinecraftServerAccess;
@@ -143,6 +145,12 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI {
PocketUpgrades.register(upgrade); PocketUpgrades.register(upgrade);
} }
@Override
public void registerGenericSource( @Nonnull GenericSource source )
{
GenericMethod.register( source );
}
@Nonnull @Nonnull
@Override @Override
public IPacketNetwork getWirelessNetwork() { public IPacketNetwork getWirelessNetwork() {

View File

@@ -11,6 +11,7 @@ import javax.annotation.Nullable;
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.ILuaAPIFactory; import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.media.IMediaProvider; import dan200.computercraft.api.media.IMediaProvider;
@@ -136,6 +137,17 @@ public final class ComputerCraftAPI {
getInstance().registerPeripheralProvider(provider); 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 * 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. * 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 registerPeripheralProvider(@Nonnull IPeripheralProvider provider);
void registerGenericSource( @Nonnull GenericSource source );
void registerTurtleUpgrade(@Nonnull ITurtleUpgrade upgrade); void registerTurtleUpgrade(@Nonnull ITurtleUpgrade upgrade);
void registerBundledRedstoneProvider(@Nonnull IBundledRedstoneProvider provider); 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_LEFT_X = BORDER;
private static final int CORNER_RIGHT_X = 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 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; private static final float TEX_SCALE = 1 / 256.0f;
static { 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) { 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, 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 )
float b) { {
new ComputerBorderRenderer(transform, buffer, z, r, g, b).doRender(x, y, width, height, borderHeight); 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 endX = x + width;
int endY = y + height; 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 // Bottom bar. We allow for drawing a stretched version, which allows for additional elements (such as the
// pocket computer's lights). // 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.renderLine(x, endY, 0, BORDER, endX - x, BORDER);
this.renderCorner(x - BORDER, endY, CORNER_LEFT_X, CORNER_BOTTOM_Y); this.renderCorner(x - BORDER, endY, CORNER_LEFT_X, CORNER_BOTTOM_Y);
this.renderCorner(endX, endY, CORNER_RIGHT_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; 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_HEIGHT;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER; 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.item.ItemStack;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import static dan200.computercraft.client.render.ComputerBorderRenderer.*;
/** /**
* Emulates map rendering for pocket computers. * Emulates map rendering for pocket computers.
*/ */
public final class ItemPocketRenderer extends ItemMapLikeRenderer { public final class ItemPocketRenderer extends ItemMapLikeRenderer {
public static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer(); public static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer();
private static final int LIGHT_HEIGHT = 8;
private ItemPocketRenderer() { private ItemPocketRenderer() {
} }
@@ -108,7 +110,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer {
BufferBuilder buffer = tessellator.getBuffer(); BufferBuilder buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, VertexFormats.POSITION_COLOR_TEXTURE); 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(); tessellator.draw();
} }

View File

@@ -36,10 +36,7 @@ import com.google.common.cache.LoadingCache;
import com.google.common.primitives.Primitives; import com.google.common.primitives.Primitives;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.lua.MethodResult;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
@@ -120,10 +117,9 @@ public final class Generator<T> {
this.addMethod(methods, method, annotation, instance); this.addMethod(methods, method, annotation, instance);
} }
for (GenericSource.GenericMethod method : GenericSource.GenericMethod.all()) { for( GenericMethod method : GenericMethod.all() )
if (!method.target.isAssignableFrom(klass)) { {
continue; if( !method.target.isAssignableFrom( klass ) ) continue;
}
T instance = this.methodCache.getUnchecked(method.method) T instance = this.methodCache.getUnchecked(method.method)
.orElse(null); .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.ComputerCraft;
import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.core.apis.handles.ArrayByteChannel; import dan200.computercraft.core.apis.handles.ArrayByteChannel;
import dan200.computercraft.shared.util.IoUtil;
import net.minecraft.resource.ReloadableResourceManager; import net.minecraft.resource.ReloadableResourceManager;
import net.minecraft.resource.Resource; import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourceManager; import net.minecraft.resource.ResourceManager;
@@ -108,8 +108,8 @@ public final class ResourceMount implements IMount {
if( !hasAny ) if( !hasAny )
{ {
ComputerCraft.log.warn("Cannot find any files under /data/{}/{} for resource mount.", namespace, subPath); ComputerCraft.log.warn( "Cannot find any files under /data/{}/{} for resource mount.", namespace, subPath );
if( newRoot != null ) if( existingNamespace != null )
{ {
ComputerCraft.log.warn("There are files under /data/{}/{} though. Did you get the wrong namespace?", existingNamespace, subPath); 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); return new ArrayByteChannel(contents);
} }
try (InputStream stream = this.manager.getResource(file.identifier) try
.getInputStream()) { {
if (stream.available() > MAX_CACHED_SIZE) { InputStream stream = manager.getResource( file.identifier ).getInputStream();
return Channels.newChannel(stream); 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); CONTENTS_CACHE.put(file, contents);
return new ArrayByteChannel(contents); return new ArrayByteChannel(contents);
} catch (FileNotFoundException ignored) { } catch (FileNotFoundException ignored) {

View File

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

View File

@@ -5,30 +5,20 @@
*/ */
package dan200.computercraft.shared.peripheral.generic.methods; package dan200.computercraft.shared.peripheral.generic.methods;
import com.google.auto.service.AutoService;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.GenericSource;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.asm.GenericSource;
import dan200.computercraft.shared.peripheral.generic.data.ItemData; import dan200.computercraft.shared.peripheral.generic.data.ItemData;
import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.InventoryUtil;
import dan200.computercraft.shared.util.ItemStorage; 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.BlockEntity;
import net.minecraft.block.entity.ChestBlockEntity;
import net.minecraft.inventory.Inventory; import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Nameable; import net.minecraft.util.Nameable;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -43,14 +33,13 @@ import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHel
* *
* @cc.module inventory * @cc.module inventory
*/ */
@AutoService( GenericSource.class )
public class InventoryMethods implements GenericSource public class InventoryMethods implements GenericSource
{ {
@Nonnull @Nonnull
@Override @Override
public Identifier id() 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. * 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 * 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 * {@link dan200.computercraft.shared.turtle.apis.TurtleAPI#getItemDetail} includes. More information can be fetched
* with {@link #getItemDetail}. * 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` * The returned table is sparse, and so empty slots will be `nil` - it is recommended to loop over using `pairs`
* rather than `ipairs`. * rather than `ipairs`.
@@ -94,6 +84,14 @@ public class InventoryMethods implements GenericSource
* @param inventory The current inventory. * @param inventory The current inventory.
* @return All items in this inventory. * @return All items in this inventory.
* @cc.treturn { (table|nil)... } 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 ) @LuaFunction( mainThread = true )
public static Map<Integer, Map<String, ?>> list( Inventory inventory ) public static Map<Integer, Map<String, ?>> list( Inventory inventory )
@@ -114,11 +112,32 @@ public class InventoryMethods implements GenericSource
/** /**
* Get detailed information about an item. * 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 inventory The current inventory.
* @param slot The slot to get information about. * @param slot The slot to get information about.
* @return Information about the item in this slot, or {@code nil} if not present. * @return Information about the item in this slot, or {@code nil} if not present.
* @throws LuaException If the slot is out of range. * @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.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 @Nullable
@LuaFunction( mainThread = true ) @LuaFunction( mainThread = true )
@@ -132,6 +151,33 @@ public class InventoryMethods implements GenericSource
return stack.isEmpty() ? null : ItemData.fill( new HashMap<>(), stack ); 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. * 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.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import dan200.computercraft.api.turtle.FakePlayer;
import dan200.computercraft.shared.common.BlockGeneric; import dan200.computercraft.shared.common.BlockGeneric;
import net.minecraft.block.Block; import net.minecraft.block.Block;
@@ -71,9 +72,14 @@ public class BlockMonitor extends BlockGeneric {
BlockEntity entity = world.getBlockEntity(pos); BlockEntity entity = world.getBlockEntity(pos);
if (entity instanceof TileMonitor && !world.isClient) { if (entity instanceof TileMonitor && !world.isClient) {
TileMonitor monitor = (TileMonitor) entity; TileMonitor monitor = (TileMonitor) entity;
monitor.contractNeighbours(); // Defer the block update if we're being placed by another TE. See #691
monitor.contract(); if ( livingEntity == null || livingEntity instanceof FakePlayer )
monitor.expand(); {
monitor.updateNeighborsDeferred();
return;
}
monitor.updateNeighbors();
} }
} }

View File

@@ -54,6 +54,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile {
private ServerMonitor m_serverMonitor; private ServerMonitor m_serverMonitor;
private ClientMonitor m_clientMonitor; private ClientMonitor m_clientMonitor;
private MonitorPeripheral peripheral; private MonitorPeripheral peripheral;
private boolean needsUpdate = false;
private boolean m_destroyed = false; private boolean m_destroyed = false;
private boolean visiting = false; private boolean visiting = false;
private int m_width = 1; private int m_width = 1;
@@ -98,6 +99,12 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile {
@Override @Override
public void blockTick() { public void blockTick() {
if ( needsUpdate )
{
needsUpdate = false;
updateNeighbors();
}
if (this.m_xIndex != 0 || this.m_yIndex != 0 || this.m_serverMonitor == null) { if (this.m_xIndex != 0 || this.m_yIndex != 0 || this.m_serverMonitor == null) {
return; return;
} }
@@ -530,6 +537,18 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile {
return true; return true;
} }
void updateNeighborsDeferred()
{
needsUpdate = true;
}
void updateNeighbors()
{
contractNeighbours();
contract();
expand();
}
@SuppressWarnings ("StatementWithEmptyBody") @SuppressWarnings ("StatementWithEmptyBody")
void expand() { void expand() {
while (this.mergeLeft() || this.mergeRight() || this.mergeUp() || this.mergeDown()) { 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. * @return The turtle command result.
* @cc.treturn boolean Whether there is a block in front of the turtle. * @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.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 @LuaFunction
public final MethodResult inspect() { public final MethodResult inspect() {
@@ -700,6 +712,7 @@ public class TurtleAPI implements ILuaAPI {
* cost of taking longer to run. * cost of taking longer to run.
* @return The command result. * @return The command result.
* @throws LuaException If the slot is out of range. * @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.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. * @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 _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 -- 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 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) function load(x, name, mode, env)
expect(1, x, "function", "string") expect(1, x, "function", "string")
@@ -40,29 +25,11 @@ if _VERSION == "Lua 5.1" then
expect(4, env, "table", "nil") expect(4, env, "table", "nil")
local ok, p1, p2 = pcall(function() local ok, p1, p2 = pcall(function()
if type(x) == "string" then local result, err = nativeload(x, name, mode, env)
local result, err = nativeloadstring(x, name) if result and env then
if result then
if env then
env._ENV = env 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
end end
return result, err
end) end)
if ok then if ok then
return p1, p2 return p1, p2
@@ -81,7 +48,7 @@ if _VERSION == "Lua 5.1" then
math.log10 = nil math.log10 = nil
table.maxn = nil table.maxn = nil
else 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 -- Inject a stub for the old bit library
_G.bit = { _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: Several bug fixes:
* Correctly serialise sparse arrays into JSON (livegamer999) * 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: * Use lightGrey for folders within the "list" program.
* Correctly serialise sparse arrays into JSON (livegamer999) * Add getLimit to inventory peripherals.
* Fix rs.getBundledInput returning the output instead (SkyTheCodeMaster) * Expose the generic peripheral system to the public API.
* Programs run via edit are now a little better behaved (Wojbie) * Add cc.expect.range (Lupus590).
* Add User-Agent to a websocket's headers. * 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. Type "help changelog" to see the full version history.

View File

@@ -88,7 +88,34 @@ local function field(tbl, index, ...)
end end
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, expect = expect,
field = field, 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 doc = setmetatable({ tag = "concat", n = 1, space_line }, Doc)
local length, keys, keysn = #obj, {}, 1 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) 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 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 k = keys[i]
local v = obj[k] local v = obj[k]
local ty = type(k) if type(k) == "string" and not keywords[k] and k:match("^[%a_][%a%d_]*$") then
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
append(doc, text(k .. " = ")) append(doc, text(k .. " = "))
append(doc, pretty_impl(v, options, tracking)) append(doc, pretty_impl(v, options, tracking))
else else

View File

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