mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 05:33:00 +00:00 
			
		
		
		
	fix: first part of syncing with Tweaked codebase
includes: file drag'n'drop (now doesn't work in Tweaked) and no inventory mode for left hand pocket computer
This commit is contained in:
		| @@ -9,17 +9,18 @@ package dan200.computercraft.api.lua; | |||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * An interface passed to peripherals and {@link IDynamicLuaObject}s by computers or turtles, providing methods that allow the peripheral call to interface |  * An interface passed to peripherals and {@link IDynamicLuaObject}s by computers or turtles, providing methods | ||||||
|  * with the computer. |  * 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 |      * Queue a task to be executed on the main server thread at the beginning of next tick, but do not wait for it to | ||||||
|      * need to interact with the world in a thread-safe manner but do not care about the result or you wish to run asynchronously. |      * 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. | ||||||
|      * |      * | ||||||
|      * When the task has finished, it will enqueue a {@code task_completed} event, which takes the task id, a success value and the return values, or an |      * When the task has finished, it will enqueue a {@code task_completed} event, which takes the task id, a success | ||||||
|      * error message if it failed. |      * value and the return values, or an error message if it failed. | ||||||
|      * |      * | ||||||
|      * @param task The task to execute on the main thread. |      * @param task The task to execute on the main thread. | ||||||
|      * @return The "id" of the task. This will be the first argument to the {@code task_completed} event. |      * @return The "id" of the task. This will be the first argument to the {@code task_completed} event. | ||||||
| @@ -27,4 +28,18 @@ public interface ILuaContext | |||||||
|      * @see LuaFunction#mainThread() To run functions on the main thread and return their results synchronously. |      * @see LuaFunction#mainThread() To run functions on the main thread and return their results synchronously. | ||||||
|      */ |      */ | ||||||
|     long issueMainThreadTask( @Nonnull ILuaTask task ) throws LuaException; |     long issueMainThreadTask( @Nonnull ILuaTask task ) throws LuaException; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Queue a task to be executed on the main server thread at the beginning of next tick, waiting for it to complete. | ||||||
|  |      * This should be used when you need to interact with the world in a thread-safe manner. | ||||||
|  |      * | ||||||
|  |      * Note that the return values of your task are handled as events, meaning more complex objects such as maps or | ||||||
|  |      * {@link IDynamicLuaObject} will not preserve their identities. | ||||||
|  |      * | ||||||
|  |      * @param task The task to execute on the main thread. | ||||||
|  |      * @return The objects returned by {@code task}. | ||||||
|  |      * @throws LuaException If the task could not be queued, or if the task threw an exception. | ||||||
|  |      */ | ||||||
|  |     @Nonnull | ||||||
|  |     MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,18 +0,0 @@ | |||||||
| /* |  | ||||||
|  * This file is part of the public ComputerCraft API - http://www.computercraft.info |  | ||||||
|  * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. |  | ||||||
|  * For help using the API, and posting your mods, visit the forums at computercraft.info. |  | ||||||
|  */ |  | ||||||
| package dan200.computercraft.api.lua; |  | ||||||
|  |  | ||||||
| import javax.annotation.Nonnull; |  | ||||||
| import javax.annotation.Nullable; |  | ||||||
|  |  | ||||||
| public interface ILuaObject |  | ||||||
| { |  | ||||||
|     @Nonnull |  | ||||||
|     String[] getMethodNames(); |  | ||||||
|  |  | ||||||
|     @Nullable |  | ||||||
|     Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException; |  | ||||||
| } |  | ||||||
| @@ -6,12 +6,15 @@ | |||||||
|  |  | ||||||
| package dan200.computercraft.api.pocket; | package dan200.computercraft.api.pocket; | ||||||
|  |  | ||||||
|  | import dan200.computercraft.shared.util.NonNullSupplier; | ||||||
|  | import net.minecraft.item.Item; | ||||||
| import net.minecraft.item.ItemConvertible; | import net.minecraft.item.ItemConvertible; | ||||||
| import net.minecraft.item.ItemStack; | import net.minecraft.item.ItemStack; | ||||||
| import net.minecraft.util.Identifier; | import net.minecraft.util.Identifier; | ||||||
| import net.minecraft.util.Util; | import net.minecraft.util.Util; | ||||||
|  |  | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
|  | import java.util.function.Supplier; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * A base class for {@link IPocketUpgrade}s. |  * A base class for {@link IPocketUpgrade}s. | ||||||
| @@ -22,27 +25,49 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade | |||||||
| { | { | ||||||
|     private final Identifier id; |     private final Identifier id; | ||||||
|     private final String adjective; |     private final String adjective; | ||||||
|     private final ItemStack stack; |     private final NonNullSupplier<ItemStack> stack; | ||||||
|  |  | ||||||
|     protected AbstractPocketUpgrade( Identifier id, ItemConvertible item ) |     protected AbstractPocketUpgrade( Identifier id, String adjective, NonNullSupplier<ItemStack> stack ) | ||||||
|     { |  | ||||||
|         this( id, Util.createTranslationKey( "upgrade", id ) + ".adjective", item ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     protected AbstractPocketUpgrade( Identifier id, String adjective, ItemConvertible item ) |  | ||||||
|     { |  | ||||||
|         this.id = id; |  | ||||||
|         this.adjective = adjective; |  | ||||||
|         stack = new ItemStack( item ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     protected AbstractPocketUpgrade( Identifier id, String adjective, ItemStack stack ) |  | ||||||
|     { |     { | ||||||
|         this.id = id; |         this.id = id; | ||||||
|         this.adjective = adjective; |         this.adjective = adjective; | ||||||
|         this.stack = stack; |         this.stack = stack; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     protected AbstractPocketUpgrade( Identifier id, NonNullSupplier<ItemStack> item ) | ||||||
|  |     { | ||||||
|  |         this( id, Util.createTranslationKey( "upgrade", id ) + ".adjective", item ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AbstractPocketUpgrade( Identifier id, String adjective, ItemStack stack ) | ||||||
|  |     { | ||||||
|  |         this( id, adjective, () -> stack ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AbstractPocketUpgrade( Identifier id, ItemStack stack ) | ||||||
|  |     { | ||||||
|  |         this( id, () -> stack ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AbstractPocketUpgrade( Identifier id, String adjective, ItemConvertible item ) | ||||||
|  |     { | ||||||
|  |         this( id, adjective, new CachedStack( () -> item ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AbstractPocketUpgrade( Identifier id, ItemConvertible item ) | ||||||
|  |     { | ||||||
|  |         this( id, new CachedStack( () -> item ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AbstractPocketUpgrade( Identifier id, String adjective, Supplier<? extends ItemConvertible> item ) | ||||||
|  |     { | ||||||
|  |         this( id, adjective, new CachedStack( item ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AbstractPocketUpgrade( Identifier id, Supplier<? extends ItemConvertible> item ) | ||||||
|  |     { | ||||||
|  |         this( id, new CachedStack( item ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Nonnull |     @Nonnull | ||||||
|     @Override |     @Override | ||||||
| @@ -62,6 +87,32 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade | |||||||
|     @Override |     @Override | ||||||
|     public final ItemStack getCraftingItem() |     public final ItemStack getCraftingItem() | ||||||
|     { |     { | ||||||
|         return stack; |         return stack.get(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Caches the construction of an item stack. | ||||||
|  |      * | ||||||
|  |      * @see dan200.computercraft.api.turtle.AbstractTurtleUpgrade For explanation of this class. | ||||||
|  |      */ | ||||||
|  |     private static final class CachedStack implements NonNullSupplier<ItemStack> | ||||||
|  |     { | ||||||
|  |         private final Supplier<? extends ItemConvertible> provider; | ||||||
|  |         private Item item; | ||||||
|  |         private ItemStack stack; | ||||||
|  |  | ||||||
|  |         CachedStack( Supplier<? extends ItemConvertible> provider ) | ||||||
|  |         { | ||||||
|  |             this.provider = provider; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Nonnull | ||||||
|  |         @Override | ||||||
|  |         public ItemStack get() | ||||||
|  |         { | ||||||
|  |             Item item = provider.get().asItem(); | ||||||
|  |             if( item == this.item && stack != null ) return stack; | ||||||
|  |             return stack = new ItemStack( this.item = item ); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,12 +6,15 @@ | |||||||
|  |  | ||||||
| package dan200.computercraft.api.turtle; | package dan200.computercraft.api.turtle; | ||||||
|  |  | ||||||
|  | import dan200.computercraft.shared.util.NonNullSupplier; | ||||||
|  | import net.minecraft.item.Item; | ||||||
| import net.minecraft.item.ItemConvertible; | import net.minecraft.item.ItemConvertible; | ||||||
| import net.minecraft.item.ItemStack; | import net.minecraft.item.ItemStack; | ||||||
| import net.minecraft.util.Identifier; | import net.minecraft.util.Identifier; | ||||||
| import net.minecraft.util.Util; | import net.minecraft.util.Util; | ||||||
|  |  | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
|  | import java.util.function.Supplier; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * A base class for {@link ITurtleUpgrade}s. |  * A base class for {@link ITurtleUpgrade}s. | ||||||
| @@ -23,14 +26,9 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade | |||||||
|     private final Identifier id; |     private final Identifier id; | ||||||
|     private final TurtleUpgradeType type; |     private final TurtleUpgradeType type; | ||||||
|     private final String adjective; |     private final String adjective; | ||||||
|     private final ItemStack stack; |     private final NonNullSupplier<ItemStack> stack; | ||||||
|  |  | ||||||
|     protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemConvertible item ) |     protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, NonNullSupplier<ItemStack> stack ) | ||||||
|     { |  | ||||||
|         this( id, type, adjective, new ItemStack( item ) ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemStack stack ) |  | ||||||
|     { |     { | ||||||
|         this.id = id; |         this.id = id; | ||||||
|         this.type = type; |         this.type = type; | ||||||
| @@ -38,16 +36,40 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade | |||||||
|         this.stack = stack; |         this.stack = stack; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, ItemConvertible item ) |     protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, NonNullSupplier<ItemStack> stack ) | ||||||
|     { |  | ||||||
|         this( id, type, new ItemStack( item ) ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, ItemStack stack ) |  | ||||||
|     { |     { | ||||||
|         this( id, type, Util.createTranslationKey( "upgrade", id ) + ".adjective", stack ); |         this( id, type, Util.createTranslationKey( "upgrade", id ) + ".adjective", stack ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemStack stack ) | ||||||
|  |     { | ||||||
|  |         this( id, type, adjective, () -> stack ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, ItemStack stack ) | ||||||
|  |     { | ||||||
|  |         this( id, type, () -> stack ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemConvertible item ) | ||||||
|  |     { | ||||||
|  |         this( id, type, adjective, new CachedStack( () -> item ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, ItemConvertible item ) | ||||||
|  |     { | ||||||
|  |         this( id, type, new CachedStack( () -> item ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, Supplier<? extends ItemConvertible> item ) | ||||||
|  |     { | ||||||
|  |         this( id, type, adjective, new CachedStack( item ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, Supplier<? extends ItemConvertible> item ) | ||||||
|  |     { | ||||||
|  |         this( id, type, new CachedStack( item ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Nonnull |     @Nonnull | ||||||
|     @Override |     @Override | ||||||
| @@ -74,6 +96,32 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade | |||||||
|     @Override |     @Override | ||||||
|     public final ItemStack getCraftingItem() |     public final ItemStack getCraftingItem() | ||||||
|     { |     { | ||||||
|         return stack; |         return stack.get(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * A supplier which converts an item into an item stack. | ||||||
|  |      * | ||||||
|  |      * Constructing item stacks is somewhat expensive due to attaching capabilities. We cache it if given a consistent item. | ||||||
|  |      */ | ||||||
|  |     private static final class CachedStack implements NonNullSupplier<ItemStack> | ||||||
|  |     { | ||||||
|  |         private final Supplier<? extends ItemConvertible> provider; | ||||||
|  |         private Item item; | ||||||
|  |         private ItemStack stack; | ||||||
|  |  | ||||||
|  |         CachedStack( Supplier<? extends ItemConvertible> provider ) | ||||||
|  |         { | ||||||
|  |             this.provider = provider; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Nonnull | ||||||
|  |         @Override | ||||||
|  |         public ItemStack get() | ||||||
|  |         { | ||||||
|  |             Item item = provider.get().asItem(); | ||||||
|  |             if( item == this.item && stack != null ) return stack; | ||||||
|  |             return stack = new ItemStack( this.item = item ); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,10 +1,16 @@ | |||||||
| package dan200.computercraft.client.gui; | package dan200.computercraft.client.gui; | ||||||
|  |  | ||||||
|  | import dan200.computercraft.ComputerCraft; | ||||||
| import dan200.computercraft.client.gui.widgets.ComputerSidebar; | import dan200.computercraft.client.gui.widgets.ComputerSidebar; | ||||||
| import dan200.computercraft.client.gui.widgets.WidgetTerminal; | import dan200.computercraft.client.gui.widgets.WidgetTerminal; | ||||||
| import dan200.computercraft.shared.computer.core.ClientComputer; | import dan200.computercraft.shared.computer.core.ClientComputer; | ||||||
| import dan200.computercraft.shared.computer.core.ComputerFamily; | import dan200.computercraft.shared.computer.core.ComputerFamily; | ||||||
| import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; | import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; | ||||||
|  | import dan200.computercraft.shared.computer.upload.FileUpload; | ||||||
|  | import dan200.computercraft.shared.computer.upload.UploadResult; | ||||||
|  | import dan200.computercraft.shared.network.NetworkHandler; | ||||||
|  | import dan200.computercraft.shared.network.server.ContinueUploadMessage; | ||||||
|  | import dan200.computercraft.shared.network.server.UploadFileMessage; | ||||||
| import net.minecraft.client.gui.screen.ingame.HandledScreen; | import net.minecraft.client.gui.screen.ingame.HandledScreen; | ||||||
| import net.minecraft.client.util.math.MatrixStack; | import net.minecraft.client.util.math.MatrixStack; | ||||||
| import net.minecraft.entity.player.PlayerInventory; | import net.minecraft.entity.player.PlayerInventory; | ||||||
| @@ -13,6 +19,15 @@ import net.minecraft.text.TranslatableText; | |||||||
| import org.lwjgl.glfw.GLFW; | import org.lwjgl.glfw.GLFW; | ||||||
|  |  | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.nio.ByteBuffer; | ||||||
|  | import java.nio.channels.SeekableByteChannel; | ||||||
|  | import java.nio.file.Files; | ||||||
|  | import java.nio.file.Path; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
| public abstract class ComputerScreenBase <T extends ContainerComputerBase> extends HandledScreen<T> { | public abstract class ComputerScreenBase <T extends ContainerComputerBase> extends HandledScreen<T> { | ||||||
|  |  | ||||||
| @@ -94,4 +109,117 @@ public abstract class ComputerScreenBase <T extends ContainerComputerBase> exten | |||||||
|         // Skip rendering labels. |         // Skip rendering labels. | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void filesDragged( @Nonnull List<Path> files ) | ||||||
|  |     { | ||||||
|  |         // TODO: this thing doesn't work in Tweaked at this moment | ||||||
|  |         if (true) return; | ||||||
|  |         if( files.isEmpty() ) return; | ||||||
|  |  | ||||||
|  |         if( computer == null || !computer.isOn() ) | ||||||
|  |         { | ||||||
|  |             alert( UploadResult.FAILED_TITLE, UploadResult.COMPUTER_OFF_MSG ); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         long size = 0; | ||||||
|  |  | ||||||
|  |         List<FileUpload> toUpload = new ArrayList<>(); | ||||||
|  |         for( Path file : files ) | ||||||
|  |         { | ||||||
|  |             // TODO: Recurse directories? If so, we probably want to shunt this off-thread. | ||||||
|  |             if( !Files.isRegularFile( file ) ) continue; | ||||||
|  |  | ||||||
|  |             try( SeekableByteChannel sbc = Files.newByteChannel( file ) ) | ||||||
|  |             { | ||||||
|  |                 long fileSize = sbc.size(); | ||||||
|  |                 if( fileSize > UploadFileMessage.MAX_SIZE || (size += fileSize) >= UploadFileMessage.MAX_SIZE ) | ||||||
|  |                 { | ||||||
|  |                     alert( UploadResult.FAILED_TITLE, UploadResult.TOO_MUCH_MSG ); | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 String name = file.getFileName().toString(); | ||||||
|  |                 if( name.length() > UploadFileMessage.MAX_FILE_NAME ) | ||||||
|  |                 { | ||||||
|  |                     alert( UploadResult.FAILED_TITLE, new TranslatableText( "gui.computercraft.upload.failed.name_too_long" ) ); | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 ByteBuffer buffer = ByteBuffer.allocateDirect( (int) fileSize ); | ||||||
|  |                 sbc.read( buffer ); | ||||||
|  |                 buffer.flip(); | ||||||
|  |  | ||||||
|  |                 byte[] digest = FileUpload.getDigest( buffer ); | ||||||
|  |                 if( digest == null ) | ||||||
|  |                 { | ||||||
|  |                     alert( UploadResult.FAILED_TITLE, new TranslatableText( "gui.computercraft.upload.failed.corrupted" ) ); | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 buffer.rewind(); | ||||||
|  |                 toUpload.add( new FileUpload( name, buffer, digest ) ); | ||||||
|  |             } | ||||||
|  |             catch( IOException e ) | ||||||
|  |             { | ||||||
|  |                 ComputerCraft.log.error( "Failed uploading files", e ); | ||||||
|  |                 alert( UploadResult.FAILED_TITLE, new TranslatableText( "gui.computercraft.upload.failed.generic", "Cannot compute checksum" ) ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if( toUpload.size() > UploadFileMessage.MAX_FILES ) | ||||||
|  |         { | ||||||
|  |             alert( UploadResult.FAILED_TITLE, new TranslatableText( "gui.computercraft.upload.failed.too_many_files" ) ); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if( toUpload.size() > 0 ) | ||||||
|  |         { | ||||||
|  |             UploadFileMessage.send( computer.getInstanceID(), toUpload ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void uploadResult( UploadResult result, Text message ) | ||||||
|  |     { | ||||||
|  |         switch( result ) | ||||||
|  |         { | ||||||
|  |             case SUCCESS: | ||||||
|  |                 alert( UploadResult.SUCCESS_TITLE, message ); | ||||||
|  |                 break; | ||||||
|  |             case ERROR: | ||||||
|  |                 alert( UploadResult.FAILED_TITLE, message ); | ||||||
|  |                 break; | ||||||
|  |             case CONFIRM_OVERWRITE: | ||||||
|  |                 OptionScreen.show( | ||||||
|  |                     client, UploadResult.UPLOAD_OVERWRITE, message, | ||||||
|  |                     Arrays.asList( | ||||||
|  |                         OptionScreen.newButton( CANCEL, b -> cancelUpload() ), | ||||||
|  |                         OptionScreen.newButton( OVERWRITE, b -> continueUpload() ) | ||||||
|  |                     ), | ||||||
|  |                     this::cancelUpload | ||||||
|  |                 ); | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void continueUpload() | ||||||
|  |     { | ||||||
|  |         if( client.currentScreen instanceof OptionScreen ) ((OptionScreen) client.currentScreen).disable(); | ||||||
|  |         NetworkHandler.sendToServer( new ContinueUploadMessage( computer.getInstanceID(), true ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void cancelUpload() | ||||||
|  |     { | ||||||
|  |         client.setScreen( this ); | ||||||
|  |         NetworkHandler.sendToServer( new ContinueUploadMessage( computer.getInstanceID(), false ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void alert( Text title, Text message ) | ||||||
|  |     { | ||||||
|  |         OptionScreen.show( client, title, message, | ||||||
|  |             Collections.singletonList( OptionScreen.newButton( OK, b -> client.setScreen( this ) ) ), | ||||||
|  |             () -> client.setScreen( this ) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,10 +11,10 @@ import dan200.computercraft.client.gui.widgets.ComputerSidebar; | |||||||
| import dan200.computercraft.client.gui.widgets.WidgetTerminal; | import dan200.computercraft.client.gui.widgets.WidgetTerminal; | ||||||
| import dan200.computercraft.client.render.ComputerBorderRenderer; | import dan200.computercraft.client.render.ComputerBorderRenderer; | ||||||
| import dan200.computercraft.client.render.RenderTypes; | import dan200.computercraft.client.render.RenderTypes; | ||||||
| import dan200.computercraft.shared.computer.inventory.ContainerComputer; | //import dan200.computercraft.shared.computer.inventory.ContainerComputer; | ||||||
| import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; | import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; | ||||||
| import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; | import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; | ||||||
| import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; | //import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; | ||||||
| import net.minecraft.client.util.math.MatrixStack; | import net.minecraft.client.util.math.MatrixStack; | ||||||
| import net.minecraft.entity.player.PlayerInventory; | import net.minecraft.entity.player.PlayerInventory; | ||||||
| import net.minecraft.text.Text; | import net.minecraft.text.Text; | ||||||
| @@ -39,12 +39,12 @@ public final class GuiComputer<T extends ContainerComputerBase> extends Computer | |||||||
|         backgroundHeight = WidgetTerminal.getHeight( termHeight ) + BORDER * 2; |         backgroundHeight = WidgetTerminal.getHeight( termHeight ) + BORDER * 2; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static GuiComputer<ContainerComputer> create( ContainerComputer container, PlayerInventory inventory, Text component ) |     public static GuiComputer<ContainerComputerBase> create( ContainerComputerBase container, PlayerInventory inventory, Text component ) | ||||||
|     { |     { | ||||||
|         return new GuiComputer<>( container, inventory, component, ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight ); |         return new GuiComputer<>( container, inventory, component, ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static GuiComputer<ContainerPocketComputer> createPocket( ContainerPocketComputer container, PlayerInventory inventory, Text component ) |     public static GuiComputer<ContainerComputerBase> createPocket( ContainerComputerBase container, PlayerInventory inventory, Text component ) | ||||||
|     { |     { | ||||||
|         return new GuiComputer<>( container, inventory, component, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ); |         return new GuiComputer<>( container, inventory, component, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -0,0 +1,108 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.client.gui; | ||||||
|  |  | ||||||
|  | import dan200.computercraft.ComputerCraft; | ||||||
|  | import dan200.computercraft.client.gui.widgets.WidgetTerminal; | ||||||
|  | import dan200.computercraft.shared.computer.core.ClientComputer; | ||||||
|  | import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; | ||||||
|  | import net.minecraft.client.font.TextRenderer; | ||||||
|  | import net.minecraft.client.gui.screen.Screen; | ||||||
|  | import net.minecraft.client.gui.screen.ingame.ScreenHandlerProvider; | ||||||
|  | import net.minecraft.client.util.math.MatrixStack; | ||||||
|  | import net.minecraft.entity.player.PlayerInventory; | ||||||
|  | import net.minecraft.text.OrderedText; | ||||||
|  | import net.minecraft.text.Text; | ||||||
|  | import net.minecraft.text.TranslatableText; | ||||||
|  | import org.lwjgl.glfw.GLFW; | ||||||
|  |  | ||||||
|  | import javax.annotation.Nonnull; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | public class NoTermComputerScreen<T extends ContainerComputerBase> extends Screen implements ScreenHandlerProvider<T> | ||||||
|  | { | ||||||
|  |     private final T menu; | ||||||
|  |     private WidgetTerminal terminal; | ||||||
|  |  | ||||||
|  |     public NoTermComputerScreen(T menu, PlayerInventory player, Text title ) | ||||||
|  |     { | ||||||
|  |         super( title ); | ||||||
|  |         this.menu = menu; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Nonnull | ||||||
|  |     @Override | ||||||
|  |     public T getScreenHandler() | ||||||
|  |     { | ||||||
|  |         return menu; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected void init() | ||||||
|  |     { | ||||||
|  |         super.init(); | ||||||
|  |         client.keyboard.setRepeatEvents( true ); | ||||||
|  |  | ||||||
|  |         terminal = addDrawableChild( new WidgetTerminal( (ClientComputer) menu.getComputer(), 0, 0, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ) ); | ||||||
|  |         terminal.visible = false; | ||||||
|  |         terminal.active = false; | ||||||
|  |         setFocused( terminal ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public final void removed() | ||||||
|  |     { | ||||||
|  |         super.removed(); | ||||||
|  |         client.keyboard.setRepeatEvents( false ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public final void tick() | ||||||
|  |     { | ||||||
|  |         super.tick(); | ||||||
|  |         terminal.update(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void onClose() | ||||||
|  |     { | ||||||
|  |         client.player.closeHandledScreen(); | ||||||
|  |         super.onClose(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public boolean isPauseScreen() | ||||||
|  |     { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public final 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 && getFocused() != null && getFocused() == terminal ) | ||||||
|  |         { | ||||||
|  |             return getFocused().keyPressed( key, scancode, modifiers ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return super.keyPressed( key, scancode, modifiers ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void render(MatrixStack transform, int mouseX, int mouseY, float partialTicks ) | ||||||
|  |     { | ||||||
|  |         super.render( transform, mouseX, mouseY, partialTicks ); | ||||||
|  |  | ||||||
|  |         TextRenderer font = client.textRenderer; | ||||||
|  |         List<OrderedText> lines = font.wrapLines( new TranslatableText( "gui.computercraft.pocket_computer_overlay" ), (int) (width * 0.8) ); | ||||||
|  |         float y = 10.0f; | ||||||
|  |         for( OrderedText line : lines ) | ||||||
|  |         { | ||||||
|  |             font.drawWithShadow( transform, line, (float) ((width / 2) - (client.textRenderer.getWidth( line ) / 2)), y, 0xFFFFFF ); | ||||||
|  |             y += 9.0f; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										128
									
								
								src/main/java/dan200/computercraft/client/gui/OptionScreen.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								src/main/java/dan200/computercraft/client/gui/OptionScreen.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.client.gui; | ||||||
|  |  | ||||||
|  | import com.mojang.blaze3d.systems.RenderSystem; | ||||||
|  | import net.minecraft.client.MinecraftClient; | ||||||
|  | import net.minecraft.client.font.MultilineText; | ||||||
|  | import net.minecraft.client.gui.screen.Screen; | ||||||
|  | import net.minecraft.client.gui.widget.ButtonWidget; | ||||||
|  | import net.minecraft.client.gui.widget.ClickableWidget; | ||||||
|  | import net.minecraft.client.util.math.MatrixStack; | ||||||
|  | import net.minecraft.text.Text; | ||||||
|  | import net.minecraft.util.Identifier; | ||||||
|  |  | ||||||
|  | import javax.annotation.Nonnull; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | public final class OptionScreen extends Screen | ||||||
|  | { | ||||||
|  |     private static final Identifier BACKGROUND = new Identifier( "computercraft", "textures/gui/blank_screen.png" ); | ||||||
|  |  | ||||||
|  |     public static final int BUTTON_WIDTH = 100; | ||||||
|  |     public static final int BUTTON_HEIGHT = 20; | ||||||
|  |  | ||||||
|  |     private static final int PADDING = 16; | ||||||
|  |     private static final int FONT_HEIGHT = 9; | ||||||
|  |  | ||||||
|  |     private int x; | ||||||
|  |     private int y; | ||||||
|  |     private int innerWidth; | ||||||
|  |     private int innerHeight; | ||||||
|  |  | ||||||
|  |     private MultilineText messageRenderer; | ||||||
|  |     private final Text message; | ||||||
|  |     private final List<ClickableWidget> buttons; | ||||||
|  |     private final Runnable exit; | ||||||
|  |  | ||||||
|  |     private final Screen originalScreen; | ||||||
|  |  | ||||||
|  |     private OptionScreen(Text title, Text message, List<ClickableWidget> buttons, Runnable exit, Screen originalScreen ) | ||||||
|  |     { | ||||||
|  |         super( title ); | ||||||
|  |         this.message = message; | ||||||
|  |         this.buttons = buttons; | ||||||
|  |         this.exit = exit; | ||||||
|  |         this.originalScreen = originalScreen; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static void show( MinecraftClient client, Text title, Text message, List<ClickableWidget> buttons, Runnable exit ) | ||||||
|  |     { | ||||||
|  |         client.setScreen( new OptionScreen( title, message, buttons, exit, unwrap( client.currentScreen ) ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static Screen unwrap( Screen screen ) | ||||||
|  |     { | ||||||
|  |         return screen instanceof OptionScreen ? ((OptionScreen) screen).getOriginalScreen() : screen; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void init() | ||||||
|  |     { | ||||||
|  |         super.init(); | ||||||
|  |  | ||||||
|  |         int buttonWidth = BUTTON_WIDTH * buttons.size() + PADDING * (buttons.size() - 1); | ||||||
|  |         int innerWidth = this.innerWidth = Math.max( 256, buttonWidth + PADDING * 2 ); | ||||||
|  |  | ||||||
|  |         messageRenderer = MultilineText.create( textRenderer, message, innerWidth - PADDING * 2 ); | ||||||
|  |  | ||||||
|  |         int textHeight = messageRenderer.count() * FONT_HEIGHT + PADDING * 2; | ||||||
|  |         innerHeight = textHeight + (buttons.isEmpty() ? 0 : buttons.get( 0 ).getHeight()) + PADDING; | ||||||
|  |  | ||||||
|  |         x = (width - innerWidth) / 2; | ||||||
|  |         y = (height - innerHeight) / 2; | ||||||
|  |  | ||||||
|  |         int x = (width - buttonWidth) / 2; | ||||||
|  |         for( ClickableWidget button : buttons ) | ||||||
|  |         { | ||||||
|  |             button.x = x; | ||||||
|  |             button.y = y + textHeight; | ||||||
|  |             addDrawableChild( button ); | ||||||
|  |  | ||||||
|  |             x += BUTTON_WIDTH + PADDING; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void render(@Nonnull MatrixStack transform, int mouseX, int mouseY, float partialTicks ) | ||||||
|  |     { | ||||||
|  |         renderBackground( transform ); | ||||||
|  |  | ||||||
|  |         // Render the actual texture. | ||||||
|  |         RenderSystem.setShaderTexture( 0, BACKGROUND ); | ||||||
|  |         drawTexture( transform, x, y, 0, 0, innerWidth, PADDING ); | ||||||
|  |         drawTexture( transform, | ||||||
|  |             x, y + PADDING, 0, PADDING, innerWidth, innerHeight - PADDING * 2, | ||||||
|  |             innerWidth, PADDING | ||||||
|  |         ); | ||||||
|  |         drawTexture( transform, x, y + innerHeight - PADDING, 0, 256 - PADDING, innerWidth, PADDING ); | ||||||
|  |  | ||||||
|  |         messageRenderer.draw( transform, x + PADDING, y + PADDING, FONT_HEIGHT, 0x404040 ); | ||||||
|  |         super.render( transform, mouseX, mouseY, partialTicks ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void onClose() | ||||||
|  |     { | ||||||
|  |         exit.run(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static ClickableWidget newButton( Text component, ButtonWidget.PressAction clicked ) | ||||||
|  |     { | ||||||
|  |         return new ButtonWidget( 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT, component, clicked ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void disable() | ||||||
|  |     { | ||||||
|  |         for( ClickableWidget widget : buttons ) widget.active = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Nonnull | ||||||
|  |     public Screen getOriginalScreen() | ||||||
|  |     { | ||||||
|  |         return originalScreen; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -34,7 +34,6 @@ import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN; | |||||||
| public class WidgetTerminal extends ClickableWidget { | public class WidgetTerminal extends ClickableWidget { | ||||||
|     private static final float TERMINATE_TIME = 0.5f; |     private static final float TERMINATE_TIME = 0.5f; | ||||||
|  |  | ||||||
| //    private final MinecraftClient client; |  | ||||||
|     private final ClientComputer computer; |     private final ClientComputer computer; | ||||||
|  |  | ||||||
|     // The positions of the actual terminal |     // The positions of the actual terminal | ||||||
| @@ -43,8 +42,6 @@ public class WidgetTerminal extends ClickableWidget { | |||||||
|     private final int innerWidth; |     private final int innerWidth; | ||||||
|     private final int innerHeight; |     private final int innerHeight; | ||||||
|  |  | ||||||
|     private final BitSet keysDown = new BitSet( 256 ); |  | ||||||
| //    private boolean focused; |  | ||||||
|     private float terminateTimer = -1; |     private float terminateTimer = -1; | ||||||
|     private float rebootTimer = -1; |     private float rebootTimer = -1; | ||||||
|     private float shutdownTimer = -1; |     private float shutdownTimer = -1; | ||||||
| @@ -53,6 +50,8 @@ public class WidgetTerminal extends ClickableWidget { | |||||||
|     private int lastMouseX = -1; |     private int lastMouseX = -1; | ||||||
|     private int lastMouseY = -1; |     private int lastMouseY = -1; | ||||||
|  |  | ||||||
|  |     private final BitSet keysDown = new BitSet( 256 ); | ||||||
|  |  | ||||||
|     public WidgetTerminal( @Nonnull ClientComputer computer, int x, int y, int termWidth, int termHeight ) |     public WidgetTerminal( @Nonnull ClientComputer computer, int x, int y, int termWidth, int termHeight ) | ||||||
|     { |     { | ||||||
|         super( x, y, termWidth * FONT_WIDTH + MARGIN * 2, termHeight * FONT_HEIGHT + MARGIN * 2, LiteralText.EMPTY); |         super( x, y, termWidth * FONT_WIDTH + MARGIN * 2, termHeight * FONT_HEIGHT + MARGIN * 2, LiteralText.EMPTY); | ||||||
| @@ -65,6 +64,18 @@ public class WidgetTerminal extends ClickableWidget { | |||||||
|         innerHeight = termHeight * FONT_HEIGHT; |         innerHeight = termHeight * FONT_HEIGHT; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     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 | ||||||
|  |             queueEvent( "char", Character.toString( ch )); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private boolean inTermRegion( double mouseX, double mouseY ) |     private boolean inTermRegion( double mouseX, double mouseY ) | ||||||
|     { |     { | ||||||
|         return active && visible && mouseX >= innerX && mouseY >= innerY && mouseX < innerX + innerWidth && mouseY < innerY + innerHeight; |         return active && visible && mouseX >= innerX && mouseY >= innerY && mouseX < innerX + innerWidth && mouseY < innerY + innerHeight; | ||||||
| @@ -79,10 +90,8 @@ public class WidgetTerminal extends ClickableWidget { | |||||||
|         Terminal term = computer.getTerminal(); |         Terminal term = computer.getTerminal(); | ||||||
|         if( term != null ) |         if( term != null ) | ||||||
|         { |         { | ||||||
|             mouseX -= innerX; |             int charX = (int) ((mouseX - innerX) / FONT_WIDTH); | ||||||
|             mouseY -= innerY; |             int charY = (int) ((mouseY - innerY) / FONT_HEIGHT); | ||||||
|             int charX = (int) (mouseX / FONT_WIDTH); |  | ||||||
|             int charY = (int) (mouseY / FONT_HEIGHT); |  | ||||||
|             charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); |             charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); | ||||||
|             charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); |             charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); | ||||||
|  |  | ||||||
| @@ -105,10 +114,8 @@ public class WidgetTerminal extends ClickableWidget { | |||||||
|         Terminal term = computer.getTerminal(); |         Terminal term = computer.getTerminal(); | ||||||
|         if( term != null ) |         if( term != null ) | ||||||
|         { |         { | ||||||
|             mouseX -= innerX; |             int charX = (int) ((mouseX - innerX) / FONT_WIDTH); | ||||||
|             mouseY -= innerY; |             int charY = (int) ((mouseY - innerY) / FONT_HEIGHT); | ||||||
|             int charX = (int) (mouseX / FONT_WIDTH); |  | ||||||
|             int charY = (int) (mouseY / FONT_HEIGHT); |  | ||||||
|             charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); |             charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); | ||||||
|             charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); |             charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); | ||||||
|  |  | ||||||
| @@ -134,10 +141,8 @@ public class WidgetTerminal extends ClickableWidget { | |||||||
|         Terminal term = computer.getTerminal(); |         Terminal term = computer.getTerminal(); | ||||||
|         if( term != null ) |         if( term != null ) | ||||||
|         { |         { | ||||||
|             mouseX -= innerX; |             int charX = (int) ((mouseX - innerX) / FONT_WIDTH); | ||||||
|             mouseY -= innerY; |             int charY = (int) ((mouseY - innerY) / FONT_HEIGHT); | ||||||
|             int charX = (int) (mouseX / FONT_WIDTH); |  | ||||||
|             int charY = (int) (mouseY / FONT_HEIGHT); |  | ||||||
|             charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); |             charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); | ||||||
|             charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); |             charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); | ||||||
|  |  | ||||||
| @@ -161,10 +166,8 @@ public class WidgetTerminal extends ClickableWidget { | |||||||
|         Terminal term = computer.getTerminal(); |         Terminal term = computer.getTerminal(); | ||||||
|         if( term != null ) |         if( term != null ) | ||||||
|         { |         { | ||||||
|             mouseX -= innerX; |             int charX = (int) ((mouseX - innerX) / FONT_WIDTH); | ||||||
|             mouseY -= innerY; |             int charY = (int) ((mouseY - innerY) / FONT_HEIGHT); | ||||||
|             int charX = (int) (mouseX / FONT_WIDTH); |  | ||||||
|             int charY = (int) (mouseY / FONT_HEIGHT); |  | ||||||
|             charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); |             charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); | ||||||
|             charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); |             charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); | ||||||
|  |  | ||||||
| @@ -250,11 +253,7 @@ public class WidgetTerminal extends ClickableWidget { | |||||||
|             // Queue the "key" event and add to the down set |             // Queue the "key" event and add to the down set | ||||||
|             boolean repeat = keysDown.get( key ); |             boolean repeat = keysDown.get( key ); | ||||||
|             keysDown.set( key ); |             keysDown.set( key ); | ||||||
|             IComputer computer = this.computer; |             computer.keyDown( key, repeat ); | ||||||
|             if( computer != null ) |  | ||||||
|             { |  | ||||||
|                 computer.keyDown( key, repeat ); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return true; |         return true; | ||||||
| @@ -267,11 +266,7 @@ public class WidgetTerminal extends ClickableWidget { | |||||||
|         if( key >= 0 && keysDown.get( key ) ) |         if( key >= 0 && keysDown.get( key ) ) | ||||||
|         { |         { | ||||||
|             keysDown.set( key, false ); |             keysDown.set( key, false ); | ||||||
|             IComputer computer = this.computer; |             computer.keyUp( key ); | ||||||
|             if( computer != null ) |  | ||||||
|             { |  | ||||||
|                 computer.keyUp( key ); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         switch( key ) |         switch( key ) | ||||||
| @@ -294,18 +289,6 @@ public class WidgetTerminal extends ClickableWidget { | |||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     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 |  | ||||||
|             queueEvent( "char", Character.toString( ch ) ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void onFocusedChanged( boolean focused ) |     public void onFocusedChanged( boolean focused ) | ||||||
|     { |     { | ||||||
| @@ -337,11 +320,7 @@ public class WidgetTerminal extends ClickableWidget { | |||||||
|  |  | ||||||
|     private void queueEvent( String event, Object... args ) |     private void queueEvent( String event, Object... args ) | ||||||
|     { |     { | ||||||
|         ClientComputer computer = this.computer; |         computer.queueEvent( event, args ); | ||||||
|         if( computer != null ) |  | ||||||
|         { |  | ||||||
|             computer.queueEvent( event, args ); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void update() |     public void update() | ||||||
| @@ -353,20 +332,12 @@ public class WidgetTerminal extends ClickableWidget { | |||||||
|  |  | ||||||
|         if( shutdownTimer >= 0 && shutdownTimer < TERMINATE_TIME && (shutdownTimer += 0.05f) > TERMINATE_TIME ) |         if( shutdownTimer >= 0 && shutdownTimer < TERMINATE_TIME && (shutdownTimer += 0.05f) > TERMINATE_TIME ) | ||||||
|         { |         { | ||||||
|             ClientComputer computer = this.computer; |             computer.shutdown(); | ||||||
|             if( computer != null ) |  | ||||||
|             { |  | ||||||
|                 computer.shutdown(); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if( rebootTimer >= 0 && rebootTimer < TERMINATE_TIME && (rebootTimer += 0.05f) > TERMINATE_TIME ) |         if( rebootTimer >= 0 && rebootTimer < TERMINATE_TIME && (rebootTimer += 0.05f) > TERMINATE_TIME ) | ||||||
|         { |         { | ||||||
|             ClientComputer computer = this.computer; |             computer.reboot(); | ||||||
|             if( computer != null ) |  | ||||||
|             { |  | ||||||
|                 computer.reboot(); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,12 +20,13 @@ import dan200.computercraft.shared.common.ContainerHeldItem; | |||||||
| import dan200.computercraft.shared.common.IColouredItem; | import dan200.computercraft.shared.common.IColouredItem; | ||||||
| import dan200.computercraft.shared.common.TileGeneric; | import dan200.computercraft.shared.common.TileGeneric; | ||||||
| import dan200.computercraft.shared.computer.blocks.TileComputer; | import dan200.computercraft.shared.computer.blocks.TileComputer; | ||||||
| import dan200.computercraft.shared.computer.inventory.ContainerComputer; | //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.computer.inventory.ContainerViewComputer; | ||||||
| import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; | import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; | ||||||
| import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; | import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; | ||||||
| import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; | import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; | ||||||
| import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; | //import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; | ||||||
| import dan200.computercraft.shared.pocket.items.ItemPocketComputer; | import dan200.computercraft.shared.pocket.items.ItemPocketComputer; | ||||||
| import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; | import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; | ||||||
| import dan200.computercraft.shared.util.Config; | import dan200.computercraft.shared.util.Config; | ||||||
| @@ -115,9 +116,11 @@ public final class ComputerCraftProxyClient implements ClientModInitializer | |||||||
|     // My IDE doesn't think so, but we do actually need these generics. |     // My IDE doesn't think so, but we do actually need these generics. | ||||||
|     private static void registerContainers() |     private static void registerContainers() | ||||||
|     { |     { | ||||||
|         ScreenRegistry.<ContainerComputer, GuiComputer<ContainerComputer>>register( ComputerCraftRegistry.ModContainers.COMPUTER, GuiComputer::create ); |         ScreenRegistry.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register( ComputerCraftRegistry.ModContainers.COMPUTER, GuiComputer::create ); | ||||||
|         ScreenRegistry.<ContainerPocketComputer, GuiComputer<ContainerPocketComputer>>register( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER, |         ScreenRegistry.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER, | ||||||
|             GuiComputer::createPocket ); |             GuiComputer::createPocket ); | ||||||
|  |         ScreenRegistry.<ContainerComputerBase, NoTermComputerScreen<ContainerComputerBase>>register( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER_NO_TERM, | ||||||
|  |             NoTermComputerScreen::new ); | ||||||
|         ScreenRegistry.<ContainerTurtle, GuiTurtle>register( ComputerCraftRegistry.ModContainers.TURTLE, GuiTurtle::new ); |         ScreenRegistry.<ContainerTurtle, GuiTurtle>register( ComputerCraftRegistry.ModContainers.TURTLE, GuiTurtle::new ); | ||||||
|  |  | ||||||
|         ScreenRegistry.<ContainerPrinter, GuiPrinter>register( ComputerCraftRegistry.ModContainers.PRINTER, GuiPrinter::new ); |         ScreenRegistry.<ContainerPrinter, GuiPrinter>register( ComputerCraftRegistry.ModContainers.PRINTER, GuiPrinter::new ); | ||||||
|   | |||||||
| @@ -40,7 +40,7 @@ import java.util.List; | |||||||
| import java.util.Random; | import java.util.Random; | ||||||
|  |  | ||||||
| public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle> | public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle> | ||||||
| { //FIXME: more rendering puzzles. | { | ||||||
|     private static final ModelIdentifier NORMAL_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_normal", "inventory" ); |     private static final ModelIdentifier NORMAL_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_normal", "inventory" ); | ||||||
|     private static final ModelIdentifier ADVANCED_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_advanced", "inventory" ); |     private static final ModelIdentifier ADVANCED_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_advanced", "inventory" ); | ||||||
|     private static final ModelIdentifier COLOUR_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_colour", "inventory" ); |     private static final ModelIdentifier COLOUR_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_colour", "inventory" ); | ||||||
| @@ -48,13 +48,13 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle> | |||||||
|  |  | ||||||
|     private final Random random = new Random( 0 ); |     private final Random random = new Random( 0 ); | ||||||
|  |  | ||||||
|     BlockEntityRenderDispatcher dispatcher; |     BlockEntityRenderDispatcher renderer; | ||||||
|  |  | ||||||
|     public TileEntityTurtleRenderer( BlockEntityRendererFactory.Context context ) |     public TileEntityTurtleRenderer( BlockEntityRendererFactory.Context context ) | ||||||
|     { |     { | ||||||
|         dispatcher = context.getRenderDispatcher(); |         renderer = context.getRenderDispatcher(); | ||||||
|     } |     } | ||||||
|      |  | ||||||
|     public static ModelIdentifier getTurtleModel( ComputerFamily family, boolean coloured ) |     public static ModelIdentifier getTurtleModel( ComputerFamily family, boolean coloured ) | ||||||
|     { |     { | ||||||
|         switch( family ) |         switch( family ) | ||||||
| @@ -80,6 +80,118 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle> | |||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void render( @Nonnull TileTurtle turtle, float partialTicks, @Nonnull MatrixStack transform, @Nonnull VertexConsumerProvider buffers, | ||||||
|  |                         int lightmapCoord, int overlayLight ) | ||||||
|  |     { | ||||||
|  |         // Render the label | ||||||
|  |         String label = turtle.createProxy() | ||||||
|  |             .getLabel(); | ||||||
|  |         HitResult hit = renderer.crosshairTarget; | ||||||
|  |         if( label != null && hit.getType() == HitResult.Type.BLOCK && turtle.getPos() | ||||||
|  |             .equals( ((BlockHitResult) hit).getBlockPos() ) ) | ||||||
|  |         { | ||||||
|  |             MinecraftClient mc = MinecraftClient.getInstance(); | ||||||
|  |             TextRenderer font = mc.textRenderer; | ||||||
|  |  | ||||||
|  |             transform.push(); | ||||||
|  |             transform.translate( 0.5, 1.2, 0.5 ); | ||||||
|  |             transform.multiply( mc.getEntityRenderDispatcher() | ||||||
|  |                 .getRotation() ); | ||||||
|  |             transform.scale( -0.025f, -0.025f, 0.025f ); | ||||||
|  |  | ||||||
|  |             Matrix4f matrix = transform.peek() | ||||||
|  |                 .getModel(); | ||||||
|  |             int opacity = (int) (mc.options.getTextBackgroundOpacity( 0.25f ) * 255) << 24; | ||||||
|  |             float width = -font.getWidth( label ) / 2.0f; | ||||||
|  |             font.draw( label, width, (float) 0, 0x20ffffff, false, matrix, buffers, true, opacity, lightmapCoord ); | ||||||
|  |             font.draw( label, width, (float) 0, 0xffffffff, false, matrix, buffers, false, 0, lightmapCoord ); | ||||||
|  |  | ||||||
|  |             transform.pop(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         transform.push(); | ||||||
|  |  | ||||||
|  |         // Setup the transform. | ||||||
|  |         Vec3d offset = turtle.getRenderOffset( partialTicks ); | ||||||
|  |         float yaw = turtle.getRenderYaw( partialTicks ); | ||||||
|  |         transform.translate( offset.x, offset.y, offset.z ); | ||||||
|  |  | ||||||
|  |         transform.translate( 0.5f, 0.5f, 0.5f ); | ||||||
|  |         transform.multiply( Vec3f.POSITIVE_Y.getDegreesQuaternion( 180.0f - yaw ) ); | ||||||
|  |         if( label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )) ) | ||||||
|  |         { | ||||||
|  |             // Flip the model | ||||||
|  |             transform.scale( 1.0f, -1.0f, 1.0f ); | ||||||
|  |         } | ||||||
|  |         transform.translate( -0.5f, -0.5f, -0.5f ); | ||||||
|  |  | ||||||
|  |         // Render the turtle | ||||||
|  |         int colour = turtle.getColour(); | ||||||
|  |         ComputerFamily family = turtle.getFamily(); | ||||||
|  |         Identifier overlay = turtle.getOverlay(); | ||||||
|  |  | ||||||
|  |         VertexConsumer buffer = buffers.getBuffer( TexturedRenderLayers.getEntityTranslucentCull() ); | ||||||
|  |         renderModel( transform, buffer, lightmapCoord, overlayLight, getTurtleModel( family, colour != -1 ), colour == -1 ? null : new int[] { colour } ); | ||||||
|  |  | ||||||
|  |         // Render the overlay | ||||||
|  |         ModelIdentifier overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS ); | ||||||
|  |         if( overlayModel != null ) | ||||||
|  |         { | ||||||
|  |             renderModel( transform, buffer, lightmapCoord, overlayLight, overlayModel, null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Render the upgrades | ||||||
|  |         renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.LEFT, partialTicks ); | ||||||
|  |         renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.RIGHT, partialTicks ); | ||||||
|  |  | ||||||
|  |         transform.pop(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void renderUpgrade( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, TileTurtle turtle, | ||||||
|  |                                       TurtleSide side, float f ) | ||||||
|  |     { | ||||||
|  |         ITurtleUpgrade upgrade = turtle.getUpgrade( side ); | ||||||
|  |         if( upgrade == null ) | ||||||
|  |         { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         transform.push(); | ||||||
|  |  | ||||||
|  |         float toolAngle = turtle.getToolRenderAngle( side, f ); | ||||||
|  |         transform.translate( 0.0f, 0.5f, 0.5f ); | ||||||
|  |         transform.multiply( Vec3f.NEGATIVE_X.getDegreesQuaternion( toolAngle ) ); | ||||||
|  |         transform.translate( 0.0f, -0.5f, -0.5f ); | ||||||
|  |  | ||||||
|  |         TransformedModel model = upgrade.getModel( turtle.getAccess(), side ); | ||||||
|  |         model.push( transform ); | ||||||
|  |         renderModel( transform, renderer, lightmapCoord, overlayLight, model.getModel(), null ); | ||||||
|  |         transform.pop(); | ||||||
|  |  | ||||||
|  |         transform.pop(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, | ||||||
|  |                                     ModelIdentifier modelLocation, int[] tints ) | ||||||
|  |     { | ||||||
|  |         BakedModelManager modelManager = MinecraftClient.getInstance() | ||||||
|  |             .getItemRenderer() | ||||||
|  |             .getModels() | ||||||
|  |             .getModelManager(); | ||||||
|  |         renderModel( transform, renderer, lightmapCoord, overlayLight, modelManager.getModel( modelLocation ), tints ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model, | ||||||
|  |                                     int[] tints ) | ||||||
|  |     { | ||||||
|  |         random.setSeed( 0 ); | ||||||
|  |         renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, null, random ), tints ); | ||||||
|  |         for( Direction facing : DirectionUtil.FACINGS ) | ||||||
|  |         { | ||||||
|  |             renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, facing, random ), tints ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private static void renderQuads( @Nonnull MatrixStack transform, @Nonnull VertexConsumer buffer, int lightmapCoord, int overlayLight, |     private static void renderQuads( @Nonnull MatrixStack transform, @Nonnull VertexConsumer buffer, int lightmapCoord, int overlayLight, | ||||||
|                                      List<BakedQuad> quads, int[] tints ) |                                      List<BakedQuad> quads, int[] tints ) | ||||||
|     { |     { | ||||||
| @@ -111,117 +223,4 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle> | |||||||
|                 true ); |                 true ); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void render( @Nonnull TileTurtle turtle, float partialTicks, @Nonnull MatrixStack transform, @Nonnull VertexConsumerProvider renderer, |  | ||||||
|                         int lightmapCoord, int overlayLight ) |  | ||||||
|     { |  | ||||||
|         // Render the label |  | ||||||
|         String label = turtle.createProxy() |  | ||||||
|             .getLabel(); |  | ||||||
|         MinecraftClient mc = MinecraftClient.getInstance(); |  | ||||||
|         HitResult hit = mc.crosshairTarget; |  | ||||||
|         if( label != null && hit.getType() == HitResult.Type.BLOCK && turtle.getPos() |  | ||||||
|             .equals( ((BlockHitResult) hit).getBlockPos() ) ) |  | ||||||
|         { |  | ||||||
|             TextRenderer font = mc.textRenderer; |  | ||||||
|  |  | ||||||
|             transform.push(); |  | ||||||
|             transform.translate( 0.5, 1.2, 0.5 ); |  | ||||||
|             transform.multiply( mc.getEntityRenderDispatcher() |  | ||||||
|                 .getRotation() ); |  | ||||||
|             transform.scale( -0.025f, -0.025f, 0.025f ); |  | ||||||
|  |  | ||||||
|             Matrix4f matrix = transform.peek() |  | ||||||
|                 .getModel(); |  | ||||||
|             int opacity = (int) (mc.options.getTextBackgroundOpacity( 0.25f ) * 255) << 24; |  | ||||||
|             float width = -font.getWidth( label ) / 2.0f; |  | ||||||
|             font.draw( label, width, (float) 0, 0x20ffffff, false, matrix, renderer, true, opacity, lightmapCoord ); |  | ||||||
|             font.draw( label, width, (float) 0, 0xffffffff, false, matrix, renderer, false, 0, lightmapCoord ); |  | ||||||
|  |  | ||||||
|             transform.pop(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         transform.push(); |  | ||||||
|  |  | ||||||
|         // Setup the transform. |  | ||||||
|         Vec3d offset = turtle.getRenderOffset( partialTicks ); |  | ||||||
|         float yaw = turtle.getRenderYaw( partialTicks ); |  | ||||||
|         transform.translate( offset.x, offset.y, offset.z ); |  | ||||||
|  |  | ||||||
|         transform.translate( 0.5f, 0.5f, 0.5f ); |  | ||||||
|         transform.multiply( Vec3f.POSITIVE_Y.getDegreesQuaternion( 180.0f - yaw ) ); |  | ||||||
|         if( label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )) ) |  | ||||||
|         { |  | ||||||
|             // Flip the model |  | ||||||
|             transform.scale( 1.0f, -1.0f, 1.0f ); |  | ||||||
|         } |  | ||||||
|         transform.translate( -0.5f, -0.5f, -0.5f ); |  | ||||||
|  |  | ||||||
|         // Render the turtle |  | ||||||
|         int colour = turtle.getColour(); |  | ||||||
|         ComputerFamily family = turtle.getFamily(); |  | ||||||
|         Identifier overlay = turtle.getOverlay(); |  | ||||||
|  |  | ||||||
|         VertexConsumer buffer = renderer.getBuffer( TexturedRenderLayers.getEntityTranslucentCull() ); |  | ||||||
|         renderModel( transform, buffer, lightmapCoord, overlayLight, getTurtleModel( family, colour != -1 ), colour == -1 ? null : new int[] { colour } ); |  | ||||||
|  |  | ||||||
|         // Render the overlay |  | ||||||
|         ModelIdentifier overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS ); |  | ||||||
|         if( overlayModel != null ) |  | ||||||
|         { |  | ||||||
|             renderModel( transform, buffer, lightmapCoord, overlayLight, overlayModel, null ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Render the upgrades |  | ||||||
|         renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.LEFT, partialTicks ); |  | ||||||
|         renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.RIGHT, partialTicks ); |  | ||||||
|  |  | ||||||
|         transform.pop(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static void renderUpgrade( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, TileTurtle turtle, |  | ||||||
|                                       TurtleSide side, float f ) |  | ||||||
|     { |  | ||||||
|         ITurtleUpgrade upgrade = turtle.getUpgrade( side ); |  | ||||||
|         if( upgrade == null ) |  | ||||||
|         { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         transform.push(); |  | ||||||
|  |  | ||||||
|         float toolAngle = turtle.getToolRenderAngle( side, f ); |  | ||||||
|         transform.translate( 0.0f, 0.5f, 0.5f ); |  | ||||||
|         transform.multiply( Vec3f.NEGATIVE_X.getDegreesQuaternion( toolAngle ) ); |  | ||||||
|         transform.translate( 0.0f, -0.5f, -0.5f ); |  | ||||||
|  |  | ||||||
|         TransformedModel model = upgrade.getModel( turtle.getAccess(), side ); |  | ||||||
|         model.push( transform ); |  | ||||||
|         TileEntityTurtleRenderer.renderModel( transform, renderer, lightmapCoord, overlayLight, model.getModel(), null ); |  | ||||||
|         transform.pop(); |  | ||||||
|  |  | ||||||
|         transform.pop(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, |  | ||||||
|                                     ModelIdentifier modelLocation, int[] tints ) |  | ||||||
|     { |  | ||||||
|         BakedModelManager modelManager = MinecraftClient.getInstance() |  | ||||||
|             .getItemRenderer() |  | ||||||
|             .getModels() |  | ||||||
|             .getModelManager(); |  | ||||||
|         renderModel( transform, renderer, lightmapCoord, overlayLight, modelManager.getModel( modelLocation ), tints ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model, |  | ||||||
|                                     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 ) |  | ||||||
|         { |  | ||||||
|             renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, facing, random ), tints ); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -293,9 +293,8 @@ class MountWrapper | |||||||
|  |  | ||||||
|     private FileSystemException localExceptionOf( @Nullable String localPath, @Nonnull IOException e ) |     private FileSystemException localExceptionOf( @Nullable String localPath, @Nonnull IOException e ) | ||||||
|     { |     { | ||||||
|         if( !location.isEmpty() && e instanceof FileOperationException ) |         if( !location.isEmpty() && e instanceof FileOperationException ex ) | ||||||
|         { |         { | ||||||
|             FileOperationException ex = (FileOperationException) e; |  | ||||||
|             if( ex.getFilename() != null ) return localExceptionOf( ex.getFilename(), ex.getMessage() ); |             if( ex.getFilename() != null ) return localExceptionOf( ex.getFilename(), ex.getMessage() ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,10 +13,7 @@ import dan200.computercraft.ComputerCraft; | |||||||
| import dan200.computercraft.api.filesystem.IMount; | import dan200.computercraft.api.filesystem.IMount; | ||||||
| import dan200.computercraft.core.apis.handles.ArrayByteChannel; | import dan200.computercraft.core.apis.handles.ArrayByteChannel; | ||||||
| import dan200.computercraft.shared.util.IoUtil; | import dan200.computercraft.shared.util.IoUtil; | ||||||
| import net.minecraft.resource.ReloadableResourceManager; | import net.minecraft.resource.*; | ||||||
| import net.minecraft.resource.Resource; |  | ||||||
| import net.minecraft.resource.ResourceManager; |  | ||||||
| import net.minecraft.resource.ResourceReloader; |  | ||||||
| import net.minecraft.resource.ResourceReloader.Synchronizer; | import net.minecraft.resource.ResourceReloader.Synchronizer; | ||||||
| import net.minecraft.util.Identifier; | import net.minecraft.util.Identifier; | ||||||
| import net.minecraft.util.InvalidIdentifierException; | import net.minecraft.util.InvalidIdentifierException; | ||||||
| @@ -114,6 +111,7 @@ public final class ResourceMount implements IMount | |||||||
|             existingNamespace = file.getNamespace(); |             existingNamespace = file.getNamespace(); | ||||||
|  |  | ||||||
|             if( !file.getNamespace().equals( namespace ) ) continue; |             if( !file.getNamespace().equals( namespace ) ) continue; | ||||||
|  |             if( !FileSystem.contains( subPath, file.getPath() ) ) continue; // Some packs seem to include the parent? | ||||||
|  |  | ||||||
|             String localPath = FileSystem.toLocal( file.getPath(), subPath ); |             String localPath = FileSystem.toLocal( file.getPath(), subPath ); | ||||||
|             create( newRoot, localPath ); |             create( newRoot, localPath ); | ||||||
| @@ -300,7 +298,7 @@ public final class ResourceMount implements IMount | |||||||
|      * While people should really be keeping a permanent reference to this, some people construct it every |      * While people should really be keeping a permanent reference to this, some people construct it every | ||||||
|      * method call, so let's make this as small as possible. |      * method call, so let's make this as small as possible. | ||||||
|      */ |      */ | ||||||
|     static class Listener implements ResourceReloader |     static class Listener implements SynchronousResourceReloader | ||||||
|     { |     { | ||||||
|         private static final Listener INSTANCE = new Listener(); |         private static final Listener INSTANCE = new Listener(); | ||||||
|  |  | ||||||
| @@ -308,19 +306,9 @@ public final class ResourceMount implements IMount | |||||||
|         private final Set<ReloadableResourceManager> managers = Collections.newSetFromMap( new WeakHashMap<>() ); |         private final Set<ReloadableResourceManager> managers = Collections.newSetFromMap( new WeakHashMap<>() ); | ||||||
|  |  | ||||||
|         @Override |         @Override | ||||||
|         public CompletableFuture<Void> reload( Synchronizer synchronizer, ResourceManager manager, Profiler prepareProfiler, Profiler applyProfiler, Executor prepareExecutor, Executor applyExecutor ) |         public void reload( @Nonnull ResourceManager manager ) | ||||||
|         { |         { | ||||||
|             return CompletableFuture.runAsync( () -> { |             for( ResourceMount mount : mounts ) mount.load(); | ||||||
|                 prepareProfiler.push( "Mount reloading" ); |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     for( ResourceMount mount : mounts ) mount.load(); |  | ||||||
|                 } |  | ||||||
|                 finally |  | ||||||
|                 { |  | ||||||
|                     prepareProfiler.pop(); |  | ||||||
|                 } |  | ||||||
|             }, prepareExecutor ); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         synchronized void add( ReloadableResourceManager manager, ResourceMount mount ) |         synchronized void add( ReloadableResourceManager manager, ResourceMount mount ) | ||||||
|   | |||||||
| @@ -97,7 +97,7 @@ public class CobaltLuaMachine implements ILuaMachine | |||||||
|         globals.load( state, new CoroutineLib() ); |         globals.load( state, new CoroutineLib() ); | ||||||
|         globals.load( state, new Bit32Lib() ); |         globals.load( state, new Bit32Lib() ); | ||||||
|         globals.load( state, new Utf8Lib() ); |         globals.load( state, new Utf8Lib() ); | ||||||
|         if( ComputerCraft.debugEnable ) globals.load( state, new DebugLib() ); |         globals.load( state, new DebugLib() ); | ||||||
|  |  | ||||||
|         // Remove globals we don't want to expose |         // Remove globals we don't want to expose | ||||||
|         globals.rawset( "collectgarbage", Constants.NIL ); |         globals.rawset( "collectgarbage", Constants.NIL ); | ||||||
| @@ -260,14 +260,12 @@ public class CobaltLuaMachine implements ILuaMachine | |||||||
|         if( object instanceof Number ) return valueOf( ((Number) object).doubleValue() ); |         if( object instanceof Number ) return valueOf( ((Number) object).doubleValue() ); | ||||||
|         if( object instanceof Boolean ) return valueOf( (Boolean) object ); |         if( object instanceof Boolean ) return valueOf( (Boolean) object ); | ||||||
|         if( object instanceof String ) return valueOf( object.toString() ); |         if( object instanceof String ) return valueOf( object.toString() ); | ||||||
|         if( object instanceof byte[] ) |         if( object instanceof byte[] b ) | ||||||
|         { |         { | ||||||
|             byte[] b = (byte[]) object; |  | ||||||
|             return valueOf( Arrays.copyOf( b, b.length ) ); |             return valueOf( Arrays.copyOf( b, b.length ) ); | ||||||
|         } |         } | ||||||
|         if( object instanceof ByteBuffer ) |         if( object instanceof ByteBuffer b ) | ||||||
|         { |         { | ||||||
|             ByteBuffer b = (ByteBuffer) object; |  | ||||||
|             byte[] bytes = new byte[b.remaining()]; |             byte[] bytes = new byte[b.remaining()]; | ||||||
|             b.get( bytes ); |             b.get( bytes ); | ||||||
|             return valueOf( bytes ); |             return valueOf( bytes ); | ||||||
| @@ -304,9 +302,8 @@ public class CobaltLuaMachine implements ILuaMachine | |||||||
|             return table; |             return table; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if( object instanceof Collection ) |         if( object instanceof Collection<?> objects ) | ||||||
|         { |         { | ||||||
|             Collection<?> objects = (Collection<?>) object; |  | ||||||
|             LuaTable table = new LuaTable( objects.size(), 0 ); |             LuaTable table = new LuaTable( objects.size(), 0 ); | ||||||
|             values.put( object, table ); |             values.put( object, table ); | ||||||
|             int i = 0; |             int i = 0; | ||||||
| @@ -314,9 +311,8 @@ public class CobaltLuaMachine implements ILuaMachine | |||||||
|             return table; |             return table; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if( object instanceof Object[] ) |         if( object instanceof Object[] objects ) | ||||||
|         { |         { | ||||||
|             Object[] objects = (Object[]) object; |  | ||||||
|             LuaTable table = new LuaTable( objects.length, 0 ); |             LuaTable table = new LuaTable( objects.length, 0 ); | ||||||
|             values.put( object, table ); |             values.put( object, table ); | ||||||
|             for( int i = 0; i < objects.length; i++ ) table.rawset( i + 1, toValue( objects[i], values ) ); |             for( int i = 0; i < objects.length; i++ ) table.rawset( i + 1, toValue( objects[i], values ) ); | ||||||
| @@ -367,6 +363,7 @@ public class CobaltLuaMachine implements ILuaMachine | |||||||
|             case Constants.TSTRING: |             case Constants.TSTRING: | ||||||
|                 return value.toString(); |                 return value.toString(); | ||||||
|             case Constants.TTABLE: |             case Constants.TTABLE: | ||||||
|  |             { | ||||||
|                 // Table: |                 // Table: | ||||||
|                 // Start remembering stuff |                 // Start remembering stuff | ||||||
|                 if( objects == null ) |                 if( objects == null ) | ||||||
| @@ -408,6 +405,7 @@ public class CobaltLuaMachine implements ILuaMachine | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 return table; |                 return table; | ||||||
|  |             } | ||||||
|             default: |             default: | ||||||
|                 return null; |                 return null; | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -9,6 +9,8 @@ import dan200.computercraft.ComputerCraft; | |||||||
| import dan200.computercraft.api.lua.ILuaContext; | import dan200.computercraft.api.lua.ILuaContext; | ||||||
| import dan200.computercraft.api.lua.ILuaTask; | import dan200.computercraft.api.lua.ILuaTask; | ||||||
| import dan200.computercraft.api.lua.LuaException; | import dan200.computercraft.api.lua.LuaException; | ||||||
|  | import dan200.computercraft.api.lua.MethodResult; | ||||||
|  | import dan200.computercraft.core.asm.TaskCallback; | ||||||
| import dan200.computercraft.core.computer.Computer; | import dan200.computercraft.core.computer.Computer; | ||||||
| import dan200.computercraft.core.computer.MainThread; | import dan200.computercraft.core.computer.MainThread; | ||||||
|  |  | ||||||
| @@ -66,4 +68,11 @@ class LuaContext implements ILuaContext | |||||||
|             throw new LuaException( "Task limit exceeded" ); |             throw new LuaException( "Task limit exceeded" ); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Nonnull | ||||||
|  |     @Override | ||||||
|  |     public MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException | ||||||
|  |     { | ||||||
|  |         return TaskCallback.make( this, task ); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -79,6 +79,7 @@ public class TextBuffer | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|     public String toString() |     public String toString() | ||||||
|     { |     { | ||||||
|         return new String( text ); |         return new String( text ); | ||||||
|   | |||||||
| @@ -14,25 +14,24 @@ import net.minecraft.util.math.Direction; | |||||||
| import net.minecraft.world.World; | import net.minecraft.world.World; | ||||||
|  |  | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import java.util.LinkedHashSet; | import java.util.ArrayList; | ||||||
| import java.util.Objects; | import java.util.Objects; | ||||||
| import java.util.Set; |  | ||||||
|  |  | ||||||
| public final class BundledRedstone | public final class BundledRedstone | ||||||
| { | { | ||||||
|     private static final Set<IBundledRedstoneProvider> providers = new LinkedHashSet<>(); |     private static final ArrayList<IBundledRedstoneProvider> providers = new ArrayList<>(); | ||||||
|  |  | ||||||
|     private BundledRedstone() {} |     private BundledRedstone() {} | ||||||
|  |  | ||||||
|     public static synchronized void register( @Nonnull IBundledRedstoneProvider provider ) |     public static synchronized void register( @Nonnull IBundledRedstoneProvider provider ) | ||||||
|     { |     { | ||||||
|         Objects.requireNonNull( provider, "provider cannot be null" ); |         Objects.requireNonNull( provider, "provider cannot be null" ); | ||||||
|         providers.add( provider ); |         if( !providers.contains( provider ) ) providers.add( provider ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static int getDefaultOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) |     public static int getDefaultOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) | ||||||
|     { |     { | ||||||
|         return !world.isInBuildLimit( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1; |         return world.isInBuildLimit( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static int getOutput( World world, BlockPos pos, Direction side ) |     public static int getOutput( World world, BlockPos pos, Direction side ) | ||||||
|   | |||||||
| @@ -13,12 +13,17 @@ import dan200.computercraft.shared.computer.blocks.BlockComputer; | |||||||
| import dan200.computercraft.shared.computer.blocks.TileCommandComputer; | import dan200.computercraft.shared.computer.blocks.TileCommandComputer; | ||||||
| import dan200.computercraft.shared.computer.blocks.TileComputer; | import dan200.computercraft.shared.computer.blocks.TileComputer; | ||||||
| import dan200.computercraft.shared.computer.core.ComputerFamily; | import dan200.computercraft.shared.computer.core.ComputerFamily; | ||||||
| import dan200.computercraft.shared.computer.inventory.ContainerComputer; | import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory; | ||||||
|  | import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; | ||||||
| import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; | import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; | ||||||
| import dan200.computercraft.shared.computer.items.ItemComputer; | import dan200.computercraft.shared.computer.items.ItemComputer; | ||||||
| import dan200.computercraft.shared.media.items.ItemDisk; | import dan200.computercraft.shared.media.items.ItemDisk; | ||||||
| import dan200.computercraft.shared.media.items.ItemPrintout; | import dan200.computercraft.shared.media.items.ItemPrintout; | ||||||
| import dan200.computercraft.shared.media.items.ItemTreasureDisk; | import dan200.computercraft.shared.media.items.ItemTreasureDisk; | ||||||
|  | import dan200.computercraft.shared.network.container.ComputerContainerData; | ||||||
|  | import dan200.computercraft.shared.network.container.ContainerData; | ||||||
|  | import dan200.computercraft.shared.network.container.HeldItemContainerData; | ||||||
|  | import dan200.computercraft.shared.network.container.ViewComputerContainerData; | ||||||
| import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive; | import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive; | ||||||
| import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; | import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; | ||||||
| import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive; | import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive; | ||||||
| @@ -32,7 +37,6 @@ import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; | |||||||
| import dan200.computercraft.shared.peripheral.printer.TilePrinter; | import dan200.computercraft.shared.peripheral.printer.TilePrinter; | ||||||
| import dan200.computercraft.shared.peripheral.speaker.BlockSpeaker; | import dan200.computercraft.shared.peripheral.speaker.BlockSpeaker; | ||||||
| import dan200.computercraft.shared.peripheral.speaker.TileSpeaker; | import dan200.computercraft.shared.peripheral.speaker.TileSpeaker; | ||||||
| import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; |  | ||||||
| import dan200.computercraft.shared.pocket.items.ItemPocketComputer; | import dan200.computercraft.shared.pocket.items.ItemPocketComputer; | ||||||
| import dan200.computercraft.shared.pocket.peripherals.PocketModem; | import dan200.computercraft.shared.pocket.peripherals.PocketModem; | ||||||
| import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; | import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; | ||||||
| @@ -42,10 +46,8 @@ import dan200.computercraft.shared.turtle.core.TurtlePlayer; | |||||||
| import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; | import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; | ||||||
| import dan200.computercraft.shared.turtle.items.ItemTurtle; | import dan200.computercraft.shared.turtle.items.ItemTurtle; | ||||||
| import dan200.computercraft.shared.turtle.upgrades.*; | import dan200.computercraft.shared.turtle.upgrades.*; | ||||||
| //import dan200.computercraft.shared.util.FixedPointTileEntityType; |  | ||||||
| import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; |  | ||||||
| import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder.Factory; |  | ||||||
| import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; | import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; | ||||||
|  | import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; | ||||||
| import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; | import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; | ||||||
| import net.minecraft.block.*; | import net.minecraft.block.*; | ||||||
| import net.minecraft.block.entity.BlockEntity; | import net.minecraft.block.entity.BlockEntity; | ||||||
| @@ -63,10 +65,7 @@ import net.minecraft.util.Identifier; | |||||||
| import net.minecraft.util.math.BlockPos; | import net.minecraft.util.math.BlockPos; | ||||||
| import net.minecraft.util.registry.Registry; | import net.minecraft.util.registry.Registry; | ||||||
|  |  | ||||||
| import java.util.Objects; |  | ||||||
| import java.util.function.BiFunction; | import java.util.function.BiFunction; | ||||||
| import java.util.function.Function; |  | ||||||
| import java.util.function.Supplier; |  | ||||||
|  |  | ||||||
| import static net.minecraft.util.registry.Registry.BLOCK_ENTITY_TYPE; | import static net.minecraft.util.registry.Registry.BLOCK_ENTITY_TYPE; | ||||||
|  |  | ||||||
| @@ -258,24 +257,20 @@ public final class ComputerCraftRegistry | |||||||
|  |  | ||||||
|     public static class ModContainers |     public static class ModContainers | ||||||
|     { |     { | ||||||
|         public static final ScreenHandlerType<ContainerComputer> COMPUTER = registerExtended( "computer", ContainerComputer::new ); |         public static final ScreenHandlerType<ContainerComputerBase> COMPUTER = ContainerData.toType(new Identifier( MOD_ID, "computer" ), ModContainers.COMPUTER, ComputerContainerData::new, ComputerMenuWithoutInventory::new ); | ||||||
|         public static final ScreenHandlerType<ContainerPocketComputer> POCKET_COMPUTER = registerExtended( "pocket_computer", ContainerPocketComputer::new ); |         public static final ScreenHandlerType<ContainerComputerBase> POCKET_COMPUTER = ContainerData.toType( new Identifier( MOD_ID, "pocket_computer" ), ModContainers.POCKET_COMPUTER, ComputerContainerData::new, ComputerMenuWithoutInventory::new ); | ||||||
|         public static final ScreenHandlerType<ContainerTurtle> TURTLE = registerExtended( "turtle", ContainerTurtle::new ); |         public static final ScreenHandlerType<ContainerComputerBase> POCKET_COMPUTER_NO_TERM = ContainerData.toType( new Identifier( MOD_ID, "pocket_computer_no_term" ), ModContainers.POCKET_COMPUTER_NO_TERM, ComputerContainerData::new, ComputerMenuWithoutInventory::new ); | ||||||
|  |         public static final ScreenHandlerType<ContainerTurtle> TURTLE = ContainerData.toType( new Identifier( MOD_ID, "turtle" ), ComputerContainerData::new, ContainerTurtle::new ); | ||||||
|         public static final ScreenHandlerType<ContainerDiskDrive> DISK_DRIVE = registerSimple( "disk_drive", ContainerDiskDrive::new ); |         public static final ScreenHandlerType<ContainerDiskDrive> DISK_DRIVE = registerSimple( "disk_drive", ContainerDiskDrive::new ); | ||||||
|         public static final ScreenHandlerType<ContainerPrinter> PRINTER = registerSimple( "printer", ContainerPrinter::new ); |         public static final ScreenHandlerType<ContainerPrinter> PRINTER = registerSimple( "printer", ContainerPrinter::new ); | ||||||
|         public static final ScreenHandlerType<ContainerHeldItem> PRINTOUT = registerExtended( "printout", ContainerHeldItem::createPrintout ); |         public static final ScreenHandlerType<ContainerHeldItem> PRINTOUT = ContainerData.toType( new Identifier( MOD_ID, "printout" ), HeldItemContainerData::new, ContainerHeldItem::createPrintout ); | ||||||
|         public static final ScreenHandlerType<ContainerViewComputer> VIEW_COMPUTER = registerExtended( "view_computer", ContainerViewComputer::new ); |         public static final ScreenHandlerType<ContainerViewComputer> VIEW_COMPUTER = ContainerData.toType( new Identifier( MOD_ID, "view_computer" ), ViewComputerContainerData::new, ContainerViewComputer::new ); | ||||||
|  |  | ||||||
|         private static <T extends ScreenHandler> ScreenHandlerType<T> registerSimple( String id, |         private static <T extends ScreenHandler> ScreenHandlerType<T> registerSimple( String id, | ||||||
|                                                                                       ScreenHandlerRegistry.SimpleClientHandlerFactory<T> function ) |                                                                                       ScreenHandlerRegistry.SimpleClientHandlerFactory<T> function ) | ||||||
|         { |         { | ||||||
|             return ScreenHandlerRegistry.registerSimple( new Identifier( MOD_ID, id ), function ); |             return ScreenHandlerRegistry.registerSimple( new Identifier( MOD_ID, id ), function ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private static <T extends ScreenHandler> ScreenHandlerType<T> registerExtended( String id, ScreenHandlerRegistry.ExtendedClientHandlerFactory<T> function ) |  | ||||||
|         { |  | ||||||
|             return ScreenHandlerRegistry.registerExtended( new Identifier( MOD_ID, id ), function ); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static final class TurtleUpgrades |     public static final class TurtleUpgrades | ||||||
|   | |||||||
| @@ -245,7 +245,7 @@ public final class CommandComputerCraft | |||||||
|                         @Override |                         @Override | ||||||
|                         public ScreenHandler createMenu( int id, @Nonnull PlayerInventory player, @Nonnull PlayerEntity entity ) |                         public ScreenHandler createMenu( int id, @Nonnull PlayerInventory player, @Nonnull PlayerEntity entity ) | ||||||
|                         { |                         { | ||||||
|                             return new ContainerViewComputer( id, computer ); |                             return new ContainerViewComputer( id, player, computer ); | ||||||
|                         } |                         } | ||||||
|                     } ); |                     } ); | ||||||
|                     return 1; |                     return 1; | ||||||
|   | |||||||
| @@ -56,18 +56,17 @@ public enum UserLevel implements Predicate<ServerCommandSource> | |||||||
|     public boolean test( ServerCommandSource source ) |     public boolean test( ServerCommandSource source ) | ||||||
|     { |     { | ||||||
|         if( this == ANYONE ) return true; |         if( this == ANYONE ) return true; | ||||||
|  |         if( this == OWNER ) return isOwner( source ); | ||||||
|         if( this == OWNER || this == OWNER_OP ) |         if( this == OWNER_OP && isOwner( source ) ) return true; | ||||||
|         { |  | ||||||
|             MinecraftServer server = source.getServer(); |  | ||||||
|             Entity sender = source.getEntity(); |  | ||||||
|             if( server.isSingleplayer() && sender instanceof PlayerEntity && |  | ||||||
|                 ((PlayerEntity) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ) ) |  | ||||||
|             { |  | ||||||
|                 return true; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return source.hasPermissionLevel( toLevel() ); |         return source.hasPermissionLevel( toLevel() ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private static boolean isOwner( ServerCommandSource source ) | ||||||
|  |     { | ||||||
|  |         MinecraftServer server = source.getServer(); | ||||||
|  |         Entity sender = source.getEntity(); | ||||||
|  |         return server.isDedicated() | ||||||
|  |             ? source.getEntity() == null && source.hasPermissionLevel( 4 ) && source.getName().equals( "Server" ) | ||||||
|  |             : sender instanceof PlayerEntity && ((PlayerEntity) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -79,19 +79,4 @@ public class ClientTerminal implements ITerminal | |||||||
|             terminalChanged = true; |             terminalChanged = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void readDescription( NbtCompound nbt ) |  | ||||||
|     { |  | ||||||
|         colour = nbt.getBoolean( "colour" ); |  | ||||||
|         if( nbt.contains( "terminal" ) ) |  | ||||||
|         { |  | ||||||
|         	NbtCompound terminal = nbt.getCompound( "terminal" ); |  | ||||||
|             resizeTerminal( terminal.getInt( "term_width" ), terminal.getInt( "term_height" ) ); |  | ||||||
|             this.terminal.readFromNBT( terminal ); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             deleteTerminal(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -36,11 +36,6 @@ public class ContainerHeldItem extends ScreenHandler | |||||||
|             .copy(); |             .copy(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static ContainerHeldItem createPrintout( int id, PlayerInventory inventory, PacketByteBuf data ) |  | ||||||
|     { |  | ||||||
|         return createPrintout( id, inventory, new HeldItemContainerData( data ) ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static ContainerHeldItem createPrintout( int id, PlayerInventory inventory, HeldItemContainerData data ) |     public static ContainerHeldItem createPrintout( int id, PlayerInventory inventory, HeldItemContainerData data ) | ||||||
|     { |     { | ||||||
|         return new ContainerHeldItem( ComputerCraftRegistry.ModContainers.PRINTOUT, id, inventory.player, data.getHand() ); |         return new ContainerHeldItem( ComputerCraftRegistry.ModContainers.PRINTOUT, id, inventory.player, data.getHand() ); | ||||||
|   | |||||||
| @@ -8,10 +8,11 @@ package dan200.computercraft.shared.computer.blocks; | |||||||
|  |  | ||||||
| import dan200.computercraft.ComputerCraft; | import dan200.computercraft.ComputerCraft; | ||||||
| import dan200.computercraft.core.computer.ComputerSide; | import dan200.computercraft.core.computer.ComputerSide; | ||||||
|  | import dan200.computercraft.shared.ComputerCraftRegistry; | ||||||
| import dan200.computercraft.shared.computer.core.ComputerFamily; | import dan200.computercraft.shared.computer.core.ComputerFamily; | ||||||
| import dan200.computercraft.shared.computer.core.ComputerState; | import dan200.computercraft.shared.computer.core.ComputerState; | ||||||
| import dan200.computercraft.shared.computer.core.ServerComputer; | import dan200.computercraft.shared.computer.core.ServerComputer; | ||||||
| import dan200.computercraft.shared.computer.inventory.ContainerComputer; | import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory; | ||||||
| import net.minecraft.block.BlockState; | import net.minecraft.block.BlockState; | ||||||
| import net.minecraft.block.entity.BlockEntityType; | import net.minecraft.block.entity.BlockEntityType; | ||||||
| import net.minecraft.entity.player.PlayerEntity; | import net.minecraft.entity.player.PlayerEntity; | ||||||
| @@ -104,7 +105,7 @@ public class TileComputer extends TileComputerBase | |||||||
|     @Override |     @Override | ||||||
|     public ScreenHandler createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) |     public ScreenHandler createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) | ||||||
|     { |     { | ||||||
|         return new ContainerComputer( id, this ); |         return new ComputerMenuWithoutInventory( ComputerCraftRegistry.ModContainers.COMPUTER, id, inventory, this::isUsableByPlayer, createServerComputer(), getFamily() ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -17,7 +17,6 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; | |||||||
| import dan200.computercraft.shared.computer.core.ComputerState; | import dan200.computercraft.shared.computer.core.ComputerState; | ||||||
| import dan200.computercraft.shared.computer.core.ServerComputer; | import dan200.computercraft.shared.computer.core.ServerComputer; | ||||||
| import dan200.computercraft.shared.network.container.ComputerContainerData; | import dan200.computercraft.shared.network.container.ComputerContainerData; | ||||||
| import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive; |  | ||||||
| import dan200.computercraft.shared.util.DirectionUtil; | import dan200.computercraft.shared.util.DirectionUtil; | ||||||
| import dan200.computercraft.shared.util.RedstoneUtil; | import dan200.computercraft.shared.util.RedstoneUtil; | ||||||
| import joptsimple.internal.Strings; | import joptsimple.internal.Strings; | ||||||
|   | |||||||
| @@ -12,13 +12,15 @@ import javax.annotation.Nonnull; | |||||||
|  |  | ||||||
| public enum ComputerState implements StringIdentifiable | public enum ComputerState implements StringIdentifiable | ||||||
| { | { | ||||||
|     OFF( "off" ), ON( "on" ), BLINKING( "blinking" ); |     OFF( "off", "" ), ON( "on", "_on" ), BLINKING( "blinking", "_blink" ); | ||||||
|  |  | ||||||
|     private final String name; |     private final String name; | ||||||
|  |     private final String texture; | ||||||
|  |  | ||||||
|     ComputerState( String name ) |     ComputerState( String name, String texture ) | ||||||
|     { |     { | ||||||
|         this.name = name; |         this.name = name; | ||||||
|  |         this.texture = texture; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Nonnull |     @Nonnull | ||||||
| @@ -33,4 +35,10 @@ public enum ComputerState implements StringIdentifiable | |||||||
|     { |     { | ||||||
|         return name; |         return name; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Nonnull | ||||||
|  |     public String getTexture() | ||||||
|  |     { | ||||||
|  |         return texture; | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,13 +6,19 @@ | |||||||
|  |  | ||||||
| package dan200.computercraft.shared.computer.core; | package dan200.computercraft.shared.computer.core; | ||||||
|  |  | ||||||
|  | import dan200.computercraft.shared.computer.upload.FileSlice; | ||||||
|  | import dan200.computercraft.shared.computer.upload.FileUpload; | ||||||
|  | import net.minecraft.server.network.ServerPlayerEntity; | ||||||
|  |  | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * An instance of {@link Container} which provides a computer. You should implement this if you provide custom computers/GUIs to interact with them. |  * An instance of {@link Container} which provides a computer. You should implement this if you provide custom computers/GUIs to interact with them. | ||||||
|  */ |  */ | ||||||
| @FunctionalInterface | //@FunctionalInterface | ||||||
| public interface IContainerComputer | public interface IContainerComputer | ||||||
| { | { | ||||||
|     /** |     /** | ||||||
| @@ -31,8 +37,37 @@ public interface IContainerComputer | |||||||
|      * @return This container's input. |      * @return This container's input. | ||||||
|      */ |      */ | ||||||
|     @Nonnull |     @Nonnull | ||||||
|     default InputState getInput() |     InputState getInput(); | ||||||
|     { |  | ||||||
|         return new InputState( this ); |     /** | ||||||
|     } |      * Start a file upload into this container. | ||||||
|  |      * | ||||||
|  |      * @param uploadId The unique ID of this upload. | ||||||
|  |      * @param files    The files to upload. | ||||||
|  |      */ | ||||||
|  |     void startUpload(@Nonnull UUID uploadId, @Nonnull List<FileUpload> files ); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Append more data to partially uploaded files. | ||||||
|  |      * | ||||||
|  |      * @param uploadId The unique ID of this upload. | ||||||
|  |      * @param slices   Additional parts of file data to upload. | ||||||
|  |      */ | ||||||
|  |     void continueUpload( @Nonnull UUID uploadId, @Nonnull List<FileSlice> slices ); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Finish off an upload. This either writes the uploaded files or | ||||||
|  |      * | ||||||
|  |      * @param uploader The player uploading files. | ||||||
|  |      * @param uploadId The unique ID of this upload. | ||||||
|  |      */ | ||||||
|  |     void finishUpload(@Nonnull ServerPlayerEntity uploader, @Nonnull UUID uploadId ); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Continue an upload. | ||||||
|  |      * | ||||||
|  |      * @param uploader  The player uploading files. | ||||||
|  |      * @param overwrite Whether the files should be overwritten or not. | ||||||
|  |      */ | ||||||
|  |     void confirmUpload( @Nonnull ServerPlayerEntity uploader, boolean overwrite ); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,41 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.shared.computer.inventory; | ||||||
|  |  | ||||||
|  | import dan200.computercraft.shared.computer.core.ComputerFamily; | ||||||
|  | import dan200.computercraft.shared.computer.core.IComputer; | ||||||
|  | import dan200.computercraft.shared.network.container.ComputerContainerData; | ||||||
|  | import dan200.computercraft.shared.util.InvisibleSlot; | ||||||
|  | import net.minecraft.entity.player.PlayerEntity; | ||||||
|  | import net.minecraft.entity.player.PlayerInventory; | ||||||
|  | import net.minecraft.screen.ScreenHandlerType; | ||||||
|  |  | ||||||
|  | import java.util.function.Predicate; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A computer menu which does not have any visible inventory. | ||||||
|  |  * | ||||||
|  |  * This adds invisible versions of the player's hotbars slots, to ensure they're synced to the client when changed. | ||||||
|  |  */ | ||||||
|  | public class ComputerMenuWithoutInventory extends ContainerComputerBase | ||||||
|  | { | ||||||
|  |     public ComputerMenuWithoutInventory(ScreenHandlerType<? extends ContainerComputerBase> type, int id, PlayerInventory player, Predicate<PlayerEntity> canUse, IComputer computer, ComputerFamily family ) | ||||||
|  |     { | ||||||
|  |         super( type, id, canUse, computer, family ); | ||||||
|  |         addSlots( player ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public ComputerMenuWithoutInventory( ScreenHandlerType<? extends ContainerComputerBase> type, int id, PlayerInventory player, ComputerContainerData data ) | ||||||
|  |     { | ||||||
|  |         super( type, id, player, data ); | ||||||
|  |         addSlots( player ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void addSlots( PlayerInventory player ) | ||||||
|  |     { | ||||||
|  |         for( int i = 0; i < 9; i++ ) addSlot( new InvisibleSlot( player, i ) ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,25 +0,0 @@ | |||||||
| /* |  | ||||||
|  * This file is part of ComputerCraft - http://www.computercraft.info |  | ||||||
|  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. |  | ||||||
|  * Send enquiries to dratcliffe@gmail.com |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| package dan200.computercraft.shared.computer.inventory; |  | ||||||
|  |  | ||||||
| import dan200.computercraft.shared.ComputerCraftRegistry; |  | ||||||
| import dan200.computercraft.shared.computer.blocks.TileComputer; |  | ||||||
| import net.minecraft.entity.player.PlayerInventory; |  | ||||||
| import net.minecraft.network.PacketByteBuf; |  | ||||||
|  |  | ||||||
| public class ContainerComputer extends ContainerComputerBase |  | ||||||
| { |  | ||||||
|     public ContainerComputer( int id, TileComputer tile ) |  | ||||||
|     { |  | ||||||
|         super( ComputerCraftRegistry.ModContainers.COMPUTER, id, tile::isUsableByPlayer, tile.createServerComputer(), tile.getFamily() ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public ContainerComputer( int i, PlayerInventory playerInventory, PacketByteBuf packetByteBuf ) |  | ||||||
|     { |  | ||||||
|         super( ComputerCraftRegistry.ModContainers.COMPUTER, i, playerInventory, packetByteBuf ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -7,36 +7,54 @@ | |||||||
| package dan200.computercraft.shared.computer.inventory; | package dan200.computercraft.shared.computer.inventory; | ||||||
|  |  | ||||||
| import dan200.computercraft.ComputerCraft; | import dan200.computercraft.ComputerCraft; | ||||||
|  | import dan200.computercraft.core.filesystem.FileSystem; | ||||||
|  | import dan200.computercraft.core.filesystem.FileSystemException; | ||||||
|  | import dan200.computercraft.core.filesystem.FileSystemWrapper; | ||||||
| import dan200.computercraft.shared.computer.core.*; | import dan200.computercraft.shared.computer.core.*; | ||||||
|  | import dan200.computercraft.shared.computer.upload.FileSlice; | ||||||
|  | import dan200.computercraft.shared.computer.upload.FileUpload; | ||||||
|  | import dan200.computercraft.shared.computer.upload.UploadResult; | ||||||
|  | import dan200.computercraft.shared.network.NetworkHandler; | ||||||
|  | import dan200.computercraft.shared.network.client.UploadResultMessage; | ||||||
| import dan200.computercraft.shared.network.container.ComputerContainerData; | import dan200.computercraft.shared.network.container.ComputerContainerData; | ||||||
| import net.minecraft.entity.player.PlayerEntity; | import net.minecraft.entity.player.PlayerEntity; | ||||||
| import net.minecraft.entity.player.PlayerInventory; | import net.minecraft.entity.player.PlayerInventory; | ||||||
| import net.minecraft.network.PacketByteBuf; | import net.minecraft.network.PacketByteBuf; | ||||||
| import net.minecraft.screen.ScreenHandler; | import net.minecraft.screen.ScreenHandler; | ||||||
| import net.minecraft.screen.ScreenHandlerType; | import net.minecraft.screen.ScreenHandlerType; | ||||||
|  | import net.minecraft.server.network.ServerPlayerEntity; | ||||||
|  | import net.minecraft.text.TranslatableText; | ||||||
|  |  | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||||
| import java.util.Objects; | import java.io.IOException; | ||||||
|  | import java.nio.channels.WritableByteChannel; | ||||||
|  | import java.util.*; | ||||||
|  | import java.util.function.Function; | ||||||
| import java.util.function.Predicate; | import java.util.function.Predicate; | ||||||
|  |  | ||||||
| public class ContainerComputerBase extends ScreenHandler implements IContainerComputer | public abstract class ContainerComputerBase extends ScreenHandler implements IContainerComputer | ||||||
| { | { | ||||||
|  |     private static final String LIST_PREFIX = "\n \u2022 "; | ||||||
|  |  | ||||||
|     private final Predicate<PlayerEntity> canUse; |     private final Predicate<PlayerEntity> canUse; | ||||||
|     private final IComputer computer; |     private final IComputer computer; | ||||||
|     private final ComputerFamily family; |     private final ComputerFamily family; | ||||||
|     private final InputState input = new InputState( this ); |     private final InputState input = new InputState( this ); | ||||||
|  |  | ||||||
|     protected ContainerComputerBase( ScreenHandlerType<? extends ContainerComputerBase> type, int id, PlayerInventory player, PacketByteBuf packetByteBuf ) |     private UUID toUploadId; | ||||||
|  |     private List<FileUpload> toUpload; | ||||||
|  |  | ||||||
|  |     public ContainerComputerBase( ScreenHandlerType<? extends ContainerComputerBase> type, int id, PlayerInventory player, ComputerContainerData data ) | ||||||
|     { |     { | ||||||
|         this( type, |         this( type, | ||||||
|             id, |             id, | ||||||
|             x -> true, |             x -> true, | ||||||
|             getComputer( player, new ComputerContainerData( new PacketByteBuf( packetByteBuf.copy() ) ) ), |             getComputer( player, data ), | ||||||
|             new ComputerContainerData( new PacketByteBuf( packetByteBuf.copy() ) ).getFamily() ); |             data.getFamily() ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     protected ContainerComputerBase( ScreenHandlerType<? extends ContainerComputerBase> type, int id, Predicate<PlayerEntity> canUse, IComputer computer, |     public ContainerComputerBase( ScreenHandlerType<? extends ContainerComputerBase> type, int id, Predicate<PlayerEntity> canUse, IComputer computer, | ||||||
|                                      ComputerFamily family ) |                                      ComputerFamily family ) | ||||||
|     { |     { | ||||||
|         super( type, id ); |         super( type, id ); | ||||||
| @@ -93,4 +111,121 @@ public class ContainerComputerBase extends ScreenHandler implements IContainerCo | |||||||
|     { |     { | ||||||
|         return canUse.test( player ); |         return canUse.test( player ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void startUpload(@Nonnull UUID uuid, @Nonnull List<FileUpload> files ) | ||||||
|  |     { | ||||||
|  |         toUploadId = uuid; | ||||||
|  |         toUpload = files; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void continueUpload( @Nonnull UUID uploadId, @Nonnull List<FileSlice> slices ) | ||||||
|  |     { | ||||||
|  |         if( toUploadId == null || toUpload == null || !toUploadId.equals( uploadId ) ) | ||||||
|  |         { | ||||||
|  |             ComputerCraft.log.warn( "Invalid continueUpload call, skipping." ); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for( FileSlice slice : slices ) slice.apply( toUpload ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void finishUpload(@Nonnull ServerPlayerEntity uploader, @Nonnull UUID uploadId ) | ||||||
|  |     { | ||||||
|  |         if( toUploadId == null || toUpload == null || toUpload.isEmpty() || !toUploadId.equals( uploadId ) ) | ||||||
|  |         { | ||||||
|  |             ComputerCraft.log.warn( "Invalid finishUpload call, skipping." ); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         UploadResultMessage message = finishUpload( false ); | ||||||
|  |         NetworkHandler.sendToPlayer( uploader, message ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void confirmUpload( @Nonnull ServerPlayerEntity uploader, boolean overwrite ) | ||||||
|  |     { | ||||||
|  |         if( toUploadId == null || toUpload == null || toUpload.isEmpty() ) | ||||||
|  |         { | ||||||
|  |             ComputerCraft.log.warn( "Invalid finishUpload call, skipping." ); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         UploadResultMessage message = finishUpload( true ); | ||||||
|  |         NetworkHandler.sendToPlayer( uploader, message ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Nonnull | ||||||
|  |     private UploadResultMessage finishUpload( boolean forceOverwrite ) | ||||||
|  |     { | ||||||
|  |         ServerComputer computer = (ServerComputer) getComputer(); | ||||||
|  |         if( computer == null ) return UploadResultMessage.COMPUTER_OFF; | ||||||
|  |  | ||||||
|  |         FileSystem fs = computer.getComputer().getEnvironment().getFileSystem(); | ||||||
|  |         if( fs == null ) return UploadResultMessage.COMPUTER_OFF; | ||||||
|  |  | ||||||
|  |         for( FileUpload upload : toUpload ) | ||||||
|  |         { | ||||||
|  |             if( !upload.checksumMatches() ) | ||||||
|  |             { | ||||||
|  |                 ComputerCraft.log.warn( "Checksum failed to match for {}.", upload.getName() ); | ||||||
|  |                 return new UploadResultMessage( UploadResult.ERROR, new TranslatableText( "gui.computercraft.upload.failed.corrupted" ) ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         try | ||||||
|  |         { | ||||||
|  |             List<String> overwrite = new ArrayList<>(); | ||||||
|  |             List<FileUpload> files = toUpload; | ||||||
|  |             toUpload = null; | ||||||
|  |             for( FileUpload upload : files ) | ||||||
|  |             { | ||||||
|  |                 if( !fs.exists( upload.getName() ) ) continue; | ||||||
|  |                 if( fs.isDir( upload.getName() ) ) | ||||||
|  |                 { | ||||||
|  |                     return new UploadResultMessage( | ||||||
|  |                         UploadResult.ERROR, | ||||||
|  |                         new TranslatableText( "gui.computercraft.upload.failed.overwrite_dir", upload.getName() ) | ||||||
|  |                     ); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 overwrite.add( upload.getName() ); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if( !overwrite.isEmpty() && !forceOverwrite ) | ||||||
|  |             { | ||||||
|  |                 StringJoiner joiner = new StringJoiner( LIST_PREFIX, LIST_PREFIX, "" ); | ||||||
|  |                 for( String value : overwrite ) joiner.add( value ); | ||||||
|  |                 toUpload = files; | ||||||
|  |                 return new UploadResultMessage( | ||||||
|  |                     UploadResult.CONFIRM_OVERWRITE, | ||||||
|  |                     new TranslatableText( "gui.computercraft.upload.overwrite.detail", joiner.toString() ) | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             long availableSpace = fs.getFreeSpace( "/" ); | ||||||
|  |             long neededSpace = 0; | ||||||
|  |             for( FileUpload upload : files ) neededSpace += Math.max( 512, upload.getBytes().remaining() ); | ||||||
|  |             if( neededSpace > availableSpace ) return UploadResultMessage.OUT_OF_SPACE; | ||||||
|  |  | ||||||
|  |             for( FileUpload file : files ) | ||||||
|  |             { | ||||||
|  |                 try( FileSystemWrapper<WritableByteChannel> channel = fs.openForWrite( file.getName(), false, Function.identity() ) ) | ||||||
|  |                 { | ||||||
|  |                     channel.get().write( file.getBytes() ); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return new UploadResultMessage( | ||||||
|  |                 UploadResult.SUCCESS, new TranslatableText( "gui.computercraft.upload.success.msg", files.size() ) | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         catch( FileSystemException | IOException e ) | ||||||
|  |         { | ||||||
|  |             ComputerCraft.log.error( "Error uploading files", e ); | ||||||
|  |             return new UploadResultMessage( UploadResult.ERROR, new TranslatableText( "gui.computercraft.upload.failed.generic", e.getMessage() ) ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -18,21 +18,20 @@ import net.minecraft.network.PacketByteBuf; | |||||||
|  |  | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
|  |  | ||||||
| public class ContainerViewComputer extends ContainerComputerBase | public class ContainerViewComputer extends ComputerMenuWithoutInventory | ||||||
| { | { | ||||||
|     private final int width; |     private final int width; | ||||||
|     private final int height; |     private final int height; | ||||||
|  |  | ||||||
|     public ContainerViewComputer( int id, ServerComputer computer ) |     public ContainerViewComputer( int id, PlayerInventory player, ServerComputer computer ) | ||||||
|     { |     { | ||||||
|         super( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, id, player -> canInteractWith( computer, player ), computer, computer.getFamily() ); |         super( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, id, player, p -> canInteractWith( computer, p ), computer, computer.getFamily() ); | ||||||
|         width = height = 0; |         width = height = 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public ContainerViewComputer( int id, PlayerInventory player, PacketByteBuf packetByteBuf ) |     public ContainerViewComputer( int id, PlayerInventory player, ViewComputerContainerData data ) | ||||||
|     { |     { | ||||||
|         super( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, id, player, packetByteBuf ); |         super( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, id, player, data ); | ||||||
|         ViewComputerContainerData data = new ViewComputerContainerData( new PacketByteBuf( packetByteBuf.copy() ) ); |  | ||||||
|         width = data.getWidth(); |         width = data.getWidth(); | ||||||
|         height = data.getHeight(); |         height = data.getHeight(); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -0,0 +1,63 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.shared.computer.upload; | ||||||
|  |  | ||||||
|  | import dan200.computercraft.ComputerCraft; | ||||||
|  |  | ||||||
|  | import java.nio.ByteBuffer; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | public class FileSlice | ||||||
|  | { | ||||||
|  |     private final int fileId; | ||||||
|  |     private final int offset; | ||||||
|  |     private final ByteBuffer bytes; | ||||||
|  |  | ||||||
|  |     public FileSlice( int fileId, int offset, ByteBuffer bytes ) | ||||||
|  |     { | ||||||
|  |         this.fileId = fileId; | ||||||
|  |         this.offset = offset; | ||||||
|  |         this.bytes = bytes; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public int getFileId() | ||||||
|  |     { | ||||||
|  |         return fileId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public int getOffset() | ||||||
|  |     { | ||||||
|  |         return offset; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public ByteBuffer getBytes() | ||||||
|  |     { | ||||||
|  |         return bytes; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void apply( List<FileUpload> files ) | ||||||
|  |     { | ||||||
|  |         if( fileId < 0 || fileId >= files.size() ) | ||||||
|  |         { | ||||||
|  |             ComputerCraft.log.warn( "File ID is out-of-bounds (0 <= {} < {})", fileId, files.size() ); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         ByteBuffer file = files.get( fileId ).getBytes(); | ||||||
|  |         if( offset < 0 || offset + bytes.remaining() > file.capacity() ) | ||||||
|  |         { | ||||||
|  |             ComputerCraft.log.warn( "File offset is out-of-bounds (0 <= {} <= {})", offset, file.capacity() - offset ); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         bytes.rewind(); | ||||||
|  |         file.position( offset ); | ||||||
|  |         file.put( bytes ); | ||||||
|  |         file.rewind(); | ||||||
|  |  | ||||||
|  |         if( bytes.remaining() != 0 ) throw new IllegalStateException( "Should have read the whole buffer" ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,80 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.shared.computer.upload; | ||||||
|  |  | ||||||
|  | import dan200.computercraft.ComputerCraft; | ||||||
|  |  | ||||||
|  | import javax.annotation.Nonnull; | ||||||
|  | import javax.annotation.Nullable; | ||||||
|  | import java.nio.ByteBuffer; | ||||||
|  | import java.security.MessageDigest; | ||||||
|  | import java.security.NoSuchAlgorithmException; | ||||||
|  | import java.util.Arrays; | ||||||
|  |  | ||||||
|  | public class FileUpload | ||||||
|  | { | ||||||
|  |     public static final int CHECKSUM_LENGTH = 32; | ||||||
|  |  | ||||||
|  |     private final String name; | ||||||
|  |     private final int length; | ||||||
|  |     private final ByteBuffer bytes; | ||||||
|  |     private final byte[] checksum; | ||||||
|  |  | ||||||
|  |     public FileUpload( String name, ByteBuffer bytes, byte[] checksum ) | ||||||
|  |     { | ||||||
|  |         this.name = name; | ||||||
|  |         this.bytes = bytes; | ||||||
|  |         length = bytes.remaining(); | ||||||
|  |         this.checksum = checksum; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Nonnull | ||||||
|  |     public String getName() | ||||||
|  |     { | ||||||
|  |         return name; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Nonnull | ||||||
|  |     public ByteBuffer getBytes() | ||||||
|  |     { | ||||||
|  |         return bytes; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public int getLength() | ||||||
|  |     { | ||||||
|  |         return length; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Nonnull | ||||||
|  |     public byte[] getChecksum() | ||||||
|  |     { | ||||||
|  |         return checksum; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public boolean checksumMatches() | ||||||
|  |     { | ||||||
|  |         // This is meant to be a checksum. Doesn't need to be cryptographically secure, hence non constant time. | ||||||
|  |         byte[] digest = getDigest( bytes ); | ||||||
|  |         return digest != null && Arrays.equals( checksum, digest ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Nullable | ||||||
|  |     public static byte[] getDigest( ByteBuffer bytes ) | ||||||
|  |     { | ||||||
|  |         try | ||||||
|  |         { | ||||||
|  |             bytes.rewind(); | ||||||
|  |             MessageDigest digest = MessageDigest.getInstance( "SHA-256" ); | ||||||
|  |             digest.update( bytes ); | ||||||
|  |             return digest.digest(); | ||||||
|  |         } | ||||||
|  |         catch( NoSuchAlgorithmException e ) | ||||||
|  |         { | ||||||
|  |             ComputerCraft.log.warn( "Failed to compute digest ({})", e.toString() ); | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,25 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.shared.computer.upload; | ||||||
|  |  | ||||||
|  | import net.minecraft.text.Text; | ||||||
|  | import net.minecraft.text.TranslatableText; | ||||||
|  |  | ||||||
|  | public enum UploadResult | ||||||
|  | { | ||||||
|  |     SUCCESS, | ||||||
|  |     ERROR, | ||||||
|  |     CONFIRM_OVERWRITE; | ||||||
|  |  | ||||||
|  |     public static final Text SUCCESS_TITLE = new TranslatableText( "gui.computercraft.upload.success" ); | ||||||
|  |  | ||||||
|  |     public static final Text FAILED_TITLE = new TranslatableText( "gui.computercraft.upload.failed" ); | ||||||
|  |     public static final Text COMPUTER_OFF_MSG = new TranslatableText( "gui.computercraft.upload.failed.computer_off" ); | ||||||
|  |     public static final Text OUT_OF_SPACE_MSG = new TranslatableText( "gui.computercraft.upload.failed.out_of_space" ); | ||||||
|  |     public static final Text TOO_MUCH_MSG = new TranslatableText( "gui.computercraft.upload.failed.too_much" ); | ||||||
|  |  | ||||||
|  |     public static final Text UPLOAD_OVERWRITE = new TranslatableText( "gui.computercraft.upload.overwrite" ); | ||||||
|  | } | ||||||
| @@ -56,18 +56,21 @@ public final class NetworkHandler | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Server messages |         // Server messages | ||||||
|         registerMainThread( 0, ComputerActionServerMessage::new ); |         registerMainThread( 0, ComputerActionServerMessage.class, ComputerActionServerMessage::new ); | ||||||
|         registerMainThread( 1, QueueEventServerMessage::new ); |         registerMainThread( 1, QueueEventServerMessage.class, QueueEventServerMessage::new ); | ||||||
|         registerMainThread( 2, RequestComputerMessage::new ); |         registerMainThread( 2, RequestComputerMessage.class, RequestComputerMessage::new ); | ||||||
|         registerMainThread( 3, KeyEventServerMessage::new ); |         registerMainThread( 3, KeyEventServerMessage.class, KeyEventServerMessage::new ); | ||||||
|         registerMainThread( 4, MouseEventServerMessage::new ); |         registerMainThread( 4, MouseEventServerMessage.class, MouseEventServerMessage::new ); | ||||||
|  |         registerMainThread( 5, UploadFileMessage.class, UploadFileMessage::new ); | ||||||
|  |         registerMainThread( 6, ContinueUploadMessage.class, ContinueUploadMessage::new ); | ||||||
|  |  | ||||||
|         // Client messages |         // Client messages | ||||||
|         registerMainThread( 10, ChatTableClientMessage::new ); |         registerMainThread( 10, ChatTableClientMessage.class, ChatTableClientMessage::new ); | ||||||
|         registerMainThread( 11, ComputerDataClientMessage::new ); |         registerMainThread( 11, ComputerDataClientMessage.class, ComputerDataClientMessage::new ); | ||||||
|         registerMainThread( 12, ComputerDeletedClientMessage::new ); |         registerMainThread( 12, ComputerDeletedClientMessage.class, ComputerDeletedClientMessage::new ); | ||||||
|         registerMainThread( 13, ComputerTerminalClientMessage::new ); |         registerMainThread( 13, ComputerTerminalClientMessage.class, ComputerTerminalClientMessage::new ); | ||||||
|         registerMainThread( 14, PlayRecordClientMessage.class, PlayRecordClientMessage::new ); |         registerMainThread( 14, PlayRecordClientMessage.class, PlayRecordClientMessage::new ); | ||||||
|  |         registerMainThread( 19, UploadResultMessage.class, UploadResultMessage::new ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private static void receive( PacketContext context, PacketByteBuf buffer ) |     private static void receive( PacketContext context, PacketByteBuf buffer ) | ||||||
| @@ -77,22 +80,6 @@ public final class NetworkHandler | |||||||
|             .accept( context, buffer ); |             .accept( context, buffer ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * /** Register packet, and a thread-unsafe handler for it. |  | ||||||
|      * |  | ||||||
|      * @param <T>     The type of the packet to send. |  | ||||||
|      * @param id      The identifier for this packet type |  | ||||||
|      * @param factory The factory for this type of packet. |  | ||||||
|      */ |  | ||||||
|     private static <T extends NetworkMessage> void registerMainThread( int id, Supplier<T> factory ) |  | ||||||
|     { |  | ||||||
|         registerMainThread( id, getType( factory ), buf -> { |  | ||||||
|             T instance = factory.get(); |  | ||||||
|             instance.fromBytes( buf ); |  | ||||||
|             return instance; |  | ||||||
|         } ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * /** Register packet, and a thread-unsafe handler for it. |      * /** Register packet, and a thread-unsafe handler for it. | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -25,18 +25,6 @@ public interface NetworkMessage | |||||||
|      */ |      */ | ||||||
|     void toBytes( @Nonnull PacketByteBuf buf ); |     void toBytes( @Nonnull PacketByteBuf buf ); | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Read this packet from a buffer. |  | ||||||
|      * |  | ||||||
|      * This may be called on any thread, so this should be a pure operation. |  | ||||||
|      * |  | ||||||
|      * @param buf The buffer to read data from. |  | ||||||
|      */ |  | ||||||
|     default void fromBytes( @Nonnull PacketByteBuf buf ) |  | ||||||
|     { |  | ||||||
|         throw new IllegalStateException( "Should have been registered using a \"from bytes\" method" ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Handle this {@link NetworkMessage}. |      * Handle this {@link NetworkMessage}. | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ import javax.annotation.Nonnull; | |||||||
|  |  | ||||||
| public class ChatTableClientMessage implements NetworkMessage | public class ChatTableClientMessage implements NetworkMessage | ||||||
| { | { | ||||||
|     private TableBuilder table; |     private final TableBuilder table; | ||||||
|  |  | ||||||
|     public ChatTableClientMessage( TableBuilder table ) |     public ChatTableClientMessage( TableBuilder table ) | ||||||
|     { |     { | ||||||
| @@ -30,39 +30,7 @@ public class ChatTableClientMessage implements NetworkMessage | |||||||
|         this.table = table; |         this.table = table; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public ChatTableClientMessage() |     public ChatTableClientMessage(@Nonnull PacketByteBuf buf) | ||||||
|     { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void toBytes( @Nonnull PacketByteBuf buf ) |  | ||||||
|     { |  | ||||||
|         buf.writeVarInt( table.getId() ); |  | ||||||
|         buf.writeVarInt( table.getColumns() ); |  | ||||||
|         buf.writeBoolean( table.getHeaders() != null ); |  | ||||||
|         if( table.getHeaders() != null ) |  | ||||||
|         { |  | ||||||
|             for( Text header : table.getHeaders() ) |  | ||||||
|             { |  | ||||||
|                 buf.writeText( header ); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         buf.writeVarInt( table.getRows() |  | ||||||
|             .size() ); |  | ||||||
|         for( Text[] row : table.getRows() ) |  | ||||||
|         { |  | ||||||
|             for( Text column : row ) |  | ||||||
|             { |  | ||||||
|                 buf.writeText( column ); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         buf.writeVarInt( table.getAdditional() ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void fromBytes( @Nonnull PacketByteBuf buf ) |  | ||||||
|     { |     { | ||||||
|         int id = buf.readVarInt(); |         int id = buf.readVarInt(); | ||||||
|         int columns = buf.readVarInt(); |         int columns = buf.readVarInt(); | ||||||
| @@ -96,6 +64,33 @@ public class ChatTableClientMessage implements NetworkMessage | |||||||
|         this.table = table; |         this.table = table; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void toBytes( @Nonnull PacketByteBuf buf ) | ||||||
|  |     { | ||||||
|  |         buf.writeVarInt( table.getId() ); | ||||||
|  |         buf.writeVarInt( table.getColumns() ); | ||||||
|  |         buf.writeBoolean( table.getHeaders() != null ); | ||||||
|  |         if( table.getHeaders() != null ) | ||||||
|  |         { | ||||||
|  |             for( Text header : table.getHeaders() ) | ||||||
|  |             { | ||||||
|  |                 buf.writeText( header ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         buf.writeVarInt( table.getRows() | ||||||
|  |             .size() ); | ||||||
|  |         for( Text[] row : table.getRows() ) | ||||||
|  |         { | ||||||
|  |             for( Text column : row ) | ||||||
|  |             { | ||||||
|  |                 buf.writeText( column ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         buf.writeVarInt( table.getAdditional() ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     @Environment( EnvType.CLIENT ) |     @Environment( EnvType.CLIENT ) | ||||||
|     public void handle( PacketContext context ) |     public void handle( PacketContext context ) | ||||||
|   | |||||||
| @@ -18,15 +18,16 @@ import javax.annotation.Nonnull; | |||||||
|  */ |  */ | ||||||
| public abstract class ComputerClientMessage implements NetworkMessage | public abstract class ComputerClientMessage implements NetworkMessage | ||||||
| { | { | ||||||
|     private int instanceId; |     private final int instanceId; | ||||||
|  |  | ||||||
|     public ComputerClientMessage( int instanceId ) |     public ComputerClientMessage( int instanceId ) | ||||||
|     { |     { | ||||||
|         this.instanceId = instanceId; |         this.instanceId = instanceId; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public ComputerClientMessage() |     public ComputerClientMessage( @Nonnull PacketByteBuf buf ) | ||||||
|     { |     { | ||||||
|  |         instanceId = buf.readVarInt(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public int getInstanceId() |     public int getInstanceId() | ||||||
| @@ -40,12 +41,6 @@ public abstract class ComputerClientMessage implements NetworkMessage | |||||||
|         buf.writeVarInt( instanceId ); |         buf.writeVarInt( instanceId ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void fromBytes( @Nonnull PacketByteBuf buf ) |  | ||||||
|     { |  | ||||||
|         instanceId = buf.readVarInt(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public ClientComputer getComputer() |     public ClientComputer getComputer() | ||||||
|     { |     { | ||||||
|         ClientComputer computer = ComputerCraft.clientComputerRegistry.get( instanceId ); |         ClientComputer computer = ComputerCraft.clientComputerRegistry.get( instanceId ); | ||||||
|   | |||||||
| @@ -19,8 +19,8 @@ import javax.annotation.Nonnull; | |||||||
|  */ |  */ | ||||||
| public class ComputerDataClientMessage extends ComputerClientMessage | public class ComputerDataClientMessage extends ComputerClientMessage | ||||||
| { | { | ||||||
|     private ComputerState state; |     private final ComputerState state; | ||||||
|     private NbtCompound userData; |     private final NbtCompound userData; | ||||||
|  |  | ||||||
|     public ComputerDataClientMessage( ServerComputer computer ) |     public ComputerDataClientMessage( ServerComputer computer ) | ||||||
|     { |     { | ||||||
| @@ -29,8 +29,11 @@ public class ComputerDataClientMessage extends ComputerClientMessage | |||||||
|         userData = computer.getUserData(); |         userData = computer.getUserData(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public ComputerDataClientMessage() |     public ComputerDataClientMessage( @Nonnull PacketByteBuf buf ) | ||||||
|     { |     { | ||||||
|  |         super( buf ); | ||||||
|  |         state = buf.readEnumConstant( ComputerState.class ); | ||||||
|  |         userData = buf.readNbt(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -41,14 +44,6 @@ public class ComputerDataClientMessage extends ComputerClientMessage | |||||||
|         buf.writeNbt( userData ); |         buf.writeNbt( userData ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void fromBytes( @Nonnull PacketByteBuf buf ) |  | ||||||
|     { |  | ||||||
|         super.fromBytes( buf ); |  | ||||||
|         state = buf.readEnumConstant( ComputerState.class ); |  | ||||||
|         userData = buf.readNbt(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void handle( PacketContext context ) |     public void handle( PacketContext context ) | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ package dan200.computercraft.shared.network.client; | |||||||
|  |  | ||||||
| import dan200.computercraft.ComputerCraft; | import dan200.computercraft.ComputerCraft; | ||||||
| import net.fabricmc.fabric.api.network.PacketContext; | import net.fabricmc.fabric.api.network.PacketContext; | ||||||
|  | import net.minecraft.network.PacketByteBuf; | ||||||
|  |  | ||||||
| public class ComputerDeletedClientMessage extends ComputerClientMessage | public class ComputerDeletedClientMessage extends ComputerClientMessage | ||||||
| { | { | ||||||
| @@ -16,8 +17,9 @@ public class ComputerDeletedClientMessage extends ComputerClientMessage | |||||||
|         super( instanceId ); |         super( instanceId ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public ComputerDeletedClientMessage() |     public ComputerDeletedClientMessage( PacketByteBuf buffer ) | ||||||
|     { |     { | ||||||
|  |         super( buffer ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ import javax.annotation.Nonnull; | |||||||
|  |  | ||||||
| public class ComputerTerminalClientMessage extends ComputerClientMessage | public class ComputerTerminalClientMessage extends ComputerClientMessage | ||||||
| { | { | ||||||
|     private TerminalState state; |     private final TerminalState state; | ||||||
|  |  | ||||||
|     public ComputerTerminalClientMessage( int instanceId, TerminalState state ) |     public ComputerTerminalClientMessage( int instanceId, TerminalState state ) | ||||||
|     { |     { | ||||||
| @@ -21,8 +21,10 @@ public class ComputerTerminalClientMessage extends ComputerClientMessage | |||||||
|         this.state = state; |         this.state = state; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public ComputerTerminalClientMessage() |     public ComputerTerminalClientMessage( @Nonnull PacketByteBuf buf ) | ||||||
|     { |     { | ||||||
|  |         super( buf ); | ||||||
|  |         state = new TerminalState( buf ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -32,13 +34,6 @@ public class ComputerTerminalClientMessage extends ComputerClientMessage | |||||||
|         state.write( buf ); |         state.write( buf ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void fromBytes( @Nonnull PacketByteBuf buf ) |  | ||||||
|     { |  | ||||||
|         super.fromBytes( buf ); |  | ||||||
|         state = new TerminalState( buf ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void handle( PacketContext context ) |     public void handle( PacketContext context ) | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -0,0 +1,58 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.shared.network.client; | ||||||
|  |  | ||||||
|  | import dan200.computercraft.client.gui.ComputerScreenBase; | ||||||
|  | import dan200.computercraft.client.gui.OptionScreen; | ||||||
|  | import dan200.computercraft.shared.computer.upload.UploadResult; | ||||||
|  | import dan200.computercraft.shared.network.NetworkMessage; | ||||||
|  | import net.fabricmc.fabric.api.network.PacketContext; | ||||||
|  | import net.minecraft.client.MinecraftClient; | ||||||
|  | import net.minecraft.client.gui.screen.Screen; | ||||||
|  | import net.minecraft.network.PacketByteBuf; | ||||||
|  | import net.minecraft.text.Text; | ||||||
|  |  | ||||||
|  | import javax.annotation.Nonnull; | ||||||
|  |  | ||||||
|  | public class UploadResultMessage implements NetworkMessage | ||||||
|  | { | ||||||
|  |     public static final UploadResultMessage COMPUTER_OFF = new UploadResultMessage( UploadResult.ERROR, UploadResult.COMPUTER_OFF_MSG ); | ||||||
|  |     public static final UploadResultMessage OUT_OF_SPACE = new UploadResultMessage( UploadResult.ERROR, UploadResult.OUT_OF_SPACE_MSG ); | ||||||
|  |  | ||||||
|  |     private final UploadResult result; | ||||||
|  |     private final Text message; | ||||||
|  |  | ||||||
|  |     public UploadResultMessage( UploadResult result, Text message ) | ||||||
|  |     { | ||||||
|  |         this.result = result; | ||||||
|  |         this.message = message; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public UploadResultMessage( @Nonnull PacketByteBuf buf ) | ||||||
|  |     { | ||||||
|  |         result = buf.readEnumConstant( UploadResult.class ); | ||||||
|  |         message = buf.readText(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void toBytes( @Nonnull PacketByteBuf buf ) | ||||||
|  |     { | ||||||
|  |         buf.writeEnumConstant( result ); | ||||||
|  |         buf.writeText( message ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void handle( PacketContext context ) | ||||||
|  |     { | ||||||
|  |         MinecraftClient minecraft = MinecraftClient.getInstance(); | ||||||
|  |  | ||||||
|  |         Screen screen = OptionScreen.unwrap( minecraft.currentScreen ); | ||||||
|  |         if( screen instanceof ComputerScreenBase<?> ) | ||||||
|  |         { | ||||||
|  |             ((ComputerScreenBase<?>) screen).uploadResult( result, message ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -6,17 +6,14 @@ | |||||||
|  |  | ||||||
| package dan200.computercraft.shared.network.container; | package dan200.computercraft.shared.network.container; | ||||||
|  |  | ||||||
| import dan200.computercraft.ComputerCraft; |  | ||||||
| import dan200.computercraft.shared.computer.core.ComputerFamily; | import dan200.computercraft.shared.computer.core.ComputerFamily; | ||||||
| import dan200.computercraft.shared.computer.core.ServerComputer; | import dan200.computercraft.shared.computer.core.ServerComputer; | ||||||
| import net.minecraft.network.PacketByteBuf; | import net.minecraft.network.PacketByteBuf; | ||||||
| import net.minecraft.util.Identifier; |  | ||||||
|  |  | ||||||
| public class ComputerContainerData implements ContainerData | public class ComputerContainerData implements ContainerData | ||||||
| { | { | ||||||
|     private static final Identifier IDENTIFIER = new Identifier( ComputerCraft.MOD_ID, "computer_container_data" ); |     private final int id; | ||||||
|     private int id; |     private final ComputerFamily family; | ||||||
|     private ComputerFamily family; |  | ||||||
|  |  | ||||||
|     public ComputerContainerData( ServerComputer computer ) |     public ComputerContainerData( ServerComputer computer ) | ||||||
|     { |     { | ||||||
| @@ -26,18 +23,8 @@ public class ComputerContainerData implements ContainerData | |||||||
|  |  | ||||||
|     public ComputerContainerData( PacketByteBuf byteBuf ) |     public ComputerContainerData( PacketByteBuf byteBuf ) | ||||||
|     { |     { | ||||||
|         fromBytes( byteBuf ); |         id = byteBuf.readInt(); | ||||||
|     } |         family = byteBuf.readEnumConstant( ComputerFamily.class ); | ||||||
|  |  | ||||||
|     public void fromBytes( PacketByteBuf buf ) |  | ||||||
|     { |  | ||||||
|         id = buf.readInt(); |  | ||||||
|         family = buf.readEnumConstant( ComputerFamily.class ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public Identifier getId() |  | ||||||
|     { |  | ||||||
|         return IDENTIFIER; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ | |||||||
|  |  | ||||||
| package dan200.computercraft.shared.network.container; | package dan200.computercraft.shared.network.container; | ||||||
|  |  | ||||||
|  | import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; | ||||||
| import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; | import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; | ||||||
| import net.minecraft.entity.player.PlayerEntity; | import net.minecraft.entity.player.PlayerEntity; | ||||||
| import net.minecraft.entity.player.PlayerInventory; | import net.minecraft.entity.player.PlayerInventory; | ||||||
| @@ -23,19 +24,28 @@ import java.util.function.Function; | |||||||
|  */ |  */ | ||||||
| public interface ContainerData | public interface ContainerData | ||||||
| { | { | ||||||
|     static <C extends ScreenHandler, T extends ContainerData> ScreenHandlerType<C> toType( Identifier identifier, Function<PacketByteBuf, T> reader, |     static <C extends ScreenHandler, T extends ContainerData> ScreenHandlerType<C> toType(Identifier identifier, Function<PacketByteBuf, T> reader, | ||||||
|                                                                                            Factory<C, T> factory ) |                                                                                           Factory<C, T> factory ) | ||||||
|     { |     { | ||||||
|         return ScreenHandlerRegistry.registerExtended( identifier, |         return ScreenHandlerRegistry.registerExtended( identifier, | ||||||
|             ( id, playerInventory, packetByteBuf ) -> factory.create( id, |             ( id, playerInventory, packetByteBuf ) -> factory.create( id, | ||||||
|                 playerInventory, |                 playerInventory, | ||||||
|                 reader.apply( packetByteBuf ) ) ); |                 reader.apply( packetByteBuf ) ) ); | ||||||
|     } |     } | ||||||
|  |     static <C extends ScreenHandler, T extends ContainerData> ScreenHandlerType<C> toType(Identifier identifier, ScreenHandlerType<C> type, Function<PacketByteBuf, T> reader, | ||||||
|  |                                                                                           FixedFactory<C, T> factory ) | ||||||
|  |     { | ||||||
|  |         return ScreenHandlerRegistry.registerExtended( identifier, | ||||||
|  |             ( id, playerInventory, packetByteBuf ) -> factory.create( type, id, | ||||||
|  |                 playerInventory, | ||||||
|  |                 reader.apply( packetByteBuf ) ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     void toBytes( PacketByteBuf buf ); |     void toBytes( PacketByteBuf buf ); | ||||||
|  |  | ||||||
|     default void open( PlayerEntity player, NamedScreenHandlerFactory owner ) |     default void open( PlayerEntity player, NamedScreenHandlerFactory owner ) | ||||||
|     { |     { | ||||||
|  |         if (player.world.isClient) return; | ||||||
|         player.openHandledScreen( owner ); |         player.openHandledScreen( owner ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -43,4 +53,9 @@ public interface ContainerData | |||||||
|     { |     { | ||||||
|         C create( int id, @Nonnull PlayerInventory inventory, T data ); |         C create( int id, @Nonnull PlayerInventory inventory, T data ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     interface FixedFactory<C extends ScreenHandler, T extends ContainerData> | ||||||
|  |     { | ||||||
|  |         C create( ScreenHandlerType<C> type, int id, @Nonnull PlayerInventory inventory, T data ); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,9 +21,8 @@ import javax.annotation.Nonnull; | |||||||
|  */ |  */ | ||||||
| public class ViewComputerContainerData extends ComputerContainerData | public class ViewComputerContainerData extends ComputerContainerData | ||||||
| { | { | ||||||
|     private static final Identifier IDENTIFIER = new Identifier( ComputerCraft.MOD_ID, "view_computer_container_data" ); |     private final int width; | ||||||
|     private int width; |     private final int height; | ||||||
|     private int height; |  | ||||||
|  |  | ||||||
|     public ViewComputerContainerData( ServerComputer computer ) |     public ViewComputerContainerData( ServerComputer computer ) | ||||||
|     { |     { | ||||||
| @@ -40,24 +39,11 @@ public class ViewComputerContainerData extends ComputerContainerData | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public ViewComputerContainerData( PacketByteBuf packetByteBuf ) |     public ViewComputerContainerData( PacketByteBuf buffer ) | ||||||
|     { |     { | ||||||
|         super( new PacketByteBuf( packetByteBuf.copy() ) ); |         super( buffer ); | ||||||
|         fromBytes( packetByteBuf ); |         width = buffer.readVarInt(); | ||||||
|     } |         height = buffer.readVarInt(); | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void fromBytes( PacketByteBuf buf ) |  | ||||||
|     { |  | ||||||
|         super.fromBytes( buf ); |  | ||||||
|         width = buf.readVarInt(); |  | ||||||
|         height = buf.readVarInt(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public Identifier getId() |  | ||||||
|     { |  | ||||||
|         return IDENTIFIER; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -8,13 +8,14 @@ package dan200.computercraft.shared.network.server; | |||||||
|  |  | ||||||
| import dan200.computercraft.shared.computer.core.IContainerComputer; | import dan200.computercraft.shared.computer.core.IContainerComputer; | ||||||
| import dan200.computercraft.shared.computer.core.ServerComputer; | import dan200.computercraft.shared.computer.core.ServerComputer; | ||||||
|  | import net.fabricmc.fabric.api.network.PacketContext; | ||||||
| import net.minecraft.network.PacketByteBuf; | import net.minecraft.network.PacketByteBuf; | ||||||
|  |  | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
|  |  | ||||||
| public class ComputerActionServerMessage extends ComputerServerMessage | public class ComputerActionServerMessage extends ComputerServerMessage | ||||||
| { | { | ||||||
|     private Action action; |     private final Action action; | ||||||
|  |  | ||||||
|     public ComputerActionServerMessage( int instanceId, Action action ) |     public ComputerActionServerMessage( int instanceId, Action action ) | ||||||
|     { |     { | ||||||
| @@ -22,8 +23,10 @@ public class ComputerActionServerMessage extends ComputerServerMessage | |||||||
|         this.action = action; |         this.action = action; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public ComputerActionServerMessage() |     public ComputerActionServerMessage( @Nonnull PacketByteBuf buf ) | ||||||
|     { |     { | ||||||
|  |         super( buf ); | ||||||
|  |         action = buf.readEnumConstant( Action.class ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -34,14 +37,7 @@ public class ComputerActionServerMessage extends ComputerServerMessage | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void fromBytes( @Nonnull PacketByteBuf buf ) |     protected void handle(PacketContext context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) | ||||||
|     { |  | ||||||
|         super.fromBytes( buf ); |  | ||||||
|         action = buf.readEnumConstant( Action.class ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     protected void handle( @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) |  | ||||||
|     { |     { | ||||||
|         switch( action ) |         switch( action ) | ||||||
|         { |         { | ||||||
|   | |||||||
| @@ -22,15 +22,16 @@ import javax.annotation.Nonnull; | |||||||
|  */ |  */ | ||||||
| public abstract class ComputerServerMessage implements NetworkMessage | public abstract class ComputerServerMessage implements NetworkMessage | ||||||
| { | { | ||||||
|     private int instanceId; |     private final int instanceId; | ||||||
|  |  | ||||||
|     public ComputerServerMessage( int instanceId ) |     public ComputerServerMessage( int instanceId ) | ||||||
|     { |     { | ||||||
|         this.instanceId = instanceId; |         this.instanceId = instanceId; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public ComputerServerMessage() |     public ComputerServerMessage( @Nonnull PacketByteBuf buf ) | ||||||
|     { |     { | ||||||
|  |         instanceId = buf.readVarInt(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -39,12 +40,6 @@ public abstract class ComputerServerMessage implements NetworkMessage | |||||||
|         buf.writeVarInt( instanceId ); |         buf.writeVarInt( instanceId ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void fromBytes( @Nonnull PacketByteBuf buf ) |  | ||||||
|     { |  | ||||||
|         instanceId = buf.readVarInt(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void handle( PacketContext context ) |     public void handle( PacketContext context ) | ||||||
|     { |     { | ||||||
| @@ -60,8 +55,8 @@ public abstract class ComputerServerMessage implements NetworkMessage | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         handle( computer, container ); |         handle( context, computer, container ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     protected abstract void handle( @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ); |     protected abstract void handle( PacketContext context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,46 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.shared.network.server; | ||||||
|  |  | ||||||
|  | import dan200.computercraft.shared.computer.core.IContainerComputer; | ||||||
|  | import dan200.computercraft.shared.computer.core.ServerComputer; | ||||||
|  | import net.fabricmc.fabric.api.network.PacketContext; | ||||||
|  | import net.minecraft.entity.player.PlayerEntity; | ||||||
|  | import net.minecraft.network.PacketByteBuf; | ||||||
|  | import net.minecraft.server.network.ServerPlayerEntity; | ||||||
|  |  | ||||||
|  | import javax.annotation.Nonnull; | ||||||
|  |  | ||||||
|  | public class ContinueUploadMessage extends ComputerServerMessage | ||||||
|  | { | ||||||
|  |     private final boolean overwrite; | ||||||
|  |  | ||||||
|  |     public ContinueUploadMessage( int instanceId, boolean overwrite ) | ||||||
|  |     { | ||||||
|  |         super( instanceId ); | ||||||
|  |         this.overwrite = overwrite; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public ContinueUploadMessage( @Nonnull PacketByteBuf buf ) | ||||||
|  |     { | ||||||
|  |         super( buf ); | ||||||
|  |         overwrite = buf.readBoolean(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void toBytes( @Nonnull PacketByteBuf buf ) | ||||||
|  |     { | ||||||
|  |         super.toBytes( buf ); | ||||||
|  |         buf.writeBoolean( overwrite ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected void handle(PacketContext context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) | ||||||
|  |     { | ||||||
|  |         ServerPlayerEntity player = (ServerPlayerEntity) context.getPlayer(); | ||||||
|  |         if( player != null ) container.confirmUpload( player, overwrite ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -9,6 +9,7 @@ package dan200.computercraft.shared.network.server; | |||||||
| import dan200.computercraft.shared.computer.core.IContainerComputer; | import dan200.computercraft.shared.computer.core.IContainerComputer; | ||||||
| import dan200.computercraft.shared.computer.core.InputState; | import dan200.computercraft.shared.computer.core.InputState; | ||||||
| import dan200.computercraft.shared.computer.core.ServerComputer; | import dan200.computercraft.shared.computer.core.ServerComputer; | ||||||
|  | import net.fabricmc.fabric.api.network.PacketContext; | ||||||
| import net.minecraft.network.PacketByteBuf; | import net.minecraft.network.PacketByteBuf; | ||||||
|  |  | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| @@ -19,8 +20,8 @@ public class KeyEventServerMessage extends ComputerServerMessage | |||||||
|     public static final int TYPE_REPEAT = 1; |     public static final int TYPE_REPEAT = 1; | ||||||
|     public static final int TYPE_UP = 2; |     public static final int TYPE_UP = 2; | ||||||
|  |  | ||||||
|     private int type; |     private final int type; | ||||||
|     private int key; |     private final int key; | ||||||
|  |  | ||||||
|     public KeyEventServerMessage( int instanceId, int type, int key ) |     public KeyEventServerMessage( int instanceId, int type, int key ) | ||||||
|     { |     { | ||||||
| @@ -29,8 +30,11 @@ public class KeyEventServerMessage extends ComputerServerMessage | |||||||
|         this.key = key; |         this.key = key; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public KeyEventServerMessage() |     public KeyEventServerMessage( @Nonnull PacketByteBuf buf ) | ||||||
|     { |     { | ||||||
|  |         super( buf ); | ||||||
|  |         type = buf.readByte(); | ||||||
|  |         key = buf.readVarInt(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -42,15 +46,7 @@ public class KeyEventServerMessage extends ComputerServerMessage | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void fromBytes( @Nonnull PacketByteBuf buf ) |     protected void handle(PacketContext context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) | ||||||
|     { |  | ||||||
|         super.fromBytes( buf ); |  | ||||||
|         type = buf.readByte(); |  | ||||||
|         key = buf.readVarInt(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     protected void handle( @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) |  | ||||||
|     { |     { | ||||||
|         InputState input = container.getInput(); |         InputState input = container.getInput(); | ||||||
|         if( type == TYPE_UP ) |         if( type == TYPE_UP ) | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ package dan200.computercraft.shared.network.server; | |||||||
| import dan200.computercraft.shared.computer.core.IContainerComputer; | import dan200.computercraft.shared.computer.core.IContainerComputer; | ||||||
| import dan200.computercraft.shared.computer.core.InputState; | import dan200.computercraft.shared.computer.core.InputState; | ||||||
| import dan200.computercraft.shared.computer.core.ServerComputer; | import dan200.computercraft.shared.computer.core.ServerComputer; | ||||||
|  | import net.fabricmc.fabric.api.network.PacketContext; | ||||||
| import net.minecraft.network.PacketByteBuf; | import net.minecraft.network.PacketByteBuf; | ||||||
|  |  | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| @@ -20,10 +21,10 @@ public class MouseEventServerMessage extends ComputerServerMessage | |||||||
|     public static final int TYPE_UP = 2; |     public static final int TYPE_UP = 2; | ||||||
|     public static final int TYPE_SCROLL = 3; |     public static final int TYPE_SCROLL = 3; | ||||||
|  |  | ||||||
|     private int type; |     private final int type; | ||||||
|     private int x; |     private final int x; | ||||||
|     private int y; |     private final int y; | ||||||
|     private int arg; |     private final int arg; | ||||||
|  |  | ||||||
|     public MouseEventServerMessage( int instanceId, int type, int arg, int x, int y ) |     public MouseEventServerMessage( int instanceId, int type, int arg, int x, int y ) | ||||||
|     { |     { | ||||||
| @@ -34,8 +35,13 @@ public class MouseEventServerMessage extends ComputerServerMessage | |||||||
|         this.y = y; |         this.y = y; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public MouseEventServerMessage() |     public MouseEventServerMessage( @Nonnull PacketByteBuf buf ) | ||||||
|     { |     { | ||||||
|  |         super( buf ); | ||||||
|  |         type = buf.readByte(); | ||||||
|  |         arg = buf.readVarInt(); | ||||||
|  |         x = buf.readVarInt(); | ||||||
|  |         y = buf.readVarInt(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -49,17 +55,7 @@ public class MouseEventServerMessage extends ComputerServerMessage | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void fromBytes( @Nonnull PacketByteBuf buf ) |     protected void handle(PacketContext context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) | ||||||
|     { |  | ||||||
|         super.fromBytes( buf ); |  | ||||||
|         type = buf.readByte(); |  | ||||||
|         arg = buf.readVarInt(); |  | ||||||
|         x = buf.readVarInt(); |  | ||||||
|         y = buf.readVarInt(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     protected void handle( @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) |  | ||||||
|     { |     { | ||||||
|         InputState input = container.getInput(); |         InputState input = container.getInput(); | ||||||
|         switch( type ) |         switch( type ) | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ package dan200.computercraft.shared.network.server; | |||||||
| import dan200.computercraft.shared.computer.core.IContainerComputer; | import dan200.computercraft.shared.computer.core.IContainerComputer; | ||||||
| import dan200.computercraft.shared.computer.core.ServerComputer; | import dan200.computercraft.shared.computer.core.ServerComputer; | ||||||
| import dan200.computercraft.shared.util.NBTUtil; | import dan200.computercraft.shared.util.NBTUtil; | ||||||
|  | import net.fabricmc.fabric.api.network.PacketContext; | ||||||
| import net.minecraft.nbt.NbtCompound; | import net.minecraft.nbt.NbtCompound; | ||||||
| import net.minecraft.network.PacketByteBuf; | import net.minecraft.network.PacketByteBuf; | ||||||
|  |  | ||||||
| @@ -23,8 +24,8 @@ import javax.annotation.Nullable; | |||||||
|  */ |  */ | ||||||
| public class QueueEventServerMessage extends ComputerServerMessage | public class QueueEventServerMessage extends ComputerServerMessage | ||||||
| { | { | ||||||
|     private String event; |     private final String event; | ||||||
|     private Object[] args; |     private final Object[] args; | ||||||
|  |  | ||||||
|     public QueueEventServerMessage( int instanceId, @Nonnull String event, @Nullable Object[] args ) |     public QueueEventServerMessage( int instanceId, @Nonnull String event, @Nullable Object[] args ) | ||||||
|     { |     { | ||||||
| @@ -33,8 +34,13 @@ public class QueueEventServerMessage extends ComputerServerMessage | |||||||
|         this.args = args; |         this.args = args; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public QueueEventServerMessage() |     public QueueEventServerMessage( @Nonnull PacketByteBuf buf ) | ||||||
|     { |     { | ||||||
|  |         super( buf ); | ||||||
|  |         event = buf.readString( Short.MAX_VALUE ); | ||||||
|  |  | ||||||
|  |         NbtCompound args = buf.readNbt(); | ||||||
|  |         this.args = args == null ? null : NBTUtil.decodeObjects( args ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -46,17 +52,7 @@ public class QueueEventServerMessage extends ComputerServerMessage | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void fromBytes( @Nonnull PacketByteBuf buf ) |     protected void handle(PacketContext context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) | ||||||
|     { |  | ||||||
|         super.fromBytes( buf ); |  | ||||||
|         event = buf.readString( Short.MAX_VALUE ); |  | ||||||
|  |  | ||||||
|         NbtCompound args = buf.readNbt(); |  | ||||||
|         this.args = args == null ? null : NBTUtil.decodeObjects( args ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     protected void handle( @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) |  | ||||||
|     { |     { | ||||||
|         computer.queueEvent( event, args ); |         computer.queueEvent( event, args ); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -16,15 +16,16 @@ import javax.annotation.Nonnull; | |||||||
|  |  | ||||||
| public class RequestComputerMessage implements NetworkMessage | public class RequestComputerMessage implements NetworkMessage | ||||||
| { | { | ||||||
|     private int instance; |     private final int instance; | ||||||
|  |  | ||||||
|     public RequestComputerMessage( int instance ) |     public RequestComputerMessage( int instance ) | ||||||
|     { |     { | ||||||
|         this.instance = instance; |         this.instance = instance; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public RequestComputerMessage() |     public RequestComputerMessage( @Nonnull PacketByteBuf buf ) | ||||||
|     { |     { | ||||||
|  |         instance = buf.readVarInt(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -33,12 +34,6 @@ public class RequestComputerMessage implements NetworkMessage | |||||||
|         buf.writeVarInt( instance ); |         buf.writeVarInt( instance ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void fromBytes( @Nonnull PacketByteBuf buf ) |  | ||||||
|     { |  | ||||||
|         instance = buf.readVarInt(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void handle( PacketContext context ) |     public void handle( PacketContext context ) | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -0,0 +1,187 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.shared.network.server; | ||||||
|  |  | ||||||
|  | import dan200.computercraft.ComputerCraft; | ||||||
|  | import dan200.computercraft.shared.computer.core.IContainerComputer; | ||||||
|  | import dan200.computercraft.shared.computer.core.ServerComputer; | ||||||
|  | import dan200.computercraft.shared.computer.upload.FileSlice; | ||||||
|  | import dan200.computercraft.shared.computer.upload.FileUpload; | ||||||
|  | import dan200.computercraft.shared.network.NetworkHandler; | ||||||
|  | import io.netty.handler.codec.DecoderException; | ||||||
|  | import net.fabricmc.fabric.api.network.PacketContext; | ||||||
|  | import net.minecraft.entity.player.PlayerEntity; | ||||||
|  | import net.minecraft.network.PacketByteBuf; | ||||||
|  | import net.minecraft.server.network.ServerPlayerEntity; | ||||||
|  |  | ||||||
|  | import javax.annotation.Nonnull; | ||||||
|  | import java.nio.ByteBuffer; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
|  | public class UploadFileMessage extends ComputerServerMessage | ||||||
|  | { | ||||||
|  |     public static final int MAX_SIZE = 512 * 1024; | ||||||
|  |     static final int MAX_PACKET_SIZE = 30 * 1024; // Max packet size is 32767. | ||||||
|  |  | ||||||
|  |     public static final int MAX_FILES = 32; | ||||||
|  |     public static final int MAX_FILE_NAME = 128; | ||||||
|  |  | ||||||
|  |     private static final int FLAG_FIRST = 1; | ||||||
|  |     private static final int FLAG_LAST = 2; | ||||||
|  |  | ||||||
|  |     private final UUID uuid; | ||||||
|  |     private final int flag; | ||||||
|  |     private final List<FileUpload> files; | ||||||
|  |     private final List<FileSlice> slices; | ||||||
|  |  | ||||||
|  |     UploadFileMessage( int instanceId, UUID uuid, int flag, List<FileUpload> files, List<FileSlice> slices ) | ||||||
|  |     { | ||||||
|  |         super( instanceId ); | ||||||
|  |         this.uuid = uuid; | ||||||
|  |         this.flag = flag; | ||||||
|  |         this.files = files; | ||||||
|  |         this.slices = slices; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public UploadFileMessage( @Nonnull PacketByteBuf buf ) | ||||||
|  |     { | ||||||
|  |         super( buf ); | ||||||
|  |         uuid = buf.readUuid(); | ||||||
|  |         int flag = this.flag = buf.readByte(); | ||||||
|  |  | ||||||
|  |         int totalSize = 0; | ||||||
|  |         if( (flag & FLAG_FIRST) != 0 ) | ||||||
|  |         { | ||||||
|  |             int nFiles = buf.readVarInt(); | ||||||
|  |             if( nFiles >= MAX_FILES ) throw new DecoderException( "Too many files" ); | ||||||
|  |  | ||||||
|  |             List<FileUpload> files = this.files = new ArrayList<>( nFiles ); | ||||||
|  |             for( int i = 0; i < nFiles; i++ ) | ||||||
|  |             { | ||||||
|  |                 String name = buf.readString( MAX_FILE_NAME ); | ||||||
|  |                 int size = buf.readVarInt(); | ||||||
|  |                 if( size > MAX_SIZE || (totalSize += size) >= MAX_SIZE ) | ||||||
|  |                 { | ||||||
|  |                     throw new DecoderException( "Files are too large" ); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 byte[] digest = new byte[FileUpload.CHECKSUM_LENGTH]; | ||||||
|  |                 buf.readBytes( digest ); | ||||||
|  |  | ||||||
|  |                 files.add( new FileUpload( name, ByteBuffer.allocateDirect( size ), digest ) ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             files = null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         int nSlices = buf.readVarInt(); | ||||||
|  |         List<FileSlice> slices = this.slices = new ArrayList<>( nSlices ); | ||||||
|  |         for( int i = 0; i < nSlices; i++ ) | ||||||
|  |         { | ||||||
|  |             int fileId = buf.readUnsignedByte(); | ||||||
|  |             int offset = buf.readVarInt(); | ||||||
|  |  | ||||||
|  |             int size = buf.readUnsignedShort(); | ||||||
|  |             if( size > MAX_PACKET_SIZE ) throw new DecoderException( "File is too large" ); | ||||||
|  |  | ||||||
|  |             ByteBuffer buffer = ByteBuffer.allocateDirect( size ); | ||||||
|  |             buf.readBytes( buffer ); | ||||||
|  |             buffer.flip(); | ||||||
|  |  | ||||||
|  |             slices.add( new FileSlice( fileId, offset, buffer ) ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void toBytes( @Nonnull PacketByteBuf buf ) | ||||||
|  |     { | ||||||
|  |         super.toBytes( buf ); | ||||||
|  |         buf.writeUuid( uuid ); | ||||||
|  |         buf.writeByte( flag ); | ||||||
|  |  | ||||||
|  |         if( (flag & FLAG_FIRST) != 0 ) | ||||||
|  |         { | ||||||
|  |             buf.writeVarInt( files.size() ); | ||||||
|  |             for( FileUpload file : files ) | ||||||
|  |             { | ||||||
|  |                 buf.writeString( file.getName(), MAX_FILE_NAME ); | ||||||
|  |                 buf.writeVarInt( file.getLength() ); | ||||||
|  |                 buf.writeBytes( file.getChecksum() ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         buf.writeVarInt( slices.size() ); | ||||||
|  |         for( FileSlice slice : slices ) | ||||||
|  |         { | ||||||
|  |             buf.writeByte( slice.getFileId() ); | ||||||
|  |             buf.writeVarInt( slice.getOffset() ); | ||||||
|  |  | ||||||
|  |             slice.getBytes().rewind(); | ||||||
|  |             buf.writeShort( slice.getBytes().remaining() ); | ||||||
|  |             buf.writeBytes( slice.getBytes() ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static void send( int instanceId, List<FileUpload> files ) | ||||||
|  |     { | ||||||
|  |         UUID uuid = UUID.randomUUID(); | ||||||
|  |  | ||||||
|  |         int remaining = MAX_PACKET_SIZE; | ||||||
|  |         for( FileUpload file : files ) remaining -= file.getName().length() * 4 + FileUpload.CHECKSUM_LENGTH; | ||||||
|  |  | ||||||
|  |         boolean first = true; | ||||||
|  |         List<FileSlice> slices = new ArrayList<>( files.size() ); | ||||||
|  |         for( int fileId = 0; fileId < files.size(); fileId++ ) | ||||||
|  |         { | ||||||
|  |             FileUpload file = files.get( fileId ); | ||||||
|  |             ByteBuffer contents = file.getBytes(); | ||||||
|  |             int capacity = contents.limit(); | ||||||
|  |  | ||||||
|  |             int currentOffset = 0; | ||||||
|  |             while( currentOffset < capacity ) | ||||||
|  |             { | ||||||
|  |                 if( remaining <= 0 ) | ||||||
|  |                 { | ||||||
|  |                     NetworkHandler.sendToServer( first | ||||||
|  |                         ? new UploadFileMessage( instanceId, uuid, FLAG_FIRST, files, new ArrayList<>( slices ) ) | ||||||
|  |                         : new UploadFileMessage( instanceId, uuid, 0, null, new ArrayList<>( slices ) ) ); | ||||||
|  |                     slices.clear(); | ||||||
|  |                     remaining = MAX_PACKET_SIZE; | ||||||
|  |                     first = false; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 int canWrite = Math.min( remaining, capacity - currentOffset ); | ||||||
|  |  | ||||||
|  |                 ComputerCraft.log.info( "Adding slice from {} to {}", currentOffset, currentOffset + canWrite - 1 ); | ||||||
|  |                 contents.position( currentOffset ).limit( currentOffset + canWrite ); | ||||||
|  |                 slices.add( new FileSlice( fileId, currentOffset, contents.slice() ) ); | ||||||
|  |                 currentOffset += canWrite; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             contents.position( 0 ).limit( capacity ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         NetworkHandler.sendToServer( first | ||||||
|  |             ? new UploadFileMessage( instanceId, uuid, FLAG_FIRST | FLAG_LAST, files, new ArrayList<>( slices ) ) | ||||||
|  |             : new UploadFileMessage( instanceId, uuid, FLAG_LAST, null, new ArrayList<>( slices ) ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected void handle(PacketContext context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) | ||||||
|  |     { | ||||||
|  |         ServerPlayerEntity player = (ServerPlayerEntity) context.getPlayer(); | ||||||
|  |         if( player != null ) | ||||||
|  |         { | ||||||
|  |             if( (flag & FLAG_FIRST) != 0 ) container.startUpload( uuid, files ); | ||||||
|  |             container.continueUpload( uuid, slices ); | ||||||
|  |             if( (flag & FLAG_LAST) != 0 ) container.finishUpload( player, uuid ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -170,8 +170,6 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile | |||||||
|  |  | ||||||
|         int oldXIndex = xIndex; |         int oldXIndex = xIndex; | ||||||
|         int oldYIndex = yIndex; |         int oldYIndex = yIndex; | ||||||
|         int oldWidth = width; |  | ||||||
|         int oldHeight = height; |  | ||||||
|  |  | ||||||
|         xIndex = nbt.getInt( NBT_X ); |         xIndex = nbt.getInt( NBT_X ); | ||||||
|         yIndex = nbt.getInt( NBT_Y ); |         yIndex = nbt.getInt( NBT_Y ); | ||||||
| @@ -182,27 +180,14 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile | |||||||
|         { |         { | ||||||
|             // If our index has changed then it's possible the origin monitor has changed. Thus |             // If our index has changed then it's possible the origin monitor has changed. Thus | ||||||
|             // we'll clear our cache. If we're the origin then we'll need to remove the glList as well. |             // we'll clear our cache. If we're the origin then we'll need to remove the glList as well. | ||||||
|             if( oldXIndex == 0 && oldYIndex == 0 && clientMonitor != null ) |             if( oldXIndex == 0 && oldYIndex == 0 && clientMonitor != null ) clientMonitor.destroy(); | ||||||
|             { |  | ||||||
|                 clientMonitor.destroy(); |  | ||||||
|             } |  | ||||||
|             clientMonitor = null; |             clientMonitor = null; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if( xIndex == 0 && yIndex == 0 ) |         if( xIndex == 0 && yIndex == 0 ) | ||||||
|         { |         { | ||||||
|             // If we're the origin terminal then create it. |             // If we're the origin terminal then create it. | ||||||
|             if( clientMonitor == null ) |             if( clientMonitor == null ) clientMonitor = new ClientMonitor( advanced, this ); | ||||||
|             { |  | ||||||
|                 clientMonitor = new ClientMonitor( advanced, this ); |  | ||||||
|             } |  | ||||||
|             clientMonitor.readDescription( nbt ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if( oldXIndex != xIndex || oldYIndex != yIndex || oldWidth != width || oldHeight != height ) |  | ||||||
|         { |  | ||||||
|             // One of our properties has changed, so ensure we redraw the block |  | ||||||
|             updateBlock(); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -214,11 +199,6 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile | |||||||
|         nbt.putInt( NBT_Y, yIndex ); |         nbt.putInt( NBT_Y, yIndex ); | ||||||
|         nbt.putInt( NBT_WIDTH, width ); |         nbt.putInt( NBT_WIDTH, width ); | ||||||
|         nbt.putInt( NBT_HEIGHT, height ); |         nbt.putInt( NBT_HEIGHT, height ); | ||||||
|  |  | ||||||
|         if( xIndex == 0 && yIndex == 0 && serverMonitor != null ) |  | ||||||
|         { |  | ||||||
|             serverMonitor.writeDescription( nbt ); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private TileMonitor getNeighbour( int x, int y ) |     private TileMonitor getNeighbour( int x, int y ) | ||||||
|   | |||||||
| @@ -31,7 +31,7 @@ public class TileSpeaker extends TileGeneric implements IPeripheralTile | |||||||
|         super( type, pos, state ); |         super( type, pos, state ); | ||||||
|         peripheral = new Peripheral( this ); |         peripheral = new Peripheral( this ); | ||||||
|     } |     } | ||||||
|      |  | ||||||
|     public static void tick( World world, BlockPos pos, BlockState state, TileSpeaker tileSpeaker ) |     public static void tick( World world, BlockPos pos, BlockState state, TileSpeaker tileSpeaker ) | ||||||
|     { |     { | ||||||
|         tileSpeaker.peripheral.update(); |         tileSpeaker.peripheral.update(); | ||||||
|   | |||||||
| @@ -1,78 +0,0 @@ | |||||||
| /* |  | ||||||
|  * This file is part of ComputerCraft - http://www.computercraft.info |  | ||||||
|  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. |  | ||||||
|  * Send enquiries to dratcliffe@gmail.com |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| package dan200.computercraft.shared.pocket.inventory; |  | ||||||
|  |  | ||||||
| import dan200.computercraft.shared.ComputerCraftRegistry; |  | ||||||
| import dan200.computercraft.shared.computer.core.ServerComputer; |  | ||||||
| import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; |  | ||||||
| import dan200.computercraft.shared.pocket.items.ItemPocketComputer; |  | ||||||
| import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; |  | ||||||
| import net.minecraft.entity.player.PlayerEntity; |  | ||||||
| import net.minecraft.entity.player.PlayerInventory; |  | ||||||
| import net.minecraft.item.ItemStack; |  | ||||||
| import net.minecraft.network.PacketByteBuf; |  | ||||||
| import net.minecraft.screen.ScreenHandler; |  | ||||||
| import net.minecraft.server.network.ServerPlayerEntity; |  | ||||||
| import net.minecraft.text.Text; |  | ||||||
| import net.minecraft.util.Hand; |  | ||||||
|  |  | ||||||
| import javax.annotation.Nonnull; |  | ||||||
| import javax.annotation.Nullable; |  | ||||||
|  |  | ||||||
| public final class ContainerPocketComputer extends ContainerComputerBase |  | ||||||
| { |  | ||||||
|     private ContainerPocketComputer( int id, ServerComputer computer, ItemPocketComputer item, Hand hand ) |  | ||||||
|     { |  | ||||||
|         super( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER, id, p -> { |  | ||||||
|             ItemStack stack = p.getStackInHand( hand ); |  | ||||||
|             return stack.getItem() == item && ItemPocketComputer.getServerComputer( stack ) == computer; |  | ||||||
|         }, computer, item.getFamily() ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public ContainerPocketComputer( int id, PlayerInventory player, PacketByteBuf packetByteBuf ) |  | ||||||
|     { |  | ||||||
|         super( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER, id, player, packetByteBuf ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static class Factory implements ExtendedScreenHandlerFactory |  | ||||||
|     { |  | ||||||
|         private final ServerComputer computer; |  | ||||||
|         private final Text name; |  | ||||||
|         private final ItemPocketComputer item; |  | ||||||
|         private final Hand hand; |  | ||||||
|  |  | ||||||
|         public Factory( ServerComputer computer, ItemStack stack, ItemPocketComputer item, Hand hand ) |  | ||||||
|         { |  | ||||||
|             this.computer = computer; |  | ||||||
|             name = stack.getName(); |  | ||||||
|             this.item = item; |  | ||||||
|             this.hand = hand; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         @Nonnull |  | ||||||
|         @Override |  | ||||||
|         public Text getDisplayName() |  | ||||||
|         { |  | ||||||
|             return name; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         @Nullable |  | ||||||
|         @Override |  | ||||||
|         public ScreenHandler createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity entity ) |  | ||||||
|         { |  | ||||||
|             return new ContainerPocketComputer( id, computer, item, hand ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         @Override |  | ||||||
|         public void writeScreenOpeningData( ServerPlayerEntity serverPlayerEntity, PacketByteBuf packetByteBuf ) |  | ||||||
|         { |  | ||||||
|             packetByteBuf.writeInt( computer.getInstanceID() ); |  | ||||||
|             packetByteBuf.writeEnumConstant( computer.getFamily() ); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -0,0 +1,71 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.shared.pocket.inventory; | ||||||
|  |  | ||||||
|  | import dan200.computercraft.shared.ComputerCraftRegistry; | ||||||
|  | import dan200.computercraft.shared.computer.core.ComputerFamily; | ||||||
|  | import dan200.computercraft.shared.computer.core.ServerComputer; | ||||||
|  | import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory; | ||||||
|  | import dan200.computercraft.shared.pocket.items.ItemPocketComputer; | ||||||
|  | import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; | ||||||
|  | import net.minecraft.entity.player.PlayerEntity; | ||||||
|  | import net.minecraft.entity.player.PlayerInventory; | ||||||
|  | import net.minecraft.item.ItemStack; | ||||||
|  | import net.minecraft.network.PacketByteBuf; | ||||||
|  | import net.minecraft.screen.NamedScreenHandlerFactory; | ||||||
|  | import net.minecraft.screen.ScreenHandler; | ||||||
|  | import net.minecraft.server.network.ServerPlayerEntity; | ||||||
|  | import net.minecraft.text.Text; | ||||||
|  | import net.minecraft.util.Hand; | ||||||
|  |  | ||||||
|  | import javax.annotation.Nonnull; | ||||||
|  | import javax.annotation.Nullable; | ||||||
|  |  | ||||||
|  | public class PocketComputerMenuProvider implements NamedScreenHandlerFactory, ExtendedScreenHandlerFactory | ||||||
|  | { | ||||||
|  |     private final ServerComputer computer; | ||||||
|  |     private final Text name; | ||||||
|  |     private final ItemPocketComputer item; | ||||||
|  |     private final Hand hand; | ||||||
|  |     private final boolean isTypingOnly; | ||||||
|  |  | ||||||
|  |     public PocketComputerMenuProvider(ServerComputer computer, ItemStack stack, ItemPocketComputer item, Hand hand, boolean isTypingOnly ) | ||||||
|  |     { | ||||||
|  |         this.computer = computer; | ||||||
|  |         name = stack.getName(); | ||||||
|  |         this.item = item; | ||||||
|  |         this.hand = hand; | ||||||
|  |         this.isTypingOnly = isTypingOnly; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     @Nonnull | ||||||
|  |     @Override | ||||||
|  |     public Text getDisplayName() | ||||||
|  |     { | ||||||
|  |         return name; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Nullable | ||||||
|  |     @Override | ||||||
|  |     public ScreenHandler createMenu(int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity entity ) | ||||||
|  |     { | ||||||
|  |         return new ComputerMenuWithoutInventory( | ||||||
|  |             isTypingOnly ? ComputerCraftRegistry.ModContainers.POCKET_COMPUTER_NO_TERM : ComputerCraftRegistry.ModContainers.POCKET_COMPUTER, id, inventory, | ||||||
|  |             p -> { | ||||||
|  |                 ItemStack stack = p.getStackInHand( hand ); | ||||||
|  |                 return stack.getItem() == item && ItemPocketComputer.getServerComputer( stack ) == computer; | ||||||
|  |             }, | ||||||
|  |             computer, item.getFamily() | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf packetByteBuf) { | ||||||
|  |         packetByteBuf.writeInt(computer.getInstanceID()); | ||||||
|  |         packetByteBuf.writeEnumConstant(computer.getFamily()); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -23,7 +23,7 @@ import dan200.computercraft.shared.computer.items.IComputerItem; | |||||||
| import dan200.computercraft.shared.network.container.ComputerContainerData; | import dan200.computercraft.shared.network.container.ComputerContainerData; | ||||||
| import dan200.computercraft.shared.pocket.apis.PocketAPI; | import dan200.computercraft.shared.pocket.apis.PocketAPI; | ||||||
| import dan200.computercraft.shared.pocket.core.PocketServerComputer; | import dan200.computercraft.shared.pocket.core.PocketServerComputer; | ||||||
| import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; | import dan200.computercraft.shared.pocket.inventory.PocketComputerMenuProvider; | ||||||
| import net.fabricmc.api.EnvType; | import net.fabricmc.api.EnvType; | ||||||
| import net.fabricmc.api.Environment; | import net.fabricmc.api.Environment; | ||||||
| import net.minecraft.client.item.TooltipContext; | import net.minecraft.client.item.TooltipContext; | ||||||
| @@ -164,8 +164,9 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I | |||||||
|  |  | ||||||
|             if( !stop && computer != null ) |             if( !stop && computer != null ) | ||||||
|             { |             { | ||||||
|                 computer.sendTerminalState( player ); | //                computer.sendTerminalState( player ); | ||||||
|                 new ComputerContainerData( computer ).open( player, new ContainerPocketComputer.Factory( computer, stack, this, hand ) ); |                 boolean isTypingOnly = hand == Hand.OFF_HAND; | ||||||
|  |                 new ComputerContainerData( computer ).open( player, new PocketComputerMenuProvider( computer, stack, this, hand, isTypingOnly ) ); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         return new TypedActionResult<>( ActionResult.SUCCESS, stack ); |         return new TypedActionResult<>( ActionResult.SUCCESS, stack ); | ||||||
|   | |||||||
| @@ -0,0 +1,39 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.shared.util; | ||||||
|  |  | ||||||
|  | import net.minecraft.entity.player.PlayerEntity; | ||||||
|  | import net.minecraft.inventory.Inventory; | ||||||
|  | import net.minecraft.item.ItemStack; | ||||||
|  | import net.minecraft.screen.slot.Slot; | ||||||
|  |  | ||||||
|  | import javax.annotation.Nonnull; | ||||||
|  |  | ||||||
|  | public class InvisibleSlot extends Slot | ||||||
|  | { | ||||||
|  |     public InvisibleSlot(Inventory container, int slot ) | ||||||
|  |     { | ||||||
|  |         super( container, slot, 0, 0 ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public boolean canInsert( @Nonnull ItemStack stack ) | ||||||
|  |     { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public boolean canTakeItems( @Nonnull PlayerEntity player ) | ||||||
|  |     { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public boolean isEnabled() | ||||||
|  |     { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,15 @@ | |||||||
|  | package dan200.computercraft.shared.util; | ||||||
|  |  | ||||||
|  | import javax.annotation.Nonnull; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Equivalent to {@link Supplier}, except with nonnull contract. | ||||||
|  |  * | ||||||
|  |  * @see Supplier | ||||||
|  |  */ | ||||||
|  | @FunctionalInterface | ||||||
|  | public interface NonNullSupplier<T> | ||||||
|  | { | ||||||
|  |     @Nonnull | ||||||
|  |     T get(); | ||||||
|  | } | ||||||
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 287 B | 
		Reference in New Issue
	
	Block a user
	 Nikita Savyolov
					Nikita Savyolov