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

Reformat everything

This commit is contained in:
Jonathan Coates 2021-06-09 07:53:21 +01:00
parent a6c7236fa0
commit b429095f88
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
409 changed files with 20797 additions and 15102 deletions

View File

@ -6,15 +6,6 @@
package dan200.computercraft; package dan200.computercraft;
import static dan200.computercraft.shared.ComputerCraftRegistry.ModBlocks;
import static dan200.computercraft.shared.ComputerCraftRegistry.init;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.concurrent.TimeUnit;
import dan200.computercraft.api.turtle.event.TurtleAction; 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;
@ -32,22 +23,31 @@ import dan200.computercraft.shared.pocket.recipes.PocketComputerUpgradeRecipe;
import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon; import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon;
import dan200.computercraft.shared.turtle.recipes.TurtleRecipe; import dan200.computercraft.shared.turtle.recipes.TurtleRecipe;
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe; import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
import dan200.computercraft.shared.util.*; import dan200.computercraft.shared.util.ImpostorRecipe;
import org.apache.logging.log4j.LogManager; import dan200.computercraft.shared.util.ImpostorShapelessRecipe;
import org.apache.logging.log4j.Logger;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder; import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.fabricmc.fabric.api.resource.ResourcePackActivationType; import net.fabricmc.fabric.api.resource.ResourcePackActivationType;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public final class ComputerCraft implements ModInitializer { import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static dan200.computercraft.shared.ComputerCraftRegistry.ModBlocks;
import static dan200.computercraft.shared.ComputerCraftRegistry.init;
public final class ComputerCraft implements ModInitializer
{
public static final String MOD_ID = "computercraft"; public static final String MOD_ID = "computercraft";
// Configuration fields // Configuration fields
@ -70,7 +70,6 @@ public final class ComputerCraft implements ModInitializer {
AddressRule.parse( "$private", null, Action.DENY.toPartial() ), AddressRule.parse( "$private", null, Action.DENY.toPartial() ),
AddressRule.parse( "*", null, Action.ALLOW.toPartial() ) AddressRule.parse( "*", null, Action.ALLOW.toPartial() )
) ); ) );
public static int httpMaxRequests = 16; public static int httpMaxRequests = 16;
public static int httpMaxWebsockets = 4; public static int httpMaxWebsockets = 4;
@ -99,7 +98,6 @@ public final class ComputerCraft implements ModInitializer {
public static int pocketTermWidth = 26; public static int pocketTermWidth = 26;
public static int pocketTermHeight = 20; public static int pocketTermHeight = 20;
public static int monitorWidth = 8; public static int monitorWidth = 8;
public static int monitorHeight = 6; public static int monitorHeight = 6;
@ -113,12 +111,14 @@ public final class ComputerCraft implements ModInitializer {
public static ItemGroup MAIN_GROUP = FabricItemGroupBuilder.build( new Identifier( MOD_ID, "main" ), () -> new ItemStack( ModBlocks.COMPUTER_NORMAL ) ); public static ItemGroup MAIN_GROUP = FabricItemGroupBuilder.build( new Identifier( MOD_ID, "main" ), () -> new ItemStack( ModBlocks.COMPUTER_NORMAL ) );
@Override @Override
public void onInitialize() { public void onInitialize()
{
ComputerCraftProxyCommon.init(); ComputerCraftProxyCommon.init();
Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "colour" ), ColourableRecipe.SERIALIZER ); Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "colour" ), ColourableRecipe.SERIALIZER );
Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "computer_upgrade" ), ComputerUpgradeRecipe.SERIALIZER ); Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "computer_upgrade" ), ComputerUpgradeRecipe.SERIALIZER );
Registry.register(Registry.RECIPE_SERIALIZER, new Identifier(ComputerCraft.MOD_ID, "pocket_computer_upgrade"), PocketComputerUpgradeRecipe.SERIALIZER); Registry.register( Registry.RECIPE_SERIALIZER,
new Identifier( ComputerCraft.MOD_ID, "pocket_computer_upgrade" ),
PocketComputerUpgradeRecipe.SERIALIZER );
Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "disk" ), DiskRecipe.SERIALIZER ); Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "disk" ), DiskRecipe.SERIALIZER );
Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "printout" ), PrintoutRecipe.SERIALIZER ); Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "printout" ), PrintoutRecipe.SERIALIZER );
Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "turtle" ), TurtleRecipe.SERIALIZER ); Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "turtle" ), TurtleRecipe.SERIALIZER );

View File

@ -6,13 +6,6 @@
package dan200.computercraft; package dan200.computercraft;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import javax.annotation.Nonnull;
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;
@ -31,18 +24,14 @@ 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.fabric.mixin.MinecraftServerAccess; import dan200.computercraft.fabric.mixin.MinecraftServerAccess;
import dan200.computercraft.shared.BundledRedstone; import dan200.computercraft.shared.*;
import dan200.computercraft.shared.MediaProviders;
import dan200.computercraft.shared.Peripherals;
import dan200.computercraft.shared.PocketUpgrades;
import dan200.computercraft.shared.TurtleUpgrades;
import dan200.computercraft.shared.peripheral.modem.wired.TileCable; import dan200.computercraft.shared.peripheral.modem.wired.TileCable;
import dan200.computercraft.shared.peripheral.modem.wired.TileWiredModemFull; import dan200.computercraft.shared.peripheral.modem.wired.TileWiredModemFull;
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;
import me.shedaniel.cloth.api.utils.v1.GameInstanceUtils; import me.shedaniel.cloth.api.utils.v1.GameInstanceUtils;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.resource.ReloadableResourceManager; import net.minecraft.resource.ReloadableResourceManager;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
@ -52,24 +41,35 @@ import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView; import net.minecraft.world.BlockView;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.fabricmc.loader.api.FabricLoader; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
public final class ComputerCraftAPIImpl implements IComputerCraftAPI { public final class ComputerCraftAPIImpl implements IComputerCraftAPI
{
public static final ComputerCraftAPIImpl INSTANCE = new ComputerCraftAPIImpl(); public static final ComputerCraftAPIImpl INSTANCE = new ComputerCraftAPIImpl();
private String version; private String version;
private ComputerCraftAPIImpl() { private ComputerCraftAPIImpl()
{
} }
public static InputStream getResourceFile(String domain, String subPath) { public static InputStream getResourceFile( String domain, String subPath )
{
MinecraftServer server = GameInstanceUtils.getServer(); MinecraftServer server = GameInstanceUtils.getServer();
if (server != null) { if( server != null )
{
ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) server).getServerResourceManager().getResourceManager(); ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) server).getServerResourceManager().getResourceManager();
try { try
{
return manager.getResource( new Identifier( domain, subPath ) ) return manager.getResource( new Identifier( domain, subPath ) )
.getInputStream(); .getInputStream();
} catch (IOException ignored) { }
catch( IOException ignored )
{
return null; return null;
} }
} }
@ -78,8 +78,10 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI {
@Nonnull @Nonnull
@Override @Override
public String getInstalledVersion() { public String getInstalledVersion()
if (this.version != null) { {
if( this.version != null )
{
return this.version; return this.version;
} }
return this.version = FabricLoader.getInstance() return this.version = FabricLoader.getInstance()
@ -91,23 +93,30 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI {
} }
@Override @Override
public int createUniqueNumberedSaveDir(@Nonnull World world, @Nonnull String parentSubPath) { public int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath )
{
return IDAssigner.getNextId( parentSubPath ); return IDAssigner.getNextId( parentSubPath );
} }
@Override @Override
public IWritableMount createSaveDirMount(@Nonnull World world, @Nonnull String subPath, long capacity) { public IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity )
try { {
try
{
return new FileMount( new File( IDAssigner.getDir(), subPath ), capacity ); return new FileMount( new File( IDAssigner.getDir(), subPath ), capacity );
} catch (Exception e) { }
catch( Exception e )
{
return null; return null;
} }
} }
@Override @Override
public IMount createResourceMount(@Nonnull String domain, @Nonnull String subPath) { public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath )
{
MinecraftServer server = GameInstanceUtils.getServer(); MinecraftServer server = GameInstanceUtils.getServer();
if (server != null) { if( server != null )
{
ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) server).getServerResourceManager().getResourceManager(); ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) server).getServerResourceManager().getResourceManager();
ResourceMount mount = ResourceMount.get( domain, subPath, manager ); ResourceMount mount = ResourceMount.get( domain, subPath, manager );
return mount.exists( "" ) ? mount : null; return mount.exists( "" ) ? mount : null;
@ -116,32 +125,38 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI {
} }
@Override @Override
public void registerPeripheralProvider(@Nonnull IPeripheralProvider provider) { public void registerPeripheralProvider( @Nonnull IPeripheralProvider provider )
{
Peripherals.register( provider ); Peripherals.register( provider );
} }
@Override @Override
public void registerTurtleUpgrade(@Nonnull ITurtleUpgrade upgrade) { public void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade )
{
TurtleUpgrades.register( upgrade ); TurtleUpgrades.register( upgrade );
} }
@Override @Override
public void registerBundledRedstoneProvider(@Nonnull IBundledRedstoneProvider provider) { public void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider )
{
BundledRedstone.register( provider ); BundledRedstone.register( provider );
} }
@Override @Override
public int getBundledRedstoneOutput(@Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side) { public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side )
{
return BundledRedstone.getDefaultOutput( world, pos, side ); return BundledRedstone.getDefaultOutput( world, pos, side );
} }
@Override @Override
public void registerMediaProvider(@Nonnull IMediaProvider provider) { public void registerMediaProvider( @Nonnull IMediaProvider provider )
{
MediaProviders.register( provider ); MediaProviders.register( provider );
} }
@Override @Override
public void registerPocketUpgrade(@Nonnull IPocketUpgrade upgrade) { public void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade )
{
PocketUpgrades.register( upgrade ); PocketUpgrades.register( upgrade );
} }
@ -153,28 +168,35 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI {
@Nonnull @Nonnull
@Override @Override
public IPacketNetwork getWirelessNetwork() { public IPacketNetwork getWirelessNetwork()
{
return WirelessNetwork.getUniversal(); return WirelessNetwork.getUniversal();
} }
@Override @Override
public void registerAPIFactory(@Nonnull ILuaAPIFactory factory) { public void registerAPIFactory( @Nonnull ILuaAPIFactory factory )
{
ApiFactories.register( factory ); ApiFactories.register( factory );
} }
@Nonnull @Nonnull
@Override @Override
public IWiredNode createWiredNodeForElement(@Nonnull IWiredElement element) { public IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element )
{
return new WiredNode( element ); return new WiredNode( element );
} }
@Nullable @Nullable
@Override @Override
public IWiredElement getWiredElementAt(@Nonnull BlockView world, @Nonnull BlockPos pos, @Nonnull Direction side) { public IWiredElement getWiredElementAt( @Nonnull BlockView world, @Nonnull BlockPos pos, @Nonnull Direction side )
{
BlockEntity tile = world.getBlockEntity( pos ); BlockEntity tile = world.getBlockEntity( pos );
if (tile instanceof TileCable) { if( tile instanceof TileCable )
{
return ((TileCable) tile).getElement( side ); return ((TileCable) tile).getElement( side );
} else if (tile instanceof TileWiredModemFull) { }
else if( tile instanceof TileWiredModemFull )
{
return ((TileWiredModemFull) tile).getElement(); return ((TileWiredModemFull) tile).getElement();
} }
return null; return null;

View File

@ -6,9 +6,6 @@
package dan200.computercraft.api; package dan200.computercraft.api;
import javax.annotation.Nonnull;
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.GenericSource;
@ -24,42 +21,52 @@ import dan200.computercraft.api.peripheral.IPeripheralProvider;
import dan200.computercraft.api.pocket.IPocketUpgrade; 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 net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView; import net.minecraft.world.BlockView;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* The static entry point to the ComputerCraft API. * The static entry point to the ComputerCraft API.
* *
* Members in this class must be called after mod_ComputerCraft has been initialised, but may be called before it is fully loaded. * Members in this class must be called after mod_ComputerCraft has been initialised, but may be called before it is fully loaded.
*/ */
public final class ComputerCraftAPI { public final class ComputerCraftAPI
{
private static IComputerCraftAPI instance; private static IComputerCraftAPI instance;
@Nonnull @Nonnull
@Deprecated @Deprecated
public static String getAPIVersion() { public static String getAPIVersion()
{
return getInstalledVersion(); return getInstalledVersion();
} }
@Nonnull @Nonnull
public static String getInstalledVersion() { public static String getInstalledVersion()
{
return getInstance().getInstalledVersion(); return getInstance().getInstalledVersion();
} }
@Nonnull @Nonnull
private static IComputerCraftAPI getInstance() { private static IComputerCraftAPI getInstance()
if (instance != null) { {
if( instance != null )
{
return instance; return instance;
} }
try { try
{
return instance = (IComputerCraftAPI) Class.forName( "dan200.computercraft.ComputerCraftAPIImpl" ) return instance = (IComputerCraftAPI) Class.forName( "dan200.computercraft.ComputerCraftAPIImpl" )
.getField( "INSTANCE" ) .getField( "INSTANCE" )
.get( null ); .get( null );
} catch (ReflectiveOperationException e) { }
catch( ReflectiveOperationException e )
{
throw new IllegalStateException( "Cannot find ComputerCraft API", e ); throw new IllegalStateException( "Cannot find ComputerCraft API", e );
} }
} }
@ -76,7 +83,8 @@ public final class ComputerCraftAPI {
* eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then "computer/disk/42" is now available for writing. * eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then "computer/disk/42" is now available for writing.
* @see #createSaveDirMount(World, String, long) * @see #createSaveDirMount(World, String, long)
*/ */
public static int createUniqueNumberedSaveDir(@Nonnull World world, @Nonnull String parentSubPath) { public static int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath )
{
return getInstance().createUniqueNumberedSaveDir( world, parentSubPath ); return getInstance().createUniqueNumberedSaveDir( world, parentSubPath );
} }
@ -99,7 +107,8 @@ public final class ComputerCraftAPI {
* @see IWritableMount * @see IWritableMount
*/ */
@Nullable @Nullable
public static IWritableMount createSaveDirMount(@Nonnull World world, @Nonnull String subPath, long capacity) { public static IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity )
{
return getInstance().createSaveDirMount( world, subPath, capacity ); return getInstance().createSaveDirMount( world, subPath, capacity );
} }
@ -122,7 +131,8 @@ public final class ComputerCraftAPI {
* @see IMount * @see IMount
*/ */
@Nullable @Nullable
public static IMount createResourceMount(@Nonnull String domain, @Nonnull String subPath) { public static IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath )
{
return getInstance().createResourceMount( domain, subPath ); return getInstance().createResourceMount( domain, subPath );
} }
@ -133,7 +143,8 @@ public final class ComputerCraftAPI {
* @see IPeripheral * @see IPeripheral
* @see IPeripheralProvider * @see IPeripheralProvider
*/ */
public static void registerPeripheralProvider(@Nonnull IPeripheralProvider provider) { public static void registerPeripheralProvider( @Nonnull IPeripheralProvider provider )
{
getInstance().registerPeripheralProvider( provider ); getInstance().registerPeripheralProvider( provider );
} }
@ -155,7 +166,8 @@ public final class ComputerCraftAPI {
* @param upgrade The turtle upgrade to register. * @param upgrade The turtle upgrade to register.
* @see ITurtleUpgrade * @see ITurtleUpgrade
*/ */
public static void registerTurtleUpgrade(@Nonnull ITurtleUpgrade upgrade) { public static void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade )
{
getInstance().registerTurtleUpgrade( upgrade ); getInstance().registerTurtleUpgrade( upgrade );
} }
@ -165,7 +177,8 @@ public final class ComputerCraftAPI {
* @param provider The bundled redstone provider to register. * @param provider The bundled redstone provider to register.
* @see IBundledRedstoneProvider * @see IBundledRedstoneProvider
*/ */
public static void registerBundledRedstoneProvider(@Nonnull IBundledRedstoneProvider provider) { public static void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider )
{
getInstance().registerBundledRedstoneProvider( provider ); getInstance().registerBundledRedstoneProvider( provider );
} }
@ -179,7 +192,8 @@ public final class ComputerCraftAPI {
* capable of emitting bundled redstone at the location, -1 will be returned. * capable of emitting bundled redstone at the location, -1 will be returned.
* @see IBundledRedstoneProvider * @see IBundledRedstoneProvider
*/ */
public static int getBundledRedstoneOutput(@Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side) { public static int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side )
{
return getInstance().getBundledRedstoneOutput( world, pos, side ); return getInstance().getBundledRedstoneOutput( world, pos, side );
} }
@ -189,11 +203,13 @@ public final class ComputerCraftAPI {
* @param provider The media provider to register. * @param provider The media provider to register.
* @see IMediaProvider * @see IMediaProvider
*/ */
public static void registerMediaProvider(@Nonnull IMediaProvider provider) { public static void registerMediaProvider( @Nonnull IMediaProvider provider )
{
getInstance().registerMediaProvider( provider ); getInstance().registerMediaProvider( provider );
} }
public static void registerPocketUpgrade(@Nonnull IPocketUpgrade upgrade) { public static void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade )
{
getInstance().registerPocketUpgrade( upgrade ); getInstance().registerPocketUpgrade( upgrade );
} }
@ -202,11 +218,13 @@ public final class ComputerCraftAPI {
* *
* @return The global wireless network, or {@code null} if it could not be fetched. * @return The global wireless network, or {@code null} if it could not be fetched.
*/ */
public static IPacketNetwork getWirelessNetwork() { public static IPacketNetwork getWirelessNetwork()
{
return getInstance().getWirelessNetwork(); return getInstance().getWirelessNetwork();
} }
public static void registerAPIFactory(@Nonnull ILuaAPIFactory factory) { public static void registerAPIFactory( @Nonnull ILuaAPIFactory factory )
{
getInstance().registerAPIFactory( factory ); getInstance().registerAPIFactory( factory );
} }
@ -218,7 +236,8 @@ public final class ComputerCraftAPI {
* @see IWiredElement#getNode() * @see IWiredElement#getNode()
*/ */
@Nonnull @Nonnull
public static IWiredNode createWiredNodeForElement(@Nonnull IWiredElement element) { public static IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element )
{
return getInstance().createWiredNodeForElement( element ); return getInstance().createWiredNodeForElement( element );
} }
@ -232,11 +251,13 @@ public final class ComputerCraftAPI {
* @see IWiredElement#getNode() * @see IWiredElement#getNode()
*/ */
@Nullable @Nullable
public static IWiredElement getWiredElementAt(@Nonnull BlockView world, @Nonnull BlockPos pos, @Nonnull Direction side) { public static IWiredElement getWiredElementAt( @Nonnull BlockView world, @Nonnull BlockPos pos, @Nonnull Direction side )
{
return getInstance().getWiredElementAt( world, pos, side ); return getInstance().getWiredElementAt( world, pos, side );
} }
public interface IComputerCraftAPI { public interface IComputerCraftAPI
{
@Nonnull @Nonnull
String getInstalledVersion(); String getInstalledVersion();

View File

@ -6,12 +6,9 @@
package dan200.computercraft.api.client; package dan200.computercraft.api.client;
import java.util.Objects;
import javax.annotation.Nonnull;
import dan200.computercraft.fabric.mixin.AffineTransformationAccess; import dan200.computercraft.fabric.mixin.AffineTransformationAccess;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedModelManager; import net.minecraft.client.render.model.BakedModelManager;
@ -20,34 +17,39 @@ import net.minecraft.client.util.math.AffineTransformation;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.fabricmc.api.EnvType; import javax.annotation.Nonnull;
import net.fabricmc.api.Environment; import java.util.Objects;
/** /**
* A model to render, combined with a transformation matrix to apply. * A model to render, combined with a transformation matrix to apply.
*/ */
@Environment( EnvType.CLIENT ) @Environment( EnvType.CLIENT )
public final class TransformedModel { public final class TransformedModel
{
private final BakedModel model; private final BakedModel model;
private final AffineTransformation matrix; private final AffineTransformation matrix;
public TransformedModel(@Nonnull BakedModel model, @Nonnull AffineTransformation matrix) { public TransformedModel( @Nonnull BakedModel model, @Nonnull AffineTransformation matrix )
{
this.model = Objects.requireNonNull( model ); this.model = Objects.requireNonNull( model );
this.matrix = Objects.requireNonNull( matrix ); this.matrix = Objects.requireNonNull( matrix );
} }
public TransformedModel(@Nonnull BakedModel model) { public TransformedModel( @Nonnull BakedModel model )
{
this.model = Objects.requireNonNull( model ); this.model = Objects.requireNonNull( model );
this.matrix = AffineTransformation.identity(); this.matrix = AffineTransformation.identity();
} }
public static TransformedModel of(@Nonnull ModelIdentifier location) { public static TransformedModel of( @Nonnull ModelIdentifier location )
{
BakedModelManager modelManager = MinecraftClient.getInstance() BakedModelManager modelManager = MinecraftClient.getInstance()
.getBakedModelManager(); .getBakedModelManager();
return new TransformedModel( modelManager.getModel( location ) ); return new TransformedModel( modelManager.getModel( location ) );
} }
public static TransformedModel of(@Nonnull ItemStack item, @Nonnull AffineTransformation transform) { public static TransformedModel of( @Nonnull ItemStack item, @Nonnull AffineTransformation transform )
{
BakedModel model = MinecraftClient.getInstance() BakedModel model = MinecraftClient.getInstance()
.getItemRenderer() .getItemRenderer()
.getModels() .getModels()
@ -56,28 +58,37 @@ public final class TransformedModel {
} }
@Nonnull @Nonnull
public BakedModel getModel() { public BakedModel getModel()
{
return this.model; return this.model;
} }
@Nonnull @Nonnull
public AffineTransformation getMatrix() { public AffineTransformation getMatrix()
{
return this.matrix; return this.matrix;
} }
public void push(MatrixStack matrixStack) { public void push( MatrixStack matrixStack )
{
matrixStack.push(); matrixStack.push();
AffineTransformationAccess access = (AffineTransformationAccess) (Object) this.matrix; AffineTransformationAccess access = (AffineTransformationAccess) (Object) this.matrix;
if( access.getTranslation() != null ) if( access.getTranslation() != null )
{
matrixStack.translate( access.getTranslation().getX(), access.getTranslation().getY(), access.getTranslation().getZ() ); matrixStack.translate( access.getTranslation().getX(), access.getTranslation().getY(), access.getTranslation().getZ() );
}
matrixStack.multiply( this.matrix.getRotation2() ); matrixStack.multiply( this.matrix.getRotation2() );
if( access.getScale() != null ) if( access.getScale() != null )
{
matrixStack.scale( access.getScale().getX(), access.getScale().getY(), access.getScale().getZ() ); matrixStack.scale( access.getScale().getX(), access.getScale().getY(), access.getScale().getZ() );
}
if( access.getRotation1() != null ) if( access.getRotation1() != null )
{
matrixStack.multiply( access.getRotation1() ); matrixStack.multiply( access.getRotation1() );
} }
} }
}

View File

@ -13,59 +13,70 @@ import java.time.Instant;
/** /**
* A simple version of {@link BasicFileAttributes}, which provides what information a {@link IMount} already exposes. * A simple version of {@link BasicFileAttributes}, which provides what information a {@link IMount} already exposes.
*/ */
final class FileAttributes implements BasicFileAttributes { final class FileAttributes implements BasicFileAttributes
{
private static final FileTime EPOCH = FileTime.from( Instant.EPOCH ); private static final FileTime EPOCH = FileTime.from( Instant.EPOCH );
private final boolean isDirectory; private final boolean isDirectory;
private final long size; private final long size;
FileAttributes(boolean isDirectory, long size) { FileAttributes( boolean isDirectory, long size )
{
this.isDirectory = isDirectory; this.isDirectory = isDirectory;
this.size = size; this.size = size;
} }
@Override @Override
public FileTime lastModifiedTime() { public FileTime lastModifiedTime()
{
return EPOCH; return EPOCH;
} }
@Override @Override
public FileTime lastAccessTime() { public FileTime lastAccessTime()
{
return EPOCH; return EPOCH;
} }
@Override @Override
public FileTime creationTime() { public FileTime creationTime()
{
return EPOCH; return EPOCH;
} }
@Override @Override
public boolean isRegularFile() { public boolean isRegularFile()
{
return !this.isDirectory; return !this.isDirectory;
} }
@Override @Override
public boolean isDirectory() { public boolean isDirectory()
{
return this.isDirectory; return this.isDirectory;
} }
@Override @Override
public boolean isSymbolicLink() { public boolean isSymbolicLink()
{
return false; return false;
} }
@Override @Override
public boolean isOther() { public boolean isOther()
{
return false; return false;
} }
@Override @Override
public long size() { public long size()
{
return this.size; return this.size;
} }
@Override @Override
public Object fileKey() { public Object fileKey()
{
return null; return null;
} }
} }

View File

@ -6,34 +6,37 @@
package dan200.computercraft.api.filesystem; package dan200.computercraft.api.filesystem;
import java.io.IOException;
import java.util.Objects;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Objects;
/** /**
* An {@link IOException} which occurred on a specific file. * An {@link IOException} which occurred on a specific file.
* *
* This may be thrown from a {@link IMount} or {@link IWritableMount} to give more information about a failure. * This may be thrown from a {@link IMount} or {@link IWritableMount} to give more information about a failure.
*/ */
public class FileOperationException extends IOException { public class FileOperationException extends IOException
{
private static final long serialVersionUID = -8809108200853029849L; private static final long serialVersionUID = -8809108200853029849L;
private final String filename; private final String filename;
public FileOperationException(@Nullable String filename, @Nonnull String message) { public FileOperationException( @Nullable String filename, @Nonnull String message )
{
super( Objects.requireNonNull( message, "message cannot be null" ) ); super( Objects.requireNonNull( message, "message cannot be null" ) );
this.filename = filename; this.filename = filename;
} }
public FileOperationException(@Nonnull String message) { public FileOperationException( @Nonnull String message )
{
super( Objects.requireNonNull( message, "message cannot be null" ) ); super( Objects.requireNonNull( message, "message cannot be null" ) );
this.filename = null; this.filename = null;
} }
@Nullable @Nullable
public String getFilename() { public String getFilename()
{
return this.filename; return this.filename;
} }
} }

View File

@ -13,7 +13,8 @@ import java.io.IOException;
* *
* This exists for use by various APIs - one should not attempt to mount it. * This exists for use by various APIs - one should not attempt to mount it.
*/ */
public interface IFileSystem extends IWritableMount { public interface IFileSystem extends IWritableMount
{
/** /**
* Combine two paths together, reducing them into a normalised form. * Combine two paths together, reducing them into a normalised form.
* *

View File

@ -6,18 +6,16 @@
package dan200.computercraft.api.filesystem; package dan200.computercraft.api.filesystem;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IComputerAccess;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IComputerAccess;
import net.minecraft.world.World;
/** /**
* Represents a read only part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)}. * Represents a read only part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)}.
* *
@ -29,7 +27,8 @@ import net.minecraft.world.World;
* @see IComputerAccess#mount(String, IMount) * @see IComputerAccess#mount(String, IMount)
* @see IWritableMount * @see IWritableMount
*/ */
public interface IMount { public interface IMount
{
/** /**
* Returns the file names of all the files in a directory. * Returns the file names of all the files in a directory.
* *
@ -58,8 +57,10 @@ public interface IMount {
* @throws IOException If the file does not exist, or attributes could not be fetched. * @throws IOException If the file does not exist, or attributes could not be fetched.
*/ */
@Nonnull @Nonnull
default BasicFileAttributes getAttributes(@Nonnull String path) throws IOException { default BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException
if (!this.exists(path)) { {
if( !this.exists( path ) )
{
throw new FileOperationException( path, "No such file" ); throw new FileOperationException( path, "No such file" );
} }
return new FileAttributes( this.isDirectory( path ), this.getSize( path ) ); return new FileAttributes( this.isDirectory( path ), this.getSize( path ) );

View File

@ -6,18 +6,16 @@
package dan200.computercraft.api.filesystem; package dan200.computercraft.api.filesystem;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IComputerAccess;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.channels.WritableByteChannel; import java.nio.channels.WritableByteChannel;
import java.util.OptionalLong; import java.util.OptionalLong;
import javax.annotation.Nonnull;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IComputerAccess;
import net.minecraft.world.World;
/** /**
* Represents a part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)} or {@link * Represents a part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)} or {@link
* IComputerAccess#mountWritable(String, IWritableMount)}, that can also be written to. * IComputerAccess#mountWritable(String, IWritableMount)}, that can also be written to.
@ -30,7 +28,8 @@ import net.minecraft.world.World;
* @see IComputerAccess#mountWritable(String, IWritableMount) * @see IComputerAccess#mountWritable(String, IWritableMount)
* @see IMount * @see IMount
*/ */
public interface IWritableMount extends IMount { public interface IWritableMount extends IMount
{
/** /**
* Creates a directory at a given path inside the virtual file system. * Creates a directory at a given path inside the virtual file system.
* *
@ -84,7 +83,8 @@ public interface IWritableMount extends IMount {
* @return The capacity of this mount, in bytes. * @return The capacity of this mount, in bytes.
*/ */
@Nonnull @Nonnull
default OptionalLong getCapacity() { default OptionalLong getCapacity()
{
return OptionalLong.empty(); return OptionalLong.empty();
} }
} }

View File

@ -6,19 +6,19 @@
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import static dan200.computercraft.api.lua.LuaValues.checkFinite; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import javax.annotation.Nonnull; import static dan200.computercraft.api.lua.LuaValues.checkFinite;
import javax.annotation.Nullable;
/** /**
* The arguments passed to a function. * The arguments passed to a function.
*/ */
public interface IArguments { public interface IArguments
{
/** /**
* Drop a number of arguments. The returned arguments instance will access arguments at position {@code i + count}, rather than {@code i}. However, * Drop a number of arguments. The returned arguments instance will access arguments at position {@code i + count}, rather than {@code i}. However,
* errors will still use the given argument index. * errors will still use the given argument index.
@ -28,9 +28,11 @@ public interface IArguments {
*/ */
IArguments drop( int count ); IArguments drop( int count );
default Object[] getAll() { default Object[] getAll()
{
Object[] result = new Object[this.count()]; Object[] result = new Object[this.count()];
for (int i = 0; i < result.length; i++) { for( int i = 0; i < result.length; i++ )
{
result[i] = this.get( i ); result[i] = this.get( i );
} }
return result; return result;
@ -67,7 +69,8 @@ public interface IArguments {
* @return The argument's value. * @return The argument's value.
* @throws LuaException If the value is not an integer. * @throws LuaException If the value is not an integer.
*/ */
default int getInt(int index) throws LuaException { default int getInt( int index ) throws LuaException
{
return (int) this.getLong( index ); return (int) this.getLong( index );
} }
@ -78,9 +81,11 @@ public interface IArguments {
* @return The argument's value. * @return The argument's value.
* @throws LuaException If the value is not a long. * @throws LuaException If the value is not a long.
*/ */
default long getLong(int index) throws LuaException { default long getLong( int index ) throws LuaException
{
Object value = this.get( index ); Object value = this.get( index );
if (!(value instanceof Number)) { if( !(value instanceof Number) )
{
throw LuaValues.badArgumentOf( index, "number", value ); throw LuaValues.badArgumentOf( index, "number", value );
} }
return LuaValues.checkFiniteNum( index, (Number) value ) return LuaValues.checkFiniteNum( index, (Number) value )
@ -94,7 +99,8 @@ public interface IArguments {
* @return The argument's value. * @return The argument's value.
* @throws LuaException If the value is not finite. * @throws LuaException If the value is not finite.
*/ */
default double getFiniteDouble(int index) throws LuaException { default double getFiniteDouble( int index ) throws LuaException
{
return checkFinite( index, this.getDouble( index ) ); return checkFinite( index, this.getDouble( index ) );
} }
@ -106,9 +112,11 @@ public interface IArguments {
* @throws LuaException If the value is not a number. * @throws LuaException If the value is not a number.
* @see #getFiniteDouble(int) if you require this to be finite (i.e. not infinite or NaN). * @see #getFiniteDouble(int) if you require this to be finite (i.e. not infinite or NaN).
*/ */
default double getDouble(int index) throws LuaException { default double getDouble( int index ) throws LuaException
{
Object value = this.get( index ); Object value = this.get( index );
if (!(value instanceof Number)) { if( !(value instanceof Number) )
{
throw LuaValues.badArgumentOf( index, "number", value ); throw LuaValues.badArgumentOf( index, "number", value );
} }
return ((Number) value).doubleValue(); return ((Number) value).doubleValue();
@ -121,9 +129,11 @@ public interface IArguments {
* @return The argument's value. * @return The argument's value.
* @throws LuaException If the value is not a boolean. * @throws LuaException If the value is not a boolean.
*/ */
default boolean getBoolean(int index) throws LuaException { default boolean getBoolean( int index ) throws LuaException
{
Object value = this.get( index ); Object value = this.get( index );
if (!(value instanceof Boolean)) { if( !(value instanceof Boolean) )
{
throw LuaValues.badArgumentOf( index, "boolean", value ); throw LuaValues.badArgumentOf( index, "boolean", value );
} }
return (Boolean) value; return (Boolean) value;
@ -137,7 +147,8 @@ public interface IArguments {
* @throws LuaException If the value is not a string. * @throws LuaException If the value is not a string.
*/ */
@Nonnull @Nonnull
default ByteBuffer getBytes(int index) throws LuaException { default ByteBuffer getBytes( int index ) throws LuaException
{
return LuaValues.encode( this.getString( index ) ); return LuaValues.encode( this.getString( index ) );
} }
@ -149,9 +160,11 @@ public interface IArguments {
* @throws LuaException If the value is not a string. * @throws LuaException If the value is not a string.
*/ */
@Nonnull @Nonnull
default String getString(int index) throws LuaException { default String getString( int index ) throws LuaException
{
Object value = this.get( index ); Object value = this.get( index );
if (!(value instanceof String)) { if( !(value instanceof String) )
{
throw LuaValues.badArgumentOf( index, "string", value ); throw LuaValues.badArgumentOf( index, "string", value );
} }
return (String) value; return (String) value;
@ -167,7 +180,8 @@ public interface IArguments {
* @throws LuaException If the value is not a string or not a valid option for this enum. * @throws LuaException If the value is not a string or not a valid option for this enum.
*/ */
@Nonnull @Nonnull
default <T extends Enum<T>> T getEnum(int index, Class<T> klass) throws LuaException { default <T extends Enum<T>> T getEnum( int index, Class<T> klass ) throws LuaException
{
return LuaValues.checkEnum( index, klass, this.getString( index ) ); return LuaValues.checkEnum( index, klass, this.getString( index ) );
} }
@ -179,9 +193,11 @@ public interface IArguments {
* @throws LuaException If the value is not a table. * @throws LuaException If the value is not a table.
*/ */
@Nonnull @Nonnull
default Map<?, ?> getTable(int index) throws LuaException { default Map<?, ?> getTable( int index ) throws LuaException
{
Object value = this.get( index ); Object value = this.get( index );
if (!(value instanceof Map)) { if( !(value instanceof Map) )
{
throw LuaValues.badArgumentOf( index, "table", value ); throw LuaValues.badArgumentOf( index, "table", value );
} }
return (Map<?, ?>) value; return (Map<?, ?>) value;
@ -194,7 +210,8 @@ public interface IArguments {
* @return The argument's value, or {@link Optional#empty()} if not present. This is a <em>read only</em> buffer. * @return The argument's value, or {@link Optional#empty()} if not present. This is a <em>read only</em> buffer.
* @throws LuaException If the value is not a string. * @throws LuaException If the value is not a string.
*/ */
default Optional<ByteBuffer> optBytes(int index) throws LuaException { default Optional<ByteBuffer> optBytes( int index ) throws LuaException
{
return this.optString( index ).map( LuaValues::encode ); return this.optString( index ).map( LuaValues::encode );
} }
@ -205,12 +222,15 @@ public interface IArguments {
* @return The argument's value, or {@link Optional#empty()} if not present. * @return The argument's value, or {@link Optional#empty()} if not present.
* @throws LuaException If the value is not a string. * @throws LuaException If the value is not a string.
*/ */
default Optional<String> optString(int index) throws LuaException { default Optional<String> optString( int index ) throws LuaException
{
Object value = this.get( index ); Object value = this.get( index );
if (value == null) { if( value == null )
{
return Optional.empty(); return Optional.empty();
} }
if (!(value instanceof String)) { if( !(value instanceof String) )
{
throw LuaValues.badArgumentOf( index, "string", value ); throw LuaValues.badArgumentOf( index, "string", value );
} }
return Optional.of( (String) value ); return Optional.of( (String) value );
@ -226,7 +246,8 @@ public interface IArguments {
* @throws LuaException If the value is not a string or not a valid option for this enum. * @throws LuaException If the value is not a string or not a valid option for this enum.
*/ */
@Nonnull @Nonnull
default <T extends Enum<T>> Optional<T> optEnum(int index, Class<T> klass) throws LuaException { default <T extends Enum<T>> Optional<T> optEnum( int index, Class<T> klass ) throws LuaException
{
Optional<String> str = this.optString( index ); Optional<String> str = this.optString( index );
return str.isPresent() ? Optional.of( LuaValues.checkEnum( index, klass, str.get() ) ) : Optional.empty(); return str.isPresent() ? Optional.of( LuaValues.checkEnum( index, klass, str.get() ) ) : Optional.empty();
} }
@ -239,7 +260,8 @@ public interface IArguments {
* @return The argument's value, or {@code def} if none was provided. * @return The argument's value, or {@code def} if none was provided.
* @throws LuaException If the value is not a number. * @throws LuaException If the value is not a number.
*/ */
default double optDouble(int index, double def) throws LuaException { default double optDouble( int index, double def ) throws LuaException
{
return this.optDouble( index ).orElse( def ); return this.optDouble( index ).orElse( def );
} }
@ -251,12 +273,15 @@ public interface IArguments {
* @throws LuaException If the value is not a number. * @throws LuaException If the value is not a number.
*/ */
@Nonnull @Nonnull
default Optional<Double> optDouble(int index) throws LuaException { default Optional<Double> optDouble( int index ) throws LuaException
{
Object value = this.get( index ); Object value = this.get( index );
if (value == null) { if( value == null )
{
return Optional.empty(); return Optional.empty();
} }
if (!(value instanceof Number)) { if( !(value instanceof Number) )
{
throw LuaValues.badArgumentOf( index, "number", value ); throw LuaValues.badArgumentOf( index, "number", value );
} }
return Optional.of( ((Number) value).doubleValue() ); return Optional.of( ((Number) value).doubleValue() );
@ -270,7 +295,8 @@ public interface IArguments {
* @return The argument's value, or {@code def} if none was provided. * @return The argument's value, or {@code def} if none was provided.
* @throws LuaException If the value is not a number. * @throws LuaException If the value is not a number.
*/ */
default int optInt(int index, int def) throws LuaException { default int optInt( int index, int def ) throws LuaException
{
return this.optInt( index ).orElse( def ); return this.optInt( index ).orElse( def );
} }
@ -282,7 +308,8 @@ public interface IArguments {
* @throws LuaException If the value is not a number. * @throws LuaException If the value is not a number.
*/ */
@Nonnull @Nonnull
default Optional<Integer> optInt(int index) throws LuaException { default Optional<Integer> optInt( int index ) throws LuaException
{
return this.optLong( index ).map( Long::intValue ); return this.optLong( index ).map( Long::intValue );
} }
@ -293,12 +320,15 @@ public interface IArguments {
* @return The argument's value, or {@link Optional#empty()} if not present. * @return The argument's value, or {@link Optional#empty()} if not present.
* @throws LuaException If the value is not a number. * @throws LuaException If the value is not a number.
*/ */
default Optional<Long> optLong(int index) throws LuaException { default Optional<Long> optLong( int index ) throws LuaException
{
Object value = this.get( index ); Object value = this.get( index );
if (value == null) { if( value == null )
{
return Optional.empty(); return Optional.empty();
} }
if (!(value instanceof Number)) { if( !(value instanceof Number) )
{
throw LuaValues.badArgumentOf( index, "number", value ); throw LuaValues.badArgumentOf( index, "number", value );
} }
return Optional.of( LuaValues.checkFiniteNum( index, (Number) value ) return Optional.of( LuaValues.checkFiniteNum( index, (Number) value )
@ -313,7 +343,8 @@ public interface IArguments {
* @return The argument's value, or {@code def} if none was provided. * @return The argument's value, or {@code def} if none was provided.
* @throws LuaException If the value is not a number. * @throws LuaException If the value is not a number.
*/ */
default long optLong(int index, long def) throws LuaException { default long optLong( int index, long def ) throws LuaException
{
return this.optLong( index ).orElse( def ); return this.optLong( index ).orElse( def );
} }
@ -325,7 +356,8 @@ public interface IArguments {
* @return The argument's value, or {@code def} if none was provided. * @return The argument's value, or {@code def} if none was provided.
* @throws LuaException If the value is not finite. * @throws LuaException If the value is not finite.
*/ */
default double optFiniteDouble(int index, double def) throws LuaException { default double optFiniteDouble( int index, double def ) throws LuaException
{
return this.optFiniteDouble( index ).orElse( def ); return this.optFiniteDouble( index ).orElse( def );
} }
@ -336,9 +368,11 @@ public interface IArguments {
* @return The argument's value, or {@link Optional#empty()} if not present. * @return The argument's value, or {@link Optional#empty()} if not present.
* @throws LuaException If the value is not finite. * @throws LuaException If the value is not finite.
*/ */
default Optional<Double> optFiniteDouble(int index) throws LuaException { default Optional<Double> optFiniteDouble( int index ) throws LuaException
{
Optional<Double> value = this.optDouble( index ); Optional<Double> value = this.optDouble( index );
if (value.isPresent()) { if( value.isPresent() )
{
LuaValues.checkFiniteNum( index, value.get() ); LuaValues.checkFiniteNum( index, value.get() );
} }
return value; return value;
@ -352,7 +386,8 @@ public interface IArguments {
* @return The argument's value, or {@code def} if none was provided. * @return The argument's value, or {@code def} if none was provided.
* @throws LuaException If the value is not a boolean. * @throws LuaException If the value is not a boolean.
*/ */
default boolean optBoolean(int index, boolean def) throws LuaException { default boolean optBoolean( int index, boolean def ) throws LuaException
{
return this.optBoolean( index ).orElse( def ); return this.optBoolean( index ).orElse( def );
} }
@ -363,12 +398,15 @@ public interface IArguments {
* @return The argument's value, or {@link Optional#empty()} if not present. * @return The argument's value, or {@link Optional#empty()} if not present.
* @throws LuaException If the value is not a boolean. * @throws LuaException If the value is not a boolean.
*/ */
default Optional<Boolean> optBoolean(int index) throws LuaException { default Optional<Boolean> optBoolean( int index ) throws LuaException
{
Object value = this.get( index ); Object value = this.get( index );
if (value == null) { if( value == null )
{
return Optional.empty(); return Optional.empty();
} }
if (!(value instanceof Boolean)) { if( !(value instanceof Boolean) )
{
throw LuaValues.badArgumentOf( index, "boolean", value ); throw LuaValues.badArgumentOf( index, "boolean", value );
} }
return Optional.of( (Boolean) value ); return Optional.of( (Boolean) value );
@ -382,7 +420,8 @@ public interface IArguments {
* @return The argument's value, or {@code def} if none was provided. * @return The argument's value, or {@code def} if none was provided.
* @throws LuaException If the value is not a string. * @throws LuaException If the value is not a string.
*/ */
default String optString(int index, String def) throws LuaException { default String optString( int index, String def ) throws LuaException
{
return this.optString( index ).orElse( def ); return this.optString( index ).orElse( def );
} }
@ -394,7 +433,8 @@ public interface IArguments {
* @return The argument's value, or {@code def} if none was provided. * @return The argument's value, or {@code def} if none was provided.
* @throws LuaException If the value is not a table. * @throws LuaException If the value is not a table.
*/ */
default Map<?, ?> optTable(int index, Map<Object, Object> def) throws LuaException { default Map<?, ?> optTable( int index, Map<Object, Object> def ) throws LuaException
{
return this.optTable( index ).orElse( def ); return this.optTable( index ).orElse( def );
} }
@ -405,12 +445,15 @@ public interface IArguments {
* @return The argument's value, or {@link Optional#empty()} if not present. * @return The argument's value, or {@link Optional#empty()} if not present.
* @throws LuaException If the value is not a table. * @throws LuaException If the value is not a table.
*/ */
default Optional<Map<?, ?>> optTable(int index) throws LuaException { default Optional<Map<?, ?>> optTable( int index ) throws LuaException
{
Object value = this.get( index ); Object value = this.get( index );
if (value == null) { if( value == null )
{
return Optional.empty(); return Optional.empty();
} }
if (!(value instanceof Map)) { if( !(value instanceof Map) )
{
throw LuaValues.badArgumentOf( index, "map", value ); throw LuaValues.badArgumentOf( index, "map", value );
} }
return Optional.of( (Map<?, ?>) value ); return Optional.of( (Map<?, ?>) value );

View File

@ -6,15 +6,16 @@
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import javax.annotation.Nullable;
import dan200.computercraft.api.filesystem.IFileSystem; import dan200.computercraft.api.filesystem.IFileSystem;
import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IComputerAccess;
import javax.annotation.Nullable;
/** /**
* An interface passed to {@link ILuaAPIFactory} in order to provide additional information about a computer. * An interface passed to {@link ILuaAPIFactory} in order to provide additional information about a computer.
*/ */
public interface IComputerSystem extends IComputerAccess { public interface IComputerSystem extends IComputerAccess
{
/** /**
* Get the file system for this computer. * Get the file system for this computer.
* *

View File

@ -6,17 +6,18 @@
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import javax.annotation.Nonnull;
import dan200.computercraft.api.peripheral.IDynamicPeripheral; import dan200.computercraft.api.peripheral.IDynamicPeripheral;
import javax.annotation.Nonnull;
/** /**
* An interface for representing custom objects returned by peripherals or other Lua objects. * An interface for representing custom objects returned by peripherals or other Lua objects.
* *
* Generally, one does not need to implement this type - it is sufficient to return an object with some methods annotated with {@link LuaFunction}. {@link * Generally, one does not need to implement this type - it is sufficient to return an object with some methods annotated with {@link LuaFunction}. {@link
* IDynamicLuaObject} is useful when you wish your available methods to change at runtime. * IDynamicLuaObject} is useful when you wish your available methods to change at runtime.
*/ */
public interface IDynamicLuaObject { public interface IDynamicLuaObject
{
/** /**
* Get the names of the methods that this object implements. This should not change over the course of the object's lifetime. * Get the names of the methods that this object implements. This should not change over the course of the object's lifetime.
* *

View File

@ -18,7 +18,8 @@ import dan200.computercraft.api.ComputerCraftAPI;
* @see ILuaAPIFactory * @see ILuaAPIFactory
* @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory) * @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
*/ */
public interface ILuaAPI { public interface ILuaAPI
{
/** /**
* Get the globals this API will be assigned to. This will override any other global, so you should * Get the globals this API will be assigned to. This will override any other global, so you should
* *
@ -31,13 +32,15 @@ public interface ILuaAPI {
* *
* One should only interact with the file system. * One should only interact with the file system.
*/ */
default void startup() { default void startup()
{
} }
/** /**
* Called every time the computer is ticked. This can be used to process various. * Called every time the computer is ticked. This can be used to process various.
*/ */
default void update() { default void update()
{
} }
/** /**
@ -45,6 +48,7 @@ public interface ILuaAPI {
* *
* This should reset the state of the object, disposing any remaining file handles, or other resources. * This should reset the state of the object, disposing any remaining file handles, or other resources.
*/ */
default void shutdown() { default void shutdown()
{
} }
} }

View File

@ -6,11 +6,11 @@
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import dan200.computercraft.api.ComputerCraftAPI;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import dan200.computercraft.api.ComputerCraftAPI;
/** /**
* Construct an {@link ILuaAPI} for a specific computer. * Construct an {@link ILuaAPI} for a specific computer.
* *
@ -18,7 +18,8 @@ import dan200.computercraft.api.ComputerCraftAPI;
* @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory) * @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
*/ */
@FunctionalInterface @FunctionalInterface
public interface ILuaAPIFactory { public interface ILuaAPIFactory
{
/** /**
* Create a new API instance for a given computer. * Create a new API instance for a given computer.
* *

View File

@ -13,7 +13,8 @@ import javax.annotation.Nonnull;
* *
* @see MethodResult#yield(Object[], ILuaCallback) * @see MethodResult#yield(Object[], ILuaCallback)
*/ */
public interface ILuaCallback { public interface ILuaCallback
{
/** /**
* Resume this coroutine. * Resume this coroutine.
* *

View File

@ -12,7 +12,8 @@ import javax.annotation.Nonnull;
* An interface passed to peripherals and {@link IDynamicLuaObject}s by computers or turtles, providing methods that allow the peripheral call to interface * An interface passed to peripherals and {@link IDynamicLuaObject}s by computers or turtles, providing methods that allow the peripheral call to interface
* with the computer. * with the computer.
*/ */
public interface ILuaContext { public interface ILuaContext
{
/** /**
* Queue a task to be executed on the main server thread at the beginning of next tick, but do not wait for it to complete. This should be used when you * Queue a task to be executed on the main server thread at the beginning of next tick, but do not wait for it to complete. This should be used when you
* need to interact with the world in a thread-safe manner but do not care about the result or you wish to run asynchronously. * need to interact with the world in a thread-safe manner but do not care about the result or you wish to run asynchronously.

View File

@ -15,7 +15,8 @@ import javax.annotation.Nonnull;
* @see MethodResult#of(Object) * @see MethodResult#of(Object)
*/ */
@FunctionalInterface @FunctionalInterface
public interface ILuaFunction { public interface ILuaFunction
{
/** /**
* Call this function with a series of arguments. Note, this will <em>always</em> be called on the computer thread, and so its implementation must be * Call this function with a series of arguments. Note, this will <em>always</em> be called on the computer thread, and so its implementation must be
* thread-safe. * thread-safe.

View File

@ -8,7 +8,8 @@ package dan200.computercraft.api.lua;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public interface ILuaObject { public interface ILuaObject
{
@Nonnull @Nonnull
String[] getMethodNames(); String[] getMethodNames();

View File

@ -15,7 +15,8 @@ import javax.annotation.Nullable;
* @see ILuaContext#issueMainThreadTask(ILuaTask) * @see ILuaContext#issueMainThreadTask(ILuaTask)
*/ */
@FunctionalInterface @FunctionalInterface
public interface ILuaTask { public interface ILuaTask
{
/** /**
* Execute this task. * Execute this task.
* *

View File

@ -11,18 +11,21 @@ import javax.annotation.Nullable;
/** /**
* An exception representing an error in Lua, like that raised by the {@code error()} function. * An exception representing an error in Lua, like that raised by the {@code error()} function.
*/ */
public class LuaException extends Exception { public class LuaException extends Exception
{
private static final long serialVersionUID = -6136063076818512651L; private static final long serialVersionUID = -6136063076818512651L;
private final boolean hasLevel; private final boolean hasLevel;
private final int level; private final int level;
public LuaException(@Nullable String message) { public LuaException( @Nullable String message )
{
super( message ); super( message );
this.hasLevel = false; this.hasLevel = false;
this.level = 1; this.level = 1;
} }
public LuaException(@Nullable String message, int level) { public LuaException( @Nullable String message, int level )
{
super( message ); super( message );
this.hasLevel = true; this.hasLevel = true;
this.level = level; this.level = level;
@ -33,7 +36,8 @@ public class LuaException extends Exception {
* *
* @return Whether this has an explicit level. * @return Whether this has an explicit level.
*/ */
public boolean hasLevel() { public boolean hasLevel()
{
return this.hasLevel; return this.hasLevel;
} }
@ -42,7 +46,8 @@ public class LuaException extends Exception {
* *
* @return The level to raise the error at. * @return The level to raise the error at.
*/ */
public int getLevel() { public int getLevel()
{
return this.level; return this.level;
} }
} }

View File

@ -6,17 +6,13 @@
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;
import java.util.Optional;
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 java.lang.annotation.*;
import java.util.Map;
import java.util.Optional;
/** /**
* Used to mark a Java function which is callable from Lua. * Used to mark a Java function which is callable from Lua.
* *
@ -43,7 +39,8 @@ import dan200.computercraft.api.peripheral.IPeripheral;
@Documented @Documented
@Retention( RetentionPolicy.RUNTIME ) @Retention( RetentionPolicy.RUNTIME )
@Target( ElementType.METHOD ) @Target( ElementType.METHOD )
public @interface LuaFunction { public @interface LuaFunction
{
/** /**
* Explicitly specify the method names of this function. If not given, it uses the name of the annotated method. * Explicitly specify the method names of this function. If not given, it uses the name of the annotated method.
* *

View File

@ -6,19 +6,20 @@
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import java.nio.ByteBuffer;
import java.util.Map;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.nio.ByteBuffer;
import java.util.Map;
/** /**
* Various utility functions for operating with Lua values. * Various utility functions for operating with Lua values.
* *
* @see IArguments * @see IArguments
*/ */
public final class LuaValues { public final class LuaValues
private LuaValues() { {
private LuaValues()
{
} }
/** /**
@ -28,9 +29,11 @@ public final class LuaValues {
* @return The encoded string. * @return The encoded string.
*/ */
@Nonnull @Nonnull
public static ByteBuffer encode(@Nonnull String string) { public static ByteBuffer encode( @Nonnull String string )
{
byte[] chars = new byte[string.length()]; byte[] chars = new byte[string.length()];
for (int i = 0; i < chars.length; i++) { for( int i = 0; i < chars.length; i++ )
{
char c = string.charAt( i ); char c = string.charAt( i );
chars[i] = c < 256 ? (byte) c : 63; chars[i] = c < 256 ? (byte) c : 63;
} }
@ -48,7 +51,8 @@ public final class LuaValues {
* @return The constructed exception, which should be thrown immediately. * @return The constructed exception, which should be thrown immediately.
*/ */
@Nonnull @Nonnull
public static LuaException badArgumentOf(int index, @Nonnull String expected, @Nullable Object actual) { public static LuaException badArgumentOf( int index, @Nonnull String expected, @Nullable Object actual )
{
return badArgument( index, expected, getType( actual ) ); return badArgument( index, expected, getType( actual ) );
} }
@ -61,7 +65,8 @@ public final class LuaValues {
* @return The constructed exception, which should be thrown immediately. * @return The constructed exception, which should be thrown immediately.
*/ */
@Nonnull @Nonnull
public static LuaException badArgument(int index, @Nonnull String expected, @Nonnull String actual) { public static LuaException badArgument( int index, @Nonnull String expected, @Nonnull String actual )
{
return new LuaException( "bad argument #" + (index + 1) + " (" + expected + " expected, got " + actual + ")" ); return new LuaException( "bad argument #" + (index + 1) + " (" + expected + " expected, got " + actual + ")" );
} }
@ -72,20 +77,26 @@ public final class LuaValues {
* @return A string representation of the given value's type, in a similar format to that provided by Lua's {@code type} function. * @return A string representation of the given value's type, in a similar format to that provided by Lua's {@code type} function.
*/ */
@Nonnull @Nonnull
public static String getType(@Nullable Object value) { public static String getType( @Nullable Object value )
if (value == null) { {
if( value == null )
{
return "nil"; return "nil";
} }
if (value instanceof String) { if( value instanceof String )
{
return "string"; return "string";
} }
if (value instanceof Boolean) { if( value instanceof Boolean )
{
return "boolean"; return "boolean";
} }
if (value instanceof Number) { if( value instanceof Number )
{
return "number"; return "number";
} }
if (value instanceof Map) { if( value instanceof Map )
{
return "table"; return "table";
} }
return "userdata"; return "userdata";
@ -99,7 +110,8 @@ public final class LuaValues {
* @return The input {@code value}. * @return The input {@code value}.
* @throws LuaException If this is not a finite number. * @throws LuaException If this is not a finite number.
*/ */
public static Number checkFiniteNum(int index, Number value) throws LuaException { public static Number checkFiniteNum( int index, Number value ) throws LuaException
{
checkFinite( index, value.doubleValue() ); checkFinite( index, value.doubleValue() );
return value; return value;
} }
@ -112,8 +124,10 @@ public final class LuaValues {
* @return The input {@code value}. * @return The input {@code value}.
* @throws LuaException If this is not a finite number. * @throws LuaException If this is not a finite number.
*/ */
public static double checkFinite(int index, double value) throws LuaException { public static double checkFinite( int index, double value ) throws LuaException
if (!Double.isFinite(value)) { {
if( !Double.isFinite( value ) )
{
throw badArgument( index, "number", getNumericType( value ) ); throw badArgument( index, "number", getNumericType( value ) );
} }
return value; return value;
@ -127,14 +141,18 @@ public final class LuaValues {
* @return This value's numeric type. * @return This value's numeric type.
*/ */
@Nonnull @Nonnull
public static String getNumericType(double value) { public static String getNumericType( double value )
if (Double.isNaN(value)) { {
if( Double.isNaN( value ) )
{
return "nan"; return "nan";
} }
if (value == Double.POSITIVE_INFINITY) { if( value == Double.POSITIVE_INFINITY )
{
return "inf"; return "inf";
} }
if (value == Double.NEGATIVE_INFINITY) { if( value == Double.NEGATIVE_INFINITY )
{
return "-inf"; return "-inf";
} }
return "number"; return "number";
@ -150,10 +168,13 @@ public final class LuaValues {
* @return The parsed enum value. * @return The parsed enum value.
* @throws LuaException If this is not a known enum value. * @throws LuaException If this is not a known enum value.
*/ */
public static <T extends Enum<T>> T checkEnum(int index, Class<T> klass, String value) throws LuaException { public static <T extends Enum<T>> T checkEnum( int index, Class<T> klass, String value ) throws LuaException
for (T possibility : klass.getEnumConstants()) { {
for( T possibility : klass.getEnumConstants() )
{
if( possibility.name() if( possibility.name()
.equalsIgnoreCase(value)) { .equalsIgnoreCase( value ) )
{
return possibility; return possibility;
} }
} }

View File

@ -6,36 +6,38 @@
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import dan200.computercraft.api.peripheral.IComputerAccess;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import dan200.computercraft.api.peripheral.IComputerAccess;
/** /**
* The result of invoking a Lua method. * The result of invoking a Lua method.
* *
* Method results either return a value immediately ({@link #of(Object...)} or yield control to the parent coroutine. When the current coroutine is resumed, * Method results either return a value immediately ({@link #of(Object...)} or yield control to the parent coroutine. When the current coroutine is resumed,
* we invoke the provided {@link ILuaCallback#resume(Object[])} callback. * we invoke the provided {@link ILuaCallback#resume(Object[])} callback.
*/ */
public final class MethodResult { public final class MethodResult
{
private static final MethodResult empty = new MethodResult( null, null ); private static final MethodResult empty = new MethodResult( null, null );
private final Object[] result; private final Object[] result;
private final ILuaCallback callback; private final ILuaCallback callback;
private final int adjust; private final int adjust;
private MethodResult(Object[] arguments, ILuaCallback callback) { private MethodResult( Object[] arguments, ILuaCallback callback )
{
this.result = arguments; this.result = arguments;
this.callback = callback; this.callback = callback;
this.adjust = 0; this.adjust = 0;
} }
private MethodResult(Object[] arguments, ILuaCallback callback, int adjust) { private MethodResult( Object[] arguments, ILuaCallback callback, int adjust )
{
this.result = arguments; this.result = arguments;
this.callback = callback; this.callback = callback;
this.adjust = adjust; this.adjust = adjust;
@ -47,7 +49,8 @@ public final class MethodResult {
* @return A method result which returns immediately with no values. * @return A method result which returns immediately with no values.
*/ */
@Nonnull @Nonnull
public static MethodResult of() { public static MethodResult of()
{
return empty; return empty;
} }
@ -64,7 +67,8 @@ public final class MethodResult {
* @return A method result which returns immediately with the given value. * @return A method result which returns immediately with the given value.
*/ */
@Nonnull @Nonnull
public static MethodResult of(@Nullable Object value) { public static MethodResult of( @Nullable Object value )
{
return new MethodResult( new Object[] { value }, null ); return new MethodResult( new Object[] { value }, null );
} }
@ -75,7 +79,8 @@ public final class MethodResult {
* @return A method result which returns immediately with the given values. * @return A method result which returns immediately with the given values.
*/ */
@Nonnull @Nonnull
public static MethodResult of(@Nullable Object... values) { public static MethodResult of( @Nullable Object... values )
{
return values == null || values.length == 0 ? empty : new MethodResult( values, null ); return values == null || values.length == 0 ? empty : new MethodResult( values, null );
} }
@ -89,10 +94,12 @@ public final class MethodResult {
* @see IComputerAccess#queueEvent(String, Object[]) * @see IComputerAccess#queueEvent(String, Object[])
*/ */
@Nonnull @Nonnull
public static MethodResult pullEvent(@Nullable String filter, @Nonnull ILuaCallback callback) { public static MethodResult pullEvent( @Nullable String filter, @Nonnull ILuaCallback callback )
{
Objects.requireNonNull( callback, "callback cannot be null" ); Objects.requireNonNull( callback, "callback cannot be null" );
return new MethodResult( new Object[] { filter }, results -> { return new MethodResult( new Object[] { filter }, results -> {
if (results.length >= 1 && results[0].equals("terminate")) { if( results.length >= 1 && results[0].equals( "terminate" ) )
{
throw new LuaException( "Terminated", 0 ); throw new LuaException( "Terminated", 0 );
} }
return callback.resume( results ); return callback.resume( results );
@ -109,7 +116,8 @@ public final class MethodResult {
* @see #pullEvent(String, ILuaCallback) * @see #pullEvent(String, ILuaCallback)
*/ */
@Nonnull @Nonnull
public static MethodResult pullEventRaw(@Nullable String filter, @Nonnull ILuaCallback callback) { public static MethodResult pullEventRaw( @Nullable String filter, @Nonnull ILuaCallback callback )
{
Objects.requireNonNull( callback, "callback cannot be null" ); Objects.requireNonNull( callback, "callback cannot be null" );
return new MethodResult( new Object[] { filter }, callback ); return new MethodResult( new Object[] { filter }, callback );
} }
@ -124,22 +132,26 @@ public final class MethodResult {
* @see #pullEvent(String, ILuaCallback) * @see #pullEvent(String, ILuaCallback)
*/ */
@Nonnull @Nonnull
public static MethodResult yield(@Nullable Object[] arguments, @Nonnull ILuaCallback callback) { public static MethodResult yield( @Nullable Object[] arguments, @Nonnull ILuaCallback callback )
{
Objects.requireNonNull( callback, "callback cannot be null" ); Objects.requireNonNull( callback, "callback cannot be null" );
return new MethodResult( arguments, callback ); return new MethodResult( arguments, callback );
} }
@Nullable @Nullable
public Object[] getResult() { public Object[] getResult()
{
return this.result; return this.result;
} }
@Nullable @Nullable
public ILuaCallback getCallback() { public ILuaCallback getCallback()
{
return this.callback; return this.callback;
} }
public int getErrorAdjust() { public int getErrorAdjust()
{
return this.adjust; return this.adjust;
} }
@ -150,11 +162,14 @@ public final class MethodResult {
* @return The new {@link MethodResult} with an adjusted error. This has no effect on immediate results. * @return The new {@link MethodResult} with an adjusted error. This has no effect on immediate results.
*/ */
@Nonnull @Nonnull
public MethodResult adjustError(int adjust) { public MethodResult adjustError( int adjust )
if (adjust < 0) { {
if( adjust < 0 )
{
throw new IllegalArgumentException( "cannot adjust by a negative amount" ); throw new IllegalArgumentException( "cannot adjust by a negative amount" );
} }
if (adjust == 0 || this.callback == null) { if( adjust == 0 || this.callback == null )
{
return this; return this;
} }
return new MethodResult( this.result, this.callback, this.adjust + adjust ); return new MethodResult( this.result, this.callback, this.adjust + adjust );

View File

@ -6,42 +6,49 @@
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import javax.annotation.Nullable;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import javax.annotation.Nullable;
/** /**
* An implementation of {@link IArguments} which wraps an array of {@link Object}. * An implementation of {@link IArguments} which wraps an array of {@link Object}.
*/ */
public final class ObjectArguments implements IArguments { public final class ObjectArguments implements IArguments
{
private static final IArguments EMPTY = new ObjectArguments(); private static final IArguments EMPTY = new ObjectArguments();
private final List<Object> args; private final List<Object> args;
@Deprecated @Deprecated
@SuppressWarnings( "unused" ) @SuppressWarnings( "unused" )
public ObjectArguments(IArguments arguments) { public ObjectArguments( IArguments arguments )
{
throw new IllegalStateException(); throw new IllegalStateException();
} }
public ObjectArguments(Object... args) { public ObjectArguments( Object... args )
{
this.args = Arrays.asList( args ); this.args = Arrays.asList( args );
} }
public ObjectArguments(List<Object> args) { public ObjectArguments( List<Object> args )
{
this.args = Objects.requireNonNull( args ); this.args = Objects.requireNonNull( args );
} }
@Override @Override
public IArguments drop(int count) { public IArguments drop( int count )
if (count < 0) { {
if( count < 0 )
{
throw new IllegalStateException( "count cannot be negative" ); throw new IllegalStateException( "count cannot be negative" );
} }
if (count == 0) { if( count == 0 )
{
return this; return this;
} }
if (count >= this.args.size()) { if( count >= this.args.size() )
{
return EMPTY; return EMPTY;
} }
@ -49,18 +56,21 @@ public final class ObjectArguments implements IArguments {
} }
@Override @Override
public Object[] getAll() { public Object[] getAll()
{
return this.args.toArray(); return this.args.toArray();
} }
@Override @Override
public int count() { public int count()
{
return this.args.size(); return this.args.size();
} }
@Nullable @Nullable
@Override @Override
public Object get(int index) { public Object get( int index )
{
return index >= this.args.size() ? null : this.args.get( index ); return index >= this.args.size() ? null : this.args.get( index );
} }
} }

View File

@ -6,22 +6,22 @@
package dan200.computercraft.api.media; package dan200.computercraft.api.media;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IMount;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.sound.SoundEvent; import net.minecraft.sound.SoundEvent;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* Represents an item that can be placed in a disk drive and used by a Computer. * Represents an item that can be placed in a disk drive and used by a Computer.
* *
* Implement this interface on your {@link Item} class to allow it to be used in the drive. Alternatively, register a {@link IMediaProvider}. * Implement this interface on your {@link Item} class to allow it to be used in the drive. Alternatively, register a {@link IMediaProvider}.
*/ */
public interface IMedia { public interface IMedia
{
/** /**
* Get a string representing the label of this item. Will be called via {@code disk.getLabel()} in lua. * Get a string representing the label of this item. Will be called via {@code disk.getLabel()} in lua.
* *
@ -38,7 +38,8 @@ public interface IMedia {
* @param label The string to set the label to. * @param label The string to set the label to.
* @return true if the label was updated, false if the label may not be modified. * @return true if the label was updated, false if the label may not be modified.
*/ */
default boolean setLabel(@Nonnull ItemStack stack, @Nullable String label) { default boolean setLabel( @Nonnull ItemStack stack, @Nullable String label )
{
return false; return false;
} }
@ -49,7 +50,8 @@ public interface IMedia {
* @return The name, or null if this item does not represent an item with audio. * @return The name, or null if this item does not represent an item with audio.
*/ */
@Nullable @Nullable
default String getAudioTitle(@Nonnull ItemStack stack) { default String getAudioTitle( @Nonnull ItemStack stack )
{
return null; return null;
} }
@ -60,7 +62,8 @@ public interface IMedia {
* @return The name, or null if this item does not represent an item with audio. * @return The name, or null if this item does not represent an item with audio.
*/ */
@Nullable @Nullable
default SoundEvent getAudio(@Nonnull ItemStack stack) { default SoundEvent getAudio( @Nonnull ItemStack stack )
{
return null; return null;
} }
@ -78,7 +81,8 @@ public interface IMedia {
* @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(String, String) * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(String, String)
*/ */
@Nullable @Nullable
default IMount createDataMount(@Nonnull ItemStack stack, @Nonnull World world) { default IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world )
{
return null; return null;
} }
} }

View File

@ -6,18 +6,19 @@
package dan200.computercraft.api.media; package dan200.computercraft.api.media;
import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import net.minecraft.item.ItemStack;
/** /**
* This interface is used to provide {@link IMedia} implementations for {@link ItemStack}. * This interface is used to provide {@link IMedia} implementations for {@link ItemStack}.
* *
* @see dan200.computercraft.api.ComputerCraftAPI#registerMediaProvider(IMediaProvider) * @see dan200.computercraft.api.ComputerCraftAPI#registerMediaProvider(IMediaProvider)
*/ */
@FunctionalInterface @FunctionalInterface
public interface IMediaProvider { public interface IMediaProvider
{
/** /**
* Produce an IMedia implementation from an ItemStack. * Produce an IMedia implementation from an ItemStack.
* *

View File

@ -14,7 +14,8 @@ import javax.annotation.Nonnull;
* @see Packet * @see Packet
* @see IPacketReceiver * @see IPacketReceiver
*/ */
public interface IPacketNetwork { public interface IPacketNetwork
{
/** /**
* Add a receiver to the network. * Add a receiver to the network.
* *

View File

@ -6,15 +6,16 @@
package dan200.computercraft.api.network; package dan200.computercraft.api.network;
import javax.annotation.Nonnull;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
/** /**
* An object on an {@link IPacketNetwork}, capable of receiving packets. * An object on an {@link IPacketNetwork}, capable of receiving packets.
*/ */
public interface IPacketReceiver { public interface IPacketReceiver
{
/** /**
* Get the world in which this packet receiver exists. * Get the world in which this packet receiver exists.
* *

View File

@ -6,15 +6,16 @@
package dan200.computercraft.api.network; package dan200.computercraft.api.network;
import javax.annotation.Nonnull;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
/** /**
* An object on a {@link IPacketNetwork}, capable of sending packets. * An object on a {@link IPacketNetwork}, capable of sending packets.
*/ */
public interface IPacketSender { public interface IPacketSender
{
/** /**
* Get the world in which this packet sender exists. * Get the world in which this packet sender exists.
* *

View File

@ -6,10 +6,9 @@
package dan200.computercraft.api.network; package dan200.computercraft.api.network;
import java.util.Objects;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Objects;
/** /**
* Represents a packet which may be sent across a {@link IPacketNetwork}. * Represents a packet which may be sent across a {@link IPacketNetwork}.
@ -20,7 +19,8 @@ import javax.annotation.Nullable;
* @see IPacketReceiver#receiveDifferentDimension(Packet) * @see IPacketReceiver#receiveDifferentDimension(Packet)
* @see IPacketReceiver#receiveSameDimension(Packet, double) * @see IPacketReceiver#receiveSameDimension(Packet, double)
*/ */
public class Packet { public class Packet
{
private final int channel; private final int channel;
private final int replyChannel; private final int replyChannel;
private final Object payload; private final Object payload;
@ -36,7 +36,8 @@ public class Packet {
* call. * call.
* @param sender The object which sent this packet. * @param sender The object which sent this packet.
*/ */
public Packet(int channel, int replyChannel, @Nullable Object payload, @Nonnull IPacketSender sender) { public Packet( int channel, int replyChannel, @Nullable Object payload, @Nonnull IPacketSender sender )
{
Objects.requireNonNull( sender, "sender cannot be null" ); Objects.requireNonNull( sender, "sender cannot be null" );
this.channel = channel; this.channel = channel;
@ -50,7 +51,8 @@ public class Packet {
* *
* @return This packet's channel. * @return This packet's channel.
*/ */
public int getChannel() { public int getChannel()
{
return this.channel; return this.channel;
} }
@ -59,7 +61,8 @@ public class Packet {
* *
* @return This channel to reply on. * @return This channel to reply on.
*/ */
public int getReplyChannel() { public int getReplyChannel()
{
return this.replyChannel; return this.replyChannel;
} }
@ -69,7 +72,8 @@ public class Packet {
* @return The packet's payload * @return The packet's payload
*/ */
@Nullable @Nullable
public Object getPayload() { public Object getPayload()
{
return this.payload; return this.payload;
} }
@ -79,12 +83,14 @@ public class Packet {
* @return The sending object. * @return The sending object.
*/ */
@Nonnull @Nonnull
public IPacketSender getSender() { public IPacketSender getSender()
{
return this.sender; return this.sender;
} }
@Override @Override
public int hashCode() { public int hashCode()
{
int result; int result;
result = this.channel; result = this.channel;
result = 31 * result + this.replyChannel; result = 31 * result + this.replyChannel;
@ -94,23 +100,29 @@ public class Packet {
} }
@Override @Override
public boolean equals(Object o) { public boolean equals( Object o )
if (this == o) { {
if( this == o )
{
return true; return true;
} }
if (o == null || this.getClass() != o.getClass()) { if( o == null || this.getClass() != o.getClass() )
{
return false; return false;
} }
Packet packet = (Packet) o; Packet packet = (Packet) o;
if (this.channel != packet.channel) { if( this.channel != packet.channel )
{
return false; return false;
} }
if (this.replyChannel != packet.replyChannel) { if( this.replyChannel != packet.replyChannel )
{
return false; return false;
} }
if (!Objects.equals(this.payload, packet.payload)) { if( !Objects.equals( this.payload, packet.payload ) )
{
return false; return false;
} }
return this.sender.equals( packet.sender ); return this.sender.equals( packet.sender );

View File

@ -6,10 +6,10 @@
package dan200.computercraft.api.network.wired; package dan200.computercraft.api.network.wired;
import javax.annotation.Nonnull;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import javax.annotation.Nonnull;
/** /**
* An object which may be part of a wired network. * An object which may be part of a wired network.
* *
@ -19,13 +19,15 @@ import dan200.computercraft.api.ComputerCraftAPI;
* Elements are generally tied to a block or tile entity in world. In such as case, one should provide the {@link IWiredElement} capability for the * Elements are generally tied to a block or tile entity in world. In such as case, one should provide the {@link IWiredElement} capability for the
* appropriate sides. * appropriate sides.
*/ */
public interface IWiredElement extends IWiredSender { public interface IWiredElement extends IWiredSender
{
/** /**
* Called when objects on the network change. This may occur when network nodes are added or removed, or when peripherals change. * Called when objects on the network change. This may occur when network nodes are added or removed, or when peripherals change.
* *
* @param change The change which occurred. * @param change The change which occurred.
* @see IWiredNetworkChange * @see IWiredNetworkChange
*/ */
default void networkChanged(@Nonnull IWiredNetworkChange change) { default void networkChanged( @Nonnull IWiredNetworkChange change )
{
} }
} }

View File

@ -6,11 +6,10 @@
package dan200.computercraft.api.network.wired; package dan200.computercraft.api.network.wired;
import java.util.Map; import dan200.computercraft.api.peripheral.IPeripheral;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Map;
import dan200.computercraft.api.peripheral.IPeripheral;
/** /**
* A wired network is composed of one of more {@link IWiredNode}s, a set of connections between them, and a series of peripherals. * A wired network is composed of one of more {@link IWiredNode}s, a set of connections between them, and a series of peripherals.
@ -24,7 +23,8 @@ import dan200.computercraft.api.peripheral.IPeripheral;
* *
* @see IWiredNode#getNetwork() * @see IWiredNode#getNetwork()
*/ */
public interface IWiredNetwork { public interface IWiredNetwork
{
/** /**
* Create a connection between two nodes. * Create a connection between two nodes.
* *

View File

@ -6,18 +6,18 @@
package dan200.computercraft.api.network.wired; package dan200.computercraft.api.network.wired;
import java.util.Map; import dan200.computercraft.api.peripheral.IPeripheral;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Map;
import dan200.computercraft.api.peripheral.IPeripheral;
/** /**
* Represents a change to the objects on a wired network. * Represents a change to the objects on a wired network.
* *
* @see IWiredElement#networkChanged(IWiredNetworkChange) * @see IWiredElement#networkChanged(IWiredNetworkChange)
*/ */
public interface IWiredNetworkChange { public interface IWiredNetworkChange
{
/** /**
* A set of peripherals which have been removed. Note that there may be entries with the same name in the added and removed set, but with a different * A set of peripherals which have been removed. Note that there may be entries with the same name in the added and removed set, but with a different
* peripheral. * peripheral.

View File

@ -6,13 +6,12 @@
package dan200.computercraft.api.network.wired; package dan200.computercraft.api.network.wired;
import java.util.Map;
import javax.annotation.Nonnull;
import dan200.computercraft.api.network.IPacketNetwork; import dan200.computercraft.api.network.IPacketNetwork;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import javax.annotation.Nonnull;
import java.util.Map;
/** /**
* Wired nodes act as a layer between {@link IWiredElement}s and {@link IWiredNetwork}s. * Wired nodes act as a layer between {@link IWiredElement}s and {@link IWiredNetwork}s.
* *
@ -25,7 +24,8 @@ import dan200.computercraft.api.peripheral.IPeripheral;
* *
* Wired nodes also provide several convenience methods for interacting with a wired network. These should only ever be used on the main server thread. * Wired nodes also provide several convenience methods for interacting with a wired network. These should only ever be used on the main server thread.
*/ */
public interface IWiredNode extends IPacketNetwork { public interface IWiredNode extends IPacketNetwork
{
/** /**
* The associated element for this network node. * The associated element for this network node.
* *
@ -44,7 +44,8 @@ public interface IWiredNode extends IPacketNetwork {
* @see IWiredNetwork#connect(IWiredNode, IWiredNode) * @see IWiredNetwork#connect(IWiredNode, IWiredNode)
* @see IWiredNode#disconnectFrom(IWiredNode) * @see IWiredNode#disconnectFrom(IWiredNode)
*/ */
default boolean connectTo(@Nonnull IWiredNode node) { default boolean connectTo( @Nonnull IWiredNode node )
{
return this.getNetwork().connect( this, node ); return this.getNetwork().connect( this, node );
} }
@ -69,7 +70,8 @@ public interface IWiredNode extends IPacketNetwork {
* @see IWiredNetwork#disconnect(IWiredNode, IWiredNode) * @see IWiredNetwork#disconnect(IWiredNode, IWiredNode)
* @see IWiredNode#connectTo(IWiredNode) * @see IWiredNode#connectTo(IWiredNode)
*/ */
default boolean disconnectFrom(@Nonnull IWiredNode node) { default boolean disconnectFrom( @Nonnull IWiredNode node )
{
return this.getNetwork().disconnect( this, node ); return this.getNetwork().disconnect( this, node );
} }
@ -82,7 +84,8 @@ public interface IWiredNode extends IPacketNetwork {
* @throws IllegalArgumentException If the node is not in the network. * @throws IllegalArgumentException If the node is not in the network.
* @see IWiredNetwork#remove(IWiredNode) * @see IWiredNetwork#remove(IWiredNode)
*/ */
default boolean remove() { default boolean remove()
{
return this.getNetwork().remove( this ); return this.getNetwork().remove( this );
} }
@ -94,7 +97,8 @@ public interface IWiredNode extends IPacketNetwork {
* @param peripherals The new peripherals for this node. * @param peripherals The new peripherals for this node.
* @see IWiredNetwork#updatePeripherals(IWiredNode, Map) * @see IWiredNetwork#updatePeripherals(IWiredNode, Map)
*/ */
default void updatePeripherals(@Nonnull Map<String, IPeripheral> peripherals) { default void updatePeripherals( @Nonnull Map<String, IPeripheral> peripherals )
{
this.getNetwork().updatePeripherals( this, peripherals ); this.getNetwork().updatePeripherals( this, peripherals );
} }
} }

View File

@ -6,16 +6,17 @@
package dan200.computercraft.api.network.wired; package dan200.computercraft.api.network.wired;
import javax.annotation.Nonnull;
import dan200.computercraft.api.network.IPacketSender; import dan200.computercraft.api.network.IPacketSender;
import javax.annotation.Nonnull;
/** /**
* An object on a {@link IWiredNetwork} capable of sending packets. * An object on a {@link IWiredNetwork} capable of sending packets.
* *
* Unlike a regular {@link IPacketSender}, this must be associated with the node you are attempting to to send the packet from. * Unlike a regular {@link IPacketSender}, this must be associated with the node you are attempting to to send the packet from.
*/ */
public interface IWiredSender extends IPacketSender { public interface IWiredSender extends IPacketSender
{
/** /**
* The node in the network representing this object. * The node in the network representing this object.
* *

View File

@ -6,11 +6,6 @@
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.filesystem.IWritableMount;
@ -18,14 +13,18 @@ import dan200.computercraft.api.lua.ILuaCallback;
import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaTask; import dan200.computercraft.api.lua.ILuaTask;
import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.lua.MethodResult;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Map;
/** /**
* The interface passed to peripherals by computers or turtles, providing methods that they can call. This should not be implemented by your classes. Do not * The interface passed to peripherals by computers or turtles, providing methods that they can call. This should not be implemented by your classes. Do not
* interact with computers except via this interface. * interact with computers except via this interface.
*/ */
public interface IComputerAccess { public interface IComputerAccess
{
/** /**
* Mount a mount onto the computer's file system in a read only mode. * Mount a mount onto the computer's file system in a read only mode.
* *
@ -42,7 +41,8 @@ public interface IComputerAccess {
* @see IMount * @see IMount
*/ */
@Nullable @Nullable
default String mount(@Nonnull String desiredLocation, @Nonnull IMount mount) { default String mount( @Nonnull String desiredLocation, @Nonnull IMount mount )
{
return this.mount( desiredLocation, mount, this.getAttachmentName() ); return this.mount( desiredLocation, mount, this.getAttachmentName() );
} }
@ -91,7 +91,8 @@ public interface IComputerAccess {
* @see IMount * @see IMount
*/ */
@Nullable @Nullable
default String mountWritable(@Nonnull String desiredLocation, @Nonnull IWritableMount mount) { default String mountWritable( @Nonnull String desiredLocation, @Nonnull IWritableMount mount )
{
return this.mountWritable( desiredLocation, mount, this.getAttachmentName() ); return this.mountWritable( desiredLocation, mount, this.getAttachmentName() );
} }

View File

@ -6,14 +6,9 @@
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import javax.annotation.Nonnull; import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.lua.IArguments; import javax.annotation.Nonnull;
import dan200.computercraft.api.lua.IDynamicLuaObject;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.lua.MethodResult;
/** /**
* A peripheral whose methods are not known at runtime. * A peripheral whose methods are not known at runtime.
@ -21,7 +16,8 @@ import dan200.computercraft.api.lua.MethodResult;
* This behaves similarly to {@link IDynamicLuaObject}, though also accepting the current {@link IComputerAccess}. Generally one may use {@link LuaFunction} * This behaves similarly to {@link IDynamicLuaObject}, though also accepting the current {@link IComputerAccess}. Generally one may use {@link LuaFunction}
* instead of implementing this interface. * instead of implementing this interface.
*/ */
public interface IDynamicPeripheral extends IPeripheral { public interface IDynamicPeripheral extends IPeripheral
{
/** /**
* Should return an array of strings that identify the methods that this peripheral exposes to Lua. This will be called once before each attachment, and * Should return an array of strings that identify the methods that this peripheral exposes to Lua. This will be called once before each attachment, and
* should not change when called multiple times. * should not change when called multiple times.

View File

@ -6,11 +6,11 @@
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import dan200.computercraft.api.lua.LuaFunction;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import dan200.computercraft.api.lua.LuaFunction;
/** /**
* The interface that defines a peripheral. * The interface that defines a peripheral.
* *
@ -19,7 +19,8 @@ import dan200.computercraft.api.lua.LuaFunction;
* *
* Peripherals should provide a series of methods to the user, either using {@link LuaFunction} or by implementing {@link IDynamicPeripheral}. * Peripherals should provide a series of methods to the user, either using {@link LuaFunction} or by implementing {@link IDynamicPeripheral}.
*/ */
public interface IPeripheral { public interface IPeripheral
{
/** /**
* Should return a string that uniquely identifies this type of peripheral. This can be queried from lua by calling {@code peripheral.getType()} * Should return a string that uniquely identifies this type of peripheral. This can be queried from lua by calling {@code peripheral.getType()}
* *
@ -42,7 +43,8 @@ public interface IPeripheral {
* @param computer The interface to the computer that is being attached. Remember that multiple computers can be attached to a peripheral at once. * @param computer The interface to the computer that is being attached. Remember that multiple computers can be attached to a peripheral at once.
* @see #detach * @see #detach
*/ */
default void attach(@Nonnull IComputerAccess computer) { default void attach( @Nonnull IComputerAccess computer )
{
} }
/** /**
@ -58,7 +60,8 @@ public interface IPeripheral {
* @param computer The interface to the computer that is being detached. Remember that multiple computers can be attached to a peripheral at once. * @param computer The interface to the computer that is being detached. Remember that multiple computers can be attached to a peripheral at once.
* @see #attach * @see #attach
*/ */
default void detach(@Nonnull IComputerAccess computer) { default void detach( @Nonnull IComputerAccess computer )
{
} }
/** /**
@ -67,7 +70,8 @@ public interface IPeripheral {
* @return The object this peripheral targets * @return The object this peripheral targets
*/ */
@Nullable @Nullable
default Object getTarget() { default Object getTarget()
{
return null; return null;
} }

View File

@ -6,15 +6,14 @@
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import java.util.Optional;
import javax.annotation.Nonnull;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.util.Optional;
/** /**
* This interface is used to create peripheral implementations for blocks. * This interface is used to create peripheral implementations for blocks.
* *
@ -23,7 +22,8 @@ import net.minecraft.world.World;
* @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider)
*/ */
@FunctionalInterface @FunctionalInterface
public interface IPeripheralProvider { public interface IPeripheralProvider
{
/** /**
* Produce an peripheral implementation from a block location. * Produce an peripheral implementation from a block location.
* *

View File

@ -5,19 +5,20 @@
*/ */
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* A {@link net.minecraft.block.entity.BlockEntity} which may act as a peripheral. * A {@link net.minecraft.block.entity.BlockEntity} which may act as a peripheral.
* *
* If you need more complex capabilities (such as handling TEs not belonging to your mod), you should use {@link IPeripheralProvider}. * If you need more complex capabilities (such as handling TEs not belonging to your mod), you should use {@link IPeripheralProvider}.
*/ */
public interface IPeripheralTile { public interface IPeripheralTile
{
/** /**
* Get the peripheral on the given {@code side}. * Get the peripheral on the given {@code side}.
* *

View File

@ -6,11 +6,10 @@
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import javax.annotation.Nonnull;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
/** /**
* Monitors "work" associated with a computer, keeping track of how much a computer has done, and ensuring every computer receives a fair share of any * Monitors "work" associated with a computer, keeping track of how much a computer has done, and ensuring every computer receives a fair share of any
* processing time. * processing time.
@ -25,7 +24,8 @@ import javax.annotation.Nonnull;
* *
* @see IComputerAccess#getMainThreadMonitor() * @see IComputerAccess#getMainThreadMonitor()
*/ */
public interface IWorkMonitor { public interface IWorkMonitor
{
/** /**
* If the owning computer is currently allowed to execute work, and has ample time to do so. * If the owning computer is currently allowed to execute work, and has ample time to do so.
* *
@ -42,16 +42,21 @@ public interface IWorkMonitor {
* @param runnable The task to run. * @param runnable The task to run.
* @return If the task was actually run (namely, {@link #canWork()} returned {@code true}). * @return If the task was actually run (namely, {@link #canWork()} returned {@code true}).
*/ */
default boolean runWork(@Nonnull Runnable runnable) { default boolean runWork( @Nonnull Runnable runnable )
{
Objects.requireNonNull( runnable, "runnable should not be null" ); Objects.requireNonNull( runnable, "runnable should not be null" );
if (!this.canWork()) { if( !this.canWork() )
{
return false; return false;
} }
long start = System.nanoTime(); long start = System.nanoTime();
try { try
{
runnable.run(); runnable.run();
} finally { }
finally
{
this.trackWork( System.nanoTime() - start, TimeUnit.NANOSECONDS ); this.trackWork( System.nanoTime() - start, TimeUnit.NANOSECONDS );
} }

View File

@ -9,14 +9,17 @@ package dan200.computercraft.api.peripheral;
/** /**
* Thrown when performing operations on {@link IComputerAccess} when the current peripheral is no longer attached to the computer. * Thrown when performing operations on {@link IComputerAccess} when the current peripheral is no longer attached to the computer.
*/ */
public class NotAttachedException extends IllegalStateException { public class NotAttachedException extends IllegalStateException
{
private static final long serialVersionUID = 1221244785535553536L; private static final long serialVersionUID = 1221244785535553536L;
public NotAttachedException() { public NotAttachedException()
{
super( "You are not attached to this computer" ); super( "You are not attached to this computer" );
} }
public NotAttachedException(String s) { public NotAttachedException( String s )
{
super( s ); super( s );
} }
} }

View File

@ -6,34 +6,38 @@
package dan200.computercraft.api.pocket; package dan200.computercraft.api.pocket;
import javax.annotation.Nonnull;
import net.minecraft.item.ItemConvertible; import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Util; import net.minecraft.util.Util;
import javax.annotation.Nonnull;
/** /**
* A base class for {@link IPocketUpgrade}s. * A base class for {@link IPocketUpgrade}s.
* *
* One does not have to use this, but it does provide a convenient template. * One does not have to use this, but it does provide a convenient template.
*/ */
public abstract class AbstractPocketUpgrade implements IPocketUpgrade { public abstract class AbstractPocketUpgrade implements IPocketUpgrade
{
private final Identifier id; private final Identifier id;
private final String adjective; private final String adjective;
private final ItemStack stack; private final ItemStack stack;
protected AbstractPocketUpgrade(Identifier id, ItemConvertible item) { protected AbstractPocketUpgrade( Identifier id, ItemConvertible item )
{
this( id, Util.createTranslationKey( "upgrade", id ) + ".adjective", item ); this( id, Util.createTranslationKey( "upgrade", id ) + ".adjective", item );
} }
protected AbstractPocketUpgrade(Identifier id, String adjective, ItemConvertible item) { protected AbstractPocketUpgrade( Identifier id, String adjective, ItemConvertible item )
{
this.id = id; this.id = id;
this.adjective = adjective; this.adjective = adjective;
this.stack = new ItemStack( item ); this.stack = new ItemStack( item );
} }
protected AbstractPocketUpgrade(Identifier id, String adjective, ItemStack stack) { protected AbstractPocketUpgrade( Identifier id, String adjective, ItemStack stack )
{
this.id = id; this.id = id;
this.adjective = adjective; this.adjective = adjective;
this.stack = stack; this.stack = stack;
@ -42,19 +46,22 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade {
@Nonnull @Nonnull
@Override @Override
public final Identifier getUpgradeID() { public final Identifier getUpgradeID()
{
return this.id; return this.id;
} }
@Nonnull @Nonnull
@Override @Override
public final String getUnlocalisedAdjective() { public final String getUnlocalisedAdjective()
{
return this.adjective; return this.adjective;
} }
@Nonnull @Nonnull
@Override @Override
public final ItemStack getCraftingItem() { public final ItemStack getCraftingItem()
{
return this.stack; return this.stack;
} }
} }

View File

@ -6,21 +6,20 @@
package dan200.computercraft.api.pocket; package dan200.computercraft.api.pocket;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Map;
/** /**
* Wrapper class for pocket computers. * Wrapper class for pocket computers.
*/ */
public interface IPocketAccess { public interface IPocketAccess
{
/** /**
* Gets the entity holding this item. * Gets the entity holding this item.
* *

View File

@ -6,15 +6,14 @@
package dan200.computercraft.api.pocket; package dan200.computercraft.api.pocket;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.IUpgradeBase; import dan200.computercraft.api.IUpgradeBase;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* Additional peripherals for pocket computers. * Additional peripherals for pocket computers.
* *
@ -42,7 +41,8 @@ public interface IPocketUpgrade extends IUpgradeBase
* @param peripheral The peripheral for this upgrade. * @param peripheral The peripheral for this upgrade.
* @see #createPeripheral(IPocketAccess) * @see #createPeripheral(IPocketAccess)
*/ */
default void update(@Nonnull IPocketAccess access, @Nullable IPeripheral peripheral) { default void update( @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral )
{
} }
/** /**
@ -55,7 +55,8 @@ public interface IPocketUpgrade extends IUpgradeBase
* requiring the player to be sneaking - otherwise they will be unable to access the GUI. * requiring the player to be sneaking - otherwise they will be unable to access the GUI.
* @see #createPeripheral(IPocketAccess) * @see #createPeripheral(IPocketAccess)
*/ */
default boolean onRightClick(@Nonnull World world, @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral) { default boolean onRightClick( @Nonnull World world, @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral )
{
return false; return false;
} }
} }

View File

@ -6,19 +6,20 @@
package dan200.computercraft.api.redstone; package dan200.computercraft.api.redstone;
import javax.annotation.Nonnull;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
/** /**
* This interface is used to provide bundled redstone output for blocks. * This interface is used to provide bundled redstone output for blocks.
* *
* @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider) * @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider)
*/ */
@FunctionalInterface @FunctionalInterface
public interface IBundledRedstoneProvider { public interface IBundledRedstoneProvider
{
/** /**
* Produce an bundled redstone output from a block location. * Produce an bundled redstone output from a block location.
* *

View File

@ -6,65 +6,74 @@
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
import javax.annotation.Nonnull;
import net.minecraft.item.ItemConvertible; import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Util; import net.minecraft.util.Util;
import javax.annotation.Nonnull;
/** /**
* A base class for {@link ITurtleUpgrade}s. * A base class for {@link ITurtleUpgrade}s.
* *
* One does not have to use this, but it does provide a convenient template. * One does not have to use this, but it does provide a convenient template.
*/ */
public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade { public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade
{
private final Identifier id; private final Identifier id;
private final TurtleUpgradeType type; private final TurtleUpgradeType type;
private final String adjective; private final String adjective;
private final ItemStack stack; private final ItemStack stack;
protected AbstractTurtleUpgrade(Identifier id, TurtleUpgradeType type, String adjective, ItemConvertible item) { protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemConvertible item )
{
this( id, type, adjective, new ItemStack( item ) ); this( id, type, adjective, new ItemStack( item ) );
} }
protected AbstractTurtleUpgrade(Identifier id, TurtleUpgradeType type, String adjective, ItemStack stack) { protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemStack stack )
{
this.id = id; this.id = id;
this.type = type; this.type = type;
this.adjective = adjective; this.adjective = adjective;
this.stack = stack; this.stack = stack;
} }
protected AbstractTurtleUpgrade(Identifier id, TurtleUpgradeType type, ItemConvertible item) { protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, ItemConvertible item )
{
this( id, type, new ItemStack( item ) ); this( id, type, new ItemStack( item ) );
} }
protected AbstractTurtleUpgrade(Identifier id, TurtleUpgradeType type, ItemStack stack) { protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, ItemStack stack )
{
this( id, type, Util.createTranslationKey( "upgrade", id ) + ".adjective", stack ); this( id, type, Util.createTranslationKey( "upgrade", id ) + ".adjective", stack );
} }
@Nonnull @Nonnull
@Override @Override
public final Identifier getUpgradeID() { public final Identifier getUpgradeID()
{
return this.id; return this.id;
} }
@Nonnull @Nonnull
@Override @Override
public final String getUnlocalisedAdjective() { public final String getUnlocalisedAdjective()
{
return this.adjective; return this.adjective;
} }
@Nonnull @Nonnull
@Override @Override
public final TurtleUpgradeType getType() { public final TurtleUpgradeType getType()
{
return this.type; return this.type;
} }
@Nonnull @Nonnull
@Override @Override
public final ItemStack getCraftingItem() { public final ItemStack getCraftingItem()
{
return this.stack; return this.stack;
} }
} }

View File

@ -5,18 +5,10 @@
*/ */
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
import java.util.Collection;
import java.util.OptionalInt;
import java.util.UUID;
import javax.annotation.Nullable;
import javax.crypto.Cipher;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener; import io.netty.util.concurrent.GenericFutureListener;
import net.minecraft.block.entity.CommandBlockBlockEntity; import net.minecraft.block.entity.CommandBlockBlockEntity;
import net.minecraft.block.entity.SignBlockEntity; import net.minecraft.block.entity.SignBlockEntity;
import net.minecraft.command.argument.EntityAnchorArgumentType; import net.minecraft.command.argument.EntityAnchorArgumentType;
@ -26,11 +18,7 @@ import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.passive.HorseBaseEntity; import net.minecraft.entity.passive.HorseBaseEntity;
import net.minecraft.inventory.Inventory; import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.network.ClientConnection; import net.minecraft.network.*;
import net.minecraft.network.MessageType;
import net.minecraft.network.NetworkSide;
import net.minecraft.network.NetworkState;
import net.minecraft.network.Packet;
import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket; import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket;
import net.minecraft.network.packet.c2s.play.VehicleMoveC2SPacket; import net.minecraft.network.packet.c2s.play.VehicleMoveC2SPacket;
import net.minecraft.recipe.Recipe; import net.minecraft.recipe.Recipe;
@ -50,13 +38,21 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.village.TradeOfferList; import net.minecraft.village.TradeOfferList;
import net.minecraft.world.GameMode; import net.minecraft.world.GameMode;
import javax.annotation.Nullable;
import javax.crypto.Cipher;
import java.util.Collection;
import java.util.OptionalInt;
import java.util.UUID;
/** /**
* A wrapper for {@link ServerPlayerEntity} which denotes a "fake" player. * A wrapper for {@link ServerPlayerEntity} which denotes a "fake" player.
* *
* Please note that this does not implement any of the traditional fake player behaviour. It simply exists to prevent me passing in normal players. * Please note that this does not implement any of the traditional fake player behaviour. It simply exists to prevent me passing in normal players.
*/ */
public class FakePlayer extends ServerPlayerEntity { public class FakePlayer extends ServerPlayerEntity
public FakePlayer(ServerWorld world, GameProfile gameProfile) { {
public FakePlayer( ServerWorld world, GameProfile gameProfile )
{
super( world.getServer(), world, gameProfile, new ServerPlayerInteractionManager( world ) ); super( world.getServer(), world, gameProfile, new ServerPlayerInteractionManager( world ) );
this.networkHandler = new FakeNetHandler( this ); this.networkHandler = new FakeNetHandler( this );
} }
@ -78,17 +74,20 @@ public class FakePlayer extends ServerPlayerEntity {
public void onDeath( DamageSource damage ) { } public void onDeath( DamageSource damage ) { }
@Override @Override
public Entity moveToWorld(ServerWorld destination) { public Entity moveToWorld( ServerWorld destination )
{
return this; return this;
} }
@Override @Override
public void wakeUp(boolean bl, boolean updateSleepingPlayers) { public void wakeUp( boolean bl, boolean updateSleepingPlayers )
{
} }
@Override @Override
public boolean startRiding(Entity entity, boolean flag) { public boolean startRiding( Entity entity, boolean flag )
{
return false; return false;
} }
@ -99,7 +98,8 @@ public class FakePlayer extends ServerPlayerEntity {
public void openEditSignScreen( SignBlockEntity tile ) { } public void openEditSignScreen( SignBlockEntity tile ) { }
@Override @Override
public OptionalInt openHandledScreen(@Nullable NamedScreenHandlerFactory container) { public OptionalInt openHandledScreen( @Nullable NamedScreenHandlerFactory container )
{
return OptionalInt.empty(); return OptionalInt.empty();
} }
@ -131,13 +131,15 @@ public class FakePlayer extends ServerPlayerEntity {
public void updateCursorStack() { } public void updateCursorStack() { }
@Override @Override
public int unlockRecipes(Collection<Recipe<?>> recipes) { public int unlockRecipes( Collection<Recipe<?>> recipes )
{
return 0; return 0;
} }
// Indirect // Indirect
@Override @Override
public int lockRecipes(Collection<Recipe<?>> recipes) { public int lockRecipes( Collection<Recipe<?>> recipes )
{
return 0; return 0;
} }
@ -169,12 +171,14 @@ public class FakePlayer extends ServerPlayerEntity {
public void setGameMode( GameMode gameMode ) { } public void setGameMode( GameMode gameMode ) { }
@Override @Override
public void sendMessage(Text message, MessageType type, UUID senderUuid) { public void sendMessage( Text message, MessageType type, UUID senderUuid )
{
} }
@Override @Override
public String getIp() { public String getIp()
{
return "[Fake Player]"; return "[Fake Player]";
} }
@ -199,8 +203,10 @@ public class FakePlayer extends ServerPlayerEntity {
@Override @Override
public void playSound( SoundEvent soundEvent, SoundCategory soundCategory, float volume, float pitch ) { } public void playSound( SoundEvent soundEvent, SoundCategory soundCategory, float volume, float pitch ) { }
private static class FakeNetHandler extends ServerPlayNetworkHandler { private static class FakeNetHandler extends ServerPlayNetworkHandler
FakeNetHandler(ServerPlayerEntity player) { {
FakeNetHandler( ServerPlayerEntity player )
{
super( player.server, new FakeConnection(), player ); super( player.server, new FakeConnection(), player );
} }
@ -217,50 +223,62 @@ public class FakePlayer extends ServerPlayerEntity {
public void sendPacket( Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> listener ) { } public void sendPacket( Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> listener ) { }
} }
private static class FakeConnection extends ClientConnection { private static class FakeConnection extends ClientConnection
FakeConnection() { {
FakeConnection()
{
super( NetworkSide.CLIENTBOUND ); super( NetworkSide.CLIENTBOUND );
} }
@Override @Override
public void channelActive(ChannelHandlerContext active) { public void channelActive( ChannelHandlerContext active )
{
} }
@Override @Override
public void setState(NetworkState state) { public void setState( NetworkState state )
{
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext context, Throwable err) { public void exceptionCaught( ChannelHandlerContext context, Throwable err )
{
} }
@Override @Override
protected void channelRead0(ChannelHandlerContext context, Packet<?> packet) { protected void channelRead0( ChannelHandlerContext context, Packet<?> packet )
{
} }
@Override @Override
public void send(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> listener) { public void send( Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> listener )
{
} }
@Override @Override
public void tick() { public void tick()
{
} }
@Override @Override
public void disconnect(Text message) { public void disconnect( Text message )
{
} }
@Override @Override
public void setupEncryption(Cipher cipher, Cipher cipher2) { public void setupEncryption( Cipher cipher, Cipher cipher2 )
{
super.setupEncryption( cipher, cipher2 ); super.setupEncryption( cipher, cipher2 );
} }
@Override @Override
public void disableAutoRead() { public void disableAutoRead()
{
} }
@Override @Override
public void setCompressionThreshold(int size) { public void setCompressionThreshold( int size )
{
} }
} }
} }

View File

@ -6,15 +6,11 @@
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import dan200.computercraft.api.lua.ILuaCallback; import dan200.computercraft.api.lua.ILuaCallback;
import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.util.ItemStorage; import dan200.computercraft.shared.util.ItemStorage;
import net.minecraft.inventory.Inventory; import net.minecraft.inventory.Inventory;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@ -22,12 +18,16 @@ import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* The interface passed to turtle by turtles, providing methods that they can call. * The interface passed to turtle by turtles, providing methods that they can call.
* *
* This should not be implemented by your classes. Do not interact with turtles except via this interface and {@link ITurtleUpgrade}. * This should not be implemented by your classes. Do not interact with turtles except via this interface and {@link ITurtleUpgrade}.
*/ */
public interface ITurtleAccess { public interface ITurtleAccess
{
/** /**
* Returns the world in which the turtle resides. * Returns the world in which the turtle resides.
* *
@ -265,7 +265,8 @@ public interface ITurtleAccess {
*/ */
void updateUpgradeNBTData( @Nonnull TurtleSide side ); void updateUpgradeNBTData( @Nonnull TurtleSide side );
default ItemStorage getItemHandler() { default ItemStorage getItemHandler()
{
return ItemStorage.wrap( this.getInventory() ); return ItemStorage.wrap( this.getInventory() );
} }

View File

@ -14,7 +14,8 @@ import javax.annotation.Nonnull;
* @see ITurtleAccess#executeCommand(ITurtleCommand) * @see ITurtleAccess#executeCommand(ITurtleCommand)
*/ */
@FunctionalInterface @FunctionalInterface
public interface ITurtleCommand { public interface ITurtleCommand
{
/** /**
* Will be called by the turtle on the main thread when it is time to execute the custom command. * Will be called by the turtle on the main thread when it is time to execute the custom command.
* *

View File

@ -6,18 +6,16 @@
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.IUpgradeBase; import dan200.computercraft.api.IUpgradeBase;
import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.client.TransformedModel;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.util.math.Direction;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.minecraft.util.math.Direction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* The primary interface for defining an update for Turtles. A turtle update can either be a new tool, or a new peripheral. * The primary interface for defining an update for Turtles. A turtle update can either be a new tool, or a new peripheral.
@ -46,7 +44,8 @@ public interface ITurtleUpgrade extends IUpgradeBase
* @return The newly created peripheral. You may return {@code null} if this upgrade is a Tool and this method is not expected to be called. * @return The newly created peripheral. You may return {@code null} if this upgrade is a Tool and this method is not expected to be called.
*/ */
@Nullable @Nullable
default IPeripheral createPeripheral(@Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side) { default IPeripheral createPeripheral( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side )
{
return null; return null;
} }
@ -63,7 +62,8 @@ public interface ITurtleUpgrade extends IUpgradeBase
* this method is not expected to be called. * this method is not expected to be called.
*/ */
@Nonnull @Nonnull
default TurtleCommandResult useTool(@Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull Direction direction) { default TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull Direction direction )
{
return TurtleCommandResult.failure(); return TurtleCommandResult.failure();
} }
@ -84,6 +84,7 @@ public interface ITurtleUpgrade extends IUpgradeBase
* @param turtle Access to the turtle that the upgrade resides on. * @param turtle Access to the turtle that the upgrade resides on.
* @param side Which side of the turtle (left or right) the upgrade resides on. * @param side Which side of the turtle (left or right) the upgrade resides on.
*/ */
default void update(@Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side) { default void update( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side )
{
} }
} }

View File

@ -13,7 +13,8 @@ package dan200.computercraft.api.turtle;
* *
* @see ITurtleAccess#playAnimation(TurtleAnimation) * @see ITurtleAccess#playAnimation(TurtleAnimation)
*/ */
public enum TurtleAnimation { public enum TurtleAnimation
{
/** /**
* An animation which does nothing. This takes no time to complete. * An animation which does nothing. This takes no time to complete.
* *

View File

@ -15,14 +15,16 @@ import javax.annotation.Nullable;
* @see ITurtleCommand#execute(ITurtleAccess) * @see ITurtleCommand#execute(ITurtleAccess)
* @see ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, Direction) * @see ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, Direction)
*/ */
public final class TurtleCommandResult { public final class TurtleCommandResult
{
private static final TurtleCommandResult EMPTY_SUCCESS = new TurtleCommandResult( true, null, null ); private static final TurtleCommandResult EMPTY_SUCCESS = new TurtleCommandResult( true, null, null );
private static final TurtleCommandResult EMPTY_FAILURE = new TurtleCommandResult( false, null, null ); private static final TurtleCommandResult EMPTY_FAILURE = new TurtleCommandResult( false, null, null );
private final boolean success; private final boolean success;
private final String errorMessage; private final String errorMessage;
private final Object[] results; private final Object[] results;
private TurtleCommandResult(boolean success, String errorMessage, Object[] results) { private TurtleCommandResult( boolean success, String errorMessage, Object[] results )
{
this.success = success; this.success = success;
this.errorMessage = errorMessage; this.errorMessage = errorMessage;
this.results = results; this.results = results;
@ -34,7 +36,8 @@ public final class TurtleCommandResult {
* @return A successful command result with no values. * @return A successful command result with no values.
*/ */
@Nonnull @Nonnull
public static TurtleCommandResult success() { public static TurtleCommandResult success()
{
return EMPTY_SUCCESS; return EMPTY_SUCCESS;
} }
@ -45,8 +48,10 @@ public final class TurtleCommandResult {
* @return A successful command result with the given values. * @return A successful command result with the given values.
*/ */
@Nonnull @Nonnull
public static TurtleCommandResult success(@Nullable Object[] results) { public static TurtleCommandResult success( @Nullable Object[] results )
if (results == null || results.length == 0) { {
if( results == null || results.length == 0 )
{
return EMPTY_SUCCESS; return EMPTY_SUCCESS;
} }
return new TurtleCommandResult( true, null, results ); return new TurtleCommandResult( true, null, results );
@ -58,7 +63,8 @@ public final class TurtleCommandResult {
* @return A failed command result with no message. * @return A failed command result with no message.
*/ */
@Nonnull @Nonnull
public static TurtleCommandResult failure() { public static TurtleCommandResult failure()
{
return EMPTY_FAILURE; return EMPTY_FAILURE;
} }
@ -69,8 +75,10 @@ public final class TurtleCommandResult {
* @return A failed command result with a message. * @return A failed command result with a message.
*/ */
@Nonnull @Nonnull
public static TurtleCommandResult failure(@Nullable String errorMessage) { public static TurtleCommandResult failure( @Nullable String errorMessage )
if (errorMessage == null) { {
if( errorMessage == null )
{
return EMPTY_FAILURE; return EMPTY_FAILURE;
} }
return new TurtleCommandResult( false, errorMessage, null ); return new TurtleCommandResult( false, errorMessage, null );
@ -81,7 +89,8 @@ public final class TurtleCommandResult {
* *
* @return If the command was successful. * @return If the command was successful.
*/ */
public boolean isSuccess() { public boolean isSuccess()
{
return this.success; return this.success;
} }
@ -91,7 +100,8 @@ public final class TurtleCommandResult {
* @return The command's error message, or {@code null} if it was a success. * @return The command's error message, or {@code null} if it was a success.
*/ */
@Nullable @Nullable
public String getErrorMessage() { public String getErrorMessage()
{
return this.errorMessage; return this.errorMessage;
} }
@ -101,7 +111,8 @@ public final class TurtleCommandResult {
* @return The command's result, or {@code null} if it was a failure. * @return The command's result, or {@code null} if it was a failure.
*/ */
@Nullable @Nullable
public Object[] getResults() { public Object[] getResults()
{
return this.results; return this.results;
} }
} }

View File

@ -9,7 +9,8 @@ package dan200.computercraft.api.turtle;
/** /**
* An enum representing the two sides of the turtle that a turtle turtle might reside. * An enum representing the two sides of the turtle that a turtle turtle might reside.
*/ */
public enum TurtleSide { public enum TurtleSide
{
/** /**
* The turtle's left side (where the pickaxe usually is on a Wireless Mining Turtle). * The turtle's left side (where the pickaxe usually is on a Wireless Mining Turtle).
*/ */

View File

@ -11,7 +11,8 @@ package dan200.computercraft.api.turtle;
* *
* @see ITurtleUpgrade#getType() * @see ITurtleUpgrade#getType()
*/ */
public enum TurtleUpgradeType { public enum TurtleUpgradeType
{
/** /**
* A tool is rendered as an item on the side of the turtle, and responds to the {@code turtle.dig()} and {@code turtle.attack()} methods (Such as * A tool is rendered as an item on the side of the turtle, and responds to the {@code turtle.dig()} and {@code turtle.attack()} methods (Such as
* pickaxe or sword on Mining and Melee turtles). * pickaxe or sword on Mining and Melee turtles).
@ -30,11 +31,13 @@ public enum TurtleUpgradeType {
*/ */
BOTH; BOTH;
public boolean isTool() { public boolean isTool()
{
return this == TOOL || this == BOTH; return this == TOOL || this == BOTH;
} }
public boolean isPeripheral() { public boolean isPeripheral()
{
return this == PERIPHERAL || this == BOTH; return this == PERIPHERAL || this == BOTH;
} }
} }

View File

@ -12,7 +12,8 @@ package dan200.computercraft.api.turtle;
* @see ITurtleUpgrade#getType() * @see ITurtleUpgrade#getType()
* @see ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, Direction) * @see ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, Direction)
*/ */
public enum TurtleVerb { public enum TurtleVerb
{
/** /**
* The turtle called {@code turtle.dig()}, {@code turtle.digUp()} or {@code turtle.digDown()}. * The turtle called {@code turtle.dig()}, {@code turtle.digUp()} or {@code turtle.digDown()}.
*/ */

View File

@ -11,7 +11,8 @@ package dan200.computercraft.api.turtle.event;
* *
* @see TurtleActionEvent * @see TurtleActionEvent
*/ */
public enum TurtleAction { public enum TurtleAction
{
/** /**
* A turtle moves to a new position. * A turtle moves to a new position.
* *

View File

@ -6,30 +6,32 @@
package dan200.computercraft.api.turtle.event; package dan200.computercraft.api.turtle.event;
import java.util.Objects; import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.TurtleCommandResult;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Objects;
import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.TurtleCommandResult;
/** /**
* An event fired when a turtle is performing a known action. * An event fired when a turtle is performing a known action.
*/ */
public class TurtleActionEvent extends TurtleEvent { public class TurtleActionEvent extends TurtleEvent
{
private final TurtleAction action; private final TurtleAction action;
private String failureMessage; private String failureMessage;
private boolean cancelled = false; private boolean cancelled = false;
public TurtleActionEvent(@Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action) { public TurtleActionEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action )
{
super( turtle ); super( turtle );
Objects.requireNonNull( action, "action cannot be null" ); Objects.requireNonNull( action, "action cannot be null" );
this.action = action; this.action = action;
} }
public TurtleAction getAction() { public TurtleAction getAction()
{
return this.action; return this.action;
} }
@ -43,7 +45,8 @@ public class TurtleActionEvent extends TurtleEvent {
* @deprecated Use {@link #setCanceled(boolean, String)} instead. * @deprecated Use {@link #setCanceled(boolean, String)} instead.
*/ */
@Deprecated @Deprecated
public void setCanceled(boolean cancel) { public void setCanceled( boolean cancel )
{
this.setCanceled( cancel, null ); this.setCanceled( cancel, null );
} }
@ -56,7 +59,8 @@ public class TurtleActionEvent extends TurtleEvent {
* @param failureMessage The message to return to the user explaining the failure. * @param failureMessage The message to return to the user explaining the failure.
* @see TurtleCommandResult#failure(String) * @see TurtleCommandResult#failure(String)
*/ */
public void setCanceled(boolean cancel, @Nullable String failureMessage) { public void setCanceled( boolean cancel, @Nullable String failureMessage )
{
this.cancelled = true; this.cancelled = true;
this.failureMessage = cancel ? failureMessage : null; this.failureMessage = cancel ? failureMessage : null;
} }
@ -69,11 +73,13 @@ public class TurtleActionEvent extends TurtleEvent {
* @see #setCanceled(boolean, String) * @see #setCanceled(boolean, String)
*/ */
@Nullable @Nullable
public String getFailureMessage() { public String getFailureMessage()
{
return this.failureMessage; return this.failureMessage;
} }
public boolean isCancelled() { public boolean isCancelled()
{
return this.cancelled; return this.cancelled;
} }
} }

View File

@ -6,29 +6,29 @@
package dan200.computercraft.api.turtle.event; package dan200.computercraft.api.turtle.event;
import java.util.Objects;
import javax.annotation.Nonnull;
import dan200.computercraft.api.turtle.FakePlayer; import dan200.computercraft.api.turtle.FakePlayer;
import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleSide;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import javax.annotation.Nonnull;
import java.util.Objects;
/** /**
* Fired when a turtle attempts to attack an entity. * Fired when a turtle attempts to attack an entity.
* *
* @see TurtleAction#ATTACK * @see TurtleAction#ATTACK
*/ */
public class TurtleAttackEvent extends TurtlePlayerEvent { public class TurtleAttackEvent extends TurtlePlayerEvent
{
private final Entity target; private final Entity target;
private final ITurtleUpgrade upgrade; private final ITurtleUpgrade upgrade;
private final TurtleSide side; private final TurtleSide side;
public TurtleAttackEvent( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Entity target, @Nonnull ITurtleUpgrade upgrade, public TurtleAttackEvent( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Entity target, @Nonnull ITurtleUpgrade upgrade,
@Nonnull TurtleSide side) { @Nonnull TurtleSide side )
{
super( turtle, TurtleAction.ATTACK, player ); super( turtle, TurtleAction.ATTACK, player );
Objects.requireNonNull( target, "target cannot be null" ); Objects.requireNonNull( target, "target cannot be null" );
Objects.requireNonNull( upgrade, "upgrade cannot be null" ); Objects.requireNonNull( upgrade, "upgrade cannot be null" );
@ -44,7 +44,8 @@ public class TurtleAttackEvent extends TurtlePlayerEvent {
* @return The entity being attacked. * @return The entity being attacked.
*/ */
@Nonnull @Nonnull
public Entity getTarget() { public Entity getTarget()
{
return this.target; return this.target;
} }
@ -54,7 +55,8 @@ public class TurtleAttackEvent extends TurtlePlayerEvent {
* @return The upgrade responsible for attacking. * @return The upgrade responsible for attacking.
*/ */
@Nonnull @Nonnull
public ITurtleUpgrade getUpgrade() { public ITurtleUpgrade getUpgrade()
{
return this.upgrade; return this.upgrade;
} }
@ -64,7 +66,8 @@ public class TurtleAttackEvent extends TurtlePlayerEvent {
* @return The upgrade's side. * @return The upgrade's side.
*/ */
@Nonnull @Nonnull
public TurtleSide getSide() { public TurtleSide getSide()
{
return this.side; return this.side;
} }
} }

View File

@ -6,22 +6,20 @@
package dan200.computercraft.api.turtle.event; package dan200.computercraft.api.turtle.event;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nonnull;
import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.turtle.FakePlayer; import dan200.computercraft.api.turtle.FakePlayer;
import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleSide;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.util.Map;
import java.util.Objects;
/** /**
* A general event for when a turtle interacts with a block or region. * A general event for when a turtle interacts with a block or region.
* *
@ -31,12 +29,14 @@ import net.minecraft.world.World;
* *
* Be aware that some events (such as {@link TurtleInventoryEvent}) do not necessarily interact with a block, simply objects within that block space. * Be aware that some events (such as {@link TurtleInventoryEvent}) do not necessarily interact with a block, simply objects within that block space.
*/ */
public abstract class TurtleBlockEvent extends TurtlePlayerEvent { public abstract class TurtleBlockEvent extends TurtlePlayerEvent
{
private final World world; private final World world;
private final BlockPos pos; private final BlockPos pos;
protected TurtleBlockEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull World world, protected TurtleBlockEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull World world,
@Nonnull BlockPos pos) { @Nonnull BlockPos pos )
{
super( turtle, action, player ); super( turtle, action, player );
Objects.requireNonNull( world, "world cannot be null" ); Objects.requireNonNull( world, "world cannot be null" );
@ -50,7 +50,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent {
* *
* @return The world the turtle is interacting in. * @return The world the turtle is interacting in.
*/ */
public World getWorld() { public World getWorld()
{
return this.world; return this.world;
} }
@ -59,7 +60,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent {
* *
* @return The position the turtle is interacting with. * @return The position the turtle is interacting with.
*/ */
public BlockPos getPos() { public BlockPos getPos()
{
return this.pos; return this.pos;
} }
@ -68,13 +70,15 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent {
* *
* @see TurtleAction#DIG * @see TurtleAction#DIG
*/ */
public static class Dig extends TurtleBlockEvent { public static class Dig extends TurtleBlockEvent
{
private final BlockState block; private final BlockState block;
private final ITurtleUpgrade upgrade; private final ITurtleUpgrade upgrade;
private final TurtleSide side; private final TurtleSide side;
public Dig( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState block, public Dig( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState block,
@Nonnull ITurtleUpgrade upgrade, @Nonnull TurtleSide side) { @Nonnull ITurtleUpgrade upgrade, @Nonnull TurtleSide side )
{
super( turtle, TurtleAction.DIG, player, world, pos ); super( turtle, TurtleAction.DIG, player, world, pos );
Objects.requireNonNull( block, "block cannot be null" ); Objects.requireNonNull( block, "block cannot be null" );
@ -91,7 +95,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent {
* @return The block which is going to be broken. * @return The block which is going to be broken.
*/ */
@Nonnull @Nonnull
public BlockState getBlock() { public BlockState getBlock()
{
return this.block; return this.block;
} }
@ -101,7 +106,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent {
* @return The upgrade doing the digging. * @return The upgrade doing the digging.
*/ */
@Nonnull @Nonnull
public ITurtleUpgrade getUpgrade() { public ITurtleUpgrade getUpgrade()
{
return this.upgrade; return this.upgrade;
} }
@ -111,7 +117,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent {
* @return The upgrade's side. * @return The upgrade's side.
*/ */
@Nonnull @Nonnull
public TurtleSide getSide() { public TurtleSide getSide()
{
return this.side; return this.side;
} }
} }
@ -121,8 +128,10 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent {
* *
* @see TurtleAction#MOVE * @see TurtleAction#MOVE
*/ */
public static class Move extends TurtleBlockEvent { public static class Move extends TurtleBlockEvent
public Move(@Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos) { {
public Move( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos )
{
super( turtle, TurtleAction.MOVE, player, world, pos ); super( turtle, TurtleAction.MOVE, player, world, pos );
} }
} }
@ -132,10 +141,12 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent {
* *
* @see TurtleAction#PLACE * @see TurtleAction#PLACE
*/ */
public static class Place extends TurtleBlockEvent { public static class Place extends TurtleBlockEvent
{
private final ItemStack stack; private final ItemStack stack;
public Place(@Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull ItemStack stack) { public Place( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull ItemStack stack )
{
super( turtle, TurtleAction.PLACE, player, world, pos ); super( turtle, TurtleAction.PLACE, player, world, pos );
Objects.requireNonNull( stack, "stack cannot be null" ); Objects.requireNonNull( stack, "stack cannot be null" );
@ -148,7 +159,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent {
* @return The item stack to be placed. * @return The item stack to be placed.
*/ */
@Nonnull @Nonnull
public ItemStack getStack() { public ItemStack getStack()
{
return this.stack; return this.stack;
} }
} }
@ -160,12 +172,14 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent {
* *
* @see TurtleAction#INSPECT * @see TurtleAction#INSPECT
*/ */
public static class Inspect extends TurtleBlockEvent { public static class Inspect extends TurtleBlockEvent
{
private final BlockState state; private final BlockState state;
private final Map<String, Object> data; private final Map<String, Object> data;
public Inspect( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, public Inspect( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state,
@Nonnull Map<String, Object> data) { @Nonnull Map<String, Object> data )
{
super( turtle, TurtleAction.INSPECT, player, world, pos ); super( turtle, TurtleAction.INSPECT, player, world, pos );
Objects.requireNonNull( state, "state cannot be null" ); Objects.requireNonNull( state, "state cannot be null" );
@ -180,7 +194,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent {
* @return The inspected block state. * @return The inspected block state.
*/ */
@Nonnull @Nonnull
public BlockState getState() { public BlockState getState()
{
return this.state; return this.state;
} }
@ -190,7 +205,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent {
* @return This block's inspection data. * @return This block's inspection data.
*/ */
@Nonnull @Nonnull
public Map<String, Object> getData() { public Map<String, Object> getData()
{
return this.data; return this.data;
} }
@ -199,7 +215,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent {
* *
* @param newData The data to add. Note all values should be convertible to Lua (see {@link MethodResult#of(Object)}). * @param newData The data to add. Note all values should be convertible to Lua (see {@link MethodResult#of(Object)}).
*/ */
public void addData(@Nonnull Map<String, ?> newData) { public void addData( @Nonnull Map<String, ?> newData )
{
Objects.requireNonNull( newData, "newData cannot be null" ); Objects.requireNonNull( newData, "newData cannot be null" );
this.data.putAll( newData ); this.data.putAll( newData );
} }

View File

@ -6,13 +6,12 @@
package dan200.computercraft.api.turtle.event; package dan200.computercraft.api.turtle.event;
import java.util.Objects;
import javax.annotation.Nonnull;
import com.google.common.eventbus.EventBus; import com.google.common.eventbus.EventBus;
import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleAccess;
import javax.annotation.Nonnull;
import java.util.Objects;
/** /**
* A base class for all events concerning a turtle. This will only ever constructed and fired on the server side, so sever specific methods on {@link * A base class for all events concerning a turtle. This will only ever constructed and fired on the server side, so sever specific methods on {@link
* ITurtleAccess} are safe to use. * ITurtleAccess} are safe to use.
@ -21,17 +20,20 @@ import dan200.computercraft.api.turtle.ITurtleAccess;
* *
* @see TurtleActionEvent * @see TurtleActionEvent
*/ */
public abstract class TurtleEvent { public abstract class TurtleEvent
{
public static final EventBus EVENT_BUS = new EventBus(); public static final EventBus EVENT_BUS = new EventBus();
private final ITurtleAccess turtle; private final ITurtleAccess turtle;
protected TurtleEvent(@Nonnull ITurtleAccess turtle) { protected TurtleEvent( @Nonnull ITurtleAccess turtle )
{
Objects.requireNonNull( turtle, "turtle cannot be null" ); Objects.requireNonNull( turtle, "turtle cannot be null" );
this.turtle = turtle; this.turtle = turtle;
} }
public static boolean post(TurtleActionEvent event) { public static boolean post( TurtleActionEvent event )
{
EVENT_BUS.post( event ); EVENT_BUS.post( event );
return event.isCancelled(); return event.isCancelled();
} }
@ -42,7 +44,8 @@ public abstract class TurtleEvent {
* @return The access for this turtle. * @return The access for this turtle.
*/ */
@Nonnull @Nonnull
public ITurtleAccess getTurtle() { public ITurtleAccess getTurtle()
{
return this.turtle; return this.turtle;
} }

View File

@ -6,16 +6,14 @@
package dan200.computercraft.api.turtle.event; package dan200.computercraft.api.turtle.event;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nonnull;
import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleAccess;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull;
import java.util.Map;
import java.util.Objects;
/** /**
* Fired when a turtle gathers data on an item in its inventory. * Fired when a turtle gathers data on an item in its inventory.
* *
@ -24,17 +22,20 @@ import net.minecraft.item.ItemStack;
* *
* @see TurtleAction#INSPECT_ITEM * @see TurtleAction#INSPECT_ITEM
*/ */
public class TurtleInspectItemEvent extends TurtleActionEvent { public class TurtleInspectItemEvent extends TurtleActionEvent
{
private final ItemStack stack; private final ItemStack stack;
private final Map<String, Object> data; private final Map<String, Object> data;
private final boolean mainThread; private final boolean mainThread;
@Deprecated @Deprecated
public TurtleInspectItemEvent(@Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack, @Nonnull Map<String, Object> data) { public TurtleInspectItemEvent( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack, @Nonnull Map<String, Object> data )
{
this( turtle, stack, data, false ); this( turtle, stack, data, false );
} }
public TurtleInspectItemEvent(@Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack, @Nonnull Map<String, Object> data, boolean mainThread) { public TurtleInspectItemEvent( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack, @Nonnull Map<String, Object> data, boolean mainThread )
{
super( turtle, TurtleAction.INSPECT_ITEM ); super( turtle, TurtleAction.INSPECT_ITEM );
Objects.requireNonNull( stack, "stack cannot be null" ); Objects.requireNonNull( stack, "stack cannot be null" );
@ -50,7 +51,8 @@ public class TurtleInspectItemEvent extends TurtleActionEvent {
* @return The item stack which is being inspected. This should <b>not</b> be modified. * @return The item stack which is being inspected. This should <b>not</b> be modified.
*/ */
@Nonnull @Nonnull
public ItemStack getStack() { public ItemStack getStack()
{
return this.stack; return this.stack;
} }
@ -60,7 +62,8 @@ public class TurtleInspectItemEvent extends TurtleActionEvent {
* @return This items's inspection data. * @return This items's inspection data.
*/ */
@Nonnull @Nonnull
public Map<String, Object> getData() { public Map<String, Object> getData()
{
return this.data; return this.data;
} }
@ -69,7 +72,8 @@ public class TurtleInspectItemEvent extends TurtleActionEvent {
* *
* @return If this is run on the main thread. * @return If this is run on the main thread.
*/ */
public boolean onMainThread() { public boolean onMainThread()
{
return this.mainThread; return this.mainThread;
} }
@ -78,7 +82,8 @@ public class TurtleInspectItemEvent extends TurtleActionEvent {
* *
* @param newData The data to add. Note all values should be convertible to Lua (see {@link MethodResult#of(Object)}). * @param newData The data to add. Note all values should be convertible to Lua (see {@link MethodResult#of(Object)}).
*/ */
public void addData(@Nonnull Map<String, ?> newData) { public void addData( @Nonnull Map<String, ?> newData )
{
Objects.requireNonNull( newData, "newData cannot be null" ); Objects.requireNonNull( newData, "newData cannot be null" );
this.data.putAll( newData ); this.data.putAll( newData );
} }

View File

@ -6,27 +6,27 @@
package dan200.computercraft.api.turtle.event; package dan200.computercraft.api.turtle.event;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import dan200.computercraft.api.turtle.FakePlayer; import dan200.computercraft.api.turtle.FakePlayer;
import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleAccess;
import net.minecraft.inventory.Inventory; import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Objects;
/** /**
* Fired when a turtle attempts to interact with an inventory. * Fired when a turtle attempts to interact with an inventory.
*/ */
public abstract class TurtleInventoryEvent extends TurtleBlockEvent { public abstract class TurtleInventoryEvent extends TurtleBlockEvent
{
private final Inventory handler; private final Inventory handler;
protected TurtleInventoryEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull World world, protected TurtleInventoryEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull World world,
@Nonnull BlockPos pos, @Nullable Inventory handler) { @Nonnull BlockPos pos, @Nullable Inventory handler )
{
super( turtle, action, player, world, pos ); super( turtle, action, player, world, pos );
this.handler = handler; this.handler = handler;
} }
@ -37,7 +37,8 @@ public abstract class TurtleInventoryEvent extends TurtleBlockEvent {
* @return The inventory being interacted with, {@code null} if the item will be dropped to/sucked from the world. * @return The inventory being interacted with, {@code null} if the item will be dropped to/sucked from the world.
*/ */
@Nullable @Nullable
public Inventory getItemHandler() { public Inventory getItemHandler()
{
return this.handler; return this.handler;
} }
@ -46,8 +47,10 @@ public abstract class TurtleInventoryEvent extends TurtleBlockEvent {
* *
* @see TurtleAction#SUCK * @see TurtleAction#SUCK
*/ */
public static class Suck extends TurtleInventoryEvent { public static class Suck extends TurtleInventoryEvent
public Suck(@Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nullable Inventory handler) { {
public Suck( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nullable Inventory handler )
{
super( turtle, TurtleAction.SUCK, player, world, pos, handler ); super( turtle, TurtleAction.SUCK, player, world, pos, handler );
} }
} }
@ -57,11 +60,13 @@ public abstract class TurtleInventoryEvent extends TurtleBlockEvent {
* *
* @see TurtleAction#DROP * @see TurtleAction#DROP
*/ */
public static class Drop extends TurtleInventoryEvent { public static class Drop extends TurtleInventoryEvent
{
private final ItemStack stack; private final ItemStack stack;
public Drop( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nullable Inventory handler, public Drop( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nullable Inventory handler,
@Nonnull ItemStack stack) { @Nonnull ItemStack stack )
{
super( turtle, TurtleAction.DROP, player, world, pos, handler ); super( turtle, TurtleAction.DROP, player, world, pos, handler );
Objects.requireNonNull( stack, "stack cannot be null" ); Objects.requireNonNull( stack, "stack cannot be null" );
@ -74,7 +79,8 @@ public abstract class TurtleInventoryEvent extends TurtleBlockEvent {
* @return The item stack which will be dropped. This should <b>not</b> be modified. * @return The item stack which will be dropped. This should <b>not</b> be modified.
*/ */
@Nonnull @Nonnull
public ItemStack getStack() { public ItemStack getStack()
{
return this.stack; return this.stack;
} }
} }

View File

@ -6,22 +6,23 @@
package dan200.computercraft.api.turtle.event; package dan200.computercraft.api.turtle.event;
import java.util.Objects;
import javax.annotation.Nonnull;
import dan200.computercraft.api.turtle.FakePlayer; import dan200.computercraft.api.turtle.FakePlayer;
import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleAccess;
import javax.annotation.Nonnull;
import java.util.Objects;
/** /**
* An action done by a turtle which is normally done by a player. * An action done by a turtle which is normally done by a player.
* *
* {@link #getPlayer()} may be used to modify the player's attributes or perform permission checks. * {@link #getPlayer()} may be used to modify the player's attributes or perform permission checks.
*/ */
public abstract class TurtlePlayerEvent extends TurtleActionEvent { public abstract class TurtlePlayerEvent extends TurtleActionEvent
{
private final FakePlayer player; private final FakePlayer player;
protected TurtlePlayerEvent(@Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player) { protected TurtlePlayerEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player )
{
super( turtle, action ); super( turtle, action );
Objects.requireNonNull( player, "player cannot be null" ); Objects.requireNonNull( player, "player cannot be null" );
@ -36,7 +37,8 @@ public abstract class TurtlePlayerEvent extends TurtleActionEvent {
* @return A {@link FakePlayer} representing this turtle. * @return A {@link FakePlayer} representing this turtle.
*/ */
@Nonnull @Nonnull
public FakePlayer getPlayer() { public FakePlayer getPlayer()
{
return this.player; return this.player;
} }
} }

View File

@ -6,14 +6,12 @@
package dan200.computercraft.api.turtle.event; package dan200.computercraft.api.turtle.event;
import java.util.Objects; import dan200.computercraft.api.turtle.ITurtleAccess;
import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Objects;
import dan200.computercraft.api.turtle.ITurtleAccess;
import net.minecraft.item.ItemStack;
/** /**
* Fired when a turtle attempts to refuel from an item. * Fired when a turtle attempts to refuel from an item.
@ -21,11 +19,13 @@ import net.minecraft.item.ItemStack;
* One may use {@link #setCanceled(boolean, String)} to prevent refueling from this specific item. Additionally, you may use {@link #setHandler(Handler)} to * One may use {@link #setCanceled(boolean, String)} to prevent refueling from this specific item. Additionally, you may use {@link #setHandler(Handler)} to
* register a custom fuel provider. * register a custom fuel provider.
*/ */
public class TurtleRefuelEvent extends TurtleActionEvent { public class TurtleRefuelEvent extends TurtleActionEvent
{
private final ItemStack stack; private final ItemStack stack;
private Handler handler; private Handler handler;
public TurtleRefuelEvent(@Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack) { public TurtleRefuelEvent( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack )
{
super( turtle, TurtleAction.REFUEL ); super( turtle, TurtleAction.REFUEL );
Objects.requireNonNull( turtle, "turtle cannot be null" ); Objects.requireNonNull( turtle, "turtle cannot be null" );
@ -39,7 +39,8 @@ public class TurtleRefuelEvent extends TurtleActionEvent {
* *
* @return The stack to refuel from. * @return The stack to refuel from.
*/ */
public ItemStack getStack() { public ItemStack getStack()
{
return this.stack; return this.stack;
} }
@ -50,7 +51,8 @@ public class TurtleRefuelEvent extends TurtleActionEvent {
* @see #setHandler(Handler) * @see #setHandler(Handler)
*/ */
@Nullable @Nullable
public Handler getHandler() { public Handler getHandler()
{
return this.handler; return this.handler;
} }
@ -62,7 +64,8 @@ public class TurtleRefuelEvent extends TurtleActionEvent {
* @param handler The new refuel handler. * @param handler The new refuel handler.
* @see #getHandler() * @see #getHandler()
*/ */
public void setHandler(@Nullable Handler handler) { public void setHandler( @Nullable Handler handler )
{
this.handler = handler; this.handler = handler;
} }
@ -70,7 +73,8 @@ public class TurtleRefuelEvent extends TurtleActionEvent {
* Handles refuelling a turtle from a specific item. * Handles refuelling a turtle from a specific item.
*/ */
@FunctionalInterface @FunctionalInterface
public interface Handler { public interface Handler
{
/** /**
* Refuel a turtle using an item. * Refuel a turtle using an item.
* *

View File

@ -6,9 +6,6 @@
package dan200.computercraft.client; package dan200.computercraft.client;
import java.util.HashSet;
import java.util.function.Consumer;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.ComputerCraftRegistry;
import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.common.IColouredItem;
@ -16,7 +13,8 @@ import dan200.computercraft.shared.media.items.ItemDisk;
import dan200.computercraft.shared.media.items.ItemTreasureDisk; import dan200.computercraft.shared.media.items.ItemTreasureDisk;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.ModelLoader; import net.minecraft.client.render.model.ModelLoader;
@ -27,8 +25,8 @@ import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.resource.ResourceManager; import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; import java.util.HashSet;
import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; import java.util.function.Consumer;
/** /**
* Registers textures and models for items. * Registers textures and models for items.
@ -37,7 +35,8 @@ import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback;
"MethodCallSideOnly", "MethodCallSideOnly",
"LocalVariableDeclarationSideOnly" "LocalVariableDeclarationSideOnly"
} ) } )
public final class ClientRegistry { public final class ClientRegistry
{
private static final String[] EXTRA_MODELS = new String[] { private static final String[] EXTRA_MODELS = new String[] {
"turtle_modem_normal_off_left", "turtle_modem_normal_off_left",
"turtle_modem_normal_on_left", "turtle_modem_normal_on_left",
@ -69,20 +68,25 @@ public final class ClientRegistry {
private ClientRegistry() {} private ClientRegistry() {}
public static void onTextureStitchEvent(SpriteAtlasTexture atlasTexture, ClientSpriteRegistryCallback.Registry registry) { public static void onTextureStitchEvent( SpriteAtlasTexture atlasTexture, ClientSpriteRegistryCallback.Registry registry )
for (String extra : EXTRA_TEXTURES) { {
for( String extra : EXTRA_TEXTURES )
{
registry.register( new Identifier( ComputerCraft.MOD_ID, extra ) ); registry.register( new Identifier( ComputerCraft.MOD_ID, extra ) );
} }
} }
@SuppressWarnings( "NewExpressionSideOnly" ) @SuppressWarnings( "NewExpressionSideOnly" )
public static void onModelBakeEvent(ResourceManager manager, Consumer<ModelIdentifier> out) { public static void onModelBakeEvent( ResourceManager manager, Consumer<ModelIdentifier> out )
for (String model : EXTRA_MODELS) { {
for( String model : EXTRA_MODELS )
{
out.accept( new ModelIdentifier( new Identifier( ComputerCraft.MOD_ID, model ), "inventory" ) ); out.accept( new ModelIdentifier( new Identifier( ComputerCraft.MOD_ID, model ), "inventory" ) );
} }
} }
public static void onItemColours() { public static void onItemColours()
{
ColorProviderRegistry.ITEM.register( ( stack, layer ) -> { ColorProviderRegistry.ITEM.register( ( stack, layer ) -> {
return layer == 1 ? ((ItemDisk) stack.getItem()).getColour( stack ) : 0xFFFFFF; return layer == 1 ? ((ItemDisk) stack.getItem()).getColour( stack ) : 0xFFFFFF;
}, ComputerCraftRegistry.ModItems.DISK ); }, ComputerCraftRegistry.ModItems.DISK );
@ -91,7 +95,8 @@ public final class ClientRegistry {
ComputerCraftRegistry.ModItems.TREASURE_DISK ); ComputerCraftRegistry.ModItems.TREASURE_DISK );
ColorProviderRegistry.ITEM.register( ( stack, layer ) -> { ColorProviderRegistry.ITEM.register( ( stack, layer ) -> {
switch (layer) { switch( layer )
{
case 0: case 0:
default: default:
return 0xFFFFFF; return 0xFFFFFF;
@ -111,7 +116,8 @@ public final class ClientRegistry {
ComputerCraftRegistry.ModBlocks.TURTLE_ADVANCED ); ComputerCraftRegistry.ModBlocks.TURTLE_ADVANCED );
} }
private static BakedModel bake(ModelLoader loader, UnbakedModel model, Identifier identifier) { private static BakedModel bake( ModelLoader loader, UnbakedModel model, Identifier identifier )
{
model.getTextureDependencies( loader::getOrLoadModel, new HashSet<>() ); model.getTextureDependencies( loader::getOrLoadModel, new HashSet<>() );
return model.bake( loader, return model.bake( loader,
spriteIdentifier -> MinecraftClient.getInstance() spriteIdentifier -> MinecraftClient.getInstance()

View File

@ -6,36 +6,38 @@
package dan200.computercraft.client; package dan200.computercraft.client;
import javax.annotation.Nullable;
import dan200.computercraft.fabric.mixin.ChatHudAccess; import dan200.computercraft.fabric.mixin.ChatHudAccess;
import dan200.computercraft.shared.command.text.ChatHelpers; import dan200.computercraft.shared.command.text.ChatHelpers;
import dan200.computercraft.shared.command.text.TableBuilder; import dan200.computercraft.shared.command.text.TableBuilder;
import dan200.computercraft.shared.command.text.TableFormatter; import dan200.computercraft.shared.command.text.TableFormatter;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import org.apache.commons.lang3.StringUtils;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer; import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.hud.ChatHud; import net.minecraft.client.gui.hud.ChatHud;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable;
@SuppressWarnings( { @SuppressWarnings( {
"MethodCallSideOnly", "MethodCallSideOnly",
"LocalVariableDeclarationSideOnly" "LocalVariableDeclarationSideOnly"
} ) } )
public class ClientTableFormatter implements TableFormatter { public class ClientTableFormatter implements TableFormatter
{
public static final ClientTableFormatter INSTANCE = new ClientTableFormatter(); public static final ClientTableFormatter INSTANCE = new ClientTableFormatter();
private static Int2IntOpenHashMap lastHeights = new Int2IntOpenHashMap(); private static Int2IntOpenHashMap lastHeights = new Int2IntOpenHashMap();
@Override @Override
@Nullable @Nullable
public Text getPadding(Text component, int width) { public Text getPadding( Text component, int width )
{
int extraWidth = width - this.getWidth( component ); int extraWidth = width - this.getWidth( component );
if (extraWidth <= 0) { if( extraWidth <= 0 )
{
return null; return null;
} }
@ -48,22 +50,26 @@ public class ClientTableFormatter implements TableFormatter {
return ChatHelpers.coloured( StringUtils.repeat( ' ', spaces ) + StringUtils.repeat( (char) 712, extra ), Formatting.GRAY ); return ChatHelpers.coloured( StringUtils.repeat( ' ', spaces ) + StringUtils.repeat( (char) 712, extra ), Formatting.GRAY );
} }
private static TextRenderer renderer() { private static TextRenderer renderer()
{
return MinecraftClient.getInstance().textRenderer; return MinecraftClient.getInstance().textRenderer;
} }
@Override @Override
public int getColumnPadding() { public int getColumnPadding()
{
return 3; return 3;
} }
@Override @Override
public int getWidth(Text component) { public int getWidth( Text component )
{
return renderer().getWidth( component ); return renderer().getWidth( component );
} }
@Override @Override
public void writeLine(int id, Text component) { public void writeLine( int id, Text component )
{
MinecraftClient mc = MinecraftClient.getInstance(); MinecraftClient mc = MinecraftClient.getInstance();
ChatHud chat = mc.inGameHud.getChatHud(); ChatHud chat = mc.inGameHud.getChatHud();
@ -75,7 +81,8 @@ public class ClientTableFormatter implements TableFormatter {
} }
@Override @Override
public int display(TableBuilder table) { public int display( TableBuilder table )
{
ChatHud chat = MinecraftClient.getInstance().inGameHud.getChatHud(); ChatHud chat = MinecraftClient.getInstance().inGameHud.getChatHud();
int lastHeight = lastHeights.get( table.getId() ); int lastHeight = lastHeights.get( table.getId() );
@ -83,7 +90,8 @@ public class ClientTableFormatter implements TableFormatter {
int height = TableFormatter.super.display( table ); int height = TableFormatter.super.display( table );
lastHeights.put( table.getId(), height ); lastHeights.put( table.getId(), height );
for (int i = height; i < lastHeight; i++) { for( int i = height; i < lastHeight; i++ )
{
((ChatHudAccess) chat).callRemoveMessage( i + table.getId() ); ((ChatHudAccess) chat).callRemoveMessage( i + table.getId() );
} }
return height; return height;

View File

@ -8,38 +8,46 @@ package dan200.computercraft.client;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
public final class FrameInfo { public final class FrameInfo
{
private static int tick; private static int tick;
private static long renderFrame; private static long renderFrame;
static { static
{
} }
private FrameInfo() { private FrameInfo()
{
} }
public static void init() { public static void init()
{
ClientTickEvents.START_CLIENT_TICK.register( m -> { ClientTickEvents.START_CLIENT_TICK.register( m -> {
tick++; tick++;
} ); } );
} }
public static boolean getGlobalCursorBlink() { public static boolean getGlobalCursorBlink()
{
return (tick / 8) % 2 == 0; return (tick / 8) % 2 == 0;
} }
public static long getRenderFrame() { public static long getRenderFrame()
{
return renderFrame; return renderFrame;
} }
// TODO Call this in a callback // TODO Call this in a callback
public static void onTick() { public static void onTick()
{
tick++; tick++;
} }
// TODO Call this in a callback // TODO Call this in a callback
public static void onRenderFrame() { public static void onRenderFrame()
{
renderFrame++; renderFrame++;
} }
} }

View File

@ -6,29 +6,24 @@
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Palette; import dan200.computercraft.shared.util.Palette;
import org.lwjgl.opengl.GL11;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.*;
import net.minecraft.client.render.RenderPhase;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.util.math.AffineTransformation; import net.minecraft.client.util.math.AffineTransformation;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import org.lwjgl.opengl.GL11;
public final class FixedWidthFontRenderer { import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class FixedWidthFontRenderer
{
public static final int FONT_HEIGHT = 9; public static final int FONT_HEIGHT = 9;
public static final int FONT_WIDTH = 6; public static final int FONT_WIDTH = 6;
public static final float WIDTH = 256.0f; public static final float WIDTH = 256.0f;
@ -40,11 +35,13 @@ public final class FixedWidthFontRenderer {
public static final RenderLayer TYPE = Type.MAIN; public static final RenderLayer TYPE = Type.MAIN;
private FixedWidthFontRenderer() { private FixedWidthFontRenderer()
{
} }
public static void drawString( float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour, public static void drawString( float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour,
@Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize) { @Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize )
{
bindFont(); bindFont();
VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance() VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance()
@ -64,7 +61,8 @@ public final class FixedWidthFontRenderer {
renderer.draw(); renderer.draw();
} }
private static void bindFont() { private static void bindFont()
{
MinecraftClient.getInstance() MinecraftClient.getInstance()
.getTextureManager() .getTextureManager()
.bindTexture( FONT ); .bindTexture( FONT );
@ -73,17 +71,23 @@ public final class FixedWidthFontRenderer {
public static void drawString( @Nonnull Matrix4f transform, @Nonnull VertexConsumer renderer, float x, float y, @Nonnull TextBuffer text, public static void drawString( @Nonnull Matrix4f transform, @Nonnull VertexConsumer renderer, float x, float y, @Nonnull TextBuffer text,
@Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale,
float leftMarginSize, float rightMarginSize) { float leftMarginSize, float rightMarginSize )
if (backgroundColour != null) { {
if( backgroundColour != null )
{
drawBackground( transform, renderer, x, y, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize, FONT_HEIGHT ); drawBackground( transform, renderer, x, y, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize, FONT_HEIGHT );
} }
for (int i = 0; i < text.length(); i++) { for( int i = 0; i < text.length(); i++ )
{
double[] colour = palette.getColour( getColour( textColour.charAt( i ), Colour.BLACK ) ); double[] colour = palette.getColour( getColour( textColour.charAt( i ), Colour.BLACK ) );
float r, g, b; float r, g, b;
if (greyscale) { if( greyscale )
{
r = g = b = toGreyscale( colour ); r = g = b = toGreyscale( colour );
} else { }
else
{
r = (float) colour[0]; r = (float) colour[0];
g = (float) colour[1]; g = (float) colour[1];
b = (float) colour[2]; b = (float) colour[2];
@ -91,7 +95,8 @@ public final class FixedWidthFontRenderer {
// Draw char // Draw char
int index = text.charAt( i ); int index = text.charAt( i );
if (index > 255) { if( index > 255 )
{
index = '?'; index = '?';
} }
drawChar( transform, renderer, x + i * FONT_WIDTH, y, index, r, g, b ); drawChar( transform, renderer, x + i * FONT_WIDTH, y, index, r, g, b );
@ -101,12 +106,15 @@ public final class FixedWidthFontRenderer {
private static void drawBackground( @Nonnull Matrix4f transform, @Nonnull VertexConsumer renderer, float x, float y, private static void drawBackground( @Nonnull Matrix4f transform, @Nonnull VertexConsumer renderer, float x, float y,
@Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, float leftMarginSize, @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, float leftMarginSize,
float rightMarginSize, float height) { float rightMarginSize, float height )
if (leftMarginSize > 0) { {
if( leftMarginSize > 0 )
{
drawQuad( transform, renderer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) ); drawQuad( transform, renderer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) );
} }
if (rightMarginSize > 0) { if( rightMarginSize > 0 )
{
drawQuad( transform, drawQuad( transform,
renderer, renderer,
x + backgroundColour.length() * FONT_WIDTH, x + backgroundColour.length() * FONT_WIDTH,
@ -121,13 +129,16 @@ public final class FixedWidthFontRenderer {
// Batch together runs of identical background cells. // Batch together runs of identical background cells.
int blockStart = 0; int blockStart = 0;
char blockColour = '\0'; char blockColour = '\0';
for (int i = 0; i < backgroundColour.length(); i++) { for( int i = 0; i < backgroundColour.length(); i++ )
{
char colourIndex = backgroundColour.charAt( i ); char colourIndex = backgroundColour.charAt( i );
if (colourIndex == blockColour) { if( colourIndex == blockColour )
{
continue; continue;
} }
if (blockColour != '\0') { if( blockColour != '\0' )
{
drawQuad( transform, renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour ); drawQuad( transform, renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour );
} }
@ -135,7 +146,8 @@ public final class FixedWidthFontRenderer {
blockStart = i; blockStart = i;
} }
if (blockColour != '\0') { if( blockColour != '\0' )
{
drawQuad( transform, drawQuad( transform,
renderer, renderer,
x + blockStart * FONT_WIDTH, x + blockStart * FONT_WIDTH,
@ -148,17 +160,21 @@ public final class FixedWidthFontRenderer {
} }
} }
public static int getColour(char c, Colour def) { public static int getColour( char c, Colour def )
{
return 15 - Terminal.getColour( c, def ); return 15 - Terminal.getColour( c, def );
} }
public static float toGreyscale(double[] rgb) { public static float toGreyscale( double[] rgb )
{
return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3); return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3);
} }
private static void drawChar(Matrix4f transform, VertexConsumer buffer, float x, float y, int index, float r, float g, float b) { private static void drawChar( Matrix4f transform, VertexConsumer buffer, float x, float y, int index, float r, float g, float b )
{
// Short circuit to avoid the common case - the texture should be blank here after all. // Short circuit to avoid the common case - the texture should be blank here after all.
if (index == '\0' || index == ' ') { if( index == '\0' || index == ' ' )
{
return; return;
} }
@ -195,12 +211,16 @@ public final class FixedWidthFontRenderer {
} }
private static void drawQuad( Matrix4f transform, VertexConsumer buffer, float x, float y, float width, float height, Palette palette, private static void drawQuad( Matrix4f transform, VertexConsumer buffer, float x, float y, float width, float height, Palette palette,
boolean greyscale, char colourIndex) { boolean greyscale, char colourIndex )
{
double[] colour = palette.getColour( getColour( colourIndex, Colour.BLACK ) ); double[] colour = palette.getColour( getColour( colourIndex, Colour.BLACK ) );
float r, g, b; float r, g, b;
if (greyscale) { if( greyscale )
{
r = g = b = toGreyscale( colour ); r = g = b = toGreyscale( colour );
} else { }
else
{
r = (float) colour[0]; r = (float) colour[0];
g = (float) colour[1]; g = (float) colour[1];
b = (float) colour[2]; b = (float) colour[2];
@ -209,7 +229,8 @@ public final class FixedWidthFontRenderer {
drawQuad( transform, buffer, x, y, width, height, r, g, b ); drawQuad( transform, buffer, x, y, width, height, r, g, b );
} }
private static void drawQuad(Matrix4f transform, VertexConsumer buffer, float x, float y, float width, float height, float r, float g, float b) { private static void drawQuad( Matrix4f transform, VertexConsumer buffer, float x, float y, float width, float height, float r, float g, float b )
{
buffer.vertex( transform, x, y, 0 ) buffer.vertex( transform, x, y, 0 )
.color( r, g, b, 1.0f ) .color( r, g, b, 1.0f )
.texture( BACKGROUND_START, BACKGROUND_START ) .texture( BACKGROUND_START, BACKGROUND_START )
@ -238,7 +259,8 @@ public final class FixedWidthFontRenderer {
public static void drawTerminalWithoutCursor( @Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y, public static void drawTerminalWithoutCursor( @Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y,
@Nonnull Terminal terminal, boolean greyscale, float topMarginSize, float bottomMarginSize, @Nonnull Terminal terminal, boolean greyscale, float topMarginSize, float bottomMarginSize,
float leftMarginSize, float rightMarginSize) { float leftMarginSize, float rightMarginSize )
{
Palette palette = terminal.getPalette(); Palette palette = terminal.getPalette();
int height = terminal.getHeight(); int height = terminal.getHeight();
@ -266,7 +288,8 @@ public final class FixedWidthFontRenderer {
bottomMarginSize ); bottomMarginSize );
// The main text // The main text
for (int i = 0; i < height; i++) { for( int i = 0; i < height; i++ )
{
drawString( transform, drawString( transform,
buffer, buffer,
x, x,
@ -282,19 +305,24 @@ public final class FixedWidthFontRenderer {
} }
public static void drawCursor( @Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y, @Nonnull Terminal terminal, public static void drawCursor( @Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y, @Nonnull Terminal terminal,
boolean greyscale) { boolean greyscale )
{
Palette palette = terminal.getPalette(); Palette palette = terminal.getPalette();
int width = terminal.getWidth(); int width = terminal.getWidth();
int height = terminal.getHeight(); int height = terminal.getHeight();
int cursorX = terminal.getCursorX(); int cursorX = terminal.getCursorX();
int cursorY = terminal.getCursorY(); int cursorY = terminal.getCursorY();
if (terminal.getCursorBlink() && cursorX >= 0 && cursorX < width && cursorY >= 0 && cursorY < height && FrameInfo.getGlobalCursorBlink()) { if( terminal.getCursorBlink() && cursorX >= 0 && cursorX < width && cursorY >= 0 && cursorY < height && FrameInfo.getGlobalCursorBlink() )
{
double[] colour = palette.getColour( 15 - terminal.getTextColour() ); double[] colour = palette.getColour( 15 - terminal.getTextColour() );
float r, g, b; float r, g, b;
if (greyscale) { if( greyscale )
{
r = g = b = toGreyscale( colour ); r = g = b = toGreyscale( colour );
} else { }
else
{
r = (float) colour[0]; r = (float) colour[0];
g = (float) colour[1]; g = (float) colour[1];
b = (float) colour[2]; b = (float) colour[2];
@ -305,13 +333,15 @@ public final class FixedWidthFontRenderer {
} }
public static void drawTerminal( @Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y, @Nonnull Terminal terminal, public static void drawTerminal( @Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y, @Nonnull Terminal terminal,
boolean greyscale, float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize) { boolean greyscale, float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize )
{
drawTerminalWithoutCursor( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); drawTerminalWithoutCursor( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
drawCursor( transform, buffer, x, y, terminal, greyscale ); drawCursor( transform, buffer, x, y, terminal, greyscale );
} }
public static void drawTerminal( @Nonnull Matrix4f transform, float x, float y, @Nonnull Terminal terminal, boolean greyscale, float topMarginSize, public static void drawTerminal( @Nonnull Matrix4f transform, float x, float y, @Nonnull Terminal terminal, boolean greyscale, float topMarginSize,
float bottomMarginSize, float leftMarginSize, float rightMarginSize) { float bottomMarginSize, float leftMarginSize, float rightMarginSize )
{
bindFont(); bindFont();
VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance() VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance()
@ -323,15 +353,18 @@ public final class FixedWidthFontRenderer {
} }
public static void drawTerminal( float x, float y, @Nonnull Terminal terminal, boolean greyscale, float topMarginSize, float bottomMarginSize, public static void drawTerminal( float x, float y, @Nonnull Terminal terminal, boolean greyscale, float topMarginSize, float bottomMarginSize,
float leftMarginSize, float rightMarginSize) { float leftMarginSize, float rightMarginSize )
{
drawTerminal( IDENTITY, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); drawTerminal( IDENTITY, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
} }
public static void drawEmptyTerminal(float x, float y, float width, float height) { public static void drawEmptyTerminal( float x, float y, float width, float height )
{
drawEmptyTerminal( IDENTITY, x, y, width, height ); drawEmptyTerminal( IDENTITY, x, y, width, height );
} }
public static void drawEmptyTerminal(@Nonnull Matrix4f transform, float x, float y, float width, float height) { public static void drawEmptyTerminal( @Nonnull Matrix4f transform, float x, float y, float width, float height )
{
bindFont(); bindFont();
VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance() VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance()
@ -342,17 +375,20 @@ public final class FixedWidthFontRenderer {
} }
public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull VertexConsumerProvider renderer, float x, float y, float width, public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull VertexConsumerProvider renderer, float x, float y, float width,
float height) { float height )
{
Colour colour = Colour.BLACK; Colour colour = Colour.BLACK;
drawQuad( transform, renderer.getBuffer( TYPE ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); drawQuad( transform, renderer.getBuffer( TYPE ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() );
} }
public static void drawBlocker(@Nonnull Matrix4f transform, @Nonnull VertexConsumerProvider renderer, float x, float y, float width, float height) { public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull VertexConsumerProvider renderer, float x, float y, float width, float height )
{
Colour colour = Colour.BLACK; Colour colour = Colour.BLACK;
drawQuad( transform, renderer.getBuffer( Type.BLOCKER ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); drawQuad( transform, renderer.getBuffer( Type.BLOCKER ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() );
} }
private static final class Type extends RenderPhase { private static final class Type extends RenderPhase
{
private static final int GL_MODE = GL11.GL_TRIANGLES; private static final int GL_MODE = GL11.GL_TRIANGLES;
private static final VertexFormat FORMAT = VertexFormats.POSITION_COLOR_TEXTURE; private static final VertexFormat FORMAT = VertexFormats.POSITION_COLOR_TEXTURE;
@ -377,7 +413,8 @@ public final class FixedWidthFontRenderer {
.lightmap( DISABLE_LIGHTMAP ) .lightmap( DISABLE_LIGHTMAP )
.build( false ) ); .build( false ) );
private Type(String name, Runnable setup, Runnable destroy) { private Type( String name, Runnable setup, Runnable destroy )
{
super( name, setup, destroy ); super( name, setup, destroy );
} }
} }

View File

@ -6,11 +6,6 @@
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
import javax.annotation.Nonnull;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.gui.widgets.WidgetTerminal;
@ -22,14 +17,19 @@ import dan200.computercraft.shared.computer.inventory.ContainerComputer;
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
import org.lwjgl.glfw.GLFW;
import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import org.lwjgl.glfw.GLFW;
public final class GuiComputer<T extends ContainerComputerBase> extends HandledScreen<T> { import javax.annotation.Nonnull;
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
public final class GuiComputer<T extends ContainerComputerBase> extends HandledScreen<T>
{
private final ComputerFamily family; private final ComputerFamily family;
private final ClientComputer computer; private final ClientComputer computer;
private final int termWidth; private final int termWidth;
@ -38,7 +38,8 @@ public final class GuiComputer<T extends ContainerComputerBase> extends HandledS
private WidgetTerminal terminal; private WidgetTerminal terminal;
private WidgetWrapper terminalWrapper; private WidgetWrapper terminalWrapper;
private GuiComputer(T container, PlayerInventory player, Text title, int termWidth, int termHeight) { private GuiComputer( T container, PlayerInventory player, Text title, int termWidth, int termHeight )
{
super( container, player, title ); super( container, player, title );
this.family = container.getFamily(); this.family = container.getFamily();
this.computer = (ClientComputer) container.getComputer(); this.computer = (ClientComputer) container.getComputer();
@ -47,21 +48,25 @@ public final class GuiComputer<T extends ContainerComputerBase> extends HandledS
this.terminal = null; this.terminal = null;
} }
public static GuiComputer<ContainerComputer> create(ContainerComputer container, PlayerInventory inventory, Text component) { public static GuiComputer<ContainerComputer> create( ContainerComputer container, PlayerInventory inventory, Text component )
{
return new GuiComputer<>( container, inventory, component, ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight ); return new GuiComputer<>( container, inventory, component, ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight );
} }
public static GuiComputer<ContainerPocketComputer> createPocket(ContainerPocketComputer container, PlayerInventory inventory, Text component) { public static GuiComputer<ContainerPocketComputer> createPocket( ContainerPocketComputer container, PlayerInventory inventory, Text component )
{
return new GuiComputer<>( container, inventory, component, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ); return new GuiComputer<>( container, inventory, component, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight );
} }
public static GuiComputer<ContainerViewComputer> createView(ContainerViewComputer container, PlayerInventory inventory, Text component) { public static GuiComputer<ContainerViewComputer> createView( ContainerViewComputer container, PlayerInventory inventory, Text component )
{
return new GuiComputer<>( container, inventory, component, container.getWidth(), container.getHeight() ); return new GuiComputer<>( container, inventory, component, container.getWidth(), container.getHeight() );
} }
@Override @Override
protected void init() { protected void init()
{
this.client.keyboard.setRepeatEvents( true ); this.client.keyboard.setRepeatEvents( true );
int termPxWidth = this.termWidth * FixedWidthFontRenderer.FONT_WIDTH; int termPxWidth = this.termWidth * FixedWidthFontRenderer.FONT_WIDTH;
@ -80,18 +85,21 @@ public final class GuiComputer<T extends ContainerComputerBase> extends HandledS
} }
@Override @Override
public void render(@Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks) { public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
{
super.render( stack, mouseX, mouseY, partialTicks ); super.render( stack, mouseX, mouseY, partialTicks );
this.drawMouseoverTooltip( stack, mouseX, mouseY ); this.drawMouseoverTooltip( stack, mouseX, mouseY );
} }
@Override @Override
protected void drawForeground(@Nonnull MatrixStack transform, int mouseX, int mouseY) { protected void drawForeground( @Nonnull MatrixStack transform, int mouseX, int mouseY )
{
// Skip rendering labels. // Skip rendering labels.
} }
@Override @Override
public void drawBackground(@Nonnull MatrixStack stack, float partialTicks, int mouseX, int mouseY) { public void drawBackground( @Nonnull MatrixStack stack, float partialTicks, int mouseX, int mouseY )
{
// Draw terminal // Draw terminal
this.terminal.draw( this.terminalWrapper.getX(), this.terminalWrapper.getY() ); this.terminal.draw( this.terminalWrapper.getX(), this.terminalWrapper.getY() );
@ -104,19 +112,23 @@ public final class GuiComputer<T extends ContainerComputerBase> extends HandledS
} }
@Override @Override
public 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 (this.getFocused() != null && this.getFocused().mouseDragged( x, y, button, deltaX, deltaY )) || super.mouseDragged( x, y, button, deltaX, deltaY ); return (this.getFocused() != null && this.getFocused().mouseDragged( x, y, button, deltaX, deltaY )) || super.mouseDragged( x, y, button, deltaX, deltaY );
} }
@Override @Override
public boolean mouseReleased(double mouseX, double mouseY, int button) { public boolean mouseReleased( double mouseX, double mouseY, int button )
{
return (this.getFocused() != null && this.getFocused().mouseReleased( mouseX, mouseY, button )) || super.mouseReleased( x, y, button ); return (this.getFocused() != null && this.getFocused().mouseReleased( mouseX, mouseY, button )) || super.mouseReleased( x, y, button );
} }
@Override @Override
public 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 && this.getFocused() != null && this.getFocused() == this.terminalWrapper) { if( key == GLFW.GLFW_KEY_TAB && this.getFocused() != null && this.getFocused() == this.terminalWrapper )
{
return this.getFocused().keyPressed( key, scancode, modifiers ); return this.getFocused().keyPressed( key, scancode, modifiers );
} }
@ -124,7 +136,8 @@ public final class GuiComputer<T extends ContainerComputerBase> extends HandledS
} }
@Override @Override
public void removed() { public void removed()
{
super.removed(); super.removed();
this.children.remove( this.terminal ); this.children.remove( this.terminal );
this.terminal = null; this.terminal = null;
@ -132,7 +145,8 @@ public final class GuiComputer<T extends ContainerComputerBase> extends HandledS
} }
@Override @Override
public void tick() { public void tick()
{
super.tick(); super.tick();
this.terminal.update(); this.terminal.update();
} }

View File

@ -6,33 +6,36 @@
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import javax.annotation.Nonnull;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive;
import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public class GuiDiskDrive extends HandledScreen<ContainerDiskDrive> { import javax.annotation.Nonnull;
public class GuiDiskDrive extends HandledScreen<ContainerDiskDrive>
{
private static final Identifier BACKGROUND = new Identifier( "computercraft", "textures/gui/disk_drive.png" ); private static final Identifier BACKGROUND = new Identifier( "computercraft", "textures/gui/disk_drive.png" );
public GuiDiskDrive(ContainerDiskDrive container, PlayerInventory player, Text title) { public GuiDiskDrive( ContainerDiskDrive container, PlayerInventory player, Text title )
{
super( container, player, title ); super( container, player, title );
} }
@Override @Override
public void render(@Nonnull MatrixStack transform, int mouseX, int mouseY, float partialTicks) { public void render( @Nonnull MatrixStack transform, int mouseX, int mouseY, float partialTicks )
{
this.renderBackground( transform ); this.renderBackground( transform );
super.render( transform, mouseX, mouseY, partialTicks ); super.render( transform, mouseX, mouseY, partialTicks );
this.drawMouseoverTooltip( transform, mouseX, mouseY ); this.drawMouseoverTooltip( transform, mouseX, mouseY );
} }
@Override @Override
protected void drawBackground(@Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY) { protected void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{
RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
this.client.getTextureManager() this.client.getTextureManager()
.bindTexture( BACKGROUND ); .bindTexture( BACKGROUND );

View File

@ -6,21 +6,22 @@
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import javax.annotation.Nonnull;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; import dan200.computercraft.shared.peripheral.printer.ContainerPrinter;
import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public class GuiPrinter extends HandledScreen<ContainerPrinter> { import javax.annotation.Nonnull;
public class GuiPrinter extends HandledScreen<ContainerPrinter>
{
private static final Identifier BACKGROUND = new Identifier( "computercraft", "textures/gui/printer.png" ); private static final Identifier BACKGROUND = new Identifier( "computercraft", "textures/gui/printer.png" );
public GuiPrinter(ContainerPrinter container, PlayerInventory player, Text title) { public GuiPrinter( ContainerPrinter container, PlayerInventory player, Text title )
{
super( container, player, title ); super( container, player, title );
} }
@ -33,20 +34,23 @@ public class GuiPrinter extends HandledScreen<ContainerPrinter> {
}*/ }*/
@Override @Override
public void render(@Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks) { public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
{
this.renderBackground( stack ); this.renderBackground( stack );
super.render( stack, mouseX, mouseY, partialTicks ); super.render( stack, mouseX, mouseY, partialTicks );
this.drawMouseoverTooltip( stack, mouseX, mouseY ); this.drawMouseoverTooltip( stack, mouseX, mouseY );
} }
@Override @Override
protected void drawBackground(@Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY) { protected void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{
RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
this.client.getTextureManager() this.client.getTextureManager()
.bindTexture( BACKGROUND ); .bindTexture( BACKGROUND );
this.drawTexture( transform, this.x, this.y, 0, 0, this.backgroundWidth, this.backgroundHeight ); this.drawTexture( transform, this.x, this.y, 0, 0, this.backgroundWidth, this.backgroundHeight );
if (this.getScreenHandler().isPrinting()) { if( this.getScreenHandler().isPrinting() )
{
this.drawTexture( transform, this.x + 34, this.y + 21, 176, 0, 25, 45 ); this.drawTexture( transform, this.x + 34, this.y + 21, 176, 0, 25, 45 );
} }
} }

View File

@ -6,20 +6,10 @@
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import static dan200.computercraft.client.render.PrintoutRenderer.X_TEXT_MARGIN;
import static dan200.computercraft.client.render.PrintoutRenderer.Y_SIZE;
import static dan200.computercraft.client.render.PrintoutRenderer.Y_TEXT_MARGIN;
import static dan200.computercraft.client.render.PrintoutRenderer.drawBorder;
import static dan200.computercraft.client.render.PrintoutRenderer.drawText;
import javax.annotation.Nonnull;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.media.items.ItemPrintout;
import org.lwjgl.glfw.GLFW;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
@ -27,28 +17,37 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import org.lwjgl.glfw.GLFW;
public class GuiPrintout extends HandledScreen<ContainerHeldItem> { import javax.annotation.Nonnull;
import static dan200.computercraft.client.render.PrintoutRenderer.*;
public class GuiPrintout extends HandledScreen<ContainerHeldItem>
{
private final boolean m_book; private final boolean m_book;
private final int m_pages; private final int m_pages;
private final TextBuffer[] m_text; private final TextBuffer[] m_text;
private final TextBuffer[] m_colours; private final TextBuffer[] m_colours;
private int m_page; private int m_page;
public GuiPrintout(ContainerHeldItem container, PlayerInventory player, Text title) { public GuiPrintout( ContainerHeldItem container, PlayerInventory player, Text title )
{
super( container, player, title ); super( container, player, title );
this.backgroundHeight = Y_SIZE; this.backgroundHeight = Y_SIZE;
String[] text = ItemPrintout.getText( container.getStack() ); String[] text = ItemPrintout.getText( container.getStack() );
this.m_text = new TextBuffer[text.length]; this.m_text = new TextBuffer[text.length];
for (int i = 0; i < this.m_text.length; i++) { for( int i = 0; i < this.m_text.length; i++ )
{
this.m_text[i] = new TextBuffer( text[i] ); this.m_text[i] = new TextBuffer( text[i] );
} }
String[] colours = ItemPrintout.getColours( container.getStack() ); String[] colours = ItemPrintout.getColours( container.getStack() );
this.m_colours = new TextBuffer[colours.length]; this.m_colours = new TextBuffer[colours.length];
for (int i = 0; i < this.m_colours.length; i++) { for( int i = 0; i < this.m_colours.length; i++ )
{
this.m_colours[i] = new TextBuffer( colours[i] ); this.m_colours[i] = new TextBuffer( colours[i] );
} }
@ -59,21 +58,27 @@ public class GuiPrintout extends HandledScreen<ContainerHeldItem> {
} }
@Override @Override
public boolean mouseScrolled(double x, double y, double delta) { public boolean mouseScrolled( double x, double y, double delta )
if (super.mouseScrolled(x, y, delta)) { {
if( super.mouseScrolled( x, y, delta ) )
{
return true; return true;
} }
if (delta < 0) { if( delta < 0 )
{
// Scroll up goes to the next page // Scroll up goes to the next page
if (this.m_page < this.m_pages - 1) { if( this.m_page < this.m_pages - 1 )
{
this.m_page++; this.m_page++;
} }
return true; return true;
} }
if (delta > 0) { if( delta > 0 )
{
// Scroll down goes to the previous page // Scroll down goes to the previous page
if (this.m_page > 0) { if( this.m_page > 0 )
{
this.m_page--; this.m_page--;
} }
return true; return true;
@ -83,7 +88,8 @@ public class GuiPrintout extends HandledScreen<ContainerHeldItem> {
} }
@Override @Override
public void render(@Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks) { public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
{
// We must take the background further back in order to not overlap with our printed pages. // We must take the background further back in order to not overlap with our printed pages.
this.setZOffset( this.getZOffset() - 1 ); this.setZOffset( this.getZOffset() - 1 );
this.renderBackground( stack ); this.renderBackground( stack );
@ -93,12 +99,14 @@ public class GuiPrintout extends HandledScreen<ContainerHeldItem> {
} }
@Override @Override
protected void drawForeground(@Nonnull MatrixStack transform, int mouseX, int mouseY) { protected void drawForeground( @Nonnull MatrixStack transform, int mouseX, int mouseY )
{
// Skip rendering labels. // Skip rendering labels.
} }
@Override @Override
protected void drawBackground(@Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY) { protected void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{
// Draw the printout // Draw the printout
RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f );
RenderSystem.enableDepthTest(); RenderSystem.enableDepthTest();
@ -114,20 +122,26 @@ public class GuiPrintout extends HandledScreen<ContainerHeldItem> {
} }
@Override @Override
public boolean keyPressed(int key, int scancode, int modifiers) { public boolean keyPressed( int key, int scancode, int modifiers )
if (super.keyPressed(key, scancode, modifiers)) { {
if( super.keyPressed( key, scancode, modifiers ) )
{
return true; return true;
} }
if (key == GLFW.GLFW_KEY_RIGHT) { if( key == GLFW.GLFW_KEY_RIGHT )
if (this.m_page < this.m_pages - 1) { {
if( this.m_page < this.m_pages - 1 )
{
this.m_page++; this.m_page++;
} }
return true; return true;
} }
if (key == GLFW.GLFW_KEY_LEFT) { if( key == GLFW.GLFW_KEY_LEFT )
if (this.m_page > 0) { {
if( this.m_page > 0 )
{
this.m_page--; this.m_page--;
} }
return true; return true;

View File

@ -6,8 +6,6 @@
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import javax.annotation.Nonnull;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.gui.widgets.WidgetTerminal;
@ -15,15 +13,17 @@ import dan200.computercraft.client.gui.widgets.WidgetWrapper;
import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
import org.lwjgl.glfw.GLFW;
import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import org.lwjgl.glfw.GLFW;
public class GuiTurtle extends HandledScreen<ContainerTurtle> { import javax.annotation.Nonnull;
public class GuiTurtle extends HandledScreen<ContainerTurtle>
{
private static final Identifier BACKGROUND_NORMAL = new Identifier( "computercraft", "textures/gui/turtle_normal.png" ); private static final Identifier BACKGROUND_NORMAL = new Identifier( "computercraft", "textures/gui/turtle_normal.png" );
private static final Identifier BACKGROUND_ADVANCED = new Identifier( "computercraft", "textures/gui/turtle_advanced.png" ); private static final Identifier BACKGROUND_ADVANCED = new Identifier( "computercraft", "textures/gui/turtle_advanced.png" );
private final ComputerFamily m_family; private final ComputerFamily m_family;
@ -32,7 +32,8 @@ public class GuiTurtle extends HandledScreen<ContainerTurtle> {
private WidgetTerminal terminal; private WidgetTerminal terminal;
private WidgetWrapper terminalWrapper; private WidgetWrapper terminalWrapper;
public GuiTurtle(ContainerTurtle container, PlayerInventory player, Text title) { public GuiTurtle( ContainerTurtle container, PlayerInventory player, Text title )
{
super( container, player, title ); super( container, player, title );
this.m_container = container; this.m_container = container;
@ -44,7 +45,8 @@ public class GuiTurtle extends HandledScreen<ContainerTurtle> {
} }
@Override @Override
protected void init() { protected void init()
{
super.init(); super.init();
this.client.keyboard.setRepeatEvents( true ); this.client.keyboard.setRepeatEvents( true );
@ -59,19 +61,22 @@ public class GuiTurtle extends HandledScreen<ContainerTurtle> {
} }
@Override @Override
public void render(@Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks) { public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
{
this.renderBackground( stack ); this.renderBackground( stack );
super.render( stack, mouseX, mouseY, partialTicks ); super.render( stack, mouseX, mouseY, partialTicks );
this.drawMouseoverTooltip( stack, mouseX, mouseY ); this.drawMouseoverTooltip( stack, mouseX, mouseY );
} }
@Override @Override
protected void drawForeground(@Nonnull MatrixStack transform, int mouseX, int mouseY) { protected void drawForeground( @Nonnull MatrixStack transform, int mouseX, int mouseY )
{
// Skip rendering labels. // Skip rendering labels.
} }
@Override @Override
protected void drawBackground(@Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY) { protected void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{
// Draw term // Draw term
Identifier texture = this.m_family == ComputerFamily.ADVANCED ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL; Identifier texture = this.m_family == ComputerFamily.ADVANCED ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL;
this.terminal.draw( this.terminalWrapper.getX(), this.terminalWrapper.getY() ); this.terminal.draw( this.terminalWrapper.getX(), this.terminalWrapper.getY() );
@ -84,7 +89,8 @@ public class GuiTurtle extends HandledScreen<ContainerTurtle> {
// Draw selection slot // Draw selection slot
int slot = this.m_container.getSelectedSlot(); int slot = this.m_container.getSelectedSlot();
if (slot >= 0) { if( slot >= 0 )
{
int slotX = slot % 4; int slotX = slot % 4;
int slotY = slot / 4; int slotY = slot / 4;
this.drawTexture( transform, this.x + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, this.y + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18, this.drawTexture( transform, this.x + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, this.y + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18,
@ -96,14 +102,17 @@ public class GuiTurtle extends HandledScreen<ContainerTurtle> {
} }
@Override @Override
public 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 (this.getFocused() != null && this.getFocused().mouseDragged( x, y, button, deltaX, deltaY )) || super.mouseDragged( x, y, button, deltaX, deltaY ); return (this.getFocused() != null && this.getFocused().mouseDragged( x, y, button, deltaX, deltaY )) || super.mouseDragged( x, y, button, deltaX, deltaY );
} }
@Override @Override
public 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 && this.getFocused() != null && this.getFocused() == this.terminalWrapper) { if( key == GLFW.GLFW_KEY_TAB && this.getFocused() != null && this.getFocused() == this.terminalWrapper )
{
return this.getFocused().keyPressed( key, scancode, modifiers ); return this.getFocused().keyPressed( key, scancode, modifiers );
} }
@ -111,7 +120,8 @@ public class GuiTurtle extends HandledScreen<ContainerTurtle> {
} }
@Override @Override
public void removed() { public void removed()
{
super.removed(); super.removed();
this.children.remove( this.terminal ); this.children.remove( this.terminal );
this.terminal = null; this.terminal = null;
@ -119,7 +129,8 @@ public class GuiTurtle extends HandledScreen<ContainerTurtle> {
} }
@Override @Override
public void tick() { public void tick()
{
super.tick(); super.tick();
this.terminal.update(); this.terminal.update();
} }

View File

@ -6,23 +6,23 @@
package dan200.computercraft.client.gui.widgets; package dan200.computercraft.client.gui.widgets;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
import java.util.BitSet;
import java.util.function.Supplier;
import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IComputer;
import org.lwjgl.glfw.GLFW;
import net.minecraft.SharedConstants; import net.minecraft.SharedConstants;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Element; import net.minecraft.client.gui.Element;
import org.lwjgl.glfw.GLFW;
public class WidgetTerminal implements Element { import java.util.BitSet;
import java.util.function.Supplier;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
public class WidgetTerminal implements Element
{
private static final float TERMINATE_TIME = 0.5f; private static final float TERMINATE_TIME = 0.5f;
private final MinecraftClient client; private final MinecraftClient client;
@ -43,7 +43,8 @@ public class WidgetTerminal implements Element {
private int lastMouseY = -1; private int lastMouseY = -1;
public WidgetTerminal( MinecraftClient client, Supplier<ClientComputer> computer, int termWidth, int termHeight, int leftMargin, int rightMargin, public WidgetTerminal( MinecraftClient client, Supplier<ClientComputer> computer, int termWidth, int termHeight, int leftMargin, int rightMargin,
int topMargin, int bottomMargin) { int topMargin, int bottomMargin )
{
this.client = client; this.client = client;
this.computer = computer; this.computer = computer;
this.termWidth = termWidth; this.termWidth = termWidth;
@ -55,14 +56,17 @@ public class WidgetTerminal implements Element {
} }
@Override @Override
public boolean mouseClicked(double mouseX, double mouseY, int button) { public boolean mouseClicked( double mouseX, double mouseY, int button )
{
ClientComputer computer = this.computer.get(); ClientComputer computer = this.computer.get();
if (computer == null || !computer.isColour() || button < 0 || button > 2) { if( computer == null || !computer.isColour() || button < 0 || button > 2 )
{
return false; return false;
} }
Terminal term = computer.getTerminal(); Terminal term = computer.getTerminal();
if (term != null) { if( term != null )
{
int charX = (int) (mouseX / FONT_WIDTH); int charX = (int) (mouseX / FONT_WIDTH);
int charY = (int) (mouseY / FONT_HEIGHT); int charY = (int) (mouseY / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
@ -79,20 +83,24 @@ public class WidgetTerminal implements Element {
} }
@Override @Override
public boolean mouseReleased(double mouseX, double mouseY, int button) { public boolean mouseReleased( double mouseX, double mouseY, int button )
{
ClientComputer computer = this.computer.get(); ClientComputer computer = this.computer.get();
if (computer == null || !computer.isColour() || button < 0 || button > 2) { if( computer == null || !computer.isColour() || button < 0 || button > 2 )
{
return false; return false;
} }
Terminal term = computer.getTerminal(); Terminal term = computer.getTerminal();
if (term != null) { if( term != null )
{
int charX = (int) (mouseX / FONT_WIDTH); int charX = (int) (mouseX / FONT_WIDTH);
int charY = (int) (mouseY / FONT_HEIGHT); int charY = (int) (mouseY / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
if (this.lastMouseButton == button) { if( this.lastMouseButton == button )
{
computer.mouseUp( this.lastMouseButton + 1, charX + 1, charY + 1 ); computer.mouseUp( this.lastMouseButton + 1, charX + 1, charY + 1 );
this.lastMouseButton = -1; this.lastMouseButton = -1;
} }
@ -105,20 +113,24 @@ public class WidgetTerminal implements Element {
} }
@Override @Override
public boolean mouseDragged(double mouseX, double mouseY, int button, double v2, double v3) { public boolean mouseDragged( double mouseX, double mouseY, int button, double v2, double v3 )
{
ClientComputer computer = this.computer.get(); ClientComputer computer = this.computer.get();
if (computer == null || !computer.isColour() || button < 0 || button > 2) { if( computer == null || !computer.isColour() || button < 0 || button > 2 )
{
return false; return false;
} }
Terminal term = computer.getTerminal(); Terminal term = computer.getTerminal();
if (term != null) { if( term != null )
{
int charX = (int) (mouseX / FONT_WIDTH); int charX = (int) (mouseX / FONT_WIDTH);
int charY = (int) (mouseY / FONT_HEIGHT); int charY = (int) (mouseY / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
if (button == this.lastMouseButton && (charX != this.lastMouseX || charY != this.lastMouseY)) { if( button == this.lastMouseButton && (charX != this.lastMouseX || charY != this.lastMouseY) )
{
computer.mouseDrag( button + 1, charX + 1, charY + 1 ); computer.mouseDrag( button + 1, charX + 1, charY + 1 );
this.lastMouseX = charX; this.lastMouseX = charX;
this.lastMouseY = charY; this.lastMouseY = charY;
@ -129,14 +141,17 @@ public class WidgetTerminal implements Element {
} }
@Override @Override
public boolean mouseScrolled(double mouseX, double mouseY, double delta) { public boolean mouseScrolled( double mouseX, double mouseY, double delta )
{
ClientComputer computer = this.computer.get(); ClientComputer computer = this.computer.get();
if (computer == null || !computer.isColour() || delta == 0) { if( computer == null || !computer.isColour() || delta == 0 )
{
return false; return false;
} }
Terminal term = computer.getTerminal(); Terminal term = computer.getTerminal();
if (term != null) { if( term != null )
{
int charX = (int) (mouseX / FONT_WIDTH); int charX = (int) (mouseX / FONT_WIDTH);
int charY = (int) (mouseY / FONT_HEIGHT); int charY = (int) (mouseY / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
@ -152,24 +167,31 @@ public class WidgetTerminal implements Element {
} }
@Override @Override
public boolean keyPressed(int key, int scancode, int modifiers) { public boolean keyPressed( int key, int scancode, int modifiers )
if (key == GLFW.GLFW_KEY_ESCAPE) { {
if( key == GLFW.GLFW_KEY_ESCAPE )
{
return false; return false;
} }
if ((modifiers & GLFW.GLFW_MOD_CONTROL) != 0) { if( (modifiers & GLFW.GLFW_MOD_CONTROL) != 0 )
switch (key) { {
switch( key )
{
case GLFW.GLFW_KEY_T: case GLFW.GLFW_KEY_T:
if (this.terminateTimer < 0) { if( this.terminateTimer < 0 )
{
this.terminateTimer = 0; this.terminateTimer = 0;
} }
return true; return true;
case GLFW.GLFW_KEY_S: case GLFW.GLFW_KEY_S:
if (this.shutdownTimer < 0) { if( this.shutdownTimer < 0 )
{
this.shutdownTimer = 0; this.shutdownTimer = 0;
} }
return true; return true;
case GLFW.GLFW_KEY_R: case GLFW.GLFW_KEY_R:
if (this.rebootTimer < 0) { if( this.rebootTimer < 0 )
{
this.rebootTimer = 0; this.rebootTimer = 0;
} }
return true; return true;
@ -177,23 +199,31 @@ public class WidgetTerminal implements Element {
case GLFW.GLFW_KEY_V: case GLFW.GLFW_KEY_V:
// Ctrl+V for paste // Ctrl+V for paste
String clipboard = this.client.keyboard.getClipboard(); String clipboard = this.client.keyboard.getClipboard();
if (clipboard != null) { if( clipboard != null )
{
// Clip to the first occurrence of \r or \n // Clip to the first occurrence of \r or \n
int newLineIndex1 = clipboard.indexOf( "\r" ); int newLineIndex1 = clipboard.indexOf( "\r" );
int newLineIndex2 = clipboard.indexOf( "\n" ); int newLineIndex2 = clipboard.indexOf( "\n" );
if (newLineIndex1 >= 0 && newLineIndex2 >= 0) { if( newLineIndex1 >= 0 && newLineIndex2 >= 0 )
{
clipboard = clipboard.substring( 0, Math.min( newLineIndex1, newLineIndex2 ) ); clipboard = clipboard.substring( 0, Math.min( newLineIndex1, newLineIndex2 ) );
} else if (newLineIndex1 >= 0) { }
else if( newLineIndex1 >= 0 )
{
clipboard = clipboard.substring( 0, newLineIndex1 ); clipboard = clipboard.substring( 0, newLineIndex1 );
} else if (newLineIndex2 >= 0) { }
else if( newLineIndex2 >= 0 )
{
clipboard = clipboard.substring( 0, newLineIndex2 ); clipboard = clipboard.substring( 0, newLineIndex2 );
} }
// Filter the string // Filter the string
clipboard = SharedConstants.stripInvalidChars( clipboard ); clipboard = SharedConstants.stripInvalidChars( clipboard );
if (!clipboard.isEmpty()) { if( !clipboard.isEmpty() )
{
// Clip to 512 characters and queue the event // Clip to 512 characters and queue the event
if (clipboard.length() > 512) { if( clipboard.length() > 512 )
{
clipboard = clipboard.substring( 0, 512 ); clipboard = clipboard.substring( 0, 512 );
} }
this.queueEvent( "paste", clipboard ); this.queueEvent( "paste", clipboard );
@ -204,12 +234,14 @@ public class WidgetTerminal implements Element {
} }
} }
if (key >= 0 && this.terminateTimer < 0 && this.rebootTimer < 0 && this.shutdownTimer < 0) { if( key >= 0 && this.terminateTimer < 0 && this.rebootTimer < 0 && this.shutdownTimer < 0 )
{
// Queue the "key" event and add to the down set // Queue the "key" event and add to the down set
boolean repeat = this.keysDown.get( key ); boolean repeat = this.keysDown.get( key );
this.keysDown.set( key ); this.keysDown.set( key );
IComputer computer = this.computer.get(); IComputer computer = this.computer.get();
if (computer != null) { if( computer != null )
{
computer.keyDown( key, repeat ); computer.keyDown( key, repeat );
} }
} }
@ -218,17 +250,21 @@ public class WidgetTerminal implements Element {
} }
@Override @Override
public boolean keyReleased(int key, int scancode, int modifiers) { public boolean keyReleased( int key, int scancode, int modifiers )
{
// Queue the "key_up" event and remove from the down set // Queue the "key_up" event and remove from the down set
if (key >= 0 && this.keysDown.get(key)) { if( key >= 0 && this.keysDown.get( key ) )
{
this.keysDown.set( key, false ); this.keysDown.set( key, false );
IComputer computer = this.computer.get(); IComputer computer = this.computer.get();
if (computer != null) { if( computer != null )
{
computer.keyUp( key ); computer.keyUp( key );
} }
} }
switch (key) { switch( key )
{
case GLFW.GLFW_KEY_T: case GLFW.GLFW_KEY_T:
this.terminateTimer = -1; this.terminateTimer = -1;
break; break;
@ -248,7 +284,8 @@ public class WidgetTerminal implements Element {
} }
@Override @Override
public boolean charTyped(char ch, int modifiers) { public boolean charTyped( char ch, int modifiers )
{
if( ch >= 32 && ch <= 126 || ch >= 160 && ch <= 255 ) // printable chars in byte range if( ch >= 32 && ch <= 126 || ch >= 160 && ch <= 255 ) // printable chars in byte range
{ {
// Queue the "char" event // Queue the "char" event
@ -259,20 +296,26 @@ public class WidgetTerminal implements Element {
} }
@Override @Override
public boolean changeFocus(boolean reversed) { public boolean changeFocus( boolean reversed )
if (this.focused) { {
if( this.focused )
{
// When blurring, we should make all keys go up // When blurring, we should make all keys go up
for (int key = 0; key < this.keysDown.size(); key++) { for( int key = 0; key < this.keysDown.size(); key++ )
if (this.keysDown.get(key)) { {
if( this.keysDown.get( key ) )
{
this.queueEvent( "key_up", key ); this.queueEvent( "key_up", key );
} }
} }
this.keysDown.clear(); this.keysDown.clear();
// When blurring, we should make the last mouse button go up // When blurring, we should make the last mouse button go up
if (this.lastMouseButton > 0) { if( this.lastMouseButton > 0 )
{
IComputer computer = this.computer.get(); IComputer computer = this.computer.get();
if (computer != null) { if( computer != null )
{
computer.mouseUp( this.lastMouseButton + 1, this.lastMouseX + 1, this.lastMouseY + 1 ); computer.mouseUp( this.lastMouseButton + 1, this.lastMouseX + 1, this.lastMouseY + 1 );
} }
this.lastMouseButton = -1; this.lastMouseButton = -1;
@ -285,53 +328,69 @@ public class WidgetTerminal implements Element {
} }
@Override @Override
public boolean isMouseOver(double x, double y) { public boolean isMouseOver( double x, double y )
{
return true; return true;
} }
private void queueEvent(String event, Object... args) { private void queueEvent( String event, Object... args )
{
ClientComputer computer = this.computer.get(); ClientComputer computer = this.computer.get();
if (computer != null) { if( computer != null )
{
computer.queueEvent( event, args ); computer.queueEvent( event, args );
} }
} }
public void update() { public void update()
if (this.terminateTimer >= 0 && this.terminateTimer < TERMINATE_TIME && (this.terminateTimer += 0.05f) > TERMINATE_TIME) { {
if( this.terminateTimer >= 0 && this.terminateTimer < TERMINATE_TIME && (this.terminateTimer += 0.05f) > TERMINATE_TIME )
{
this.queueEvent( "terminate" ); this.queueEvent( "terminate" );
} }
if (this.shutdownTimer >= 0 && this.shutdownTimer < TERMINATE_TIME && (this.shutdownTimer += 0.05f) > TERMINATE_TIME) { if( this.shutdownTimer >= 0 && this.shutdownTimer < TERMINATE_TIME && (this.shutdownTimer += 0.05f) > TERMINATE_TIME )
{
ClientComputer computer = this.computer.get(); ClientComputer computer = this.computer.get();
if (computer != null) { if( computer != null )
{
computer.shutdown(); computer.shutdown();
} }
} }
if (this.rebootTimer >= 0 && this.rebootTimer < TERMINATE_TIME && (this.rebootTimer += 0.05f) > TERMINATE_TIME) { if( this.rebootTimer >= 0 && this.rebootTimer < TERMINATE_TIME && (this.rebootTimer += 0.05f) > TERMINATE_TIME )
{
ClientComputer computer = this.computer.get(); ClientComputer computer = this.computer.get();
if (computer != null) { if( computer != null )
{
computer.reboot(); computer.reboot();
} }
} }
} }
private void queueEvent(String event) { private void queueEvent( String event )
{
ClientComputer computer = this.computer.get(); ClientComputer computer = this.computer.get();
if (computer != null) { if( computer != null )
{
computer.queueEvent( event ); computer.queueEvent( event );
} }
} }
public void draw(int originX, int originY) { public void draw( int originX, int originY )
synchronized (this.computer) { {
synchronized( this.computer )
{
// Draw the screen contents // Draw the screen contents
ClientComputer computer = this.computer.get(); ClientComputer computer = this.computer.get();
Terminal terminal = computer != null ? computer.getTerminal() : null; Terminal terminal = computer != null ? computer.getTerminal() : null;
if (terminal != null) { if( terminal != null )
{
FixedWidthFontRenderer.drawTerminal( originX, originY, terminal, !computer.isColour(), this.topMargin, this.bottomMargin, this.leftMargin, FixedWidthFontRenderer.drawTerminal( originX, originY, terminal, !computer.isColour(), this.topMargin, this.bottomMargin, this.leftMargin,
this.rightMargin ); this.rightMargin );
} else { }
else
{
FixedWidthFontRenderer.drawEmptyTerminal( originX - this.leftMargin, FixedWidthFontRenderer.drawEmptyTerminal( originX - this.leftMargin,
originY - this.rightMargin, this.termWidth * FONT_WIDTH + this.leftMargin + this.rightMargin, originY - this.rightMargin, this.termWidth * FONT_WIDTH + this.leftMargin + this.rightMargin,
this.termHeight * FONT_HEIGHT + this.topMargin + this.bottomMargin ); this.termHeight * FONT_HEIGHT + this.topMargin + this.bottomMargin );

View File

@ -8,14 +8,16 @@ package dan200.computercraft.client.gui.widgets;
import net.minecraft.client.gui.Element; import net.minecraft.client.gui.Element;
public class WidgetWrapper implements Element { public class WidgetWrapper implements Element
{
private final Element listener; private final Element listener;
private final int x; private final int x;
private final int y; private final int y;
private final int width; private final int width;
private final int height; private final int height;
public WidgetWrapper(Element listener, int x, int y, int width, int height) { public WidgetWrapper( Element listener, int x, int y, int width, int height )
{
this.listener = listener; this.listener = listener;
this.x = x; this.x = x;
this.y = y; this.y = y;
@ -24,68 +26,81 @@ public class WidgetWrapper implements Element {
} }
@Override @Override
public boolean mouseClicked(double x, double y, int button) { public boolean mouseClicked( double x, double y, int button )
{
double dx = x - this.x, dy = y - this.y; double dx = x - this.x, dy = y - this.y;
return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height && this.listener.mouseClicked( dx, dy, button ); return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height && this.listener.mouseClicked( dx, dy, button );
} }
@Override @Override
public boolean mouseReleased(double x, double y, int button) { public boolean mouseReleased( double x, double y, int button )
{
double dx = x - this.x, dy = y - this.y; double dx = x - this.x, dy = y - this.y;
return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height && this.listener.mouseReleased( dx, dy, button ); return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height && this.listener.mouseReleased( dx, dy, button );
} }
@Override @Override
public 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 )
{
double dx = x - this.x, dy = y - this.y; double dx = x - this.x, dy = y - this.y;
return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height && this.listener.mouseDragged( dx, dy, button, deltaX, deltaY ); return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height && this.listener.mouseDragged( dx, dy, button, deltaX, deltaY );
} }
@Override @Override
public boolean mouseScrolled(double x, double y, double delta) { public boolean mouseScrolled( double x, double y, double delta )
{
double dx = x - this.x, dy = y - this.y; double dx = x - this.x, dy = y - this.y;
return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height && this.listener.mouseScrolled( dx, dy, delta ); return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height && this.listener.mouseScrolled( dx, dy, delta );
} }
@Override @Override
public boolean keyPressed(int key, int scancode, int modifiers) { public boolean keyPressed( int key, int scancode, int modifiers )
{
return this.listener.keyPressed( key, scancode, modifiers ); return this.listener.keyPressed( key, scancode, modifiers );
} }
@Override @Override
public boolean keyReleased(int key, int scancode, int modifiers) { public boolean keyReleased( int key, int scancode, int modifiers )
{
return this.listener.keyReleased( key, scancode, modifiers ); return this.listener.keyReleased( key, scancode, modifiers );
} }
@Override @Override
public boolean charTyped(char character, int modifiers) { public boolean charTyped( char character, int modifiers )
{
return this.listener.charTyped( character, modifiers ); return this.listener.charTyped( character, modifiers );
} }
@Override @Override
public boolean changeFocus(boolean b) { public boolean changeFocus( boolean b )
{
return this.listener.changeFocus( b ); return this.listener.changeFocus( b );
} }
@Override @Override
public boolean isMouseOver(double x, double y) { public boolean isMouseOver( double x, double y )
{
double dx = x - this.x, dy = y - this.y; double dx = x - this.x, dy = y - this.y;
return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height; return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height;
} }
public int getX() { public int getX()
{
return this.x; return this.x;
} }
public int getY() { public int getY()
{
return this.y; return this.y;
} }
public int getWidth() { public int getWidth()
{
return this.width; return this.width;
} }
public int getHeight() { public int getHeight()
{
return this.height; return this.height;
} }
} }

View File

@ -6,16 +6,10 @@
package dan200.computercraft.client.proxy; package dan200.computercraft.client.proxy;
import java.util.function.Supplier;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.ClientRegistry; import dan200.computercraft.client.ClientRegistry;
import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.gui.GuiComputer; import dan200.computercraft.client.gui.*;
import dan200.computercraft.client.gui.GuiDiskDrive;
import dan200.computercraft.client.gui.GuiPrinter;
import dan200.computercraft.client.gui.GuiPrintout;
import dan200.computercraft.client.gui.GuiTurtle;
import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityMonitorRenderer;
import dan200.computercraft.client.render.TileEntityTurtleRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer;
import dan200.computercraft.client.render.TurtleModelLoader; import dan200.computercraft.client.render.TurtleModelLoader;
@ -33,33 +27,36 @@ import dan200.computercraft.shared.peripheral.printer.ContainerPrinter;
import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
import dan200.computercraft.shared.util.Config; import dan200.computercraft.shared.util.Config;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientBlockEntityEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.minecraft.client.item.ModelPredicateProvider;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.item.Item;
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.util.Identifier;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientBlockEntityEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry; import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry;
import net.fabricmc.fabric.api.client.rendereregistry.v1.BlockEntityRendererRegistry; import net.fabricmc.fabric.api.client.rendereregistry.v1.BlockEntityRendererRegistry;
import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry; import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry;
import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry; import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry;
import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback;
import net.fabricmc.fabric.mixin.object.builder.ModelPredicateProviderRegistrySpecificAccessor; import net.fabricmc.fabric.mixin.object.builder.ModelPredicateProviderRegistrySpecificAccessor;
import net.minecraft.client.item.ModelPredicateProvider;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.item.Item;
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.util.Identifier;
import java.util.function.Supplier;
@Environment( EnvType.CLIENT ) @Environment( EnvType.CLIENT )
public final class ComputerCraftProxyClient implements ClientModInitializer { public final class ComputerCraftProxyClient implements ClientModInitializer
{
private static void initEvents() { private static void initEvents()
{
ClientBlockEntityEvents.BLOCK_ENTITY_UNLOAD.register( ( blockEntity, world ) -> { ClientBlockEntityEvents.BLOCK_ENTITY_UNLOAD.register( ( blockEntity, world ) -> {
if(blockEntity instanceof TileGeneric ) { if( blockEntity instanceof TileGeneric )
{
((TileGeneric) blockEntity).onChunkUnloaded(); ((TileGeneric) blockEntity).onChunkUnloaded();
} }
} ); } );
@ -71,7 +68,8 @@ public final class ComputerCraftProxyClient implements ClientModInitializer {
} }
@Override @Override
public void onInitializeClient() { public void onInitializeClient()
{
FrameInfo.init(); FrameInfo.init();
registerContainers(); registerContainers();
@ -113,7 +111,8 @@ public final class ComputerCraftProxyClient implements ClientModInitializer {
} }
// My IDE doesn't think so, but we do actually need these generics. // My IDE doesn't think so, but we do actually need these generics.
private static void registerContainers() { private static void registerContainers()
{
ScreenRegistry.<ContainerComputer, GuiComputer<ContainerComputer>>register( ComputerCraftRegistry.ModContainers.COMPUTER, GuiComputer::create ); ScreenRegistry.<ContainerComputer, GuiComputer<ContainerComputer>>register( ComputerCraftRegistry.ModContainers.COMPUTER, GuiComputer::create );
ScreenRegistry.<ContainerPocketComputer, GuiComputer<ContainerPocketComputer>>register( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER, ScreenRegistry.<ContainerPocketComputer, GuiComputer<ContainerPocketComputer>>register( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER,
GuiComputer::createPocket ); GuiComputer::createPocket );
@ -128,9 +127,11 @@ public final class ComputerCraftProxyClient implements ClientModInitializer {
} }
@SafeVarargs @SafeVarargs
private static void registerItemProperty(String name, ModelPredicateProvider getter, Supplier<? extends Item>... items) { private static void registerItemProperty( String name, ModelPredicateProvider getter, Supplier<? extends Item>... items )
{
Identifier id = new Identifier( ComputerCraft.MOD_ID, name ); Identifier id = new Identifier( ComputerCraft.MOD_ID, name );
for (Supplier<? extends Item> item : items) { for( Supplier<? extends Item> item : items )
{
ModelPredicateProviderRegistrySpecificAccessor.callRegister( item.get(), id, getter ); ModelPredicateProviderRegistrySpecificAccessor.callRegister( item.get(), id, getter );
} }
} }

View File

@ -10,7 +10,8 @@ import dan200.computercraft.shared.ComputerCraftRegistry;
import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable;
import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; import dan200.computercraft.shared.peripheral.modem.wired.CableShapes;
import dan200.computercraft.shared.util.WorldUtil; import dan200.computercraft.shared.util.WorldUtil;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera; import net.minecraft.client.render.Camera;
@ -23,25 +24,26 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShape;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@Environment( EnvType.CLIENT ) @Environment( EnvType.CLIENT )
public final class CableHighlightRenderer { public final class CableHighlightRenderer
private CableHighlightRenderer() { {
private CableHighlightRenderer()
{
} }
/** /**
* Draw an outline for a specific part of a cable "Multipart". * Draw an outline for a specific part of a cable "Multipart".
*/ */
public static boolean drawHighlight( MatrixStack stack, VertexConsumer consumer, Entity entity, double d, double e, double f, BlockPos pos, public static boolean drawHighlight( MatrixStack stack, VertexConsumer consumer, Entity entity, double d, double e, double f, BlockPos pos,
BlockState state) { BlockState state )
{
World world = entity.getEntityWorld(); World world = entity.getEntityWorld();
Camera info = MinecraftClient.getInstance().gameRenderer.getCamera(); Camera info = MinecraftClient.getInstance().gameRenderer.getCamera();
// We only care about instances with both cable and modem. // We only care about instances with both cable and modem.
if( state.getBlock() != ComputerCraftRegistry.ModBlocks.CABLE || state.get( BlockCable.MODEM ) if( state.getBlock() != ComputerCraftRegistry.ModBlocks.CABLE || state.get( BlockCable.MODEM )
.getFacing() == null || !state.get(BlockCable.CABLE)) { .getFacing() == null || !state.get( BlockCable.CABLE ) )
{
return false; return false;
} }

View File

@ -5,21 +5,21 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import javax.annotation.Nonnull;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import org.lwjgl.opengl.GL11;
import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexFormats; import net.minecraft.client.render.VertexFormats;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import org.lwjgl.opengl.GL11;
public class ComputerBorderRenderer { import javax.annotation.Nonnull;
public class ComputerBorderRenderer
{
public static final Identifier BACKGROUND_NORMAL = new Identifier( ComputerCraft.MOD_ID, "textures/gui/corners_normal.png" ); public static final Identifier BACKGROUND_NORMAL = new Identifier( ComputerCraft.MOD_ID, "textures/gui/corners_normal.png" );
public static final Identifier BACKGROUND_ADVANCED = new Identifier( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" ); public static final Identifier BACKGROUND_ADVANCED = new Identifier( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" );
public static final Identifier BACKGROUND_COMMAND = new Identifier( ComputerCraft.MOD_ID, "textures/gui/corners_command.png" ); public static final Identifier BACKGROUND_COMMAND = new Identifier( ComputerCraft.MOD_ID, "textures/gui/corners_command.png" );
@ -44,7 +44,8 @@ public class ComputerBorderRenderer {
public static final int LIGHT_HEIGHT = 8; 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
{
IDENTITY.loadIdentity(); IDENTITY.loadIdentity();
} }
@ -53,7 +54,8 @@ public class ComputerBorderRenderer {
private final int z; private final int z;
private final float r, g, b; private final float r, g, b;
public ComputerBorderRenderer(Matrix4f transform, VertexConsumer builder, int z, float r, float g, float b) { public ComputerBorderRenderer( Matrix4f transform, VertexConsumer builder, int z, float r, float g, float b )
{
this.transform = transform; this.transform = transform;
this.builder = builder; this.builder = builder;
this.z = z; this.z = z;
@ -64,8 +66,10 @@ public class ComputerBorderRenderer {
@Nonnull @Nonnull
public static Identifier getTexture(@Nonnull ComputerFamily family) { public static Identifier getTexture( @Nonnull ComputerFamily family )
switch (family) { {
switch( family )
{
case NORMAL: case NORMAL:
default: default:
return BACKGROUND_NORMAL; return BACKGROUND_NORMAL;
@ -76,7 +80,8 @@ public class ComputerBorderRenderer {
} }
} }
public static void render(int x, int y, int z, int width, int height) { public static void render( int x, int y, int z, int width, int height )
{
Tessellator tessellator = Tessellator.getInstance(); Tessellator tessellator = Tessellator.getInstance();
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 );
@ -87,11 +92,13 @@ public class ComputerBorderRenderer {
tessellator.draw(); tessellator.draw();
} }
public static void render(Matrix4f transform, VertexConsumer buffer, int x, int y, int z, int width, int height) { public static void render( Matrix4f transform, VertexConsumer buffer, int x, int y, int z, int width, int height )
{
render( transform, buffer, x, y, z, width, height, 1, 1, 1 ); render( transform, buffer, x, y, z, width, height, 1, 1, 1 );
} }
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, false, r, g, b ); render( transform, buffer, x, y, z, width, height, false, r, g, b );
} }
@ -130,19 +137,23 @@ public class ComputerBorderRenderer {
} }
} }
private void renderLine(int x, int y, int u, int v, int width, int height) { private void renderLine( int x, int y, int u, int v, int width, int height )
{
this.renderTexture( x, y, u, v, width, height, BORDER, BORDER ); this.renderTexture( x, y, u, v, width, height, BORDER, BORDER );
} }
private void renderCorner(int x, int y, int u, int v) { private void renderCorner( int x, int y, int u, int v )
{
this.renderTexture( x, y, u, v, BORDER, BORDER, BORDER, BORDER ); this.renderTexture( x, y, u, v, BORDER, BORDER, BORDER, BORDER );
} }
private void renderTexture(int x, int y, int u, int v, int width, int height) { private void renderTexture( int x, int y, int u, int v, int width, int height )
{
this.renderTexture( x, y, u, v, width, height, width, height ); this.renderTexture( x, y, u, v, width, height, width, height );
} }
private void renderTexture(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight) { private void renderTexture( int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight )
{
this.builder.vertex( this.transform, x, y + height, this.z ) this.builder.vertex( this.transform, x, y + height, this.z )
.color( this.r, this.g, this.b, 1.0f ) .color( this.r, this.g, this.b, 1.0f )
.texture( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE ) .texture( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE )

View File

@ -7,7 +7,8 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import dan200.computercraft.fabric.mixin.HeldItemRendererAccess; import dan200.computercraft.fabric.mixin.HeldItemRendererAccess;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.item.HeldItemRenderer; import net.minecraft.client.render.item.HeldItemRenderer;
@ -19,20 +20,22 @@ import net.minecraft.util.Arm;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@Environment( EnvType.CLIENT ) @Environment( EnvType.CLIENT )
public abstract class ItemMapLikeRenderer { public abstract class ItemMapLikeRenderer
{
public void renderItemFirstPerson( MatrixStack transform, VertexConsumerProvider render, int lightTexture, Hand hand, float pitch, float equipProgress public void renderItemFirstPerson( MatrixStack transform, VertexConsumerProvider render, int lightTexture, Hand hand, float pitch, float equipProgress
, float swingProgress, ItemStack stack) { , float swingProgress, ItemStack stack )
{
PlayerEntity player = MinecraftClient.getInstance().player; PlayerEntity player = MinecraftClient.getInstance().player;
transform.push(); transform.push();
if( hand == Hand.MAIN_HAND && player.getOffHandStack() if( hand == Hand.MAIN_HAND && player.getOffHandStack()
.isEmpty()) { .isEmpty() )
{
this.renderItemFirstPersonCenter( transform, render, lightTexture, pitch, equipProgress, swingProgress, stack ); this.renderItemFirstPersonCenter( transform, render, lightTexture, pitch, equipProgress, swingProgress, stack );
} else { }
else
{
this.renderItemFirstPersonSide( transform, this.renderItemFirstPersonSide( transform,
render, render,
lightTexture, lightTexture,
@ -57,7 +60,8 @@ public abstract class ItemMapLikeRenderer {
* @param stack The stack to render * @param stack The stack to render
*/ */
private void renderItemFirstPersonCenter( MatrixStack transform, VertexConsumerProvider render, int combinedLight, float pitch, float equipProgress, private void renderItemFirstPersonCenter( MatrixStack transform, VertexConsumerProvider render, int combinedLight, float pitch, float equipProgress,
float swingProgress, ItemStack stack) { float swingProgress, ItemStack stack )
{
MinecraftClient minecraft = MinecraftClient.getInstance(); MinecraftClient minecraft = MinecraftClient.getInstance();
HeldItemRenderer renderer = minecraft.getHeldItemRenderer(); HeldItemRenderer renderer = minecraft.getHeldItemRenderer();
@ -72,7 +76,8 @@ public abstract class ItemMapLikeRenderer {
float pitchAngle = access.callGetMapAngle( pitch ); float pitchAngle = access.callGetMapAngle( pitch );
transform.translate( 0, 0.04F + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f ); transform.translate( 0, 0.04F + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f );
transform.multiply( Vector3f.POSITIVE_X.getDegreesQuaternion( pitchAngle * -85.0f ) ); transform.multiply( Vector3f.POSITIVE_X.getDegreesQuaternion( pitchAngle * -85.0f ) );
if (!minecraft.player.isInvisible()) { if( !minecraft.player.isInvisible() )
{
transform.push(); transform.push();
transform.multiply( Vector3f.POSITIVE_Y.getDegreesQuaternion( 90.0F ) ); transform.multiply( Vector3f.POSITIVE_Y.getDegreesQuaternion( 90.0F ) );
access.callRenderArm( transform, render, combinedLight, Arm.RIGHT ); access.callRenderArm( transform, render, combinedLight, Arm.RIGHT );
@ -99,13 +104,15 @@ public abstract class ItemMapLikeRenderer {
* @param stack The stack to render * @param stack The stack to render
*/ */
private void renderItemFirstPersonSide( MatrixStack transform, VertexConsumerProvider render, int combinedLight, Arm side, float equipProgress, private void renderItemFirstPersonSide( MatrixStack transform, VertexConsumerProvider render, int combinedLight, Arm side, float equipProgress,
float swingProgress, ItemStack stack) { float swingProgress, ItemStack stack )
{
MinecraftClient minecraft = MinecraftClient.getInstance(); MinecraftClient minecraft = MinecraftClient.getInstance();
float offset = side == Arm.RIGHT ? 1f : -1f; float offset = side == Arm.RIGHT ? 1f : -1f;
transform.translate( offset * 0.125f, -0.125f, 0f ); transform.translate( offset * 0.125f, -0.125f, 0f );
// If the player is not invisible then render a single arm // If the player is not invisible then render a single arm
if (!minecraft.player.isInvisible()) { if( !minecraft.player.isInvisible() )
{
transform.push(); transform.push();
transform.multiply( Vector3f.POSITIVE_Z.getDegreesQuaternion( offset * 10f ) ); transform.multiply( Vector3f.POSITIVE_Z.getDegreesQuaternion( offset * 10f ) );
((HeldItemRendererAccess) minecraft.getHeldItemRenderer()) ((HeldItemRendererAccess) minecraft.getHeldItemRenderer())

View File

@ -6,12 +6,6 @@
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_WIDTH;
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.client.gui.FixedWidthFontRenderer;
@ -20,8 +14,6 @@ import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import org.lwjgl.opengl.GL11;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.Tessellator;
@ -31,28 +23,37 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.util.math.Vector3f; 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 org.lwjgl.opengl.GL11;
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.*; 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 ItemPocketRenderer() { private ItemPocketRenderer()
{
} }
@Override @Override
protected void renderItem(MatrixStack transform, VertexConsumerProvider render, ItemStack stack) { protected void renderItem( MatrixStack transform, VertexConsumerProvider render, ItemStack stack )
{
ClientComputer computer = ItemPocketComputer.createClientComputer( stack ); ClientComputer computer = ItemPocketComputer.createClientComputer( stack );
Terminal terminal = computer == null ? null : computer.getTerminal(); Terminal terminal = computer == null ? null : computer.getTerminal();
int termWidth, termHeight; int termWidth, termHeight;
if (terminal == null) { if( terminal == null )
{
termWidth = ComputerCraft.pocketTermWidth; termWidth = ComputerCraft.pocketTermWidth;
termHeight = ComputerCraft.pocketTermHeight; termHeight = ComputerCraft.pocketTermHeight;
} else { }
else
{
termWidth = terminal.getWidth(); termWidth = terminal.getWidth();
termHeight = terminal.getHeight(); termHeight = terminal.getHeight();
} }
@ -82,21 +83,26 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer {
// Render the light // Render the light
int lightColour = ItemPocketComputer.getLightState( stack ); int lightColour = ItemPocketComputer.getLightState( stack );
if (lightColour == -1) { if( lightColour == -1 )
{
lightColour = Colour.BLACK.getHex(); lightColour = Colour.BLACK.getHex();
} }
renderLight( matrix, lightColour, width, height ); renderLight( matrix, lightColour, width, height );
if (computer != null && terminal != null) { if( computer != null && terminal != null )
{
FixedWidthFontRenderer.drawTerminal( matrix, MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN ); FixedWidthFontRenderer.drawTerminal( matrix, MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN );
} else { }
else
{
FixedWidthFontRenderer.drawEmptyTerminal( matrix, 0, 0, width, height ); FixedWidthFontRenderer.drawEmptyTerminal( matrix, 0, 0, width, height );
} }
transform.pop(); transform.pop();
} }
private static void renderFrame(Matrix4f transform, ComputerFamily family, int colour, int width, int height) { private static void renderFrame( Matrix4f transform, ComputerFamily family, int colour, int width, int height )
{
RenderSystem.enableBlend(); RenderSystem.enableBlend();
MinecraftClient.getInstance() MinecraftClient.getInstance()
.getTextureManager() .getTextureManager()
@ -115,7 +121,8 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer {
tessellator.draw(); tessellator.draw();
} }
private static void renderLight(Matrix4f transform, int colour, int width, int height) { private static void renderLight( Matrix4f transform, int colour, int width, int height )
{
RenderSystem.disableTexture(); RenderSystem.disableTexture();
float r = ((colour >>> 16) & 0xFF) / 255.0f; float r = ((colour >>> 16) & 0xFF) / 255.0f;

View File

@ -6,36 +6,33 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
import static dan200.computercraft.client.render.PrintoutRenderer.COVER_SIZE;
import static dan200.computercraft.client.render.PrintoutRenderer.X_TEXT_MARGIN;
import static dan200.computercraft.client.render.PrintoutRenderer.Y_TEXT_MARGIN;
import static dan200.computercraft.client.render.PrintoutRenderer.drawBorder;
import static dan200.computercraft.client.render.PrintoutRenderer.drawText;
import static dan200.computercraft.client.render.PrintoutRenderer.offsetAt;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENGTH;
import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.media.items.ItemPrintout;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.util.math.Vector3f; 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.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
import static dan200.computercraft.client.render.PrintoutRenderer.*;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENGTH;
/** /**
* Emulates map and item-frame rendering for printouts. * Emulates map and item-frame rendering for printouts.
*/ */
public final class ItemPrintoutRenderer extends ItemMapLikeRenderer { public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
{
public static final ItemPrintoutRenderer INSTANCE = new ItemPrintoutRenderer(); public static final ItemPrintoutRenderer INSTANCE = new ItemPrintoutRenderer();
private ItemPrintoutRenderer() { private ItemPrintoutRenderer()
{
} }
@Override @Override
protected void renderItem(MatrixStack transform, VertexConsumerProvider render, ItemStack stack) { protected void renderItem( MatrixStack transform, VertexConsumerProvider render, ItemStack stack )
{
transform.multiply( Vector3f.POSITIVE_X.getDegreesQuaternion( 180f ) ); transform.multiply( Vector3f.POSITIVE_X.getDegreesQuaternion( 180f ) );
transform.scale( 0.42f, 0.42f, -0.42f ); transform.scale( 0.42f, 0.42f, -0.42f );
transform.translate( -0.5f, -0.48f, 0.0f ); transform.translate( -0.5f, -0.48f, 0.0f );
@ -43,7 +40,8 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer {
drawPrintout( transform, render, stack ); drawPrintout( transform, render, stack );
} }
private static void drawPrintout(MatrixStack transform, VertexConsumerProvider render, ItemStack stack) { private static void drawPrintout( MatrixStack transform, VertexConsumerProvider render, ItemStack stack )
{
int pages = ItemPrintout.getPageCount( stack ); int pages = ItemPrintout.getPageCount( stack );
boolean book = ((ItemPrintout) stack.getItem()).getType() == ItemPrintout.Type.BOOK; boolean book = ((ItemPrintout) stack.getItem()).getType() == ItemPrintout.Type.BOOK;
@ -51,14 +49,16 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer {
double height = LINES_PER_PAGE * FONT_HEIGHT + Y_TEXT_MARGIN * 2; double height = LINES_PER_PAGE * FONT_HEIGHT + Y_TEXT_MARGIN * 2;
// Non-books will be left aligned // Non-books will be left aligned
if (!book) { if( !book )
{
width += offsetAt( pages ); width += offsetAt( pages );
} }
double visualWidth = width, visualHeight = height; double visualWidth = width, visualHeight = height;
// Meanwhile books will be centred // Meanwhile books will be centred
if (book) { if( book )
{
visualWidth += 2 * COVER_SIZE + 2 * offsetAt( pages ); visualWidth += 2 * COVER_SIZE + 2 * offsetAt( pages );
visualHeight += 2 * COVER_SIZE; visualHeight += 2 * COVER_SIZE;
} }
@ -76,8 +76,10 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer {
drawText( matrix, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) ); drawText( matrix, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) );
} }
public boolean renderInFrame(MatrixStack matrixStack, VertexConsumerProvider consumerProvider, ItemStack stack) { public boolean renderInFrame( MatrixStack matrixStack, VertexConsumerProvider consumerProvider, ItemStack stack )
if (!(stack.getItem() instanceof ItemPrintout)) { {
if( !(stack.getItem() instanceof ItemPrintout) )
{
return false; return false;
} }

View File

@ -5,10 +5,9 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import java.util.List;
import dan200.computercraft.fabric.mixin.BakedQuadAccess; import dan200.computercraft.fabric.mixin.BakedQuadAccess;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormatElement; import net.minecraft.client.render.VertexFormatElement;
import net.minecraft.client.render.VertexFormats; import net.minecraft.client.render.VertexFormats;
@ -16,44 +15,54 @@ import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.util.math.Vector4f; import net.minecraft.client.util.math.Vector4f;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import net.fabricmc.api.EnvType; import java.util.List;
import net.fabricmc.api.Environment;
/** /**
* Transforms vertices of a model, remaining aware of winding order, and rearranging vertices if needed. * Transforms vertices of a model, remaining aware of winding order, and rearranging vertices if needed.
*/ */
@Environment( EnvType.CLIENT ) @Environment( EnvType.CLIENT )
public final class ModelTransformer { public final class ModelTransformer
{
private static final Matrix4f identity; private static final Matrix4f identity;
static { static
{
identity = new Matrix4f(); identity = new Matrix4f();
identity.loadIdentity(); identity.loadIdentity();
} }
private ModelTransformer() { private ModelTransformer()
{
} }
public static void transformQuadsTo(List<BakedQuad> output, List<BakedQuad> input, Matrix4f transform) { public static void transformQuadsTo( List<BakedQuad> output, List<BakedQuad> input, Matrix4f transform )
{
transformQuadsTo( VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, output, input, transform ); transformQuadsTo( VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, output, input, transform );
} }
public static void transformQuadsTo(VertexFormat format, List<BakedQuad> output, List<BakedQuad> input, Matrix4f transform) { public static void transformQuadsTo( VertexFormat format, List<BakedQuad> output, List<BakedQuad> input, Matrix4f transform )
if (transform == null || transform.equals(identity)) { {
if( transform == null || transform.equals( identity ) )
{
output.addAll( input ); output.addAll( input );
} else { }
for (BakedQuad quad : input) { else
{
for( BakedQuad quad : input )
{
output.add( doTransformQuad( format, quad, transform ) ); output.add( doTransformQuad( format, quad, transform ) );
} }
} }
} }
private static BakedQuad doTransformQuad(VertexFormat format, BakedQuad quad, Matrix4f transform) { private static BakedQuad doTransformQuad( VertexFormat format, BakedQuad quad, Matrix4f transform )
{
int[] vertexData = quad.getVertexData().clone(); int[] vertexData = quad.getVertexData().clone();
BakedQuad copy = new BakedQuad( vertexData, -1, quad.getFace(), ((BakedQuadAccess) quad).getSprite(), true ); BakedQuad copy = new BakedQuad( vertexData, -1, quad.getFace(), ((BakedQuadAccess) quad).getSprite(), true );
int offsetBytes = 0; int offsetBytes = 0;
for (int v = 0; v < 4; ++v) { for( int v = 0; v < 4; ++v )
{
for( VertexFormatElement element : format.getElements() ) // For each vertex element for( VertexFormatElement element : format.getElements() ) // For each vertex element
{ {
int start = offsetBytes / Integer.BYTES; int start = offsetBytes / Integer.BYTES;
@ -78,8 +87,10 @@ public final class ModelTransformer {
return copy; return copy;
} }
public static BakedQuad transformQuad(VertexFormat format, BakedQuad input, Matrix4f transform) { public static BakedQuad transformQuad( VertexFormat format, BakedQuad input, Matrix4f transform )
if (transform == null || transform.equals(identity)) { {
if( transform == null || transform.equals( identity ) )
{
return input; return input;
} }
return doTransformQuad( format, input, transform ); return doTransformQuad( format, input, transform );

View File

@ -6,17 +6,9 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import static net.minecraft.util.math.Direction.DOWN;
import static net.minecraft.util.math.Direction.EAST;
import static net.minecraft.util.math.Direction.NORTH;
import static net.minecraft.util.math.Direction.SOUTH;
import static net.minecraft.util.math.Direction.UP;
import static net.minecraft.util.math.Direction.WEST;
import java.util.EnumSet;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
@ -29,29 +21,35 @@ import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.fabricmc.api.EnvType; import java.util.EnumSet;
import net.fabricmc.api.Environment;
import static net.minecraft.util.math.Direction.*;
/** /**
* Overrides monitor highlighting to only render the outline of the <em>whole</em> monitor, rather than the current block. This means you do not get an * Overrides monitor highlighting to only render the outline of the <em>whole</em> monitor, rather than the current block. This means you do not get an
* intrusive outline on top of the screen. * intrusive outline on top of the screen.
*/ */
@Environment( EnvType.CLIENT ) @Environment( EnvType.CLIENT )
public final class MonitorHighlightRenderer { public final class MonitorHighlightRenderer
private MonitorHighlightRenderer() { {
private MonitorHighlightRenderer()
{
} }
public static boolean drawHighlight( MatrixStack matrixStack, VertexConsumer vertexConsumer, Entity entity, double d, double e, double f, BlockPos pos public static boolean drawHighlight( MatrixStack matrixStack, VertexConsumer vertexConsumer, Entity entity, double d, double e, double f, BlockPos pos
, BlockState blockState) { , BlockState blockState )
{
// Preserve normal behaviour when crouching. // Preserve normal behaviour when crouching.
if (entity.isInSneakingPose()) { if( entity.isInSneakingPose() )
{
return false; return false;
} }
World world = entity.getEntityWorld(); World world = entity.getEntityWorld();
BlockEntity tile = world.getBlockEntity( pos ); BlockEntity tile = world.getBlockEntity( pos );
if (!(tile instanceof TileMonitor)) { if( !(tile instanceof TileMonitor) )
{
return false; return false;
} }
@ -61,18 +59,22 @@ public final class MonitorHighlightRenderer {
EnumSet<Direction> faces = EnumSet.allOf( Direction.class ); EnumSet<Direction> faces = EnumSet.allOf( Direction.class );
Direction front = monitor.getFront(); Direction front = monitor.getFront();
faces.remove( front ); faces.remove( front );
if (monitor.getXIndex() != 0) { if( monitor.getXIndex() != 0 )
{
faces.remove( monitor.getRight() faces.remove( monitor.getRight()
.getOpposite() ); .getOpposite() );
} }
if (monitor.getXIndex() != monitor.getWidth() - 1) { if( monitor.getXIndex() != monitor.getWidth() - 1 )
{
faces.remove( monitor.getRight() ); faces.remove( monitor.getRight() );
} }
if (monitor.getYIndex() != 0) { if( monitor.getYIndex() != 0 )
{
faces.remove( monitor.getDown() faces.remove( monitor.getDown()
.getOpposite() ); .getOpposite() );
} }
if (monitor.getYIndex() != monitor.getHeight() - 1) { if( monitor.getYIndex() != monitor.getHeight() - 1 )
{
faces.remove( monitor.getDown() ); faces.remove( monitor.getDown() );
} }
@ -84,40 +86,52 @@ public final class MonitorHighlightRenderer {
// I wish I could think of a better way to do this // I wish I could think of a better way to do this
Matrix4f transform = matrixStack.peek() Matrix4f transform = matrixStack.peek()
.getModel(); .getModel();
if (faces.contains(NORTH) || faces.contains(WEST)) { if( faces.contains( NORTH ) || faces.contains( WEST ) )
{
line( vertexConsumer, transform, 0, 0, 0, UP ); line( vertexConsumer, transform, 0, 0, 0, UP );
} }
if (faces.contains(SOUTH) || faces.contains(WEST)) { if( faces.contains( SOUTH ) || faces.contains( WEST ) )
{
line( vertexConsumer, transform, 0, 0, 1, UP ); line( vertexConsumer, transform, 0, 0, 1, UP );
} }
if (faces.contains(NORTH) || faces.contains(EAST)) { if( faces.contains( NORTH ) || faces.contains( EAST ) )
{
line( vertexConsumer, transform, 1, 0, 0, UP ); line( vertexConsumer, transform, 1, 0, 0, UP );
} }
if (faces.contains(SOUTH) || faces.contains(EAST)) { if( faces.contains( SOUTH ) || faces.contains( EAST ) )
{
line( vertexConsumer, transform, 1, 0, 1, UP ); line( vertexConsumer, transform, 1, 0, 1, UP );
} }
if (faces.contains(NORTH) || faces.contains(DOWN)) { if( faces.contains( NORTH ) || faces.contains( DOWN ) )
{
line( vertexConsumer, transform, 0, 0, 0, EAST ); line( vertexConsumer, transform, 0, 0, 0, EAST );
} }
if (faces.contains(SOUTH) || faces.contains(DOWN)) { if( faces.contains( SOUTH ) || faces.contains( DOWN ) )
{
line( vertexConsumer, transform, 0, 0, 1, EAST ); line( vertexConsumer, transform, 0, 0, 1, EAST );
} }
if (faces.contains(NORTH) || faces.contains(UP)) { if( faces.contains( NORTH ) || faces.contains( UP ) )
{
line( vertexConsumer, transform, 0, 1, 0, EAST ); line( vertexConsumer, transform, 0, 1, 0, EAST );
} }
if (faces.contains(SOUTH) || faces.contains(UP)) { if( faces.contains( SOUTH ) || faces.contains( UP ) )
{
line( vertexConsumer, transform, 0, 1, 1, EAST ); line( vertexConsumer, transform, 0, 1, 1, EAST );
} }
if (faces.contains(WEST) || faces.contains(DOWN)) { if( faces.contains( WEST ) || faces.contains( DOWN ) )
{
line( vertexConsumer, transform, 0, 0, 0, SOUTH ); line( vertexConsumer, transform, 0, 0, 0, SOUTH );
} }
if (faces.contains(EAST) || faces.contains(DOWN)) { if( faces.contains( EAST ) || faces.contains( DOWN ) )
{
line( vertexConsumer, transform, 1, 0, 0, SOUTH ); line( vertexConsumer, transform, 1, 0, 0, SOUTH );
} }
if (faces.contains(WEST) || faces.contains(UP)) { if( faces.contains( WEST ) || faces.contains( UP ) )
{
line( vertexConsumer, transform, 0, 1, 0, SOUTH ); line( vertexConsumer, transform, 0, 1, 0, SOUTH );
} }
if (faces.contains(EAST) || faces.contains(UP)) { if( faces.contains( EAST ) || faces.contains( UP ) )
{
line( vertexConsumer, transform, 1, 1, 0, SOUTH ); line( vertexConsumer, transform, 1, 1, 0, SOUTH );
} }
@ -126,7 +140,8 @@ public final class MonitorHighlightRenderer {
return true; return true;
} }
private static void line(VertexConsumer buffer, Matrix4f transform, float x, float y, float z, Direction direction) { private static void line( VertexConsumer buffer, Matrix4f transform, float x, float y, float z, Direction direction )
{
buffer.vertex( transform, x, y, z ) buffer.vertex( transform, x, y, z )
.color( 0, 0, 0, 0.4f ) .color( 0, 0, 0, 0.4f )
.next(); .next();

View File

@ -5,23 +5,23 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import java.io.InputStream;
import java.nio.FloatBuffer;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.shared.util.Palette; import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.texture.TextureUtil;
import net.minecraft.util.math.Matrix4f;
import org.lwjgl.BufferUtils; import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL20;
import net.minecraft.client.texture.TextureUtil; import java.io.InputStream;
import net.minecraft.util.math.Matrix4f; import java.nio.FloatBuffer;
class MonitorTextureBufferShader { class MonitorTextureBufferShader
{
static final int TEXTURE_INDEX = GL13.GL_TEXTURE3; static final int TEXTURE_INDEX = GL13.GL_TEXTURE3;
private static final FloatBuffer MATRIX_BUFFER = BufferUtils.createFloatBuffer( 16 ); private static final FloatBuffer MATRIX_BUFFER = BufferUtils.createFloatBuffer( 16 );
@ -39,7 +39,8 @@ class MonitorTextureBufferShader {
private static boolean ok; private static boolean ok;
private static int program; private static int program;
static void setupUniform(Matrix4f transform, int width, int height, Palette palette, boolean greyscale) { static void setupUniform( Matrix4f transform, int width, int height, Palette palette, boolean greyscale )
{
MATRIX_BUFFER.rewind(); MATRIX_BUFFER.rewind();
transform.writeToBuffer( MATRIX_BUFFER ); transform.writeToBuffer( MATRIX_BUFFER );
MATRIX_BUFFER.rewind(); MATRIX_BUFFER.rewind();
@ -49,14 +50,18 @@ class MonitorTextureBufferShader {
RenderSystem.glUniform1i( uniformHeight, height ); RenderSystem.glUniform1i( uniformHeight, height );
PALETTE_BUFFER.rewind(); PALETTE_BUFFER.rewind();
for (int i = 0; i < 16; i++) { for( int i = 0; i < 16; i++ )
{
double[] colour = palette.getColour( i ); double[] colour = palette.getColour( i );
if (greyscale) { if( greyscale )
{
float f = FixedWidthFontRenderer.toGreyscale( colour ); float f = FixedWidthFontRenderer.toGreyscale( colour );
PALETTE_BUFFER.put( f ) PALETTE_BUFFER.put( f )
.put( f ) .put( f )
.put( f ); .put( f );
} else { }
else
{
PALETTE_BUFFER.put( (float) colour[0] ) PALETTE_BUFFER.put( (float) colour[0] )
.put( (float) colour[1] ) .put( (float) colour[1] )
.put( (float) colour[2] ); .put( (float) colour[2] );
@ -66,15 +71,19 @@ class MonitorTextureBufferShader {
RenderSystem.glUniform3( uniformPalette, PALETTE_BUFFER ); RenderSystem.glUniform3( uniformPalette, PALETTE_BUFFER );
} }
static boolean use() { static boolean use()
if (initialised) { {
if (ok) { if( initialised )
{
if( ok )
{
GlStateManager.useProgram( program ); GlStateManager.useProgram( program );
} }
return ok; return ok;
} }
if (ok = load()) { if( ok = load() )
{
GL20.glUseProgram( program ); GL20.glUseProgram( program );
RenderSystem.glUniform1i( uniformFont, 0 ); RenderSystem.glUniform1i( uniformFont, 0 );
RenderSystem.glUniform1i( uniformTbo, TEXTURE_INDEX - GL13.GL_TEXTURE0 ); RenderSystem.glUniform1i( uniformTbo, TEXTURE_INDEX - GL13.GL_TEXTURE0 );
@ -83,10 +92,12 @@ class MonitorTextureBufferShader {
return ok; return ok;
} }
private static boolean load() { private static boolean load()
{
initialised = true; initialised = true;
try { try
{
int vertexShader = loadShader( GL20.GL_VERTEX_SHADER, "assets/computercraft/shaders/monitor.vert" ); int vertexShader = loadShader( GL20.GL_VERTEX_SHADER, "assets/computercraft/shaders/monitor.vert" );
int fragmentShader = loadShader( GL20.GL_FRAGMENT_SHADER, "assets/computercraft/shaders/monitor.frag" ); int fragmentShader = loadShader( GL20.GL_FRAGMENT_SHADER, "assets/computercraft/shaders/monitor.frag" );
@ -99,7 +110,8 @@ class MonitorTextureBufferShader {
boolean ok = GlStateManager.getProgram( program, GL20.GL_LINK_STATUS ) != 0; boolean ok = GlStateManager.getProgram( program, GL20.GL_LINK_STATUS ) != 0;
String log = GlStateManager.getProgramInfoLog( program, Short.MAX_VALUE ) String log = GlStateManager.getProgramInfoLog( program, Short.MAX_VALUE )
.trim(); .trim();
if (!Strings.isNullOrEmpty(log)) { if( !Strings.isNullOrEmpty( log ) )
{
ComputerCraft.log.warn( "Problems when linking monitor shader: {}", log ); ComputerCraft.log.warn( "Problems when linking monitor shader: {}", log );
} }
@ -108,7 +120,8 @@ class MonitorTextureBufferShader {
GlStateManager.deleteShader( vertexShader ); GlStateManager.deleteShader( vertexShader );
GlStateManager.deleteShader( fragmentShader ); GlStateManager.deleteShader( fragmentShader );
if (!ok) { if( !ok )
{
return false; return false;
} }
@ -121,16 +134,20 @@ class MonitorTextureBufferShader {
ComputerCraft.log.info( "Loaded monitor shader." ); ComputerCraft.log.info( "Loaded monitor shader." );
return true; return true;
} catch (Exception e) { }
catch( Exception e )
{
ComputerCraft.log.error( "Cannot load monitor shaders", e ); ComputerCraft.log.error( "Cannot load monitor shaders", e );
return false; return false;
} }
} }
private static int loadShader(int kind, String path) { private static int loadShader( int kind, String path )
{
InputStream stream = TileEntityMonitorRenderer.class.getClassLoader() InputStream stream = TileEntityMonitorRenderer.class.getClassLoader()
.getResourceAsStream( path ); .getResourceAsStream( path );
if (stream == null) { if( stream == null )
{
throw new IllegalArgumentException( "Cannot find " + path ); throw new IllegalArgumentException( "Cannot find " + path );
} }
String contents = TextureUtil.readAllToString( stream ); String contents = TextureUtil.readAllToString( stream );
@ -143,19 +160,23 @@ class MonitorTextureBufferShader {
boolean ok = GlStateManager.getShader( shader, GL20.GL_COMPILE_STATUS ) != 0; boolean ok = GlStateManager.getShader( shader, GL20.GL_COMPILE_STATUS ) != 0;
String log = GlStateManager.getShaderInfoLog( shader, Short.MAX_VALUE ) String log = GlStateManager.getShaderInfoLog( shader, Short.MAX_VALUE )
.trim(); .trim();
if (!Strings.isNullOrEmpty(log)) { if( !Strings.isNullOrEmpty( log ) )
{
ComputerCraft.log.warn( "Problems when loading monitor shader {}: {}", path, log ); ComputerCraft.log.warn( "Problems when loading monitor shader {}: {}", path, log );
} }
if (!ok) { if( !ok )
{
throw new IllegalStateException( "Cannot compile shader " + path ); throw new IllegalStateException( "Cannot compile shader " + path );
} }
return shader; return shader;
} }
private static int getUniformLocation(int program, String name) { private static int getUniformLocation( int program, String name )
{
int uniform = GlStateManager.getUniformLocation( program, name ); int uniform = GlStateManager.getUniformLocation( program, name );
if (uniform == -1) { if( uniform == -1 )
{
throw new IllegalStateException( "Cannot find uniform " + name ); throw new IllegalStateException( "Cannot find uniform " + name );
} }
return uniform; return uniform;

View File

@ -6,23 +6,19 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Palette; import dan200.computercraft.shared.util.Palette;
import org.lwjgl.opengl.GL11; import net.minecraft.client.render.*;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.RenderPhase;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import org.lwjgl.opengl.GL11;
public final class PrintoutRenderer { import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
public final class PrintoutRenderer
{
/** /**
* Width of a page. * Width of a page.
*/ */
@ -54,9 +50,11 @@ public final class PrintoutRenderer {
private PrintoutRenderer() {} private PrintoutRenderer() {}
public static void drawText(Matrix4f transform, VertexConsumerProvider renderer, int x, int y, int start, TextBuffer[] text, TextBuffer[] colours) { public static void drawText( Matrix4f transform, VertexConsumerProvider renderer, int x, int y, int start, TextBuffer[] text, TextBuffer[] colours )
{
VertexConsumer buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE ); VertexConsumer buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE );
for (int line = 0; line < LINES_PER_PAGE && line < text.length; line++) { for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ )
{
FixedWidthFontRenderer.drawString( transform, FixedWidthFontRenderer.drawString( transform,
buffer, buffer,
x, x,
@ -71,9 +69,11 @@ public final class PrintoutRenderer {
} }
} }
public static void drawText(Matrix4f transform, VertexConsumerProvider renderer, int x, int y, int start, String[] text, String[] colours) { public static void drawText( Matrix4f transform, VertexConsumerProvider renderer, int x, int y, int start, String[] text, String[] colours )
{
VertexConsumer buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE ); VertexConsumer buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE );
for (int line = 0; line < LINES_PER_PAGE && line < text.length; line++) { for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ )
{
FixedWidthFontRenderer.drawString( transform, FixedWidthFontRenderer.drawString( transform,
buffer, buffer,
x, x,
@ -88,13 +88,15 @@ public final class PrintoutRenderer {
} }
} }
public static void drawBorder(Matrix4f transform, VertexConsumerProvider renderer, float x, float y, float z, int page, int pages, boolean isBook) { public static void drawBorder( Matrix4f transform, VertexConsumerProvider renderer, float x, float y, float z, int page, int pages, boolean isBook )
{
int leftPages = page; int leftPages = page;
int rightPages = pages - page - 1; int rightPages = pages - page - 1;
VertexConsumer buffer = renderer.getBuffer( Type.TYPE ); VertexConsumer buffer = renderer.getBuffer( Type.TYPE );
if (isBook) { if( isBook )
{
// Border // Border
float offset = offsetAt( pages ); float offset = offsetAt( pages );
float left = x - 4 - offset; float left = x - 4 - offset;
@ -118,7 +120,8 @@ public final class PrintoutRenderer {
Y_SIZE ); Y_SIZE );
float borderX = left; float borderX = left;
while (borderX < right) { while( borderX < right )
{
double thisWidth = Math.min( right - borderX, X_SIZE ); double thisWidth = Math.min( right - borderX, X_SIZE );
drawTexture( transform, buffer, borderX, y - 8, z - 0.02f, 0, COVER_Y, (float) thisWidth, COVER_SIZE ); drawTexture( transform, buffer, borderX, y - 8, z - 0.02f, 0, COVER_Y, (float) thisWidth, COVER_SIZE );
drawTexture( transform, buffer, borderX, y + Y_SIZE - 4, z - 0.02f, 0, COVER_Y + COVER_SIZE, (float) thisWidth, COVER_SIZE ); drawTexture( transform, buffer, borderX, y + Y_SIZE - 4, z - 0.02f, 0, COVER_Y + COVER_SIZE, (float) thisWidth, COVER_SIZE );
@ -128,7 +131,8 @@ public final class PrintoutRenderer {
// Left half // Left half
drawTexture( transform, buffer, x, y, z, X_FOLD_SIZE * 2, 0, X_SIZE / 2.0f, Y_SIZE ); drawTexture( transform, buffer, x, y, z, X_FOLD_SIZE * 2, 0, X_SIZE / 2.0f, Y_SIZE );
for (int n = 0; n <= leftPages; n++) { for( int n = 0; n <= leftPages; n++ )
{
drawTexture( transform, buffer, x - offsetAt( n ), y, z - 1e-3f * n, drawTexture( transform, buffer, x - offsetAt( n ), y, z - 1e-3f * n,
// Use the left "bold" fold for the outermost page // Use the left "bold" fold for the outermost page
n == leftPages ? 0 : X_FOLD_SIZE, 0, X_FOLD_SIZE, Y_SIZE ); n == leftPages ? 0 : X_FOLD_SIZE, 0, X_FOLD_SIZE, Y_SIZE );
@ -136,18 +140,21 @@ public final class PrintoutRenderer {
// Right half // Right half
drawTexture( transform, buffer, x + X_SIZE / 2.0f, y, z, X_FOLD_SIZE * 2 + X_SIZE / 2.0f, 0, X_SIZE / 2.0f, Y_SIZE ); drawTexture( transform, buffer, x + X_SIZE / 2.0f, y, z, X_FOLD_SIZE * 2 + X_SIZE / 2.0f, 0, X_SIZE / 2.0f, Y_SIZE );
for (int n = 0; n <= rightPages; n++) { for( int n = 0; n <= rightPages; n++ )
{
drawTexture( transform, buffer, x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3f * n, drawTexture( transform, buffer, x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3f * n,
// Two folds, then the main page. Use the right "bold" fold for the outermost page. // Two folds, then the main page. Use the right "bold" fold for the outermost page.
X_FOLD_SIZE * 2 + X_SIZE + (n == rightPages ? X_FOLD_SIZE : 0), 0, X_FOLD_SIZE, Y_SIZE ); X_FOLD_SIZE * 2 + X_SIZE + (n == rightPages ? X_FOLD_SIZE : 0), 0, X_FOLD_SIZE, Y_SIZE );
} }
} }
public static float offsetAt(int page) { public static float offsetAt( int page )
{
return (float) (32 * (1 - Math.pow( 1.2, -page ))); return (float) (32 * (1 - Math.pow( 1.2, -page )));
} }
private static void drawTexture(Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float u, float v, float width, float height) { private static void drawTexture( Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float u, float v, float width, float height )
{
buffer.vertex( matrix, x, y + height, z ) buffer.vertex( matrix, x, y + height, z )
.texture( u / BG_SIZE, (v + height) / BG_SIZE ) .texture( u / BG_SIZE, (v + height) / BG_SIZE )
.next(); .next();
@ -163,7 +170,8 @@ public final class PrintoutRenderer {
} }
private static void drawTexture( Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float width, float height, float u, float v, private static void drawTexture( Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float width, float height, float u, float v,
float tWidth, float tHeight) { float tWidth, float tHeight )
{
buffer.vertex( matrix, x, y + height, z ) buffer.vertex( matrix, x, y + height, z )
.texture( u / BG_SIZE, (v + tHeight) / BG_SIZE ) .texture( u / BG_SIZE, (v + tHeight) / BG_SIZE )
.next(); .next();
@ -178,7 +186,8 @@ public final class PrintoutRenderer {
.next(); .next();
} }
private static final class Type extends RenderPhase { private static final class Type extends RenderPhase
{
static final RenderLayer TYPE = RenderLayer.of( "printout_background", static final RenderLayer TYPE = RenderLayer.of( "printout_background",
VertexFormats.POSITION_TEXTURE, VertexFormats.POSITION_TEXTURE,
GL11.GL_QUADS, GL11.GL_QUADS,
@ -192,7 +201,8 @@ public final class PrintoutRenderer {
.lightmap( DISABLE_LIGHTMAP ) .lightmap( DISABLE_LIGHTMAP )
.build( false ) ); .build( false ) );
private Type(String name, Runnable setup, Runnable destroy) { private Type( String name, Runnable setup, Runnable destroy )
{
super( name, setup, destroy ); super( name, setup, destroy );
} }
} }

View File

@ -6,14 +6,6 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
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.getColour;
import java.nio.ByteBuffer;
import javax.annotation.Nonnull;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.client.gui.FixedWidthFontRenderer;
@ -24,17 +16,8 @@ import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.DirectionUtil;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL31;
import net.minecraft.client.gl.VertexBuffer; import net.minecraft.client.gl.VertexBuffer;
import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.*;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher;
import net.minecraft.client.render.block.entity.BlockEntityRenderer; import net.minecraft.client.render.block.entity.BlockEntityRenderer;
import net.minecraft.client.util.GlAllocationUtils; import net.minecraft.client.util.GlAllocationUtils;
@ -44,8 +27,18 @@ import net.minecraft.client.util.math.Vector3f;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL31;
public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor> { import javax.annotation.Nonnull;
import java.nio.ByteBuffer;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*;
public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
{
/** /**
* {@link TileMonitor#RENDER_MARGIN}, but a tiny bit of additional padding to ensure that there is no space between the monitor frame and contents. * {@link TileMonitor#RENDER_MARGIN}, but a tiny bit of additional padding to ensure that there is no space between the monitor frame and contents.
*/ */
@ -54,17 +47,20 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
.getMatrix(); .getMatrix();
private static ByteBuffer tboContents; private static ByteBuffer tboContents;
public TileEntityMonitorRenderer(BlockEntityRenderDispatcher rendererDispatcher) { public TileEntityMonitorRenderer( BlockEntityRenderDispatcher rendererDispatcher )
{
super( rendererDispatcher ); super( rendererDispatcher );
} }
@Override @Override
public void render( @Nonnull TileMonitor monitor, float partialTicks, @Nonnull MatrixStack transform, @Nonnull VertexConsumerProvider renderer, public void render( @Nonnull TileMonitor monitor, float partialTicks, @Nonnull MatrixStack transform, @Nonnull VertexConsumerProvider renderer,
int lightmapCoord, int overlayLight) { int lightmapCoord, int overlayLight )
{
// Render from the origin monitor // Render from the origin monitor
ClientMonitor originTerminal = monitor.getClientMonitor(); ClientMonitor originTerminal = monitor.getClientMonitor();
if (originTerminal == null) { if( originTerminal == null )
{
return; return;
} }
TileMonitor origin = originTerminal.getOrigin(); TileMonitor origin = originTerminal.getOrigin();
@ -74,7 +70,8 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
// multiple times in a single frame to ensure compatibility with shaders which may run a // multiple times in a single frame to ensure compatibility with shaders which may run a
// pass multiple times. // pass multiple times.
long renderFrame = FrameInfo.getRenderFrame(); long renderFrame = FrameInfo.getRenderFrame();
if (originTerminal.lastRenderFrame == renderFrame && !monitorPos.equals(originTerminal.lastRenderPos)) { if( originTerminal.lastRenderFrame == renderFrame && !monitorPos.equals( originTerminal.lastRenderPos ) )
{
return; return;
} }
@ -105,7 +102,8 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
// Draw the contents // Draw the contents
Terminal terminal = originTerminal.getTerminal(); Terminal terminal = originTerminal.getTerminal();
if (terminal != null) { if( terminal != null )
{
// Draw a terminal // Draw a terminal
int width = terminal.getWidth(), height = terminal.getHeight(); int width = terminal.getWidth(), height = terminal.getHeight();
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT; int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
@ -130,7 +128,9 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
FixedWidthFontRenderer.drawCursor( matrix, buffer, 0, 0, terminal, !originTerminal.isColour() ); FixedWidthFontRenderer.drawCursor( matrix, buffer, 0, 0, terminal, !originTerminal.isColour() );
transform.pop(); transform.pop();
} else { }
else
{
FixedWidthFontRenderer.drawEmptyTerminal( transform.peek() FixedWidthFontRenderer.drawEmptyTerminal( transform.peek()
.getModel(), .getModel(),
renderer, renderer,
@ -151,35 +151,44 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
transform.pop(); transform.pop();
} }
private static void renderTerminal(Matrix4f matrix, ClientMonitor monitor, float xMargin, float yMargin) { private static void renderTerminal( Matrix4f matrix, ClientMonitor monitor, float xMargin, float yMargin )
{
Terminal terminal = monitor.getTerminal(); Terminal terminal = monitor.getTerminal();
MonitorRenderer renderType = MonitorRenderer.current(); MonitorRenderer renderType = MonitorRenderer.current();
boolean redraw = monitor.pollTerminalChanged(); boolean redraw = monitor.pollTerminalChanged();
if (monitor.createBuffer(renderType)) { if( monitor.createBuffer( renderType ) )
{
redraw = true; redraw = true;
} }
switch (renderType) { switch( renderType )
case TBO: { {
if (!MonitorTextureBufferShader.use()) { case TBO:
{
if( !MonitorTextureBufferShader.use() )
{
return; return;
} }
int width = terminal.getWidth(), height = terminal.getHeight(); int width = terminal.getWidth(), height = terminal.getHeight();
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT; int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
if (redraw) { if( redraw )
{
int size = width * height * 3; int size = width * height * 3;
if (tboContents == null || tboContents.capacity() < size) { if( tboContents == null || tboContents.capacity() < size )
{
tboContents = GlAllocationUtils.allocateByteBuffer( size ); tboContents = GlAllocationUtils.allocateByteBuffer( size );
} }
ByteBuffer monitorBuffer = tboContents; ByteBuffer monitorBuffer = tboContents;
monitorBuffer.clear(); monitorBuffer.clear();
for (int y = 0; y < height; y++) { for( int y = 0; y < height; y++ )
{
TextBuffer text = terminal.getLine( y ), textColour = terminal.getTextColourLine( y ), background = terminal.getBackgroundColourLine( y ); TextBuffer text = terminal.getLine( y ), textColour = terminal.getTextColourLine( y ), background = terminal.getBackgroundColourLine( y );
for (int x = 0; x < width; x++) { for( int x = 0; x < width; x++ )
{
monitorBuffer.put( (byte) (text.charAt( x ) & 0xFF) ); monitorBuffer.put( (byte) (text.charAt( x ) & 0xFF) );
monitorBuffer.put( (byte) getColour( textColour.charAt( x ), Colour.WHITE ) ); monitorBuffer.put( (byte) getColour( textColour.charAt( x ), Colour.WHITE ) );
monitorBuffer.put( (byte) getColour( background.charAt( x ), Colour.BLACK ) ); monitorBuffer.put( (byte) getColour( background.charAt( x ), Colour.BLACK ) );
@ -216,9 +225,11 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
break; break;
} }
case VBO: { case VBO:
{
VertexBuffer vbo = monitor.buffer; VertexBuffer vbo = monitor.buffer;
if (redraw) { if( redraw )
{
Tessellator tessellator = Tessellator.getInstance(); Tessellator tessellator = Tessellator.getInstance();
BufferBuilder builder = tessellator.getBuffer(); BufferBuilder builder = tessellator.getBuffer();
builder.begin( FixedWidthFontRenderer.TYPE.getDrawMode(), FixedWidthFontRenderer.TYPE.getVertexFormat() ); builder.begin( FixedWidthFontRenderer.TYPE.getDrawMode(), FixedWidthFontRenderer.TYPE.getVertexFormat() );

View File

@ -6,11 +6,6 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import java.util.List;
import java.util.Random;
import javax.annotation.Nonnull;
import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.client.TransformedModel;
import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleSide;
@ -19,7 +14,6 @@ import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.DirectionUtil;
import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil; import dan200.computercraft.shared.util.HolidayUtil;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer; import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.render.TexturedRenderLayers; import net.minecraft.client.render.TexturedRenderLayers;
@ -40,7 +34,12 @@ import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle> { import javax.annotation.Nonnull;
import java.util.List;
import java.util.Random;
public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle>
{
private static final ModelIdentifier NORMAL_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_normal", "inventory" ); private static final ModelIdentifier NORMAL_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_normal", "inventory" );
private static final ModelIdentifier ADVANCED_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_advanced", "inventory" ); private static final ModelIdentifier ADVANCED_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_advanced", "inventory" );
private static final ModelIdentifier COLOUR_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_colour", "inventory" ); private static final ModelIdentifier COLOUR_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_colour", "inventory" );
@ -48,12 +47,15 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle> {
private final Random random = new Random( 0 ); private final Random random = new Random( 0 );
public TileEntityTurtleRenderer(BlockEntityRenderDispatcher renderDispatcher) { public TileEntityTurtleRenderer( BlockEntityRenderDispatcher renderDispatcher )
{
super( renderDispatcher ); super( renderDispatcher );
} }
public static ModelIdentifier getTurtleModel(ComputerFamily family, boolean coloured) { public static ModelIdentifier getTurtleModel( ComputerFamily family, boolean coloured )
switch (family) { {
switch( family )
{
case NORMAL: case NORMAL:
default: default:
return coloured ? COLOUR_TURTLE_MODEL : NORMAL_TURTLE_MODEL; return coloured ? COLOUR_TURTLE_MODEL : NORMAL_TURTLE_MODEL;
@ -62,25 +64,32 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle> {
} }
} }
public static ModelIdentifier getTurtleOverlayModel(Identifier overlay, boolean christmas) { public static ModelIdentifier getTurtleOverlayModel( Identifier overlay, boolean christmas )
if (overlay != null) { {
if( overlay != null )
{
return new ModelIdentifier( overlay, "inventory" ); return new ModelIdentifier( overlay, "inventory" );
} }
if (christmas) { if( christmas )
{
return ELF_OVERLAY_MODEL; return ELF_OVERLAY_MODEL;
} }
return null; return null;
} }
private static void renderQuads( @Nonnull MatrixStack transform, @Nonnull VertexConsumer buffer, int lightmapCoord, int overlayLight, private static void renderQuads( @Nonnull MatrixStack transform, @Nonnull VertexConsumer buffer, int lightmapCoord, int overlayLight,
List<BakedQuad> quads, int[] tints) { List<BakedQuad> quads, int[] tints )
{
MatrixStack.Entry matrix = transform.peek(); MatrixStack.Entry matrix = transform.peek();
for (BakedQuad bakedquad : quads) { for( BakedQuad bakedquad : quads )
{
int tint = -1; int tint = -1;
if (tints != null && bakedquad.hasColor()) { if( tints != null && bakedquad.hasColor() )
{
int idx = bakedquad.getColorIndex(); int idx = bakedquad.getColorIndex();
if (idx >= 0 && idx < tints.length) { if( idx >= 0 && idx < tints.length )
{
tint = tints[bakedquad.getColorIndex()]; tint = tints[bakedquad.getColorIndex()];
} }
} }
@ -112,13 +121,15 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle> {
@Override @Override
public void render( @Nonnull TileTurtle turtle, float partialTicks, @Nonnull MatrixStack transform, @Nonnull VertexConsumerProvider renderer, public void render( @Nonnull TileTurtle turtle, float partialTicks, @Nonnull MatrixStack transform, @Nonnull VertexConsumerProvider renderer,
int lightmapCoord, int overlayLight) { int lightmapCoord, int overlayLight )
{
// Render the label // Render the label
String label = turtle.createProxy() String label = turtle.createProxy()
.getLabel(); .getLabel();
HitResult hit = this.dispatcher.crosshairTarget; HitResult hit = this.dispatcher.crosshairTarget;
if( label != null && hit.getType() == HitResult.Type.BLOCK && turtle.getPos() if( label != null && hit.getType() == HitResult.Type.BLOCK && turtle.getPos()
.equals(((BlockHitResult) hit).getBlockPos())) { .equals( ((BlockHitResult) hit).getBlockPos() ) )
{
MinecraftClient mc = MinecraftClient.getInstance(); MinecraftClient mc = MinecraftClient.getInstance();
TextRenderer font = mc.textRenderer; TextRenderer font = mc.textRenderer;
@ -147,7 +158,8 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle> {
transform.translate( 0.5f, 0.5f, 0.5f ); transform.translate( 0.5f, 0.5f, 0.5f );
transform.multiply( Vector3f.POSITIVE_Y.getDegreesQuaternion( 180.0f - yaw ) ); transform.multiply( Vector3f.POSITIVE_Y.getDegreesQuaternion( 180.0f - yaw ) );
if (label != null && (label.equals("Dinnerbone") || label.equals("Grumm"))) { if( label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )) )
{
// Flip the model // Flip the model
transform.scale( 1.0f, -1.0f, 1.0f ); transform.scale( 1.0f, -1.0f, 1.0f );
} }
@ -163,7 +175,8 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle> {
// Render the overlay // Render the overlay
ModelIdentifier overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS ); ModelIdentifier overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS );
if (overlayModel != null) { if( overlayModel != null )
{
renderModel( transform, buffer, lightmapCoord, overlayLight, overlayModel, null ); renderModel( transform, buffer, lightmapCoord, overlayLight, overlayModel, null );
} }
@ -175,9 +188,11 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle> {
} }
public static void renderUpgrade( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, TileTurtle turtle, public static void renderUpgrade( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, TileTurtle turtle,
TurtleSide side, float f) { TurtleSide side, float f )
{
ITurtleUpgrade upgrade = turtle.getUpgrade( side ); ITurtleUpgrade upgrade = turtle.getUpgrade( side );
if (upgrade == null) { if( upgrade == null )
{
return; return;
} }
transform.push(); transform.push();
@ -196,7 +211,8 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle> {
} }
public static void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, public static void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight,
ModelIdentifier modelLocation, int[] tints) { ModelIdentifier modelLocation, int[] tints )
{
BakedModelManager modelManager = MinecraftClient.getInstance() BakedModelManager modelManager = MinecraftClient.getInstance()
.getItemRenderer() .getItemRenderer()
.getModels() .getModels()
@ -205,11 +221,13 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle> {
} }
public static void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model, public static void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model,
int[] tints) { int[] tints )
{
Random random = new Random(); Random random = new Random();
random.setSeed( 0 ); random.setSeed( 0 );
renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, null, random ), tints ); renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, null, random ), tints );
for (Direction facing : DirectionUtil.FACINGS) { for( Direction facing : DirectionUtil.FACINGS )
{
renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, facing, random ), tints ); renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, facing, random ), tints );
} }
} }

View File

@ -6,17 +6,10 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Pair;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.ModelBakeSettings; import net.minecraft.client.render.model.ModelBakeSettings;
import net.minecraft.client.render.model.ModelLoader; import net.minecraft.client.render.model.ModelLoader;
@ -25,20 +18,27 @@ import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.SpriteIdentifier; import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.fabricmc.api.EnvType; import javax.annotation.Nonnull;
import net.fabricmc.api.Environment; import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@Environment( EnvType.CLIENT ) @Environment( EnvType.CLIENT )
public final class TurtleModelLoader { public final class TurtleModelLoader
{
public static final TurtleModelLoader INSTANCE = new TurtleModelLoader(); public static final TurtleModelLoader INSTANCE = new TurtleModelLoader();
private static final Identifier NORMAL_TURTLE_MODEL = new Identifier( ComputerCraft.MOD_ID, "block/turtle_normal" ); private static final Identifier NORMAL_TURTLE_MODEL = new Identifier( ComputerCraft.MOD_ID, "block/turtle_normal" );
private static final Identifier ADVANCED_TURTLE_MODEL = new Identifier( ComputerCraft.MOD_ID, "block/turtle_advanced" ); private static final Identifier ADVANCED_TURTLE_MODEL = new Identifier( ComputerCraft.MOD_ID, "block/turtle_advanced" );
private static final Identifier COLOUR_TURTLE_MODEL = new Identifier( ComputerCraft.MOD_ID, "block/turtle_colour" ); private static final Identifier COLOUR_TURTLE_MODEL = new Identifier( ComputerCraft.MOD_ID, "block/turtle_colour" );
private TurtleModelLoader() { private TurtleModelLoader()
{
} }
public boolean accepts(@Nonnull Identifier name) { public boolean accepts( @Nonnull Identifier name )
{
return name.getNamespace() return name.getNamespace()
.equals( ComputerCraft.MOD_ID ) && (name.getPath() .equals( ComputerCraft.MOD_ID ) && (name.getPath()
.equals( "item/turtle_normal" ) || name.getPath() .equals( "item/turtle_normal" ) || name.getPath()
@ -46,10 +46,13 @@ public final class TurtleModelLoader {
} }
@Nonnull @Nonnull
public UnbakedModel loadModel(@Nonnull Identifier name) { public UnbakedModel loadModel( @Nonnull Identifier name )
{
if( name.getNamespace() if( name.getNamespace()
.equals(ComputerCraft.MOD_ID)) { .equals( ComputerCraft.MOD_ID ) )
switch (name.getPath()) { {
switch( name.getPath() )
{
case "item/turtle_normal": case "item/turtle_normal":
return new TurtleModel( NORMAL_TURTLE_MODEL ); return new TurtleModel( NORMAL_TURTLE_MODEL );
case "item/turtle_advanced": case "item/turtle_advanced":
@ -60,14 +63,16 @@ public final class TurtleModelLoader {
throw new IllegalStateException( "Loader does not accept " + name ); throw new IllegalStateException( "Loader does not accept " + name );
} }
private static final class TurtleModel implements UnbakedModel { private static final class TurtleModel implements UnbakedModel
{
private final Identifier family; private final Identifier family;
private TurtleModel( Identifier family ) {this.family = family;} private TurtleModel( Identifier family ) {this.family = family;}
@Override @Override
public Collection<SpriteIdentifier> getTextureDependencies( Function<Identifier, UnbakedModel> modelGetter, public Collection<SpriteIdentifier> getTextureDependencies( Function<Identifier, UnbakedModel> modelGetter,
Set<Pair<String, String>> missingTextureErrors) { Set<Pair<String, String>> missingTextureErrors )
{
return this.getModelDependencies() return this.getModelDependencies()
.stream() .stream()
.flatMap( x -> modelGetter.apply( x ) .flatMap( x -> modelGetter.apply( x )
@ -78,13 +83,15 @@ public final class TurtleModelLoader {
@Nonnull @Nonnull
@Override @Override
public Collection<Identifier> getModelDependencies() { public Collection<Identifier> getModelDependencies()
{
return Arrays.asList( this.family, COLOUR_TURTLE_MODEL ); return Arrays.asList( this.family, COLOUR_TURTLE_MODEL );
} }
@Override @Override
public BakedModel bake( @Nonnull ModelLoader loader, @Nonnull Function<SpriteIdentifier, Sprite> spriteGetter, @Nonnull ModelBakeSettings state, public BakedModel bake( @Nonnull ModelLoader loader, @Nonnull Function<SpriteIdentifier, Sprite> spriteGetter, @Nonnull ModelBakeSettings state,
Identifier modelId) { Identifier modelId )
{
return new TurtleSmartItemModel( loader.getOrLoadModel( this.family ) return new TurtleSmartItemModel( loader.getOrLoadModel( this.family )
.bake( loader, spriteGetter, state, modelId ), .bake( loader, spriteGetter, state, modelId ),
loader.getOrLoadModel( COLOUR_TURTLE_MODEL ) loader.getOrLoadModel( COLOUR_TURTLE_MODEL )

View File

@ -6,16 +6,9 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.annotation.Nonnull;
import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.client.TransformedModel;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedQuad; import net.minecraft.client.render.model.BakedQuad;
@ -24,11 +17,12 @@ import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.math.AffineTransformation; import net.minecraft.client.util.math.AffineTransformation;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.fabricmc.api.EnvType; import javax.annotation.Nonnull;
import net.fabricmc.api.Environment; import java.util.*;
@Environment( EnvType.CLIENT ) @Environment( EnvType.CLIENT )
public class TurtleMultiModel implements BakedModel { public class TurtleMultiModel implements BakedModel
{
private final BakedModel m_baseModel; private final BakedModel m_baseModel;
private final BakedModel m_overlayModel; private final BakedModel m_overlayModel;
private final AffineTransformation m_generalTransform; private final AffineTransformation m_generalTransform;
@ -38,7 +32,8 @@ public class TurtleMultiModel implements BakedModel {
private Map<Direction, List<BakedQuad>> m_faceQuads = new EnumMap<>( Direction.class ); private Map<Direction, List<BakedQuad>> m_faceQuads = new EnumMap<>( Direction.class );
public TurtleMultiModel( BakedModel baseModel, BakedModel overlayModel, AffineTransformation generalTransform, TransformedModel leftUpgradeModel, public TurtleMultiModel( BakedModel baseModel, BakedModel overlayModel, AffineTransformation generalTransform, TransformedModel leftUpgradeModel,
TransformedModel rightUpgradeModel) { TransformedModel rightUpgradeModel )
{
// Get the models // Get the models
this.m_baseModel = baseModel; this.m_baseModel = baseModel;
this.m_overlayModel = overlayModel; this.m_overlayModel = overlayModel;
@ -49,35 +44,45 @@ public class TurtleMultiModel implements BakedModel {
@Nonnull @Nonnull
@Override @Override
public List<BakedQuad> getQuads(BlockState state, Direction side, @Nonnull Random rand) { public List<BakedQuad> getQuads( BlockState state, Direction side, @Nonnull Random rand )
if (side != null) { {
if (!this.m_faceQuads.containsKey(side)) { if( side != null )
{
if( !this.m_faceQuads.containsKey( side ) )
{
this.m_faceQuads.put( side, this.buildQuads( state, side, rand ) ); this.m_faceQuads.put( side, this.buildQuads( state, side, rand ) );
} }
return this.m_faceQuads.get( side ); return this.m_faceQuads.get( side );
} else { }
if (this.m_generalQuads == null) { else
{
if( this.m_generalQuads == null )
{
this.m_generalQuads = this.buildQuads( state, side, rand ); this.m_generalQuads = this.buildQuads( state, side, rand );
} }
return this.m_generalQuads; return this.m_generalQuads;
} }
} }
private List<BakedQuad> buildQuads(BlockState state, Direction side, Random rand) { private List<BakedQuad> buildQuads( BlockState state, Direction side, Random rand )
{
ArrayList<BakedQuad> quads = new ArrayList<>(); ArrayList<BakedQuad> quads = new ArrayList<>();
ModelTransformer.transformQuadsTo( quads, this.m_baseModel.getQuads( state, side, rand ), this.m_generalTransform.getMatrix() ); ModelTransformer.transformQuadsTo( quads, this.m_baseModel.getQuads( state, side, rand ), this.m_generalTransform.getMatrix() );
if (this.m_overlayModel != null) { if( this.m_overlayModel != null )
{
ModelTransformer.transformQuadsTo( quads, this.m_overlayModel.getQuads( state, side, rand ), this.m_generalTransform.getMatrix() ); ModelTransformer.transformQuadsTo( quads, this.m_overlayModel.getQuads( state, side, rand ), this.m_generalTransform.getMatrix() );
} }
if (this.m_leftUpgradeModel != null) { if( this.m_leftUpgradeModel != null )
{
AffineTransformation upgradeTransform = this.m_generalTransform.multiply( this.m_leftUpgradeModel.getMatrix() ); AffineTransformation upgradeTransform = this.m_generalTransform.multiply( this.m_leftUpgradeModel.getMatrix() );
ModelTransformer.transformQuadsTo( quads, this.m_leftUpgradeModel.getModel() ModelTransformer.transformQuadsTo( quads, this.m_leftUpgradeModel.getModel()
.getQuads( state, side, rand ), .getQuads( state, side, rand ),
upgradeTransform.getMatrix() ); upgradeTransform.getMatrix() );
} }
if (this.m_rightUpgradeModel != null) { if( this.m_rightUpgradeModel != null )
{
AffineTransformation upgradeTransform = this.m_generalTransform.multiply( this.m_rightUpgradeModel.getMatrix() ); AffineTransformation upgradeTransform = this.m_generalTransform.multiply( this.m_rightUpgradeModel.getMatrix() );
ModelTransformer.transformQuadsTo( quads, this.m_rightUpgradeModel.getModel() ModelTransformer.transformQuadsTo( quads, this.m_rightUpgradeModel.getModel()
.getQuads( state, side, rand ), .getQuads( state, side, rand ),
@ -88,42 +93,49 @@ public class TurtleMultiModel implements BakedModel {
} }
@Override @Override
public boolean useAmbientOcclusion() { public boolean useAmbientOcclusion()
{
return this.m_baseModel.useAmbientOcclusion(); return this.m_baseModel.useAmbientOcclusion();
} }
@Override @Override
public boolean hasDepth() { public boolean hasDepth()
{
return this.m_baseModel.hasDepth(); return this.m_baseModel.hasDepth();
} }
@Override @Override
public boolean isSideLit() { public boolean isSideLit()
{
return this.m_baseModel.isSideLit(); return this.m_baseModel.isSideLit();
} }
@Override @Override
public boolean isBuiltin() { public boolean isBuiltin()
{
return this.m_baseModel.isBuiltin(); return this.m_baseModel.isBuiltin();
} }
@Nonnull @Nonnull
@Override @Override
@Deprecated @Deprecated
public Sprite getSprite() { public Sprite getSprite()
{
return this.m_baseModel.getSprite(); return this.m_baseModel.getSprite();
} }
@Nonnull @Nonnull
@Override @Override
@Deprecated @Deprecated
public net.minecraft.client.render.model.json.ModelTransformation getTransformation() { public net.minecraft.client.render.model.json.ModelTransformation getTransformation()
{
return this.m_baseModel.getTransformation(); return this.m_baseModel.getTransformation();
} }
@Nonnull @Nonnull
@Override @Override
public ModelOverrideList getOverrides() { public ModelOverrideList getOverrides()
{
return ModelOverrideList.EMPTY; return ModelOverrideList.EMPTY;
} }
} }

View File

@ -5,35 +5,38 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import javax.annotation.Nonnull;
import dan200.computercraft.shared.turtle.core.TurtlePlayer; import dan200.computercraft.shared.turtle.core.TurtlePlayer;
import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.EntityRenderDispatcher; import net.minecraft.client.render.entity.EntityRenderDispatcher;
import net.minecraft.client.render.entity.EntityRenderer; import net.minecraft.client.render.entity.EntityRenderer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry; import javax.annotation.Nonnull;
public class TurtlePlayerRenderer extends EntityRenderer<TurtlePlayer> { public class TurtlePlayerRenderer extends EntityRenderer<TurtlePlayer>
public TurtlePlayerRenderer(EntityRenderDispatcher renderManager) { {
public TurtlePlayerRenderer( EntityRenderDispatcher renderManager )
{
super( renderManager ); super( renderManager );
} }
public TurtlePlayerRenderer(EntityRenderDispatcher entityRenderDispatcher, EntityRendererRegistry.Context context) { public TurtlePlayerRenderer( EntityRenderDispatcher entityRenderDispatcher, EntityRendererRegistry.Context context )
{
super( entityRenderDispatcher ); super( entityRenderDispatcher );
} }
@Override @Override
public void render( @Nonnull TurtlePlayer entityIn, float entityYaw, float partialTicks, @Nonnull MatrixStack transform, public void render( @Nonnull TurtlePlayer entityIn, float entityYaw, float partialTicks, @Nonnull MatrixStack transform,
@Nonnull VertexConsumerProvider buffer, int packedLightIn) { @Nonnull VertexConsumerProvider buffer, int packedLightIn )
{
} }
@Nonnull @Nonnull
@Override @Override
public Identifier getTexture(@Nonnull TurtlePlayer entity) { public Identifier getTexture( @Nonnull TurtlePlayer entity )
{
return ComputerBorderRenderer.BACKGROUND_NORMAL; return ComputerBorderRenderer.BACKGROUND_NORMAL;
} }
} }

View File

@ -6,23 +6,15 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.client.TransformedModel;
import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.turtle.items.ItemTurtle; import dan200.computercraft.shared.turtle.items.ItemTurtle;
import dan200.computercraft.shared.turtle.upgrades.TurtleTool;
import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil; import dan200.computercraft.shared.util.HolidayUtil;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedModel;
@ -40,14 +32,20 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.fabricmc.api.EnvType; import javax.annotation.Nonnull;
import net.fabricmc.api.Environment; import javax.annotation.Nullable;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
@Environment( EnvType.CLIENT ) @Environment( EnvType.CLIENT )
public class TurtleSmartItemModel implements BakedModel { public class TurtleSmartItemModel implements BakedModel
{
private static final AffineTransformation identity, flip; private static final AffineTransformation identity, flip;
static { static
{
MatrixStack stack = new MatrixStack(); MatrixStack stack = new MatrixStack();
stack.scale( 0, -1, 0 ); stack.scale( 0, -1, 0 );
stack.translate( 0, 0, 1 ); stack.translate( 0, 0, 1 );
@ -61,16 +59,20 @@ public class TurtleSmartItemModel implements BakedModel {
private final BakedModel colourModel; private final BakedModel colourModel;
private final HashMap<TurtleModelCombination, BakedModel> m_cachedModels = new HashMap<>(); private final HashMap<TurtleModelCombination, BakedModel> m_cachedModels = new HashMap<>();
private final ModelOverrideList m_overrides; private final ModelOverrideList m_overrides;
public TurtleSmartItemModel(BakedModel familyModel, BakedModel colourModel) {
public TurtleSmartItemModel( BakedModel familyModel, BakedModel colourModel )
{
this.familyModel = familyModel; this.familyModel = familyModel;
this.colourModel = colourModel; this.colourModel = colourModel;
// this actually works I think, trust me // this actually works I think, trust me
this.m_overrides = new ModelOverrideList(null, null, null, Collections.emptyList()) { this.m_overrides = new ModelOverrideList( null, null, null, Collections.emptyList() )
{
@Nonnull @Nonnull
@Override @Override
public BakedModel apply( @Nonnull BakedModel originalModel, @Nonnull ItemStack stack, @Nullable ClientWorld world, public BakedModel apply( @Nonnull BakedModel originalModel, @Nonnull ItemStack stack, @Nullable ClientWorld world,
@Nullable LivingEntity entity) { @Nullable LivingEntity entity )
{
ItemTurtle turtle = (ItemTurtle) stack.getItem(); ItemTurtle turtle = (ItemTurtle) stack.getItem();
int colour = turtle.getColour( stack ); int colour = turtle.getColour( stack );
ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.LEFT ); ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.LEFT );
@ -84,7 +86,8 @@ public class TurtleSmartItemModel implements BakedModel {
TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip ); TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip );
BakedModel model = TurtleSmartItemModel.this.m_cachedModels.get( combo ); BakedModel model = TurtleSmartItemModel.this.m_cachedModels.get( combo );
if (model == null) { if( model == null )
{
TurtleSmartItemModel.this.m_cachedModels.put( combo, model = TurtleSmartItemModel.this.buildModel( combo ) ); TurtleSmartItemModel.this.m_cachedModels.put( combo, model = TurtleSmartItemModel.this.buildModel( combo ) );
} }
return model; return model;
@ -92,7 +95,8 @@ public class TurtleSmartItemModel implements BakedModel {
}; };
} }
private BakedModel buildModel(TurtleModelCombination combo) { private BakedModel buildModel( TurtleModelCombination combo )
{
MinecraftClient mc = MinecraftClient.getInstance(); MinecraftClient mc = MinecraftClient.getInstance();
BakedModelManager modelManager = mc.getItemRenderer() BakedModelManager modelManager = mc.getItemRenderer()
.getModels() .getModels()
@ -110,51 +114,60 @@ public class TurtleSmartItemModel implements BakedModel {
@Nonnull @Nonnull
@Override @Override
@Deprecated @Deprecated
public List<BakedQuad> getQuads(BlockState state, Direction facing, @Nonnull Random rand) { public List<BakedQuad> getQuads( BlockState state, Direction facing, @Nonnull Random rand )
{
return this.familyModel.getQuads( state, facing, rand ); return this.familyModel.getQuads( state, facing, rand );
} }
@Override @Override
public boolean useAmbientOcclusion() { public boolean useAmbientOcclusion()
{
return this.familyModel.useAmbientOcclusion(); return this.familyModel.useAmbientOcclusion();
} }
@Override @Override
public boolean hasDepth() { public boolean hasDepth()
{
return this.familyModel.hasDepth(); return this.familyModel.hasDepth();
} }
@Override @Override
public boolean isSideLit() { public boolean isSideLit()
{
return this.familyModel.isSideLit(); return this.familyModel.isSideLit();
} }
@Override @Override
public boolean isBuiltin() { public boolean isBuiltin()
{
return this.familyModel.isBuiltin(); return this.familyModel.isBuiltin();
} }
@Nonnull @Nonnull
@Override @Override
@Deprecated @Deprecated
public Sprite getSprite() { public Sprite getSprite()
{
return this.familyModel.getSprite(); return this.familyModel.getSprite();
} }
@Nonnull @Nonnull
@Override @Override
@Deprecated @Deprecated
public ModelTransformation getTransformation() { public ModelTransformation getTransformation()
{
return this.familyModel.getTransformation(); return this.familyModel.getTransformation();
} }
@Nonnull @Nonnull
@Override @Override
public ModelOverrideList getOverrides() { public ModelOverrideList getOverrides()
{
return this.m_overrides; return this.m_overrides;
} }
private static class TurtleModelCombination { private static class TurtleModelCombination
{
final boolean m_colour; final boolean m_colour;
final ITurtleUpgrade m_leftUpgrade; final ITurtleUpgrade m_leftUpgrade;
final ITurtleUpgrade m_rightUpgrade; final ITurtleUpgrade m_rightUpgrade;
@ -163,7 +176,8 @@ public class TurtleSmartItemModel implements BakedModel {
final boolean m_flip; final boolean m_flip;
TurtleModelCombination( boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, Identifier overlay, boolean christmas, TurtleModelCombination( boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, Identifier overlay, boolean christmas,
boolean flip) { boolean flip )
{
this.m_colour = colour; this.m_colour = colour;
this.m_leftUpgrade = leftUpgrade; this.m_leftUpgrade = leftUpgrade;
this.m_rightUpgrade = rightUpgrade; this.m_rightUpgrade = rightUpgrade;
@ -173,7 +187,8 @@ public class TurtleSmartItemModel implements BakedModel {
} }
@Override @Override
public int hashCode() { public int hashCode()
{
final int prime = 31; final int prime = 31;
int result = 0; int result = 0;
result = prime * result + (this.m_colour ? 1 : 0); result = prime * result + (this.m_colour ? 1 : 0);
@ -186,11 +201,14 @@ public class TurtleSmartItemModel implements BakedModel {
} }
@Override @Override
public boolean equals(Object other) { public boolean equals( Object other )
if (other == this) { {
if( other == this )
{
return true; return true;
} }
if (!(other instanceof TurtleModelCombination)) { if( !(other instanceof TurtleModelCombination) )
{
return false; return false;
} }

View File

@ -6,27 +6,31 @@
package dan200.computercraft.core.apis; package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import javax.annotation.Nonnull;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Objects; import java.util.Objects;
import javax.annotation.Nonnull; public final class ApiFactories
{
import dan200.computercraft.api.lua.ILuaAPIFactory;
public final class ApiFactories {
private static final Collection<ILuaAPIFactory> factories = new LinkedHashSet<>(); private static final Collection<ILuaAPIFactory> factories = new LinkedHashSet<>();
private static final Collection<ILuaAPIFactory> factoriesView = Collections.unmodifiableCollection( factories ); private static final Collection<ILuaAPIFactory> factoriesView = Collections.unmodifiableCollection( factories );
private ApiFactories() {
private ApiFactories()
{
} }
public static synchronized void register(@Nonnull ILuaAPIFactory factory) { public static synchronized void register( @Nonnull ILuaAPIFactory factory )
{
Objects.requireNonNull( factory, "provider cannot be null" ); Objects.requireNonNull( factory, "provider cannot be null" );
factories.add( factory ); factories.add( factory );
} }
public static Iterable<ILuaAPIFactory> getAll() { public static Iterable<ILuaAPIFactory> getAll()
{
return factoriesView; return factoriesView;
} }
} }

View File

@ -6,12 +6,6 @@
package dan200.computercraft.core.apis; package dan200.computercraft.core.apis;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import javax.annotation.Nonnull;
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.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IComputerAccess;
@ -19,24 +13,34 @@ import dan200.computercraft.api.peripheral.IWorkMonitor;
import dan200.computercraft.core.filesystem.FileSystem; import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.filesystem.FileSystemException; import dan200.computercraft.core.filesystem.FileSystemException;
public abstract class ComputerAccess implements IComputerAccess { import javax.annotation.Nonnull;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
public abstract class ComputerAccess implements IComputerAccess
{
private final IAPIEnvironment m_environment; private final IAPIEnvironment m_environment;
private final Set<String> m_mounts = new HashSet<>(); private final Set<String> m_mounts = new HashSet<>();
protected ComputerAccess(IAPIEnvironment environment) { protected ComputerAccess( IAPIEnvironment environment )
{
this.m_environment = environment; this.m_environment = environment;
} }
public void unmountAll() { public void unmountAll()
{
FileSystem fileSystem = this.m_environment.getFileSystem(); FileSystem fileSystem = this.m_environment.getFileSystem();
for (String mount : this.m_mounts) { for( String mount : this.m_mounts )
{
fileSystem.unmount( mount ); fileSystem.unmount( mount );
} }
this.m_mounts.clear(); this.m_mounts.clear();
} }
@Override @Override
public synchronized String mount(@Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName) { public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName )
{
Objects.requireNonNull( desiredLoc, "desiredLocation cannot be null" ); Objects.requireNonNull( desiredLoc, "desiredLocation cannot be null" );
Objects.requireNonNull( mount, "mount cannot be null" ); Objects.requireNonNull( mount, "mount cannot be null" );
Objects.requireNonNull( driveName, "driveName cannot be null" ); Objects.requireNonNull( driveName, "driveName cannot be null" );
@ -44,28 +48,36 @@ public abstract class ComputerAccess implements IComputerAccess {
// Mount the location // Mount the location
String location; String location;
FileSystem fileSystem = this.m_environment.getFileSystem(); FileSystem fileSystem = this.m_environment.getFileSystem();
if (fileSystem == null) { if( fileSystem == null )
{
throw new IllegalStateException( "File system has not been created" ); throw new IllegalStateException( "File system has not been created" );
} }
synchronized (fileSystem) { synchronized( fileSystem )
{
location = this.findFreeLocation( desiredLoc ); location = this.findFreeLocation( desiredLoc );
if (location != null) { if( location != null )
try { {
try
{
fileSystem.mount( driveName, location, mount ); fileSystem.mount( driveName, location, mount );
} catch (FileSystemException ignored) { }
catch( FileSystemException ignored )
{
} }
} }
} }
if (location != null) { if( location != null )
{
this.m_mounts.add( location ); this.m_mounts.add( location );
} }
return location; return location;
} }
@Override @Override
public synchronized String mountWritable(@Nonnull String desiredLoc, @Nonnull IWritableMount mount, @Nonnull String driveName) { public synchronized String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount, @Nonnull String driveName )
{
Objects.requireNonNull( desiredLoc, "desiredLocation cannot be null" ); Objects.requireNonNull( desiredLoc, "desiredLocation cannot be null" );
Objects.requireNonNull( mount, "mount cannot be null" ); Objects.requireNonNull( mount, "mount cannot be null" );
Objects.requireNonNull( driveName, "driveName cannot be null" ); Objects.requireNonNull( driveName, "driveName cannot be null" );
@ -73,32 +85,42 @@ public abstract class ComputerAccess implements IComputerAccess {
// Mount the location // Mount the location
String location; String location;
FileSystem fileSystem = this.m_environment.getFileSystem(); FileSystem fileSystem = this.m_environment.getFileSystem();
if (fileSystem == null) { if( fileSystem == null )
{
throw new IllegalStateException( "File system has not been created" ); throw new IllegalStateException( "File system has not been created" );
} }
synchronized (fileSystem) { synchronized( fileSystem )
{
location = this.findFreeLocation( desiredLoc ); location = this.findFreeLocation( desiredLoc );
if (location != null) { if( location != null )
try { {
try
{
fileSystem.mountWritable( driveName, location, mount ); fileSystem.mountWritable( driveName, location, mount );
} catch (FileSystemException ignored) { }
catch( FileSystemException ignored )
{
} }
} }
} }
if (location != null) { if( location != null )
{
this.m_mounts.add( location ); this.m_mounts.add( location );
} }
return location; return location;
} }
@Override @Override
public void unmount(String location) { public void unmount( String location )
if (location == null) { {
if( location == null )
{
return; return;
} }
if (!this.m_mounts.contains(location)) { if( !this.m_mounts.contains( location ) )
{
throw new IllegalStateException( "You didn't mount this location" ); throw new IllegalStateException( "You didn't mount this location" );
} }
@ -108,32 +130,40 @@ public abstract class ComputerAccess implements IComputerAccess {
} }
@Override @Override
public int getID() { public int getID()
{
return this.m_environment.getComputerID(); return this.m_environment.getComputerID();
} }
@Override @Override
public void queueEvent(@Nonnull String event, Object... arguments) { public void queueEvent( @Nonnull String event, Object... arguments )
{
Objects.requireNonNull( event, "event cannot be null" ); Objects.requireNonNull( event, "event cannot be null" );
this.m_environment.queueEvent( event, arguments ); this.m_environment.queueEvent( event, arguments );
} }
@Nonnull @Nonnull
@Override @Override
public IWorkMonitor getMainThreadMonitor() { public IWorkMonitor getMainThreadMonitor()
{
return this.m_environment.getMainThreadMonitor(); return this.m_environment.getMainThreadMonitor();
} }
private String findFreeLocation(String desiredLoc) { private String findFreeLocation( String desiredLoc )
try { {
try
{
FileSystem fileSystem = this.m_environment.getFileSystem(); FileSystem fileSystem = this.m_environment.getFileSystem();
if (!fileSystem.exists(desiredLoc)) { if( !fileSystem.exists( desiredLoc ) )
{
return desiredLoc; return desiredLoc;
} }
// We used to check foo2, foo3, foo4, etc here but the disk drive does this itself now // We used to check foo2, foo3, foo4, etc here but the disk drive does this itself now
return null; return null;
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
return null; return null;
} }
} }

View File

@ -6,18 +6,6 @@
package dan200.computercraft.core.apis; package dan200.computercraft.core.apis;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.HashMap;
import java.util.Map;
import java.util.OptionalLong;
import java.util.function.Function;
import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.IArguments;
import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
@ -31,31 +19,47 @@ import dan200.computercraft.core.filesystem.FileSystemException;
import dan200.computercraft.core.filesystem.FileSystemWrapper; import dan200.computercraft.core.filesystem.FileSystemWrapper;
import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.core.tracking.TrackingField;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.HashMap;
import java.util.Map;
import java.util.OptionalLong;
import java.util.function.Function;
/** /**
* The FS API allows you to manipulate files and the filesystem. * The FS API allows you to manipulate files and the filesystem.
* *
* @cc.module fs * @cc.module fs
*/ */
public class FSAPI implements ILuaAPI { public class FSAPI implements ILuaAPI
{
private final IAPIEnvironment environment; private final IAPIEnvironment environment;
private FileSystem fileSystem = null; private FileSystem fileSystem = null;
public FSAPI(IAPIEnvironment env) { public FSAPI( IAPIEnvironment env )
{
this.environment = env; this.environment = env;
} }
@Override @Override
public String[] getNames() { public String[] getNames()
{
return new String[] { "fs" }; return new String[] { "fs" };
} }
@Override @Override
public void startup() { public void startup()
{
this.fileSystem = this.environment.getFileSystem(); this.fileSystem = this.environment.getFileSystem();
} }
@Override @Override
public void shutdown() { public void shutdown()
{
this.fileSystem = null; this.fileSystem = null;
} }
@ -67,11 +71,15 @@ public class FSAPI implements ILuaAPI {
* @throws LuaException If the path doesn't exist. * @throws LuaException If the path doesn't exist.
*/ */
@LuaFunction @LuaFunction
public final String[] list(String path) throws LuaException { public final String[] list( String path ) throws LuaException
{
this.environment.addTrackingChange( TrackingField.FS_OPS ); this.environment.addTrackingChange( TrackingField.FS_OPS );
try { try
{
return this.fileSystem.list( path ); return this.fileSystem.list( path );
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
@ -82,16 +90,18 @@ public class FSAPI implements ILuaAPI {
* *
* @param arguments The paths to combine. * @param arguments The paths to combine.
* @return The new path, with separators added between parts as needed. * @return The new path, with separators added between parts as needed.
* @throws LuaException On argument errors.
* @cc.tparam string path The first part of the path. For example, a parent directory path. * @cc.tparam string path The first part of the path. For example, a parent directory path.
* @cc.tparam string ... Additional parts of the path to combine. * @cc.tparam string ... Additional parts of the path to combine.
* @throws LuaException On argument errors.
*/ */
@LuaFunction @LuaFunction
public final String combine( IArguments arguments ) throws LuaException { public final String combine( IArguments arguments ) throws LuaException
{
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
result.append( FileSystem.sanitizePath( arguments.getString( 0 ), true ) ); result.append( FileSystem.sanitizePath( arguments.getString( 0 ), true ) );
for (int i = 1, n = arguments.count(); i < n; i++) { for( int i = 1, n = arguments.count(); i < n; i++ )
{
String part = FileSystem.sanitizePath( arguments.getString( i ), true ); String part = FileSystem.sanitizePath( arguments.getString( i ), true );
if( result.length() != 0 && !part.isEmpty() ) result.append( '/' ); if( result.length() != 0 && !part.isEmpty() ) result.append( '/' );
result.append( part ); result.append( part );
@ -107,7 +117,8 @@ public class FSAPI implements ILuaAPI {
* @return The final part of the path (the file name). * @return The final part of the path (the file name).
*/ */
@LuaFunction @LuaFunction
public final String getName(String path) { public final String getName( String path )
{
return FileSystem.getName( path ); return FileSystem.getName( path );
} }
@ -118,7 +129,8 @@ public class FSAPI implements ILuaAPI {
* @return The path with the final part removed (the parent directory). * @return The path with the final part removed (the parent directory).
*/ */
@LuaFunction @LuaFunction
public final String getDir(String path) { public final String getDir( String path )
{
return FileSystem.getDirectory( path ); return FileSystem.getDirectory( path );
} }
@ -130,10 +142,14 @@ public class FSAPI implements ILuaAPI {
* @throws LuaException If the path doesn't exist. * @throws LuaException If the path doesn't exist.
*/ */
@LuaFunction @LuaFunction
public final long getSize(String path) throws LuaException { public final long getSize( String path ) throws LuaException
try { {
try
{
return this.fileSystem.getSize( path ); return this.fileSystem.getSize( path );
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
@ -145,10 +161,14 @@ public class FSAPI implements ILuaAPI {
* @return Whether the path exists. * @return Whether the path exists.
*/ */
@LuaFunction @LuaFunction
public final boolean exists(String path) { public final boolean exists( String path )
try { {
try
{
return this.fileSystem.exists( path ); return this.fileSystem.exists( path );
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
return false; return false;
} }
} }
@ -160,10 +180,14 @@ public class FSAPI implements ILuaAPI {
* @return Whether the path is a directory. * @return Whether the path is a directory.
*/ */
@LuaFunction @LuaFunction
public final boolean isDir(String path) { public final boolean isDir( String path )
try { {
try
{
return this.fileSystem.isDir( path ); return this.fileSystem.isDir( path );
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
return false; return false;
} }
} }
@ -175,10 +199,14 @@ public class FSAPI implements ILuaAPI {
* @return Whether the path cannot be written to. * @return Whether the path cannot be written to.
*/ */
@LuaFunction @LuaFunction
public final boolean isReadOnly(String path) { public final boolean isReadOnly( String path )
try { {
try
{
return this.fileSystem.isReadOnly( path ); return this.fileSystem.isReadOnly( path );
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
return false; return false;
} }
} }
@ -190,11 +218,15 @@ public class FSAPI implements ILuaAPI {
* @throws LuaException If the directory couldn't be created. * @throws LuaException If the directory couldn't be created.
*/ */
@LuaFunction @LuaFunction
public final void makeDir(String path) throws LuaException { public final void makeDir( String path ) throws LuaException
try { {
try
{
this.environment.addTrackingChange( TrackingField.FS_OPS ); this.environment.addTrackingChange( TrackingField.FS_OPS );
this.fileSystem.makeDir( path ); this.fileSystem.makeDir( path );
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
@ -209,11 +241,15 @@ public class FSAPI implements ILuaAPI {
* @throws LuaException If the file or directory couldn't be moved. * @throws LuaException If the file or directory couldn't be moved.
*/ */
@LuaFunction @LuaFunction
public final void move(String path, String dest) throws LuaException { public final void move( String path, String dest ) throws LuaException
try { {
try
{
this.environment.addTrackingChange( TrackingField.FS_OPS ); this.environment.addTrackingChange( TrackingField.FS_OPS );
this.fileSystem.move( path, dest ); this.fileSystem.move( path, dest );
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
@ -228,11 +264,15 @@ public class FSAPI implements ILuaAPI {
* @throws LuaException If the file or directory couldn't be copied. * @throws LuaException If the file or directory couldn't be copied.
*/ */
@LuaFunction @LuaFunction
public final void copy(String path, String dest) throws LuaException { public final void copy( String path, String dest ) throws LuaException
try { {
try
{
this.environment.addTrackingChange( TrackingField.FS_OPS ); this.environment.addTrackingChange( TrackingField.FS_OPS );
this.fileSystem.copy( path, dest ); this.fileSystem.copy( path, dest );
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
@ -246,11 +286,15 @@ public class FSAPI implements ILuaAPI {
* @throws LuaException If the file or directory couldn't be deleted. * @throws LuaException If the file or directory couldn't be deleted.
*/ */
@LuaFunction @LuaFunction
public final void delete(String path) throws LuaException { public final void delete( String path ) throws LuaException
try { {
try
{
this.environment.addTrackingChange( TrackingField.FS_OPS ); this.environment.addTrackingChange( TrackingField.FS_OPS );
this.fileSystem.delete( path ); this.fileSystem.delete( path );
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
@ -272,36 +316,45 @@ public class FSAPI implements ILuaAPI {
* @cc.treturn string|nil A message explaining why the file cannot be opened. * @cc.treturn string|nil A message explaining why the file cannot be opened.
*/ */
@LuaFunction @LuaFunction
public final Object[] open(String path, String mode) throws LuaException { public final Object[] open( String path, String mode ) throws LuaException
{
this.environment.addTrackingChange( TrackingField.FS_OPS ); this.environment.addTrackingChange( TrackingField.FS_OPS );
try { try
switch (mode) { {
case "r": { switch( mode )
{
case "r":
{
// Open the file for reading, then create a wrapper around the reader // Open the file for reading, then create a wrapper around the reader
FileSystemWrapper<BufferedReader> reader = this.fileSystem.openForRead( path, EncodedReadableHandle::openUtf8 ); FileSystemWrapper<BufferedReader> reader = this.fileSystem.openForRead( path, EncodedReadableHandle::openUtf8 );
return new Object[] { new EncodedReadableHandle( reader.get(), reader ) }; return new Object[] { new EncodedReadableHandle( reader.get(), reader ) };
} }
case "w": { case "w":
{
// Open the file for writing, then create a wrapper around the writer // Open the file for writing, then create a wrapper around the writer
FileSystemWrapper<BufferedWriter> writer = this.fileSystem.openForWrite( path, false, EncodedWritableHandle::openUtf8 ); FileSystemWrapper<BufferedWriter> writer = this.fileSystem.openForWrite( path, false, EncodedWritableHandle::openUtf8 );
return new Object[] { new EncodedWritableHandle( writer.get(), writer ) }; return new Object[] { new EncodedWritableHandle( writer.get(), writer ) };
} }
case "a": { case "a":
{
// Open the file for appending, then create a wrapper around the writer // Open the file for appending, then create a wrapper around the writer
FileSystemWrapper<BufferedWriter> writer = this.fileSystem.openForWrite( path, true, EncodedWritableHandle::openUtf8 ); FileSystemWrapper<BufferedWriter> writer = this.fileSystem.openForWrite( path, true, EncodedWritableHandle::openUtf8 );
return new Object[] { new EncodedWritableHandle( writer.get(), writer ) }; return new Object[] { new EncodedWritableHandle( writer.get(), writer ) };
} }
case "rb": { case "rb":
{
// Open the file for binary reading, then create a wrapper around the reader // Open the file for binary reading, then create a wrapper around the reader
FileSystemWrapper<ReadableByteChannel> reader = this.fileSystem.openForRead( path, Function.identity() ); FileSystemWrapper<ReadableByteChannel> reader = this.fileSystem.openForRead( path, Function.identity() );
return new Object[] { BinaryReadableHandle.of( reader.get(), reader ) }; return new Object[] { BinaryReadableHandle.of( reader.get(), reader ) };
} }
case "wb": { case "wb":
{
// Open the file for binary writing, then create a wrapper around the writer // Open the file for binary writing, then create a wrapper around the writer
FileSystemWrapper<WritableByteChannel> writer = this.fileSystem.openForWrite( path, false, Function.identity() ); FileSystemWrapper<WritableByteChannel> writer = this.fileSystem.openForWrite( path, false, Function.identity() );
return new Object[] { BinaryWritableHandle.of( writer.get(), writer ) }; return new Object[] { BinaryWritableHandle.of( writer.get(), writer ) };
} }
case "ab": { case "ab":
{
// Open the file for binary appending, then create a wrapper around the reader // Open the file for binary appending, then create a wrapper around the reader
FileSystemWrapper<WritableByteChannel> writer = this.fileSystem.openForWrite( path, true, Function.identity() ); FileSystemWrapper<WritableByteChannel> writer = this.fileSystem.openForWrite( path, true, Function.identity() );
return new Object[] { BinaryWritableHandle.of( writer.get(), writer ) }; return new Object[] { BinaryWritableHandle.of( writer.get(), writer ) };
@ -309,7 +362,9 @@ public class FSAPI implements ILuaAPI {
default: default:
throw new LuaException( "Unsupported mode" ); throw new LuaException( "Unsupported mode" );
} }
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
return new Object[] { return new Object[] {
null, null,
e.getMessage() e.getMessage()
@ -326,10 +381,14 @@ public class FSAPI implements ILuaAPI {
* @cc.treturn string The name of the drive that the file is on; e.g. {@code hdd} for local files, or {@code rom} for ROM files. * @cc.treturn string The name of the drive that the file is on; e.g. {@code hdd} for local files, or {@code rom} for ROM files.
*/ */
@LuaFunction @LuaFunction
public final Object[] getDrive(String path) throws LuaException { public final Object[] getDrive( String path ) throws LuaException
try { {
try
{
return this.fileSystem.exists( path ) ? new Object[] { this.fileSystem.getMountLabel( path ) } : null; return this.fileSystem.exists( path ) ? new Object[] { this.fileSystem.getMountLabel( path ) } : null;
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
@ -343,11 +402,15 @@ public class FSAPI implements ILuaAPI {
* @cc.treturn number|"unlimited" The amount of free space available, in bytes, or "unlimited". * @cc.treturn number|"unlimited" The amount of free space available, in bytes, or "unlimited".
*/ */
@LuaFunction @LuaFunction
public final Object getFreeSpace(String path) throws LuaException { public final Object getFreeSpace( String path ) throws LuaException
try { {
try
{
long freeSpace = this.fileSystem.getFreeSpace( path ); long freeSpace = this.fileSystem.getFreeSpace( path );
return freeSpace >= 0 ? freeSpace : "unlimited"; return freeSpace >= 0 ? freeSpace : "unlimited";
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
@ -363,11 +426,15 @@ public class FSAPI implements ILuaAPI {
* @throws LuaException If the path doesn't exist. * @throws LuaException If the path doesn't exist.
*/ */
@LuaFunction @LuaFunction
public final String[] find(String path) throws LuaException { public final String[] find( String path ) throws LuaException
try { {
try
{
this.environment.addTrackingChange( TrackingField.FS_OPS ); this.environment.addTrackingChange( TrackingField.FS_OPS );
return this.fileSystem.find( path ); return this.fileSystem.find( path );
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
@ -384,11 +451,15 @@ public class FSAPI implements ILuaAPI {
* @cc.treturn number|nil This drive's capacity. This will be nil for "read-only" drives, such as the ROM or treasure disks. * @cc.treturn number|nil This drive's capacity. This will be nil for "read-only" drives, such as the ROM or treasure disks.
*/ */
@LuaFunction @LuaFunction
public final Object getCapacity(String path) throws LuaException { public final Object getCapacity( String path ) throws LuaException
try { {
try
{
OptionalLong capacity = this.fileSystem.getCapacity( path ); OptionalLong capacity = this.fileSystem.getCapacity( path );
return capacity.isPresent() ? capacity.getAsLong() : null; return capacity.isPresent() ? capacity.getAsLong() : null;
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
@ -410,8 +481,10 @@ public class FSAPI implements ILuaAPI {
* @see #isDir If you only care whether a path is a directory or not. * @see #isDir If you only care whether a path is a directory or not.
*/ */
@LuaFunction @LuaFunction
public final Map<String, Object> attributes(String path) throws LuaException { public final Map<String, Object> attributes( String path ) throws LuaException
try { {
try
{
BasicFileAttributes attributes = this.fileSystem.getAttributes( path ); BasicFileAttributes attributes = this.fileSystem.getAttributes( path );
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
result.put( "modification", getFileTime( attributes.lastModifiedTime() ) ); result.put( "modification", getFileTime( attributes.lastModifiedTime() ) );
@ -421,12 +494,15 @@ public class FSAPI implements ILuaAPI {
result.put( "isDir", attributes.isDirectory() ); result.put( "isDir", attributes.isDirectory() );
result.put( "isReadOnly", fileSystem.isReadOnly( path ) ); result.put( "isReadOnly", fileSystem.isReadOnly( path ) );
return result; return result;
} catch (FileSystemException e) { }
catch( FileSystemException e )
{
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
private static long getFileTime(FileTime time) { private static long getFileTime( FileTime time )
{
return time == null ? 0 : time.toMillis(); return time == null ? 0 : time.toMillis();
} }
} }

View File

@ -5,26 +5,30 @@
*/ */
package dan200.computercraft.core.apis; package dan200.computercraft.core.apis;
import javax.annotation.Nullable;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import javax.annotation.Nullable;
/** /**
* A Lua exception which does not contain its stack trace. * A Lua exception which does not contain its stack trace.
*/ */
public class FastLuaException extends LuaException { public class FastLuaException extends LuaException
{
private static final long serialVersionUID = 5957864899303561143L; private static final long serialVersionUID = 5957864899303561143L;
public FastLuaException(@Nullable String message) { public FastLuaException( @Nullable String message )
{
super( message ); super( message );
} }
public FastLuaException(@Nullable String message, int level) { public FastLuaException( @Nullable String message, int level )
{
super( message, level ); super( message, level );
} }
@Override @Override
public synchronized Throwable fillInStackTrace() { public synchronized Throwable fillInStackTrace()
{
return this; return this;
} }
} }

View File

@ -6,9 +6,6 @@
package dan200.computercraft.core.apis; package dan200.computercraft.core.apis;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IWorkMonitor; import dan200.computercraft.api.peripheral.IWorkMonitor;
import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.ComputerSide;
@ -17,7 +14,11 @@ import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.core.tracking.TrackingField;
public interface IAPIEnvironment { import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public interface IAPIEnvironment
{
String TIMER_EVENT = "timer"; String TIMER_EVENT = "timer";
int getComputerID(); int getComputerID();
@ -64,14 +65,16 @@ public interface IAPIEnvironment {
void cancelTimer( int id ); void cancelTimer( int id );
default void addTrackingChange(@Nonnull TrackingField field) { default void addTrackingChange( @Nonnull TrackingField field )
{
this.addTrackingChange( field, 1 ); this.addTrackingChange( field, 1 );
} }
void addTrackingChange( @Nonnull TrackingField field, long change ); void addTrackingChange( @Nonnull TrackingField field, long change );
@FunctionalInterface @FunctionalInterface
interface IPeripheralChangeListener { interface IPeripheralChangeListener
{
void onPeripheralChanged( ComputerSide side, @Nullable IPeripheral newPeripheral ); void onPeripheralChanged( ComputerSide side, @Nullable IPeripheral newPeripheral );
} }
} }

View File

@ -6,37 +6,35 @@
package dan200.computercraft.core.apis; package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.LuaException;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle; import java.time.format.TextStyle;
import java.time.temporal.ChronoField; import java.time.temporal.*;
import java.time.temporal.IsoFields;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.time.temporal.ValueRange;
import java.time.temporal.WeekFields;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.LongUnaryOperator; import java.util.function.LongUnaryOperator;
import dan200.computercraft.api.lua.LuaException; final class LuaDateTime
{
final class LuaDateTime {
private static final TemporalField CENTURY = map( ChronoField.YEAR, ValueRange.of( 0, 6 ), x -> (x / 100) % 100 ); private static final TemporalField CENTURY = map( ChronoField.YEAR, ValueRange.of( 0, 6 ), x -> (x / 100) % 100 );
private static final TemporalField ZERO_WEEK = map( WeekFields.SUNDAY_START.dayOfWeek(), ValueRange.of( 0, 6 ), x -> x - 1 ); private static final TemporalField ZERO_WEEK = map( WeekFields.SUNDAY_START.dayOfWeek(), ValueRange.of( 0, 6 ), x -> x - 1 );
private LuaDateTime() { private LuaDateTime()
{
} }
static void format(DateTimeFormatterBuilder formatter, String format, ZoneOffset offset) throws LuaException { static void format( DateTimeFormatterBuilder formatter, String format, ZoneOffset offset ) throws LuaException
for (int i = 0; i < format.length(); ) { {
for( int i = 0; i < format.length(); )
{
char c; char c;
switch (c = format.charAt(i++)) { switch( c = format.charAt( i++ ) )
{
case '\n': case '\n':
formatter.appendLiteral( '\n' ); formatter.appendLiteral( '\n' );
break; break;
@ -44,10 +42,12 @@ final class LuaDateTime {
formatter.appendLiteral( c ); formatter.appendLiteral( c );
break; break;
case '%': case '%':
if (i >= format.length()) { if( i >= format.length() )
{
break; break;
} }
switch (c = format.charAt(i++)) { switch( c = format.charAt( i++ ) )
{
default: default:
throw new LuaException( "bad argument #1: invalid conversion specifier '%" + c + "'" ); throw new LuaException( "bad argument #1: invalid conversion specifier '%" + c + "'" );
@ -162,7 +162,8 @@ final class LuaDateTime {
} }
} }
static long fromTable(Map<?, ?> table) throws LuaException { static long fromTable( Map<?, ?> table ) throws LuaException
{
int year = getField( table, "year", -1 ); int year = getField( table, "year", -1 );
int month = getField( table, "month", -1 ); int month = getField( table, "month", -1 );
int day = getField( table, "day", -1 ); int day = getField( table, "day", -1 );
@ -172,15 +173,18 @@ final class LuaDateTime {
LocalDateTime time = LocalDateTime.of( year, month, day, hour, minute, second ); LocalDateTime time = LocalDateTime.of( year, month, day, hour, minute, second );
Boolean isDst = getBoolField( table, "isdst" ); Boolean isDst = getBoolField( table, "isdst" );
if (isDst != null) { if( isDst != null )
{
boolean requireDst = isDst; boolean requireDst = isDst;
for( ZoneOffset possibleOffset : ZoneOffset.systemDefault() for( ZoneOffset possibleOffset : ZoneOffset.systemDefault()
.getRules() .getRules()
.getValidOffsets(time)) { .getValidOffsets( time ) )
{
Instant instant = time.toInstant( possibleOffset ); Instant instant = time.toInstant( possibleOffset );
if( possibleOffset.getRules() if( possibleOffset.getRules()
.getDaylightSavings( instant ) .getDaylightSavings( instant )
.isZero() == requireDst) { .isZero() == requireDst )
{
return instant.getEpochSecond(); return instant.getEpochSecond();
} }
} }
@ -193,26 +197,32 @@ final class LuaDateTime {
.getEpochSecond(); .getEpochSecond();
} }
private static int getField(Map<?, ?> table, String field, int def) throws LuaException { private static int getField( Map<?, ?> table, String field, int def ) throws LuaException
{
Object value = table.get( field ); Object value = table.get( field );
if (value instanceof Number) { if( value instanceof Number )
{
return ((Number) value).intValue(); return ((Number) value).intValue();
} }
if (def < 0) { if( def < 0 )
{
throw new LuaException( "field \"" + field + "\" missing in date table" ); throw new LuaException( "field \"" + field + "\" missing in date table" );
} }
return def; return def;
} }
private static Boolean getBoolField(Map<?, ?> table, String field) throws LuaException { private static Boolean getBoolField( Map<?, ?> table, String field ) throws LuaException
{
Object value = table.get( field ); Object value = table.get( field );
if (value instanceof Boolean || value == null) { if( value instanceof Boolean || value == null )
{
return (Boolean) value; return (Boolean) value;
} }
throw new LuaException( "field \"" + field + "\" missing in date table" ); throw new LuaException( "field \"" + field + "\" missing in date table" );
} }
static Map<String, ?> toTable(TemporalAccessor date, ZoneId offset, Instant instant) { static Map<String, ?> toTable( TemporalAccessor date, ZoneId offset, Instant instant )
{
HashMap<String, Object> table = new HashMap<>( 9 ); HashMap<String, Object> table = new HashMap<>( 9 );
table.put( "year", date.getLong( ChronoField.YEAR ) ); table.put( "year", date.getLong( ChronoField.YEAR ) );
table.put( "month", date.getLong( ChronoField.MONTH_OF_YEAR ) ); table.put( "month", date.getLong( ChronoField.MONTH_OF_YEAR ) );
@ -228,53 +238,64 @@ final class LuaDateTime {
return table; return table;
} }
private static TemporalField map(TemporalField field, ValueRange range, LongUnaryOperator convert) { private static TemporalField map( TemporalField field, ValueRange range, LongUnaryOperator convert )
return new TemporalField() { {
return new TemporalField()
{
private final ValueRange range = ValueRange.of( 0, 99 ); private final ValueRange range = ValueRange.of( 0, 99 );
@Override @Override
public TemporalUnit getBaseUnit() { public TemporalUnit getBaseUnit()
{
return field.getBaseUnit(); return field.getBaseUnit();
} }
@Override @Override
public TemporalUnit getRangeUnit() { public TemporalUnit getRangeUnit()
{
return field.getRangeUnit(); return field.getRangeUnit();
} }
@Override @Override
public ValueRange range() { public ValueRange range()
{
return this.range; return this.range;
} }
@Override @Override
public boolean isDateBased() { public boolean isDateBased()
{
return field.isDateBased(); return field.isDateBased();
} }
@Override @Override
public boolean isTimeBased() { public boolean isTimeBased()
{
return field.isTimeBased(); return field.isTimeBased();
} }
@Override @Override
public boolean isSupportedBy(TemporalAccessor temporal) { public boolean isSupportedBy( TemporalAccessor temporal )
{
return field.isSupportedBy( temporal ); return field.isSupportedBy( temporal );
} }
@Override @Override
public ValueRange rangeRefinedBy(TemporalAccessor temporal) { public ValueRange rangeRefinedBy( TemporalAccessor temporal )
{
return this.range; return this.range;
} }
@Override @Override
public long getFrom(TemporalAccessor temporal) { public long getFrom( TemporalAccessor temporal )
{
return convert.applyAsLong( temporal.getLong( field ) ); return convert.applyAsLong( temporal.getLong( field ) );
} }
@Override @Override
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
public <R extends Temporal> R adjustInto(R temporal, long newValue) { public <R extends Temporal> R adjustInto( R temporal, long newValue )
{
return (R) temporal.with( field, newValue ); return (R) temporal.with( field, newValue );
} }
}; };

View File

@ -6,23 +6,6 @@
package dan200.computercraft.core.apis; package dan200.computercraft.core.apis;
import static dan200.computercraft.api.lua.LuaValues.checkFinite;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.TimeZone;
import javax.annotation.Nonnull;
import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.IArguments;
import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
@ -31,12 +14,23 @@ import dan200.computercraft.shared.util.StringUtil;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import javax.annotation.Nonnull;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatterBuilder;
import java.util.*;
import static dan200.computercraft.api.lua.LuaValues.checkFinite;
/** /**
* The {@link OSAPI} API allows interacting with the current computer. * The {@link OSAPI} API allows interacting with the current computer.
* *
* @cc.module os * @cc.module os
*/ */
public class OSAPI implements ILuaAPI { public class OSAPI implements ILuaAPI
{
private final IAPIEnvironment apiEnvironment; private final IAPIEnvironment apiEnvironment;
private final Int2ObjectMap<Alarm> m_alarms = new Int2ObjectOpenHashMap<>(); private final Int2ObjectMap<Alarm> m_alarms = new Int2ObjectOpenHashMap<>();
@ -46,34 +40,40 @@ public class OSAPI implements ILuaAPI {
private int m_nextAlarmToken = 0; private int m_nextAlarmToken = 0;
public OSAPI(IAPIEnvironment environment) { public OSAPI( IAPIEnvironment environment )
{
this.apiEnvironment = environment; this.apiEnvironment = environment;
} }
@Override @Override
public String[] getNames() { public String[] getNames()
{
return new String[] { "os" }; return new String[] { "os" };
} }
@Override @Override
public void startup() { public void startup()
{
this.m_time = this.apiEnvironment.getComputerEnvironment() this.m_time = this.apiEnvironment.getComputerEnvironment()
.getTimeOfDay(); .getTimeOfDay();
this.m_day = this.apiEnvironment.getComputerEnvironment() this.m_day = this.apiEnvironment.getComputerEnvironment()
.getDay(); .getDay();
this.m_clock = 0; this.m_clock = 0;
synchronized (this.m_alarms) { synchronized( this.m_alarms )
{
this.m_alarms.clear(); this.m_alarms.clear();
} }
} }
@Override @Override
public void update() { public void update()
{
this.m_clock++; this.m_clock++;
// Wait for all of our alarms // Wait for all of our alarms
synchronized (this.m_alarms) { synchronized( this.m_alarms )
{
double previousTime = this.m_time; double previousTime = this.m_time;
int previousDay = this.m_day; int previousDay = this.m_day;
double time = this.apiEnvironment.getComputerEnvironment() double time = this.apiEnvironment.getComputerEnvironment()
@ -81,15 +81,18 @@ public class OSAPI implements ILuaAPI {
int day = this.apiEnvironment.getComputerEnvironment() int day = this.apiEnvironment.getComputerEnvironment()
.getDay(); .getDay();
if (time > previousTime || day > previousDay) { if( time > previousTime || day > previousDay )
{
double now = this.m_day * 24.0 + this.m_time; double now = this.m_day * 24.0 + this.m_time;
Iterator<Int2ObjectMap.Entry<Alarm>> it = this.m_alarms.int2ObjectEntrySet() Iterator<Int2ObjectMap.Entry<Alarm>> it = this.m_alarms.int2ObjectEntrySet()
.iterator(); .iterator();
while (it.hasNext()) { while( it.hasNext() )
{
Int2ObjectMap.Entry<Alarm> entry = it.next(); Int2ObjectMap.Entry<Alarm> entry = it.next();
Alarm alarm = entry.getValue(); Alarm alarm = entry.getValue();
double t = alarm.m_day * 24.0 + alarm.m_time; double t = alarm.m_day * 24.0 + alarm.m_time;
if (now >= t) { if( now >= t )
{
this.apiEnvironment.queueEvent( "alarm", entry.getIntKey() ); this.apiEnvironment.queueEvent( "alarm", entry.getIntKey() );
it.remove(); it.remove();
} }
@ -102,8 +105,10 @@ public class OSAPI implements ILuaAPI {
} }
@Override @Override
public void shutdown() { public void shutdown()
synchronized (this.m_alarms) { {
synchronized( this.m_alarms )
{
this.m_alarms.clear(); this.m_alarms.clear();
} }
} }
@ -118,7 +123,8 @@ public class OSAPI implements ILuaAPI {
* @cc.see os.pullEvent To pull the event queued * @cc.see os.pullEvent To pull the event queued
*/ */
@LuaFunction @LuaFunction
public final void queueEvent(String name, IArguments args) { public final void queueEvent( String name, IArguments args )
{
this.apiEnvironment.queueEvent( name, this.apiEnvironment.queueEvent( name,
args.drop( 1 ) args.drop( 1 )
.getAll() ); .getAll() );
@ -133,7 +139,8 @@ public class OSAPI implements ILuaAPI {
* @throws LuaException If the time is below zero. * @throws LuaException If the time is below zero.
*/ */
@LuaFunction @LuaFunction
public final int startTimer(double timer) throws LuaException { public final int startTimer( double timer ) throws LuaException
{
return this.apiEnvironment.startTimer( Math.round( checkFinite( 0, timer ) / 0.05 ) ); return this.apiEnvironment.startTimer( Math.round( checkFinite( 0, timer ) / 0.05 ) );
} }
@ -144,7 +151,8 @@ public class OSAPI implements ILuaAPI {
* @see #startTimer To start a timer. * @see #startTimer To start a timer.
*/ */
@LuaFunction @LuaFunction
public final void cancelTimer(int token) { public final void cancelTimer( int token )
{
this.apiEnvironment.cancelTimer( token ); this.apiEnvironment.cancelTimer( token );
} }
@ -156,12 +164,15 @@ public class OSAPI implements ILuaAPI {
* @throws LuaException If the time is out of range. * @throws LuaException If the time is out of range.
*/ */
@LuaFunction @LuaFunction
public final int setAlarm(double time) throws LuaException { public final int setAlarm( double time ) throws LuaException
{
checkFinite( 0, time ); checkFinite( 0, time );
if (time < 0.0 || time >= 24.0) { if( time < 0.0 || time >= 24.0 )
{
throw new LuaException( "Number out of range" ); throw new LuaException( "Number out of range" );
} }
synchronized (this.m_alarms) { synchronized( this.m_alarms )
{
int day = time > this.m_time ? this.m_day : this.m_day + 1; int day = time > this.m_time ? this.m_day : this.m_day + 1;
this.m_alarms.put( this.m_nextAlarmToken, new Alarm( time, day ) ); this.m_alarms.put( this.m_nextAlarmToken, new Alarm( time, day ) );
return this.m_nextAlarmToken++; return this.m_nextAlarmToken++;
@ -175,8 +186,10 @@ public class OSAPI implements ILuaAPI {
* @see #setAlarm To set an alarm. * @see #setAlarm To set an alarm.
*/ */
@LuaFunction @LuaFunction
public final void cancelAlarm(int token) { public final void cancelAlarm( int token )
synchronized (this.m_alarms) { {
synchronized( this.m_alarms )
{
this.m_alarms.remove( token ); this.m_alarms.remove( token );
} }
} }
@ -185,7 +198,8 @@ public class OSAPI implements ILuaAPI {
* Shuts down the computer immediately. * Shuts down the computer immediately.
*/ */
@LuaFunction( "shutdown" ) @LuaFunction( "shutdown" )
public final void doShutdown() { public final void doShutdown()
{
this.apiEnvironment.shutdown(); this.apiEnvironment.shutdown();
} }
@ -193,7 +207,8 @@ public class OSAPI implements ILuaAPI {
* Reboots the computer immediately. * Reboots the computer immediately.
*/ */
@LuaFunction( "reboot" ) @LuaFunction( "reboot" )
public final void doReboot() { public final void doReboot()
{
this.apiEnvironment.reboot(); this.apiEnvironment.reboot();
} }
@ -206,7 +221,8 @@ public class OSAPI implements ILuaAPI {
"getComputerID", "getComputerID",
"computerID" "computerID"
} ) } )
public final int getComputerID() { public final int getComputerID()
{
return this.apiEnvironment.getComputerID(); return this.apiEnvironment.getComputerID();
} }
@ -220,7 +236,8 @@ public class OSAPI implements ILuaAPI {
"getComputerLabel", "getComputerLabel",
"computerLabel" "computerLabel"
} ) } )
public final Object[] getComputerLabel() { public final Object[] getComputerLabel()
{
String label = this.apiEnvironment.getLabel(); String label = this.apiEnvironment.getLabel();
return label == null ? null : new Object[] { label }; return label == null ? null : new Object[] { label };
} }
@ -231,7 +248,8 @@ public class OSAPI implements ILuaAPI {
* @param label The new label. May be {@code nil} in order to clear it. * @param label The new label. May be {@code nil} in order to clear it.
*/ */
@LuaFunction @LuaFunction
public final void setComputerLabel(Optional<String> label) { public final void setComputerLabel( Optional<String> label )
{
this.apiEnvironment.setLabel( StringUtil.normaliseLabel( label.orElse( null ) ) ); this.apiEnvironment.setLabel( StringUtil.normaliseLabel( label.orElse( null ) ) );
} }
@ -241,7 +259,8 @@ public class OSAPI implements ILuaAPI {
* @return The computer's uptime. * @return The computer's uptime.
*/ */
@LuaFunction @LuaFunction
public final double clock() { public final double clock()
{
return this.m_clock * 0.05; return this.m_clock * 0.05;
} }
@ -262,14 +281,17 @@ public class OSAPI implements ILuaAPI {
* @see #date To get a date table that can be converted with this function. * @see #date To get a date table that can be converted with this function.
*/ */
@LuaFunction @LuaFunction
public final Object time(IArguments args) throws LuaException { public final Object time( IArguments args ) throws LuaException
{
Object value = args.get( 0 ); Object value = args.get( 0 );
if (value instanceof Map) { if( value instanceof Map )
{
return LuaDateTime.fromTable( (Map<?, ?>) value ); return LuaDateTime.fromTable( (Map<?, ?>) value );
} }
String param = args.optString( 0, "ingame" ); String param = args.optString( 0, "ingame" );
switch (param.toLowerCase(Locale.ROOT)) { switch( param.toLowerCase( Locale.ROOT ) )
{
case "utc": // Get Hour of day (UTC) case "utc": // Get Hour of day (UTC)
return getTimeForCalendar( Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) ); return getTimeForCalendar( Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) );
case "local": // Get Hour of day (local time) case "local": // Get Hour of day (local time)
@ -281,7 +303,8 @@ public class OSAPI implements ILuaAPI {
} }
} }
private static float getTimeForCalendar(Calendar c) { private static float getTimeForCalendar( Calendar c )
{
float time = c.get( Calendar.HOUR_OF_DAY ); float time = c.get( Calendar.HOUR_OF_DAY );
time += c.get( Calendar.MINUTE ) / 60.0f; time += c.get( Calendar.MINUTE ) / 60.0f;
time += c.get( Calendar.SECOND ) / (60.0f * 60.0f); time += c.get( Calendar.SECOND ) / (60.0f * 60.0f);
@ -300,9 +323,11 @@ public class OSAPI implements ILuaAPI {
* @throws LuaException If an invalid locale is passed. * @throws LuaException If an invalid locale is passed.
*/ */
@LuaFunction @LuaFunction
public final int day(Optional<String> args) throws LuaException { public final int day( Optional<String> args ) throws LuaException
{
switch( args.orElse( "ingame" ) switch( args.orElse( "ingame" )
.toLowerCase(Locale.ROOT)) { .toLowerCase( Locale.ROOT ) )
{
case "utc": // Get numbers of days since 1970-01-01 (utc) case "utc": // Get numbers of days since 1970-01-01 (utc)
return getDayForCalendar( Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) ); return getDayForCalendar( Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) );
case "local": // Get numbers of days since 1970-01-01 (local time) case "local": // Get numbers of days since 1970-01-01 (local time)
@ -314,11 +339,13 @@ public class OSAPI implements ILuaAPI {
} }
} }
private static int getDayForCalendar(Calendar c) { private static int getDayForCalendar( Calendar c )
{
GregorianCalendar g = c instanceof GregorianCalendar ? (GregorianCalendar) c : new GregorianCalendar(); GregorianCalendar g = c instanceof GregorianCalendar ? (GregorianCalendar) c : new GregorianCalendar();
int year = c.get( Calendar.YEAR ); int year = c.get( Calendar.YEAR );
int day = 0; int day = 0;
for (int y = 1970; y < year; y++) { for( int y = 1970; y < year; y++ )
{
day += g.isLeapYear( y ) ? 366 : 365; day += g.isLeapYear( y ) ? 366 : 365;
} }
day += c.get( Calendar.DAY_OF_YEAR ); day += c.get( Calendar.DAY_OF_YEAR );
@ -337,22 +364,27 @@ public class OSAPI implements ILuaAPI {
* @throws LuaException If an invalid locale is passed. * @throws LuaException If an invalid locale is passed.
*/ */
@LuaFunction @LuaFunction
public final long epoch(Optional<String> args) throws LuaException { public final long epoch( Optional<String> args ) throws LuaException
{
switch( args.orElse( "ingame" ) switch( args.orElse( "ingame" )
.toLowerCase(Locale.ROOT)) { .toLowerCase( Locale.ROOT ) )
case "utc": { {
case "utc":
{
// Get utc epoch // Get utc epoch
Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ); Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
return getEpochForCalendar( c ); return getEpochForCalendar( c );
} }
case "local": { case "local":
{
// Get local epoch // Get local epoch
Calendar c = Calendar.getInstance(); Calendar c = Calendar.getInstance();
return getEpochForCalendar( c ); return getEpochForCalendar( c );
} }
case "ingame": case "ingame":
// Get in-game epoch // Get in-game epoch
synchronized (this.m_alarms) { synchronized( this.m_alarms )
{
return this.m_day * 86400000L + (long) (this.m_time * 3600000.0); return this.m_day * 86400000L + (long) (this.m_time * 3600000.0);
} }
default: default:
@ -360,7 +392,8 @@ public class OSAPI implements ILuaAPI {
} }
} }
private static long getEpochForCalendar(Calendar c) { private static long getEpochForCalendar( Calendar c )
{
return c.getTime() return c.getTime()
.getTime(); .getTime();
} }
@ -381,7 +414,8 @@ public class OSAPI implements ILuaAPI {
* @throws LuaException If an invalid format is passed. * @throws LuaException If an invalid format is passed.
*/ */
@LuaFunction @LuaFunction
public final Object date(Optional<String> formatA, Optional<Long> timeA) throws LuaException { public final Object date( Optional<String> formatA, Optional<Long> timeA ) throws LuaException
{
String format = formatA.orElse( "%c" ); String format = formatA.orElse( "%c" );
long time = timeA.orElseGet( () -> Instant.now() long time = timeA.orElseGet( () -> Instant.now()
.getEpochSecond() ); .getEpochSecond() );
@ -389,18 +423,22 @@ public class OSAPI implements ILuaAPI {
Instant instant = Instant.ofEpochSecond( time ); Instant instant = Instant.ofEpochSecond( time );
ZonedDateTime date; ZonedDateTime date;
ZoneOffset offset; ZoneOffset offset;
if (format.startsWith("!")) { if( format.startsWith( "!" ) )
{
offset = ZoneOffset.UTC; offset = ZoneOffset.UTC;
date = ZonedDateTime.ofInstant( instant, offset ); date = ZonedDateTime.ofInstant( instant, offset );
format = format.substring( 1 ); format = format.substring( 1 );
} else { }
else
{
ZoneId id = ZoneId.systemDefault(); ZoneId id = ZoneId.systemDefault();
offset = id.getRules() offset = id.getRules()
.getOffset( instant ); .getOffset( instant );
date = ZonedDateTime.ofInstant( instant, id ); date = ZonedDateTime.ofInstant( instant, id );
} }
if (format.equals("*t")) { if( format.equals( "*t" ) )
{
return LuaDateTime.toTable( date, offset, instant ); return LuaDateTime.toTable( date, offset, instant );
} }
@ -410,17 +448,20 @@ public class OSAPI implements ILuaAPI {
.format( date ); .format( date );
} }
private static class Alarm implements Comparable<Alarm> { private static class Alarm implements Comparable<Alarm>
{
final double m_time; final double m_time;
final int m_day; final int m_day;
Alarm(double time, int day) { Alarm( double time, int day )
{
this.m_time = time; this.m_time = time;
this.m_day = day; this.m_day = day;
} }
@Override @Override
public int compareTo(@Nonnull Alarm o) { public int compareTo( @Nonnull Alarm o )
{
double t = this.m_day * 24.0 + this.m_time; double t = this.m_day * 24.0 + this.m_time;
double ot = this.m_day * 24.0 + this.m_time; double ot = this.m_day * 24.0 + this.m_time;
return Double.compare( t, ot ); return Double.compare( t, ot );

View File

@ -6,24 +6,9 @@
package dan200.computercraft.core.apis; package dan200.computercraft.core.apis;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nonnull;
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.IArguments; import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.peripheral.IDynamicPeripheral; import dan200.computercraft.api.peripheral.IDynamicPeripheral;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IWorkMonitor; import dan200.computercraft.api.peripheral.IWorkMonitor;
@ -34,23 +19,31 @@ import dan200.computercraft.core.asm.PeripheralMethod;
import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.core.tracking.TrackingField;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
/** /**
* CC's "native" peripheral API. This is wrapped within CraftOS to provide a version which works with modems. * CC's "native" peripheral API. This is wrapped within CraftOS to provide a version which works with modems.
* *
* @cc.module peripheral * @cc.module peripheral
* @hidden * @hidden
*/ */
public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener { public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener
{
private final IAPIEnvironment environment; private final IAPIEnvironment environment;
private final PeripheralWrapper[] peripherals = new PeripheralWrapper[6]; private final PeripheralWrapper[] peripherals = new PeripheralWrapper[6];
private boolean running; private boolean running;
public PeripheralAPI(IAPIEnvironment environment) {
public PeripheralAPI( IAPIEnvironment environment )
{
this.environment = environment; this.environment = environment;
this.environment.setPeripheralChangeListener( this ); this.environment.setPeripheralChangeListener( this );
this.running = false; this.running = false;
} }
public static Map<String, PeripheralMethod> getMethods(IPeripheral peripheral) { public static Map<String, PeripheralMethod> getMethods( IPeripheral peripheral )
{
String[] dynamicMethods = peripheral instanceof IDynamicPeripheral ? Objects.requireNonNull( ((IDynamicPeripheral) peripheral).getMethodNames(), String[] dynamicMethods = peripheral instanceof IDynamicPeripheral ? Objects.requireNonNull( ((IDynamicPeripheral) peripheral).getMethodNames(),
"Peripheral methods cannot be null" ) : "Peripheral methods cannot be null" ) :
LuaMethod.EMPTY_METHODS; LuaMethod.EMPTY_METHODS;
@ -58,10 +51,12 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
List<NamedMethod<PeripheralMethod>> methods = PeripheralMethod.GENERATOR.getMethods( peripheral.getClass() ); List<NamedMethod<PeripheralMethod>> methods = PeripheralMethod.GENERATOR.getMethods( peripheral.getClass() );
Map<String, PeripheralMethod> methodMap = new HashMap<>( methods.size() + dynamicMethods.length ); Map<String, PeripheralMethod> methodMap = new HashMap<>( methods.size() + dynamicMethods.length );
for (int i = 0; i < dynamicMethods.length; i++) { for( int i = 0; i < dynamicMethods.length; i++ )
{
methodMap.put( dynamicMethods[i], PeripheralMethod.DYNAMIC.get( i ) ); methodMap.put( dynamicMethods[i], PeripheralMethod.DYNAMIC.get( i ) );
} }
for (NamedMethod<PeripheralMethod> method : methods) { for( NamedMethod<PeripheralMethod> method : methods )
{
methodMap.put( method.getName(), method.getMethod() ); methodMap.put( method.getName(), method.getMethod() );
} }
return methodMap; return methodMap;
@ -70,13 +65,17 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
// IPeripheralChangeListener // IPeripheralChangeListener
@Override @Override
public void onPeripheralChanged(ComputerSide side, IPeripheral newPeripheral) { public void onPeripheralChanged( ComputerSide side, IPeripheral newPeripheral )
synchronized (this.peripherals) { {
synchronized( this.peripherals )
{
int index = side.ordinal(); int index = side.ordinal();
if (this.peripherals[index] != null) { if( this.peripherals[index] != null )
{
// Queue a detachment // Queue a detachment
final PeripheralWrapper wrapper = this.peripherals[index]; final PeripheralWrapper wrapper = this.peripherals[index];
if (wrapper.isAttached()) { if( wrapper.isAttached() )
{
wrapper.detach(); wrapper.detach();
} }
@ -87,10 +86,12 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
// Assign the new peripheral // Assign the new peripheral
this.peripherals[index] = newPeripheral == null ? null : new PeripheralWrapper( newPeripheral, side.getName() ); this.peripherals[index] = newPeripheral == null ? null : new PeripheralWrapper( newPeripheral, side.getName() );
if (this.peripherals[index] != null) { if( this.peripherals[index] != null )
{
// Queue an attachment // Queue an attachment
final PeripheralWrapper wrapper = this.peripherals[index]; final PeripheralWrapper wrapper = this.peripherals[index];
if (this.running && !wrapper.isAttached()) { if( this.running && !wrapper.isAttached() )
{
wrapper.attach(); wrapper.attach();
} }
@ -101,17 +102,22 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
} }
@Override @Override
public String[] getNames() { public String[] getNames()
{
return new String[] { "peripheral" }; return new String[] { "peripheral" };
} }
@Override @Override
public void startup() { public void startup()
synchronized (this.peripherals) { {
synchronized( this.peripherals )
{
this.running = true; this.running = true;
for (int i = 0; i < 6; i++) { for( int i = 0; i < 6; i++ )
{
PeripheralWrapper wrapper = this.peripherals[i]; PeripheralWrapper wrapper = this.peripherals[i];
if (wrapper != null && !wrapper.isAttached()) { if( wrapper != null && !wrapper.isAttached() )
{
wrapper.attach(); wrapper.attach();
} }
} }
@ -119,12 +125,16 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
} }
@Override @Override
public void shutdown() { public void shutdown()
synchronized (this.peripherals) { {
synchronized( this.peripherals )
{
this.running = false; this.running = false;
for (int i = 0; i < 6; i++) { for( int i = 0; i < 6; i++ )
{
PeripheralWrapper wrapper = this.peripherals[i]; PeripheralWrapper wrapper = this.peripherals[i];
if (wrapper != null && wrapper.isAttached()) { if( wrapper != null && wrapper.isAttached() )
{
wrapper.detach(); wrapper.detach();
} }
} }
@ -132,12 +142,16 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
} }
@LuaFunction @LuaFunction
public final boolean isPresent(String sideName) { public final boolean isPresent( String sideName )
{
ComputerSide side = ComputerSide.valueOfInsensitive( sideName ); ComputerSide side = ComputerSide.valueOfInsensitive( sideName );
if (side != null) { if( side != null )
synchronized (this.peripherals) { {
synchronized( this.peripherals )
{
PeripheralWrapper p = this.peripherals[side.ordinal()]; PeripheralWrapper p = this.peripherals[side.ordinal()];
if (p != null) { if( p != null )
{
return true; return true;
} }
} }
@ -146,15 +160,19 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
} }
@LuaFunction @LuaFunction
public final Object[] getType(String sideName) { public final Object[] getType( String sideName )
{
ComputerSide side = ComputerSide.valueOfInsensitive( sideName ); ComputerSide side = ComputerSide.valueOfInsensitive( sideName );
if (side == null) { if( side == null )
{
return null; return null;
} }
synchronized (this.peripherals) { synchronized( this.peripherals )
{
PeripheralWrapper p = this.peripherals[side.ordinal()]; PeripheralWrapper p = this.peripherals[side.ordinal()];
if (p != null) { if( p != null )
{
return new Object[] { p.getType() }; return new Object[] { p.getType() };
} }
} }
@ -162,15 +180,19 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
} }
@LuaFunction @LuaFunction
public final Object[] getMethods(String sideName) { public final Object[] getMethods( String sideName )
{
ComputerSide side = ComputerSide.valueOfInsensitive( sideName ); ComputerSide side = ComputerSide.valueOfInsensitive( sideName );
if (side == null) { if( side == null )
{
return null; return null;
} }
synchronized (this.peripherals) { synchronized( this.peripherals )
{
PeripheralWrapper p = this.peripherals[side.ordinal()]; PeripheralWrapper p = this.peripherals[side.ordinal()];
if (p != null) { if( p != null )
{
return new Object[] { p.getMethods() }; return new Object[] { p.getMethods() };
} }
} }
@ -178,37 +200,46 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
} }
@LuaFunction @LuaFunction
public final MethodResult call(ILuaContext context, IArguments args) throws LuaException { public final MethodResult call( ILuaContext context, IArguments args ) throws LuaException
{
ComputerSide side = ComputerSide.valueOfInsensitive( args.getString( 0 ) ); ComputerSide side = ComputerSide.valueOfInsensitive( args.getString( 0 ) );
String methodName = args.getString( 1 ); String methodName = args.getString( 1 );
IArguments methodArgs = args.drop( 2 ); IArguments methodArgs = args.drop( 2 );
if (side == null) { if( side == null )
{
throw new LuaException( "No peripheral attached" ); throw new LuaException( "No peripheral attached" );
} }
PeripheralWrapper p; PeripheralWrapper p;
synchronized (this.peripherals) { synchronized( this.peripherals )
{
p = this.peripherals[side.ordinal()]; p = this.peripherals[side.ordinal()];
} }
if (p == null) { if( p == null )
{
throw new LuaException( "No peripheral attached" ); throw new LuaException( "No peripheral attached" );
} }
try { try
{
return p.call( context, methodName, methodArgs ) return p.call( context, methodName, methodArgs )
.adjustError( 1 ); .adjustError( 1 );
} catch (LuaException e) { }
catch( LuaException e )
{
// We increase the error level by one in order to shift the error level to where peripheral.call was // We increase the error level by one in order to shift the error level to where peripheral.call was
// invoked. It would be possible to do it in Lua code, but would add significantly more overhead. // invoked. It would be possible to do it in Lua code, but would add significantly more overhead.
if (e.getLevel() > 0) { if( e.getLevel() > 0 )
{
throw new FastLuaException( e.getMessage(), e.getLevel() + 1 ); throw new FastLuaException( e.getMessage(), e.getLevel() + 1 );
} }
throw e; throw e;
} }
} }
private class PeripheralWrapper extends ComputerAccess { private class PeripheralWrapper extends ComputerAccess
{
private final String side; private final String side;
private final IPeripheral peripheral; private final IPeripheral peripheral;
@ -216,7 +247,8 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
private final Map<String, PeripheralMethod> methodMap; private final Map<String, PeripheralMethod> methodMap;
private boolean attached; private boolean attached;
PeripheralWrapper(IPeripheral peripheral, String side) { PeripheralWrapper( IPeripheral peripheral, String side )
{
super( PeripheralAPI.this.environment ); super( PeripheralAPI.this.environment );
this.side = side; this.side = side;
this.peripheral = peripheral; this.peripheral = peripheral;
@ -227,42 +259,56 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
this.methodMap = PeripheralAPI.getMethods( peripheral ); this.methodMap = PeripheralAPI.getMethods( peripheral );
} }
public String getType() { public String getType()
{
return this.type; return this.type;
} public IPeripheral getPeripheral() { }
public IPeripheral getPeripheral()
{
return this.peripheral; return this.peripheral;
} }
public Collection<String> getMethods() { public Collection<String> getMethods()
{
return this.methodMap.keySet(); return this.methodMap.keySet();
} }
public synchronized void attach() { public synchronized void attach()
{
this.attached = true; this.attached = true;
this.peripheral.attach( this ); this.peripheral.attach( this );
} }
public void detach() { public void detach()
{
// Call detach // Call detach
this.peripheral.detach( this ); this.peripheral.detach( this );
synchronized (this) { synchronized( this )
{
// Unmount everything the detach function forgot to do // Unmount everything the detach function forgot to do
this.unmountAll(); this.unmountAll();
} }
this.attached = false; this.attached = false;
} public synchronized boolean isAttached() { }
public synchronized boolean isAttached()
{
return this.attached; return this.attached;
} }
public MethodResult call(ILuaContext context, String methodName, IArguments arguments) throws LuaException { public MethodResult call( ILuaContext context, String methodName, IArguments arguments ) throws LuaException
{
PeripheralMethod method; PeripheralMethod method;
synchronized (this) { synchronized( this )
{
method = this.methodMap.get( methodName ); method = this.methodMap.get( methodName );
} }
if (method == null) { if( method == null )
{
throw new LuaException( "No such method " + methodName ); throw new LuaException( "No such method " + methodName );
} }
@ -272,40 +318,50 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
// IComputerAccess implementation // IComputerAccess implementation
@Override @Override
public synchronized String mount(@Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName) { public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName )
if (!this.attached) { {
if( !this.attached )
{
throw new NotAttachedException(); throw new NotAttachedException();
} }
return super.mount( desiredLoc, mount, driveName ); return super.mount( desiredLoc, mount, driveName );
} }
@Override @Override
public synchronized String mountWritable(@Nonnull String desiredLoc, @Nonnull IWritableMount mount, @Nonnull String driveName) { public synchronized String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount, @Nonnull String driveName )
if (!this.attached) { {
if( !this.attached )
{
throw new NotAttachedException(); throw new NotAttachedException();
} }
return super.mountWritable( desiredLoc, mount, driveName ); return super.mountWritable( desiredLoc, mount, driveName );
} }
@Override @Override
public synchronized void unmount(String location) { public synchronized void unmount( String location )
if (!this.attached) { {
if( !this.attached )
{
throw new NotAttachedException(); throw new NotAttachedException();
} }
super.unmount( location ); super.unmount( location );
} }
@Override @Override
public int getID() { public int getID()
if (!this.attached) { {
if( !this.attached )
{
throw new NotAttachedException(); throw new NotAttachedException();
} }
return super.getID(); return super.getID();
} }
@Override @Override
public void queueEvent(@Nonnull String event, Object... arguments) { public void queueEvent( @Nonnull String event, Object... arguments )
if (!this.attached) { {
if( !this.attached )
{
throw new NotAttachedException(); throw new NotAttachedException();
} }
super.queueEvent( event, arguments ); super.queueEvent( event, arguments );
@ -313,19 +369,22 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
@Nonnull @Nonnull
@Override @Override
public IWorkMonitor getMainThreadMonitor() { public IWorkMonitor getMainThreadMonitor()
if (!this.attached) { {
if( !this.attached )
{
throw new NotAttachedException(); throw new NotAttachedException();
} }
return super.getMainThreadMonitor(); return super.getMainThreadMonitor();
} }
@Nonnull @Nonnull
@Override @Override
public String getAttachmentName() { public String getAttachmentName()
if (!this.attached) { {
if( !this.attached )
{
throw new NotAttachedException(); throw new NotAttachedException();
} }
return this.side; return this.side;
@ -333,14 +392,18 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
@Nonnull @Nonnull
@Override @Override
public Map<String, IPeripheral> getAvailablePeripherals() { public Map<String, IPeripheral> getAvailablePeripherals()
if (!this.attached) { {
if( !this.attached )
{
throw new NotAttachedException(); throw new NotAttachedException();
} }
Map<String, IPeripheral> peripherals = new HashMap<>(); Map<String, IPeripheral> peripherals = new HashMap<>();
for (PeripheralWrapper wrapper : PeripheralAPI.this.peripherals) { for( PeripheralWrapper wrapper : PeripheralAPI.this.peripherals )
if (wrapper != null && wrapper.isAttached()) { {
if( wrapper != null && wrapper.isAttached() )
{
peripherals.put( wrapper.getAttachmentName(), wrapper.getPeripheral() ); peripherals.put( wrapper.getAttachmentName(), wrapper.getPeripheral() );
} }
} }
@ -350,14 +413,18 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
@Nullable @Nullable
@Override @Override
public IPeripheral getAvailablePeripheral(@Nonnull String name) { public IPeripheral getAvailablePeripheral( @Nonnull String name )
if (!this.attached) { {
if( !this.attached )
{
throw new NotAttachedException(); throw new NotAttachedException();
} }
for (PeripheralWrapper wrapper : PeripheralAPI.this.peripherals) { for( PeripheralWrapper wrapper : PeripheralAPI.this.peripherals )
{
if( wrapper != null && wrapper.isAttached() && wrapper.getAttachmentName() if( wrapper != null && wrapper.isAttached() && wrapper.getAttachmentName()
.equals(name)) { .equals( name ) )
{
return wrapper.getPeripheral(); return wrapper.getPeripheral();
} }
} }

Some files were not shown because too many files have changed in this diff Show More