1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2026-04-19 21:41:23 +00:00

Merge branch 'mc-1.18.x' into mc-1.19.x

This commit is contained in:
Jonathan Coates
2022-10-26 09:49:51 +01:00
477 changed files with 9322 additions and 8139 deletions

View File

@@ -9,8 +9,6 @@ import dan200.computercraft.core.apis.http.options.Action;
import dan200.computercraft.core.apis.http.options.AddressRule;
import dan200.computercraft.shared.Config;
import dan200.computercraft.shared.Registry;
import dan200.computercraft.shared.computer.core.ClientComputerRegistry;
import dan200.computercraft.shared.computer.core.ServerComputerRegistry;
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
import net.minecraftforge.fml.common.Mod;
import org.slf4j.Logger;
@@ -76,11 +74,6 @@ public final class ComputerCraft
public static int monitorWidth = 8;
public static int monitorHeight = 6;
// Registries
public static final ClientComputerRegistry clientComputerRegistry = new ClientComputerRegistry();
public static final ServerComputerRegistry serverComputerRegistry = new ServerComputerRegistry();
// Logging
public static final Logger log = LoggerFactory.getLogger( MOD_ID );
public ComputerCraft()

View File

@@ -5,7 +5,9 @@
*/
package dan200.computercraft;
import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI;
import com.google.auto.service.AutoService;
import dan200.computercraft.api.detail.BlockReference;
import dan200.computercraft.api.detail.DetailRegistry;
import dan200.computercraft.api.detail.IDetailProvider;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
@@ -21,23 +23,30 @@ import dan200.computercraft.core.apis.ApiFactories;
import dan200.computercraft.core.asm.GenericMethod;
import dan200.computercraft.core.filesystem.FileMount;
import dan200.computercraft.core.filesystem.ResourceMount;
import dan200.computercraft.impl.ComputerCraftAPIService;
import dan200.computercraft.impl.detail.DetailRegistryImpl;
import dan200.computercraft.shared.BundledRedstone;
import dan200.computercraft.shared.MediaProviders;
import dan200.computercraft.shared.Peripherals;
import dan200.computercraft.shared.computer.core.ServerContext;
import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider;
import dan200.computercraft.shared.peripheral.generic.data.DetailProviders;
import dan200.computercraft.shared.peripheral.generic.data.BlockData;
import dan200.computercraft.shared.peripheral.generic.data.FluidData;
import dan200.computercraft.shared.peripheral.generic.data.ItemData;
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
import dan200.computercraft.shared.util.IDAssigner;
import dan200.computercraft.shared.wired.WiredNode;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.server.ServerLifecycleHooks;
@@ -48,19 +57,18 @@ import java.io.InputStream;
import static dan200.computercraft.shared.Capabilities.CAPABILITY_WIRED_ELEMENT;
public final class ComputerCraftAPIImpl implements IComputerCraftAPI
@AutoService( ComputerCraftAPIService.class )
public final class ComputerCraftAPIImpl implements ComputerCraftAPIService
{
public static final ComputerCraftAPIImpl INSTANCE = new ComputerCraftAPIImpl();
private final DetailRegistry<ItemStack> itemStackDetails = new DetailRegistryImpl<>( ItemData::fillBasic );
private final DetailRegistry<BlockReference> blockDetails = new DetailRegistryImpl<>( BlockData::fillBasic );
private final DetailRegistry<FluidStack> fluidStackDetails = new DetailRegistryImpl<>( FluidData::fillBasic );
private String version;
private ComputerCraftAPIImpl()
public static InputStream getResourceFile( MinecraftServer server, String domain, String subPath )
{
}
public static InputStream getResourceFile( String domain, String subPath )
{
var manager = ServerLifecycleHooks.getCurrentServer().getResourceManager();
ResourceManager manager = server.getResourceManager();
var resource = manager.getResource( new ResourceLocation( domain, subPath ) ).orElse( null );
if( resource == null ) return null;
try
@@ -86,7 +94,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
@Override
public int createUniqueNumberedSaveDir( @Nonnull Level world, @Nonnull String parentSubPath )
{
return IDAssigner.getNextId( parentSubPath );
return ServerContext.get( world.getServer() ).getNextId( parentSubPath );
}
@Override
@@ -94,7 +102,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
{
try
{
return new FileMount( new File( IDAssigner.getDir(), subPath ), capacity );
return new FileMount( new File( ServerContext.get( world.getServer() ).storageDir().toFile(), subPath ), capacity );
}
catch( Exception e )
{
@@ -160,9 +168,26 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
}
@Override
@Deprecated
@SuppressWarnings( "unchecked" )
public <T> void registerDetailProvider( @Nonnull Class<T> type, @Nonnull IDetailProvider<T> provider )
{
DetailProviders.registerProvider( type, provider );
if( type == ItemStack.class )
{
itemStackDetails.addProvider( (IDetailProvider<ItemStack>) provider );
}
else if( type == BlockReference.class )
{
blockDetails.addProvider( (IDetailProvider<BlockReference>) provider );
}
else if( type == FluidStack.class )
{
itemStackDetails.addProvider( (IDetailProvider<ItemStack>) provider );
}
else
{
throw new IllegalArgumentException( "Unknown detail provider " + type );
}
}
@Nonnull
@@ -179,4 +204,22 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
BlockEntity tile = world.getBlockEntity( pos );
return tile == null ? LazyOptional.empty() : tile.getCapability( CAPABILITY_WIRED_ELEMENT, side );
}
@Override
public DetailRegistry<ItemStack> getItemStackDetailRegistry()
{
return itemStackDetails;
}
@Override
public DetailRegistry<BlockReference> getBlockInWorldDetailRegistry()
{
return blockDetails;
}
@Override
public DetailRegistry<FluidStack> getFluidStackDetailRegistry()
{
return fluidStackDetails;
}
}

View File

@@ -6,6 +6,7 @@
package dan200.computercraft.api;
import dan200.computercraft.api.detail.BlockReference;
import dan200.computercraft.api.detail.DetailRegistry;
import dan200.computercraft.api.detail.IDetailProvider;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
@@ -20,6 +21,7 @@ import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralProvider;
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
import dan200.computercraft.impl.ComputerCraftAPIService;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.ItemStack;
@@ -34,7 +36,7 @@ import javax.annotation.Nullable;
/**
* The static entry point to the ComputerCraft API.
*
* <p>
* Members in this class must be called after mod_ComputerCraft has been initialised, but may be called before it is
* fully loaded.
*/
@@ -50,13 +52,13 @@ public final class ComputerCraftAPI
/**
* Creates a numbered directory in a subfolder of the save directory for a given world, and returns that number.
*
* <p>
* Use in conjunction with createSaveDirMount() to create a unique place for your peripherals or media items to store files.
*
* @param world The world for which the save dir should be created. This should be the server side world object.
* @param parentSubPath The folder path within the save directory where the new directory should be created. eg: "computercraft/disk"
* @return The numerical value of the name of the new folder, or -1 if the folder could not be created for some reason.
*
* <p>
* eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then "computer/disk/42" is now
* available for writing.
* @see #createSaveDirMount(Level, String, long)
@@ -68,7 +70,7 @@ public final class ComputerCraftAPI
/**
* Creates a file system mount that maps to a subfolder of the save directory for a given world, and returns it.
*
* <p>
* Use in conjunction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a folder from the
* users save directory onto a computers file system.
*
@@ -92,10 +94,10 @@ public final class ComputerCraftAPI
/**
* Creates a file system mount to a resource folder, and returns it.
*
* <p>
* Use in conjunction with {@link IComputerAccess#mount} or {@link IComputerAccess#mountWritable} to mount a
* resource folder onto a computer's file system.
*
* <p>
* The files in this mount will be a combination of files in all mod jar, and data packs that contain
* resources with the same domain and path. For instance, ComputerCraft's resources are stored in
* "/data/computercraft/lua/rom". We construct a mount for that with
@@ -208,7 +210,9 @@ public final class ComputerCraftAPI
* {@link FluidStack} or {@link ItemStack}.
* @param provider The detail provider to register.
* @param <T> The type of object that this provider can provide details for.
* @deprecated Use {@link DetailRegistry#addProvider(IDetailProvider)} to register your provider.
*/
@Deprecated
public static <T> void registerDetailProvider( @Nonnull Class<T> type, @Nonnull IDetailProvider<T> provider )
{
getInstance().registerDetailProvider( type, provider );
@@ -242,60 +246,9 @@ public final class ComputerCraftAPI
return getInstance().getWiredElementAt( world, pos, side );
}
private static IComputerCraftAPI instance;
@Nonnull
private static IComputerCraftAPI getInstance()
private static ComputerCraftAPIService getInstance()
{
if( instance != null ) return instance;
try
{
return instance = (IComputerCraftAPI) Class.forName( "dan200.computercraft.ComputerCraftAPIImpl" )
.getField( "INSTANCE" ).get( null );
}
catch( ReflectiveOperationException e )
{
throw new IllegalStateException( "Cannot find ComputerCraft API", e );
}
}
public interface IComputerCraftAPI
{
@Nonnull
String getInstalledVersion();
int createUniqueNumberedSaveDir( @Nonnull Level world, @Nonnull String parentSubPath );
@Nullable
IWritableMount createSaveDirMount( @Nonnull Level world, @Nonnull String subPath, long capacity );
@Nullable
IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath );
void registerPeripheralProvider( @Nonnull IPeripheralProvider provider );
void registerGenericSource( @Nonnull GenericSource source );
void registerGenericCapability( @Nonnull Capability<?> capability );
void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider );
int getBundledRedstoneOutput( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side );
void registerMediaProvider( @Nonnull IMediaProvider provider );
@Nonnull
IPacketNetwork getWirelessNetwork();
void registerAPIFactory( @Nonnull ILuaAPIFactory factory );
<T> void registerDetailProvider( @Nonnull Class<T> type, @Nonnull IDetailProvider<T> provider );
@Nonnull
IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element );
@Nonnull
LazyOptional<IWiredElement> getWiredElementAt( @Nonnull BlockGetter world, @Nonnull BlockPos pos, @Nonnull Direction side );
return ComputerCraftAPIService.get();
}
}

View File

@@ -8,6 +8,7 @@ package dan200.computercraft.api.client;
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
import dan200.computercraft.impl.client.ComputerCraftAPIClientService;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import javax.annotation.Nonnull;
@@ -20,7 +21,7 @@ public final class ComputerCraftAPIClient
/**
* Register a {@link TurtleUpgradeModeller} for a class of turtle upgrades.
*
* <p>
* This may be called at any point after registry creation, though it is recommended to call it within {@link FMLClientSetupEvent}.
*
* @param serialiser The turtle upgrade serialiser.
@@ -32,26 +33,9 @@ public final class ComputerCraftAPIClient
getInstance().registerTurtleUpgradeModeller( serialiser, modeller );
}
private static IComputerCraftAPIClient instance;
@Nonnull
private static IComputerCraftAPIClient getInstance()
private static ComputerCraftAPIClientService getInstance()
{
if( instance != null ) return instance;
try
{
return instance = (IComputerCraftAPIClient) Class.forName( "dan200.computercraft.client.ComputerCraftAPIClientImpl" )
.getField( "INSTANCE" ).get( null );
}
catch( ReflectiveOperationException e )
{
throw new IllegalStateException( "Cannot find ComputerCraft API", e );
}
}
public interface IComputerCraftAPIClient
{
<T extends ITurtleUpgrade> void registerTurtleUpgradeModeller( @Nonnull TurtleUpgradeSerialiser<T> serialiser, @Nonnull TurtleUpgradeModeller<T> modeller );
return ComputerCraftAPIClientService.get();
}
}

View File

@@ -10,6 +10,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import javax.annotation.Nonnull;
@@ -41,6 +42,12 @@ public final class TransformedModel
return new TransformedModel( modelManager.getModel( location ) );
}
public static TransformedModel of( @Nonnull ResourceLocation location )
{
ModelManager modelManager = Minecraft.getInstance().getModelManager();
return new TransformedModel( modelManager.getModel( location ) );
}
public static TransformedModel of( @Nonnull ItemStack item, @Nonnull Transformation transform )
{
BakedModel model = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getItemModel( item );

View File

@@ -12,6 +12,7 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.resources.ResourceLocation;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -26,7 +27,7 @@ public interface TurtleUpgradeModeller<T extends ITurtleUpgrade>
{
/**
* Obtain the model to be used when rendering a turtle peripheral.
*
* <p>
* When the current turtle is {@literal null}, this function should be constant for a given upgrade and side.
*
* @param upgrade The upgrade that you're getting the model for.
@@ -40,7 +41,7 @@ public interface TurtleUpgradeModeller<T extends ITurtleUpgrade>
/**
* A basic {@link TurtleUpgradeModeller} which renders using the upgrade's {@linkplain ITurtleUpgrade#getCraftingItem()
* crafting item}.
*
* <p>
* This uses appropriate transformations for "flat" items, namely those extending the {@literal minecraft:item/generated}
* model type. It will not appear correct for 3D models with additional depth, such as blocks.
*
@@ -65,4 +66,17 @@ public interface TurtleUpgradeModeller<T extends ITurtleUpgrade>
{
return ( upgrade, turtle, side ) -> TransformedModel.of( side == TurtleSide.LEFT ? left : right );
}
/**
* Construct a {@link TurtleUpgradeModeller} which has a single model for the left and right side.
*
* @param left The model to use on the left.
* @param right The model to use on the right.
* @param <T> The type of the turtle upgrade.
* @return The constructed modeller.
*/
static <T extends ITurtleUpgrade> TurtleUpgradeModeller<T> sided( ResourceLocation left, ResourceLocation right )
{
return ( upgrade, turtle, side ) -> TransformedModel.of( side == TurtleSide.LEFT ? left : right );
}
}

View File

@@ -49,7 +49,7 @@ public abstract class BasicItemDetailProvider<T> implements IDetailProvider<Item
/**
* Provide additional details for the given {@link Item} and {@link ItemStack}. This method is called by
* {@code turtle.getItemDetail()}. New properties should be added to the given {@link Map}, {@code data}.
*
* <p>
* This method is always called on the server thread, so it is safe to interact with the world here, but you should
* take care to avoid long blocking operations as this will stall the server and other computers.
*

View File

@@ -0,0 +1,32 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. 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.detail;
import dan200.computercraft.impl.ComputerCraftAPIService;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block;
import net.minecraftforge.fluids.FluidStack;
/**
* {@link DetailRegistry}s for built-in Minecraft types.
*/
public class DetailRegistries
{
/**
* Provides details for {@link ItemStack}s.
*/
public static final DetailRegistry<ItemStack> ITEM_STACK = ComputerCraftAPIService.get().getItemStackDetailRegistry();
/**
* Provides details for {@link BlockReference}, a reference to a {@link Block} in the world.
*/
public static final DetailRegistry<BlockReference> BLOCK_IN_WORLD = ComputerCraftAPIService.get().getBlockInWorldDetailRegistry();
/**
* Provides details for {@link FluidStack}.
*/
public static final DetailRegistry<FluidStack> FLUID_STACK = ComputerCraftAPIService.get().getFluidStackDetailRegistry();
}

View File

@@ -0,0 +1,49 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. 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.detail;
import org.jetbrains.annotations.ApiStatus;
import java.util.Map;
/**
* A registry which provides computer-visible detail about in-game objects such as blocks, items or fluids.
* <p>
* These are used by computer methods such as {@code turtle.getItemDetail()} or {@code turtle.inspect()}.
* <p>
* Specific instances of this registry are available from {@link DetailRegistries} and loader-specific versions
* also in this package.
*
* @param <T> The type of object that this registry provides details for.
*/
@ApiStatus.NonExtendable
public interface DetailRegistry<T>
{
/**
* Registers a detail provider.
*
* @param provider The detail provider to register.
* @see IDetailProvider
*/
void addProvider( IDetailProvider<T> provider );
/**
* Compute basic details about an object. This is cheaper than computing all details operation, and so is suitable
* for when you need to compute the details for a large number of values.
*
* @param object The object to get details for.
* @return The basic details.
*/
Map<String, Object> getBasicDetails( T object );
/**
* Compute all details about an object, using {@link #getBasicDetails(Object)} and any registered providers.
*
* @param object The object to get details for.
* @return The computed details.
*/
Map<String, Object> getDetails( T object );
}

View File

@@ -9,10 +9,13 @@ import javax.annotation.Nonnull;
import java.util.Map;
/**
* This interface is used to provide details about a block, fluid, or item.
* Provide details about a block, fluid, or item.
* <p>
* When implementing this interface, be careful to only expose information the player can see through normal gameplay.
* Computers shouldn't break progression or mechanics of other mods.
*
* @param <T> The type of object that this provider can provide details for.
* @see dan200.computercraft.api.ComputerCraftAPI#registerDetailProvider(Class, IDetailProvider)
* @see DetailRegistry
*/
@FunctionalInterface
public interface IDetailProvider<T>
@@ -21,7 +24,7 @@ public interface IDetailProvider<T>
* Provide additional details for the given object. This method is called by functions such as
* {@code turtle.getItemDetail()} and {@code turtle.inspect()}. New properties should be added to the given
* {@link Map}, {@code data}.
*
* <p>
* This method is always called on the server thread, so it is safe to interact with the world here, but you should
* take care to avoid long blocking operations as this will stall the server and other computers.
*

View File

@@ -11,20 +11,14 @@ import java.time.Instant;
/**
* A simple version of {@link BasicFileAttributes}, which provides what information a {@link IMount} already exposes.
*
* @param isDirectory Whether this filesystem entry is a directory.
* @param size The size of the file.
*/
final class FileAttributes implements BasicFileAttributes
record FileAttributes(boolean isDirectory, long size) implements BasicFileAttributes
{
private static final FileTime EPOCH = FileTime.from( Instant.EPOCH );
private final boolean isDirectory;
private final long size;
FileAttributes( boolean isDirectory, long size )
{
this.isDirectory = isDirectory;
this.size = size;
}
@Override
public FileTime lastModifiedTime()
{
@@ -49,12 +43,6 @@ final class FileAttributes implements BasicFileAttributes
return !isDirectory;
}
@Override
public boolean isDirectory()
{
return isDirectory;
}
@Override
public boolean isSymbolicLink()
{
@@ -67,12 +55,6 @@ final class FileAttributes implements BasicFileAttributes
return false;
}
@Override
public long size()
{
return size;
}
@Override
public Object fileKey()
{

View File

@@ -12,7 +12,7 @@ import java.util.Objects;
/**
* An {@link IOException} which occurred on a specific file.
*
* <p>
* This may be thrown from a {@link IMount} or {@link IWritableMount} to give more information about a failure.
*/
public class FileOperationException extends IOException

View File

@@ -9,7 +9,7 @@ import java.io.IOException;
/**
* Provides a mount of the entire computer's file system.
*
* <p>
* This exists for use by various APIs - one should not attempt to mount it.
*/
public interface IFileSystem extends IWritableMount

View File

@@ -18,7 +18,7 @@ import java.util.List;
/**
* Represents a read only part of a virtual filesystem that can be mounted onto a computer using
* {@link IComputerAccess#mount(String, IMount)}.
*
* <p>
* Ready made implementations of this interface can be created using
* {@link ComputerCraftAPI#createSaveDirMount(Level, String, long)} or
* {@link ComputerCraftAPI#createResourceMount(String, String)}, or you're free to implement it yourselves!

View File

@@ -18,7 +18,7 @@ import java.util.OptionalLong;
/**
* Represents a part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)}
* or {@link IComputerAccess#mountWritable(String, IWritableMount)}, that can also be written to.
*
* <p>
* Ready made implementations of this interface can be created using
* {@link ComputerCraftAPI#createSaveDirMount(Level, String, long)}, or you're free to implement it yourselves!
*

View File

@@ -17,17 +17,17 @@ import javax.annotation.Nonnull;
/**
* A generic source of {@link LuaMethod} functions.
*
* <p>
* Unlike normal objects ({@link IDynamicLuaObject} or {@link IPeripheral}), methods do not target this object but
* instead are defined as {@code static} and accept their target as the first parameter. This allows you to inject
* methods onto objects you do not own, as well as declaring methods for a specific "trait" (for instance, a
* {@link Capability}).
*
* <p>
* Currently the "generic peripheral" system is incompatible with normal peripherals. Normal {@link IPeripheralProvider}
* or {@link IPeripheral} implementations take priority. Tile entities which use this system are given a peripheral name
* determined by their id, rather than any peripheral provider. This will hopefully change in the future, once a suitable
* design has been established.
*
* <p>
* For example, the main CC: Tweaked mod defines a generic source for inventories, which works on {@link IItemHandler}s:
*
* <pre>{@code
@@ -49,7 +49,7 @@ public interface GenericSource
{
/**
* A unique identifier for this generic source.
*
* <p>
* This is currently unused, but may be used in the future to allow disabling specific sources. It is recommended
* to return an identifier using your mod's ID.
*

View File

@@ -69,8 +69,8 @@ public interface IArguments
default double getDouble( int index ) throws LuaException
{
Object value = get( index );
if( !(value instanceof Number) ) throw LuaValues.badArgumentOf( index, "number", value );
return ((Number) value).doubleValue();
if( !(value instanceof Number number) ) throw LuaValues.badArgumentOf( index, "number", value );
return number.doubleValue();
}
/**
@@ -95,8 +95,8 @@ public interface IArguments
default long getLong( int index ) throws LuaException
{
Object value = get( index );
if( !(value instanceof Number) ) throw LuaValues.badArgumentOf( index, "number", value );
return LuaValues.checkFiniteNum( index, (Number) value ).longValue();
if( !(value instanceof Number number) ) throw LuaValues.badArgumentOf( index, "number", value );
return LuaValues.checkFiniteNum( index, number ).longValue();
}
/**
@@ -121,8 +121,8 @@ public interface IArguments
default boolean getBoolean( int index ) throws LuaException
{
Object value = get( index );
if( !(value instanceof Boolean) ) throw LuaValues.badArgumentOf( index, "boolean", value );
return (Boolean) value;
if( !(value instanceof Boolean bool) ) throw LuaValues.badArgumentOf( index, "boolean", value );
return bool;
}
/**
@@ -136,8 +136,8 @@ public interface IArguments
default String getString( int index ) throws LuaException
{
Object value = get( index );
if( !(value instanceof String) ) throw LuaValues.badArgumentOf( index, "string", value );
return (String) value;
if( !(value instanceof String string) ) throw LuaValues.badArgumentOf( index, "string", value );
return string;
}
/**
@@ -185,7 +185,7 @@ public interface IArguments
/**
* Get an argument as a table in an unsafe manner.
*
* <p>
* Classes implementing this interface may choose to implement a more optimised version which does not copy the
* table, instead returning a wrapper version, making it more efficient. However, the caller must guarantee that
* they do not access the table the computer thread (and so should not be used with main-thread functions) or once
@@ -213,8 +213,8 @@ public interface IArguments
{
Object value = get( index );
if( value == null ) return Optional.empty();
if( !(value instanceof Number) ) throw LuaValues.badArgumentOf( index, "number", value );
return Optional.of( ((Number) value).doubleValue() );
if( !(value instanceof Number number) ) throw LuaValues.badArgumentOf( index, "number", value );
return Optional.of( number.doubleValue() );
}
/**
@@ -241,8 +241,8 @@ public interface IArguments
{
Object value = get( index );
if( value == null ) return Optional.empty();
if( !(value instanceof Number) ) throw LuaValues.badArgumentOf( index, "number", value );
return Optional.of( LuaValues.checkFiniteNum( index, (Number) value ).longValue() );
if( !(value instanceof Number number) ) throw LuaValues.badArgumentOf( index, "number", value );
return Optional.of( LuaValues.checkFiniteNum( index, number ).longValue() );
}
/**
@@ -270,8 +270,8 @@ public interface IArguments
{
Object value = get( index );
if( value == null ) return Optional.empty();
if( !(value instanceof Boolean) ) throw LuaValues.badArgumentOf( index, "boolean", value );
return Optional.of( (Boolean) value );
if( !(value instanceof Boolean bool) ) throw LuaValues.badArgumentOf( index, "boolean", value );
return Optional.of( bool );
}
/**
@@ -285,8 +285,8 @@ public interface IArguments
{
Object value = get( index );
if( value == null ) return Optional.empty();
if( !(value instanceof String) ) throw LuaValues.badArgumentOf( index, "string", value );
return Optional.of( (String) value );
if( !(value instanceof String string) ) throw LuaValues.badArgumentOf( index, "string", value );
return Optional.of( string );
}
/**
@@ -334,7 +334,7 @@ public interface IArguments
/**
* Get an argument as a table in an unsafe manner.
*
* <p>
* Classes implementing this interface may choose to implement a more optimised version which does not copy the
* table, instead returning a wrapper version, making it more efficient. However, the caller must guarantee that
* they do not access off the computer thread (and so should not be used with main-thread functions) or once the

View File

@@ -11,7 +11,7 @@ import javax.annotation.Nonnull;
/**
* An interface for representing custom objects returned by peripherals or other Lua objects.
*
* <p>
* Generally, one does not need to implement this type - it is sufficient to return an object with some methods
* annotated with {@link LuaFunction}. {@link IDynamicLuaObject} is useful when you wish your available methods to
* change at runtime.

View File

@@ -10,7 +10,7 @@ import dan200.computercraft.api.ComputerCraftAPI;
/**
* Represents a Lua object which is stored as a global variable on computer startup. This must either provide
* {@link LuaFunction} annotated functions or implement {@link IDynamicLuaObject}.
*
* <p>
* Before implementing this interface, consider alternative methods of providing methods. It is generally preferred
* to use peripherals to provide functionality to users.
*
@@ -28,7 +28,7 @@ public interface ILuaAPI
/**
* Called when the computer is turned on.
*
* <p>
* One should only interact with the file system.
*/
default void startup()
@@ -44,7 +44,7 @@ public interface ILuaAPI
/**
* Called when the computer is turned off or unloaded.
*
* <p>
* This should reset the state of the object, disposing any remaining file handles, or other resources.
*/
default void shutdown()

View File

@@ -17,7 +17,7 @@ public interface ILuaContext
* Queue a task to be executed on the main server thread at the beginning of next tick, but do not wait for it to
* complete. This should be used when you need to interact with the world in a thread-safe manner but do not care
* about the result or you wish to run asynchronously.
*
* <p>
* 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 error message if it failed.
*
@@ -31,7 +31,7 @@ public interface ILuaContext
/**
* 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.
*
* <p>
* 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.
*

View File

@@ -14,7 +14,7 @@ import java.util.Optional;
/**
* Used to mark a Java function which is callable from Lua.
*
* <p>
* Methods annotated with {@link LuaFunction} must be public final instance methods. They can have any number of
* parameters, but they must be of the following types:
*
@@ -24,12 +24,12 @@ import java.util.Optional;
* <li>
* Alternatively, one may specify the desired arguments as normal parameters and the argument parsing code will
* be generated automatically.
*
* <p>
* Each parameter must be one of the given types supported by {@link IArguments} (for instance, {@link int} or
* {@link Map}). Optional values are supported by accepting a parameter of type {@link Optional}.
* </li>
* </ul>
*
* <p>
* This function may return {@link MethodResult}. However, if you simply return a value (rather than having to yield),
* you may return {@code void}, a single value (either an object or a primitive like {@code int}) or array of objects.
* These will be treated the same as {@link MethodResult#of()}, {@link MethodResult#of(Object)} and
@@ -58,7 +58,7 @@ public @interface LuaFunction
/**
* Allow using "unsafe" arguments, such {@link IArguments#getTableUnsafe(int)}.
*
* <p>
* This is incompatible with {@link #mainThread()}.
*
* @return Whether this function supports unsafe arguments.

View File

@@ -35,9 +35,8 @@ public interface LuaTable<K, V> extends Map<K, V>
default long getLong( int index ) throws LuaException
{
Object value = get( (double) index );
if( !(value instanceof Number) ) throw badTableItem( index, "number", getType( value ) );
if( !(value instanceof Number number) ) throw badTableItem( index, "number", getType( value ) );
Number number = (Number) value;
double asDouble = number.doubleValue();
if( !Double.isFinite( asDouble ) ) throw badTableItem( index, "number", getNumericType( asDouble ) );
return number.longValue();
@@ -53,9 +52,8 @@ public interface LuaTable<K, V> extends Map<K, V>
default long getLong( String key ) throws LuaException
{
Object value = get( key );
if( !(value instanceof Number) ) throw badField( key, "number", getType( value ) );
if( !(value instanceof Number number) ) throw badField( key, "number", getType( value ) );
Number number = (Number) value;
double asDouble = number.doubleValue();
if( !Double.isFinite( asDouble ) ) throw badField( key, "number", getNumericType( asDouble ) );
return number.longValue();

View File

@@ -16,7 +16,7 @@ import java.util.Objects;
/**
* The result of invoking a Lua method.
*
* <p>
* Method results either return a value immediately ({@link #of(Object...)} or yield control to the parent coroutine.
* When the current coroutine is resumed, we invoke the provided {@link ILuaCallback#resume(Object[])} callback.
*/
@@ -55,11 +55,11 @@ public final class MethodResult
/**
* Return a single value immediately.
*
* <p>
* Integers, doubles, floats, strings, booleans, {@link Map}, {@link Collection}s, arrays and {@code null} will be
* converted to their corresponding Lua type. {@code byte[]} and {@link ByteBuffer} will be treated as binary
* strings. {@link ILuaFunction} will be treated as a function.
*
* <p>
* In order to provide a custom object with methods, one may return a {@link IDynamicLuaObject}, or an arbitrary
* class with {@link LuaFunction} annotations. Anything else will be converted to {@code nil}.
*

View File

@@ -16,7 +16,7 @@ import javax.annotation.Nullable;
/**
* Represents an item that can be placed in a disk drive and used by a Computer.
*
* <p>
* Implement this interface on your {@link Item} class to allow it to be used in the drive. Alternatively, register
* a {@link IMediaProvider}.
*/

View File

@@ -33,7 +33,7 @@ public interface IPacketReceiver
/**
* Get the maximum distance this receiver can send and receive messages.
*
* <p>
* When determining whether a receiver can receive a message, the largest distance of the packet and receiver is
* used - ensuring it is within range. If the packet or receiver is inter-dimensional, then the packet will always
* be received.
@@ -47,7 +47,7 @@ public interface IPacketReceiver
/**
* Determine whether this receiver can receive packets from other dimensions.
*
* <p>
* A device will receive an inter-dimensional packet if either it or the sending device is inter-dimensional.
*
* @return Whether this receiver receives packets from other dimensions.

View File

@@ -11,11 +11,11 @@ import javax.annotation.Nonnull;
/**
* An object which may be part of a wired network.
*
* <p>
* Elements should construct a node using {@link ComputerCraftAPI#createWiredNodeForElement(IWiredElement)}. This acts
* as a proxy for all network objects. Whilst the node may change networks, an element's node should remain constant
* for its lifespan.
*
* <p>
* Elements are generally tied to a block or tile entity in world. In such as case, one should provide the
* {@link IWiredElement} capability for the appropriate sides.
*/

View File

@@ -13,12 +13,12 @@ import java.util.Map;
/**
* A wired network is composed of one of more {@link IWiredNode}s, a set of connections between them, and a series
* of peripherals.
*
* <p>
* Networks from a connected graph. This means there is some path between all nodes on the network. Further more, if
* there is some path between two nodes then they must be on the same network. {@link IWiredNetwork} will automatically
* handle the merging and splitting of networks (and thus changing of available nodes and peripherals) as connections
* change.
*
* <p>
* This does mean one can not rely on the network remaining consistent between subsequent operations. Consequently,
* it is generally preferred to use the methods provided by {@link IWiredNode}.
*
@@ -28,7 +28,7 @@ public interface IWiredNetwork
{
/**
* Create a connection between two nodes.
*
* <p>
* This should only be used on the server thread.
*
* @param left The first node to connect
@@ -43,7 +43,7 @@ public interface IWiredNetwork
/**
* Destroy a connection between this node and another.
*
* <p>
* This should only be used on the server thread.
*
* @param left The first node in the connection.
@@ -58,7 +58,7 @@ public interface IWiredNetwork
/**
* Sever all connections this node has, removing it from this network.
*
* <p>
* This should only be used on the server thread. You should only call this on nodes
* that your network element owns.
*
@@ -72,7 +72,7 @@ public interface IWiredNetwork
/**
* Update the peripherals a node provides.
*
* <p>
* This should only be used on the server thread. You should only call this on nodes
* that your network element owns.
*

View File

@@ -13,14 +13,14 @@ import java.util.Map;
/**
* Wired nodes act as a layer between {@link IWiredElement}s and {@link IWiredNetwork}s.
*
* <p>
* Firstly, a node acts as a packet network, capable of sending and receiving modem messages to connected nodes. These
* methods may be safely used on any thread.
*
* <p>
* When sending a packet, the system will attempt to find the shortest path between the two nodes based on their
* element's position. Note that packet senders and receivers can have different locations from their associated
* element: the distance between the two will be added to the total packet's distance.
*
* <p>
* Wired nodes also provide several convenience methods for interacting with a wired network. These should only ever
* be used on the main server thread.
*/
@@ -37,7 +37,7 @@ public interface IWiredNode extends IPacketNetwork
/**
* The network this node is currently connected to. Note that this may change
* after any network operation, so it should not be cached.
*
* <p>
* This should only be used on the server thread.
*
* @return This node's network.
@@ -47,7 +47,7 @@ public interface IWiredNode extends IPacketNetwork
/**
* Create a connection from this node to another.
*
* <p>
* This should only be used on the server thread.
*
* @param node The other node to connect to.
@@ -62,7 +62,7 @@ public interface IWiredNode extends IPacketNetwork
/**
* Destroy a connection between this node and another.
*
* <p>
* This should only be used on the server thread.
*
* @param node The other node to disconnect from.
@@ -78,7 +78,7 @@ public interface IWiredNode extends IPacketNetwork
/**
* Sever all connections this node has, removing it from this network.
*
* <p>
* This should only be used on the server thread. You should only call this on nodes
* that your network element owns.
*
@@ -94,7 +94,7 @@ public interface IWiredNode extends IPacketNetwork
/**
* Mark this node's peripherals as having changed.
*
* <p>
* This should only be used on the server thread. You should only call this on nodes
* that your network element owns.
*

View File

@@ -11,7 +11,7 @@ import javax.annotation.Nonnull;
/**
* An object on a {@link IWiredNetwork} capable of sending packets.
*
* <p>
* Unlike a regular {@link IPacketSender}, this must be associated with the node you are attempting to
* to send the packet from.
*/
@@ -19,7 +19,7 @@ public interface IWiredSender extends IPacketSender
{
/**
* The node in the network representing this object.
*
* <p>
* This should be used as a proxy for the main network. One should send packets
* and register receivers through this object.
*

View File

@@ -13,7 +13,7 @@ import javax.annotation.Nonnull;
/**
* A {@link GenericSource} which provides methods for a peripheral.
*
* <p>
* Unlike a {@link GenericSource}, all methods <strong>should</strong> target the same type, for instance a
* {@link BlockEntity} subclass or a capability interface. This is not currently enforced.
*/
@@ -21,13 +21,13 @@ public interface GenericPeripheral extends GenericSource
{
/**
* Get the type of the exposed peripheral.
*
* <p>
* Unlike normal {@link IPeripheral}s, {@link GenericPeripheral} do not have to have a type. By default, the
* resulting peripheral uses the resource name of the wrapped {@link BlockEntity} (for instance {@code minecraft:chest}).
*
* <p>
* However, in some cases it may be more appropriate to specify a more readable name. Overriding this method allows
* you to do so.
*
* <p>
* When multiple {@link GenericPeripheral}s return a non-empty peripheral type for a single tile entity, the
* lexicographically smallest will be chosen. In order to avoid this conflict, this method should only be
* implemented when your peripheral targets a single tile entity <strong>AND</strong> it's likely that you're the

View File

@@ -105,11 +105,11 @@ public interface IComputerAccess
/**
* Unmounts a directory previously mounted onto the computers file system by {@link #mount(String, IMount)}
* or {@link #mountWritable(String, IWritableMount)}.
*
* <p>
* When a directory is unmounted, it will disappear from the computers file system, and the user will no longer be
* able to access it. All directories mounted by a mount or mountWritable are automatically unmounted when the
* peripheral is attached if they have not been explicitly unmounted.
*
* <p>
* Note that you cannot unmount another peripheral's mounts.
*
* @param location The desired location in the computers file system of the directory to unmount.
@@ -124,7 +124,7 @@ public interface IComputerAccess
/**
* Returns the numerical ID of this computer.
*
* <p>
* This is the same number obtained by calling {@code os.getComputerID()} or running the "id" program from lua,
* and is guaranteed unique. This number will be positive.
*
@@ -145,7 +145,7 @@ public interface IComputerAccess
* @param arguments In addition to a name, you may pass an array of extra arguments to the event, that will
* be supplied as extra return values to os.pullEvent(). Objects in the array will be converted
* to lua data types in the same fashion as the return values of IPeripheral.callMethod().
*
* <p>
* You may supply {@code null} to indicate that no arguments are to be supplied.
* @throws NotAttachedException If the peripheral has been detached.
* @see MethodResult#pullEvent(String, ILuaCallback)
@@ -167,7 +167,7 @@ public interface IComputerAccess
/**
* Get a set of peripherals that this computer access can "see", along with their attachment name.
*
* <p>
* This may include other peripherals on the wired network or peripherals on other sides of the computer.
*
* @return All reachable peripherals
@@ -191,12 +191,12 @@ public interface IComputerAccess
/**
* Get a {@link IWorkMonitor} for tasks your peripheral might execute on the main (server) thread.
*
* <p>
* This should be used to ensure your peripheral integrates with ComputerCraft's monitoring and limiting of how much
* server time each computer consumes. You should not need to use this if you use
* {@link ILuaContext#issueMainThreadTask(ILuaTask)} - this is intended for mods with their own system for running
* work on the main thread.
*
* <p>
* Please note that the returned implementation is <em>not</em> thread-safe, and should only be used from the main
* thread.
*

View File

@@ -11,7 +11,7 @@ import javax.annotation.Nonnull;
/**
* A peripheral whose methods are not known at runtime.
*
* <p>
* This behaves similarly to {@link IDynamicLuaObject}, though also accepting the current {@link IComputerAccess}.
* Generally one may use {@link LuaFunction} instead of implementing this interface.
*/
@@ -30,7 +30,7 @@ public interface IDynamicPeripheral extends IPeripheral
/**
* This is called when a lua program on an attached computer calls {@code peripheral.call()} with
* one of the methods exposed by {@link #getMethodNames()}.
*
* <p>
* Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe when interacting
* with Minecraft objects.
*

View File

@@ -15,10 +15,10 @@ import java.util.Set;
/**
* The interface that defines a peripheral.
*
* <p>
* In order to expose a peripheral for your block or tile entity, you may either attach a {@link Capability}, or
* register a {@link IPeripheralProvider}. This <em>cannot</em> be implemented {@link IPeripheral} directly on the tile.
*
* <p>
* Peripherals should provide a series of methods to the user, either using {@link LuaFunction} or by implementing
* {@link IDynamicPeripheral}.
*/
@@ -47,15 +47,15 @@ public interface IPeripheral
/**
* Is called when when a computer is attaching to the peripheral.
*
* <p>
* This will occur when a peripheral is placed next to an active computer, when a computer is turned on next to a
* peripheral, when a turtle travels into a square next to a peripheral, or when a wired modem adjacent to this
* peripheral is does any of the above.
*
* <p>
* Between calls to attach and {@link #detach}, the attached computer can make method calls on the peripheral using
* {@code peripheral.call()}. This method can be used to keep track of which computers are attached to the
* peripheral, or to take action when attachment occurs.
*
* <p>
* Be aware that will be called from both the server thread and ComputerCraft Lua thread, and so must be thread-safe
* and reentrant.
*
@@ -69,14 +69,14 @@ public interface IPeripheral
/**
* Called when a computer is detaching from the peripheral.
*
* <p>
* This will occur when a computer shuts down, when the peripheral is removed while attached to computers, when a
* turtle moves away from a block attached to a peripheral, or when a wired modem adjacent to this peripheral is
* detached.
*
* <p>
* This method can be used to keep track of which computers are attached to the peripheral, or to take action when
* detachment occurs.
*
* <p>
* Be aware that this will be called from both the server and ComputerCraft Lua thread, and must be thread-safe
* and reentrant.
*
@@ -102,7 +102,7 @@ public interface IPeripheral
/**
* Determine whether this peripheral is equivalent to another one.
*
* <p>
* The minimal example should at least check whether they are the same object. However, you may wish to check if
* they point to the same block or tile entity.
*

View File

@@ -15,7 +15,7 @@ import javax.annotation.Nonnull;
/**
* This interface is used to create peripheral implementations for blocks.
*
* <p>
* If you have a {@link BlockEntity} which acts as a peripheral, you may alternatively expose the {@link IPeripheral}
* capability.
*

View File

@@ -12,14 +12,14 @@ import java.util.concurrent.TimeUnit;
/**
* Monitors "work" associated with a computer, keeping track of how much a computer has done, and ensuring every
* computer receives a fair share of any processing time.
*
* <p>
* This is primarily intended for work done by peripherals on the main thread (such as on a tile entity's tick), but
* could be used for other purposes (such as complex computations done on another thread).
*
* <p>
* Before running a task, one should call {@link #canWork()} to determine if the computer is currently allowed to
* execute work. If that returns true, you should execute the task and use {@link #trackWork(long, TimeUnit)} to inform
* the monitor how long that task took.
*
* <p>
* Alternatively, use {@link #runWork(Runnable)} to run and keep track of work.
*
* @see IComputerAccess#getMainThreadMonitor()
@@ -35,7 +35,7 @@ public interface IWorkMonitor
/**
* If the owning computer is currently allowed to execute work, and has ample time to do so.
*
* <p>
* This is effectively a more restrictive form of {@link #canWork()}. One should use that in order to determine if
* you may do an initial piece of work, and shouldWork to determine if any additional task may be performed.
*

View File

@@ -16,7 +16,7 @@ import java.util.Set;
/**
* The type of a {@link GenericPeripheral}.
*
* <p>
* When determining the final type of the resulting peripheral, the union of all types is taken, with the
* lexicographically smallest non-empty name being chosen.
*/

View File

@@ -13,7 +13,7 @@ import javax.annotation.Nonnull;
/**
* A base class for {@link IPocketUpgrade}s.
*
* <p>
* One does not have to use this, but it does provide a convenient template.
*/
public abstract class AbstractPocketUpgrade implements IPocketUpgrade

View File

@@ -21,7 +21,7 @@ public interface IPocketAccess
{
/**
* Gets the entity holding this item.
*
* <p>
* This must be called on the server thread.
*
* @return The holding entity, or {@code null} if none exists.
@@ -67,7 +67,7 @@ public interface IPocketAccess
/**
* Get the upgrade-specific NBT.
*
* <p>
* This is persisted between computer reboots and chunk loads.
*
* @return The upgrade's NBT.

View File

@@ -14,10 +14,10 @@ import javax.annotation.Nullable;
/**
* A peripheral which can be equipped to the back side of a pocket computer.
*
* <p>
* Pocket upgrades are defined in two stages. First, on creates a {@link IPocketUpgrade} subclass and corresponding
* {@link PocketUpgradeSerialiser} instance, which are then registered in a Forge registry.
*
* <p>
* You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
* the upgrade registered internally. See the documentation in {@link PocketUpgradeSerialiser} for details on this process
* and where files should be located.
@@ -28,7 +28,7 @@ public interface IPocketUpgrade extends IUpgradeBase
{
/**
* Creates a peripheral for the pocket computer.
*
* <p>
* The peripheral created will be stored for the lifetime of the upgrade, will be passed an argument to
* {@link #update(IPocketAccess, IPeripheral)} and will be attached, detached and have methods called in the same
* manner as an ordinary peripheral.

View File

@@ -14,7 +14,7 @@ import java.util.function.Consumer;
/**
* A data provider to generate pocket computer upgrades.
*
* <p>
* This should be subclassed and registered to a {@link DataGenerator}. Override the {@link #addUpgrades(Consumer)} function,
* construct each upgrade, and pass them off to the provided consumer to generate them.
*

View File

@@ -25,7 +25,7 @@ import java.util.function.Function;
/**
* Reads a {@link IPocketUpgrade} from disk and reads/writes it to a network packet.
*
* <p>
* This follows the same format as {@link dan200.computercraft.api.turtle.TurtleUpgradeSerialiser} - consult the
* documentation there for more information.
*
@@ -37,7 +37,7 @@ public interface PocketUpgradeSerialiser<T extends IPocketUpgrade> extends Upgra
{
/**
* The ID for the associated registry.
*
* <p>
* This is largely intended for use with Forge Registry methods/classes, such as {@link DeferredRegister} and
* {@link RegistryManager#getRegistry(ResourceKey)}.
*
@@ -59,7 +59,7 @@ public interface PocketUpgradeSerialiser<T extends IPocketUpgrade> extends Upgra
/**
* Create an upgrade serialiser for a simple upgrade. This is similar to a {@link SimpleRecipeSerializer}, but for
* upgrades.
*
* <p>
* If you might want to vary the item, it's suggested you use {@link #simpleWithCustomItem(BiFunction)} instead.
*
* @param factory Generate a new upgrade with a specific ID.
@@ -69,7 +69,7 @@ public interface PocketUpgradeSerialiser<T extends IPocketUpgrade> extends Upgra
@Nonnull
static <T extends IPocketUpgrade> PocketUpgradeSerialiser<T> simple( @Nonnull Function<ResourceLocation, T> factory )
{
class Impl extends SimpleSerialiser<T> implements PocketUpgradeSerialiser<T>
final class Impl extends SimpleSerialiser<T> implements PocketUpgradeSerialiser<T>
{
private Impl( Function<ResourceLocation, T> constructor )
{
@@ -92,7 +92,7 @@ public interface PocketUpgradeSerialiser<T extends IPocketUpgrade> extends Upgra
@Nonnull
static <T extends IPocketUpgrade> PocketUpgradeSerialiser<T> simpleWithCustomItem( @Nonnull BiFunction<ResourceLocation, ItemStack, T> factory )
{
class Impl extends SerialiserWithCraftingItem<T> implements PocketUpgradeSerialiser<T>
final class Impl extends SerialiserWithCraftingItem<T> implements PocketUpgradeSerialiser<T>
{
private Impl( BiFunction<ResourceLocation, ItemStack, T> factory )
{

View File

@@ -13,7 +13,7 @@ import javax.annotation.Nonnull;
/**
* A base class for {@link ITurtleUpgrade}s.
*
* <p>
* One does not have to use this, but it does provide a convenient template.
*/
public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade

View File

@@ -22,7 +22,7 @@ import javax.annotation.Nullable;
/**
* The interface passed to turtle by turtles, providing methods that they can call.
*
* <p>
* This should not be implemented by your classes. Do not interact with turtles except via this interface and
* {@link ITurtleUpgrade}.
*/
@@ -46,7 +46,7 @@ public interface ITurtleAccess
/**
* Attempt to move this turtle to a new position.
*
* <p>
* This will preserve the turtle's internal state, such as it's inventory, computer and upgrades. It should
* be used before playing a movement animation using {@link #playAnimation(TurtleAnimation)}.
*
@@ -144,7 +144,7 @@ public interface ITurtleAccess
/**
* Get the inventory of this turtle.
*
* <p>
* Note: this inventory should only be accessed and modified on the server thread.
*
* @return This turtle's inventory
@@ -155,7 +155,7 @@ public interface ITurtleAccess
/**
* Get the inventory of this turtle as an {@link IItemHandlerModifiable}.
*
* <p>
* Note: this inventory should only be accessed and modified on the server thread.
*
* @return This turtle's inventory
@@ -278,7 +278,7 @@ public interface ITurtleAccess
/**
* Get an upgrade-specific NBT compound, which can be used to store arbitrary data.
*
* <p>
* This will be persisted across turtle restarts and chunk loads, as well as being synced to the client. You must
* call {@link #updateUpgradeNBTData(TurtleSide)} after modifying it.
*

View File

@@ -17,7 +17,7 @@ public interface ITurtleCommand
{
/**
* Will be called by the turtle on the main thread when it is time to execute the custom command.
*
* <p>
* The handler should either perform the work of the command, and return success, or return
* failure with an error message to indicate the command cannot be executed at this time.
*

View File

@@ -17,10 +17,10 @@ import javax.annotation.Nullable;
/**
* The primary interface for defining an update for Turtles. A turtle update can either be a new tool, or a new
* peripheral.
*
* <p>
* Turtle upgrades are defined in two stages. First, one creates a {@link ITurtleUpgrade} subclass and corresponding
* {@link TurtleUpgradeSerialiser} instance, which are then registered in a Forge registry.
*
* <p>
* You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
* the upgrade registered internally. See the documentation in {@link TurtleUpgradeSerialiser} for details on this process
* and where files should be located.
@@ -40,7 +40,7 @@ public interface ITurtleUpgrade extends IUpgradeBase
/**
* Will only be called for peripheral upgrades. Creates a peripheral for a turtle being placed using this upgrade.
*
* <p>
* The peripheral created will be stored for the lifetime of the upgrade and will be passed as an argument to
* {@link #update(ITurtleAccess, TurtleSide)}. It will be attached, detached and have methods called in the same
* manner as a Computer peripheral.
@@ -59,7 +59,7 @@ public interface ITurtleUpgrade extends IUpgradeBase
/**
* Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called
* by the turtle, and the tool is required to do some work.
*
* <p>
* Conforming implementations should fire {@link BlockEvent.BreakEvent} for digging {@link AttackEntityEvent}
* for attacking.
*

View File

@@ -7,7 +7,7 @@ package dan200.computercraft.api.turtle;
/**
* An animation a turtle will play between executing commands.
*
* <p>
* Each animation takes 8 ticks to complete unless otherwise specified.
*
* @see ITurtleAccess#playAnimation(TurtleAnimation)

View File

@@ -22,7 +22,7 @@ import java.util.function.Consumer;
/**
* A data provider to generate turtle upgrades.
*
* <p>
* This should be subclassed and registered to a {@link DataGenerator}. Override the {@link #addUpgrades(Consumer)} function,
* construct each upgrade, and pass them off to the provided consumer to generate them.
*

View File

@@ -28,10 +28,10 @@ import java.util.function.Function;
/**
* Reads a {@link ITurtleUpgrade} from disk and reads/writes it to a network packet.
*
* <p>
* These should be registered in a {@link IForgeRegistry} while the game is loading, much like {@link RecipeSerializer}s.
* It is suggested you use a {@link DeferredRegister}.
*
* <p>
* If your turtle upgrade doesn't have any associated configurable parameters (like most upgrades), you can use
* {@link #simple(Function)} or {@link #simpleWithCustomItem(BiFunction)} to create a basic upgrade serialiser.
*
@@ -46,7 +46,7 @@ import java.util.function.Function;
* // Then in your constructor
* SERIALISERS.register( bus );
* }</pre>
*
* <p>
* We can then define a new upgrade using JSON by placing the following in
* {@literal data/<my_mod>/computercraft/turtle_upgrades/<my_upgrade_id>.json}}.
*
@@ -55,7 +55,7 @@ import java.util.function.Function;
* "type": my_mod:my_upgrade",
* }
* }</pre>
*
* <p>
* Finally, we need to register a model for our upgrade. This is done with
* {@link ComputerCraftAPIClient#registerTurtleUpgradeModeller(TurtleUpgradeSerialiser, TurtleUpgradeModeller)}:
*
@@ -63,7 +63,7 @@ import java.util.function.Function;
* // Register our model inside FMLClientSetupEvent
* ComputerCraftAPIClient.registerTurtleUpgradeModeller(MY_UPGRADE.get(), TurtleUpgradeModeller.flatItem())
* }</pre>
*
* <p>
* {@link TurtleUpgradeDataProvider} provides a data provider to aid with generating these JSON files.
*
* @param <T> The type of turtle upgrade this is responsible for serialising.
@@ -75,7 +75,7 @@ public interface TurtleUpgradeSerialiser<T extends ITurtleUpgrade> extends Upgra
{
/**
* The ID for the associated registry.
*
* <p>
* This is largely intended for use with Forge Registry methods/classes, such as {@link DeferredRegister} and
* {@link RegistryManager#getRegistry(ResourceKey)}.
*
@@ -97,7 +97,7 @@ public interface TurtleUpgradeSerialiser<T extends ITurtleUpgrade> extends Upgra
/**
* Create an upgrade serialiser for a simple upgrade. This is similar to a {@link SimpleRecipeSerializer}, but for
* upgrades.
*
* <p>
* If you might want to vary the item, it's suggested you use {@link #simpleWithCustomItem(BiFunction)} instead.
*
* @param factory Generate a new upgrade with a specific ID.
@@ -107,7 +107,7 @@ public interface TurtleUpgradeSerialiser<T extends ITurtleUpgrade> extends Upgra
@Nonnull
static <T extends ITurtleUpgrade> TurtleUpgradeSerialiser<T> simple( @Nonnull Function<ResourceLocation, T> factory )
{
class Impl extends SimpleSerialiser<T> implements TurtleUpgradeSerialiser<T>
final class Impl extends SimpleSerialiser<T> implements TurtleUpgradeSerialiser<T>
{
private Impl( Function<ResourceLocation, T> constructor )
{
@@ -130,7 +130,7 @@ public interface TurtleUpgradeSerialiser<T extends ITurtleUpgrade> extends Upgra
@Nonnull
static <T extends ITurtleUpgrade> TurtleUpgradeSerialiser<T> simpleWithCustomItem( @Nonnull BiFunction<ResourceLocation, ItemStack, T> factory )
{
class Impl extends SerialiserWithCraftingItem<T> implements TurtleUpgradeSerialiser<T>
final class Impl extends SerialiserWithCraftingItem<T> implements TurtleUpgradeSerialiser<T>
{
private Impl( BiFunction<ResourceLocation, ItemStack, T> factory )
{

View File

@@ -14,7 +14,7 @@ import java.util.Objects;
/**
* A base class for all events concerning a turtle. This will only ever constructed and fired on the server side,
* so sever specific methods on {@link ITurtleAccess} are safe to use.
*
* <p>
* You should generally not need to subscribe to this event, preferring one of the more specific classes.
*/
public abstract class TurtleEvent extends Event

View File

@@ -14,7 +14,7 @@ import java.util.Objects;
/**
* Fired when a turtle attempts to refuel from an item.
*
* <p>
* One may use {@link #setHandler(Handler)} to register a custom fuel provider for a given item.
*/
public class TurtleRefuelEvent extends TurtleEvent
@@ -32,7 +32,7 @@ public class TurtleRefuelEvent extends TurtleEvent
/**
* Get the stack we are attempting to refuel from.
*
* <p>
* Do not modify the returned stack - all modifications should be done within the {@link Handler}.
*
* @return The stack to refuel from.
@@ -56,7 +56,7 @@ public class TurtleRefuelEvent extends TurtleEvent
/**
* Set the refuel handler for this stack.
*
* <p>
* You should call this if you can actually refuel from this item, and ideally only if there are no existing
* handlers.
*

View File

@@ -22,7 +22,7 @@ public interface IUpgradeBase
/**
* Gets a unique identifier representing this type of turtle upgrade. eg: "computercraft:wireless_modem"
* or "my_mod:my_upgrade".
*
* <p>
* You should use a unique resource domain to ensure this upgrade is uniquely identified.
* The upgrade will fail registration if an already used ID is specified.
*
@@ -33,7 +33,7 @@ public interface IUpgradeBase
/**
* Return an unlocalised string to describe this type of computer in item names.
*
* <p>
* Examples of built-in adjectives are "Wireless", "Mining" and "Crafty".
*
* @return The localisation key for this upgrade's adjective.
@@ -45,7 +45,7 @@ public interface IUpgradeBase
* Return an item stack representing the type of item that a computer must be crafted
* with to create a version which holds this upgrade. This item stack is also used
* to determine the upgrade given by {@code turtle.equipLeft()} or {@code pocket.equipBack()}
*
* <p>
* This should be constant over a session (or at least a datapack reload). It is recommended
* that you cache the stack too, in order to prevent constructing it every time the method
* is called.
@@ -57,11 +57,11 @@ public interface IUpgradeBase
/**
* Determine if an item is suitable for being used for this upgrade.
*
* <p>
* When un-equipping an upgrade, we return {@link #getCraftingItem()} rather than
* the original stack. In order to prevent people losing items with enchantments (or
* repairing items with non-0 damage), we impose additional checks on the item.
*
* <p>
* The default check requires that any non-capability NBT is exactly the same as the
* crafting item, but this may be relaxed for your upgrade.
*

View File

@@ -16,7 +16,7 @@ import javax.annotation.Nonnull;
/**
* Base interface for upgrade serialisers. This should generally not be implemented directly, instead implementing one
* of {@link TurtleUpgradeSerialiser} or {@link PocketUpgradeSerialiser}.
*
* <p>
* However, it may sometimes be useful to implement this if you have some shared logic between upgrade types.
*
* @param <T> The upgrade that this class can serialise and deserialise.

View File

@@ -6,6 +6,7 @@
package dan200.computercraft.client;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.pocket.ClientPocketComputers;
import dan200.computercraft.client.sound.SpeakerManager;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import net.minecraftforge.api.distmarker.Dist;
@@ -30,12 +31,12 @@ public class ClientHooks
@SubscribeEvent
public static void onLogIn( ClientPlayerNetworkEvent.LoggingIn event )
{
ComputerCraft.clientComputerRegistry.reset();
ClientPocketComputers.reset();
}
@SubscribeEvent
public static void onLogOut( ClientPlayerNetworkEvent.LoggingOut event )
{
ComputerCraft.clientComputerRegistry.reset();
ClientPocketComputers.reset();
}
}

View File

@@ -9,6 +9,7 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.client.ComputerCraftAPIClient;
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
import dan200.computercraft.client.gui.*;
import dan200.computercraft.client.pocket.ClientPocketComputers;
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
import dan200.computercraft.client.render.TileEntityTurtleRenderer;
import dan200.computercraft.client.render.TurtleModelLoader;
@@ -19,13 +20,11 @@ import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import dan200.computercraft.shared.media.items.ItemDisk;
import dan200.computercraft.shared.media.items.ItemTreasureDisk;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.util.Colour;
import net.minecraft.client.gui.screens.MenuScreens;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
import net.minecraft.client.renderer.item.ItemProperties;
import net.minecraft.client.renderer.item.ItemPropertyFunction;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraftforge.api.distmarker.Dist;
@@ -45,24 +44,25 @@ public final class ClientRegistry
{
private static final String[] EXTRA_MODELS = new String[] {
// Turtle upgrades
"turtle_modem_normal_off_left",
"turtle_modem_normal_on_left",
"turtle_modem_normal_off_right",
"turtle_modem_normal_on_right",
"block/turtle_modem_normal_off_left",
"block/turtle_modem_normal_on_left",
"block/turtle_modem_normal_off_right",
"block/turtle_modem_normal_on_right",
"turtle_modem_advanced_off_left",
"turtle_modem_advanced_on_left",
"turtle_modem_advanced_off_right",
"turtle_modem_advanced_on_right",
"turtle_crafting_table_left",
"turtle_crafting_table_right",
"block/turtle_modem_advanced_off_left",
"block/turtle_modem_advanced_on_left",
"block/turtle_modem_advanced_off_right",
"block/turtle_modem_advanced_on_right",
"turtle_speaker_upgrade_left",
"turtle_speaker_upgrade_right",
"block/turtle_crafting_table_left",
"block/turtle_crafting_table_right",
"block/turtle_speaker_left",
"block/turtle_speaker_right",
// Turtle block renderer
"turtle_colour",
"turtle_elf_overlay",
"block/turtle_colour",
"block/turtle_elf_overlay",
};
private ClientRegistry() {}
@@ -78,7 +78,7 @@ public final class ClientRegistry
{
for( String model : EXTRA_MODELS )
{
event.register( new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, model ), "inventory" ) );
event.register( new ResourceLocation( ComputerCraft.MOD_ID, model ) );
}
}
@@ -111,7 +111,7 @@ public final class ClientRegistry
return IColouredItem.getColourBasic( stack );
case 2: // Light colour
{
int light = ItemPocketComputer.getLightState( stack );
int light = ClientPocketComputers.get( stack ).getLightState();
return light == -1 ? Colour.BLACK.getHex() : light;
}
}
@@ -134,12 +134,12 @@ public final class ClientRegistry
BlockEntityRenderers.register( Registry.ModBlockEntities.TURTLE_ADVANCED.get(), TileEntityTurtleRenderer::new );
ComputerCraftAPIClient.registerTurtleUpgradeModeller( Registry.ModTurtleSerialisers.SPEAKER.get(), TurtleUpgradeModeller.sided(
new ModelResourceLocation( "computercraft:turtle_speaker_upgrade_left", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_speaker_upgrade_right", "inventory" )
new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_speaker_left" ),
new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_speaker_right" )
) );
ComputerCraftAPIClient.registerTurtleUpgradeModeller( Registry.ModTurtleSerialisers.WORKBENCH.get(), TurtleUpgradeModeller.sided(
new ModelResourceLocation( "computercraft:turtle_crafting_table_left", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_crafting_table_right", "inventory" )
new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_crafting_table_left" ),
new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_crafting_table_right" )
) );
ComputerCraftAPIClient.registerTurtleUpgradeModeller( Registry.ModTurtleSerialisers.WIRELESS_MODEM_NORMAL.get(), new TurtleModemModeller( false ) );
ComputerCraftAPIClient.registerTurtleUpgradeModeller( Registry.ModTurtleSerialisers.WIRELESS_MODEM_ADVANCED.get(), new TurtleModemModeller( true ) );
@@ -149,7 +149,7 @@ public final class ClientRegistry
registerContainers();
registerItemProperty( "state",
( stack, world, player, random ) -> ItemPocketComputer.getState( stack ).ordinal(),
( stack, world, player, random ) -> ClientPocketComputers.get( stack ).getState().ordinal(),
Registry.ModItems.POCKET_COMPUTER_NORMAL, Registry.ModItems.POCKET_COMPUTER_ADVANCED
);
registerItemProperty( "coloured",
@@ -174,8 +174,8 @@ public final class ClientRegistry
{
// My IDE doesn't think so, but we do actually need these generics.
MenuScreens.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register( Registry.ModContainers.COMPUTER.get(), GuiComputer::create );
MenuScreens.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register( Registry.ModContainers.POCKET_COMPUTER.get(), GuiComputer::createPocket );
MenuScreens.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register( Registry.ModContainers.COMPUTER.get(), GuiComputer::new );
MenuScreens.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register( Registry.ModContainers.POCKET_COMPUTER.get(), GuiComputer::new );
MenuScreens.<ContainerComputerBase, NoTermComputerScreen<ContainerComputerBase>>register( Registry.ModContainers.POCKET_COMPUTER_NO_TERM.get(), NoTermComputerScreen::new );
MenuScreens.register( Registry.ModContainers.TURTLE.get(), GuiTurtle::new );
@@ -183,6 +183,6 @@ public final class ClientRegistry
MenuScreens.register( Registry.ModContainers.DISK_DRIVE.get(), GuiDiskDrive::new );
MenuScreens.register( Registry.ModContainers.PRINTOUT.get(), GuiPrintout::new );
MenuScreens.<ContainerViewComputer, GuiComputer<ContainerViewComputer>>register( Registry.ModContainers.VIEW_COMPUTER.get(), GuiComputer::createView );
MenuScreens.<ContainerViewComputer, GuiComputer<ContainerViewComputer>>register( Registry.ModContainers.VIEW_COMPUTER.get(), GuiComputer::new );
}
}

View File

@@ -5,22 +5,18 @@
*/
package dan200.computercraft.client;
import dan200.computercraft.api.client.ComputerCraftAPIClient;
import com.google.auto.service.AutoService;
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
import dan200.computercraft.impl.client.ComputerCraftAPIClientService;
import javax.annotation.Nonnull;
public final class ComputerCraftAPIClientImpl implements ComputerCraftAPIClient.IComputerCraftAPIClient
@AutoService( ComputerCraftAPIClientService.class )
public final class ComputerCraftAPIClientImpl implements ComputerCraftAPIClientService
{
public static final ComputerCraftAPIClientImpl INSTANCE = new ComputerCraftAPIClientImpl();
private ComputerCraftAPIClientImpl()
{
}
@Override
public <T extends ITurtleUpgrade> void registerTurtleUpgradeModeller( @Nonnull TurtleUpgradeSerialiser<T> serialiser, @Nonnull TurtleUpgradeModeller<T> modeller )
{

View File

@@ -0,0 +1,92 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.gui;
import dan200.computercraft.shared.computer.core.InputHandler;
import dan200.computercraft.shared.computer.menu.ComputerMenu;
import dan200.computercraft.shared.network.NetworkHandler;
import dan200.computercraft.shared.network.server.ComputerActionServerMessage;
import dan200.computercraft.shared.network.server.KeyEventServerMessage;
import dan200.computercraft.shared.network.server.MouseEventServerMessage;
import dan200.computercraft.shared.network.server.QueueEventServerMessage;
import net.minecraft.world.inventory.AbstractContainerMenu;
import javax.annotation.Nullable;
/**
* An {@link InputHandler} which for use on the client.
* <p>
* This queues events on the remote player's open {@link ComputerMenu}
*/
public final class ClientInputHandler implements InputHandler
{
private final AbstractContainerMenu menu;
public ClientInputHandler( AbstractContainerMenu menu )
{
this.menu = menu;
}
@Override
public void turnOn()
{
NetworkHandler.sendToServer( new ComputerActionServerMessage( menu, ComputerActionServerMessage.Action.TURN_ON ) );
}
@Override
public void shutdown()
{
NetworkHandler.sendToServer( new ComputerActionServerMessage( menu, ComputerActionServerMessage.Action.SHUTDOWN ) );
}
@Override
public void reboot()
{
NetworkHandler.sendToServer( new ComputerActionServerMessage( menu, ComputerActionServerMessage.Action.REBOOT ) );
}
@Override
public void queueEvent( String event, @Nullable Object[] arguments )
{
NetworkHandler.sendToServer( new QueueEventServerMessage( menu, event, arguments ) );
}
@Override
public void keyDown( int key, boolean repeat )
{
NetworkHandler.sendToServer( new KeyEventServerMessage( menu, repeat ? KeyEventServerMessage.TYPE_REPEAT : KeyEventServerMessage.TYPE_DOWN, key ) );
}
@Override
public void keyUp( int key )
{
NetworkHandler.sendToServer( new KeyEventServerMessage( menu, KeyEventServerMessage.TYPE_UP, key ) );
}
@Override
public void mouseClick( int button, int x, int y )
{
NetworkHandler.sendToServer( new MouseEventServerMessage( menu, MouseEventServerMessage.TYPE_CLICK, button, x, y ) );
}
@Override
public void mouseUp( int button, int x, int y )
{
NetworkHandler.sendToServer( new MouseEventServerMessage( menu, MouseEventServerMessage.TYPE_UP, button, x, y ) );
}
@Override
public void mouseDrag( int button, int x, int y )
{
NetworkHandler.sendToServer( new MouseEventServerMessage( menu, MouseEventServerMessage.TYPE_DRAG, button, x, y ) );
}
@Override
public void mouseScroll( int direction, int x, int y )
{
NetworkHandler.sendToServer( new MouseEventServerMessage( menu, MouseEventServerMessage.TYPE_SCROLL, direction, x, y ) );
}
}

View File

@@ -10,8 +10,9 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
import dan200.computercraft.client.gui.widgets.DynamicImageButton;
import dan200.computercraft.client.gui.widgets.WidgetTerminal;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.InputHandler;
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
import dan200.computercraft.shared.computer.upload.FileUpload;
import dan200.computercraft.shared.computer.upload.UploadResult;
@@ -41,16 +42,18 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
private static final Component OVERWRITE = Component.translatable( "gui.computercraft.upload.overwrite_button" );
protected WidgetTerminal terminal;
protected final ClientComputer computer;
protected Terminal terminalData;
protected final ComputerFamily family;
protected final InputHandler input;
protected final int sidebarYOffset;
public ComputerScreenBase( T container, Inventory player, Component title, int sidebarYOffset )
{
super( container, player, title );
computer = (ClientComputer) container.getComputer();
terminalData = container.getTerminal();
family = container.getFamily();
input = new ClientInputHandler( menu );
this.sidebarYOffset = sidebarYOffset;
}
@@ -63,7 +66,7 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
minecraft.keyboardHandler.setSendRepeatsToGui( true );
terminal = addRenderableWidget( createTerminal() );
ComputerSidebar.addButtons( this, computer, this::addRenderableWidget, leftPos, topPos + sidebarYOffset );
ComputerSidebar.addButtons( this, menu::isOn, input, this::addRenderableWidget, leftPos, topPos + sidebarYOffset );
setFocused( terminal );
}
@@ -131,7 +134,7 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
{
if( files.isEmpty() ) return;
if( computer == null || !computer.isOn() )
if( !menu.isOn() )
{
alert( UploadResult.FAILED_TITLE, UploadResult.COMPUTER_OFF_MSG );
return;
@@ -187,10 +190,7 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
return;
}
if( toUpload.size() > 0 )
{
UploadFileMessage.send( computer.getInstanceID(), toUpload );
}
if( toUpload.size() > 0 ) UploadFileMessage.send( menu, toUpload, NetworkHandler::sendToServer );
}
public void uploadResult( UploadResult result, Component message )
@@ -219,13 +219,13 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
private void continueUpload()
{
if( minecraft.screen instanceof OptionScreen screen ) screen.disable();
NetworkHandler.sendToServer( new ContinueUploadMessage( computer.getInstanceID(), true ) );
NetworkHandler.sendToServer( new ContinueUploadMessage( menu, true ) );
}
private void cancelUpload()
{
minecraft.setScreen( this );
NetworkHandler.sendToServer( new ContinueUploadMessage( computer.getInstanceID(), false ) );
NetworkHandler.sendToServer( new ContinueUploadMessage( menu, false ) );
}
private void alert( Component title, Component message )

View File

@@ -6,12 +6,10 @@
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.vertex.PoseStack;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
import dan200.computercraft.client.gui.widgets.WidgetTerminal;
import dan200.computercraft.client.render.ComputerBorderRenderer;
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
@@ -22,54 +20,18 @@ import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMA
public final class GuiComputer<T extends ContainerComputerBase> extends ComputerScreenBase<T>
{
private final int termWidth;
private final int termHeight;
private GuiComputer(
T container, Inventory player, Component title, int termWidth, int termHeight
)
public GuiComputer( T container, Inventory player, Component title )
{
super( container, player, title, BORDER );
this.termWidth = termWidth;
this.termHeight = termHeight;
imageWidth = WidgetTerminal.getWidth( termWidth ) + BORDER * 2 + ComputerSidebar.WIDTH;
imageHeight = WidgetTerminal.getHeight( termHeight ) + BORDER * 2;
}
@Nonnull
public static GuiComputer<ContainerComputerBase> create( ContainerComputerBase container, Inventory inventory, Component component )
{
return new GuiComputer<>(
container, inventory, component,
ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight
);
}
@Nonnull
public static GuiComputer<ContainerComputerBase> createPocket( ContainerComputerBase container, Inventory inventory, Component component )
{
return new GuiComputer<>(
container, inventory, component,
ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight
);
}
@Nonnull
public static GuiComputer<ContainerViewComputer> createView( ContainerViewComputer container, Inventory inventory, Component component )
{
return new GuiComputer<>(
container, inventory, component,
container.getWidth(), container.getHeight()
);
imageWidth = WidgetTerminal.getWidth( terminalData.getWidth() ) + BORDER * 2 + ComputerSidebar.WIDTH;
imageHeight = WidgetTerminal.getHeight( terminalData.getHeight() ) + BORDER * 2;
}
@Override
protected WidgetTerminal createTerminal()
{
return new WidgetTerminal( computer,
leftPos + ComputerSidebar.WIDTH + BORDER, topPos + BORDER, termWidth, termHeight
);
return new WidgetTerminal( terminalData, input, leftPos + ComputerSidebar.WIDTH + BORDER, topPos + BORDER );
}
@Override

View File

@@ -43,10 +43,7 @@ public class GuiTurtle extends ComputerScreenBase<ContainerTurtle>
@Override
protected WidgetTerminal createTerminal()
{
return new WidgetTerminal(
computer, leftPos + BORDER + ComputerSidebar.WIDTH, topPos + BORDER,
ComputerCraft.turtleTermWidth, ComputerCraft.turtleTermHeight
);
return new WidgetTerminal( terminalData, input, leftPos + BORDER + ComputerSidebar.WIDTH, topPos + BORDER );
}
@Override

View File

@@ -6,9 +6,8 @@
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.vertex.PoseStack;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.WidgetTerminal;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.gui.Font;
@@ -25,12 +24,14 @@ import java.util.List;
public class NoTermComputerScreen<T extends ContainerComputerBase> extends Screen implements MenuAccess<T>
{
private final T menu;
private final Terminal terminalData;
private WidgetTerminal terminal;
public NoTermComputerScreen( T menu, Inventory player, Component title )
{
super( title );
this.menu = menu;
terminalData = menu.getTerminal();
}
@Nonnull
@@ -53,7 +54,7 @@ public class NoTermComputerScreen<T extends ContainerComputerBase> extends Scree
super.init();
minecraft.keyboardHandler.setSendRepeatsToGui( true );
terminal = addWidget( new WidgetTerminal( (ClientComputer) menu.getComputer(), 0, 0, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ) );
terminal = addWidget( new WidgetTerminal( terminalData, new ClientInputHandler( menu ), 0, 0 ) );
terminal.visible = false;
terminal.active = false;
setFocused( terminal );

View File

@@ -56,7 +56,7 @@ public final class OptionScreen extends Screen
public static Screen unwrap( Screen screen )
{
return screen instanceof OptionScreen ? ((OptionScreen) screen).getOriginalScreen() : screen;
return screen instanceof OptionScreen option ? option.getOriginalScreen() : screen;
}
@Override

View File

@@ -8,7 +8,7 @@ package dan200.computercraft.client.gui.widgets;
import com.mojang.blaze3d.vertex.PoseStack;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.render.ComputerBorderRenderer;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.InputHandler;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.screens.Screen;
@@ -16,6 +16,7 @@ import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import java.util.Arrays;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
/**
@@ -44,15 +45,15 @@ public final class ComputerSidebar
{
}
public static void addButtons( Screen screen, ClientComputer computer, Consumer<AbstractWidget> add, int x, int y )
public static void addButtons( Screen screen, BooleanSupplier isOn, InputHandler input, Consumer<AbstractWidget> add, int x, int y )
{
x += CORNERS_BORDER + 1;
y += CORNERS_BORDER + ICON_MARGIN;
add.accept( new DynamicImageButton(
screen, x, y, ICON_WIDTH, ICON_HEIGHT, () -> computer.isOn() ? 15 : 1, 1, ICON_TEX_Y_DIFF,
TEXTURE, TEX_SIZE, TEX_SIZE, b -> toggleComputer( computer ),
() -> computer.isOn() ? Arrays.asList(
screen, x, y, ICON_WIDTH, ICON_HEIGHT, () -> isOn.getAsBoolean() ? 15 : 1, 1, ICON_TEX_Y_DIFF,
TEXTURE, TEX_SIZE, TEX_SIZE, b -> toggleComputer( isOn, input ),
() -> isOn.getAsBoolean() ? Arrays.asList(
Component.translatable( "gui.computercraft.tooltip.turn_off" ),
Component.translatable( "gui.computercraft.tooltip.turn_off.key" ).withStyle( ChatFormatting.GRAY )
) : Arrays.asList(
@@ -65,7 +66,7 @@ public final class ComputerSidebar
add.accept( new DynamicImageButton(
screen, x, y, ICON_WIDTH, ICON_HEIGHT, 29, 1, ICON_TEX_Y_DIFF,
TEXTURE, TEX_SIZE, TEX_SIZE, b -> computer.queueEvent( "terminate" ),
TEXTURE, TEX_SIZE, TEX_SIZE, b -> input.queueEvent( "terminate" ),
Arrays.asList(
Component.translatable( "gui.computercraft.tooltip.terminate" ),
Component.translatable( "gui.computercraft.tooltip.terminate.key" ).withStyle( ChatFormatting.GRAY )
@@ -92,15 +93,15 @@ public final class ComputerSidebar
);
}
private static void toggleComputer( ClientComputer computer )
private static void toggleComputer( BooleanSupplier isOn, InputHandler input )
{
if( computer.isOn() )
if( isOn.getAsBoolean() )
{
computer.shutdown();
input.shutdown();
}
else
{
computer.turnOn();
input.turnOn();
}
}
}

View File

@@ -10,7 +10,7 @@ import com.mojang.blaze3d.vertex.Tesselator;
import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.InputHandler;
import net.minecraft.SharedConstants;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.AbstractWidget;
@@ -30,7 +30,8 @@ public class WidgetTerminal extends AbstractWidget
{
private static final float TERMINATE_TIME = 0.5f;
private final ClientComputer computer;
private final @Nonnull Terminal terminal;
private final @Nonnull InputHandler computer;
// The positions of the actual terminal
private final int innerX;
@@ -48,16 +49,17 @@ public class WidgetTerminal extends AbstractWidget
private final BitSet keysDown = new BitSet( 256 );
public WidgetTerminal( @Nonnull ClientComputer computer, int x, int y, int termWidth, int termHeight )
public WidgetTerminal( @Nonnull Terminal terminal, @Nonnull InputHandler computer, int x, int y )
{
super( x, y, termWidth * FONT_WIDTH + MARGIN * 2, termHeight * FONT_HEIGHT + MARGIN * 2, Component.empty() );
super( x, y, terminal.getWidth() * FONT_WIDTH + MARGIN * 2, terminal.getHeight() * FONT_HEIGHT + MARGIN * 2, Component.empty() );
this.terminal = terminal;
this.computer = computer;
innerX = x + MARGIN;
innerY = y + MARGIN;
innerWidth = termWidth * FONT_WIDTH;
innerHeight = termHeight * FONT_HEIGHT;
innerWidth = terminal.getWidth() * FONT_WIDTH;
innerHeight = terminal.getHeight() * FONT_HEIGHT;
}
@Override
@@ -170,22 +172,18 @@ public class WidgetTerminal extends AbstractWidget
public boolean mouseClicked( double mouseX, double mouseY, int button )
{
if( !inTermRegion( mouseX, mouseY ) ) return false;
if( !computer.isColour() || button < 0 || button > 2 ) return false;
if( !hasMouseSupport() || button < 0 || button > 2 ) return false;
Terminal term = computer.getTerminal();
if( term != null )
{
int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), terminal.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), terminal.getHeight() - 1 );
computer.mouseClick( button + 1, charX + 1, charY + 1 );
computer.mouseClick( button + 1, charX + 1, charY + 1 );
lastMouseButton = button;
lastMouseX = charX;
lastMouseY = charY;
}
lastMouseButton = button;
lastMouseX = charX;
lastMouseY = charY;
return true;
}
@@ -194,26 +192,22 @@ public class WidgetTerminal extends AbstractWidget
public boolean mouseReleased( double mouseX, double mouseY, int button )
{
if( !inTermRegion( mouseX, mouseY ) ) return false;
if( !computer.isColour() || button < 0 || button > 2 ) return false;
if( !hasMouseSupport() || button < 0 || button > 2 ) return false;
Terminal term = computer.getTerminal();
if( term != null )
int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), terminal.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), terminal.getHeight() - 1 );
if( lastMouseButton == button )
{
int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
if( lastMouseButton == button )
{
computer.mouseUp( lastMouseButton + 1, charX + 1, charY + 1 );
lastMouseButton = -1;
}
lastMouseX = charX;
lastMouseY = charY;
computer.mouseUp( lastMouseButton + 1, charX + 1, charY + 1 );
lastMouseButton = -1;
}
lastMouseX = charX;
lastMouseY = charY;
return false;
}
@@ -221,22 +215,18 @@ public class WidgetTerminal extends AbstractWidget
public boolean mouseDragged( double mouseX, double mouseY, int button, double v2, double v3 )
{
if( !inTermRegion( mouseX, mouseY ) ) return false;
if( !computer.isColour() || button < 0 || button > 2 ) return false;
if( !hasMouseSupport() || button < 0 || button > 2 ) return false;
Terminal term = computer.getTerminal();
if( term != null )
int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), terminal.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), terminal.getHeight() - 1 );
if( button == lastMouseButton && (charX != lastMouseX || charY != lastMouseY) )
{
int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
if( button == lastMouseButton && (charX != lastMouseX || charY != lastMouseY) )
{
computer.mouseDrag( button + 1, charX + 1, charY + 1 );
lastMouseX = charX;
lastMouseY = charY;
}
computer.mouseDrag( button + 1, charX + 1, charY + 1 );
lastMouseX = charX;
lastMouseY = charY;
}
return false;
@@ -246,21 +236,17 @@ public class WidgetTerminal extends AbstractWidget
public boolean mouseScrolled( double mouseX, double mouseY, double delta )
{
if( !inTermRegion( mouseX, mouseY ) ) return false;
if( !computer.isColour() || delta == 0 ) return false;
if( !hasMouseSupport() || delta == 0 ) return false;
Terminal term = computer.getTerminal();
if( term != null )
{
int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), terminal.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), terminal.getHeight() - 1 );
computer.mouseScroll( delta < 0 ? 1 : -1, charX + 1, charY + 1 );
computer.mouseScroll( delta < 0 ? 1 : -1, charX + 1, charY + 1 );
lastMouseX = charX;
lastMouseY = charY;
}
lastMouseX = charX;
lastMouseY = charY;
return true;
}
@@ -270,6 +256,11 @@ public class WidgetTerminal extends AbstractWidget
return active && visible && mouseX >= innerX && mouseY >= innerY && mouseX < innerX + innerWidth && mouseY < innerY + innerHeight;
}
private boolean hasMouseSupport()
{
return terminal.isColour();
}
public void update()
{
if( terminateTimer >= 0 && terminateTimer < TERMINATE_TIME && (terminateTimer += 0.05f) > TERMINATE_TIME )
@@ -315,23 +306,14 @@ public class WidgetTerminal extends AbstractWidget
public void render( @Nonnull PoseStack transform, int mouseX, int mouseY, float partialTicks )
{
if( !visible ) return;
Terminal terminal = computer.getTerminal();
var bufferSource = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() );
var emitter = FixedWidthFontRenderer.toVertexConsumer( transform, bufferSource.getBuffer( RenderTypes.TERMINAL ) );
if( terminal != null )
{
boolean greyscale = !computer.isColour();
FixedWidthFontRenderer.drawTerminal(
emitter,
(float) innerX, (float) innerY, terminal, greyscale, (float) MARGIN, (float) MARGIN, (float) MARGIN, (float) MARGIN
);
}
else
{
FixedWidthFontRenderer.drawEmptyTerminal( emitter, (float) x, (float) y, (float) width, (float) height );
}
FixedWidthFontRenderer.drawTerminal(
emitter,
(float) innerX, (float) innerY, terminal, (float) MARGIN, (float) MARGIN, (float) MARGIN, (float) MARGIN
);
bufferSource.endBatch();
}

View File

@@ -0,0 +1,63 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.pocket;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.computer.items.ItemComputer;
import dan200.computercraft.shared.network.client.PocketComputerDataMessage;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.world.item.ItemStack;
import javax.annotation.Nonnull;
/**
* Maps {@link ServerComputer#getInstanceID()} to locals {@link PocketComputerData}.
* <p>
* This is populated by {@link PocketComputerDataMessage} and accessed when rendering pocket computers
*/
public final class ClientPocketComputers
{
private static final Int2ObjectMap<PocketComputerData> instances = new Int2ObjectOpenHashMap<>();
private ClientPocketComputers()
{
}
public static void reset()
{
instances.clear();
}
public static void remove( int id )
{
instances.remove( id );
}
/**
* Get or create a pocket computer.
*
* @param instanceId The instance ID of the pocket computer.
* @param advanced Whether this computer has an advanced terminal.
* @return The pocket computer data.
*/
@Nonnull
public static PocketComputerData get( int instanceId, boolean advanced )
{
PocketComputerData computer = instances.get( instanceId );
if( computer == null ) instances.put( instanceId, computer = new PocketComputerData( advanced ) );
return computer;
}
@Nonnull
public static PocketComputerData get( ItemStack stack )
{
ComputerFamily family = stack.getItem() instanceof ItemComputer computer ? computer.getFamily() : ComputerFamily.NORMAL;
return get( ItemPocketComputer.getInstanceID( stack ), family != ComputerFamily.NORMAL );
}
}

View File

@@ -0,0 +1,63 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.pocket;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.network.client.TerminalState;
import dan200.computercraft.shared.pocket.core.PocketServerComputer;
import javax.annotation.Nonnull;
/**
* Clientside data about a pocket computer.
* <p>
* Normal computers don't store any state long-term on the client - everything is tied to the container and only synced
* while the UI is open. Pocket computers are a little more complex, as their on/off state is visible on the item's
* texture, and the terminal can be viewed at any time. This class is what holds this needed data clientside.
*
* @see ClientPocketComputers The registry which holds pocket computers.
* @see PocketServerComputer The server-side pocket computer.
*/
public class PocketComputerData
{
private final Terminal terminal;
private ComputerState state = ComputerState.OFF;
private int lightColour = -1;
public PocketComputerData( boolean colour )
{
terminal = new Terminal( ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight, colour );
}
public int getLightState()
{
return state != ComputerState.OFF ? lightColour : -1;
}
@Nonnull
public Terminal getTerminal()
{
return terminal;
}
public ComputerState getState()
{
return state;
}
public void setState( ComputerState state, int lightColour )
{
this.state = state;
this.lightColour = lightColour;
}
public void setTerminal( TerminalState state )
{
state.apply( terminal );
}
}

View File

@@ -10,9 +10,10 @@ import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.pocket.ClientPocketComputers;
import dan200.computercraft.client.pocket.PocketComputerData;
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.util.Colour;
@@ -56,20 +57,11 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
@Override
protected void renderItem( PoseStack transform, MultiBufferSource bufferSource, ItemStack stack, int light )
{
ClientComputer computer = ItemPocketComputer.createClientComputer( stack );
Terminal terminal = computer == null ? null : computer.getTerminal();
PocketComputerData computer = ClientPocketComputers.get( stack );
Terminal terminal = computer.getTerminal();
int termWidth, termHeight;
if( terminal == null )
{
termWidth = ComputerCraft.pocketTermWidth;
termHeight = ComputerCraft.pocketTermHeight;
}
else
{
termWidth = terminal.getWidth();
termHeight = terminal.getHeight();
}
int termWidth = terminal.getWidth();
int termHeight = terminal.getHeight();
int width = termWidth * FONT_WIDTH + MARGIN * 2;
int height = termHeight * FONT_HEIGHT + MARGIN * 2;
@@ -94,24 +86,14 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
renderFrame( matrix, bufferSource, family, frameColour, light, width, height );
// Render the light
int lightColour = ItemPocketComputer.getLightState( stack );
int lightColour = ClientPocketComputers.get( stack ).getLightState();
if( lightColour == -1 ) lightColour = Colour.BLACK.getHex();
renderLight( transform, bufferSource, lightColour, width, height );
if( computer != null && terminal != null )
{
FixedWidthFontRenderer.drawTerminal(
FixedWidthFontRenderer.toVertexConsumer( transform, bufferSource.getBuffer( RenderTypes.TERMINAL ) ),
MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN
);
}
else
{
FixedWidthFontRenderer.drawEmptyTerminal(
FixedWidthFontRenderer.toVertexConsumer( transform, bufferSource.getBuffer( RenderTypes.TERMINAL ) ),
0, 0, width, height
);
}
FixedWidthFontRenderer.drawTerminal(
FixedWidthFontRenderer.toVertexConsumer( transform, bufferSource.getBuffer( RenderTypes.TERMINAL ) ),
MARGIN, MARGIN, terminal, MARGIN, MARGIN, MARGIN, MARGIN
);
transform.popPose();
}

View File

@@ -98,7 +98,7 @@ public class MonitorTextureBufferShader extends ShaderInstance
buffer.limit( pos );
}
public static void setUniformData( ByteBuffer buffer, Terminal terminal, boolean greyscale )
public static void setUniformData( ByteBuffer buffer, Terminal terminal )
{
int pos = 0;
var palette = terminal.getPalette();
@@ -106,7 +106,7 @@ public class MonitorTextureBufferShader extends ShaderInstance
{
{
double[] colour = palette.getColour( i );
if( greyscale )
if( !terminal.isColour() )
{
float f = FixedWidthFontRenderer.toGreyscale( colour );
buffer.putFloat( pos, f ).putFloat( pos + 4, f ).putFloat( pos + 8, f );

View File

@@ -63,7 +63,7 @@ public final class PrintoutRenderer
{
FixedWidthFontRenderer.drawString( emitter,
x, y + line * FONT_HEIGHT, text[start + line], colours[start + line],
Palette.DEFAULT, false, light
Palette.DEFAULT, light
);
}
}
@@ -77,7 +77,7 @@ public final class PrintoutRenderer
FixedWidthFontRenderer.drawString( emitter,
x, y + line * FONT_HEIGHT,
new TextBuffer( text[start + line] ), new TextBuffer( colours[start + line] ),
Palette.DEFAULT, false, light
Palette.DEFAULT, light
);
}
}

View File

@@ -156,7 +156,7 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
DirectBuffers.setBufferData( GL31.GL_TEXTURE_BUFFER, monitor.tboBuffer, terminalBuffer, GL20.GL_STATIC_DRAW );
var uniformBuffer = getBuffer( MonitorTextureBufferShader.UNIFORM_SIZE );
MonitorTextureBufferShader.setUniformData( uniformBuffer, terminal, !monitor.isColour() );
MonitorTextureBufferShader.setUniformData( uniformBuffer, terminal );
DirectBuffers.setBufferData( GL31.GL_UNIFORM_BUFFER, monitor.tboUniform, uniformBuffer, GL20.GL_STATIC_DRAW );
}
@@ -192,13 +192,13 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
// and starting and ending offset, and so need to use two buffers instead.
renderToBuffer( backgroundBuffer, size, sink ->
DirectFixedWidthFontRenderer.drawTerminalBackground( sink, 0, 0, terminal, !monitor.isColour(), yMargin, yMargin, xMargin, xMargin ) );
DirectFixedWidthFontRenderer.drawTerminalBackground( sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin ) );
renderToBuffer( foregroundBuffer, size, sink -> {
DirectFixedWidthFontRenderer.drawTerminalForeground( sink, 0, 0, terminal, !monitor.isColour() );
DirectFixedWidthFontRenderer.drawTerminalForeground( sink, 0, 0, terminal );
// If the cursor is visible, we append it to the end of our buffer. When rendering, we can either
// render n or n+1 quads and so toggle the cursor on and off.
DirectFixedWidthFontRenderer.drawCursor( sink, 0, 0, terminal, !monitor.isColour() );
DirectFixedWidthFontRenderer.drawCursor( sink, 0, 0, terminal );
} );
}

View File

@@ -9,6 +9,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.client.TransformedModel;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
@@ -44,8 +45,8 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
{
private static final ModelResourceLocation NORMAL_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_normal", "inventory" );
private static final ModelResourceLocation ADVANCED_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_advanced", "inventory" );
private static final ModelResourceLocation COLOUR_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_colour", "inventory" );
private static final ModelResourceLocation ELF_OVERLAY_MODEL = new ModelResourceLocation( "computercraft:turtle_elf_overlay", "inventory" );
private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_colour" );
private static final ResourceLocation ELF_OVERLAY_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_elf_overlay" );
private final RandomSource random = RandomSource.create( 0 );
@@ -56,7 +57,7 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
renderer = context.getBlockEntityRenderDispatcher();
}
public static ModelResourceLocation getTurtleModel( ComputerFamily family, boolean coloured )
public static ResourceLocation getTurtleModel( ComputerFamily family, boolean coloured )
{
switch( family )
{
@@ -68,9 +69,9 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
}
}
public static ModelResourceLocation getTurtleOverlayModel( ResourceLocation overlay, boolean christmas )
public static ResourceLocation getTurtleOverlayModel( ResourceLocation overlay, boolean christmas )
{
if( overlay != null ) return new ModelResourceLocation( overlay, "inventory" );
if( overlay != null ) return overlay;
if( christmas ) return ELF_OVERLAY_MODEL;
return null;
}
@@ -125,7 +126,7 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
renderModel( transform, buffer, lightmapCoord, overlayLight, getTurtleModel( family, colour != -1 ), colour == -1 ? null : new int[] { colour } );
// Render the overlay
ModelResourceLocation overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS );
ResourceLocation overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS );
if( overlayModel != null )
{
renderModel( transform, buffer, lightmapCoord, overlayLight, overlayModel, null );
@@ -157,7 +158,7 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
transform.popPose();
}
private void renderModel( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, ModelResourceLocation modelLocation, int[] tints )
private void renderModel( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, ResourceLocation modelLocation, int[] tints )
{
ModelManager modelManager = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getModelManager();
renderModel( transform, renderer, lightmapCoord, overlayLight, modelManager.getModel( modelLocation ), tints );

View File

@@ -17,7 +17,6 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.client.model.BakedModelWrapper;
@@ -100,7 +99,7 @@ public class TurtleSmartItemModel extends BakedModelWrapper<BakedModel>
ArrayList<BakedModel> parts = new ArrayList<>( 4 );
parts.add( new TransformedBakedModel( combo.colour() ? colourModel : familyModel, transformation ) );
ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.overlay(), combo.christmas() );
ResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.overlay(), combo.christmas() );
if( overlayModelLocation != null )
{
parts.add( new TransformedBakedModel( modelManager.getModel( overlayModelLocation ), transformation ) );

View File

@@ -25,14 +25,14 @@ import static org.lwjgl.system.MemoryUtil.*;
/**
* An optimised copy of {@link FixedWidthFontRenderer} emitter emits directly to a {@link QuadEmitter} rather than
* emitting to {@link VertexConsumer}. This allows us to emit vertices very quickly, when using the VBO renderer.
*
* <p>
* There are some limitations here:
* <ul>
* <li>No transformation matrix (not needed for VBOs).</li>
* <li>Only works with {@link DefaultVertexFormat#POSITION_COLOR_TEX_LIGHTMAP}.</li>
* <li>The buffer <strong>MUST</strong> be allocated with {@link MemoryTracker}, and not through any other means.</li>
* </ul>
*
* <p>
* Note this is almost an exact copy of {@link FixedWidthFontRenderer}. While the code duplication is unfortunate,
* it is measurably faster than introducing polymorphism into {@link FixedWidthFontRenderer}.
*
@@ -62,25 +62,25 @@ public final class DirectFixedWidthFontRenderer
);
}
private static void drawQuad( QuadEmitter emitter, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex )
private static void drawQuad( QuadEmitter emitter, float x, float y, float width, float height, Palette palette, char colourIndex )
{
byte[] colour = palette.getByteColour( getColour( colourIndex, Colour.BLACK ), greyscale );
byte[] colour = palette.getRenderColours( getColour( colourIndex, Colour.BLACK ) );
quad( emitter, x, y, x + width, y + height, 0f, colour, BACKGROUND_START, BACKGROUND_START, BACKGROUND_END, BACKGROUND_END );
}
private static void drawBackground(
@Nonnull QuadEmitter emitter, float x, float y, @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale,
@Nonnull QuadEmitter emitter, float x, float y, @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette,
float leftMarginSize, float rightMarginSize, float height
)
{
if( leftMarginSize > 0 )
{
drawQuad( emitter, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) );
drawQuad( emitter, x - leftMarginSize, y, leftMarginSize, height, palette, backgroundColour.charAt( 0 ) );
}
if( rightMarginSize > 0 )
{
drawQuad( emitter, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, greyscale, backgroundColour.charAt( backgroundColour.length() - 1 ) );
drawQuad( emitter, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, backgroundColour.charAt( backgroundColour.length() - 1 ) );
}
// Batch together runs of identical background cells.
@@ -93,7 +93,7 @@ public final class DirectFixedWidthFontRenderer
if( blockColour != '\0' )
{
drawQuad( emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour );
drawQuad( emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, blockColour );
}
blockColour = colourIndex;
@@ -102,15 +102,15 @@ public final class DirectFixedWidthFontRenderer
if( blockColour != '\0' )
{
drawQuad( emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour );
drawQuad( emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, blockColour );
}
}
public static void drawString( @Nonnull QuadEmitter emitter, float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nonnull Palette palette, boolean greyscale )
public static void drawString( @Nonnull QuadEmitter emitter, float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nonnull Palette palette )
{
for( int i = 0; i < text.length(); i++ )
{
byte[] colour = palette.getByteColour( getColour( textColour.charAt( i ), Colour.BLACK ), greyscale );
byte[] colour = palette.getRenderColours( getColour( textColour.charAt( i ), Colour.BLACK ) );
int index = text.charAt( i );
if( index > 255 ) index = '?';
@@ -119,7 +119,7 @@ public final class DirectFixedWidthFontRenderer
}
public static void drawTerminalForeground( @Nonnull QuadEmitter emitter, float x, float y, @Nonnull Terminal terminal, boolean greyscale )
public static void drawTerminalForeground( @Nonnull QuadEmitter emitter, float x, float y, @Nonnull Terminal terminal )
{
Palette palette = terminal.getPalette();
int height = terminal.getHeight();
@@ -130,13 +130,13 @@ public final class DirectFixedWidthFontRenderer
float rowY = y + FONT_HEIGHT * i;
drawString(
emitter, x, rowY, terminal.getLine( i ), terminal.getTextColourLine( i ),
palette, greyscale
palette
);
}
}
public static void drawTerminalBackground(
@Nonnull QuadEmitter emitter, float x, float y, @Nonnull Terminal terminal, boolean greyscale,
@Nonnull QuadEmitter emitter, float x, float y, @Nonnull Terminal terminal,
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
)
{
@@ -145,12 +145,12 @@ public final class DirectFixedWidthFontRenderer
// Top and bottom margins
drawBackground(
emitter, x, y - topMarginSize, terminal.getBackgroundColourLine( 0 ), palette, greyscale,
emitter, x, y - topMarginSize, terminal.getBackgroundColourLine( 0 ), palette,
leftMarginSize, rightMarginSize, topMarginSize
);
drawBackground(
emitter, x, y + height * FONT_HEIGHT, terminal.getBackgroundColourLine( height - 1 ), palette, greyscale,
emitter, x, y + height * FONT_HEIGHT, terminal.getBackgroundColourLine( height - 1 ), palette,
leftMarginSize, rightMarginSize, bottomMarginSize
);
@@ -159,17 +159,17 @@ public final class DirectFixedWidthFontRenderer
{
float rowY = y + FONT_HEIGHT * i;
drawBackground(
emitter, x, rowY, terminal.getBackgroundColourLine( i ), palette, greyscale,
emitter, x, rowY, terminal.getBackgroundColourLine( i ), palette,
leftMarginSize, rightMarginSize, FONT_HEIGHT
);
}
}
public static void drawCursor( @Nonnull QuadEmitter emitter, float x, float y, @Nonnull Terminal terminal, boolean greyscale )
public static void drawCursor( @Nonnull QuadEmitter emitter, float x, float y, @Nonnull Terminal terminal )
{
if( isCursorVisible( terminal ) )
{
byte[] colour = terminal.getPalette().getByteColour( 15 - terminal.getTextColour(), greyscale );
byte[] colour = terminal.getPalette().getRenderColours( 15 - terminal.getTextColour() );
drawChar( emitter, x + terminal.getCursorX() * FONT_WIDTH, y + terminal.getCursorY() * FONT_HEIGHT, '_', colour );
}
}

View File

@@ -22,7 +22,7 @@ import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMA
/**
* Handles rendering fixed width text and computer terminals.
*
* <p>
* This class has several modes of usage:
* <ul>
* <li>{@link #drawString}: Drawing basic text without a terminal (such as for printouts). Unlike the other methods,
@@ -89,25 +89,25 @@ public final class FixedWidthFontRenderer
quad( emitter, x, y, x + width, y + height, z, colour, BACKGROUND_START, BACKGROUND_START, BACKGROUND_END, BACKGROUND_END, light );
}
private static void drawQuad( QuadEmitter emitter, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex, int light )
private static void drawQuad( QuadEmitter emitter, float x, float y, float width, float height, Palette palette, char colourIndex, int light )
{
byte[] colour = palette.getByteColour( getColour( colourIndex, Colour.BLACK ), greyscale );
byte[] colour = palette.getRenderColours( getColour( colourIndex, Colour.BLACK ) );
drawQuad( emitter, x, y, 0, width, height, colour, light );
}
private static void drawBackground(
@Nonnull QuadEmitter emitter, float x, float y, @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale,
@Nonnull QuadEmitter emitter, float x, float y, @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette,
float leftMarginSize, float rightMarginSize, float height, int light
)
{
if( leftMarginSize > 0 )
{
drawQuad( emitter, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ), light );
drawQuad( emitter, x - leftMarginSize, y, leftMarginSize, height, palette, backgroundColour.charAt( 0 ), light );
}
if( rightMarginSize > 0 )
{
drawQuad( emitter, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, greyscale, backgroundColour.charAt( backgroundColour.length() - 1 ), light );
drawQuad( emitter, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, backgroundColour.charAt( backgroundColour.length() - 1 ), light );
}
// Batch together runs of identical background cells.
@@ -120,7 +120,7 @@ public final class FixedWidthFontRenderer
if( blockColour != '\0' )
{
drawQuad( emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour, light );
drawQuad( emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, blockColour, light );
}
blockColour = colourIndex;
@@ -129,15 +129,15 @@ public final class FixedWidthFontRenderer
if( blockColour != '\0' )
{
drawQuad( emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour, light );
drawQuad( emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, blockColour, light );
}
}
public static void drawString( @Nonnull QuadEmitter emitter, float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nonnull Palette palette, boolean greyscale, int light )
public static void drawString( @Nonnull QuadEmitter emitter, float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nonnull Palette palette, int light )
{
for( int i = 0; i < text.length(); i++ )
{
byte[] colour = palette.getByteColour( getColour( textColour.charAt( i ), Colour.BLACK ), greyscale );
byte[] colour = palette.getRenderColours( getColour( textColour.charAt( i ), Colour.BLACK ) );
int index = text.charAt( i );
if( index > 255 ) index = '?';
@@ -146,7 +146,7 @@ public final class FixedWidthFontRenderer
}
public static void drawTerminalForeground( @Nonnull QuadEmitter emitter, float x, float y, @Nonnull Terminal terminal, boolean greyscale )
public static void drawTerminalForeground( @Nonnull QuadEmitter emitter, float x, float y, @Nonnull Terminal terminal )
{
Palette palette = terminal.getPalette();
int height = terminal.getHeight();
@@ -157,13 +157,13 @@ public final class FixedWidthFontRenderer
float rowY = y + FONT_HEIGHT * i;
drawString(
emitter, x, rowY, terminal.getLine( i ), terminal.getTextColourLine( i ),
palette, greyscale, FULL_BRIGHT_LIGHTMAP
palette, FULL_BRIGHT_LIGHTMAP
);
}
}
public static void drawTerminalBackground(
@Nonnull QuadEmitter emitter, float x, float y, @Nonnull Terminal terminal, boolean greyscale,
@Nonnull QuadEmitter emitter, float x, float y, @Nonnull Terminal terminal,
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
)
{
@@ -172,12 +172,12 @@ public final class FixedWidthFontRenderer
// Top and bottom margins
drawBackground(
emitter, x, y - topMarginSize, terminal.getBackgroundColourLine( 0 ), palette, greyscale,
emitter, x, y - topMarginSize, terminal.getBackgroundColourLine( 0 ), palette,
leftMarginSize, rightMarginSize, topMarginSize, FULL_BRIGHT_LIGHTMAP
);
drawBackground(
emitter, x, y + height * FONT_HEIGHT, terminal.getBackgroundColourLine( height - 1 ), palette, greyscale,
emitter, x, y + height * FONT_HEIGHT, terminal.getBackgroundColourLine( height - 1 ), palette,
leftMarginSize, rightMarginSize, bottomMarginSize, FULL_BRIGHT_LIGHTMAP
);
@@ -186,7 +186,7 @@ public final class FixedWidthFontRenderer
{
float rowY = y + FONT_HEIGHT * i;
drawBackground(
emitter, x, rowY, terminal.getBackgroundColourLine( i ), palette, greyscale,
emitter, x, rowY, terminal.getBackgroundColourLine( i ), palette,
leftMarginSize, rightMarginSize, FONT_HEIGHT, FULL_BRIGHT_LIGHTMAP
);
}
@@ -201,23 +201,22 @@ public final class FixedWidthFontRenderer
return cursorX >= 0 && cursorX < terminal.getWidth() && cursorY >= 0 && cursorY < terminal.getHeight();
}
public static void drawCursor( @Nonnull QuadEmitter emitter, float x, float y, @Nonnull Terminal terminal, boolean greyscale )
public static void drawCursor( @Nonnull QuadEmitter emitter, float x, float y, @Nonnull Terminal terminal )
{
if( isCursorVisible( terminal ) && FrameInfo.getGlobalCursorBlink() )
{
byte[] colour = terminal.getPalette().getByteColour( 15 - terminal.getTextColour(), greyscale );
byte[] colour = terminal.getPalette().getRenderColours( 15 - terminal.getTextColour() );
drawChar( emitter, x + terminal.getCursorX() * FONT_WIDTH, y + terminal.getCursorY() * FONT_HEIGHT, '_', colour, FULL_BRIGHT_LIGHTMAP );
}
}
public static void drawTerminal(
@Nonnull QuadEmitter emitter, float x, float y,
@Nonnull Terminal terminal, boolean greyscale,
@Nonnull QuadEmitter emitter, float x, float y, @Nonnull Terminal terminal,
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
)
{
drawTerminalBackground(
emitter, x, y, terminal, greyscale,
emitter, x, y, terminal,
topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize
);
@@ -227,8 +226,8 @@ public final class FixedWidthFontRenderer
var transformBackup = emitter.poseMatrix().copy();
emitter.poseMatrix().translate( new Vector3f( 0, 0, Z_OFFSET ) );
drawTerminalForeground( emitter, x, y, terminal, greyscale );
drawCursor( emitter, x, y, terminal, greyscale );
drawTerminalForeground( emitter, x, y, terminal );
drawCursor( emitter, x, y, terminal );
emitter.poseMatrix().load( transformBackup );
}

View File

@@ -5,39 +5,40 @@
*/
package dan200.computercraft.client.turtle;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.client.TransformedModel;
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.turtle.upgrades.TurtleModem;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nonnull;
public class TurtleModemModeller implements TurtleUpgradeModeller<TurtleModem>
{
private final ModelResourceLocation leftOffModel;
private final ModelResourceLocation rightOffModel;
private final ModelResourceLocation leftOnModel;
private final ModelResourceLocation rightOnModel;
private final ResourceLocation leftOffModel;
private final ResourceLocation rightOffModel;
private final ResourceLocation leftOnModel;
private final ResourceLocation rightOnModel;
public TurtleModemModeller( boolean advanced )
{
if( advanced )
{
leftOffModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_off_left", "inventory" );
rightOffModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_off_right", "inventory" );
leftOnModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_on_left", "inventory" );
rightOnModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_on_right", "inventory" );
leftOffModel = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_modem_advanced_off_left" );
rightOffModel = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_modem_advanced_off_right" );
leftOnModel = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_modem_advanced_on_left" );
rightOnModel = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_modem_advanced_on_right" );
}
else
{
leftOffModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_off_left", "inventory" );
rightOffModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_off_right", "inventory" );
leftOnModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_on_left", "inventory" );
rightOnModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_on_right", "inventory" );
leftOffModel = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_modem_normal_off_left" );
rightOffModel = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_modem_normal_off_right" );
leftOnModel = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_modem_normal_on_left" );
rightOnModel = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_modem_normal_on_right" );
}
}

View File

@@ -37,7 +37,7 @@ public class DirectBuffers
/**
* Delete a previously created buffer.
*
* <p>
* On Linux, {@link GlStateManager#_glDeleteBuffers(int)} clears a buffer before deleting it. However, this involves
* binding and unbinding the buffer, conflicting with {@link BufferUploader}'s cache. This deletion method uses
* our existing {@link #setEmptyBufferData(int, int, int)}, which correctly handles clearing the buffer.

View File

@@ -19,7 +19,7 @@ import java.nio.ByteBuffer;
/**
* A version of {@link VertexBuffer} which allows uploading {@link ByteBuffer}s directly.
*
* <p>
* This should probably be its own class (rather than subclassing), but I need access to {@link VertexBuffer#drawWithShader}.
*/
public class DirectVertexBuffer extends VertexBuffer

View File

@@ -0,0 +1,120 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core;
import dan200.computercraft.core.computer.ComputerThread;
import dan200.computercraft.core.computer.GlobalEnvironment;
import dan200.computercraft.core.computer.mainthread.MainThreadScheduler;
import dan200.computercraft.core.lua.CobaltLuaMachine;
import dan200.computercraft.core.lua.ILuaMachine;
import javax.annotation.CheckReturnValue;
import java.util.concurrent.TimeUnit;
/**
* The global context under which computers run.
*/
public final class ComputerContext
{
private final GlobalEnvironment globalEnvironment;
private final ComputerThread computerScheduler;
private final MainThreadScheduler mainThreadScheduler;
private final ILuaMachine.Factory factory;
public ComputerContext(
GlobalEnvironment globalEnvironment, ComputerThread computerScheduler,
MainThreadScheduler mainThreadScheduler, ILuaMachine.Factory factory
)
{
this.globalEnvironment = globalEnvironment;
this.computerScheduler = computerScheduler;
this.mainThreadScheduler = mainThreadScheduler;
this.factory = factory;
}
/**
* Create a default {@link ComputerContext} with the given global environment.
*
* @param environment The current global environment.
* @param threads The number of threads to use for the {@link #computerScheduler()}
* @param mainThreadScheduler The main thread scheduler to use.
*/
public ComputerContext( GlobalEnvironment environment, int threads, MainThreadScheduler mainThreadScheduler )
{
this( environment, new ComputerThread( threads ), mainThreadScheduler, CobaltLuaMachine::new );
}
/**
* The global environment.
*
* @return The current global environment.
*/
public GlobalEnvironment globalEnvironment()
{
return globalEnvironment;
}
/**
* The {@link ComputerThread} instance under which computers are run. This is closed when the context is closed, and
* so should be unique per-context.
*
* @return The current computer thread manager.
*/
public ComputerThread computerScheduler()
{
return computerScheduler;
}
/**
* The {@link MainThreadScheduler} instance used to run main-thread tasks.
*
* @return The current main thread scheduler.
*/
public MainThreadScheduler mainThreadScheduler()
{
return mainThreadScheduler;
}
/**
* The factory to create new Lua machines.
*
* @return The current Lua machine factory.
*/
public ILuaMachine.Factory luaFactory()
{
return factory;
}
/**
* Close the current {@link ComputerContext}, disposing of any resources inside.
*
* @param timeout The maximum time to wait.
* @param unit The unit {@code timeout} is in.
* @return Whether the context was successfully shut down.
* @throws InterruptedException If interrupted while waiting.
*/
@CheckReturnValue
public boolean close( long timeout, TimeUnit unit ) throws InterruptedException
{
return computerScheduler().stop( timeout, unit );
}
/**
* Close the current {@link ComputerContext}, disposing of any resources inside.
*
* @param timeout The maximum time to wait.
* @param unit The unit {@code timeout} is in.
* @throws IllegalStateException If the computer thread was not shut down in time.
* @throws InterruptedException If interrupted while waiting.
*/
public void ensureClosed( long timeout, TimeUnit unit ) throws InterruptedException
{
if( !computerScheduler().stop( timeout, unit ) )
{
throw new IllegalStateException( "Failed to shutdown ComputerContext in time." );
}
}
}

View File

@@ -16,7 +16,7 @@ import dan200.computercraft.core.apis.handles.EncodedWritableHandle;
import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.filesystem.FileSystemException;
import dan200.computercraft.core.filesystem.FileSystemWrapper;
import dan200.computercraft.core.tracking.TrackingField;
import dan200.computercraft.core.metrics.Metrics;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -43,20 +43,20 @@ import java.util.function.Function;
* <li>**File and directory manipulation:** For instance, moving or copying files. See {@link #makeDir}, {@link #move},
* {@link #copy} and {@link #delete}.</li>
* </ul>
*
* <p>
* :::note
* All functions in the API work on absolute paths, and do not take the @{shell.dir|current directory} into account.
* You can use @{shell.resolve} to convert a relative path into an absolute one.
* :::
*
* <p>
* ## Mounts
* While a computer can only have one hard drive and filesystem, other filesystems may be "mounted" inside it. For
* instance, the {@link dan200.computercraft.shared.peripheral.diskdrive.DiskDrivePeripheral drive peripheral} mounts
* its disk's contents at {@code "disk/"}, {@code "disk1/"}, etc...
*
* <p>
* You can see which mount a path belongs to with the {@link #getDrive} function. This returns {@code "hdd"} for the
* computer's main filesystem ({@code "/"}), {@code "rom"} for the rom ({@code "rom/"}).
*
* <p>
* Most filesystems have a limited capacity, operations which would cause that capacity to be reached (such as writing
* an incredibly large file) will fail. You can see a mount's capacity with {@link #getCapacity} and the remaining
* space with {@link #getFreeSpace}.
@@ -108,7 +108,7 @@ public class FSAPI implements ILuaAPI
@LuaFunction
public final String[] list( String path ) throws LuaException
{
environment.addTrackingChange( TrackingField.FS_OPS );
environment.observe( Metrics.FS_OPS );
try
{
return fileSystem.list( path );
@@ -276,7 +276,7 @@ public class FSAPI implements ILuaAPI
{
try
{
environment.addTrackingChange( TrackingField.FS_OPS );
environment.observe( Metrics.FS_OPS );
fileSystem.makeDir( path );
}
catch( FileSystemException e )
@@ -287,7 +287,7 @@ public class FSAPI implements ILuaAPI
/**
* Moves a file or directory from one path to another.
*
* <p>
* Any parent directories are created as needed.
*
* @param path The current file or directory to move from.
@@ -299,7 +299,7 @@ public class FSAPI implements ILuaAPI
{
try
{
environment.addTrackingChange( TrackingField.FS_OPS );
environment.observe( Metrics.FS_OPS );
fileSystem.move( path, dest );
}
catch( FileSystemException e )
@@ -310,7 +310,7 @@ public class FSAPI implements ILuaAPI
/**
* Copies a file or directory to a new path.
*
* <p>
* Any parent directories are created as needed.
*
* @param path The file or directory to copy.
@@ -322,7 +322,7 @@ public class FSAPI implements ILuaAPI
{
try
{
environment.addTrackingChange( TrackingField.FS_OPS );
environment.observe( Metrics.FS_OPS );
fileSystem.copy( path, dest );
}
catch( FileSystemException e )
@@ -333,7 +333,7 @@ public class FSAPI implements ILuaAPI
/**
* Deletes a file or directory.
*
* <p>
* If the path points to a directory, all of the enclosed files and
* subdirectories are also deleted.
*
@@ -345,7 +345,7 @@ public class FSAPI implements ILuaAPI
{
try
{
environment.addTrackingChange( TrackingField.FS_OPS );
environment.observe( Metrics.FS_OPS );
fileSystem.delete( path );
}
catch( FileSystemException e )
@@ -358,14 +358,14 @@ public class FSAPI implements ILuaAPI
/**
* Opens a file for reading or writing at a path.
*
* <p>
* The {@code mode} string can be any of the following:
* <ul>
* <li><strong>"r"</strong>: Read mode</li>
* <li><strong>"w"</strong>: Write mode</li>
* <li><strong>"a"</strong>: Append mode</li>
* </ul>
*
* <p>
* The mode may also have a "b" at the end, which opens the file in "binary
* mode". This allows you to read binary files, as well as seek within a file.
*
@@ -411,7 +411,7 @@ public class FSAPI implements ILuaAPI
@LuaFunction
public final Object[] open( String path, String mode ) throws LuaException
{
environment.addTrackingChange( TrackingField.FS_OPS );
environment.observe( Metrics.FS_OPS );
try
{
switch( mode )
@@ -516,7 +516,7 @@ public class FSAPI implements ILuaAPI
/**
* Searches for files matching a string with wildcards.
*
* <p>
* This string is formatted like a normal path string, but can include any
* number of wildcards ({@code *}) to look for files matching anything.
* For example, <code>rom/&#42;/command*</code> will look for any path starting with
@@ -532,7 +532,7 @@ public class FSAPI implements ILuaAPI
{
try
{
environment.addTrackingChange( TrackingField.FS_OPS );
environment.observe( Metrics.FS_OPS );
return fileSystem.find( path );
}
catch( FileSystemException e )
@@ -568,10 +568,10 @@ public class FSAPI implements ILuaAPI
/**
* Get attributes about a specific file or folder.
*
* <p>
* The returned attributes table contains information about the size of the file, whether it is a directory,
* when it was created and last modified, and whether it is read only.
*
* <p>
* The creation and modification times are given as the number of milliseconds since the UNIX epoch. This may be
* given to {@link OSAPI#date} in order to convert it to more usable form.
*

View File

@@ -207,7 +207,7 @@ public class HTTPAPI implements ILuaAPI
if( !headers.contains( HttpHeaderNames.USER_AGENT ) )
{
headers.set( HttpHeaderNames.USER_AGENT, apiEnvironment.getComputerEnvironment().getUserAgent() );
headers.set( HttpHeaderNames.USER_AGENT, apiEnvironment.getGlobalEnvironment().getUserAgent() );
}
return headers;
}

View File

@@ -7,11 +7,12 @@ package dan200.computercraft.core.apis;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IWorkMonitor;
import dan200.computercraft.core.computer.ComputerEnvironment;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.computer.IComputerEnvironment;
import dan200.computercraft.core.computer.GlobalEnvironment;
import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.metrics.Metric;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.tracking.TrackingField;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -29,7 +30,10 @@ public interface IAPIEnvironment
int getComputerID();
@Nonnull
IComputerEnvironment getComputerEnvironment();
ComputerEnvironment getComputerEnvironment();
@Nonnull
GlobalEnvironment getGlobalEnvironment();
@Nonnull
IWorkMonitor getMainThreadMonitor();
@@ -71,10 +75,7 @@ public interface IAPIEnvironment
void cancelTimer( int id );
void addTrackingChange( @Nonnull TrackingField field, long change );
void observe( @Nonnull Metric.Event event, long change );
default void addTrackingChange( @Nonnull TrackingField field )
{
addTrackingChange( field, 1 );
}
void observe( @Nonnull Metric.Counter counter );
}

View File

@@ -39,17 +39,8 @@ public class OSAPI implements ILuaAPI
private int nextAlarmToken = 0;
private static class Alarm implements Comparable<Alarm>
private record Alarm(double time, int day) implements Comparable<Alarm>
{
final double time;
final int day;
Alarm( double time, int day )
{
this.time = time;
this.day = day;
}
@Override
public int compareTo( @Nonnull Alarm o )
{
@@ -173,7 +164,7 @@ public class OSAPI implements ILuaAPI
* Starts a timer that will run for the specified number of seconds. Once
* the timer fires, a {@code timer} event will be added to the queue with
* the ID returned from this function as the first parameter.
*
* <p>
* As with @{os.sleep|sleep}, {@code timer} will automatically be rounded up
* to the nearest multiple of 0.05 seconds, as it waits for a fixed amount
* of world ticks.
@@ -315,13 +306,13 @@ public class OSAPI implements ILuaAPI
/**
* Returns the current time depending on the string passed in. This will
* always be in the range [0.0, 24.0).
*
* <p>
* * If called with {@code ingame}, the current world time will be returned.
* This is the default if nothing is passed.
* * If called with {@code utc}, returns the hour of the day in UTC time.
* * If called with {@code local}, returns the hour of the day in the
* timezone the server is located in.
*
* <p>
* This function can also be called with a table returned from {@link #date},
* which will convert the date fields into a UNIX timestamp (number of
* seconds since 1 January 1970).
@@ -363,7 +354,7 @@ public class OSAPI implements ILuaAPI
/**
* Returns the day depending on the locale specified.
*
* <p>
* * If called with {@code ingame}, returns the number of days since the
* world was created. This is the default.
* * If called with {@code utc}, returns the number of days since 1 January
@@ -395,7 +386,7 @@ public class OSAPI implements ILuaAPI
/**
* Returns the number of milliseconds since an epoch depending on the locale.
*
* <p>
* * If called with {@code ingame}, returns the number of milliseconds since the
* world was created. This is the default.
* * If called with {@code utc}, returns the number of milliseconds since 1
@@ -446,12 +437,12 @@ public class OSAPI implements ILuaAPI
/**
* Returns a date string (or table) using a specified format string and
* optional time to format.
*
* <p>
* The format string takes the same formats as C's {@code strftime} function
* (http://www.cplusplus.com/reference/ctime/strftime/). In extension, it
* can be prefixed with an exclamation mark ({@code !}) to use UTC time
* instead of the server's local timezone.
*
* <p>
* If the format is exactly {@code *t} (optionally prefixed with {@code !}), a
* table will be returned instead. This table has fields for the year, month,
* day, hour, minute, second, day of the week, day of the year, and whether

View File

@@ -16,7 +16,7 @@ import dan200.computercraft.core.asm.LuaMethod;
import dan200.computercraft.core.asm.NamedMethod;
import dan200.computercraft.core.asm.PeripheralMethod;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.tracking.TrackingField;
import dan200.computercraft.core.metrics.Metrics;
import dan200.computercraft.shared.util.LuaUtil;
import javax.annotation.Nonnull;
@@ -108,7 +108,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
if( method == null ) throw new LuaException( "No such method " + methodName );
environment.addTrackingChange( TrackingField.PERIPHERAL_OPS );
environment.observe( Metrics.PERIPHERAL_OPS );
return method.apply( peripheral, context, this, arguments );
}

View File

@@ -12,7 +12,7 @@ import dan200.computercraft.core.computer.ComputerSide;
/**
* Get and set redstone signals adjacent to this computer.
*
* <p>
* The {@link RedstoneAPI} library exposes three "types" of redstone control:
* - Binary input/output ({@link #setOutput}/{@link #getInput}): These simply check if a redstone wire has any input or
* output. A signal strength of 1 and 15 are treated the same.
@@ -21,10 +21,10 @@ import dan200.computercraft.core.computer.ComputerSide;
* - Bundled cables ({@link #setBundledOutput}/{@link #getBundledInput}): These interact with "bundled" cables, such
* as those from Project:Red. These allow you to send 16 separate on/off signals. Each channel corresponds to a
* colour, with the first being @{colors.white} and the last @{colors.black}.
*
* <p>
* Whenever a redstone input changes, a @{event!redstone} event will be fired. This may be used instead of repeativly
* polling.
*
* <p>
* This module may also be referred to as {@code rs}. For example, one may call {@code rs.getSides()} instead of
* {@link #getSides}.
*
@@ -47,7 +47,7 @@ import dan200.computercraft.core.computer.ComputerSide;
* os.pullEvent("redstone") -- Wait for a change to inputs.
* end
* }</pre>
*
* <p>
* [comparator]: https://minecraft.gamepedia.com/Redstone_Comparator#Subtract_signal_strength "Redstone Comparator on
* the Minecraft wiki."
* @cc.module redstone

View File

@@ -9,7 +9,6 @@ import dan200.computercraft.api.lua.IArguments;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.core.computer.IComputerEnvironment;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.util.Colour;
@@ -24,12 +23,10 @@ import javax.annotation.Nonnull;
public class TermAPI extends TermMethods implements ILuaAPI
{
private final Terminal terminal;
private final IComputerEnvironment environment;
public TermAPI( IAPIEnvironment environment )
{
terminal = environment.getTerminal();
this.environment = environment.getComputerEnvironment();
}
@Override
@@ -55,12 +52,7 @@ public class TermAPI extends TermMethods implements ILuaAPI
{
int actualColour = 15 - parseColour( colour );
Colour c = Colour.fromInt( actualColour );
float[] rgb = c.getRGB();
Object[] rgbObj = new Object[rgb.length];
for( int i = 0; i < rgbObj.length; ++i ) rgbObj[i] = rgb[i];
return rgbObj;
return new Object[] { c.getR(), c.getG(), c.getB() };
}
@Nonnull
@@ -69,10 +61,4 @@ public class TermAPI extends TermMethods implements ILuaAPI
{
return terminal;
}
@Override
public boolean isColour()
{
return environment.isColour();
}
}

View File

@@ -37,11 +37,9 @@ public abstract class TermMethods
@Nonnull
public abstract Terminal getTerminal() throws LuaException;
public abstract boolean isColour() throws LuaException;
/**
* Write {@code text} at the current cursor position, moving the cursor to the end of the text.
*
* <p>
* Unlike functions like {@code write} and {@code print}, this does not wrap the text - it simply copies the
* text to the current terminal line.
*
@@ -63,7 +61,7 @@ public abstract class TermMethods
/**
* Move all positions up (or down) by {@code y} pixels.
*
* <p>
* Every pixel in the terminal will be replaced by the line {@code y} pixels below it. If {@code y} is negative, it
* will copy pixels from above instead.
*
@@ -247,7 +245,7 @@ public abstract class TermMethods
/**
* Determine if this terminal supports colour.
*
* <p>
* Terminals which do not support colour will still allow writing coloured text/backgrounds, but it will be
* displayed in greyscale.
*
@@ -258,15 +256,15 @@ public abstract class TermMethods
@LuaFunction( { "isColour", "isColor" } )
public final boolean getIsColour() throws LuaException
{
return isColour();
return getTerminal().isColour();
}
/**
* Writes {@code text} to the terminal with the specific foreground and background characters.
*
* <p>
* As with {@link #write(IArguments)}, the text will be written at the current cursor location, with the cursor
* moving to the end of the text.
*
* <p>
* {@code textColour} and {@code backgroundColour} must both be strings the same length as {@code text}. All
* characters represent a single hexadecimal digit, which is converted to one of CC's colours. For instance,
* {@code "a"} corresponds to purple.
@@ -301,7 +299,7 @@ public abstract class TermMethods
/**
* Set the palette for a specific colour.
*
* <p>
* ComputerCraft's palette system allows you to change how a specific colour should be displayed. For instance, you
* can make @{colors.red} <em>more red</em> by setting its palette to #FF0000. This does now allow you to draw more
* colours - you are still limited to 16 on the screen at one time - but you can change <em>which</em> colours are

View File

@@ -249,11 +249,11 @@ public class BinaryReadableHandle extends HandleGeneric
/**
* Seek to a new position within the file, changing where bytes are written to. The new position is an offset
* given by {@code offset}, relative to a start position determined by {@code whence}:
*
* <p>
* - {@code "set"}: {@code offset} is relative to the beginning of the file.
* - {@code "cur"}: Relative to the current position. This is the default.
* - {@code "end"}: Relative to the end of the file.
*
* <p>
* In case of success, {@code seek} returns the new file position from the beginning of the file.
*
* @param whence Where the offset is relative to.

View File

@@ -117,11 +117,11 @@ public class BinaryWritableHandle extends HandleGeneric
/**
* Seek to a new position within the file, changing where bytes are written to. The new position is an offset
* given by {@code offset}, relative to a start position determined by {@code whence}:
*
* <p>
* - {@code "set"}: {@code offset} is relative to the beginning of the file.
* - {@code "cur"}: Relative to the current position. This is the default.
* - {@code "end"}: Relative to the end of the file.
*
* <p>
* In case of success, {@code seek} returns the new file position from the beginning of the file.
*
* @param whence Where the offset is relative to.

View File

@@ -39,7 +39,7 @@ public abstract class HandleGeneric
/**
* Close this file, freeing any resources it uses.
*
* <p>
* Once a file is closed it may no longer be read or written to.
*
* @throws LuaException If the file has already been closed.

View File

@@ -13,7 +13,7 @@ import java.util.concurrent.Future;
/**
* Checks a URL using {@link NetworkUtils#getAddress(String, int, boolean)}}
*
* <p>
* This requires a DNS lookup, and so needs to occur off-thread.
*/
public class CheckUrl extends Resource<CheckUrl>

View File

@@ -126,7 +126,7 @@ public final class NetworkUtils
/**
* Create a {@link InetSocketAddress} from a {@link java.net.URI}.
*
* <p>
* Note, this may require a DNS lookup, and so should not be executed on the main CC thread.
*
* @param uri The URI to fetch.
@@ -141,7 +141,7 @@ public final class NetworkUtils
/**
* Create a {@link InetSocketAddress} from the resolved {@code host} and port.
*
* <p>
* Note, this may require a DNS lookup, and so should not be executed on the main CC thread.
*
* @param host The host to resolve.

View File

@@ -68,7 +68,7 @@ public abstract class Resource<T extends Resource<T>> implements Closeable
/**
* Clean up any pending resources
*
* <p>
* Note, this may be called multiple times, and so should be thread-safe and
* avoid any major side effects.
*/

View File

@@ -85,8 +85,8 @@ public final class AddressRule
int port = socketAddress.getPort();
InetAddress address = socketAddress.getAddress();
Inet4Address ipv4Address = address instanceof Inet6Address && InetAddresses.is6to4Address( (Inet6Address) address )
? InetAddresses.get6to4IPv4Address( (Inet6Address) address ) : null;
Inet4Address ipv4Address = address instanceof Inet6Address inet6 && InetAddresses.is6to4Address( inet6 )
? InetAddresses.get6to4IPv4Address( inet6 ) : null;
for( AddressRule rule : rules )
{

View File

@@ -12,7 +12,7 @@ import dan200.computercraft.core.apis.http.NetworkUtils;
import dan200.computercraft.core.apis.http.Resource;
import dan200.computercraft.core.apis.http.ResourceGroup;
import dan200.computercraft.core.apis.http.options.Options;
import dan200.computercraft.core.tracking.TrackingField;
import dan200.computercraft.core.metrics.Metrics;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
@@ -148,8 +148,8 @@ public class HttpRequest extends Resource<HttpRequest>
}
// Add request size to the tracker before opening the connection
environment.addTrackingChange( TrackingField.HTTP_REQUESTS, 1 );
environment.addTrackingChange( TrackingField.HTTP_UPLOAD, requestBody );
environment.observe( Metrics.HTTP_REQUESTS );
environment.observe( Metrics.HTTP_UPLOAD, requestBody );
HttpRequestHandler handler = currentRequest = new HttpRequestHandler( this, uri, method, options );
connectFuture = new Bootstrap()

View File

@@ -13,7 +13,7 @@ import dan200.computercraft.core.apis.handles.HandleGeneric;
import dan200.computercraft.core.apis.http.HTTPRequestException;
import dan200.computercraft.core.apis.http.NetworkUtils;
import dan200.computercraft.core.apis.http.options.Options;
import dan200.computercraft.core.tracking.TrackingField;
import dan200.computercraft.core.metrics.Metrics;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.CompositeByteBuf;
import io.netty.channel.ChannelHandlerContext;
@@ -199,7 +199,7 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<HttpOb
}
// Fire off a stats event
request.environment().addTrackingChange( TrackingField.HTTP_DOWNLOAD, getHeaderSize( responseHeaders ) + bytes.length );
request.environment().observe( Metrics.HTTP_DOWNLOAD, getHeaderSize( responseHeaders ) + bytes.length );
// Prepare to queue an event
ArrayByteChannel contents = new ArrayByteChannel( bytes );

View File

@@ -8,7 +8,7 @@ package dan200.computercraft.core.apis.http.websocket;
import com.google.common.base.Objects;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.core.apis.http.options.Options;
import dan200.computercraft.core.tracking.TrackingField;
import dan200.computercraft.core.metrics.Metrics;
import dan200.computercraft.shared.util.StringUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
@@ -89,7 +89,7 @@ public class WebsocketHandle implements Closeable
throw new LuaException( "Message is too large" );
}
websocket.environment().addTrackingChange( TrackingField.WEBSOCKET_OUTGOING, text.length() );
websocket.environment().observe( Metrics.WEBSOCKET_OUTGOING, text.length() );
Channel channel = this.channel;
if( channel != null )

View File

@@ -7,7 +7,7 @@ package dan200.computercraft.core.apis.http.websocket;
import dan200.computercraft.core.apis.http.NetworkUtils;
import dan200.computercraft.core.apis.http.options.Options;
import dan200.computercraft.core.tracking.TrackingField;
import dan200.computercraft.core.metrics.Metrics;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpResponse;
@@ -61,18 +61,18 @@ public class WebsocketHandler extends SimpleChannelInboundHandler<Object>
}
WebSocketFrame frame = (WebSocketFrame) msg;
if( frame instanceof TextWebSocketFrame )
if( frame instanceof TextWebSocketFrame textFrame )
{
String data = ((TextWebSocketFrame) frame).text();
String data = textFrame.text();
websocket.environment().addTrackingChange( TrackingField.WEBSOCKET_INCOMING, data.length() );
websocket.environment().observe( Metrics.WEBSOCKET_INCOMING, data.length() );
websocket.environment().queueEvent( MESSAGE_EVENT, websocket.address(), data, false );
}
else if( frame instanceof BinaryWebSocketFrame )
{
byte[] converted = NetworkUtils.toBytes( frame.content() );
websocket.environment().addTrackingChange( TrackingField.WEBSOCKET_INCOMING, converted.length );
websocket.environment().observe( Metrics.WEBSOCKET_INCOMING, converted.length );
websocket.environment().queueEvent( MESSAGE_EVENT, websocket.address(), converted, true );
}
else if( frame instanceof CloseWebSocketFrame closeFrame )

View File

@@ -19,7 +19,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
@@ -51,7 +50,7 @@ public class GenericMethod
static List<GenericMethod> all()
{
if( cache != null ) return cache;
return cache = sources.stream().flatMap( GenericMethod::getMethods ).collect( Collectors.toList() );
return cache = sources.stream().flatMap( GenericMethod::getMethods ).toList();
}
public static synchronized void register( @Nonnull GenericSource source )
@@ -69,7 +68,7 @@ public class GenericMethod
private static Stream<GenericMethod> getMethods( GenericSource source )
{
Class<?> klass = source.getClass();
PeripheralType type = source instanceof GenericPeripheral ? ((GenericPeripheral) source).getType() : null;
PeripheralType type = source instanceof GenericPeripheral generic ? generic.getType() : null;
return Arrays.stream( klass.getDeclaredMethods() )
.map( method -> {

View File

@@ -9,7 +9,7 @@ import java.util.function.BiConsumer;
/**
* A Lua object which exposes additional methods.
*
* <p>
* This can be used to merge multiple objects together into one. Ideally this'd be part of the API, but I'm not entirely
* happy with the interface - something I'd like to think about first.
*/
@@ -21,9 +21,9 @@ public interface ObjectSource
{
for( NamedMethod<T> method : generator.getMethods( object.getClass() ) ) accept.accept( object, method );
if( object instanceof ObjectSource )
if( object instanceof ObjectSource source )
{
for( Object extra : ((ObjectSource) object).getExtra() )
for( Object extra : source.getExtra() )
{
for( NamedMethod<T> method : generator.getMethods( extra.getClass() ) ) accept.accept( extra, method );
}

View File

@@ -52,7 +52,7 @@ final class Reflect
Type underlying = root;
while( true )
{
if( underlying instanceof Class<?> ) return (Class<?>) underlying;
if( underlying instanceof Class<?> klass ) return klass;
if( underlying instanceof ParameterizedType type )
{
@@ -61,7 +61,7 @@ final class Reflect
for( java.lang.reflect.Type arg : type.getActualTypeArguments() )
{
if( arg instanceof WildcardType ) continue;
if( arg instanceof TypeVariable && ((TypeVariable<?>) arg).getName().startsWith( "capture#" ) )
if( arg instanceof TypeVariable<?> var && var.getName().startsWith( "capture#" ) )
{
continue;
}

View File

@@ -7,16 +7,21 @@ package dan200.computercraft.core.computer;
import com.google.common.base.Objects;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaTask;
import dan200.computercraft.api.peripheral.IWorkMonitor;
import dan200.computercraft.core.ComputerContext;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.computer.mainthread.MainThreadScheduler;
import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.terminal.Terminal;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
/**
* Represents a computer which may exist in-world or elsewhere.
*
* <p>
* Note, this class has several (read: far, far too many) responsibilities, so can get a little unwieldy at times.
*
* <ul>
@@ -24,7 +29,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* <li>Keeps track of whether the computer is on and blinking.</li>
* <li>Monitors whether the computer's visible state (redstone, on/off/blinking) has changed.</li>
* <li>Passes commands and events to the {@link ComputerExecutor}.</li>
* <li>Passes main thread tasks to the {@link MainThreadExecutor}.</li>
* <li>Passes main thread tasks to the {@link MainThreadScheduler.Executor}.</li>
* </ul>
*/
public class Computer
@@ -32,36 +37,46 @@ public class Computer
private static final int START_DELAY = 50;
// Various properties of the computer
private int id;
private final int id;
private String label = null;
// Read-only fields about the computer
private final IComputerEnvironment environment;
private final GlobalEnvironment globalEnvironment;
private final Terminal terminal;
private final ComputerExecutor executor;
private final MainThreadExecutor serverExecutor;
private final MainThreadScheduler.Executor serverExecutor;
/**
* An internal counter for {@link ILuaTask} ids.
*
* @see ILuaContext#issueMainThreadTask(ILuaTask)
* @see #getUniqueTaskId()
*/
private final AtomicLong lastTaskId = new AtomicLong();
// Additional state about the computer and its environment.
private boolean blinking = false;
private final Environment internalEnvironment = new Environment( this );
private final Environment internalEnvironment;
private final AtomicBoolean externalOutputChanged = new AtomicBoolean();
private boolean startRequested;
private int ticksSinceStart = -1;
public Computer( IComputerEnvironment environment, Terminal terminal, int id )
public Computer( ComputerContext context, ComputerEnvironment environment, Terminal terminal, int id )
{
if( id < 0 ) throw new IllegalStateException( "Id has not been assigned" );
this.id = id;
this.environment = environment;
globalEnvironment = context.globalEnvironment();
this.terminal = terminal;
executor = new ComputerExecutor( this );
serverExecutor = new MainThreadExecutor( this );
internalEnvironment = new Environment( this, environment );
executor = new ComputerExecutor( this, environment, context );
serverExecutor = context.mainThreadScheduler().createExecutor( environment.getMetrics() );
}
IComputerEnvironment getComputerEnvironment()
GlobalEnvironment getGlobalEnvironment()
{
return environment;
return globalEnvironment;
}
FileSystem getFileSystem()
@@ -115,7 +130,7 @@ public class Computer
}
/**
* Queue a task to be run on the main thread, using {@link MainThread}.
* Queue a task to be run on the main thread, using {@link MainThreadScheduler}.
*
* @param runnable The task to run
* @return If the task was successfully queued (namely, whether there is space on it).
@@ -135,20 +150,6 @@ public class Computer
return id;
}
public int assignID()
{
if( id < 0 )
{
id = environment.assignNewID();
}
return id;
}
public void setID( int id )
{
this.id = id;
}
public String getLabel()
{
return label;
@@ -216,4 +217,9 @@ public class Computer
{
executor.addApi( api );
}
long getUniqueTaskId()
{
return lastTaskId.incrementAndGet();
}
}

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