mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-30 21:23:00 +00:00 
			
		
		
		
	Reformat everything
This commit is contained in:
		| @@ -6,15 +6,6 @@ | ||||
|  | ||||
| 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.core.apis.http.options.Action; | ||||
| 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.turtle.recipes.TurtleRecipe; | ||||
| import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe; | ||||
| import dan200.computercraft.shared.util.*; | ||||
| import org.apache.logging.log4j.LogManager; | ||||
| 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 dan200.computercraft.shared.util.ImpostorRecipe; | ||||
| import dan200.computercraft.shared.util.ImpostorShapelessRecipe; | ||||
| import net.fabricmc.api.ModInitializer; | ||||
| import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder; | ||||
| import net.fabricmc.fabric.api.resource.ResourceManagerHelper; | ||||
| import net.fabricmc.fabric.api.resource.ResourcePackActivationType; | ||||
| 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"; | ||||
|  | ||||
|     // Configuration fields | ||||
| @@ -70,7 +70,6 @@ public final class ComputerCraft implements ModInitializer { | ||||
|         AddressRule.parse( "$private", null, Action.DENY.toPartial() ), | ||||
|         AddressRule.parse( "*", null, Action.ALLOW.toPartial() ) | ||||
|     ) ); | ||||
|  | ||||
|     public static int httpMaxRequests = 16; | ||||
|     public static int httpMaxWebsockets = 4; | ||||
|  | ||||
| @@ -99,7 +98,6 @@ public final class ComputerCraft implements ModInitializer { | ||||
|  | ||||
|     public static int pocketTermWidth = 26; | ||||
|     public static int pocketTermHeight = 20; | ||||
|  | ||||
|     public static int monitorWidth = 8; | ||||
|     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 ) ); | ||||
|  | ||||
|     @Override | ||||
|     public void onInitialize() { | ||||
|     public void onInitialize() | ||||
|     { | ||||
|         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, "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, "printout" ), PrintoutRecipe.SERIALIZER ); | ||||
|         Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "turtle" ), TurtleRecipe.SERIALIZER ); | ||||
|   | ||||
| @@ -6,13 +6,6 @@ | ||||
|  | ||||
| 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.filesystem.IMount; | ||||
| 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.ResourceMount; | ||||
| import dan200.computercraft.fabric.mixin.MinecraftServerAccess; | ||||
| import dan200.computercraft.shared.BundledRedstone; | ||||
| import dan200.computercraft.shared.MediaProviders; | ||||
| import dan200.computercraft.shared.Peripherals; | ||||
| import dan200.computercraft.shared.PocketUpgrades; | ||||
| import dan200.computercraft.shared.TurtleUpgrades; | ||||
| import dan200.computercraft.shared.*; | ||||
| import dan200.computercraft.shared.peripheral.modem.wired.TileCable; | ||||
| import dan200.computercraft.shared.peripheral.modem.wired.TileWiredModemFull; | ||||
| import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; | ||||
| import dan200.computercraft.shared.util.IDAssigner; | ||||
| import dan200.computercraft.shared.wired.WiredNode; | ||||
| import me.shedaniel.cloth.api.utils.v1.GameInstanceUtils; | ||||
|  | ||||
| import net.fabricmc.loader.api.FabricLoader; | ||||
| import net.minecraft.block.entity.BlockEntity; | ||||
| import net.minecraft.resource.ReloadableResourceManager; | ||||
| import net.minecraft.server.MinecraftServer; | ||||
| @@ -52,24 +41,35 @@ import net.minecraft.util.math.Direction; | ||||
| import net.minecraft.world.BlockView; | ||||
| 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(); | ||||
|  | ||||
|     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(); | ||||
|         if (server != null) { | ||||
|         if( server != null ) | ||||
|         { | ||||
|             ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) server).getServerResourceManager().getResourceManager(); | ||||
|             try { | ||||
|             try | ||||
|             { | ||||
|                 return manager.getResource( new Identifier( domain, subPath ) ) | ||||
|                     .getInputStream(); | ||||
|             } catch (IOException ignored) { | ||||
|             } | ||||
|             catch( IOException ignored ) | ||||
|             { | ||||
|                 return null; | ||||
|             } | ||||
|         } | ||||
| @@ -78,8 +78,10 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI { | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public String getInstalledVersion() { | ||||
|         if (this.version != null) { | ||||
|     public String getInstalledVersion() | ||||
|     { | ||||
|         if( this.version != null ) | ||||
|         { | ||||
|             return this.version; | ||||
|         } | ||||
|         return this.version = FabricLoader.getInstance() | ||||
| @@ -91,23 +93,30 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int createUniqueNumberedSaveDir(@Nonnull World world, @Nonnull String parentSubPath) { | ||||
|     public int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath ) | ||||
|     { | ||||
|         return IDAssigner.getNextId( parentSubPath ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public IWritableMount createSaveDirMount(@Nonnull World world, @Nonnull String subPath, long capacity) { | ||||
|         try { | ||||
|     public IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity ) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return new FileMount( new File( IDAssigner.getDir(), subPath ), capacity ); | ||||
|         } catch (Exception e) { | ||||
|         } | ||||
|         catch( Exception e ) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public IMount createResourceMount(@Nonnull String domain, @Nonnull String subPath) { | ||||
|     public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath ) | ||||
|     { | ||||
|         MinecraftServer server = GameInstanceUtils.getServer(); | ||||
|         if (server != null) { | ||||
|         if( server != null ) | ||||
|         { | ||||
|             ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) server).getServerResourceManager().getResourceManager(); | ||||
|             ResourceMount mount = ResourceMount.get( domain, subPath, manager ); | ||||
|             return mount.exists( "" ) ? mount : null; | ||||
| @@ -116,32 +125,38 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void registerPeripheralProvider(@Nonnull IPeripheralProvider provider) { | ||||
|     public void registerPeripheralProvider( @Nonnull IPeripheralProvider provider ) | ||||
|     { | ||||
|         Peripherals.register( provider ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void registerTurtleUpgrade(@Nonnull ITurtleUpgrade upgrade) { | ||||
|     public void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade ) | ||||
|     { | ||||
|         TurtleUpgrades.register( upgrade ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void registerBundledRedstoneProvider(@Nonnull IBundledRedstoneProvider provider) { | ||||
|     public void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider ) | ||||
|     { | ||||
|         BundledRedstone.register( provider ); | ||||
|     } | ||||
|  | ||||
|     @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 ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void registerMediaProvider(@Nonnull IMediaProvider provider) { | ||||
|     public void registerMediaProvider( @Nonnull IMediaProvider provider ) | ||||
|     { | ||||
|         MediaProviders.register( provider ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void registerPocketUpgrade(@Nonnull IPocketUpgrade upgrade) { | ||||
|     public void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade ) | ||||
|     { | ||||
|         PocketUpgrades.register( upgrade ); | ||||
|     } | ||||
|  | ||||
| @@ -153,28 +168,35 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI { | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public IPacketNetwork getWirelessNetwork() { | ||||
|     public IPacketNetwork getWirelessNetwork() | ||||
|     { | ||||
|         return WirelessNetwork.getUniversal(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void registerAPIFactory(@Nonnull ILuaAPIFactory factory) { | ||||
|     public void registerAPIFactory( @Nonnull ILuaAPIFactory factory ) | ||||
|     { | ||||
|         ApiFactories.register( factory ); | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public IWiredNode createWiredNodeForElement(@Nonnull IWiredElement element) { | ||||
|     public IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element ) | ||||
|     { | ||||
|         return new WiredNode( element ); | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     @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 ); | ||||
|         if (tile instanceof TileCable) { | ||||
|         if( tile instanceof TileCable ) | ||||
|         { | ||||
|             return ((TileCable) tile).getElement( side ); | ||||
|         } else if (tile instanceof TileWiredModemFull) { | ||||
|         } | ||||
|         else if( tile instanceof TileWiredModemFull ) | ||||
|         { | ||||
|             return ((TileWiredModemFull) tile).getElement(); | ||||
|         } | ||||
|         return null; | ||||
|   | ||||
| @@ -6,9 +6,6 @@ | ||||
|  | ||||
| package dan200.computercraft.api; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import dan200.computercraft.api.filesystem.IMount; | ||||
| import dan200.computercraft.api.filesystem.IWritableMount; | ||||
| 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.redstone.IBundledRedstoneProvider; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
|  | ||||
| import net.minecraft.util.math.BlockPos; | ||||
| import net.minecraft.util.math.Direction; | ||||
| import net.minecraft.world.BlockView; | ||||
| import net.minecraft.world.World; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| /** | ||||
|  * 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. | ||||
|  */ | ||||
| public final class ComputerCraftAPI { | ||||
| public final class ComputerCraftAPI | ||||
| { | ||||
|     private static IComputerCraftAPI instance; | ||||
|  | ||||
|     @Nonnull | ||||
|     @Deprecated | ||||
|     public static String getAPIVersion() { | ||||
|     public static String getAPIVersion() | ||||
|     { | ||||
|         return getInstalledVersion(); | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     public static String getInstalledVersion() { | ||||
|     public static String getInstalledVersion() | ||||
|     { | ||||
|         return getInstance().getInstalledVersion(); | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     private static IComputerCraftAPI getInstance() { | ||||
|         if (instance != null) { | ||||
|     private static IComputerCraftAPI getInstance() | ||||
|     { | ||||
|         if( instance != null ) | ||||
|         { | ||||
|             return instance; | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|         try | ||||
|         { | ||||
|             return instance = (IComputerCraftAPI) Class.forName( "dan200.computercraft.ComputerCraftAPIImpl" ) | ||||
|                 .getField( "INSTANCE" ) | ||||
|                 .get( null ); | ||||
|         } catch (ReflectiveOperationException e) { | ||||
|         } | ||||
|         catch( ReflectiveOperationException 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. | ||||
|      * @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 ); | ||||
|     } | ||||
|  | ||||
| @@ -99,7 +107,8 @@ public final class ComputerCraftAPI { | ||||
|      * @see IWritableMount | ||||
|      */ | ||||
|     @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 ); | ||||
|     } | ||||
|  | ||||
| @@ -122,7 +131,8 @@ public final class ComputerCraftAPI { | ||||
|      * @see IMount | ||||
|      */ | ||||
|     @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 ); | ||||
|     } | ||||
|  | ||||
| @@ -133,7 +143,8 @@ public final class ComputerCraftAPI { | ||||
|      * @see IPeripheral | ||||
|      * @see IPeripheralProvider | ||||
|      */ | ||||
|     public static void registerPeripheralProvider(@Nonnull IPeripheralProvider provider) { | ||||
|     public static void registerPeripheralProvider( @Nonnull IPeripheralProvider provider ) | ||||
|     { | ||||
|         getInstance().registerPeripheralProvider( provider ); | ||||
|     } | ||||
|  | ||||
| @@ -155,7 +166,8 @@ public final class ComputerCraftAPI { | ||||
|      * @param upgrade The turtle upgrade to register. | ||||
|      * @see ITurtleUpgrade | ||||
|      */ | ||||
|     public static void registerTurtleUpgrade(@Nonnull ITurtleUpgrade upgrade) { | ||||
|     public static void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade ) | ||||
|     { | ||||
|         getInstance().registerTurtleUpgrade( upgrade ); | ||||
|     } | ||||
|  | ||||
| @@ -165,7 +177,8 @@ public final class ComputerCraftAPI { | ||||
|      * @param provider The bundled redstone provider to register. | ||||
|      * @see IBundledRedstoneProvider | ||||
|      */ | ||||
|     public static void registerBundledRedstoneProvider(@Nonnull IBundledRedstoneProvider provider) { | ||||
|     public static void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider ) | ||||
|     { | ||||
|         getInstance().registerBundledRedstoneProvider( provider ); | ||||
|     } | ||||
|  | ||||
| @@ -179,7 +192,8 @@ public final class ComputerCraftAPI { | ||||
|      * capable of emitting bundled redstone at the location, -1 will be returned. | ||||
|      * @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 ); | ||||
|     } | ||||
|  | ||||
| @@ -189,11 +203,13 @@ public final class ComputerCraftAPI { | ||||
|      * @param provider The media provider to register. | ||||
|      * @see IMediaProvider | ||||
|      */ | ||||
|     public static void registerMediaProvider(@Nonnull IMediaProvider provider) { | ||||
|     public static void registerMediaProvider( @Nonnull IMediaProvider provider ) | ||||
|     { | ||||
|         getInstance().registerMediaProvider( provider ); | ||||
|     } | ||||
|  | ||||
|     public static void registerPocketUpgrade(@Nonnull IPocketUpgrade upgrade) { | ||||
|     public static void registerPocketUpgrade( @Nonnull IPocketUpgrade 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. | ||||
|      */ | ||||
|     public static IPacketNetwork getWirelessNetwork() { | ||||
|     public static IPacketNetwork getWirelessNetwork() | ||||
|     { | ||||
|         return getInstance().getWirelessNetwork(); | ||||
|     } | ||||
|  | ||||
|     public static void registerAPIFactory(@Nonnull ILuaAPIFactory factory) { | ||||
|     public static void registerAPIFactory( @Nonnull ILuaAPIFactory factory ) | ||||
|     { | ||||
|         getInstance().registerAPIFactory( factory ); | ||||
|     } | ||||
|  | ||||
| @@ -218,7 +236,8 @@ public final class ComputerCraftAPI { | ||||
|      * @see IWiredElement#getNode() | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public static IWiredNode createWiredNodeForElement(@Nonnull IWiredElement element) { | ||||
|     public static IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element ) | ||||
|     { | ||||
|         return getInstance().createWiredNodeForElement( element ); | ||||
|     } | ||||
|  | ||||
| @@ -232,11 +251,13 @@ public final class ComputerCraftAPI { | ||||
|      * @see IWiredElement#getNode() | ||||
|      */ | ||||
|     @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 ); | ||||
|     } | ||||
|  | ||||
|     public interface IComputerCraftAPI { | ||||
|     public interface IComputerCraftAPI | ||||
|     { | ||||
|         @Nonnull | ||||
|         String getInstalledVersion(); | ||||
|  | ||||
|   | ||||
| @@ -6,12 +6,9 @@ | ||||
|  | ||||
| package dan200.computercraft.api.client; | ||||
|  | ||||
| import java.util.Objects; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| 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.render.model.BakedModel; | ||||
| 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.item.ItemStack; | ||||
|  | ||||
| import net.fabricmc.api.EnvType; | ||||
| import net.fabricmc.api.Environment; | ||||
| import javax.annotation.Nonnull; | ||||
| import java.util.Objects; | ||||
|  | ||||
| /** | ||||
|  * A model to render, combined with a transformation matrix to apply. | ||||
|  */ | ||||
| @Environment( EnvType.CLIENT ) | ||||
| public final class TransformedModel { | ||||
| public final class TransformedModel | ||||
| { | ||||
|     private final BakedModel model; | ||||
|     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.matrix = Objects.requireNonNull( matrix ); | ||||
|     } | ||||
|  | ||||
|     public TransformedModel(@Nonnull BakedModel model) { | ||||
|     public TransformedModel( @Nonnull BakedModel model ) | ||||
|     { | ||||
|         this.model = Objects.requireNonNull( model ); | ||||
|         this.matrix = AffineTransformation.identity(); | ||||
|     } | ||||
|  | ||||
|     public static TransformedModel of(@Nonnull ModelIdentifier location) { | ||||
|     public static TransformedModel of( @Nonnull ModelIdentifier location ) | ||||
|     { | ||||
|         BakedModelManager modelManager = MinecraftClient.getInstance() | ||||
|             .getBakedModelManager(); | ||||
|         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() | ||||
|             .getItemRenderer() | ||||
|             .getModels() | ||||
| @@ -56,28 +58,37 @@ public final class TransformedModel { | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     public BakedModel getModel() { | ||||
|     public BakedModel getModel() | ||||
|     { | ||||
|         return this.model; | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     public AffineTransformation getMatrix() { | ||||
|     public AffineTransformation getMatrix() | ||||
|     { | ||||
|         return this.matrix; | ||||
|     } | ||||
|  | ||||
|     public void push(MatrixStack matrixStack) { | ||||
|     public void push( MatrixStack matrixStack ) | ||||
|     { | ||||
|         matrixStack.push(); | ||||
|  | ||||
|         AffineTransformationAccess access = (AffineTransformationAccess) (Object) this.matrix; | ||||
|         if( access.getTranslation() != null ) | ||||
|         { | ||||
|             matrixStack.translate( access.getTranslation().getX(), access.getTranslation().getY(), access.getTranslation().getZ() ); | ||||
|         } | ||||
|  | ||||
|         matrixStack.multiply( this.matrix.getRotation2() ); | ||||
|  | ||||
|         if( access.getScale() != null ) | ||||
|         { | ||||
|             matrixStack.scale( access.getScale().getX(), access.getScale().getY(), access.getScale().getZ() ); | ||||
|         } | ||||
|  | ||||
|         if( access.getRotation1() != null ) | ||||
|         { | ||||
|             matrixStack.multiply( access.getRotation1() ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -13,59 +13,70 @@ import java.time.Instant; | ||||
| /** | ||||
|  * 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 final boolean isDirectory; | ||||
|     private final long size; | ||||
|  | ||||
|     FileAttributes(boolean isDirectory, long size) { | ||||
|     FileAttributes( boolean isDirectory, long size ) | ||||
|     { | ||||
|         this.isDirectory = isDirectory; | ||||
|         this.size = size; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public FileTime lastModifiedTime() { | ||||
|     public FileTime lastModifiedTime() | ||||
|     { | ||||
|         return EPOCH; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public FileTime lastAccessTime() { | ||||
|     public FileTime lastAccessTime() | ||||
|     { | ||||
|         return EPOCH; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public FileTime creationTime() { | ||||
|     public FileTime creationTime() | ||||
|     { | ||||
|         return EPOCH; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isRegularFile() { | ||||
|     public boolean isRegularFile() | ||||
|     { | ||||
|         return !this.isDirectory; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isDirectory() { | ||||
|     public boolean isDirectory() | ||||
|     { | ||||
|         return this.isDirectory; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isSymbolicLink() { | ||||
|     public boolean isSymbolicLink() | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isOther() { | ||||
|     public boolean isOther() | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public long size() { | ||||
|     public long size() | ||||
|     { | ||||
|         return this.size; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Object fileKey() { | ||||
|     public Object fileKey() | ||||
|     { | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,34 +6,37 @@ | ||||
|  | ||||
| package dan200.computercraft.api.filesystem; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.util.Objects; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
| import java.io.IOException; | ||||
| import java.util.Objects; | ||||
|  | ||||
| /** | ||||
|  * 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. | ||||
|  */ | ||||
| public class FileOperationException extends IOException { | ||||
| public class FileOperationException extends IOException | ||||
| { | ||||
|     private static final long serialVersionUID = -8809108200853029849L; | ||||
|  | ||||
|     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" ) ); | ||||
|         this.filename = filename; | ||||
|     } | ||||
|  | ||||
|     public FileOperationException(@Nonnull String message) { | ||||
|     public FileOperationException( @Nonnull String message ) | ||||
|     { | ||||
|         super( Objects.requireNonNull( message, "message cannot be null" ) ); | ||||
|         this.filename = null; | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     public String getFilename() { | ||||
|     public String getFilename() | ||||
|     { | ||||
|         return this.filename; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -13,7 +13,8 @@ import java.io.IOException; | ||||
|  * | ||||
|  * 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. | ||||
|      * | ||||
|   | ||||
| @@ -6,18 +6,16 @@ | ||||
|  | ||||
| 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.nio.channels.ReadableByteChannel; | ||||
| import java.nio.file.attribute.BasicFileAttributes; | ||||
| 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)}. | ||||
|  * | ||||
| @@ -29,7 +27,8 @@ import net.minecraft.world.World; | ||||
|  * @see IComputerAccess#mount(String, IMount) | ||||
|  * @see IWritableMount | ||||
|  */ | ||||
| public interface IMount { | ||||
| public interface IMount | ||||
| { | ||||
|     /** | ||||
|      * 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. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     default BasicFileAttributes getAttributes(@Nonnull String path) throws IOException { | ||||
|         if (!this.exists(path)) { | ||||
|     default BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException | ||||
|     { | ||||
|         if( !this.exists( path ) ) | ||||
|         { | ||||
|             throw new FileOperationException( path, "No such file" ); | ||||
|         } | ||||
|         return new FileAttributes( this.isDirectory( path ), this.getSize( path ) ); | ||||
|   | ||||
| @@ -6,18 +6,16 @@ | ||||
|  | ||||
| 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.OutputStream; | ||||
| import java.nio.channels.WritableByteChannel; | ||||
| 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 | ||||
|  * 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 IMount | ||||
|  */ | ||||
| public interface IWritableMount extends IMount { | ||||
| public interface IWritableMount extends IMount | ||||
| { | ||||
|     /** | ||||
|      * 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. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     default OptionalLong getCapacity() { | ||||
|     default OptionalLong getCapacity() | ||||
|     { | ||||
|         return OptionalLong.empty(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,19 +6,19 @@ | ||||
|  | ||||
| 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.util.Map; | ||||
| import java.util.Optional; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
| import static dan200.computercraft.api.lua.LuaValues.checkFinite; | ||||
|  | ||||
| /** | ||||
|  * 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, | ||||
|      * errors will still use the given argument index. | ||||
| @@ -28,9 +28,11 @@ public interface IArguments { | ||||
|      */ | ||||
|     IArguments drop( int count ); | ||||
|  | ||||
|     default Object[] getAll() { | ||||
|     default Object[] getAll() | ||||
|     { | ||||
|         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 ); | ||||
|         } | ||||
|         return result; | ||||
| @@ -67,7 +69,8 @@ public interface IArguments { | ||||
|      * @return The argument's value. | ||||
|      * @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 ); | ||||
|     } | ||||
|  | ||||
| @@ -78,9 +81,11 @@ public interface IArguments { | ||||
|      * @return The argument's value. | ||||
|      * @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 ); | ||||
|         if (!(value instanceof Number)) { | ||||
|         if( !(value instanceof Number) ) | ||||
|         { | ||||
|             throw LuaValues.badArgumentOf( index, "number", value ); | ||||
|         } | ||||
|         return LuaValues.checkFiniteNum( index, (Number) value ) | ||||
| @@ -94,7 +99,8 @@ public interface IArguments { | ||||
|      * @return The argument's value. | ||||
|      * @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 ) ); | ||||
|     } | ||||
|  | ||||
| @@ -106,9 +112,11 @@ public interface IArguments { | ||||
|      * @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). | ||||
|      */ | ||||
|     default double getDouble(int index) throws LuaException { | ||||
|     default double getDouble( int index ) throws LuaException | ||||
|     { | ||||
|         Object value = this.get( index ); | ||||
|         if (!(value instanceof Number)) { | ||||
|         if( !(value instanceof Number) ) | ||||
|         { | ||||
|             throw LuaValues.badArgumentOf( index, "number", value ); | ||||
|         } | ||||
|         return ((Number) value).doubleValue(); | ||||
| @@ -121,9 +129,11 @@ public interface IArguments { | ||||
|      * @return The argument's value. | ||||
|      * @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 ); | ||||
|         if (!(value instanceof Boolean)) { | ||||
|         if( !(value instanceof Boolean) ) | ||||
|         { | ||||
|             throw LuaValues.badArgumentOf( index, "boolean", value ); | ||||
|         } | ||||
|         return (Boolean) value; | ||||
| @@ -137,7 +147,8 @@ public interface IArguments { | ||||
|      * @throws LuaException If the value is not a string. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     default ByteBuffer getBytes(int index) throws LuaException { | ||||
|     default ByteBuffer getBytes( int index ) throws LuaException | ||||
|     { | ||||
|         return LuaValues.encode( this.getString( index ) ); | ||||
|     } | ||||
|  | ||||
| @@ -149,9 +160,11 @@ public interface IArguments { | ||||
|      * @throws LuaException If the value is not a string. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     default String getString(int index) throws LuaException { | ||||
|     default String getString( int index ) throws LuaException | ||||
|     { | ||||
|         Object value = this.get( index ); | ||||
|         if (!(value instanceof String)) { | ||||
|         if( !(value instanceof String) ) | ||||
|         { | ||||
|             throw LuaValues.badArgumentOf( index, "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. | ||||
|      */ | ||||
|     @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 ) ); | ||||
|     } | ||||
|  | ||||
| @@ -179,9 +193,11 @@ public interface IArguments { | ||||
|      * @throws LuaException If the value is not a table. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     default Map<?, ?> getTable(int index) throws LuaException { | ||||
|     default Map<?, ?> getTable( int index ) throws LuaException | ||||
|     { | ||||
|         Object value = this.get( index ); | ||||
|         if (!(value instanceof Map)) { | ||||
|         if( !(value instanceof Map) ) | ||||
|         { | ||||
|             throw LuaValues.badArgumentOf( index, "table", 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. | ||||
|      * @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 ); | ||||
|     } | ||||
|  | ||||
| @@ -205,12 +222,15 @@ public interface IArguments { | ||||
|      * @return The argument's value, or {@link Optional#empty()} if not present. | ||||
|      * @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 ); | ||||
|         if (value == null) { | ||||
|         if( value == null ) | ||||
|         { | ||||
|             return Optional.empty(); | ||||
|         } | ||||
|         if (!(value instanceof String)) { | ||||
|         if( !(value instanceof String) ) | ||||
|         { | ||||
|             throw LuaValues.badArgumentOf( index, "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. | ||||
|      */ | ||||
|     @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 ); | ||||
|         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. | ||||
|      * @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 ); | ||||
|     } | ||||
|  | ||||
| @@ -251,12 +273,15 @@ public interface IArguments { | ||||
|      * @throws LuaException If the value is not a number. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     default Optional<Double> optDouble(int index) throws LuaException { | ||||
|     default Optional<Double> optDouble( int index ) throws LuaException | ||||
|     { | ||||
|         Object value = this.get( index ); | ||||
|         if (value == null) { | ||||
|         if( value == null ) | ||||
|         { | ||||
|             return Optional.empty(); | ||||
|         } | ||||
|         if (!(value instanceof Number)) { | ||||
|         if( !(value instanceof Number) ) | ||||
|         { | ||||
|             throw LuaValues.badArgumentOf( index, "number", value ); | ||||
|         } | ||||
|         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. | ||||
|      * @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 ); | ||||
|     } | ||||
|  | ||||
| @@ -282,7 +308,8 @@ public interface IArguments { | ||||
|      * @throws LuaException If the value is not a number. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     default Optional<Integer> optInt(int index) throws LuaException { | ||||
|     default Optional<Integer> optInt( int index ) throws LuaException | ||||
|     { | ||||
|         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. | ||||
|      * @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 ); | ||||
|         if (value == null) { | ||||
|         if( value == null ) | ||||
|         { | ||||
|             return Optional.empty(); | ||||
|         } | ||||
|         if (!(value instanceof Number)) { | ||||
|         if( !(value instanceof Number) ) | ||||
|         { | ||||
|             throw LuaValues.badArgumentOf( 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. | ||||
|      * @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 ); | ||||
|     } | ||||
|  | ||||
| @@ -325,7 +356,8 @@ public interface IArguments { | ||||
|      * @return The argument's value, or {@code def} if none was provided. | ||||
|      * @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 ); | ||||
|     } | ||||
|  | ||||
| @@ -336,9 +368,11 @@ public interface IArguments { | ||||
|      * @return The argument's value, or {@link Optional#empty()} if not present. | ||||
|      * @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 ); | ||||
|         if (value.isPresent()) { | ||||
|         if( value.isPresent() ) | ||||
|         { | ||||
|             LuaValues.checkFiniteNum( index, value.get() ); | ||||
|         } | ||||
|         return value; | ||||
| @@ -352,7 +386,8 @@ public interface IArguments { | ||||
|      * @return The argument's value, or {@code def} if none was provided. | ||||
|      * @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 ); | ||||
|     } | ||||
|  | ||||
| @@ -363,12 +398,15 @@ public interface IArguments { | ||||
|      * @return The argument's value, or {@link Optional#empty()} if not present. | ||||
|      * @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 ); | ||||
|         if (value == null) { | ||||
|         if( value == null ) | ||||
|         { | ||||
|             return Optional.empty(); | ||||
|         } | ||||
|         if (!(value instanceof Boolean)) { | ||||
|         if( !(value instanceof Boolean) ) | ||||
|         { | ||||
|             throw LuaValues.badArgumentOf( index, "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. | ||||
|      * @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 ); | ||||
|     } | ||||
|  | ||||
| @@ -394,7 +433,8 @@ public interface IArguments { | ||||
|      * @return The argument's value, or {@code def} if none was provided. | ||||
|      * @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 ); | ||||
|     } | ||||
|  | ||||
| @@ -405,12 +445,15 @@ public interface IArguments { | ||||
|      * @return The argument's value, or {@link Optional#empty()} if not present. | ||||
|      * @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 ); | ||||
|         if (value == null) { | ||||
|         if( value == null ) | ||||
|         { | ||||
|             return Optional.empty(); | ||||
|         } | ||||
|         if (!(value instanceof Map)) { | ||||
|         if( !(value instanceof Map) ) | ||||
|         { | ||||
|             throw LuaValues.badArgumentOf( index, "map", value ); | ||||
|         } | ||||
|         return Optional.of( (Map<?, ?>) value ); | ||||
|   | ||||
| @@ -6,15 +6,16 @@ | ||||
|  | ||||
| package dan200.computercraft.api.lua; | ||||
|  | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import dan200.computercraft.api.filesystem.IFileSystem; | ||||
| 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. | ||||
|  */ | ||||
| public interface IComputerSystem extends IComputerAccess { | ||||
| public interface IComputerSystem extends IComputerAccess | ||||
| { | ||||
|     /** | ||||
|      * Get the file system for this computer. | ||||
|      * | ||||
|   | ||||
| @@ -6,17 +6,18 @@ | ||||
|  | ||||
| package dan200.computercraft.api.lua; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import dan200.computercraft.api.peripheral.IDynamicPeripheral; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| /** | ||||
|  * 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 | ||||
|  * 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. | ||||
|      * | ||||
|   | ||||
| @@ -18,7 +18,8 @@ import dan200.computercraft.api.ComputerCraftAPI; | ||||
|  * @see 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 | ||||
|      * | ||||
| @@ -31,13 +32,15 @@ public interface ILuaAPI { | ||||
|      * | ||||
|      * 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. | ||||
|      */ | ||||
|     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. | ||||
|      */ | ||||
|     default void shutdown() { | ||||
|     default void shutdown() | ||||
|     { | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,11 +6,11 @@ | ||||
|  | ||||
| package dan200.computercraft.api.lua; | ||||
|  | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
|  | ||||
| /** | ||||
|  * Construct an {@link ILuaAPI} for a specific computer. | ||||
|  * | ||||
| @@ -18,7 +18,8 @@ import dan200.computercraft.api.ComputerCraftAPI; | ||||
|  * @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory) | ||||
|  */ | ||||
| @FunctionalInterface | ||||
| public interface ILuaAPIFactory { | ||||
| public interface ILuaAPIFactory | ||||
| { | ||||
|     /** | ||||
|      * Create a new API instance for a given computer. | ||||
|      * | ||||
|   | ||||
| @@ -13,7 +13,8 @@ import javax.annotation.Nonnull; | ||||
|  * | ||||
|  * @see MethodResult#yield(Object[], ILuaCallback) | ||||
|  */ | ||||
| public interface ILuaCallback { | ||||
| public interface ILuaCallback | ||||
| { | ||||
|     /** | ||||
|      * Resume this coroutine. | ||||
|      * | ||||
|   | ||||
| @@ -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 | ||||
|  * 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 | ||||
|      * need to interact with the world in a thread-safe manner but do not care about the result or you wish to run asynchronously. | ||||
|   | ||||
| @@ -15,7 +15,8 @@ import javax.annotation.Nonnull; | ||||
|  * @see MethodResult#of(Object) | ||||
|  */ | ||||
| @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 | ||||
|      * thread-safe. | ||||
|   | ||||
| @@ -8,7 +8,8 @@ package dan200.computercraft.api.lua; | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| public interface ILuaObject { | ||||
| public interface ILuaObject | ||||
| { | ||||
|     @Nonnull | ||||
|     String[] getMethodNames(); | ||||
|  | ||||
|   | ||||
| @@ -15,7 +15,8 @@ import javax.annotation.Nullable; | ||||
|  * @see ILuaContext#issueMainThreadTask(ILuaTask) | ||||
|  */ | ||||
| @FunctionalInterface | ||||
| public interface ILuaTask { | ||||
| public interface ILuaTask | ||||
| { | ||||
|     /** | ||||
|      * Execute this task. | ||||
|      * | ||||
|   | ||||
| @@ -11,18 +11,21 @@ import javax.annotation.Nullable; | ||||
| /** | ||||
|  * 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 final boolean hasLevel; | ||||
|     private final int level; | ||||
|  | ||||
|     public LuaException(@Nullable String message) { | ||||
|     public LuaException( @Nullable String message ) | ||||
|     { | ||||
|         super( message ); | ||||
|         this.hasLevel = false; | ||||
|         this.level = 1; | ||||
|     } | ||||
|  | ||||
|     public LuaException(@Nullable String message, int level) { | ||||
|     public LuaException( @Nullable String message, int level ) | ||||
|     { | ||||
|         super( message ); | ||||
|         this.hasLevel = true; | ||||
|         this.level = level; | ||||
| @@ -33,7 +36,8 @@ public class LuaException extends Exception { | ||||
|      * | ||||
|      * @return Whether this has an explicit level. | ||||
|      */ | ||||
|     public boolean hasLevel() { | ||||
|     public boolean hasLevel() | ||||
|     { | ||||
|         return this.hasLevel; | ||||
|     } | ||||
|  | ||||
| @@ -42,7 +46,8 @@ public class LuaException extends Exception { | ||||
|      * | ||||
|      * @return The level to raise the error at. | ||||
|      */ | ||||
|     public int getLevel() { | ||||
|     public int getLevel() | ||||
|     { | ||||
|         return this.level; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,17 +6,13 @@ | ||||
|  | ||||
| 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.IPeripheral; | ||||
|  | ||||
| import java.lang.annotation.*; | ||||
| import java.util.Map; | ||||
| import java.util.Optional; | ||||
|  | ||||
| /** | ||||
|  * Used to mark a Java function which is callable from Lua. | ||||
|  * | ||||
| @@ -43,7 +39,8 @@ import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| @Documented | ||||
| @Retention( RetentionPolicy.RUNTIME ) | ||||
| @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. | ||||
|      * | ||||
|   | ||||
| @@ -6,19 +6,20 @@ | ||||
|  | ||||
| package dan200.computercraft.api.lua; | ||||
|  | ||||
| import java.nio.ByteBuffer; | ||||
| import java.util.Map; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
| import java.nio.ByteBuffer; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * Various utility functions for operating with Lua values. | ||||
|  * | ||||
|  * @see IArguments | ||||
|  */ | ||||
| public final class LuaValues { | ||||
|     private LuaValues() { | ||||
| public final class LuaValues | ||||
| { | ||||
|     private LuaValues() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -28,9 +29,11 @@ public final class LuaValues { | ||||
|      * @return The encoded string. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public static ByteBuffer encode(@Nonnull String string) { | ||||
|     public static ByteBuffer encode( @Nonnull String string ) | ||||
|     { | ||||
|         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 ); | ||||
|             chars[i] = c < 256 ? (byte) c : 63; | ||||
|         } | ||||
| @@ -48,7 +51,8 @@ public final class LuaValues { | ||||
|      * @return The constructed exception, which should be thrown immediately. | ||||
|      */ | ||||
|     @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 ) ); | ||||
|     } | ||||
|  | ||||
| @@ -61,7 +65,8 @@ public final class LuaValues { | ||||
|      * @return The constructed exception, which should be thrown immediately. | ||||
|      */ | ||||
|     @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 + ")" ); | ||||
|     } | ||||
|  | ||||
| @@ -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. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public static String getType(@Nullable Object value) { | ||||
|         if (value == null) { | ||||
|     public static String getType( @Nullable Object value ) | ||||
|     { | ||||
|         if( value == null ) | ||||
|         { | ||||
|             return "nil"; | ||||
|         } | ||||
|         if (value instanceof String) { | ||||
|         if( value instanceof String ) | ||||
|         { | ||||
|             return "string"; | ||||
|         } | ||||
|         if (value instanceof Boolean) { | ||||
|         if( value instanceof Boolean ) | ||||
|         { | ||||
|             return "boolean"; | ||||
|         } | ||||
|         if (value instanceof Number) { | ||||
|         if( value instanceof Number ) | ||||
|         { | ||||
|             return "number"; | ||||
|         } | ||||
|         if (value instanceof Map) { | ||||
|         if( value instanceof Map ) | ||||
|         { | ||||
|             return "table"; | ||||
|         } | ||||
|         return "userdata"; | ||||
| @@ -99,7 +110,8 @@ public final class LuaValues { | ||||
|      * @return The input {@code value}. | ||||
|      * @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() ); | ||||
|         return value; | ||||
|     } | ||||
| @@ -112,8 +124,10 @@ public final class LuaValues { | ||||
|      * @return The input {@code value}. | ||||
|      * @throws LuaException If this is not a finite number. | ||||
|      */ | ||||
|     public static double checkFinite(int index, double value) throws LuaException { | ||||
|         if (!Double.isFinite(value)) { | ||||
|     public static double checkFinite( int index, double value ) throws LuaException | ||||
|     { | ||||
|         if( !Double.isFinite( value ) ) | ||||
|         { | ||||
|             throw badArgument( index, "number", getNumericType( value ) ); | ||||
|         } | ||||
|         return value; | ||||
| @@ -127,14 +141,18 @@ public final class LuaValues { | ||||
|      * @return This value's numeric type. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public static String getNumericType(double value) { | ||||
|         if (Double.isNaN(value)) { | ||||
|     public static String getNumericType( double value ) | ||||
|     { | ||||
|         if( Double.isNaN( value ) ) | ||||
|         { | ||||
|             return "nan"; | ||||
|         } | ||||
|         if (value == Double.POSITIVE_INFINITY) { | ||||
|         if( value == Double.POSITIVE_INFINITY ) | ||||
|         { | ||||
|             return "inf"; | ||||
|         } | ||||
|         if (value == Double.NEGATIVE_INFINITY) { | ||||
|         if( value == Double.NEGATIVE_INFINITY ) | ||||
|         { | ||||
|             return "-inf"; | ||||
|         } | ||||
|         return "number"; | ||||
| @@ -150,10 +168,13 @@ public final class LuaValues { | ||||
|      * @return The parsed 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 { | ||||
|         for (T possibility : klass.getEnumConstants()) { | ||||
|     public static <T extends Enum<T>> T checkEnum( int index, Class<T> klass, String value ) throws LuaException | ||||
|     { | ||||
|         for( T possibility : klass.getEnumConstants() ) | ||||
|         { | ||||
|             if( possibility.name() | ||||
|                            .equalsIgnoreCase(value)) { | ||||
|                 .equalsIgnoreCase( value ) ) | ||||
|             { | ||||
|                 return possibility; | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -6,36 +6,38 @@ | ||||
|  | ||||
| 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.util.Collection; | ||||
| import java.util.Map; | ||||
| 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. | ||||
|  * | ||||
|  * 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. | ||||
|  */ | ||||
| public final class MethodResult { | ||||
| public final class MethodResult | ||||
| { | ||||
|     private static final MethodResult empty = new MethodResult( null, null ); | ||||
|  | ||||
|     private final Object[] result; | ||||
|     private final ILuaCallback callback; | ||||
|     private final int adjust; | ||||
|  | ||||
|     private MethodResult(Object[] arguments, ILuaCallback callback) { | ||||
|     private MethodResult( Object[] arguments, ILuaCallback callback ) | ||||
|     { | ||||
|         this.result = arguments; | ||||
|         this.callback = callback; | ||||
|         this.adjust = 0; | ||||
|     } | ||||
|  | ||||
|     private MethodResult(Object[] arguments, ILuaCallback callback, int adjust) { | ||||
|     private MethodResult( Object[] arguments, ILuaCallback callback, int adjust ) | ||||
|     { | ||||
|         this.result = arguments; | ||||
|         this.callback = callback; | ||||
|         this.adjust = adjust; | ||||
| @@ -47,7 +49,8 @@ public final class MethodResult { | ||||
|      * @return A method result which returns immediately with no values. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public static MethodResult of() { | ||||
|     public static MethodResult of() | ||||
|     { | ||||
|         return empty; | ||||
|     } | ||||
|  | ||||
| @@ -64,7 +67,8 @@ public final class MethodResult { | ||||
|      * @return A method result which returns immediately with the given value. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public static MethodResult of(@Nullable Object value) { | ||||
|     public static MethodResult of( @Nullable Object value ) | ||||
|     { | ||||
|         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. | ||||
|      */ | ||||
|     @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 ); | ||||
|     } | ||||
|  | ||||
| @@ -89,10 +94,12 @@ public final class MethodResult { | ||||
|      * @see IComputerAccess#queueEvent(String, Object[]) | ||||
|      */ | ||||
|     @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" ); | ||||
|         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 ); | ||||
|             } | ||||
|             return callback.resume( results ); | ||||
| @@ -109,7 +116,8 @@ public final class MethodResult { | ||||
|      * @see #pullEvent(String, ILuaCallback) | ||||
|      */ | ||||
|     @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" ); | ||||
|         return new MethodResult( new Object[] { filter }, callback ); | ||||
|     } | ||||
| @@ -124,22 +132,26 @@ public final class MethodResult { | ||||
|      * @see #pullEvent(String, ILuaCallback) | ||||
|      */ | ||||
|     @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" ); | ||||
|         return new MethodResult( arguments, callback ); | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     public Object[] getResult() { | ||||
|     public Object[] getResult() | ||||
|     { | ||||
|         return this.result; | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     public ILuaCallback getCallback() { | ||||
|     public ILuaCallback getCallback() | ||||
|     { | ||||
|         return this.callback; | ||||
|     } | ||||
|  | ||||
|     public int getErrorAdjust() { | ||||
|     public int getErrorAdjust() | ||||
|     { | ||||
|         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. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public MethodResult adjustError(int adjust) { | ||||
|         if (adjust < 0) { | ||||
|     public MethodResult adjustError( int adjust ) | ||||
|     { | ||||
|         if( adjust < 0 ) | ||||
|         { | ||||
|             throw new IllegalArgumentException( "cannot adjust by a negative amount" ); | ||||
|         } | ||||
|         if (adjust == 0 || this.callback == null) { | ||||
|         if( adjust == 0 || this.callback == null ) | ||||
|         { | ||||
|             return this; | ||||
|         } | ||||
|         return new MethodResult( this.result, this.callback, this.adjust + adjust ); | ||||
|   | ||||
| @@ -6,42 +6,49 @@ | ||||
|  | ||||
| package dan200.computercraft.api.lua; | ||||
|  | ||||
| import javax.annotation.Nullable; | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
| import java.util.Objects; | ||||
|  | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| /** | ||||
|  * 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 final List<Object> args; | ||||
|  | ||||
|     @Deprecated | ||||
|     @SuppressWarnings( "unused" ) | ||||
|     public ObjectArguments(IArguments arguments) { | ||||
|     public ObjectArguments( IArguments arguments ) | ||||
|     { | ||||
|         throw new IllegalStateException(); | ||||
|     } | ||||
|  | ||||
|     public ObjectArguments(Object... args) { | ||||
|     public ObjectArguments( Object... args ) | ||||
|     { | ||||
|         this.args = Arrays.asList( args ); | ||||
|     } | ||||
|  | ||||
|     public ObjectArguments(List<Object> args) { | ||||
|     public ObjectArguments( List<Object> args ) | ||||
|     { | ||||
|         this.args = Objects.requireNonNull( args ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public IArguments drop(int count) { | ||||
|         if (count < 0) { | ||||
|     public IArguments drop( int count ) | ||||
|     { | ||||
|         if( count < 0 ) | ||||
|         { | ||||
|             throw new IllegalStateException( "count cannot be negative" ); | ||||
|         } | ||||
|         if (count == 0) { | ||||
|         if( count == 0 ) | ||||
|         { | ||||
|             return this; | ||||
|         } | ||||
|         if (count >= this.args.size()) { | ||||
|         if( count >= this.args.size() ) | ||||
|         { | ||||
|             return EMPTY; | ||||
|         } | ||||
|  | ||||
| @@ -49,18 +56,21 @@ public final class ObjectArguments implements IArguments { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Object[] getAll() { | ||||
|     public Object[] getAll() | ||||
|     { | ||||
|         return this.args.toArray(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int count() { | ||||
|     public int count() | ||||
|     { | ||||
|         return this.args.size(); | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     @Override | ||||
|     public Object get(int index) { | ||||
|     public Object get( int index ) | ||||
|     { | ||||
|         return index >= this.args.size() ? null : this.args.get( index ); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,22 +6,22 @@ | ||||
|  | ||||
| package dan200.computercraft.api.media; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import dan200.computercraft.api.filesystem.IMount; | ||||
|  | ||||
| import net.minecraft.item.Item; | ||||
| import net.minecraft.item.ItemStack; | ||||
| import net.minecraft.sound.SoundEvent; | ||||
| 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. | ||||
|  * | ||||
|  * 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. | ||||
|      * | ||||
| @@ -38,7 +38,8 @@ public interface IMedia { | ||||
|      * @param label The string to set the label to. | ||||
|      * @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; | ||||
|     } | ||||
|  | ||||
| @@ -49,7 +50,8 @@ public interface IMedia { | ||||
|      * @return The name, or null if this item does not represent an item with audio. | ||||
|      */ | ||||
|     @Nullable | ||||
|     default String getAudioTitle(@Nonnull ItemStack stack) { | ||||
|     default String getAudioTitle( @Nonnull ItemStack stack ) | ||||
|     { | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| @@ -60,7 +62,8 @@ public interface IMedia { | ||||
|      * @return The name, or null if this item does not represent an item with audio. | ||||
|      */ | ||||
|     @Nullable | ||||
|     default SoundEvent getAudio(@Nonnull ItemStack stack) { | ||||
|     default SoundEvent getAudio( @Nonnull ItemStack stack ) | ||||
|     { | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| @@ -78,7 +81,8 @@ public interface IMedia { | ||||
|      * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(String, String) | ||||
|      */ | ||||
|     @Nullable | ||||
|     default IMount createDataMount(@Nonnull ItemStack stack, @Nonnull World world) { | ||||
|     default IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world ) | ||||
|     { | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,18 +6,19 @@ | ||||
|  | ||||
| package dan200.computercraft.api.media; | ||||
|  | ||||
| import net.minecraft.item.ItemStack; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import net.minecraft.item.ItemStack; | ||||
|  | ||||
| /** | ||||
|  * This interface is used to provide {@link IMedia} implementations for {@link ItemStack}. | ||||
|  * | ||||
|  * @see dan200.computercraft.api.ComputerCraftAPI#registerMediaProvider(IMediaProvider) | ||||
|  */ | ||||
| @FunctionalInterface | ||||
| public interface IMediaProvider { | ||||
| public interface IMediaProvider | ||||
| { | ||||
|     /** | ||||
|      * Produce an IMedia implementation from an ItemStack. | ||||
|      * | ||||
|   | ||||
| @@ -14,7 +14,8 @@ import javax.annotation.Nonnull; | ||||
|  * @see Packet | ||||
|  * @see IPacketReceiver | ||||
|  */ | ||||
| public interface IPacketNetwork { | ||||
| public interface IPacketNetwork | ||||
| { | ||||
|     /** | ||||
|      * Add a receiver to the network. | ||||
|      * | ||||
|   | ||||
| @@ -6,15 +6,16 @@ | ||||
|  | ||||
| package dan200.computercraft.api.network; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import net.minecraft.util.math.Vec3d; | ||||
| import net.minecraft.world.World; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| /** | ||||
|  * 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. | ||||
|      * | ||||
|   | ||||
| @@ -6,15 +6,16 @@ | ||||
|  | ||||
| package dan200.computercraft.api.network; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import net.minecraft.util.math.Vec3d; | ||||
| import net.minecraft.world.World; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| /** | ||||
|  * 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. | ||||
|      * | ||||
|   | ||||
| @@ -6,10 +6,9 @@ | ||||
|  | ||||
| package dan200.computercraft.api.network; | ||||
|  | ||||
| import java.util.Objects; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
| import java.util.Objects; | ||||
|  | ||||
| /** | ||||
|  * 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#receiveSameDimension(Packet, double) | ||||
|  */ | ||||
| public class Packet { | ||||
| public class Packet | ||||
| { | ||||
|     private final int channel; | ||||
|     private final int replyChannel; | ||||
|     private final Object payload; | ||||
| @@ -36,7 +36,8 @@ public class Packet { | ||||
|      *                     call. | ||||
|      * @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" ); | ||||
|  | ||||
|         this.channel = channel; | ||||
| @@ -50,7 +51,8 @@ public class Packet { | ||||
|      * | ||||
|      * @return This packet's channel. | ||||
|      */ | ||||
|     public int getChannel() { | ||||
|     public int getChannel() | ||||
|     { | ||||
|         return this.channel; | ||||
|     } | ||||
|  | ||||
| @@ -59,7 +61,8 @@ public class Packet { | ||||
|      * | ||||
|      * @return This channel to reply on. | ||||
|      */ | ||||
|     public int getReplyChannel() { | ||||
|     public int getReplyChannel() | ||||
|     { | ||||
|         return this.replyChannel; | ||||
|     } | ||||
|  | ||||
| @@ -69,7 +72,8 @@ public class Packet { | ||||
|      * @return The packet's payload | ||||
|      */ | ||||
|     @Nullable | ||||
|     public Object getPayload() { | ||||
|     public Object getPayload() | ||||
|     { | ||||
|         return this.payload; | ||||
|     } | ||||
|  | ||||
| @@ -79,12 +83,14 @@ public class Packet { | ||||
|      * @return The sending object. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public IPacketSender getSender() { | ||||
|     public IPacketSender getSender() | ||||
|     { | ||||
|         return this.sender; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|     public int hashCode() | ||||
|     { | ||||
|         int result; | ||||
|         result = this.channel; | ||||
|         result = 31 * result + this.replyChannel; | ||||
| @@ -94,23 +100,29 @@ public class Packet { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean equals(Object o) { | ||||
|         if (this == o) { | ||||
|     public boolean equals( Object o ) | ||||
|     { | ||||
|         if( this == o ) | ||||
|         { | ||||
|             return true; | ||||
|         } | ||||
|         if (o == null || this.getClass() != o.getClass()) { | ||||
|         if( o == null || this.getClass() != o.getClass() ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         Packet packet = (Packet) o; | ||||
|  | ||||
|         if (this.channel != packet.channel) { | ||||
|         if( this.channel != packet.channel ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|         if (this.replyChannel != packet.replyChannel) { | ||||
|         if( this.replyChannel != packet.replyChannel ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|         if (!Objects.equals(this.payload, packet.payload)) { | ||||
|         if( !Objects.equals( this.payload, packet.payload ) ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|         return this.sender.equals( packet.sender ); | ||||
|   | ||||
| @@ -6,10 +6,10 @@ | ||||
|  | ||||
| package dan200.computercraft.api.network.wired; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| /** | ||||
|  * 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 | ||||
|  * 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. | ||||
|      * | ||||
|      * @param change The change which occurred. | ||||
|      * @see IWiredNetworkChange | ||||
|      */ | ||||
|     default void networkChanged(@Nonnull IWiredNetworkChange change) { | ||||
|     default void networkChanged( @Nonnull IWiredNetworkChange change ) | ||||
|     { | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,11 +6,10 @@ | ||||
|  | ||||
| package dan200.computercraft.api.network.wired; | ||||
|  | ||||
| import java.util.Map; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * 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() | ||||
|  */ | ||||
| public interface IWiredNetwork { | ||||
| public interface IWiredNetwork | ||||
| { | ||||
|     /** | ||||
|      * Create a connection between two nodes. | ||||
|      * | ||||
|   | ||||
| @@ -6,18 +6,18 @@ | ||||
|  | ||||
| package dan200.computercraft.api.network.wired; | ||||
|  | ||||
| import java.util.Map; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * Represents a change to the objects on a wired network. | ||||
|  * | ||||
|  * @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 | ||||
|      * peripheral. | ||||
|   | ||||
| @@ -6,13 +6,12 @@ | ||||
|  | ||||
| package dan200.computercraft.api.network.wired; | ||||
|  | ||||
| import java.util.Map; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import dan200.computercraft.api.network.IPacketNetwork; | ||||
| 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. | ||||
|  * | ||||
| @@ -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. | ||||
|  */ | ||||
| public interface IWiredNode extends IPacketNetwork { | ||||
| public interface IWiredNode extends IPacketNetwork | ||||
| { | ||||
|     /** | ||||
|      * The associated element for this network node. | ||||
|      * | ||||
| @@ -44,7 +44,8 @@ public interface IWiredNode extends IPacketNetwork { | ||||
|      * @see IWiredNetwork#connect(IWiredNode, IWiredNode) | ||||
|      * @see IWiredNode#disconnectFrom(IWiredNode) | ||||
|      */ | ||||
|     default boolean connectTo(@Nonnull IWiredNode node) { | ||||
|     default boolean connectTo( @Nonnull IWiredNode node ) | ||||
|     { | ||||
|         return this.getNetwork().connect( this, node ); | ||||
|     } | ||||
|  | ||||
| @@ -69,7 +70,8 @@ public interface IWiredNode extends IPacketNetwork { | ||||
|      * @see IWiredNetwork#disconnect(IWiredNode, IWiredNode) | ||||
|      * @see IWiredNode#connectTo(IWiredNode) | ||||
|      */ | ||||
|     default boolean disconnectFrom(@Nonnull IWiredNode node) { | ||||
|     default boolean disconnectFrom( @Nonnull IWiredNode 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. | ||||
|      * @see IWiredNetwork#remove(IWiredNode) | ||||
|      */ | ||||
|     default boolean remove() { | ||||
|     default boolean remove() | ||||
|     { | ||||
|         return this.getNetwork().remove( this ); | ||||
|     } | ||||
|  | ||||
| @@ -94,7 +97,8 @@ public interface IWiredNode extends IPacketNetwork { | ||||
|      * @param peripherals The new peripherals for this node. | ||||
|      * @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 ); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,16 +6,17 @@ | ||||
|  | ||||
| package dan200.computercraft.api.network.wired; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import dan200.computercraft.api.network.IPacketSender; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| /** | ||||
|  * 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. | ||||
|  */ | ||||
| public interface IWiredSender extends IPacketSender { | ||||
| public interface IWiredSender extends IPacketSender | ||||
| { | ||||
|     /** | ||||
|      * The node in the network representing this object. | ||||
|      * | ||||
|   | ||||
| @@ -6,11 +6,6 @@ | ||||
|  | ||||
| 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.filesystem.IMount; | ||||
| 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.ILuaTask; | ||||
| import dan200.computercraft.api.lua.MethodResult; | ||||
|  | ||||
| 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 | ||||
|  * 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. | ||||
|      * | ||||
| @@ -42,7 +41,8 @@ public interface IComputerAccess { | ||||
|      * @see IMount | ||||
|      */ | ||||
|     @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() ); | ||||
|     } | ||||
|  | ||||
| @@ -91,7 +91,8 @@ public interface IComputerAccess { | ||||
|      * @see IMount | ||||
|      */ | ||||
|     @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() ); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -6,14 +6,9 @@ | ||||
|  | ||||
| package dan200.computercraft.api.peripheral; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import dan200.computercraft.api.lua.*; | ||||
|  | ||||
| import dan200.computercraft.api.lua.IArguments; | ||||
| 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; | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| /** | ||||
|  * 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} | ||||
|  * 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 not change when called multiple times. | ||||
|   | ||||
| @@ -6,11 +6,11 @@ | ||||
|  | ||||
| package dan200.computercraft.api.peripheral; | ||||
|  | ||||
| import dan200.computercraft.api.lua.LuaFunction; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import dan200.computercraft.api.lua.LuaFunction; | ||||
|  | ||||
| /** | ||||
|  * 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}. | ||||
|  */ | ||||
| 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()} | ||||
|      * | ||||
| @@ -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. | ||||
|      * @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. | ||||
|      * @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 | ||||
|      */ | ||||
|     @Nullable | ||||
|     default Object getTarget() { | ||||
|     default Object getTarget() | ||||
|     { | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -6,15 +6,14 @@ | ||||
|  | ||||
| package dan200.computercraft.api.peripheral; | ||||
|  | ||||
| import java.util.Optional; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import net.minecraft.block.entity.BlockEntity; | ||||
| import net.minecraft.util.math.BlockPos; | ||||
| import net.minecraft.util.math.Direction; | ||||
| import net.minecraft.world.World; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import java.util.Optional; | ||||
|  | ||||
| /** | ||||
|  * 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) | ||||
|  */ | ||||
| @FunctionalInterface | ||||
| public interface IPeripheralProvider { | ||||
| public interface IPeripheralProvider | ||||
| { | ||||
|     /** | ||||
|      * Produce an peripheral implementation from a block location. | ||||
|      * | ||||
|   | ||||
| @@ -5,19 +5,20 @@ | ||||
|  */ | ||||
| package dan200.computercraft.api.peripheral; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import net.minecraft.util.math.BlockPos; | ||||
| import net.minecraft.util.math.Direction; | ||||
| 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. | ||||
|  * | ||||
|  * 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}. | ||||
|      * | ||||
|   | ||||
| @@ -6,11 +6,10 @@ | ||||
|  | ||||
| package dan200.computercraft.api.peripheral; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import java.util.Objects; | ||||
| 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 | ||||
|  * processing time. | ||||
| @@ -25,7 +24,8 @@ import javax.annotation.Nonnull; | ||||
|  * | ||||
|  * @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. | ||||
|      * | ||||
| @@ -42,16 +42,21 @@ public interface IWorkMonitor { | ||||
|      * @param runnable The task to run. | ||||
|      * @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" ); | ||||
|         if (!this.canWork()) { | ||||
|         if( !this.canWork() ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         long start = System.nanoTime(); | ||||
|         try { | ||||
|         try | ||||
|         { | ||||
|             runnable.run(); | ||||
|         } finally { | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             this.trackWork( System.nanoTime() - start, TimeUnit.NANOSECONDS ); | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -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. | ||||
|  */ | ||||
| public class NotAttachedException extends IllegalStateException { | ||||
| public class NotAttachedException extends IllegalStateException | ||||
| { | ||||
|     private static final long serialVersionUID = 1221244785535553536L; | ||||
|  | ||||
|     public NotAttachedException() { | ||||
|     public NotAttachedException() | ||||
|     { | ||||
|         super( "You are not attached to this computer" ); | ||||
|     } | ||||
|  | ||||
|     public NotAttachedException(String s) { | ||||
|     public NotAttachedException( String s ) | ||||
|     { | ||||
|         super( s ); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,34 +6,38 @@ | ||||
|  | ||||
| package dan200.computercraft.api.pocket; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import net.minecraft.item.ItemConvertible; | ||||
| import net.minecraft.item.ItemStack; | ||||
| import net.minecraft.util.Identifier; | ||||
| import net.minecraft.util.Util; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| /** | ||||
|  * A base class for {@link IPocketUpgrade}s. | ||||
|  * | ||||
|  * 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 String adjective; | ||||
|     private final ItemStack stack; | ||||
|  | ||||
|     protected AbstractPocketUpgrade(Identifier id, ItemConvertible item) { | ||||
|     protected AbstractPocketUpgrade( Identifier id, ItemConvertible 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.adjective = adjective; | ||||
|         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.adjective = adjective; | ||||
|         this.stack = stack; | ||||
| @@ -42,19 +46,22 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade { | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public final Identifier getUpgradeID() { | ||||
|     public final Identifier getUpgradeID() | ||||
|     { | ||||
|         return this.id; | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public final String getUnlocalisedAdjective() { | ||||
|     public final String getUnlocalisedAdjective() | ||||
|     { | ||||
|         return this.adjective; | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public final ItemStack getCraftingItem() { | ||||
|     public final ItemStack getCraftingItem() | ||||
|     { | ||||
|         return this.stack; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,21 +6,20 @@ | ||||
|  | ||||
| package dan200.computercraft.api.pocket; | ||||
|  | ||||
| import java.util.Map; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
|  | ||||
| import net.minecraft.entity.Entity; | ||||
| import net.minecraft.nbt.CompoundTag; | ||||
| import net.minecraft.util.Identifier; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * Wrapper class for pocket computers. | ||||
|  */ | ||||
| public interface IPocketAccess { | ||||
| public interface IPocketAccess | ||||
| { | ||||
|     /** | ||||
|      * Gets the entity holding this item. | ||||
|      * | ||||
|   | ||||
| @@ -6,15 +6,14 @@ | ||||
|  | ||||
| package dan200.computercraft.api.pocket; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.IUpgradeBase; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
|  | ||||
| import net.minecraft.world.World; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| /** | ||||
|  * Additional peripherals for pocket computers. | ||||
|  * | ||||
| @@ -42,7 +41,8 @@ public interface IPocketUpgrade extends IUpgradeBase | ||||
|      * @param peripheral The peripheral for this upgrade. | ||||
|      * @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. | ||||
|      * @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; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,19 +6,20 @@ | ||||
|  | ||||
| package dan200.computercraft.api.redstone; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import net.minecraft.util.math.BlockPos; | ||||
| import net.minecraft.util.math.Direction; | ||||
| import net.minecraft.world.World; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| /** | ||||
|  * This interface is used to provide bundled redstone output for blocks. | ||||
|  * | ||||
|  * @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider) | ||||
|  */ | ||||
| @FunctionalInterface | ||||
| public interface IBundledRedstoneProvider { | ||||
| public interface IBundledRedstoneProvider | ||||
| { | ||||
|     /** | ||||
|      * Produce an bundled redstone output from a block location. | ||||
|      * | ||||
|   | ||||
| @@ -6,65 +6,74 @@ | ||||
|  | ||||
| package dan200.computercraft.api.turtle; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import net.minecraft.item.ItemConvertible; | ||||
| import net.minecraft.item.ItemStack; | ||||
| import net.minecraft.util.Identifier; | ||||
| import net.minecraft.util.Util; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| /** | ||||
|  * A base class for {@link ITurtleUpgrade}s. | ||||
|  * | ||||
|  * 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 TurtleUpgradeType type; | ||||
|     private final String adjective; | ||||
|     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 ) ); | ||||
|     } | ||||
|  | ||||
|     protected AbstractTurtleUpgrade(Identifier id, TurtleUpgradeType type, String adjective, ItemStack stack) { | ||||
|     protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemStack stack ) | ||||
|     { | ||||
|         this.id = id; | ||||
|         this.type = type; | ||||
|         this.adjective = adjective; | ||||
|         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 ) ); | ||||
|     } | ||||
|  | ||||
|     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 ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public final Identifier getUpgradeID() { | ||||
|     public final Identifier getUpgradeID() | ||||
|     { | ||||
|         return this.id; | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public final String getUnlocalisedAdjective() { | ||||
|     public final String getUnlocalisedAdjective() | ||||
|     { | ||||
|         return this.adjective; | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public final TurtleUpgradeType getType() { | ||||
|     public final TurtleUpgradeType getType() | ||||
|     { | ||||
|         return this.type; | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public final ItemStack getCraftingItem() { | ||||
|     public final ItemStack getCraftingItem() | ||||
|     { | ||||
|         return this.stack; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -5,18 +5,10 @@ | ||||
|  */ | ||||
| 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 io.netty.channel.ChannelHandlerContext; | ||||
| import io.netty.util.concurrent.Future; | ||||
| import io.netty.util.concurrent.GenericFutureListener; | ||||
|  | ||||
| import net.minecraft.block.entity.CommandBlockBlockEntity; | ||||
| import net.minecraft.block.entity.SignBlockEntity; | ||||
| 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.inventory.Inventory; | ||||
| import net.minecraft.item.ItemStack; | ||||
| import net.minecraft.network.ClientConnection; | ||||
| import net.minecraft.network.MessageType; | ||||
| import net.minecraft.network.NetworkSide; | ||||
| import net.minecraft.network.NetworkState; | ||||
| import net.minecraft.network.Packet; | ||||
| import net.minecraft.network.*; | ||||
| import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket; | ||||
| import net.minecraft.network.packet.c2s.play.VehicleMoveC2SPacket; | ||||
| import net.minecraft.recipe.Recipe; | ||||
| @@ -50,13 +38,21 @@ import net.minecraft.util.math.Vec3d; | ||||
| import net.minecraft.village.TradeOfferList; | ||||
| 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. | ||||
|  * | ||||
|  * 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 FakePlayer(ServerWorld world, GameProfile gameProfile) { | ||||
| public class FakePlayer extends ServerPlayerEntity | ||||
| { | ||||
|     public FakePlayer( ServerWorld world, GameProfile gameProfile ) | ||||
|     { | ||||
|         super( world.getServer(), world, gameProfile, new ServerPlayerInteractionManager( world ) ); | ||||
|         this.networkHandler = new FakeNetHandler( this ); | ||||
|     } | ||||
| @@ -78,17 +74,20 @@ public class FakePlayer extends ServerPlayerEntity { | ||||
|     public void onDeath( DamageSource damage ) { } | ||||
|  | ||||
|     @Override | ||||
|     public Entity moveToWorld(ServerWorld destination) { | ||||
|     public Entity moveToWorld( ServerWorld destination ) | ||||
|     { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void wakeUp(boolean bl, boolean updateSleepingPlayers) { | ||||
|     public void wakeUp( boolean bl, boolean updateSleepingPlayers ) | ||||
|     { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean startRiding(Entity entity, boolean flag) { | ||||
|     public boolean startRiding( Entity entity, boolean flag ) | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| @@ -99,7 +98,8 @@ public class FakePlayer extends ServerPlayerEntity { | ||||
|     public void openEditSignScreen( SignBlockEntity tile ) { } | ||||
|  | ||||
|     @Override | ||||
|     public OptionalInt openHandledScreen(@Nullable NamedScreenHandlerFactory container) { | ||||
|     public OptionalInt openHandledScreen( @Nullable NamedScreenHandlerFactory container ) | ||||
|     { | ||||
|         return OptionalInt.empty(); | ||||
|     } | ||||
|  | ||||
| @@ -131,13 +131,15 @@ public class FakePlayer extends ServerPlayerEntity { | ||||
|     public void updateCursorStack() { } | ||||
|  | ||||
|     @Override | ||||
|     public int unlockRecipes(Collection<Recipe<?>> recipes) { | ||||
|     public int unlockRecipes( Collection<Recipe<?>> recipes ) | ||||
|     { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     // Indirect | ||||
|     @Override | ||||
|     public int lockRecipes(Collection<Recipe<?>> recipes) { | ||||
|     public int lockRecipes( Collection<Recipe<?>> recipes ) | ||||
|     { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
| @@ -169,12 +171,14 @@ public class FakePlayer extends ServerPlayerEntity { | ||||
|     public void setGameMode( GameMode gameMode ) { } | ||||
|  | ||||
|     @Override | ||||
|     public void sendMessage(Text message, MessageType type, UUID senderUuid) { | ||||
|     public void sendMessage( Text message, MessageType type, UUID senderUuid ) | ||||
|     { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getIp() { | ||||
|     public String getIp() | ||||
|     { | ||||
|         return "[Fake Player]"; | ||||
|     } | ||||
|  | ||||
| @@ -199,8 +203,10 @@ public class FakePlayer extends ServerPlayerEntity { | ||||
|     @Override | ||||
|     public void playSound( SoundEvent soundEvent, SoundCategory soundCategory, float volume, float pitch ) { } | ||||
|  | ||||
|     private static class FakeNetHandler extends ServerPlayNetworkHandler { | ||||
|         FakeNetHandler(ServerPlayerEntity player) { | ||||
|     private static class FakeNetHandler extends ServerPlayNetworkHandler | ||||
|     { | ||||
|         FakeNetHandler( ServerPlayerEntity 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 ) { } | ||||
|     } | ||||
|  | ||||
|     private static class FakeConnection extends ClientConnection { | ||||
|         FakeConnection() { | ||||
|     private static class FakeConnection extends ClientConnection | ||||
|     { | ||||
|         FakeConnection() | ||||
|         { | ||||
|             super( NetworkSide.CLIENTBOUND ); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void channelActive(ChannelHandlerContext active) { | ||||
|         public void channelActive( ChannelHandlerContext active ) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void setState(NetworkState state) { | ||||
|         public void setState( NetworkState state ) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void exceptionCaught(ChannelHandlerContext context, Throwable err) { | ||||
|         public void exceptionCaught( ChannelHandlerContext context, Throwable err ) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         protected void channelRead0(ChannelHandlerContext context, Packet<?> packet) { | ||||
|         protected void channelRead0( ChannelHandlerContext context, Packet<?> packet ) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         @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 | ||||
|         public void tick() { | ||||
|         public void tick() | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void disconnect(Text message) { | ||||
|         public void disconnect( Text message ) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void setupEncryption(Cipher cipher, Cipher cipher2) { | ||||
|         public void setupEncryption( Cipher cipher, Cipher cipher2 ) | ||||
|         { | ||||
|             super.setupEncryption( cipher, cipher2 ); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void disableAutoRead() { | ||||
|         public void disableAutoRead() | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void setCompressionThreshold(int size) { | ||||
|         public void setCompressionThreshold( int size ) | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,15 +6,11 @@ | ||||
|  | ||||
| package dan200.computercraft.api.turtle; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import com.mojang.authlib.GameProfile; | ||||
| import dan200.computercraft.api.lua.ILuaCallback; | ||||
| import dan200.computercraft.api.lua.MethodResult; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| import dan200.computercraft.shared.util.ItemStorage; | ||||
|  | ||||
| import net.minecraft.inventory.Inventory; | ||||
| import net.minecraft.nbt.CompoundTag; | ||||
| 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.world.World; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| /** | ||||
|  * 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}. | ||||
|  */ | ||||
| public interface ITurtleAccess { | ||||
| public interface ITurtleAccess | ||||
| { | ||||
|     /** | ||||
|      * Returns the world in which the turtle resides. | ||||
|      * | ||||
| @@ -265,7 +265,8 @@ public interface ITurtleAccess { | ||||
|      */ | ||||
|     void updateUpgradeNBTData( @Nonnull TurtleSide side ); | ||||
|  | ||||
|     default ItemStorage getItemHandler() { | ||||
|     default ItemStorage getItemHandler() | ||||
|     { | ||||
|         return ItemStorage.wrap( this.getInventory() ); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -14,7 +14,8 @@ import javax.annotation.Nonnull; | ||||
|  * @see ITurtleAccess#executeCommand(ITurtleCommand) | ||||
|  */ | ||||
| @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. | ||||
|      * | ||||
|   | ||||
| @@ -6,18 +6,16 @@ | ||||
|  | ||||
| package dan200.computercraft.api.turtle; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.IUpgradeBase; | ||||
| import dan200.computercraft.api.client.TransformedModel; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
|  | ||||
| import net.minecraft.util.math.Direction; | ||||
|  | ||||
| import net.fabricmc.api.EnvType; | ||||
| 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. | ||||
| @@ -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. | ||||
|      */ | ||||
|     @Nullable | ||||
|     default IPeripheral createPeripheral(@Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side) { | ||||
|     default IPeripheral createPeripheral( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side ) | ||||
|     { | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| @@ -63,7 +62,8 @@ public interface ITurtleUpgrade extends IUpgradeBase | ||||
|      * this method is not expected to be called. | ||||
|      */ | ||||
|     @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(); | ||||
|     } | ||||
|  | ||||
| @@ -84,6 +84,7 @@ public interface ITurtleUpgrade extends IUpgradeBase | ||||
|      * @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. | ||||
|      */ | ||||
|     default void update(@Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side) { | ||||
|     default void update( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side ) | ||||
|     { | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -13,7 +13,8 @@ package dan200.computercraft.api.turtle; | ||||
|  * | ||||
|  * @see ITurtleAccess#playAnimation(TurtleAnimation) | ||||
|  */ | ||||
| public enum TurtleAnimation { | ||||
| public enum TurtleAnimation | ||||
| { | ||||
|     /** | ||||
|      * An animation which does nothing. This takes no time to complete. | ||||
|      * | ||||
|   | ||||
| @@ -15,14 +15,16 @@ import javax.annotation.Nullable; | ||||
|  * @see ITurtleCommand#execute(ITurtleAccess) | ||||
|  * @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_FAILURE = new TurtleCommandResult( false, null, null ); | ||||
|     private final boolean success; | ||||
|     private final String errorMessage; | ||||
|     private final Object[] results; | ||||
|  | ||||
|     private TurtleCommandResult(boolean success, String errorMessage, Object[] results) { | ||||
|     private TurtleCommandResult( boolean success, String errorMessage, Object[] results ) | ||||
|     { | ||||
|         this.success = success; | ||||
|         this.errorMessage = errorMessage; | ||||
|         this.results = results; | ||||
| @@ -34,7 +36,8 @@ public final class TurtleCommandResult { | ||||
|      * @return A successful command result with no values. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public static TurtleCommandResult success() { | ||||
|     public static TurtleCommandResult success() | ||||
|     { | ||||
|         return EMPTY_SUCCESS; | ||||
|     } | ||||
|  | ||||
| @@ -45,8 +48,10 @@ public final class TurtleCommandResult { | ||||
|      * @return A successful command result with the given values. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public static TurtleCommandResult success(@Nullable Object[] results) { | ||||
|         if (results == null || results.length == 0) { | ||||
|     public static TurtleCommandResult success( @Nullable Object[] results ) | ||||
|     { | ||||
|         if( results == null || results.length == 0 ) | ||||
|         { | ||||
|             return EMPTY_SUCCESS; | ||||
|         } | ||||
|         return new TurtleCommandResult( true, null, results ); | ||||
| @@ -58,7 +63,8 @@ public final class TurtleCommandResult { | ||||
|      * @return A failed command result with no message. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public static TurtleCommandResult failure() { | ||||
|     public static TurtleCommandResult failure() | ||||
|     { | ||||
|         return EMPTY_FAILURE; | ||||
|     } | ||||
|  | ||||
| @@ -69,8 +75,10 @@ public final class TurtleCommandResult { | ||||
|      * @return A failed command result with a message. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public static TurtleCommandResult failure(@Nullable String errorMessage) { | ||||
|         if (errorMessage == null) { | ||||
|     public static TurtleCommandResult failure( @Nullable String errorMessage ) | ||||
|     { | ||||
|         if( errorMessage == null ) | ||||
|         { | ||||
|             return EMPTY_FAILURE; | ||||
|         } | ||||
|         return new TurtleCommandResult( false, errorMessage, null ); | ||||
| @@ -81,7 +89,8 @@ public final class TurtleCommandResult { | ||||
|      * | ||||
|      * @return If the command was successful. | ||||
|      */ | ||||
|     public boolean isSuccess() { | ||||
|     public boolean isSuccess() | ||||
|     { | ||||
|         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. | ||||
|      */ | ||||
|     @Nullable | ||||
|     public String getErrorMessage() { | ||||
|     public String getErrorMessage() | ||||
|     { | ||||
|         return this.errorMessage; | ||||
|     } | ||||
|  | ||||
| @@ -101,7 +111,8 @@ public final class TurtleCommandResult { | ||||
|      * @return The command's result, or {@code null} if it was a failure. | ||||
|      */ | ||||
|     @Nullable | ||||
|     public Object[] getResults() { | ||||
|     public Object[] getResults() | ||||
|     { | ||||
|         return this.results; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -9,7 +9,8 @@ package dan200.computercraft.api.turtle; | ||||
| /** | ||||
|  * 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). | ||||
|      */ | ||||
|   | ||||
| @@ -11,7 +11,8 @@ package dan200.computercraft.api.turtle; | ||||
|  * | ||||
|  * @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 | ||||
|      * pickaxe or sword on Mining and Melee turtles). | ||||
| @@ -30,11 +31,13 @@ public enum TurtleUpgradeType { | ||||
|      */ | ||||
|     BOTH; | ||||
|  | ||||
|     public boolean isTool() { | ||||
|     public boolean isTool() | ||||
|     { | ||||
|         return this == TOOL || this == BOTH; | ||||
|     } | ||||
|  | ||||
|     public boolean isPeripheral() { | ||||
|     public boolean isPeripheral() | ||||
|     { | ||||
|         return this == PERIPHERAL || this == BOTH; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -12,7 +12,8 @@ package dan200.computercraft.api.turtle; | ||||
|  * @see ITurtleUpgrade#getType() | ||||
|  * @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()}. | ||||
|      */ | ||||
|   | ||||
| @@ -11,7 +11,8 @@ package dan200.computercraft.api.turtle.event; | ||||
|  * | ||||
|  * @see TurtleActionEvent | ||||
|  */ | ||||
| public enum TurtleAction { | ||||
| public enum TurtleAction | ||||
| { | ||||
|     /** | ||||
|      * A turtle moves to a new position. | ||||
|      * | ||||
|   | ||||
| @@ -6,30 +6,32 @@ | ||||
|  | ||||
| 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.Nullable; | ||||
|  | ||||
| import dan200.computercraft.api.turtle.ITurtleAccess; | ||||
| import dan200.computercraft.api.turtle.TurtleCommandResult; | ||||
| import java.util.Objects; | ||||
|  | ||||
| /** | ||||
|  * 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 String failureMessage; | ||||
|     private boolean cancelled = false; | ||||
|  | ||||
|     public TurtleActionEvent(@Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action) { | ||||
|     public TurtleActionEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action ) | ||||
|     { | ||||
|         super( turtle ); | ||||
|  | ||||
|         Objects.requireNonNull( action, "action cannot be null" ); | ||||
|         this.action = action; | ||||
|     } | ||||
|  | ||||
|     public TurtleAction getAction() { | ||||
|     public TurtleAction getAction() | ||||
|     { | ||||
|         return this.action; | ||||
|     } | ||||
|  | ||||
| @@ -43,7 +45,8 @@ public class TurtleActionEvent extends TurtleEvent { | ||||
|      * @deprecated Use {@link #setCanceled(boolean, String)} instead. | ||||
|      */ | ||||
|     @Deprecated | ||||
|     public void setCanceled(boolean cancel) { | ||||
|     public void setCanceled( boolean cancel ) | ||||
|     { | ||||
|         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. | ||||
|      * @see TurtleCommandResult#failure(String) | ||||
|      */ | ||||
|     public void setCanceled(boolean cancel, @Nullable String failureMessage) { | ||||
|     public void setCanceled( boolean cancel, @Nullable String failureMessage ) | ||||
|     { | ||||
|         this.cancelled = true; | ||||
|         this.failureMessage = cancel ? failureMessage : null; | ||||
|     } | ||||
| @@ -69,11 +73,13 @@ public class TurtleActionEvent extends TurtleEvent { | ||||
|      * @see #setCanceled(boolean, String) | ||||
|      */ | ||||
|     @Nullable | ||||
|     public String getFailureMessage() { | ||||
|     public String getFailureMessage() | ||||
|     { | ||||
|         return this.failureMessage; | ||||
|     } | ||||
|  | ||||
|     public boolean isCancelled() { | ||||
|     public boolean isCancelled() | ||||
|     { | ||||
|         return this.cancelled; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,29 +6,29 @@ | ||||
|  | ||||
| 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.ITurtleAccess; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.api.turtle.TurtleSide; | ||||
|  | ||||
| import net.minecraft.entity.Entity; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import java.util.Objects; | ||||
|  | ||||
| /** | ||||
|  * Fired when a turtle attempts to attack an entity. | ||||
|  * | ||||
|  * @see TurtleAction#ATTACK | ||||
|  */ | ||||
| public class TurtleAttackEvent extends TurtlePlayerEvent { | ||||
| public class TurtleAttackEvent extends TurtlePlayerEvent | ||||
| { | ||||
|     private final Entity target; | ||||
|     private final ITurtleUpgrade upgrade; | ||||
|     private final TurtleSide side; | ||||
|  | ||||
|     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 ); | ||||
|         Objects.requireNonNull( target, "target cannot be null" ); | ||||
|         Objects.requireNonNull( upgrade, "upgrade cannot be null" ); | ||||
| @@ -44,7 +44,8 @@ public class TurtleAttackEvent extends TurtlePlayerEvent { | ||||
|      * @return The entity being attacked. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public Entity getTarget() { | ||||
|     public Entity getTarget() | ||||
|     { | ||||
|         return this.target; | ||||
|     } | ||||
|  | ||||
| @@ -54,7 +55,8 @@ public class TurtleAttackEvent extends TurtlePlayerEvent { | ||||
|      * @return The upgrade responsible for attacking. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public ITurtleUpgrade getUpgrade() { | ||||
|     public ITurtleUpgrade getUpgrade() | ||||
|     { | ||||
|         return this.upgrade; | ||||
|     } | ||||
|  | ||||
| @@ -64,7 +66,8 @@ public class TurtleAttackEvent extends TurtlePlayerEvent { | ||||
|      * @return The upgrade's side. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public TurtleSide getSide() { | ||||
|     public TurtleSide getSide() | ||||
|     { | ||||
|         return this.side; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,22 +6,20 @@ | ||||
|  | ||||
| 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.turtle.FakePlayer; | ||||
| import dan200.computercraft.api.turtle.ITurtleAccess; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.api.turtle.TurtleSide; | ||||
|  | ||||
| import net.minecraft.block.BlockState; | ||||
| import net.minecraft.item.ItemStack; | ||||
| import net.minecraft.util.math.BlockPos; | ||||
| 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. | ||||
|  * | ||||
| @@ -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. | ||||
|  */ | ||||
| public abstract class TurtleBlockEvent extends TurtlePlayerEvent { | ||||
| public abstract class TurtleBlockEvent extends TurtlePlayerEvent | ||||
| { | ||||
|     private final World world; | ||||
|     private final BlockPos pos; | ||||
|  | ||||
|     protected TurtleBlockEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull World world, | ||||
|                                @Nonnull BlockPos pos) { | ||||
|                                 @Nonnull BlockPos pos ) | ||||
|     { | ||||
|         super( turtle, action, player ); | ||||
|  | ||||
|         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. | ||||
|      */ | ||||
|     public World getWorld() { | ||||
|     public World getWorld() | ||||
|     { | ||||
|         return this.world; | ||||
|     } | ||||
|  | ||||
| @@ -59,7 +60,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent { | ||||
|      * | ||||
|      * @return The position the turtle is interacting with. | ||||
|      */ | ||||
|     public BlockPos getPos() { | ||||
|     public BlockPos getPos() | ||||
|     { | ||||
|         return this.pos; | ||||
|     } | ||||
|  | ||||
| @@ -68,13 +70,15 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent { | ||||
|      * | ||||
|      * @see TurtleAction#DIG | ||||
|      */ | ||||
|     public static class Dig extends TurtleBlockEvent { | ||||
|     public static class Dig extends TurtleBlockEvent | ||||
|     { | ||||
|         private final BlockState block; | ||||
|         private final ITurtleUpgrade upgrade; | ||||
|         private final TurtleSide side; | ||||
|  | ||||
|         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 ); | ||||
|  | ||||
|             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. | ||||
|          */ | ||||
|         @Nonnull | ||||
|         public BlockState getBlock() { | ||||
|         public BlockState getBlock() | ||||
|         { | ||||
|             return this.block; | ||||
|         } | ||||
|  | ||||
| @@ -101,7 +106,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent { | ||||
|          * @return The upgrade doing the digging. | ||||
|          */ | ||||
|         @Nonnull | ||||
|         public ITurtleUpgrade getUpgrade() { | ||||
|         public ITurtleUpgrade getUpgrade() | ||||
|         { | ||||
|             return this.upgrade; | ||||
|         } | ||||
|  | ||||
| @@ -111,7 +117,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent { | ||||
|          * @return The upgrade's side. | ||||
|          */ | ||||
|         @Nonnull | ||||
|         public TurtleSide getSide() { | ||||
|         public TurtleSide getSide() | ||||
|         { | ||||
|             return this.side; | ||||
|         } | ||||
|     } | ||||
| @@ -121,8 +128,10 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent { | ||||
|      * | ||||
|      * @see TurtleAction#MOVE | ||||
|      */ | ||||
|     public static class Move extends TurtleBlockEvent { | ||||
|         public Move(@Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos) { | ||||
|     public static class Move extends TurtleBlockEvent | ||||
|     { | ||||
|         public Move( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos ) | ||||
|         { | ||||
|             super( turtle, TurtleAction.MOVE, player, world, pos ); | ||||
|         } | ||||
|     } | ||||
| @@ -132,10 +141,12 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent { | ||||
|      * | ||||
|      * @see TurtleAction#PLACE | ||||
|      */ | ||||
|     public static class Place extends TurtleBlockEvent { | ||||
|     public static class Place extends TurtleBlockEvent | ||||
|     { | ||||
|         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 ); | ||||
|  | ||||
|             Objects.requireNonNull( stack, "stack cannot be null" ); | ||||
| @@ -148,7 +159,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent { | ||||
|          * @return The item stack to be placed. | ||||
|          */ | ||||
|         @Nonnull | ||||
|         public ItemStack getStack() { | ||||
|         public ItemStack getStack() | ||||
|         { | ||||
|             return this.stack; | ||||
|         } | ||||
|     } | ||||
| @@ -160,12 +172,14 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent { | ||||
|      * | ||||
|      * @see TurtleAction#INSPECT | ||||
|      */ | ||||
|     public static class Inspect extends TurtleBlockEvent { | ||||
|     public static class Inspect extends TurtleBlockEvent | ||||
|     { | ||||
|         private final BlockState state; | ||||
|         private final Map<String, Object> data; | ||||
|  | ||||
|         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 ); | ||||
|  | ||||
|             Objects.requireNonNull( state, "state cannot be null" ); | ||||
| @@ -180,7 +194,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent { | ||||
|          * @return The inspected block state. | ||||
|          */ | ||||
|         @Nonnull | ||||
|         public BlockState getState() { | ||||
|         public BlockState getState() | ||||
|         { | ||||
|             return this.state; | ||||
|         } | ||||
|  | ||||
| @@ -190,7 +205,8 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent { | ||||
|          * @return This block's inspection data. | ||||
|          */ | ||||
|         @Nonnull | ||||
|         public Map<String, Object> getData() { | ||||
|         public Map<String, Object> getData() | ||||
|         { | ||||
|             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)}). | ||||
|          */ | ||||
|         public void addData(@Nonnull Map<String, ?> newData) { | ||||
|         public void addData( @Nonnull Map<String, ?> newData ) | ||||
|         { | ||||
|             Objects.requireNonNull( newData, "newData cannot be null" ); | ||||
|             this.data.putAll( newData ); | ||||
|         } | ||||
|   | ||||
| @@ -6,13 +6,12 @@ | ||||
|  | ||||
| package dan200.computercraft.api.turtle.event; | ||||
|  | ||||
| import java.util.Objects; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import com.google.common.eventbus.EventBus; | ||||
| 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 | ||||
|  * ITurtleAccess} are safe to use. | ||||
| @@ -21,17 +20,20 @@ import dan200.computercraft.api.turtle.ITurtleAccess; | ||||
|  * | ||||
|  * @see TurtleActionEvent | ||||
|  */ | ||||
| public abstract class TurtleEvent { | ||||
| public abstract class TurtleEvent | ||||
| { | ||||
|     public static final EventBus EVENT_BUS = new EventBus(); | ||||
|  | ||||
|     private final ITurtleAccess turtle; | ||||
|  | ||||
|     protected TurtleEvent(@Nonnull ITurtleAccess turtle) { | ||||
|     protected TurtleEvent( @Nonnull ITurtleAccess turtle ) | ||||
|     { | ||||
|         Objects.requireNonNull( turtle, "turtle cannot be null" ); | ||||
|         this.turtle = turtle; | ||||
|     } | ||||
|  | ||||
|     public static boolean post(TurtleActionEvent event) { | ||||
|     public static boolean post( TurtleActionEvent event ) | ||||
|     { | ||||
|         EVENT_BUS.post( event ); | ||||
|         return event.isCancelled(); | ||||
|     } | ||||
| @@ -42,7 +44,8 @@ public abstract class TurtleEvent { | ||||
|      * @return The access for this turtle. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public ITurtleAccess getTurtle() { | ||||
|     public ITurtleAccess getTurtle() | ||||
|     { | ||||
|         return this.turtle; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -6,16 +6,14 @@ | ||||
|  | ||||
| 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.turtle.ITurtleAccess; | ||||
|  | ||||
| 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. | ||||
|  * | ||||
| @@ -24,17 +22,20 @@ import net.minecraft.item.ItemStack; | ||||
|  * | ||||
|  * @see TurtleAction#INSPECT_ITEM | ||||
|  */ | ||||
| public class TurtleInspectItemEvent extends TurtleActionEvent { | ||||
| public class TurtleInspectItemEvent extends TurtleActionEvent | ||||
| { | ||||
|     private final ItemStack stack; | ||||
|     private final Map<String, Object> data; | ||||
|     private final boolean mainThread; | ||||
|  | ||||
|     @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 ); | ||||
|     } | ||||
|  | ||||
|     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 ); | ||||
|  | ||||
|         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. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public ItemStack getStack() { | ||||
|     public ItemStack getStack() | ||||
|     { | ||||
|         return this.stack; | ||||
|     } | ||||
|  | ||||
| @@ -60,7 +62,8 @@ public class TurtleInspectItemEvent extends TurtleActionEvent { | ||||
|      * @return This items's inspection data. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public Map<String, Object> getData() { | ||||
|     public Map<String, Object> getData() | ||||
|     { | ||||
|         return this.data; | ||||
|     } | ||||
|  | ||||
| @@ -69,7 +72,8 @@ public class TurtleInspectItemEvent extends TurtleActionEvent { | ||||
|      * | ||||
|      * @return If this is run on the main thread. | ||||
|      */ | ||||
|     public boolean onMainThread() { | ||||
|     public boolean onMainThread() | ||||
|     { | ||||
|         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)}). | ||||
|      */ | ||||
|     public void addData(@Nonnull Map<String, ?> newData) { | ||||
|     public void addData( @Nonnull Map<String, ?> newData ) | ||||
|     { | ||||
|         Objects.requireNonNull( newData, "newData cannot be null" ); | ||||
|         this.data.putAll( newData ); | ||||
|     } | ||||
|   | ||||
| @@ -6,27 +6,27 @@ | ||||
|  | ||||
| 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.ITurtleAccess; | ||||
|  | ||||
| import net.minecraft.inventory.Inventory; | ||||
| import net.minecraft.item.ItemStack; | ||||
| import net.minecraft.util.math.BlockPos; | ||||
| 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. | ||||
|  */ | ||||
| public abstract class TurtleInventoryEvent extends TurtleBlockEvent { | ||||
| public abstract class TurtleInventoryEvent extends TurtleBlockEvent | ||||
| { | ||||
|     private final Inventory handler; | ||||
|  | ||||
|     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 ); | ||||
|         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. | ||||
|      */ | ||||
|     @Nullable | ||||
|     public Inventory getItemHandler() { | ||||
|     public Inventory getItemHandler() | ||||
|     { | ||||
|         return this.handler; | ||||
|     } | ||||
|  | ||||
| @@ -46,8 +47,10 @@ public abstract class TurtleInventoryEvent extends TurtleBlockEvent { | ||||
|      * | ||||
|      * @see TurtleAction#SUCK | ||||
|      */ | ||||
|     public static class Suck extends TurtleInventoryEvent { | ||||
|         public Suck(@Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nullable Inventory handler) { | ||||
|     public static class Suck extends TurtleInventoryEvent | ||||
|     { | ||||
|         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 ); | ||||
|         } | ||||
|     } | ||||
| @@ -57,11 +60,13 @@ public abstract class TurtleInventoryEvent extends TurtleBlockEvent { | ||||
|      * | ||||
|      * @see TurtleAction#DROP | ||||
|      */ | ||||
|     public static class Drop extends TurtleInventoryEvent { | ||||
|     public static class Drop extends TurtleInventoryEvent | ||||
|     { | ||||
|         private final ItemStack stack; | ||||
|  | ||||
|         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 ); | ||||
|  | ||||
|             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. | ||||
|          */ | ||||
|         @Nonnull | ||||
|         public ItemStack getStack() { | ||||
|         public ItemStack getStack() | ||||
|         { | ||||
|             return this.stack; | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -6,22 +6,23 @@ | ||||
|  | ||||
| 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.ITurtleAccess; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import java.util.Objects; | ||||
|  | ||||
| /** | ||||
|  * 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. | ||||
|  */ | ||||
| public abstract class TurtlePlayerEvent extends TurtleActionEvent { | ||||
| public abstract class TurtlePlayerEvent extends TurtleActionEvent | ||||
| { | ||||
|     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 ); | ||||
|  | ||||
|         Objects.requireNonNull( player, "player cannot be null" ); | ||||
| @@ -36,7 +37,8 @@ public abstract class TurtlePlayerEvent extends TurtleActionEvent { | ||||
|      * @return A {@link FakePlayer} representing this turtle. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     public FakePlayer getPlayer() { | ||||
|     public FakePlayer getPlayer() | ||||
|     { | ||||
|         return this.player; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,14 +6,12 @@ | ||||
|  | ||||
| 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.Nullable; | ||||
|  | ||||
| import dan200.computercraft.api.turtle.ITurtleAccess; | ||||
|  | ||||
| import net.minecraft.item.ItemStack; | ||||
| import java.util.Objects; | ||||
|  | ||||
| /** | ||||
|  * 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 | ||||
|  * register a custom fuel provider. | ||||
|  */ | ||||
| public class TurtleRefuelEvent extends TurtleActionEvent { | ||||
| public class TurtleRefuelEvent extends TurtleActionEvent | ||||
| { | ||||
|     private final ItemStack stack; | ||||
|     private Handler handler; | ||||
|  | ||||
|     public TurtleRefuelEvent(@Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack) { | ||||
|     public TurtleRefuelEvent( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack ) | ||||
|     { | ||||
|         super( turtle, TurtleAction.REFUEL ); | ||||
|  | ||||
|         Objects.requireNonNull( turtle, "turtle cannot be null" ); | ||||
| @@ -39,7 +39,8 @@ public class TurtleRefuelEvent extends TurtleActionEvent { | ||||
|      * | ||||
|      * @return The stack to refuel from. | ||||
|      */ | ||||
|     public ItemStack getStack() { | ||||
|     public ItemStack getStack() | ||||
|     { | ||||
|         return this.stack; | ||||
|     } | ||||
|  | ||||
| @@ -50,7 +51,8 @@ public class TurtleRefuelEvent extends TurtleActionEvent { | ||||
|      * @see #setHandler(Handler) | ||||
|      */ | ||||
|     @Nullable | ||||
|     public Handler getHandler() { | ||||
|     public Handler getHandler() | ||||
|     { | ||||
|         return this.handler; | ||||
|     } | ||||
|  | ||||
| @@ -62,7 +64,8 @@ public class TurtleRefuelEvent extends TurtleActionEvent { | ||||
|      * @param handler The new refuel handler. | ||||
|      * @see #getHandler() | ||||
|      */ | ||||
|     public void setHandler(@Nullable Handler handler) { | ||||
|     public void setHandler( @Nullable Handler handler ) | ||||
|     { | ||||
|         this.handler = handler; | ||||
|     } | ||||
|  | ||||
| @@ -70,7 +73,8 @@ public class TurtleRefuelEvent extends TurtleActionEvent { | ||||
|      * Handles refuelling a turtle from a specific item. | ||||
|      */ | ||||
|     @FunctionalInterface | ||||
|     public interface Handler { | ||||
|     public interface Handler | ||||
|     { | ||||
|         /** | ||||
|          * Refuel a turtle using an item. | ||||
|          * | ||||
|   | ||||
| @@ -6,9 +6,6 @@ | ||||
|  | ||||
| package dan200.computercraft.client; | ||||
|  | ||||
| import java.util.HashSet; | ||||
| import java.util.function.Consumer; | ||||
|  | ||||
| import dan200.computercraft.ComputerCraft; | ||||
| import dan200.computercraft.shared.ComputerCraftRegistry; | ||||
| 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.pocket.items.ItemPocketComputer; | ||||
| 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.render.model.BakedModel; | ||||
| 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.util.Identifier; | ||||
|  | ||||
| import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; | ||||
| import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; | ||||
| import java.util.HashSet; | ||||
| import java.util.function.Consumer; | ||||
|  | ||||
| /** | ||||
|  * Registers textures and models for items. | ||||
| @@ -37,7 +35,8 @@ import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; | ||||
|     "MethodCallSideOnly", | ||||
|     "LocalVariableDeclarationSideOnly" | ||||
| } ) | ||||
| public final class ClientRegistry { | ||||
| public final class ClientRegistry | ||||
| { | ||||
|     private static final String[] EXTRA_MODELS = new String[] { | ||||
|         "turtle_modem_normal_off_left", | ||||
|         "turtle_modem_normal_on_left", | ||||
| @@ -69,20 +68,25 @@ public final class ClientRegistry { | ||||
|  | ||||
|     private ClientRegistry() {} | ||||
|  | ||||
|     public static void onTextureStitchEvent(SpriteAtlasTexture atlasTexture, ClientSpriteRegistryCallback.Registry registry) { | ||||
|         for (String extra : EXTRA_TEXTURES) { | ||||
|     public static void onTextureStitchEvent( SpriteAtlasTexture atlasTexture, ClientSpriteRegistryCallback.Registry registry ) | ||||
|     { | ||||
|         for( String extra : EXTRA_TEXTURES ) | ||||
|         { | ||||
|             registry.register( new Identifier( ComputerCraft.MOD_ID, extra ) ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @SuppressWarnings( "NewExpressionSideOnly" ) | ||||
|     public static void onModelBakeEvent(ResourceManager manager, Consumer<ModelIdentifier> out) { | ||||
|         for (String model : EXTRA_MODELS) { | ||||
|     public static void onModelBakeEvent( ResourceManager manager, Consumer<ModelIdentifier> out ) | ||||
|     { | ||||
|         for( String model : EXTRA_MODELS ) | ||||
|         { | ||||
|             out.accept( new ModelIdentifier( new Identifier( ComputerCraft.MOD_ID, model ), "inventory" ) ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void onItemColours() { | ||||
|     public static void onItemColours() | ||||
|     { | ||||
|         ColorProviderRegistry.ITEM.register( ( stack, layer ) -> { | ||||
|             return layer == 1 ? ((ItemDisk) stack.getItem()).getColour( stack ) : 0xFFFFFF; | ||||
|         }, ComputerCraftRegistry.ModItems.DISK ); | ||||
| @@ -91,7 +95,8 @@ public final class ClientRegistry { | ||||
|             ComputerCraftRegistry.ModItems.TREASURE_DISK ); | ||||
|  | ||||
|         ColorProviderRegistry.ITEM.register( ( stack, layer ) -> { | ||||
|             switch (layer) { | ||||
|             switch( layer ) | ||||
|             { | ||||
|                 case 0: | ||||
|                 default: | ||||
|                     return 0xFFFFFF; | ||||
| @@ -111,7 +116,8 @@ public final class ClientRegistry { | ||||
|             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<>() ); | ||||
|         return model.bake( loader, | ||||
|             spriteIdentifier -> MinecraftClient.getInstance() | ||||
|   | ||||
| @@ -6,36 +6,38 @@ | ||||
|  | ||||
| package dan200.computercraft.client; | ||||
|  | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import dan200.computercraft.fabric.mixin.ChatHudAccess; | ||||
| import dan200.computercraft.shared.command.text.ChatHelpers; | ||||
| import dan200.computercraft.shared.command.text.TableBuilder; | ||||
| import dan200.computercraft.shared.command.text.TableFormatter; | ||||
| import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
|  | ||||
| import net.minecraft.client.MinecraftClient; | ||||
| import net.minecraft.client.font.TextRenderer; | ||||
| import net.minecraft.client.gui.hud.ChatHud; | ||||
| import net.minecraft.text.Text; | ||||
| import net.minecraft.util.Formatting; | ||||
| import net.minecraft.util.math.MathHelper; | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
|  | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| @SuppressWarnings( { | ||||
|     "MethodCallSideOnly", | ||||
|     "LocalVariableDeclarationSideOnly" | ||||
| } ) | ||||
| public class ClientTableFormatter implements TableFormatter { | ||||
| public class ClientTableFormatter implements TableFormatter | ||||
| { | ||||
|     public static final ClientTableFormatter INSTANCE = new ClientTableFormatter(); | ||||
|  | ||||
|     private static Int2IntOpenHashMap lastHeights = new Int2IntOpenHashMap(); | ||||
|  | ||||
|     @Override | ||||
|     @Nullable | ||||
|     public Text getPadding(Text component, int width) { | ||||
|     public Text getPadding( Text component, int width ) | ||||
|     { | ||||
|         int extraWidth = width - this.getWidth( component ); | ||||
|         if (extraWidth <= 0) { | ||||
|         if( extraWidth <= 0 ) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
| @@ -48,22 +50,26 @@ public class ClientTableFormatter implements TableFormatter { | ||||
|         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; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getColumnPadding() { | ||||
|     public int getColumnPadding() | ||||
|     { | ||||
|         return 3; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getWidth(Text component) { | ||||
|     public int getWidth( Text component ) | ||||
|     { | ||||
|         return renderer().getWidth( component ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeLine(int id, Text component) { | ||||
|     public void writeLine( int id, Text component ) | ||||
|     { | ||||
|         MinecraftClient mc = MinecraftClient.getInstance(); | ||||
|         ChatHud chat = mc.inGameHud.getChatHud(); | ||||
|  | ||||
| @@ -75,7 +81,8 @@ public class ClientTableFormatter implements TableFormatter { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int display(TableBuilder table) { | ||||
|     public int display( TableBuilder table ) | ||||
|     { | ||||
|         ChatHud chat = MinecraftClient.getInstance().inGameHud.getChatHud(); | ||||
|  | ||||
|         int lastHeight = lastHeights.get( table.getId() ); | ||||
| @@ -83,7 +90,8 @@ public class ClientTableFormatter implements TableFormatter { | ||||
|         int height = TableFormatter.super.display( table ); | ||||
|         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() ); | ||||
|         } | ||||
|         return height; | ||||
|   | ||||
| @@ -8,38 +8,46 @@ package dan200.computercraft.client; | ||||
|  | ||||
| import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; | ||||
|  | ||||
| public final class FrameInfo { | ||||
| public final class FrameInfo | ||||
| { | ||||
|     private static int tick; | ||||
|     private static long renderFrame; | ||||
|  | ||||
|     static { | ||||
|     static | ||||
|     { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     private FrameInfo() { | ||||
|     private FrameInfo() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     public static void init() { | ||||
|     public static void init() | ||||
|     { | ||||
|         ClientTickEvents.START_CLIENT_TICK.register( m -> { | ||||
|             tick++; | ||||
|         } ); | ||||
|     } | ||||
|  | ||||
|     public static boolean getGlobalCursorBlink() { | ||||
|     public static boolean getGlobalCursorBlink() | ||||
|     { | ||||
|         return (tick / 8) % 2 == 0; | ||||
|     } | ||||
|  | ||||
|     public static long getRenderFrame() { | ||||
|     public static long getRenderFrame() | ||||
|     { | ||||
|         return renderFrame; | ||||
|     } | ||||
|  | ||||
|     // TODO Call this in a callback | ||||
|     public static void onTick() { | ||||
|     public static void onTick() | ||||
|     { | ||||
|         tick++; | ||||
|     } | ||||
|  | ||||
|     // TODO Call this in a callback | ||||
|     public static void onRenderFrame() { | ||||
|     public static void onRenderFrame() | ||||
|     { | ||||
|         renderFrame++; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,29 +6,24 @@ | ||||
|  | ||||
| package dan200.computercraft.client.gui; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import com.mojang.blaze3d.systems.RenderSystem; | ||||
| import dan200.computercraft.client.FrameInfo; | ||||
| import dan200.computercraft.core.terminal.Terminal; | ||||
| import dan200.computercraft.core.terminal.TextBuffer; | ||||
| import dan200.computercraft.shared.util.Colour; | ||||
| import dan200.computercraft.shared.util.Palette; | ||||
| import org.lwjgl.opengl.GL11; | ||||
|  | ||||
| import net.minecraft.client.MinecraftClient; | ||||
| 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.VertexFormat; | ||||
| import net.minecraft.client.render.VertexFormats; | ||||
| import net.minecraft.client.render.*; | ||||
| import net.minecraft.client.util.math.AffineTransformation; | ||||
| import net.minecraft.util.Identifier; | ||||
| 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_WIDTH = 6; | ||||
|     public static final float WIDTH = 256.0f; | ||||
| @@ -40,11 +35,13 @@ public final class FixedWidthFontRenderer { | ||||
|     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, | ||||
|                                   @Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize) { | ||||
|                                    @Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize ) | ||||
|     { | ||||
|         bindFont(); | ||||
|  | ||||
|         VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance() | ||||
| @@ -64,7 +61,8 @@ public final class FixedWidthFontRenderer { | ||||
|         renderer.draw(); | ||||
|     } | ||||
|  | ||||
|     private static void bindFont() { | ||||
|     private static void bindFont() | ||||
|     { | ||||
|         MinecraftClient.getInstance() | ||||
|             .getTextureManager() | ||||
|             .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, | ||||
|                                    @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, | ||||
|                                   float leftMarginSize, float rightMarginSize) { | ||||
|         if (backgroundColour != null) { | ||||
|                                    float leftMarginSize, float rightMarginSize ) | ||||
|     { | ||||
|         if( backgroundColour != null ) | ||||
|         { | ||||
|             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 ) ); | ||||
|             float r, g, b; | ||||
|             if (greyscale) { | ||||
|             if( greyscale ) | ||||
|             { | ||||
|                 r = g = b = toGreyscale( colour ); | ||||
|             } else { | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 r = (float) colour[0]; | ||||
|                 g = (float) colour[1]; | ||||
|                 b = (float) colour[2]; | ||||
| @@ -91,7 +95,8 @@ public final class FixedWidthFontRenderer { | ||||
|  | ||||
|             // Draw char | ||||
|             int index = text.charAt( i ); | ||||
|             if (index > 255) { | ||||
|             if( index > 255 ) | ||||
|             { | ||||
|                 index = '?'; | ||||
|             } | ||||
|             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, | ||||
|                                         @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, float leftMarginSize, | ||||
|                                        float rightMarginSize, float height) { | ||||
|         if (leftMarginSize > 0) { | ||||
|                                         float rightMarginSize, float height ) | ||||
|     { | ||||
|         if( leftMarginSize > 0 ) | ||||
|         { | ||||
|             drawQuad( transform, renderer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) ); | ||||
|         } | ||||
|  | ||||
|         if (rightMarginSize > 0) { | ||||
|         if( rightMarginSize > 0 ) | ||||
|         { | ||||
|             drawQuad( transform, | ||||
|                 renderer, | ||||
|                 x + backgroundColour.length() * FONT_WIDTH, | ||||
| @@ -121,13 +129,16 @@ public final class FixedWidthFontRenderer { | ||||
|         // Batch together runs of identical background cells. | ||||
|         int blockStart = 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 ); | ||||
|             if (colourIndex == blockColour) { | ||||
|             if( colourIndex == blockColour ) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if (blockColour != '\0') { | ||||
|             if( blockColour != '\0' ) | ||||
|             { | ||||
|                 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; | ||||
|         } | ||||
|  | ||||
|         if (blockColour != '\0') { | ||||
|         if( blockColour != '\0' ) | ||||
|         { | ||||
|             drawQuad( transform, | ||||
|                 renderer, | ||||
|                 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 ); | ||||
|     } | ||||
|  | ||||
|     public static float toGreyscale(double[] rgb) { | ||||
|     public static float toGreyscale( double[] rgb ) | ||||
|     { | ||||
|         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. | ||||
|         if (index == '\0' || index == ' ') { | ||||
|         if( index == '\0' || index == ' ' ) | ||||
|         { | ||||
|             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, | ||||
|                                  boolean greyscale, char colourIndex) { | ||||
|                                   boolean greyscale, char colourIndex ) | ||||
|     { | ||||
|         double[] colour = palette.getColour( getColour( colourIndex, Colour.BLACK ) ); | ||||
|         float r, g, b; | ||||
|         if (greyscale) { | ||||
|         if( greyscale ) | ||||
|         { | ||||
|             r = g = b = toGreyscale( colour ); | ||||
|         } else { | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             r = (float) colour[0]; | ||||
|             g = (float) colour[1]; | ||||
|             b = (float) colour[2]; | ||||
| @@ -209,7 +229,8 @@ public final class FixedWidthFontRenderer { | ||||
|         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 ) | ||||
|             .color( r, g, b, 1.0f ) | ||||
|             .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, | ||||
|                                                   @Nonnull Terminal terminal, boolean greyscale, float topMarginSize, float bottomMarginSize, | ||||
|                                                  float leftMarginSize, float rightMarginSize) { | ||||
|                                                   float leftMarginSize, float rightMarginSize ) | ||||
|     { | ||||
|         Palette palette = terminal.getPalette(); | ||||
|         int height = terminal.getHeight(); | ||||
|  | ||||
| @@ -266,7 +288,8 @@ public final class FixedWidthFontRenderer { | ||||
|             bottomMarginSize ); | ||||
|  | ||||
|         // The main text | ||||
|         for (int i = 0; i < height; i++) { | ||||
|         for( int i = 0; i < height; i++ ) | ||||
|         { | ||||
|             drawString( transform, | ||||
|                 buffer, | ||||
|                 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, | ||||
|                                   boolean greyscale) { | ||||
|                                    boolean greyscale ) | ||||
|     { | ||||
|         Palette palette = terminal.getPalette(); | ||||
|         int width = terminal.getWidth(); | ||||
|         int height = terminal.getHeight(); | ||||
|  | ||||
|         int cursorX = terminal.getCursorX(); | ||||
|         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() ); | ||||
|             float r, g, b; | ||||
|             if (greyscale) { | ||||
|             if( greyscale ) | ||||
|             { | ||||
|                 r = g = b = toGreyscale( colour ); | ||||
|             } else { | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 r = (float) colour[0]; | ||||
|                 g = (float) colour[1]; | ||||
|                 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, | ||||
|                                     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 ); | ||||
|         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, | ||||
|                                     float bottomMarginSize, float leftMarginSize, float rightMarginSize) { | ||||
|                                      float bottomMarginSize, float leftMarginSize, float rightMarginSize ) | ||||
|     { | ||||
|         bindFont(); | ||||
|  | ||||
|         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, | ||||
|                                     float leftMarginSize, float rightMarginSize) { | ||||
|                                      float leftMarginSize, float 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 ); | ||||
|     } | ||||
|  | ||||
|     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(); | ||||
|  | ||||
|         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, | ||||
|                                          float height) { | ||||
|                                           float height ) | ||||
|     { | ||||
|         Colour colour = Colour.BLACK; | ||||
|         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; | ||||
|         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 VertexFormat FORMAT = VertexFormats.POSITION_COLOR_TEXTURE; | ||||
| @@ -377,7 +413,8 @@ public final class FixedWidthFontRenderer { | ||||
|                 .lightmap( DISABLE_LIGHTMAP ) | ||||
|                 .build( false ) ); | ||||
|  | ||||
|         private Type(String name, Runnable setup, Runnable destroy) { | ||||
|         private Type( String name, Runnable setup, Runnable destroy ) | ||||
|         { | ||||
|             super( name, setup, destroy ); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -6,11 +6,6 @@ | ||||
|  | ||||
| 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 dan200.computercraft.ComputerCraft; | ||||
| 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.ContainerViewComputer; | ||||
| import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; | ||||
| import org.lwjgl.glfw.GLFW; | ||||
|  | ||||
| import net.minecraft.client.gui.screen.ingame.HandledScreen; | ||||
| import net.minecraft.client.util.math.MatrixStack; | ||||
| import net.minecraft.entity.player.PlayerInventory; | ||||
| 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 ClientComputer computer; | ||||
|     private final int termWidth; | ||||
| @@ -38,7 +38,8 @@ public final class GuiComputer<T extends ContainerComputerBase> extends HandledS | ||||
|     private WidgetTerminal terminal; | ||||
|     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 ); | ||||
|         this.family = container.getFamily(); | ||||
|         this.computer = (ClientComputer) container.getComputer(); | ||||
| @@ -47,21 +48,25 @@ public final class GuiComputer<T extends ContainerComputerBase> extends HandledS | ||||
|         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 ); | ||||
|     } | ||||
|  | ||||
|     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 ); | ||||
|     } | ||||
|  | ||||
|     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() ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     protected void init() { | ||||
|     protected void init() | ||||
|     { | ||||
|         this.client.keyboard.setRepeatEvents( true ); | ||||
|  | ||||
|         int termPxWidth = this.termWidth * FixedWidthFontRenderer.FONT_WIDTH; | ||||
| @@ -80,18 +85,21 @@ public final class GuiComputer<T extends ContainerComputerBase> extends HandledS | ||||
|     } | ||||
|  | ||||
|     @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 ); | ||||
|         this.drawMouseoverTooltip( stack, mouseX, mouseY ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void drawForeground(@Nonnull MatrixStack transform, int mouseX, int mouseY) { | ||||
|     protected void drawForeground( @Nonnull MatrixStack transform, int mouseX, int mouseY ) | ||||
|     { | ||||
|         // Skip rendering labels. | ||||
|     } | ||||
|  | ||||
|     @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 | ||||
|         this.terminal.draw( this.terminalWrapper.getX(), this.terminalWrapper.getY() ); | ||||
|  | ||||
| @@ -104,19 +112,23 @@ public final class GuiComputer<T extends ContainerComputerBase> extends HandledS | ||||
|     } | ||||
|  | ||||
|     @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 ); | ||||
|     } | ||||
|  | ||||
|     @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 ); | ||||
|     } | ||||
|  | ||||
|     @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. | ||||
|         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 ); | ||||
|         } | ||||
|  | ||||
| @@ -124,7 +136,8 @@ public final class GuiComputer<T extends ContainerComputerBase> extends HandledS | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void removed() { | ||||
|     public void removed() | ||||
|     { | ||||
|         super.removed(); | ||||
|         this.children.remove( this.terminal ); | ||||
|         this.terminal = null; | ||||
| @@ -132,7 +145,8 @@ public final class GuiComputer<T extends ContainerComputerBase> extends HandledS | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void tick() { | ||||
|     public void tick() | ||||
|     { | ||||
|         super.tick(); | ||||
|         this.terminal.update(); | ||||
|     } | ||||
|   | ||||
| @@ -6,33 +6,36 @@ | ||||
|  | ||||
| package dan200.computercraft.client.gui; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import com.mojang.blaze3d.systems.RenderSystem; | ||||
| import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; | ||||
|  | ||||
| import net.minecraft.client.gui.screen.ingame.HandledScreen; | ||||
| import net.minecraft.client.util.math.MatrixStack; | ||||
| import net.minecraft.entity.player.PlayerInventory; | ||||
| import net.minecraft.text.Text; | ||||
| 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" ); | ||||
|  | ||||
|     public GuiDiskDrive(ContainerDiskDrive container, PlayerInventory player, Text title) { | ||||
|     public GuiDiskDrive( ContainerDiskDrive container, PlayerInventory player, Text title ) | ||||
|     { | ||||
|         super( container, player, title ); | ||||
|     } | ||||
|  | ||||
|     @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 ); | ||||
|         super.render( transform, mouseX, mouseY, partialTicks ); | ||||
|         this.drawMouseoverTooltip( transform, mouseX, mouseY ); | ||||
|     } | ||||
|  | ||||
|     @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 ); | ||||
|         this.client.getTextureManager() | ||||
|             .bindTexture( BACKGROUND ); | ||||
|   | ||||
| @@ -6,21 +6,22 @@ | ||||
|  | ||||
| package dan200.computercraft.client.gui; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import com.mojang.blaze3d.systems.RenderSystem; | ||||
| import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; | ||||
|  | ||||
| import net.minecraft.client.gui.screen.ingame.HandledScreen; | ||||
| import net.minecraft.client.util.math.MatrixStack; | ||||
| import net.minecraft.entity.player.PlayerInventory; | ||||
| import net.minecraft.text.Text; | ||||
| 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" ); | ||||
|  | ||||
|     public GuiPrinter(ContainerPrinter container, PlayerInventory player, Text title) { | ||||
|     public GuiPrinter( ContainerPrinter container, PlayerInventory player, Text title ) | ||||
|     { | ||||
|         super( container, player, title ); | ||||
|     } | ||||
|  | ||||
| @@ -33,20 +34,23 @@ public class GuiPrinter extends HandledScreen<ContainerPrinter> { | ||||
|     }*/ | ||||
|  | ||||
|     @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 ); | ||||
|         super.render( stack, mouseX, mouseY, partialTicks ); | ||||
|         this.drawMouseoverTooltip( stack, mouseX, mouseY ); | ||||
|     } | ||||
|  | ||||
|     @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 ); | ||||
|         this.client.getTextureManager() | ||||
|             .bindTexture( BACKGROUND ); | ||||
|         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 ); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -6,20 +6,10 @@ | ||||
|  | ||||
| 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 dan200.computercraft.core.terminal.TextBuffer; | ||||
| import dan200.computercraft.shared.common.ContainerHeldItem; | ||||
| import dan200.computercraft.shared.media.items.ItemPrintout; | ||||
| import org.lwjgl.glfw.GLFW; | ||||
|  | ||||
| import net.minecraft.client.MinecraftClient; | ||||
| import net.minecraft.client.gui.screen.ingame.HandledScreen; | ||||
| 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.text.Text; | ||||
| 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 int m_pages; | ||||
|     private final TextBuffer[] m_text; | ||||
|     private final TextBuffer[] m_colours; | ||||
|     private int m_page; | ||||
|  | ||||
|     public GuiPrintout(ContainerHeldItem container, PlayerInventory player, Text title) { | ||||
|     public GuiPrintout( ContainerHeldItem container, PlayerInventory player, Text title ) | ||||
|     { | ||||
|         super( container, player, title ); | ||||
|  | ||||
|         this.backgroundHeight = Y_SIZE; | ||||
|  | ||||
|         String[] text = ItemPrintout.getText( container.getStack() ); | ||||
|         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] ); | ||||
|         } | ||||
|  | ||||
|         String[] colours = ItemPrintout.getColours( container.getStack() ); | ||||
|         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] ); | ||||
|         } | ||||
|  | ||||
| @@ -59,21 +58,27 @@ public class GuiPrintout extends HandledScreen<ContainerHeldItem> { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean mouseScrolled(double x, double y, double delta) { | ||||
|         if (super.mouseScrolled(x, y, delta)) { | ||||
|     public boolean mouseScrolled( double x, double y, double delta ) | ||||
|     { | ||||
|         if( super.mouseScrolled( x, y, delta ) ) | ||||
|         { | ||||
|             return true; | ||||
|         } | ||||
|         if (delta < 0) { | ||||
|         if( delta < 0 ) | ||||
|         { | ||||
|             // 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++; | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         if (delta > 0) { | ||||
|         if( delta > 0 ) | ||||
|         { | ||||
|             // Scroll down goes to the previous page | ||||
|             if (this.m_page > 0) { | ||||
|             if( this.m_page > 0 ) | ||||
|             { | ||||
|                 this.m_page--; | ||||
|             } | ||||
|             return true; | ||||
| @@ -83,7 +88,8 @@ public class GuiPrintout extends HandledScreen<ContainerHeldItem> { | ||||
|     } | ||||
|  | ||||
|     @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. | ||||
|         this.setZOffset( this.getZOffset() - 1 ); | ||||
|         this.renderBackground( stack ); | ||||
| @@ -93,12 +99,14 @@ public class GuiPrintout extends HandledScreen<ContainerHeldItem> { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void drawForeground(@Nonnull MatrixStack transform, int mouseX, int mouseY) { | ||||
|     protected void drawForeground( @Nonnull MatrixStack transform, int mouseX, int mouseY ) | ||||
|     { | ||||
|         // Skip rendering labels. | ||||
|     } | ||||
|  | ||||
|     @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 | ||||
|         RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); | ||||
|         RenderSystem.enableDepthTest(); | ||||
| @@ -114,20 +122,26 @@ public class GuiPrintout extends HandledScreen<ContainerHeldItem> { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean keyPressed(int key, int scancode, int modifiers) { | ||||
|         if (super.keyPressed(key, scancode, modifiers)) { | ||||
|     public boolean keyPressed( int key, int scancode, int modifiers ) | ||||
|     { | ||||
|         if( super.keyPressed( key, scancode, modifiers ) ) | ||||
|         { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         if (key == GLFW.GLFW_KEY_RIGHT) { | ||||
|             if (this.m_page < this.m_pages - 1) { | ||||
|         if( key == GLFW.GLFW_KEY_RIGHT ) | ||||
|         { | ||||
|             if( this.m_page < this.m_pages - 1 ) | ||||
|             { | ||||
|                 this.m_page++; | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         if (key == GLFW.GLFW_KEY_LEFT) { | ||||
|             if (this.m_page > 0) { | ||||
|         if( key == GLFW.GLFW_KEY_LEFT ) | ||||
|         { | ||||
|             if( this.m_page > 0 ) | ||||
|             { | ||||
|                 this.m_page--; | ||||
|             } | ||||
|             return true; | ||||
|   | ||||
| @@ -6,8 +6,6 @@ | ||||
|  | ||||
| package dan200.computercraft.client.gui; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import com.mojang.blaze3d.systems.RenderSystem; | ||||
| import dan200.computercraft.ComputerCraft; | ||||
| 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.ComputerFamily; | ||||
| import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; | ||||
| import org.lwjgl.glfw.GLFW; | ||||
|  | ||||
| import net.minecraft.client.gui.screen.ingame.HandledScreen; | ||||
| import net.minecraft.client.util.math.MatrixStack; | ||||
| import net.minecraft.entity.player.PlayerInventory; | ||||
| import net.minecraft.text.Text; | ||||
| 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_ADVANCED = new Identifier( "computercraft", "textures/gui/turtle_advanced.png" ); | ||||
|     private final ComputerFamily m_family; | ||||
| @@ -32,7 +32,8 @@ public class GuiTurtle extends HandledScreen<ContainerTurtle> { | ||||
|     private WidgetTerminal terminal; | ||||
|     private WidgetWrapper terminalWrapper; | ||||
|  | ||||
|     public GuiTurtle(ContainerTurtle container, PlayerInventory player, Text title) { | ||||
|     public GuiTurtle( ContainerTurtle container, PlayerInventory player, Text title ) | ||||
|     { | ||||
|         super( container, player, title ); | ||||
|  | ||||
|         this.m_container = container; | ||||
| @@ -44,7 +45,8 @@ public class GuiTurtle extends HandledScreen<ContainerTurtle> { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void init() { | ||||
|     protected void init() | ||||
|     { | ||||
|         super.init(); | ||||
|         this.client.keyboard.setRepeatEvents( true ); | ||||
|  | ||||
| @@ -59,19 +61,22 @@ public class GuiTurtle extends HandledScreen<ContainerTurtle> { | ||||
|     } | ||||
|  | ||||
|     @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 ); | ||||
|         super.render( stack, mouseX, mouseY, partialTicks ); | ||||
|         this.drawMouseoverTooltip( stack, mouseX, mouseY ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void drawForeground(@Nonnull MatrixStack transform, int mouseX, int mouseY) { | ||||
|     protected void drawForeground( @Nonnull MatrixStack transform, int mouseX, int mouseY ) | ||||
|     { | ||||
|         // Skip rendering labels. | ||||
|     } | ||||
|  | ||||
|     @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 | ||||
|         Identifier texture = this.m_family == ComputerFamily.ADVANCED ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL; | ||||
|         this.terminal.draw( this.terminalWrapper.getX(), this.terminalWrapper.getY() ); | ||||
| @@ -84,7 +89,8 @@ public class GuiTurtle extends HandledScreen<ContainerTurtle> { | ||||
|  | ||||
|         // Draw selection slot | ||||
|         int slot = this.m_container.getSelectedSlot(); | ||||
|         if (slot >= 0) { | ||||
|         if( slot >= 0 ) | ||||
|         { | ||||
|             int slotX = 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, | ||||
| @@ -96,14 +102,17 @@ public class GuiTurtle extends HandledScreen<ContainerTurtle> { | ||||
|     } | ||||
|  | ||||
|     @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 ); | ||||
|     } | ||||
|  | ||||
|     @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. | ||||
|         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 ); | ||||
|         } | ||||
|  | ||||
| @@ -111,7 +120,8 @@ public class GuiTurtle extends HandledScreen<ContainerTurtle> { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void removed() { | ||||
|     public void removed() | ||||
|     { | ||||
|         super.removed(); | ||||
|         this.children.remove( this.terminal ); | ||||
|         this.terminal = null; | ||||
| @@ -119,7 +129,8 @@ public class GuiTurtle extends HandledScreen<ContainerTurtle> { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void tick() { | ||||
|     public void tick() | ||||
|     { | ||||
|         super.tick(); | ||||
|         this.terminal.update(); | ||||
|     } | ||||
|   | ||||
| @@ -6,23 +6,23 @@ | ||||
|  | ||||
| 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.core.terminal.Terminal; | ||||
| import dan200.computercraft.shared.computer.core.ClientComputer; | ||||
| import dan200.computercraft.shared.computer.core.IComputer; | ||||
| import org.lwjgl.glfw.GLFW; | ||||
|  | ||||
| import net.minecraft.SharedConstants; | ||||
| import net.minecraft.client.MinecraftClient; | ||||
| 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 final MinecraftClient client; | ||||
| @@ -43,7 +43,8 @@ public class WidgetTerminal implements Element { | ||||
|     private int lastMouseY = -1; | ||||
|  | ||||
|     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.computer = computer; | ||||
|         this.termWidth = termWidth; | ||||
| @@ -55,14 +56,17 @@ public class WidgetTerminal implements Element { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean mouseClicked(double mouseX, double mouseY, int button) { | ||||
|     public boolean mouseClicked( double mouseX, double mouseY, int button ) | ||||
|     { | ||||
|         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; | ||||
|         } | ||||
|  | ||||
|         Terminal term = computer.getTerminal(); | ||||
|         if (term != null) { | ||||
|         if( term != null ) | ||||
|         { | ||||
|             int charX = (int) (mouseX / FONT_WIDTH); | ||||
|             int charY = (int) (mouseY / FONT_HEIGHT); | ||||
|             charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); | ||||
| @@ -79,20 +83,24 @@ public class WidgetTerminal implements Element { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean mouseReleased(double mouseX, double mouseY, int button) { | ||||
|     public boolean mouseReleased( double mouseX, double mouseY, int button ) | ||||
|     { | ||||
|         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; | ||||
|         } | ||||
|  | ||||
|         Terminal term = computer.getTerminal(); | ||||
|         if (term != null) { | ||||
|         if( term != null ) | ||||
|         { | ||||
|             int charX = (int) (mouseX / FONT_WIDTH); | ||||
|             int charY = (int) (mouseY / FONT_HEIGHT); | ||||
|             charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 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 ); | ||||
|                 this.lastMouseButton = -1; | ||||
|             } | ||||
| @@ -105,20 +113,24 @@ public class WidgetTerminal implements Element { | ||||
|     } | ||||
|  | ||||
|     @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(); | ||||
|         if (computer == null || !computer.isColour() || button < 0 || button > 2) { | ||||
|         if( computer == null || !computer.isColour() || button < 0 || button > 2 ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         Terminal term = computer.getTerminal(); | ||||
|         if (term != null) { | ||||
|         if( term != null ) | ||||
|         { | ||||
|             int charX = (int) (mouseX / FONT_WIDTH); | ||||
|             int charY = (int) (mouseY / FONT_HEIGHT); | ||||
|             charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 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 ); | ||||
|                 this.lastMouseX = charX; | ||||
|                 this.lastMouseY = charY; | ||||
| @@ -129,14 +141,17 @@ public class WidgetTerminal implements Element { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean mouseScrolled(double mouseX, double mouseY, double delta) { | ||||
|     public boolean mouseScrolled( double mouseX, double mouseY, double delta ) | ||||
|     { | ||||
|         ClientComputer computer = this.computer.get(); | ||||
|         if (computer == null || !computer.isColour() || delta == 0) { | ||||
|         if( computer == null || !computer.isColour() || delta == 0 ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         Terminal term = computer.getTerminal(); | ||||
|         if (term != null) { | ||||
|         if( term != null ) | ||||
|         { | ||||
|             int charX = (int) (mouseX / FONT_WIDTH); | ||||
|             int charY = (int) (mouseY / FONT_HEIGHT); | ||||
|             charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); | ||||
| @@ -152,24 +167,31 @@ public class WidgetTerminal implements Element { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean keyPressed(int key, int scancode, int modifiers) { | ||||
|         if (key == GLFW.GLFW_KEY_ESCAPE) { | ||||
|     public boolean keyPressed( int key, int scancode, int modifiers ) | ||||
|     { | ||||
|         if( key == GLFW.GLFW_KEY_ESCAPE ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|         if ((modifiers & GLFW.GLFW_MOD_CONTROL) != 0) { | ||||
|             switch (key) { | ||||
|         if( (modifiers & GLFW.GLFW_MOD_CONTROL) != 0 ) | ||||
|         { | ||||
|             switch( key ) | ||||
|             { | ||||
|                 case GLFW.GLFW_KEY_T: | ||||
|                 if (this.terminateTimer < 0) { | ||||
|                     if( this.terminateTimer < 0 ) | ||||
|                     { | ||||
|                         this.terminateTimer = 0; | ||||
|                     } | ||||
|                     return true; | ||||
|                 case GLFW.GLFW_KEY_S: | ||||
|                 if (this.shutdownTimer < 0) { | ||||
|                     if( this.shutdownTimer < 0 ) | ||||
|                     { | ||||
|                         this.shutdownTimer = 0; | ||||
|                     } | ||||
|                     return true; | ||||
|                 case GLFW.GLFW_KEY_R: | ||||
|                 if (this.rebootTimer < 0) { | ||||
|                     if( this.rebootTimer < 0 ) | ||||
|                     { | ||||
|                         this.rebootTimer = 0; | ||||
|                     } | ||||
|                     return true; | ||||
| @@ -177,23 +199,31 @@ public class WidgetTerminal implements Element { | ||||
|                 case GLFW.GLFW_KEY_V: | ||||
|                     // Ctrl+V for paste | ||||
|                     String clipboard = this.client.keyboard.getClipboard(); | ||||
|                 if (clipboard != null) { | ||||
|                     if( clipboard != null ) | ||||
|                     { | ||||
|                         // Clip to the first occurrence of \r or \n | ||||
|                         int newLineIndex1 = clipboard.indexOf( "\r" ); | ||||
|                         int newLineIndex2 = clipboard.indexOf( "\n" ); | ||||
|                     if (newLineIndex1 >= 0 && newLineIndex2 >= 0) { | ||||
|                         if( newLineIndex1 >= 0 && newLineIndex2 >= 0 ) | ||||
|                         { | ||||
|                             clipboard = clipboard.substring( 0, Math.min( newLineIndex1, newLineIndex2 ) ); | ||||
|                     } else if (newLineIndex1 >= 0) { | ||||
|                         } | ||||
|                         else if( newLineIndex1 >= 0 ) | ||||
|                         { | ||||
|                             clipboard = clipboard.substring( 0, newLineIndex1 ); | ||||
|                     } else if (newLineIndex2 >= 0) { | ||||
|                         } | ||||
|                         else if( newLineIndex2 >= 0 ) | ||||
|                         { | ||||
|                             clipboard = clipboard.substring( 0, newLineIndex2 ); | ||||
|                         } | ||||
|  | ||||
|                         // Filter the string | ||||
|                         clipboard = SharedConstants.stripInvalidChars( clipboard ); | ||||
|                     if (!clipboard.isEmpty()) { | ||||
|                         if( !clipboard.isEmpty() ) | ||||
|                         { | ||||
|                             // Clip to 512 characters and queue the event | ||||
|                         if (clipboard.length() > 512) { | ||||
|                             if( clipboard.length() > 512 ) | ||||
|                             { | ||||
|                                 clipboard = clipboard.substring( 0, 512 ); | ||||
|                             } | ||||
|                             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 | ||||
|             boolean repeat = this.keysDown.get( key ); | ||||
|             this.keysDown.set( key ); | ||||
|             IComputer computer = this.computer.get(); | ||||
|             if (computer != null) { | ||||
|             if( computer != null ) | ||||
|             { | ||||
|                 computer.keyDown( key, repeat ); | ||||
|             } | ||||
|         } | ||||
| @@ -218,17 +250,21 @@ public class WidgetTerminal implements Element { | ||||
|     } | ||||
|  | ||||
|     @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 | ||||
|         if (key >= 0 && this.keysDown.get(key)) { | ||||
|         if( key >= 0 && this.keysDown.get( key ) ) | ||||
|         { | ||||
|             this.keysDown.set( key, false ); | ||||
|             IComputer computer = this.computer.get(); | ||||
|             if (computer != null) { | ||||
|             if( computer != null ) | ||||
|             { | ||||
|                 computer.keyUp( key ); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         switch (key) { | ||||
|         switch( key ) | ||||
|         { | ||||
|             case GLFW.GLFW_KEY_T: | ||||
|                 this.terminateTimer = -1; | ||||
|                 break; | ||||
| @@ -248,7 +284,8 @@ public class WidgetTerminal implements Element { | ||||
|     } | ||||
|  | ||||
|     @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 | ||||
|         { | ||||
|             // Queue the "char" event | ||||
| @@ -259,20 +296,26 @@ public class WidgetTerminal implements Element { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean changeFocus(boolean reversed) { | ||||
|         if (this.focused) { | ||||
|     public boolean changeFocus( boolean reversed ) | ||||
|     { | ||||
|         if( this.focused ) | ||||
|         { | ||||
|             // When blurring, we should make all keys go up | ||||
|             for (int key = 0; key < this.keysDown.size(); key++) { | ||||
|                 if (this.keysDown.get(key)) { | ||||
|             for( int key = 0; key < this.keysDown.size(); key++ ) | ||||
|             { | ||||
|                 if( this.keysDown.get( key ) ) | ||||
|                 { | ||||
|                     this.queueEvent( "key_up", key ); | ||||
|                 } | ||||
|             } | ||||
|             this.keysDown.clear(); | ||||
|  | ||||
|             // When blurring, we should make the last mouse button go up | ||||
|             if (this.lastMouseButton > 0) { | ||||
|             if( this.lastMouseButton > 0 ) | ||||
|             { | ||||
|                 IComputer computer = this.computer.get(); | ||||
|                 if (computer != null) { | ||||
|                 if( computer != null ) | ||||
|                 { | ||||
|                     computer.mouseUp( this.lastMouseButton + 1, this.lastMouseX + 1, this.lastMouseY + 1 ); | ||||
|                 } | ||||
|                 this.lastMouseButton = -1; | ||||
| @@ -285,53 +328,69 @@ public class WidgetTerminal implements Element { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isMouseOver(double x, double y) { | ||||
|     public boolean isMouseOver( double x, double y ) | ||||
|     { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     private void queueEvent(String event, Object... args) { | ||||
|     private void queueEvent( String event, Object... args ) | ||||
|     { | ||||
|         ClientComputer computer = this.computer.get(); | ||||
|         if (computer != null) { | ||||
|         if( computer != null ) | ||||
|         { | ||||
|             computer.queueEvent( event, args ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void update() { | ||||
|         if (this.terminateTimer >= 0 && this.terminateTimer < TERMINATE_TIME && (this.terminateTimer += 0.05f) > TERMINATE_TIME) { | ||||
|     public void update() | ||||
|     { | ||||
|         if( this.terminateTimer >= 0 && this.terminateTimer < TERMINATE_TIME && (this.terminateTimer += 0.05f) > TERMINATE_TIME ) | ||||
|         { | ||||
|             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(); | ||||
|             if (computer != null) { | ||||
|             if( computer != null ) | ||||
|             { | ||||
|                 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(); | ||||
|             if (computer != null) { | ||||
|             if( computer != null ) | ||||
|             { | ||||
|                 computer.reboot(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void queueEvent(String event) { | ||||
|     private void queueEvent( String event ) | ||||
|     { | ||||
|         ClientComputer computer = this.computer.get(); | ||||
|         if (computer != null) { | ||||
|         if( computer != null ) | ||||
|         { | ||||
|             computer.queueEvent( event ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void draw(int originX, int originY) { | ||||
|         synchronized (this.computer) { | ||||
|     public void draw( int originX, int originY ) | ||||
|     { | ||||
|         synchronized( this.computer ) | ||||
|         { | ||||
|             // Draw the screen contents | ||||
|             ClientComputer computer = this.computer.get(); | ||||
|             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, | ||||
|                     this.rightMargin ); | ||||
|             } else { | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 FixedWidthFontRenderer.drawEmptyTerminal( originX - this.leftMargin, | ||||
|                     originY - this.rightMargin, this.termWidth * FONT_WIDTH + this.leftMargin + this.rightMargin, | ||||
|                     this.termHeight * FONT_HEIGHT + this.topMargin + this.bottomMargin ); | ||||
|   | ||||
| @@ -8,14 +8,16 @@ package dan200.computercraft.client.gui.widgets; | ||||
|  | ||||
| import net.minecraft.client.gui.Element; | ||||
|  | ||||
| public class WidgetWrapper implements Element { | ||||
| public class WidgetWrapper implements Element | ||||
| { | ||||
|     private final Element listener; | ||||
|     private final int x; | ||||
|     private final int y; | ||||
|     private final int width; | ||||
|     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.x = x; | ||||
|         this.y = y; | ||||
| @@ -24,68 +26,81 @@ public class WidgetWrapper implements Element { | ||||
|     } | ||||
|  | ||||
|     @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; | ||||
|         return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height && this.listener.mouseClicked( dx, dy, button ); | ||||
|     } | ||||
|  | ||||
|     @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; | ||||
|         return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height && this.listener.mouseReleased( dx, dy, button ); | ||||
|     } | ||||
|  | ||||
|     @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; | ||||
|         return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height && this.listener.mouseDragged( dx, dy, button, deltaX, deltaY ); | ||||
|     } | ||||
|  | ||||
|     @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; | ||||
|         return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height && this.listener.mouseScrolled( dx, dy, delta ); | ||||
|     } | ||||
|  | ||||
|     @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 ); | ||||
|     } | ||||
|  | ||||
|     @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 ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean charTyped(char character, int modifiers) { | ||||
|     public boolean charTyped( char character, int modifiers ) | ||||
|     { | ||||
|         return this.listener.charTyped( character, modifiers ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean changeFocus(boolean b) { | ||||
|     public boolean changeFocus( boolean b ) | ||||
|     { | ||||
|         return this.listener.changeFocus( b ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isMouseOver(double x, double y) { | ||||
|     public boolean isMouseOver( double x, double y ) | ||||
|     { | ||||
|         double dx = x - this.x, dy = y - this.y; | ||||
|         return dx >= 0 && dx < this.width && dy >= 0 && dy < this.height; | ||||
|     } | ||||
|  | ||||
|     public int getX() { | ||||
|     public int getX() | ||||
|     { | ||||
|         return this.x; | ||||
|     } | ||||
|  | ||||
|     public int getY() { | ||||
|     public int getY() | ||||
|     { | ||||
|         return this.y; | ||||
|     } | ||||
|  | ||||
|     public int getWidth() { | ||||
|     public int getWidth() | ||||
|     { | ||||
|         return this.width; | ||||
|     } | ||||
|  | ||||
|     public int getHeight() { | ||||
|     public int getHeight() | ||||
|     { | ||||
|         return this.height; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,16 +6,10 @@ | ||||
|  | ||||
| package dan200.computercraft.client.proxy; | ||||
|  | ||||
| import java.util.function.Supplier; | ||||
|  | ||||
| import dan200.computercraft.ComputerCraft; | ||||
| import dan200.computercraft.client.ClientRegistry; | ||||
| import dan200.computercraft.client.FrameInfo; | ||||
| import dan200.computercraft.client.gui.GuiComputer; | ||||
| 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.gui.*; | ||||
| import dan200.computercraft.client.render.TileEntityMonitorRenderer; | ||||
| import dan200.computercraft.client.render.TileEntityTurtleRenderer; | ||||
| 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.items.ItemPocketComputer; | ||||
| import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; | ||||
|  | ||||
| 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.EnvType; | ||||
| import net.fabricmc.api.Environment; | ||||
| 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.rendereregistry.v1.BlockEntityRendererRegistry; | ||||
| import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry; | ||||
| import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry; | ||||
| import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; | ||||
| 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 ) | ||||
| 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 ) -> { | ||||
|             if(blockEntity instanceof TileGeneric ) { | ||||
|             if( blockEntity instanceof TileGeneric ) | ||||
|             { | ||||
|                 ((TileGeneric) blockEntity).onChunkUnloaded(); | ||||
|             } | ||||
|         } ); | ||||
| @@ -71,7 +68,8 @@ public final class ComputerCraftProxyClient implements ClientModInitializer { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onInitializeClient() { | ||||
|     public void onInitializeClient() | ||||
|     { | ||||
|         FrameInfo.init(); | ||||
|         registerContainers(); | ||||
|  | ||||
| @@ -113,7 +111,8 @@ public final class ComputerCraftProxyClient implements ClientModInitializer { | ||||
|     } | ||||
|  | ||||
|     // 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.<ContainerPocketComputer, GuiComputer<ContainerPocketComputer>>register( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER, | ||||
|             GuiComputer::createPocket ); | ||||
| @@ -128,9 +127,11 @@ public final class ComputerCraftProxyClient implements ClientModInitializer { | ||||
|     } | ||||
|  | ||||
|     @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 ); | ||||
|         for (Supplier<? extends Item> item : items) { | ||||
|         for( Supplier<? extends Item> item : items ) | ||||
|         { | ||||
|             ModelPredicateProviderRegistrySpecificAccessor.callRegister( item.get(), id, getter ); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -10,7 +10,8 @@ import dan200.computercraft.shared.ComputerCraftRegistry; | ||||
| import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; | ||||
| import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; | ||||
| import dan200.computercraft.shared.util.WorldUtil; | ||||
|  | ||||
| import net.fabricmc.api.EnvType; | ||||
| import net.fabricmc.api.Environment; | ||||
| import net.minecraft.block.BlockState; | ||||
| import net.minecraft.client.MinecraftClient; | ||||
| 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.world.World; | ||||
|  | ||||
| import net.fabricmc.api.EnvType; | ||||
| import net.fabricmc.api.Environment; | ||||
|  | ||||
| @Environment( EnvType.CLIENT ) | ||||
| public final class CableHighlightRenderer { | ||||
|     private CableHighlightRenderer() { | ||||
| public final class CableHighlightRenderer | ||||
| { | ||||
|     private CableHighlightRenderer() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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, | ||||
|                                         BlockState state) { | ||||
|                                          BlockState state ) | ||||
|     { | ||||
|         World world = entity.getEntityWorld(); | ||||
|         Camera info = MinecraftClient.getInstance().gameRenderer.getCamera(); | ||||
|  | ||||
|         // We only care about instances with both cable and 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; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -5,21 +5,21 @@ | ||||
|  */ | ||||
| package dan200.computercraft.client.render; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import com.mojang.blaze3d.systems.RenderSystem; | ||||
| import dan200.computercraft.ComputerCraft; | ||||
| import dan200.computercraft.shared.computer.core.ComputerFamily; | ||||
| import org.lwjgl.opengl.GL11; | ||||
|  | ||||
| import net.minecraft.client.render.BufferBuilder; | ||||
| import net.minecraft.client.render.Tessellator; | ||||
| import net.minecraft.client.render.VertexConsumer; | ||||
| import net.minecraft.client.render.VertexFormats; | ||||
| import net.minecraft.util.Identifier; | ||||
| 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_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" ); | ||||
| @@ -44,7 +44,8 @@ public class ComputerBorderRenderer { | ||||
|     public static final int LIGHT_HEIGHT = 8; | ||||
|     private static final float TEX_SCALE = 1 / 256.0f; | ||||
|  | ||||
|     static { | ||||
|     static | ||||
|     { | ||||
|         IDENTITY.loadIdentity(); | ||||
|     } | ||||
|  | ||||
| @@ -53,7 +54,8 @@ public class ComputerBorderRenderer { | ||||
|     private final int z; | ||||
|     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.builder = builder; | ||||
|         this.z = z; | ||||
| @@ -64,8 +66,10 @@ public class ComputerBorderRenderer { | ||||
|  | ||||
|  | ||||
|     @Nonnull | ||||
|     public static Identifier getTexture(@Nonnull ComputerFamily family) { | ||||
|         switch (family) { | ||||
|     public static Identifier getTexture( @Nonnull ComputerFamily family ) | ||||
|     { | ||||
|         switch( family ) | ||||
|         { | ||||
|             case NORMAL: | ||||
|             default: | ||||
|                 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(); | ||||
|         BufferBuilder buffer = tessellator.getBuffer(); | ||||
|         buffer.begin( GL11.GL_QUADS, VertexFormats.POSITION_COLOR_TEXTURE ); | ||||
| @@ -87,11 +92,13 @@ public class ComputerBorderRenderer { | ||||
|         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 ); | ||||
|     } | ||||
|  | ||||
|     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 ); | ||||
|     } | ||||
|  | ||||
| @@ -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 ); | ||||
|     } | ||||
|  | ||||
|     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 ); | ||||
|     } | ||||
|  | ||||
|     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 ); | ||||
|     } | ||||
|  | ||||
|     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 ) | ||||
|             .color( this.r, this.g, this.b, 1.0f ) | ||||
|             .texture( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE ) | ||||
|   | ||||
| @@ -7,7 +7,8 @@ | ||||
| package dan200.computercraft.client.render; | ||||
|  | ||||
| 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.render.VertexConsumerProvider; | ||||
| 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.math.MathHelper; | ||||
|  | ||||
| import net.fabricmc.api.EnvType; | ||||
| import net.fabricmc.api.Environment; | ||||
|  | ||||
| @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 | ||||
|         , float swingProgress, ItemStack stack) { | ||||
|         , float swingProgress, ItemStack stack ) | ||||
|     { | ||||
|         PlayerEntity player = MinecraftClient.getInstance().player; | ||||
|  | ||||
|         transform.push(); | ||||
|         if( hand == Hand.MAIN_HAND && player.getOffHandStack() | ||||
|                                             .isEmpty()) { | ||||
|             .isEmpty() ) | ||||
|         { | ||||
|             this.renderItemFirstPersonCenter( transform, render, lightTexture, pitch, equipProgress, swingProgress, stack ); | ||||
|         } else { | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             this.renderItemFirstPersonSide( transform, | ||||
|                 render, | ||||
|                 lightTexture, | ||||
| @@ -57,7 +60,8 @@ public abstract class ItemMapLikeRenderer { | ||||
|      * @param stack         The stack to render | ||||
|      */ | ||||
|     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(); | ||||
|         HeldItemRenderer renderer = minecraft.getHeldItemRenderer(); | ||||
|  | ||||
| @@ -72,7 +76,8 @@ public abstract class ItemMapLikeRenderer { | ||||
|         float pitchAngle = access.callGetMapAngle( pitch ); | ||||
|         transform.translate( 0, 0.04F + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f ); | ||||
|         transform.multiply( Vector3f.POSITIVE_X.getDegreesQuaternion( pitchAngle * -85.0f ) ); | ||||
|         if (!minecraft.player.isInvisible()) { | ||||
|         if( !minecraft.player.isInvisible() ) | ||||
|         { | ||||
|             transform.push(); | ||||
|             transform.multiply( Vector3f.POSITIVE_Y.getDegreesQuaternion( 90.0F ) ); | ||||
|             access.callRenderArm( transform, render, combinedLight, Arm.RIGHT ); | ||||
| @@ -99,13 +104,15 @@ public abstract class ItemMapLikeRenderer { | ||||
|      * @param stack         The stack to render | ||||
|      */ | ||||
|     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(); | ||||
|         float offset = side == Arm.RIGHT ? 1f : -1f; | ||||
|         transform.translate( offset * 0.125f, -0.125f, 0f ); | ||||
|  | ||||
|         // If the player is not invisible then render a single arm | ||||
|         if (!minecraft.player.isInvisible()) { | ||||
|         if( !minecraft.player.isInvisible() ) | ||||
|         { | ||||
|             transform.push(); | ||||
|             transform.multiply( Vector3f.POSITIVE_Z.getDegreesQuaternion( offset * 10f ) ); | ||||
|             ((HeldItemRendererAccess) minecraft.getHeldItemRenderer()) | ||||
|   | ||||
| @@ -6,12 +6,6 @@ | ||||
|  | ||||
| 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 dan200.computercraft.ComputerCraft; | ||||
| 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.pocket.items.ItemPocketComputer; | ||||
| import dan200.computercraft.shared.util.Colour; | ||||
| import org.lwjgl.opengl.GL11; | ||||
|  | ||||
| import net.minecraft.client.MinecraftClient; | ||||
| import net.minecraft.client.render.BufferBuilder; | ||||
| 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.item.ItemStack; | ||||
| 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.*; | ||||
|  | ||||
| /** | ||||
|  * 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(); | ||||
|  | ||||
|     private ItemPocketRenderer() { | ||||
|     private ItemPocketRenderer() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void renderItem(MatrixStack transform, VertexConsumerProvider render, ItemStack stack) { | ||||
|     protected void renderItem( MatrixStack transform, VertexConsumerProvider render, ItemStack stack ) | ||||
|     { | ||||
|         ClientComputer computer = ItemPocketComputer.createClientComputer( stack ); | ||||
|         Terminal terminal = computer == null ? null : computer.getTerminal(); | ||||
|  | ||||
|         int termWidth, termHeight; | ||||
|         if (terminal == null) { | ||||
|         if( terminal == null ) | ||||
|         { | ||||
|             termWidth = ComputerCraft.pocketTermWidth; | ||||
|             termHeight = ComputerCraft.pocketTermHeight; | ||||
|         } else { | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             termWidth = terminal.getWidth(); | ||||
|             termHeight = terminal.getHeight(); | ||||
|         } | ||||
| @@ -82,21 +83,26 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer { | ||||
|  | ||||
|         // Render the light | ||||
|         int lightColour = ItemPocketComputer.getLightState( stack ); | ||||
|         if (lightColour == -1) { | ||||
|         if( lightColour == -1 ) | ||||
|         { | ||||
|             lightColour = Colour.BLACK.getHex(); | ||||
|         } | ||||
|         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 ); | ||||
|         } else { | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             FixedWidthFontRenderer.drawEmptyTerminal( matrix, 0, 0, width, height ); | ||||
|         } | ||||
|  | ||||
|         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(); | ||||
|         MinecraftClient.getInstance() | ||||
|             .getTextureManager() | ||||
| @@ -115,7 +121,8 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer { | ||||
|         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(); | ||||
|  | ||||
|         float r = ((colour >>> 16) & 0xFF) / 255.0f; | ||||
|   | ||||
| @@ -6,36 +6,33 @@ | ||||
|  | ||||
| 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 net.minecraft.client.render.VertexConsumerProvider; | ||||
| import net.minecraft.client.util.math.MatrixStack; | ||||
| import net.minecraft.client.util.math.Vector3f; | ||||
| import net.minecraft.item.ItemStack; | ||||
| 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. | ||||
|  */ | ||||
| public final class ItemPrintoutRenderer extends ItemMapLikeRenderer { | ||||
| public final class ItemPrintoutRenderer extends ItemMapLikeRenderer | ||||
| { | ||||
|     public static final ItemPrintoutRenderer INSTANCE = new ItemPrintoutRenderer(); | ||||
|  | ||||
|     private ItemPrintoutRenderer() { | ||||
|     private ItemPrintoutRenderer() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     @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.scale( 0.42f, 0.42f, -0.42f ); | ||||
|         transform.translate( -0.5f, -0.48f, 0.0f ); | ||||
| @@ -43,7 +40,8 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer { | ||||
|         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 ); | ||||
|         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; | ||||
|  | ||||
|         // Non-books will be left aligned | ||||
|         if (!book) { | ||||
|         if( !book ) | ||||
|         { | ||||
|             width += offsetAt( pages ); | ||||
|         } | ||||
|  | ||||
|         double visualWidth = width, visualHeight = height; | ||||
|  | ||||
|         // Meanwhile books will be centred | ||||
|         if (book) { | ||||
|         if( book ) | ||||
|         { | ||||
|             visualWidth += 2 * COVER_SIZE + 2 * offsetAt( pages ); | ||||
|             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 ) ); | ||||
|     } | ||||
|  | ||||
|     public boolean renderInFrame(MatrixStack matrixStack, VertexConsumerProvider consumerProvider, ItemStack stack) { | ||||
|         if (!(stack.getItem() instanceof ItemPrintout)) { | ||||
|     public boolean renderInFrame( MatrixStack matrixStack, VertexConsumerProvider consumerProvider, ItemStack stack ) | ||||
|     { | ||||
|         if( !(stack.getItem() instanceof ItemPrintout) ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -5,10 +5,9 @@ | ||||
|  */ | ||||
| package dan200.computercraft.client.render; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| 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.VertexFormatElement; | ||||
| 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.util.math.Matrix4f; | ||||
|  | ||||
| import net.fabricmc.api.EnvType; | ||||
| import net.fabricmc.api.Environment; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * Transforms vertices of a model, remaining aware of winding order, and rearranging vertices if needed. | ||||
|  */ | ||||
| @Environment( EnvType.CLIENT ) | ||||
| public final class ModelTransformer { | ||||
| public final class ModelTransformer | ||||
| { | ||||
|     private static final Matrix4f identity; | ||||
|  | ||||
|     static { | ||||
|     static | ||||
|     { | ||||
|         identity = new Matrix4f(); | ||||
|         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 ); | ||||
|     } | ||||
|  | ||||
|     public static void transformQuadsTo(VertexFormat format, List<BakedQuad> output, List<BakedQuad> input, Matrix4f transform) { | ||||
|         if (transform == null || transform.equals(identity)) { | ||||
|     public static void transformQuadsTo( VertexFormat format, List<BakedQuad> output, List<BakedQuad> input, Matrix4f transform ) | ||||
|     { | ||||
|         if( transform == null || transform.equals( identity ) ) | ||||
|         { | ||||
|             output.addAll( input ); | ||||
|         } else { | ||||
|             for (BakedQuad quad : input) { | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             for( BakedQuad quad : input ) | ||||
|             { | ||||
|                 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(); | ||||
|         BakedQuad copy = new BakedQuad( vertexData, -1, quad.getFace(), ((BakedQuadAccess) quad).getSprite(), true ); | ||||
|  | ||||
|         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 | ||||
|             { | ||||
|                 int start = offsetBytes / Integer.BYTES; | ||||
| @@ -78,8 +87,10 @@ public final class ModelTransformer { | ||||
|         return copy; | ||||
|     } | ||||
|  | ||||
|     public static BakedQuad transformQuad(VertexFormat format, BakedQuad input, Matrix4f transform) { | ||||
|         if (transform == null || transform.equals(identity)) { | ||||
|     public static BakedQuad transformQuad( VertexFormat format, BakedQuad input, Matrix4f transform ) | ||||
|     { | ||||
|         if( transform == null || transform.equals( identity ) ) | ||||
|         { | ||||
|             return input; | ||||
|         } | ||||
|         return doTransformQuad( format, input, transform ); | ||||
|   | ||||
| @@ -6,17 +6,9 @@ | ||||
|  | ||||
| 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 net.fabricmc.api.EnvType; | ||||
| import net.fabricmc.api.Environment; | ||||
| import net.minecraft.block.BlockState; | ||||
| import net.minecraft.block.entity.BlockEntity; | ||||
| import net.minecraft.client.MinecraftClient; | ||||
| @@ -29,29 +21,35 @@ import net.minecraft.util.math.Matrix4f; | ||||
| import net.minecraft.util.math.Vec3d; | ||||
| import net.minecraft.world.World; | ||||
|  | ||||
| import net.fabricmc.api.EnvType; | ||||
| import net.fabricmc.api.Environment; | ||||
| import java.util.EnumSet; | ||||
|  | ||||
| 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 | ||||
|  * intrusive outline on top of the screen. | ||||
|  */ | ||||
| @Environment( EnvType.CLIENT ) | ||||
| public final class MonitorHighlightRenderer { | ||||
|     private MonitorHighlightRenderer() { | ||||
| public final class MonitorHighlightRenderer | ||||
| { | ||||
|     private MonitorHighlightRenderer() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     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. | ||||
|         if (entity.isInSneakingPose()) { | ||||
|         if( entity.isInSneakingPose() ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         World world = entity.getEntityWorld(); | ||||
|  | ||||
|         BlockEntity tile = world.getBlockEntity( pos ); | ||||
|         if (!(tile instanceof TileMonitor)) { | ||||
|         if( !(tile instanceof TileMonitor) ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
| @@ -61,18 +59,22 @@ public final class MonitorHighlightRenderer { | ||||
|         EnumSet<Direction> faces = EnumSet.allOf( Direction.class ); | ||||
|         Direction front = monitor.getFront(); | ||||
|         faces.remove( front ); | ||||
|         if (monitor.getXIndex() != 0) { | ||||
|         if( monitor.getXIndex() != 0 ) | ||||
|         { | ||||
|             faces.remove( monitor.getRight() | ||||
|                 .getOpposite() ); | ||||
|         } | ||||
|         if (monitor.getXIndex() != monitor.getWidth() - 1) { | ||||
|         if( monitor.getXIndex() != monitor.getWidth() - 1 ) | ||||
|         { | ||||
|             faces.remove( monitor.getRight() ); | ||||
|         } | ||||
|         if (monitor.getYIndex() != 0) { | ||||
|         if( monitor.getYIndex() != 0 ) | ||||
|         { | ||||
|             faces.remove( monitor.getDown() | ||||
|                 .getOpposite() ); | ||||
|         } | ||||
|         if (monitor.getYIndex() != monitor.getHeight() - 1) { | ||||
|         if( monitor.getYIndex() != monitor.getHeight() - 1 ) | ||||
|         { | ||||
|             faces.remove( monitor.getDown() ); | ||||
|         } | ||||
|  | ||||
| @@ -84,40 +86,52 @@ public final class MonitorHighlightRenderer { | ||||
|         // I wish I could think of a better way to do this | ||||
|         Matrix4f transform = matrixStack.peek() | ||||
|             .getModel(); | ||||
|         if (faces.contains(NORTH) || faces.contains(WEST)) { | ||||
|         if( faces.contains( NORTH ) || faces.contains( WEST ) ) | ||||
|         { | ||||
|             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 ); | ||||
|         } | ||||
|         if (faces.contains(NORTH) || faces.contains(EAST)) { | ||||
|         if( faces.contains( NORTH ) || faces.contains( EAST ) ) | ||||
|         { | ||||
|             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 ); | ||||
|         } | ||||
|         if (faces.contains(NORTH) || faces.contains(DOWN)) { | ||||
|         if( faces.contains( NORTH ) || faces.contains( DOWN ) ) | ||||
|         { | ||||
|             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 ); | ||||
|         } | ||||
|         if (faces.contains(NORTH) || faces.contains(UP)) { | ||||
|         if( faces.contains( NORTH ) || faces.contains( UP ) ) | ||||
|         { | ||||
|             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 ); | ||||
|         } | ||||
|         if (faces.contains(WEST) || faces.contains(DOWN)) { | ||||
|         if( faces.contains( WEST ) || faces.contains( DOWN ) ) | ||||
|         { | ||||
|             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 ); | ||||
|         } | ||||
|         if (faces.contains(WEST) || faces.contains(UP)) { | ||||
|         if( faces.contains( WEST ) || faces.contains( UP ) ) | ||||
|         { | ||||
|             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 ); | ||||
|         } | ||||
|  | ||||
| @@ -126,7 +140,8 @@ public final class MonitorHighlightRenderer { | ||||
|         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 ) | ||||
|             .color( 0, 0, 0, 0.4f ) | ||||
|             .next(); | ||||
|   | ||||
| @@ -5,23 +5,23 @@ | ||||
|  */ | ||||
| package dan200.computercraft.client.render; | ||||
|  | ||||
| import java.io.InputStream; | ||||
| import java.nio.FloatBuffer; | ||||
|  | ||||
| import com.google.common.base.Strings; | ||||
| import com.mojang.blaze3d.platform.GlStateManager; | ||||
| import com.mojang.blaze3d.systems.RenderSystem; | ||||
| import dan200.computercraft.ComputerCraft; | ||||
| import dan200.computercraft.client.gui.FixedWidthFontRenderer; | ||||
| 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.opengl.GL13; | ||||
| import org.lwjgl.opengl.GL20; | ||||
|  | ||||
| import net.minecraft.client.texture.TextureUtil; | ||||
| import net.minecraft.util.math.Matrix4f; | ||||
| import java.io.InputStream; | ||||
| import java.nio.FloatBuffer; | ||||
|  | ||||
| class MonitorTextureBufferShader { | ||||
| class MonitorTextureBufferShader | ||||
| { | ||||
|     static final int TEXTURE_INDEX = GL13.GL_TEXTURE3; | ||||
|  | ||||
|     private static final FloatBuffer MATRIX_BUFFER = BufferUtils.createFloatBuffer( 16 ); | ||||
| @@ -39,7 +39,8 @@ class MonitorTextureBufferShader { | ||||
|     private static boolean ok; | ||||
|     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(); | ||||
|         transform.writeToBuffer( MATRIX_BUFFER ); | ||||
|         MATRIX_BUFFER.rewind(); | ||||
| @@ -49,14 +50,18 @@ class MonitorTextureBufferShader { | ||||
|         RenderSystem.glUniform1i( uniformHeight, height ); | ||||
|  | ||||
|         PALETTE_BUFFER.rewind(); | ||||
|         for (int i = 0; i < 16; i++) { | ||||
|         for( int i = 0; i < 16; i++ ) | ||||
|         { | ||||
|             double[] colour = palette.getColour( i ); | ||||
|             if (greyscale) { | ||||
|             if( greyscale ) | ||||
|             { | ||||
|                 float f = FixedWidthFontRenderer.toGreyscale( colour ); | ||||
|                 PALETTE_BUFFER.put( f ) | ||||
|                     .put( f ) | ||||
|                     .put( f ); | ||||
|             } else { | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 PALETTE_BUFFER.put( (float) colour[0] ) | ||||
|                     .put( (float) colour[1] ) | ||||
|                     .put( (float) colour[2] ); | ||||
| @@ -66,15 +71,19 @@ class MonitorTextureBufferShader { | ||||
|         RenderSystem.glUniform3( uniformPalette, PALETTE_BUFFER ); | ||||
|     } | ||||
|  | ||||
|     static boolean use() { | ||||
|         if (initialised) { | ||||
|             if (ok) { | ||||
|     static boolean use() | ||||
|     { | ||||
|         if( initialised ) | ||||
|         { | ||||
|             if( ok ) | ||||
|             { | ||||
|                 GlStateManager.useProgram( program ); | ||||
|             } | ||||
|             return ok; | ||||
|         } | ||||
|  | ||||
|         if (ok = load()) { | ||||
|         if( ok = load() ) | ||||
|         { | ||||
|             GL20.glUseProgram( program ); | ||||
|             RenderSystem.glUniform1i( uniformFont, 0 ); | ||||
|             RenderSystem.glUniform1i( uniformTbo, TEXTURE_INDEX - GL13.GL_TEXTURE0 ); | ||||
| @@ -83,10 +92,12 @@ class MonitorTextureBufferShader { | ||||
|         return ok; | ||||
|     } | ||||
|  | ||||
|     private static boolean load() { | ||||
|     private static boolean load() | ||||
|     { | ||||
|         initialised = true; | ||||
|  | ||||
|         try { | ||||
|         try | ||||
|         { | ||||
|             int vertexShader = loadShader( GL20.GL_VERTEX_SHADER, "assets/computercraft/shaders/monitor.vert" ); | ||||
|             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; | ||||
|             String log = GlStateManager.getProgramInfoLog( program, Short.MAX_VALUE ) | ||||
|                 .trim(); | ||||
|             if (!Strings.isNullOrEmpty(log)) { | ||||
|             if( !Strings.isNullOrEmpty( log ) ) | ||||
|             { | ||||
|                 ComputerCraft.log.warn( "Problems when linking monitor shader: {}", log ); | ||||
|             } | ||||
|  | ||||
| @@ -108,7 +120,8 @@ class MonitorTextureBufferShader { | ||||
|             GlStateManager.deleteShader( vertexShader ); | ||||
|             GlStateManager.deleteShader( fragmentShader ); | ||||
|  | ||||
|             if (!ok) { | ||||
|             if( !ok ) | ||||
|             { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
| @@ -121,16 +134,20 @@ class MonitorTextureBufferShader { | ||||
|  | ||||
|             ComputerCraft.log.info( "Loaded monitor shader." ); | ||||
|             return true; | ||||
|         } catch (Exception e) { | ||||
|         } | ||||
|         catch( Exception e ) | ||||
|         { | ||||
|             ComputerCraft.log.error( "Cannot load monitor shaders", e ); | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static int loadShader(int kind, String path) { | ||||
|     private static int loadShader( int kind, String path ) | ||||
|     { | ||||
|         InputStream stream = TileEntityMonitorRenderer.class.getClassLoader() | ||||
|             .getResourceAsStream( path ); | ||||
|         if (stream == null) { | ||||
|         if( stream == null ) | ||||
|         { | ||||
|             throw new IllegalArgumentException( "Cannot find " + path ); | ||||
|         } | ||||
|         String contents = TextureUtil.readAllToString( stream ); | ||||
| @@ -143,19 +160,23 @@ class MonitorTextureBufferShader { | ||||
|         boolean ok = GlStateManager.getShader( shader, GL20.GL_COMPILE_STATUS ) != 0; | ||||
|         String log = GlStateManager.getShaderInfoLog( shader, Short.MAX_VALUE ) | ||||
|             .trim(); | ||||
|         if (!Strings.isNullOrEmpty(log)) { | ||||
|         if( !Strings.isNullOrEmpty( log ) ) | ||||
|         { | ||||
|             ComputerCraft.log.warn( "Problems when loading monitor shader {}: {}", path, log ); | ||||
|         } | ||||
|  | ||||
|         if (!ok) { | ||||
|         if( !ok ) | ||||
|         { | ||||
|             throw new IllegalStateException( "Cannot compile shader " + path ); | ||||
|         } | ||||
|         return shader; | ||||
|     } | ||||
|  | ||||
|     private static int getUniformLocation(int program, String name) { | ||||
|     private static int getUniformLocation( int program, String name ) | ||||
|     { | ||||
|         int uniform = GlStateManager.getUniformLocation( program, name ); | ||||
|         if (uniform == -1) { | ||||
|         if( uniform == -1 ) | ||||
|         { | ||||
|             throw new IllegalStateException( "Cannot find uniform " + name ); | ||||
|         } | ||||
|         return uniform; | ||||
|   | ||||
| @@ -6,23 +6,19 @@ | ||||
|  | ||||
| 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.core.terminal.TextBuffer; | ||||
| import dan200.computercraft.shared.util.Palette; | ||||
| import org.lwjgl.opengl.GL11; | ||||
|  | ||||
| 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.client.render.*; | ||||
| import net.minecraft.util.Identifier; | ||||
| 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. | ||||
|      */ | ||||
| @@ -54,9 +50,11 @@ public final class 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 ); | ||||
|         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, | ||||
|                 buffer, | ||||
|                 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 ); | ||||
|         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, | ||||
|                 buffer, | ||||
|                 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 rightPages = pages - page - 1; | ||||
|  | ||||
|         VertexConsumer buffer = renderer.getBuffer( Type.TYPE ); | ||||
|  | ||||
|         if (isBook) { | ||||
|         if( isBook ) | ||||
|         { | ||||
|             // Border | ||||
|             float offset = offsetAt( pages ); | ||||
|             float left = x - 4 - offset; | ||||
| @@ -118,7 +120,8 @@ public final class PrintoutRenderer { | ||||
|                 Y_SIZE ); | ||||
|  | ||||
|             float borderX = left; | ||||
|             while (borderX < right) { | ||||
|             while( borderX < right ) | ||||
|             { | ||||
|                 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 + 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 | ||||
|         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, | ||||
|                 // Use the left "bold" fold for the outermost page | ||||
|                 n == leftPages ? 0 : X_FOLD_SIZE, 0, X_FOLD_SIZE, Y_SIZE ); | ||||
| @@ -136,18 +140,21 @@ public final class PrintoutRenderer { | ||||
|  | ||||
|         // 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 ); | ||||
|         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, | ||||
|                 // 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 ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static float offsetAt(int page) { | ||||
|     public static float offsetAt( int 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 ) | ||||
|             .texture( u / BG_SIZE, (v + height) / BG_SIZE ) | ||||
|             .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, | ||||
|                                     float tWidth, float tHeight) { | ||||
|                                      float tWidth, float tHeight ) | ||||
|     { | ||||
|         buffer.vertex( matrix, x, y + height, z ) | ||||
|             .texture( u / BG_SIZE, (v + tHeight) / BG_SIZE ) | ||||
|             .next(); | ||||
| @@ -178,7 +186,8 @@ public final class PrintoutRenderer { | ||||
|             .next(); | ||||
|     } | ||||
|  | ||||
|     private static final class Type extends RenderPhase { | ||||
|     private static final class Type extends RenderPhase | ||||
|     { | ||||
|         static final RenderLayer TYPE = RenderLayer.of( "printout_background", | ||||
|             VertexFormats.POSITION_TEXTURE, | ||||
|             GL11.GL_QUADS, | ||||
| @@ -192,7 +201,8 @@ public final class PrintoutRenderer { | ||||
|                 .lightmap( DISABLE_LIGHTMAP ) | ||||
|                 .build( false ) ); | ||||
|  | ||||
|         private Type(String name, Runnable setup, Runnable destroy) { | ||||
|         private Type( String name, Runnable setup, Runnable destroy ) | ||||
|         { | ||||
|             super( name, setup, destroy ); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -6,14 +6,6 @@ | ||||
|  | ||||
| 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 dan200.computercraft.client.FrameInfo; | ||||
| 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.util.Colour; | ||||
| 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.render.BufferBuilder; | ||||
| 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.*; | ||||
| import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; | ||||
| import net.minecraft.client.render.block.entity.BlockEntityRenderer; | ||||
| 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.Direction; | ||||
| 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. | ||||
|      */ | ||||
| @@ -54,17 +47,20 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor> | ||||
|         .getMatrix(); | ||||
|     private static ByteBuffer tboContents; | ||||
|  | ||||
|     public TileEntityMonitorRenderer(BlockEntityRenderDispatcher rendererDispatcher) { | ||||
|     public TileEntityMonitorRenderer( BlockEntityRenderDispatcher rendererDispatcher ) | ||||
|     { | ||||
|         super( rendererDispatcher ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     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 | ||||
|         ClientMonitor originTerminal = monitor.getClientMonitor(); | ||||
|  | ||||
|         if (originTerminal == null) { | ||||
|         if( originTerminal == null ) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|         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 | ||||
|         // pass multiple times. | ||||
|         long renderFrame = FrameInfo.getRenderFrame(); | ||||
|         if (originTerminal.lastRenderFrame == renderFrame && !monitorPos.equals(originTerminal.lastRenderPos)) { | ||||
|         if( originTerminal.lastRenderFrame == renderFrame && !monitorPos.equals( originTerminal.lastRenderPos ) ) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
| @@ -105,7 +102,8 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor> | ||||
|  | ||||
|         // Draw the contents | ||||
|         Terminal terminal = originTerminal.getTerminal(); | ||||
|         if (terminal != null) { | ||||
|         if( terminal != null ) | ||||
|         { | ||||
|             // Draw a terminal | ||||
|             int width = terminal.getWidth(), height = terminal.getHeight(); | ||||
|             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() ); | ||||
|  | ||||
|             transform.pop(); | ||||
|         } else { | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             FixedWidthFontRenderer.drawEmptyTerminal( transform.peek() | ||||
|                     .getModel(), | ||||
|                 renderer, | ||||
| @@ -151,35 +151,44 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor> | ||||
|         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(); | ||||
|  | ||||
|         MonitorRenderer renderType = MonitorRenderer.current(); | ||||
|         boolean redraw = monitor.pollTerminalChanged(); | ||||
|         if (monitor.createBuffer(renderType)) { | ||||
|         if( monitor.createBuffer( renderType ) ) | ||||
|         { | ||||
|             redraw = true; | ||||
|         } | ||||
|  | ||||
|         switch (renderType) { | ||||
|         case TBO: { | ||||
|             if (!MonitorTextureBufferShader.use()) { | ||||
|         switch( renderType ) | ||||
|         { | ||||
|             case TBO: | ||||
|             { | ||||
|                 if( !MonitorTextureBufferShader.use() ) | ||||
|                 { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 int width = terminal.getWidth(), height = terminal.getHeight(); | ||||
|                 int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT; | ||||
|  | ||||
|             if (redraw) { | ||||
|                 if( redraw ) | ||||
|                 { | ||||
|                     int size = width * height * 3; | ||||
|                 if (tboContents == null || tboContents.capacity() < size) { | ||||
|                     if( tboContents == null || tboContents.capacity() < size ) | ||||
|                     { | ||||
|                         tboContents = GlAllocationUtils.allocateByteBuffer( size ); | ||||
|                     } | ||||
|  | ||||
|                     ByteBuffer monitorBuffer = tboContents; | ||||
|                     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 ); | ||||
|                     for (int x = 0; x < width; x++) { | ||||
|                         for( int x = 0; x < width; x++ ) | ||||
|                         { | ||||
|                             monitorBuffer.put( (byte) (text.charAt( x ) & 0xFF) ); | ||||
|                             monitorBuffer.put( (byte) getColour( textColour.charAt( x ), Colour.WHITE ) ); | ||||
|                             monitorBuffer.put( (byte) getColour( background.charAt( x ), Colour.BLACK ) ); | ||||
| @@ -216,9 +225,11 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor> | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|         case VBO: { | ||||
|             case VBO: | ||||
|             { | ||||
|                 VertexBuffer vbo = monitor.buffer; | ||||
|             if (redraw) { | ||||
|                 if( redraw ) | ||||
|                 { | ||||
|                     Tessellator tessellator = Tessellator.getInstance(); | ||||
|                     BufferBuilder builder = tessellator.getBuffer(); | ||||
|                     builder.begin( FixedWidthFontRenderer.TYPE.getDrawMode(), FixedWidthFontRenderer.TYPE.getVertexFormat() ); | ||||
|   | ||||
| @@ -6,11 +6,6 @@ | ||||
|  | ||||
| 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.turtle.ITurtleUpgrade; | ||||
| 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.Holiday; | ||||
| import dan200.computercraft.shared.util.HolidayUtil; | ||||
|  | ||||
| import net.minecraft.client.MinecraftClient; | ||||
| import net.minecraft.client.font.TextRenderer; | ||||
| 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.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 ADVANCED_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_advanced", "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 ); | ||||
|  | ||||
|     public TileEntityTurtleRenderer(BlockEntityRenderDispatcher renderDispatcher) { | ||||
|     public TileEntityTurtleRenderer( BlockEntityRenderDispatcher renderDispatcher ) | ||||
|     { | ||||
|         super( renderDispatcher ); | ||||
|     } | ||||
|  | ||||
|     public static ModelIdentifier getTurtleModel(ComputerFamily family, boolean coloured) { | ||||
|         switch (family) { | ||||
|     public static ModelIdentifier getTurtleModel( ComputerFamily family, boolean coloured ) | ||||
|     { | ||||
|         switch( family ) | ||||
|         { | ||||
|             case NORMAL: | ||||
|             default: | ||||
|                 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) { | ||||
|         if (overlay != null) { | ||||
|     public static ModelIdentifier getTurtleOverlayModel( Identifier overlay, boolean christmas ) | ||||
|     { | ||||
|         if( overlay != null ) | ||||
|         { | ||||
|             return new ModelIdentifier( overlay, "inventory" ); | ||||
|         } | ||||
|         if (christmas) { | ||||
|         if( christmas ) | ||||
|         { | ||||
|             return ELF_OVERLAY_MODEL; | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     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(); | ||||
|  | ||||
|         for (BakedQuad bakedquad : quads) { | ||||
|         for( BakedQuad bakedquad : quads ) | ||||
|         { | ||||
|             int tint = -1; | ||||
|             if (tints != null && bakedquad.hasColor()) { | ||||
|             if( tints != null && bakedquad.hasColor() ) | ||||
|             { | ||||
|                 int idx = bakedquad.getColorIndex(); | ||||
|                 if (idx >= 0 && idx < tints.length) { | ||||
|                 if( idx >= 0 && idx < tints.length ) | ||||
|                 { | ||||
|                     tint = tints[bakedquad.getColorIndex()]; | ||||
|                 } | ||||
|             } | ||||
| @@ -112,13 +121,15 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle> { | ||||
|  | ||||
|     @Override | ||||
|     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 | ||||
|         String label = turtle.createProxy() | ||||
|             .getLabel(); | ||||
|         HitResult hit = this.dispatcher.crosshairTarget; | ||||
|         if( label != null && hit.getType() == HitResult.Type.BLOCK && turtle.getPos() | ||||
|                                                                             .equals(((BlockHitResult) hit).getBlockPos())) { | ||||
|             .equals( ((BlockHitResult) hit).getBlockPos() ) ) | ||||
|         { | ||||
|             MinecraftClient mc = MinecraftClient.getInstance(); | ||||
|             TextRenderer font = mc.textRenderer; | ||||
|  | ||||
| @@ -147,7 +158,8 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle> { | ||||
|  | ||||
|         transform.translate( 0.5f, 0.5f, 0.5f ); | ||||
|         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 | ||||
|             transform.scale( 1.0f, -1.0f, 1.0f ); | ||||
|         } | ||||
| @@ -163,7 +175,8 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle> { | ||||
|  | ||||
|         // Render the overlay | ||||
|         ModelIdentifier overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS ); | ||||
|         if (overlayModel != null) { | ||||
|         if( 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, | ||||
|                                TurtleSide side, float f) { | ||||
|                                       TurtleSide side, float f ) | ||||
|     { | ||||
|         ITurtleUpgrade upgrade = turtle.getUpgrade( side ); | ||||
|         if (upgrade == null) { | ||||
|         if( upgrade == null ) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|         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, | ||||
|                              ModelIdentifier modelLocation, int[] tints) { | ||||
|                                     ModelIdentifier modelLocation, int[] tints ) | ||||
|     { | ||||
|         BakedModelManager modelManager = MinecraftClient.getInstance() | ||||
|             .getItemRenderer() | ||||
|             .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, | ||||
|                              int[] tints) { | ||||
|                                     int[] tints ) | ||||
|     { | ||||
|         Random random = new Random(); | ||||
|         random.setSeed( 0 ); | ||||
|         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 ); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -6,17 +6,10 @@ | ||||
|  | ||||
| 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 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.ModelBakeSettings; | ||||
| 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.util.Identifier; | ||||
|  | ||||
| import net.fabricmc.api.EnvType; | ||||
| import net.fabricmc.api.Environment; | ||||
| import javax.annotation.Nonnull; | ||||
| 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 ) | ||||
| public final class TurtleModelLoader { | ||||
| public final class 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 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 TurtleModelLoader() { | ||||
|     private TurtleModelLoader() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     public boolean accepts(@Nonnull Identifier name) { | ||||
|     public boolean accepts( @Nonnull Identifier name ) | ||||
|     { | ||||
|         return name.getNamespace() | ||||
|             .equals( ComputerCraft.MOD_ID ) && (name.getPath() | ||||
|             .equals( "item/turtle_normal" ) || name.getPath() | ||||
| @@ -46,10 +46,13 @@ public final class TurtleModelLoader { | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     public UnbakedModel loadModel(@Nonnull Identifier name) { | ||||
|     public UnbakedModel loadModel( @Nonnull Identifier name ) | ||||
|     { | ||||
|         if( name.getNamespace() | ||||
|                 .equals(ComputerCraft.MOD_ID)) { | ||||
|             switch (name.getPath()) { | ||||
|             .equals( ComputerCraft.MOD_ID ) ) | ||||
|         { | ||||
|             switch( name.getPath() ) | ||||
|             { | ||||
|                 case "item/turtle_normal": | ||||
|                     return new TurtleModel( NORMAL_TURTLE_MODEL ); | ||||
|                 case "item/turtle_advanced": | ||||
| @@ -60,14 +63,16 @@ public final class TurtleModelLoader { | ||||
|         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 TurtleModel( Identifier family ) {this.family = family;} | ||||
|  | ||||
|         @Override | ||||
|         public Collection<SpriteIdentifier> getTextureDependencies( Function<Identifier, UnbakedModel> modelGetter, | ||||
|                                                                    Set<Pair<String, String>> missingTextureErrors) { | ||||
|                                                                     Set<Pair<String, String>> missingTextureErrors ) | ||||
|         { | ||||
|             return this.getModelDependencies() | ||||
|                 .stream() | ||||
|                 .flatMap( x -> modelGetter.apply( x ) | ||||
| @@ -78,13 +83,15 @@ public final class TurtleModelLoader { | ||||
|  | ||||
|         @Nonnull | ||||
|         @Override | ||||
|         public Collection<Identifier> getModelDependencies() { | ||||
|         public Collection<Identifier> getModelDependencies() | ||||
|         { | ||||
|             return Arrays.asList( this.family, COLOUR_TURTLE_MODEL ); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         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 ) | ||||
|                 .bake( loader, spriteGetter, state, modelId ), | ||||
|                 loader.getOrLoadModel( COLOUR_TURTLE_MODEL ) | ||||
|   | ||||
| @@ -6,16 +6,9 @@ | ||||
|  | ||||
| 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 net.fabricmc.api.EnvType; | ||||
| import net.fabricmc.api.Environment; | ||||
| import net.minecraft.block.BlockState; | ||||
| import net.minecraft.client.render.model.BakedModel; | ||||
| 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.util.math.Direction; | ||||
|  | ||||
| import net.fabricmc.api.EnvType; | ||||
| import net.fabricmc.api.Environment; | ||||
| import javax.annotation.Nonnull; | ||||
| import java.util.*; | ||||
|  | ||||
| @Environment( EnvType.CLIENT ) | ||||
| public class TurtleMultiModel implements BakedModel { | ||||
| public class TurtleMultiModel implements BakedModel | ||||
| { | ||||
|     private final BakedModel m_baseModel; | ||||
|     private final BakedModel m_overlayModel; | ||||
|     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 ); | ||||
|  | ||||
|     public TurtleMultiModel( BakedModel baseModel, BakedModel overlayModel, AffineTransformation generalTransform, TransformedModel leftUpgradeModel, | ||||
|                             TransformedModel rightUpgradeModel) { | ||||
|                              TransformedModel rightUpgradeModel ) | ||||
|     { | ||||
|         // Get the models | ||||
|         this.m_baseModel = baseModel; | ||||
|         this.m_overlayModel = overlayModel; | ||||
| @@ -49,35 +44,45 @@ public class TurtleMultiModel implements BakedModel { | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public List<BakedQuad> getQuads(BlockState state, Direction side, @Nonnull Random rand) { | ||||
|         if (side != null) { | ||||
|             if (!this.m_faceQuads.containsKey(side)) { | ||||
|     public List<BakedQuad> getQuads( BlockState state, Direction side, @Nonnull Random rand ) | ||||
|     { | ||||
|         if( side != null ) | ||||
|         { | ||||
|             if( !this.m_faceQuads.containsKey( side ) ) | ||||
|             { | ||||
|                 this.m_faceQuads.put( side, this.buildQuads( state, side, rand ) ); | ||||
|             } | ||||
|             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 ); | ||||
|             } | ||||
|             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<>(); | ||||
|  | ||||
|  | ||||
|         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() ); | ||||
|         } | ||||
|         if (this.m_leftUpgradeModel != null) { | ||||
|         if( this.m_leftUpgradeModel != null ) | ||||
|         { | ||||
|             AffineTransformation upgradeTransform = this.m_generalTransform.multiply( this.m_leftUpgradeModel.getMatrix() ); | ||||
|             ModelTransformer.transformQuadsTo( quads, this.m_leftUpgradeModel.getModel() | ||||
|                     .getQuads( state, side, rand ), | ||||
|                 upgradeTransform.getMatrix() ); | ||||
|         } | ||||
|         if (this.m_rightUpgradeModel != null) { | ||||
|         if( this.m_rightUpgradeModel != null ) | ||||
|         { | ||||
|             AffineTransformation upgradeTransform = this.m_generalTransform.multiply( this.m_rightUpgradeModel.getMatrix() ); | ||||
|             ModelTransformer.transformQuadsTo( quads, this.m_rightUpgradeModel.getModel() | ||||
|                     .getQuads( state, side, rand ), | ||||
| @@ -88,42 +93,49 @@ public class TurtleMultiModel implements BakedModel { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean useAmbientOcclusion() { | ||||
|     public boolean useAmbientOcclusion() | ||||
|     { | ||||
|         return this.m_baseModel.useAmbientOcclusion(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean hasDepth() { | ||||
|     public boolean hasDepth() | ||||
|     { | ||||
|         return this.m_baseModel.hasDepth(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isSideLit() { | ||||
|     public boolean isSideLit() | ||||
|     { | ||||
|         return this.m_baseModel.isSideLit(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isBuiltin() { | ||||
|     public boolean isBuiltin() | ||||
|     { | ||||
|         return this.m_baseModel.isBuiltin(); | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     @Deprecated | ||||
|     public Sprite getSprite() { | ||||
|     public Sprite getSprite() | ||||
|     { | ||||
|         return this.m_baseModel.getSprite(); | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     @Deprecated | ||||
|     public net.minecraft.client.render.model.json.ModelTransformation getTransformation() { | ||||
|     public net.minecraft.client.render.model.json.ModelTransformation getTransformation() | ||||
|     { | ||||
|         return this.m_baseModel.getTransformation(); | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public ModelOverrideList getOverrides() { | ||||
|     public ModelOverrideList getOverrides() | ||||
|     { | ||||
|         return ModelOverrideList.EMPTY; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -5,35 +5,38 @@ | ||||
|  */ | ||||
| package dan200.computercraft.client.render; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| 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.entity.EntityRenderDispatcher; | ||||
| import net.minecraft.client.render.entity.EntityRenderer; | ||||
| import net.minecraft.client.util.math.MatrixStack; | ||||
| 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 TurtlePlayerRenderer(EntityRenderDispatcher renderManager) { | ||||
| public class TurtlePlayerRenderer extends EntityRenderer<TurtlePlayer> | ||||
| { | ||||
|     public TurtlePlayerRenderer( EntityRenderDispatcher renderManager ) | ||||
|     { | ||||
|         super( renderManager ); | ||||
|     } | ||||
|  | ||||
|     public TurtlePlayerRenderer(EntityRenderDispatcher entityRenderDispatcher, EntityRendererRegistry.Context context) { | ||||
|     public TurtlePlayerRenderer( EntityRenderDispatcher entityRenderDispatcher, EntityRendererRegistry.Context context ) | ||||
|     { | ||||
|         super( entityRenderDispatcher ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void render( @Nonnull TurtlePlayer entityIn, float entityYaw, float partialTicks, @Nonnull MatrixStack transform, | ||||
|                        @Nonnull VertexConsumerProvider buffer, int packedLightIn) { | ||||
|                         @Nonnull VertexConsumerProvider buffer, int packedLightIn ) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public Identifier getTexture(@Nonnull TurtlePlayer entity) { | ||||
|     public Identifier getTexture( @Nonnull TurtlePlayer entity ) | ||||
|     { | ||||
|         return ComputerBorderRenderer.BACKGROUND_NORMAL; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,23 +6,15 @@ | ||||
|  | ||||
| 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 dan200.computercraft.api.client.TransformedModel; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.api.turtle.TurtleSide; | ||||
| 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.HolidayUtil; | ||||
|  | ||||
| import net.fabricmc.api.EnvType; | ||||
| import net.fabricmc.api.Environment; | ||||
| import net.minecraft.block.BlockState; | ||||
| import net.minecraft.client.MinecraftClient; | ||||
| 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.math.Direction; | ||||
|  | ||||
| import net.fabricmc.api.EnvType; | ||||
| import net.fabricmc.api.Environment; | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
| import java.util.Collections; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Random; | ||||
|  | ||||
| @Environment( EnvType.CLIENT ) | ||||
| public class TurtleSmartItemModel implements BakedModel { | ||||
| public class TurtleSmartItemModel implements BakedModel | ||||
| { | ||||
|     private static final AffineTransformation identity, flip; | ||||
|  | ||||
|     static { | ||||
|     static | ||||
|     { | ||||
|         MatrixStack stack = new MatrixStack(); | ||||
|         stack.scale( 0, -1, 0 ); | ||||
|         stack.translate( 0, 0, 1 ); | ||||
| @@ -61,16 +59,20 @@ public class TurtleSmartItemModel implements BakedModel { | ||||
|     private final BakedModel colourModel; | ||||
|     private final HashMap<TurtleModelCombination, BakedModel> m_cachedModels = new HashMap<>(); | ||||
|     private final ModelOverrideList m_overrides; | ||||
|     public TurtleSmartItemModel(BakedModel familyModel, BakedModel colourModel) { | ||||
|  | ||||
|     public TurtleSmartItemModel( BakedModel familyModel, BakedModel colourModel ) | ||||
|     { | ||||
|         this.familyModel = familyModel; | ||||
|         this.colourModel = colourModel; | ||||
|  | ||||
|         // 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 | ||||
|             @Override | ||||
|             public BakedModel apply( @Nonnull BakedModel originalModel, @Nonnull ItemStack stack, @Nullable ClientWorld world, | ||||
|                                     @Nullable LivingEntity entity) { | ||||
|                                      @Nullable LivingEntity entity ) | ||||
|             { | ||||
|                 ItemTurtle turtle = (ItemTurtle) stack.getItem(); | ||||
|                 int colour = turtle.getColour( stack ); | ||||
|                 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 ); | ||||
|  | ||||
|                 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 ) ); | ||||
|                 } | ||||
|                 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(); | ||||
|         BakedModelManager modelManager = mc.getItemRenderer() | ||||
|             .getModels() | ||||
| @@ -110,51 +114,60 @@ public class TurtleSmartItemModel implements BakedModel { | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     @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 ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean useAmbientOcclusion() { | ||||
|     public boolean useAmbientOcclusion() | ||||
|     { | ||||
|         return this.familyModel.useAmbientOcclusion(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean hasDepth() { | ||||
|     public boolean hasDepth() | ||||
|     { | ||||
|         return this.familyModel.hasDepth(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isSideLit() { | ||||
|     public boolean isSideLit() | ||||
|     { | ||||
|         return this.familyModel.isSideLit(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isBuiltin() { | ||||
|     public boolean isBuiltin() | ||||
|     { | ||||
|         return this.familyModel.isBuiltin(); | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     @Deprecated | ||||
|     public Sprite getSprite() { | ||||
|     public Sprite getSprite() | ||||
|     { | ||||
|         return this.familyModel.getSprite(); | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     @Deprecated | ||||
|     public ModelTransformation getTransformation() { | ||||
|     public ModelTransformation getTransformation() | ||||
|     { | ||||
|         return this.familyModel.getTransformation(); | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public ModelOverrideList getOverrides() { | ||||
|     public ModelOverrideList getOverrides() | ||||
|     { | ||||
|         return this.m_overrides; | ||||
|     } | ||||
|  | ||||
|     private static class TurtleModelCombination { | ||||
|     private static class TurtleModelCombination | ||||
|     { | ||||
|         final boolean m_colour; | ||||
|         final ITurtleUpgrade m_leftUpgrade; | ||||
|         final ITurtleUpgrade m_rightUpgrade; | ||||
| @@ -163,7 +176,8 @@ public class TurtleSmartItemModel implements BakedModel { | ||||
|         final boolean m_flip; | ||||
|  | ||||
|         TurtleModelCombination( boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, Identifier overlay, boolean christmas, | ||||
|                                boolean flip) { | ||||
|                                 boolean flip ) | ||||
|         { | ||||
|             this.m_colour = colour; | ||||
|             this.m_leftUpgrade = leftUpgrade; | ||||
|             this.m_rightUpgrade = rightUpgrade; | ||||
| @@ -173,7 +187,8 @@ public class TurtleSmartItemModel implements BakedModel { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public int hashCode() { | ||||
|         public int hashCode() | ||||
|         { | ||||
|             final int prime = 31; | ||||
|             int result = 0; | ||||
|             result = prime * result + (this.m_colour ? 1 : 0); | ||||
| @@ -186,11 +201,14 @@ public class TurtleSmartItemModel implements BakedModel { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean equals(Object other) { | ||||
|             if (other == this) { | ||||
|         public boolean equals( Object other ) | ||||
|         { | ||||
|             if( other == this ) | ||||
|             { | ||||
|                 return true; | ||||
|             } | ||||
|             if (!(other instanceof TurtleModelCombination)) { | ||||
|             if( !(other instanceof TurtleModelCombination) ) | ||||
|             { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|   | ||||
| @@ -6,27 +6,31 @@ | ||||
|  | ||||
| package dan200.computercraft.core.apis; | ||||
|  | ||||
| import dan200.computercraft.api.lua.ILuaAPIFactory; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.LinkedHashSet; | ||||
| import java.util.Objects; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import dan200.computercraft.api.lua.ILuaAPIFactory; | ||||
|  | ||||
| public final class ApiFactories { | ||||
| public final class ApiFactories | ||||
| { | ||||
|     private static final Collection<ILuaAPIFactory> factories = new LinkedHashSet<>(); | ||||
|     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" ); | ||||
|         factories.add( factory ); | ||||
|     } | ||||
|  | ||||
|     public static Iterable<ILuaAPIFactory> getAll() { | ||||
|     public static Iterable<ILuaAPIFactory> getAll() | ||||
|     { | ||||
|         return factoriesView; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,12 +6,6 @@ | ||||
|  | ||||
| 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.IWritableMount; | ||||
| 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.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 Set<String> m_mounts = new HashSet<>(); | ||||
|  | ||||
|     protected ComputerAccess(IAPIEnvironment environment) { | ||||
|     protected ComputerAccess( IAPIEnvironment environment ) | ||||
|     { | ||||
|         this.m_environment = environment; | ||||
|     } | ||||
|  | ||||
|     public void unmountAll() { | ||||
|     public void unmountAll() | ||||
|     { | ||||
|         FileSystem fileSystem = this.m_environment.getFileSystem(); | ||||
|         for (String mount : this.m_mounts) { | ||||
|         for( String mount : this.m_mounts ) | ||||
|         { | ||||
|             fileSystem.unmount( mount ); | ||||
|         } | ||||
|         this.m_mounts.clear(); | ||||
|     } | ||||
|  | ||||
|     @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( mount, "mount cannot be null" ); | ||||
|         Objects.requireNonNull( driveName, "driveName cannot be null" ); | ||||
| @@ -44,28 +48,36 @@ public abstract class ComputerAccess implements IComputerAccess { | ||||
|         // Mount the location | ||||
|         String location; | ||||
|         FileSystem fileSystem = this.m_environment.getFileSystem(); | ||||
|         if (fileSystem == null) { | ||||
|         if( fileSystem == null ) | ||||
|         { | ||||
|             throw new IllegalStateException( "File system has not been created" ); | ||||
|         } | ||||
|  | ||||
|         synchronized (fileSystem) { | ||||
|         synchronized( fileSystem ) | ||||
|         { | ||||
|             location = this.findFreeLocation( desiredLoc ); | ||||
|             if (location != null) { | ||||
|                 try { | ||||
|             if( location != null ) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     fileSystem.mount( driveName, location, mount ); | ||||
|                 } catch (FileSystemException ignored) { | ||||
|                 } | ||||
|                 catch( FileSystemException ignored ) | ||||
|                 { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (location != null) { | ||||
|         if( location != null ) | ||||
|         { | ||||
|             this.m_mounts.add( location ); | ||||
|         } | ||||
|         return location; | ||||
|     } | ||||
|  | ||||
|     @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( mount, "mount cannot be null" ); | ||||
|         Objects.requireNonNull( driveName, "driveName cannot be null" ); | ||||
| @@ -73,32 +85,42 @@ public abstract class ComputerAccess implements IComputerAccess { | ||||
|         // Mount the location | ||||
|         String location; | ||||
|         FileSystem fileSystem = this.m_environment.getFileSystem(); | ||||
|         if (fileSystem == null) { | ||||
|         if( fileSystem == null ) | ||||
|         { | ||||
|             throw new IllegalStateException( "File system has not been created" ); | ||||
|         } | ||||
|  | ||||
|         synchronized (fileSystem) { | ||||
|         synchronized( fileSystem ) | ||||
|         { | ||||
|             location = this.findFreeLocation( desiredLoc ); | ||||
|             if (location != null) { | ||||
|                 try { | ||||
|             if( location != null ) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     fileSystem.mountWritable( driveName, location, mount ); | ||||
|                 } catch (FileSystemException ignored) { | ||||
|                 } | ||||
|                 catch( FileSystemException ignored ) | ||||
|                 { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (location != null) { | ||||
|         if( location != null ) | ||||
|         { | ||||
|             this.m_mounts.add( location ); | ||||
|         } | ||||
|         return location; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void unmount(String location) { | ||||
|         if (location == null) { | ||||
|     public void unmount( String location ) | ||||
|     { | ||||
|         if( location == null ) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|         if (!this.m_mounts.contains(location)) { | ||||
|         if( !this.m_mounts.contains( location ) ) | ||||
|         { | ||||
|             throw new IllegalStateException( "You didn't mount this location" ); | ||||
|         } | ||||
|  | ||||
| @@ -108,32 +130,40 @@ public abstract class ComputerAccess implements IComputerAccess { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getID() { | ||||
|     public int getID() | ||||
|     { | ||||
|         return this.m_environment.getComputerID(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void queueEvent(@Nonnull String event, Object... arguments) { | ||||
|     public void queueEvent( @Nonnull String event, Object... arguments ) | ||||
|     { | ||||
|         Objects.requireNonNull( event, "event cannot be null" ); | ||||
|         this.m_environment.queueEvent( event, arguments ); | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     public IWorkMonitor getMainThreadMonitor() { | ||||
|     public IWorkMonitor getMainThreadMonitor() | ||||
|     { | ||||
|         return this.m_environment.getMainThreadMonitor(); | ||||
|     } | ||||
|  | ||||
|     private String findFreeLocation(String desiredLoc) { | ||||
|         try { | ||||
|     private String findFreeLocation( String desiredLoc ) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             FileSystem fileSystem = this.m_environment.getFileSystem(); | ||||
|             if (!fileSystem.exists(desiredLoc)) { | ||||
|             if( !fileSystem.exists( desiredLoc ) ) | ||||
|             { | ||||
|                 return desiredLoc; | ||||
|             } | ||||
|  | ||||
|             // We used to check foo2, foo3, foo4, etc here but the disk drive does this itself now | ||||
|             return null; | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -6,18 +6,6 @@ | ||||
|  | ||||
| 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.ILuaAPI; | ||||
| 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.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. | ||||
|  * | ||||
|  * @cc.module fs | ||||
|  */ | ||||
| public class FSAPI implements ILuaAPI { | ||||
| public class FSAPI implements ILuaAPI | ||||
| { | ||||
|     private final IAPIEnvironment environment; | ||||
|     private FileSystem fileSystem = null; | ||||
|  | ||||
|     public FSAPI(IAPIEnvironment env) { | ||||
|     public FSAPI( IAPIEnvironment env ) | ||||
|     { | ||||
|         this.environment = env; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String[] getNames() { | ||||
|     public String[] getNames() | ||||
|     { | ||||
|         return new String[] { "fs" }; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void startup() { | ||||
|     public void startup() | ||||
|     { | ||||
|         this.fileSystem = this.environment.getFileSystem(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void shutdown() { | ||||
|     public void shutdown() | ||||
|     { | ||||
|         this.fileSystem = null; | ||||
|     } | ||||
|  | ||||
| @@ -67,11 +71,15 @@ public class FSAPI implements ILuaAPI { | ||||
|      * @throws LuaException If the path doesn't exist. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final String[] list(String path) throws LuaException { | ||||
|     public final String[] list( String path ) throws LuaException | ||||
|     { | ||||
|         this.environment.addTrackingChange( TrackingField.FS_OPS ); | ||||
|         try { | ||||
|         try | ||||
|         { | ||||
|             return this.fileSystem.list( path ); | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             throw new LuaException( e.getMessage() ); | ||||
|         } | ||||
|     } | ||||
| @@ -82,16 +90,18 @@ public class FSAPI implements ILuaAPI { | ||||
|      * | ||||
|      * @param arguments The paths to combine. | ||||
|      * @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 ... Additional parts of the path to combine. | ||||
|      * @throws LuaException On argument errors. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final String combine( IArguments arguments ) throws LuaException { | ||||
|     public final String combine( IArguments arguments ) throws LuaException | ||||
|     { | ||||
|         StringBuilder result = new StringBuilder(); | ||||
|         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 ); | ||||
|             if( result.length() != 0 && !part.isEmpty() ) result.append( '/' ); | ||||
|             result.append( part ); | ||||
| @@ -107,7 +117,8 @@ public class FSAPI implements ILuaAPI { | ||||
|      * @return The final part of the path (the file name). | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final String getName(String path) { | ||||
|     public final String getName( String 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). | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final String getDir(String path) { | ||||
|     public final String getDir( String path ) | ||||
|     { | ||||
|         return FileSystem.getDirectory( path ); | ||||
|     } | ||||
|  | ||||
| @@ -130,10 +142,14 @@ public class FSAPI implements ILuaAPI { | ||||
|      * @throws LuaException If the path doesn't exist. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final long getSize(String path) throws LuaException { | ||||
|         try { | ||||
|     public final long getSize( String path ) throws LuaException | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return this.fileSystem.getSize( path ); | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             throw new LuaException( e.getMessage() ); | ||||
|         } | ||||
|     } | ||||
| @@ -145,10 +161,14 @@ public class FSAPI implements ILuaAPI { | ||||
|      * @return Whether the path exists. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final boolean exists(String path) { | ||||
|         try { | ||||
|     public final boolean exists( String path ) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return this.fileSystem.exists( path ); | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| @@ -160,10 +180,14 @@ public class FSAPI implements ILuaAPI { | ||||
|      * @return Whether the path is a directory. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final boolean isDir(String path) { | ||||
|         try { | ||||
|     public final boolean isDir( String path ) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return this.fileSystem.isDir( path ); | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| @@ -175,10 +199,14 @@ public class FSAPI implements ILuaAPI { | ||||
|      * @return Whether the path cannot be written to. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final boolean isReadOnly(String path) { | ||||
|         try { | ||||
|     public final boolean isReadOnly( String path ) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return this.fileSystem.isReadOnly( path ); | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| @@ -190,11 +218,15 @@ public class FSAPI implements ILuaAPI { | ||||
|      * @throws LuaException If the directory couldn't be created. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final void makeDir(String path) throws LuaException { | ||||
|         try { | ||||
|     public final void makeDir( String path ) throws LuaException | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             this.environment.addTrackingChange( TrackingField.FS_OPS ); | ||||
|             this.fileSystem.makeDir( path ); | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             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. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final void move(String path, String dest) throws LuaException { | ||||
|         try { | ||||
|     public final void move( String path, String dest ) throws LuaException | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             this.environment.addTrackingChange( TrackingField.FS_OPS ); | ||||
|             this.fileSystem.move( path, dest ); | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             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. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final void copy(String path, String dest) throws LuaException { | ||||
|         try { | ||||
|     public final void copy( String path, String dest ) throws LuaException | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             this.environment.addTrackingChange( TrackingField.FS_OPS ); | ||||
|             this.fileSystem.copy( path, dest ); | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             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. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final void delete(String path) throws LuaException { | ||||
|         try { | ||||
|     public final void delete( String path ) throws LuaException | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             this.environment.addTrackingChange( TrackingField.FS_OPS ); | ||||
|             this.fileSystem.delete( path ); | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             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. | ||||
|      */ | ||||
|     @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 ); | ||||
|         try { | ||||
|             switch (mode) { | ||||
|             case "r": { | ||||
|         try | ||||
|         { | ||||
|             switch( mode ) | ||||
|             { | ||||
|                 case "r": | ||||
|                 { | ||||
|                     // Open the file for reading, then create a wrapper around the reader | ||||
|                     FileSystemWrapper<BufferedReader> reader = this.fileSystem.openForRead( path, EncodedReadableHandle::openUtf8 ); | ||||
|                     return new Object[] { new EncodedReadableHandle( reader.get(), reader ) }; | ||||
|                 } | ||||
|             case "w": { | ||||
|                 case "w": | ||||
|                 { | ||||
|                     // Open the file for writing, then create a wrapper around the writer | ||||
|                     FileSystemWrapper<BufferedWriter> writer = this.fileSystem.openForWrite( path, false, EncodedWritableHandle::openUtf8 ); | ||||
|                     return new Object[] { new EncodedWritableHandle( writer.get(), writer ) }; | ||||
|                 } | ||||
|             case "a": { | ||||
|                 case "a": | ||||
|                 { | ||||
|                     // Open the file for appending, then create a wrapper around the writer | ||||
|                     FileSystemWrapper<BufferedWriter> writer = this.fileSystem.openForWrite( path, true, EncodedWritableHandle::openUtf8 ); | ||||
|                     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 | ||||
|                     FileSystemWrapper<ReadableByteChannel> reader = this.fileSystem.openForRead( path, Function.identity() ); | ||||
|                     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 | ||||
|                     FileSystemWrapper<WritableByteChannel> writer = this.fileSystem.openForWrite( path, false, Function.identity() ); | ||||
|                     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 | ||||
|                     FileSystemWrapper<WritableByteChannel> writer = this.fileSystem.openForWrite( path, true, Function.identity() ); | ||||
|                     return new Object[] { BinaryWritableHandle.of( writer.get(), writer ) }; | ||||
| @@ -309,7 +362,9 @@ public class FSAPI implements ILuaAPI { | ||||
|                 default: | ||||
|                     throw new LuaException( "Unsupported mode" ); | ||||
|             } | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             return new Object[] { | ||||
|                 null, | ||||
|                 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. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final Object[] getDrive(String path) throws LuaException { | ||||
|         try { | ||||
|     public final Object[] getDrive( String path ) throws LuaException | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return this.fileSystem.exists( path ) ? new Object[] { this.fileSystem.getMountLabel( path ) } : null; | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             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". | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final Object getFreeSpace(String path) throws LuaException { | ||||
|         try { | ||||
|     public final Object getFreeSpace( String path ) throws LuaException | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             long freeSpace = this.fileSystem.getFreeSpace( path ); | ||||
|             return freeSpace >= 0 ? freeSpace : "unlimited"; | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             throw new LuaException( e.getMessage() ); | ||||
|         } | ||||
|     } | ||||
| @@ -363,11 +426,15 @@ public class FSAPI implements ILuaAPI { | ||||
|      * @throws LuaException If the path doesn't exist. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final String[] find(String path) throws LuaException { | ||||
|         try { | ||||
|     public final String[] find( String path ) throws LuaException | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             this.environment.addTrackingChange( TrackingField.FS_OPS ); | ||||
|             return this.fileSystem.find( path ); | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             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. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final Object getCapacity(String path) throws LuaException { | ||||
|         try { | ||||
|     public final Object getCapacity( String path ) throws LuaException | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             OptionalLong capacity = this.fileSystem.getCapacity( path ); | ||||
|             return capacity.isPresent() ? capacity.getAsLong() : null; | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             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. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final Map<String, Object> attributes(String path) throws LuaException { | ||||
|         try { | ||||
|     public final Map<String, Object> attributes( String path ) throws LuaException | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             BasicFileAttributes attributes = this.fileSystem.getAttributes( path ); | ||||
|             Map<String, Object> result = new HashMap<>(); | ||||
|             result.put( "modification", getFileTime( attributes.lastModifiedTime() ) ); | ||||
| @@ -421,12 +494,15 @@ public class FSAPI implements ILuaAPI { | ||||
|             result.put( "isDir", attributes.isDirectory() ); | ||||
|             result.put( "isReadOnly", fileSystem.isReadOnly( path ) ); | ||||
|             return result; | ||||
|         } catch (FileSystemException e) { | ||||
|         } | ||||
|         catch( FileSystemException e ) | ||||
|         { | ||||
|             throw new LuaException( e.getMessage() ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static long getFileTime(FileTime time) { | ||||
|     private static long getFileTime( FileTime time ) | ||||
|     { | ||||
|         return time == null ? 0 : time.toMillis(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -5,26 +5,30 @@ | ||||
|  */ | ||||
| package dan200.computercraft.core.apis; | ||||
|  | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import dan200.computercraft.api.lua.LuaException; | ||||
|  | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| /** | ||||
|  * 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; | ||||
|  | ||||
|     public FastLuaException(@Nullable String message) { | ||||
|     public FastLuaException( @Nullable String message ) | ||||
|     { | ||||
|         super( message ); | ||||
|     } | ||||
|  | ||||
|     public FastLuaException(@Nullable String message, int level) { | ||||
|     public FastLuaException( @Nullable String message, int level ) | ||||
|     { | ||||
|         super( message, level ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public synchronized Throwable fillInStackTrace() { | ||||
|     public synchronized Throwable fillInStackTrace() | ||||
|     { | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,9 +6,6 @@ | ||||
|  | ||||
| package dan200.computercraft.core.apis; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| import dan200.computercraft.api.peripheral.IWorkMonitor; | ||||
| 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.tracking.TrackingField; | ||||
|  | ||||
| public interface IAPIEnvironment { | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
|  | ||||
| public interface IAPIEnvironment | ||||
| { | ||||
|     String TIMER_EVENT = "timer"; | ||||
|  | ||||
|     int getComputerID(); | ||||
| @@ -64,14 +65,16 @@ public interface IAPIEnvironment { | ||||
|  | ||||
|     void cancelTimer( int id ); | ||||
|  | ||||
|     default void addTrackingChange(@Nonnull TrackingField field) { | ||||
|     default void addTrackingChange( @Nonnull TrackingField field ) | ||||
|     { | ||||
|         this.addTrackingChange( field, 1 ); | ||||
|     } | ||||
|  | ||||
|     void addTrackingChange( @Nonnull TrackingField field, long change ); | ||||
|  | ||||
|     @FunctionalInterface | ||||
|     interface IPeripheralChangeListener { | ||||
|     interface IPeripheralChangeListener | ||||
|     { | ||||
|         void onPeripheralChanged( ComputerSide side, @Nullable IPeripheral newPeripheral ); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,37 +6,35 @@ | ||||
|  | ||||
| package dan200.computercraft.core.apis; | ||||
|  | ||||
| import dan200.computercraft.api.lua.LuaException; | ||||
|  | ||||
| import java.time.Instant; | ||||
| import java.time.LocalDateTime; | ||||
| import java.time.ZoneId; | ||||
| import java.time.ZoneOffset; | ||||
| import java.time.format.DateTimeFormatterBuilder; | ||||
| import java.time.format.TextStyle; | ||||
| import java.time.temporal.ChronoField; | ||||
| 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.time.temporal.*; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| 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 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 { | ||||
|         for (int i = 0; i < format.length(); ) { | ||||
|     static void format( DateTimeFormatterBuilder formatter, String format, ZoneOffset offset ) throws LuaException | ||||
|     { | ||||
|         for( int i = 0; i < format.length(); ) | ||||
|         { | ||||
|             char c; | ||||
|             switch (c = format.charAt(i++)) { | ||||
|             switch( c = format.charAt( i++ ) ) | ||||
|             { | ||||
|                 case '\n': | ||||
|                     formatter.appendLiteral( '\n' ); | ||||
|                     break; | ||||
| @@ -44,10 +42,12 @@ final class LuaDateTime { | ||||
|                     formatter.appendLiteral( c ); | ||||
|                     break; | ||||
|                 case '%': | ||||
|                 if (i >= format.length()) { | ||||
|                     if( i >= format.length() ) | ||||
|                     { | ||||
|                         break; | ||||
|                     } | ||||
|                 switch (c = format.charAt(i++)) { | ||||
|                     switch( c = format.charAt( i++ ) ) | ||||
|                     { | ||||
|                         default: | ||||
|                             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 month = getField( table, "month", -1 ); | ||||
|         int day = getField( table, "day", -1 ); | ||||
| @@ -172,15 +173,18 @@ final class LuaDateTime { | ||||
|         LocalDateTime time = LocalDateTime.of( year, month, day, hour, minute, second ); | ||||
|  | ||||
|         Boolean isDst = getBoolField( table, "isdst" ); | ||||
|         if (isDst != null) { | ||||
|         if( isDst != null ) | ||||
|         { | ||||
|             boolean requireDst = isDst; | ||||
|             for( ZoneOffset possibleOffset : ZoneOffset.systemDefault() | ||||
|                 .getRules() | ||||
|                                                        .getValidOffsets(time)) { | ||||
|                 .getValidOffsets( time ) ) | ||||
|             { | ||||
|                 Instant instant = time.toInstant( possibleOffset ); | ||||
|                 if( possibleOffset.getRules() | ||||
|                     .getDaylightSavings( instant ) | ||||
|                                   .isZero() == requireDst) { | ||||
|                     .isZero() == requireDst ) | ||||
|                 { | ||||
|                     return instant.getEpochSecond(); | ||||
|                 } | ||||
|             } | ||||
| @@ -193,26 +197,32 @@ final class LuaDateTime { | ||||
|             .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 ); | ||||
|         if (value instanceof Number) { | ||||
|         if( value instanceof Number ) | ||||
|         { | ||||
|             return ((Number) value).intValue(); | ||||
|         } | ||||
|         if (def < 0) { | ||||
|         if( def < 0 ) | ||||
|         { | ||||
|             throw new LuaException( "field \"" + field + "\" missing in date table" ); | ||||
|         } | ||||
|         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 ); | ||||
|         if (value instanceof Boolean || value == null) { | ||||
|         if( value instanceof Boolean || value == null ) | ||||
|         { | ||||
|             return (Boolean) value; | ||||
|         } | ||||
|         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 ); | ||||
|         table.put( "year", date.getLong( ChronoField.YEAR ) ); | ||||
|         table.put( "month", date.getLong( ChronoField.MONTH_OF_YEAR ) ); | ||||
| @@ -228,53 +238,64 @@ final class LuaDateTime { | ||||
|         return table; | ||||
|     } | ||||
|  | ||||
|     private static TemporalField map(TemporalField field, ValueRange range, LongUnaryOperator convert) { | ||||
|         return new TemporalField() { | ||||
|     private static TemporalField map( TemporalField field, ValueRange range, LongUnaryOperator convert ) | ||||
|     { | ||||
|         return new TemporalField() | ||||
|         { | ||||
|             private final ValueRange range = ValueRange.of( 0, 99 ); | ||||
|  | ||||
|             @Override | ||||
|             public TemporalUnit getBaseUnit() { | ||||
|             public TemporalUnit getBaseUnit() | ||||
|             { | ||||
|                 return field.getBaseUnit(); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public TemporalUnit getRangeUnit() { | ||||
|             public TemporalUnit getRangeUnit() | ||||
|             { | ||||
|                 return field.getRangeUnit(); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public ValueRange range() { | ||||
|             public ValueRange range() | ||||
|             { | ||||
|                 return this.range; | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public boolean isDateBased() { | ||||
|             public boolean isDateBased() | ||||
|             { | ||||
|                 return field.isDateBased(); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public boolean isTimeBased() { | ||||
|             public boolean isTimeBased() | ||||
|             { | ||||
|                 return field.isTimeBased(); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public boolean isSupportedBy(TemporalAccessor temporal) { | ||||
|             public boolean isSupportedBy( TemporalAccessor temporal ) | ||||
|             { | ||||
|                 return field.isSupportedBy( temporal ); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public ValueRange rangeRefinedBy(TemporalAccessor temporal) { | ||||
|             public ValueRange rangeRefinedBy( TemporalAccessor temporal ) | ||||
|             { | ||||
|                 return this.range; | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public long getFrom(TemporalAccessor temporal) { | ||||
|             public long getFrom( TemporalAccessor temporal ) | ||||
|             { | ||||
|                 return convert.applyAsLong( temporal.getLong( field ) ); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             @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 ); | ||||
|             } | ||||
|         }; | ||||
|   | ||||
| @@ -6,23 +6,6 @@ | ||||
|  | ||||
| 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.ILuaAPI; | ||||
| 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.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. | ||||
|  * | ||||
|  * @cc.module os | ||||
|  */ | ||||
| public class OSAPI implements ILuaAPI { | ||||
| public class OSAPI implements ILuaAPI | ||||
| { | ||||
|     private final IAPIEnvironment apiEnvironment; | ||||
|  | ||||
|     private final Int2ObjectMap<Alarm> m_alarms = new Int2ObjectOpenHashMap<>(); | ||||
| @@ -46,34 +40,40 @@ public class OSAPI implements ILuaAPI { | ||||
|  | ||||
|     private int m_nextAlarmToken = 0; | ||||
|  | ||||
|     public OSAPI(IAPIEnvironment environment) { | ||||
|     public OSAPI( IAPIEnvironment environment ) | ||||
|     { | ||||
|         this.apiEnvironment = environment; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String[] getNames() { | ||||
|     public String[] getNames() | ||||
|     { | ||||
|         return new String[] { "os" }; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void startup() { | ||||
|     public void startup() | ||||
|     { | ||||
|         this.m_time = this.apiEnvironment.getComputerEnvironment() | ||||
|             .getTimeOfDay(); | ||||
|         this.m_day = this.apiEnvironment.getComputerEnvironment() | ||||
|             .getDay(); | ||||
|         this.m_clock = 0; | ||||
|  | ||||
|         synchronized (this.m_alarms) { | ||||
|         synchronized( this.m_alarms ) | ||||
|         { | ||||
|             this.m_alarms.clear(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void update() { | ||||
|     public void update() | ||||
|     { | ||||
|         this.m_clock++; | ||||
|  | ||||
|         // Wait for all of our alarms | ||||
|         synchronized (this.m_alarms) { | ||||
|         synchronized( this.m_alarms ) | ||||
|         { | ||||
|             double previousTime = this.m_time; | ||||
|             int previousDay = this.m_day; | ||||
|             double time = this.apiEnvironment.getComputerEnvironment() | ||||
| @@ -81,15 +81,18 @@ public class OSAPI implements ILuaAPI { | ||||
|             int day = this.apiEnvironment.getComputerEnvironment() | ||||
|                 .getDay(); | ||||
|  | ||||
|             if (time > previousTime || day > previousDay) { | ||||
|             if( time > previousTime || day > previousDay ) | ||||
|             { | ||||
|                 double now = this.m_day * 24.0 + this.m_time; | ||||
|                 Iterator<Int2ObjectMap.Entry<Alarm>> it = this.m_alarms.int2ObjectEntrySet() | ||||
|                     .iterator(); | ||||
|                 while (it.hasNext()) { | ||||
|                 while( it.hasNext() ) | ||||
|                 { | ||||
|                     Int2ObjectMap.Entry<Alarm> entry = it.next(); | ||||
|                     Alarm alarm = entry.getValue(); | ||||
|                     double t = alarm.m_day * 24.0 + alarm.m_time; | ||||
|                     if (now >= t) { | ||||
|                     if( now >= t ) | ||||
|                     { | ||||
|                         this.apiEnvironment.queueEvent( "alarm", entry.getIntKey() ); | ||||
|                         it.remove(); | ||||
|                     } | ||||
| @@ -102,8 +105,10 @@ public class OSAPI implements ILuaAPI { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void shutdown() { | ||||
|         synchronized (this.m_alarms) { | ||||
|     public void shutdown() | ||||
|     { | ||||
|         synchronized( this.m_alarms ) | ||||
|         { | ||||
|             this.m_alarms.clear(); | ||||
|         } | ||||
|     } | ||||
| @@ -118,7 +123,8 @@ public class OSAPI implements ILuaAPI { | ||||
|      * @cc.see os.pullEvent To pull the event queued | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final void queueEvent(String name, IArguments args) { | ||||
|     public final void queueEvent( String name, IArguments args ) | ||||
|     { | ||||
|         this.apiEnvironment.queueEvent( name, | ||||
|             args.drop( 1 ) | ||||
|                 .getAll() ); | ||||
| @@ -133,7 +139,8 @@ public class OSAPI implements ILuaAPI { | ||||
|      * @throws LuaException If the time is below zero. | ||||
|      */ | ||||
|     @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 ) ); | ||||
|     } | ||||
|  | ||||
| @@ -144,7 +151,8 @@ public class OSAPI implements ILuaAPI { | ||||
|      * @see #startTimer To start a timer. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final void cancelTimer(int token) { | ||||
|     public final void cancelTimer( int token ) | ||||
|     { | ||||
|         this.apiEnvironment.cancelTimer( token ); | ||||
|     } | ||||
|  | ||||
| @@ -156,12 +164,15 @@ public class OSAPI implements ILuaAPI { | ||||
|      * @throws LuaException If the time is out of range. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final int setAlarm(double time) throws LuaException { | ||||
|     public final int setAlarm( double time ) throws LuaException | ||||
|     { | ||||
|         checkFinite( 0, time ); | ||||
|         if (time < 0.0 || time >= 24.0) { | ||||
|         if( time < 0.0 || time >= 24.0 ) | ||||
|         { | ||||
|             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; | ||||
|             this.m_alarms.put( this.m_nextAlarmToken, new Alarm( time, day ) ); | ||||
|             return this.m_nextAlarmToken++; | ||||
| @@ -175,8 +186,10 @@ public class OSAPI implements ILuaAPI { | ||||
|      * @see #setAlarm To set an alarm. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final void cancelAlarm(int token) { | ||||
|         synchronized (this.m_alarms) { | ||||
|     public final void cancelAlarm( int token ) | ||||
|     { | ||||
|         synchronized( this.m_alarms ) | ||||
|         { | ||||
|             this.m_alarms.remove( token ); | ||||
|         } | ||||
|     } | ||||
| @@ -185,7 +198,8 @@ public class OSAPI implements ILuaAPI { | ||||
|      * Shuts down the computer immediately. | ||||
|      */ | ||||
|     @LuaFunction( "shutdown" ) | ||||
|     public final void doShutdown() { | ||||
|     public final void doShutdown() | ||||
|     { | ||||
|         this.apiEnvironment.shutdown(); | ||||
|     } | ||||
|  | ||||
| @@ -193,7 +207,8 @@ public class OSAPI implements ILuaAPI { | ||||
|      * Reboots the computer immediately. | ||||
|      */ | ||||
|     @LuaFunction( "reboot" ) | ||||
|     public final void doReboot() { | ||||
|     public final void doReboot() | ||||
|     { | ||||
|         this.apiEnvironment.reboot(); | ||||
|     } | ||||
|  | ||||
| @@ -206,7 +221,8 @@ public class OSAPI implements ILuaAPI { | ||||
|         "getComputerID", | ||||
|         "computerID" | ||||
|     } ) | ||||
|     public final int getComputerID() { | ||||
|     public final int getComputerID() | ||||
|     { | ||||
|         return this.apiEnvironment.getComputerID(); | ||||
|     } | ||||
|  | ||||
| @@ -220,7 +236,8 @@ public class OSAPI implements ILuaAPI { | ||||
|         "getComputerLabel", | ||||
|         "computerLabel" | ||||
|     } ) | ||||
|     public final Object[] getComputerLabel() { | ||||
|     public final Object[] getComputerLabel() | ||||
|     { | ||||
|         String label = this.apiEnvironment.getLabel(); | ||||
|         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. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final void setComputerLabel(Optional<String> label) { | ||||
|     public final void setComputerLabel( Optional<String> label ) | ||||
|     { | ||||
|         this.apiEnvironment.setLabel( StringUtil.normaliseLabel( label.orElse( null ) ) ); | ||||
|     } | ||||
|  | ||||
| @@ -241,7 +259,8 @@ public class OSAPI implements ILuaAPI { | ||||
|      * @return The computer's uptime. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final double clock() { | ||||
|     public final double clock() | ||||
|     { | ||||
|         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. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final Object time(IArguments args) throws LuaException { | ||||
|     public final Object time( IArguments args ) throws LuaException | ||||
|     { | ||||
|         Object value = args.get( 0 ); | ||||
|         if (value instanceof Map) { | ||||
|         if( value instanceof Map ) | ||||
|         { | ||||
|             return LuaDateTime.fromTable( (Map<?, ?>) value ); | ||||
|         } | ||||
|  | ||||
|         String param = args.optString( 0, "ingame" ); | ||||
|         switch (param.toLowerCase(Locale.ROOT)) { | ||||
|         switch( param.toLowerCase( Locale.ROOT ) ) | ||||
|         { | ||||
|             case "utc": // Get Hour of day (UTC) | ||||
|                 return getTimeForCalendar( Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) ); | ||||
|             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 ); | ||||
|         time += c.get( Calendar.MINUTE ) / 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. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final int day(Optional<String> args) throws LuaException { | ||||
|     public final int day( Optional<String> args ) throws LuaException | ||||
|     { | ||||
|         switch( args.orElse( "ingame" ) | ||||
|                     .toLowerCase(Locale.ROOT)) { | ||||
|             .toLowerCase( Locale.ROOT ) ) | ||||
|         { | ||||
|             case "utc":     // Get numbers of days since 1970-01-01 (utc) | ||||
|                 return getDayForCalendar( Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) ); | ||||
|             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(); | ||||
|         int year = c.get( Calendar.YEAR ); | ||||
|         int day = 0; | ||||
|         for (int y = 1970; y < year; y++) { | ||||
|         for( int y = 1970; y < year; y++ ) | ||||
|         { | ||||
|             day += g.isLeapYear( y ) ? 366 : 365; | ||||
|         } | ||||
|         day += c.get( Calendar.DAY_OF_YEAR ); | ||||
| @@ -337,22 +364,27 @@ public class OSAPI implements ILuaAPI { | ||||
|      * @throws LuaException If an invalid locale is passed. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     public final long epoch(Optional<String> args) throws LuaException { | ||||
|     public final long epoch( Optional<String> args ) throws LuaException | ||||
|     { | ||||
|         switch( args.orElse( "ingame" ) | ||||
|                     .toLowerCase(Locale.ROOT)) { | ||||
|         case "utc": { | ||||
|             .toLowerCase( Locale.ROOT ) ) | ||||
|         { | ||||
|             case "utc": | ||||
|             { | ||||
|                 // Get utc epoch | ||||
|                 Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ); | ||||
|                 return getEpochForCalendar( c ); | ||||
|             } | ||||
|         case "local": { | ||||
|             case "local": | ||||
|             { | ||||
|                 // Get local epoch | ||||
|                 Calendar c = Calendar.getInstance(); | ||||
|                 return getEpochForCalendar( c ); | ||||
|             } | ||||
|             case "ingame": | ||||
|                 // Get in-game epoch | ||||
|             synchronized (this.m_alarms) { | ||||
|                 synchronized( this.m_alarms ) | ||||
|                 { | ||||
|                     return this.m_day * 86400000L + (long) (this.m_time * 3600000.0); | ||||
|                 } | ||||
|             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() | ||||
|             .getTime(); | ||||
|     } | ||||
| @@ -381,7 +414,8 @@ public class OSAPI implements ILuaAPI { | ||||
|      * @throws LuaException If an invalid format is passed. | ||||
|      */ | ||||
|     @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" ); | ||||
|         long time = timeA.orElseGet( () -> Instant.now() | ||||
|             .getEpochSecond() ); | ||||
| @@ -389,18 +423,22 @@ public class OSAPI implements ILuaAPI { | ||||
|         Instant instant = Instant.ofEpochSecond( time ); | ||||
|         ZonedDateTime date; | ||||
|         ZoneOffset offset; | ||||
|         if (format.startsWith("!")) { | ||||
|         if( format.startsWith( "!" ) ) | ||||
|         { | ||||
|             offset = ZoneOffset.UTC; | ||||
|             date = ZonedDateTime.ofInstant( instant, offset ); | ||||
|             format = format.substring( 1 ); | ||||
|         } else { | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             ZoneId id = ZoneId.systemDefault(); | ||||
|             offset = id.getRules() | ||||
|                 .getOffset( instant ); | ||||
|             date = ZonedDateTime.ofInstant( instant, id ); | ||||
|         } | ||||
|  | ||||
|         if (format.equals("*t")) { | ||||
|         if( format.equals( "*t" ) ) | ||||
|         { | ||||
|             return LuaDateTime.toTable( date, offset, instant ); | ||||
|         } | ||||
|  | ||||
| @@ -410,17 +448,20 @@ public class OSAPI implements ILuaAPI { | ||||
|             .format( date ); | ||||
|     } | ||||
|  | ||||
|     private static class Alarm implements Comparable<Alarm> { | ||||
|     private static class Alarm implements Comparable<Alarm> | ||||
|     { | ||||
|         final double m_time; | ||||
|         final int m_day; | ||||
|  | ||||
|         Alarm(double time, int day) { | ||||
|         Alarm( double time, int day ) | ||||
|         { | ||||
|             this.m_time = time; | ||||
|             this.m_day = day; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public int compareTo(@Nonnull Alarm o) { | ||||
|         public int compareTo( @Nonnull Alarm o ) | ||||
|         { | ||||
|             double t = this.m_day * 24.0 + this.m_time; | ||||
|             double ot = this.m_day * 24.0 + this.m_time; | ||||
|             return Double.compare( t, ot ); | ||||
|   | ||||
| @@ -6,24 +6,9 @@ | ||||
|  | ||||
| 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.IWritableMount; | ||||
| import dan200.computercraft.api.lua.IArguments; | ||||
| 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.lua.*; | ||||
| import dan200.computercraft.api.peripheral.IDynamicPeripheral; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| 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.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.module peripheral | ||||
|  * @hidden | ||||
|  */ | ||||
| public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener { | ||||
| public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener | ||||
| { | ||||
|     private final IAPIEnvironment environment; | ||||
|     private final PeripheralWrapper[] peripherals = new PeripheralWrapper[6]; | ||||
|     private boolean running; | ||||
|     public PeripheralAPI(IAPIEnvironment environment) { | ||||
|  | ||||
|     public PeripheralAPI( IAPIEnvironment environment ) | ||||
|     { | ||||
|         this.environment = environment; | ||||
|         this.environment.setPeripheralChangeListener( this ); | ||||
|         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(), | ||||
|             "Peripheral methods cannot be null" ) : | ||||
|             LuaMethod.EMPTY_METHODS; | ||||
| @@ -58,10 +51,12 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|         List<NamedMethod<PeripheralMethod>> methods = PeripheralMethod.GENERATOR.getMethods( peripheral.getClass() ); | ||||
|  | ||||
|         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 ) ); | ||||
|         } | ||||
|         for (NamedMethod<PeripheralMethod> method : methods) { | ||||
|         for( NamedMethod<PeripheralMethod> method : methods ) | ||||
|         { | ||||
|             methodMap.put( method.getName(), method.getMethod() ); | ||||
|         } | ||||
|         return methodMap; | ||||
| @@ -70,13 +65,17 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|     // IPeripheralChangeListener | ||||
|  | ||||
|     @Override | ||||
|     public void onPeripheralChanged(ComputerSide side, IPeripheral newPeripheral) { | ||||
|         synchronized (this.peripherals) { | ||||
|     public void onPeripheralChanged( ComputerSide side, IPeripheral newPeripheral ) | ||||
|     { | ||||
|         synchronized( this.peripherals ) | ||||
|         { | ||||
|             int index = side.ordinal(); | ||||
|             if (this.peripherals[index] != null) { | ||||
|             if( this.peripherals[index] != null ) | ||||
|             { | ||||
|                 // Queue a detachment | ||||
|                 final PeripheralWrapper wrapper = this.peripherals[index]; | ||||
|                 if (wrapper.isAttached()) { | ||||
|                 if( wrapper.isAttached() ) | ||||
|                 { | ||||
|                     wrapper.detach(); | ||||
|                 } | ||||
|  | ||||
| @@ -87,10 +86,12 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|             // Assign the new peripheral | ||||
|             this.peripherals[index] = newPeripheral == null ? null : new PeripheralWrapper( newPeripheral, side.getName() ); | ||||
|  | ||||
|             if (this.peripherals[index] != null) { | ||||
|             if( this.peripherals[index] != null ) | ||||
|             { | ||||
|                 // Queue an attachment | ||||
|                 final PeripheralWrapper wrapper = this.peripherals[index]; | ||||
|                 if (this.running && !wrapper.isAttached()) { | ||||
|                 if( this.running && !wrapper.isAttached() ) | ||||
|                 { | ||||
|                     wrapper.attach(); | ||||
|                 } | ||||
|  | ||||
| @@ -101,17 +102,22 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String[] getNames() { | ||||
|     public String[] getNames() | ||||
|     { | ||||
|         return new String[] { "peripheral" }; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void startup() { | ||||
|         synchronized (this.peripherals) { | ||||
|     public void startup() | ||||
|     { | ||||
|         synchronized( this.peripherals ) | ||||
|         { | ||||
|             this.running = true; | ||||
|             for (int i = 0; i < 6; i++) { | ||||
|             for( int i = 0; i < 6; i++ ) | ||||
|             { | ||||
|                 PeripheralWrapper wrapper = this.peripherals[i]; | ||||
|                 if (wrapper != null && !wrapper.isAttached()) { | ||||
|                 if( wrapper != null && !wrapper.isAttached() ) | ||||
|                 { | ||||
|                     wrapper.attach(); | ||||
|                 } | ||||
|             } | ||||
| @@ -119,12 +125,16 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void shutdown() { | ||||
|         synchronized (this.peripherals) { | ||||
|     public void shutdown() | ||||
|     { | ||||
|         synchronized( this.peripherals ) | ||||
|         { | ||||
|             this.running = false; | ||||
|             for (int i = 0; i < 6; i++) { | ||||
|             for( int i = 0; i < 6; i++ ) | ||||
|             { | ||||
|                 PeripheralWrapper wrapper = this.peripherals[i]; | ||||
|                 if (wrapper != null && wrapper.isAttached()) { | ||||
|                 if( wrapper != null && wrapper.isAttached() ) | ||||
|                 { | ||||
|                     wrapper.detach(); | ||||
|                 } | ||||
|             } | ||||
| @@ -132,12 +142,16 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|     } | ||||
|  | ||||
|     @LuaFunction | ||||
|     public final boolean isPresent(String sideName) { | ||||
|     public final boolean isPresent( String sideName ) | ||||
|     { | ||||
|         ComputerSide side = ComputerSide.valueOfInsensitive( sideName ); | ||||
|         if (side != null) { | ||||
|             synchronized (this.peripherals) { | ||||
|         if( side != null ) | ||||
|         { | ||||
|             synchronized( this.peripherals ) | ||||
|             { | ||||
|                 PeripheralWrapper p = this.peripherals[side.ordinal()]; | ||||
|                 if (p != null) { | ||||
|                 if( p != null ) | ||||
|                 { | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
| @@ -146,15 +160,19 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|     } | ||||
|  | ||||
|     @LuaFunction | ||||
|     public final Object[] getType(String sideName) { | ||||
|     public final Object[] getType( String sideName ) | ||||
|     { | ||||
|         ComputerSide side = ComputerSide.valueOfInsensitive( sideName ); | ||||
|         if (side == null) { | ||||
|         if( side == null ) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         synchronized (this.peripherals) { | ||||
|         synchronized( this.peripherals ) | ||||
|         { | ||||
|             PeripheralWrapper p = this.peripherals[side.ordinal()]; | ||||
|             if (p != null) { | ||||
|             if( p != null ) | ||||
|             { | ||||
|                 return new Object[] { p.getType() }; | ||||
|             } | ||||
|         } | ||||
| @@ -162,15 +180,19 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|     } | ||||
|  | ||||
|     @LuaFunction | ||||
|     public final Object[] getMethods(String sideName) { | ||||
|     public final Object[] getMethods( String sideName ) | ||||
|     { | ||||
|         ComputerSide side = ComputerSide.valueOfInsensitive( sideName ); | ||||
|         if (side == null) { | ||||
|         if( side == null ) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         synchronized (this.peripherals) { | ||||
|         synchronized( this.peripherals ) | ||||
|         { | ||||
|             PeripheralWrapper p = this.peripherals[side.ordinal()]; | ||||
|             if (p != null) { | ||||
|             if( p != null ) | ||||
|             { | ||||
|                 return new Object[] { p.getMethods() }; | ||||
|             } | ||||
|         } | ||||
| @@ -178,37 +200,46 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|     } | ||||
|  | ||||
|     @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 ) ); | ||||
|         String methodName = args.getString( 1 ); | ||||
|         IArguments methodArgs = args.drop( 2 ); | ||||
|  | ||||
|         if (side == null) { | ||||
|         if( side == null ) | ||||
|         { | ||||
|             throw new LuaException( "No peripheral attached" ); | ||||
|         } | ||||
|  | ||||
|         PeripheralWrapper p; | ||||
|         synchronized (this.peripherals) { | ||||
|         synchronized( this.peripherals ) | ||||
|         { | ||||
|             p = this.peripherals[side.ordinal()]; | ||||
|         } | ||||
|         if (p == null) { | ||||
|         if( p == null ) | ||||
|         { | ||||
|             throw new LuaException( "No peripheral attached" ); | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|         try | ||||
|         { | ||||
|             return p.call( context, methodName, methodArgs ) | ||||
|                 .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 | ||||
|             // 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 e; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private class PeripheralWrapper extends ComputerAccess { | ||||
|     private class PeripheralWrapper extends ComputerAccess | ||||
|     { | ||||
|         private final String side; | ||||
|         private final IPeripheral peripheral; | ||||
|  | ||||
| @@ -216,7 +247,8 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|         private final Map<String, PeripheralMethod> methodMap; | ||||
|         private boolean attached; | ||||
|  | ||||
|         PeripheralWrapper(IPeripheral peripheral, String side) { | ||||
|         PeripheralWrapper( IPeripheral peripheral, String side ) | ||||
|         { | ||||
|             super( PeripheralAPI.this.environment ); | ||||
|             this.side = side; | ||||
|             this.peripheral = peripheral; | ||||
| @@ -227,42 +259,56 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|             this.methodMap = PeripheralAPI.getMethods( peripheral ); | ||||
|         } | ||||
|  | ||||
|         public String getType() { | ||||
|         public String getType() | ||||
|         { | ||||
|             return this.type; | ||||
|         }        public IPeripheral getPeripheral() { | ||||
|         } | ||||
|  | ||||
|         public IPeripheral getPeripheral() | ||||
|         { | ||||
|             return this.peripheral; | ||||
|         } | ||||
|  | ||||
|         public Collection<String> getMethods() { | ||||
|         public Collection<String> getMethods() | ||||
|         { | ||||
|             return this.methodMap.keySet(); | ||||
|         } | ||||
|  | ||||
|         public synchronized void attach() { | ||||
|         public synchronized void attach() | ||||
|         { | ||||
|             this.attached = true; | ||||
|             this.peripheral.attach( this ); | ||||
|         } | ||||
|  | ||||
|         public void detach() { | ||||
|         public void detach() | ||||
|         { | ||||
|             // Call detach | ||||
|             this.peripheral.detach( this ); | ||||
|  | ||||
|             synchronized (this) { | ||||
|             synchronized( this ) | ||||
|             { | ||||
|                 // Unmount everything the detach function forgot to do | ||||
|                 this.unmountAll(); | ||||
|             } | ||||
|  | ||||
|             this.attached = false; | ||||
|         }        public synchronized boolean isAttached() { | ||||
|         } | ||||
|  | ||||
|         public synchronized boolean isAttached() | ||||
|         { | ||||
|             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; | ||||
|             synchronized (this) { | ||||
|             synchronized( this ) | ||||
|             { | ||||
|                 method = this.methodMap.get( methodName ); | ||||
|             } | ||||
|  | ||||
|             if (method == null) { | ||||
|             if( method == null ) | ||||
|             { | ||||
|                 throw new LuaException( "No such method " + methodName ); | ||||
|             } | ||||
|  | ||||
| @@ -272,40 +318,50 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|  | ||||
|         // IComputerAccess implementation | ||||
|         @Override | ||||
|         public synchronized String mount(@Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName) { | ||||
|             if (!this.attached) { | ||||
|         public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName ) | ||||
|         { | ||||
|             if( !this.attached ) | ||||
|             { | ||||
|                 throw new NotAttachedException(); | ||||
|             } | ||||
|             return super.mount( desiredLoc, mount, driveName ); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public synchronized String mountWritable(@Nonnull String desiredLoc, @Nonnull IWritableMount mount, @Nonnull String driveName) { | ||||
|             if (!this.attached) { | ||||
|         public synchronized String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount, @Nonnull String driveName ) | ||||
|         { | ||||
|             if( !this.attached ) | ||||
|             { | ||||
|                 throw new NotAttachedException(); | ||||
|             } | ||||
|             return super.mountWritable( desiredLoc, mount, driveName ); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public synchronized void unmount(String location) { | ||||
|             if (!this.attached) { | ||||
|         public synchronized void unmount( String location ) | ||||
|         { | ||||
|             if( !this.attached ) | ||||
|             { | ||||
|                 throw new NotAttachedException(); | ||||
|             } | ||||
|             super.unmount( location ); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public int getID() { | ||||
|             if (!this.attached) { | ||||
|         public int getID() | ||||
|         { | ||||
|             if( !this.attached ) | ||||
|             { | ||||
|                 throw new NotAttachedException(); | ||||
|             } | ||||
|             return super.getID(); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void queueEvent(@Nonnull String event, Object... arguments) { | ||||
|             if (!this.attached) { | ||||
|         public void queueEvent( @Nonnull String event, Object... arguments ) | ||||
|         { | ||||
|             if( !this.attached ) | ||||
|             { | ||||
|                 throw new NotAttachedException(); | ||||
|             } | ||||
|             super.queueEvent( event, arguments ); | ||||
| @@ -313,19 +369,22 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|  | ||||
|         @Nonnull | ||||
|         @Override | ||||
|         public IWorkMonitor getMainThreadMonitor() { | ||||
|             if (!this.attached) { | ||||
|         public IWorkMonitor getMainThreadMonitor() | ||||
|         { | ||||
|             if( !this.attached ) | ||||
|             { | ||||
|                 throw new NotAttachedException(); | ||||
|             } | ||||
|             return super.getMainThreadMonitor(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|         @Nonnull | ||||
|         @Override | ||||
|         public String getAttachmentName() { | ||||
|             if (!this.attached) { | ||||
|         public String getAttachmentName() | ||||
|         { | ||||
|             if( !this.attached ) | ||||
|             { | ||||
|                 throw new NotAttachedException(); | ||||
|             } | ||||
|             return this.side; | ||||
| @@ -333,14 +392,18 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|  | ||||
|         @Nonnull | ||||
|         @Override | ||||
|         public Map<String, IPeripheral> getAvailablePeripherals() { | ||||
|             if (!this.attached) { | ||||
|         public Map<String, IPeripheral> getAvailablePeripherals() | ||||
|         { | ||||
|             if( !this.attached ) | ||||
|             { | ||||
|                 throw new NotAttachedException(); | ||||
|             } | ||||
|  | ||||
|             Map<String, IPeripheral> peripherals = new HashMap<>(); | ||||
|             for (PeripheralWrapper wrapper : PeripheralAPI.this.peripherals) { | ||||
|                 if (wrapper != null && wrapper.isAttached()) { | ||||
|             for( PeripheralWrapper wrapper : PeripheralAPI.this.peripherals ) | ||||
|             { | ||||
|                 if( wrapper != null && wrapper.isAttached() ) | ||||
|                 { | ||||
|                     peripherals.put( wrapper.getAttachmentName(), wrapper.getPeripheral() ); | ||||
|                 } | ||||
|             } | ||||
| @@ -350,14 +413,18 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | ||||
|  | ||||
|         @Nullable | ||||
|         @Override | ||||
|         public IPeripheral getAvailablePeripheral(@Nonnull String name) { | ||||
|             if (!this.attached) { | ||||
|         public IPeripheral getAvailablePeripheral( @Nonnull String name ) | ||||
|         { | ||||
|             if( !this.attached ) | ||||
|             { | ||||
|                 throw new NotAttachedException(); | ||||
|             } | ||||
|  | ||||
|             for (PeripheralWrapper wrapper : PeripheralAPI.this.peripherals) { | ||||
|             for( PeripheralWrapper wrapper : PeripheralAPI.this.peripherals ) | ||||
|             { | ||||
|                 if( wrapper != null && wrapper.isAttached() && wrapper.getAttachmentName() | ||||
|                                                                       .equals(name)) { | ||||
|                     .equals( name ) ) | ||||
|                 { | ||||
|                     return wrapper.getPeripheral(); | ||||
|                 } | ||||
|             } | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates