1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-09-06 04:17:56 +00:00

Merge as much code from CC-Tweaked/mc-1.18.x into CC:R as possible.

Hopefully this will make tracking changes and merging future CC: Tweaked
development easier! A lot of this is making whitespace and method
ordering even with Tweaked to bring down the diffs, but it also fast
forwards us to CC:T 1.99.0 features.
This commit is contained in:
Toad-Dev
2021-12-03 16:06:45 -08:00
parent 34760d3de4
commit f880396286
259 changed files with 7703 additions and 9250 deletions

View File

@@ -1,5 +1,5 @@
image: image:
file: .gitpod.Dockerfile file: config/gitpod/Dockerfile
ports: ports:
- port: 25565 - port: 25565
@@ -7,12 +7,14 @@ ports:
vscode: vscode:
extensions: extensions:
- eamodio.gitlens
- github.vscode-pull-request-github
- ms-azuretools.vscode-docker - ms-azuretools.vscode-docker
- redhat.java - redhat.java
- richardwillis.vscode-gradle - richardwillis.vscode-gradle
- vscjava.vscode-java-debug - vscjava.vscode-java-debug
- vscode.github - vscode.github
tasks: tasks:
- init: ./gradlew - name: Setup pre-commit hool
init: pre-commit install --config config/pre-commit/config.yml --allow-missing-config

View File

@@ -93,7 +93,7 @@ dependencies {
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.21' testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.21'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1' testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1'
cctJavadoc 'cc.tweaked:cct-javadoc:1.4.1' cctJavadoc 'cc.tweaked:cct-javadoc:1.4.2'
} }
processResources { processResources {

View File

@@ -2,7 +2,7 @@
module: [kind=event] redstone module: [kind=event] redstone
--- ---
The @{redstone} event is fired whenever any redstone inputs on the computer change. The @{event!redstone} event is fired whenever any redstone inputs on the computer change.
## Example ## Example
Prints a message when a redstone input changes: Prints a message when a redstone input changes:

View File

@@ -3,12 +3,11 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft; package dan200.computercraft;
import dan200.computercraft.core.apis.http.options.Action; import dan200.computercraft.core.apis.http.options.Action;
import dan200.computercraft.core.apis.http.options.AddressRule; import dan200.computercraft.core.apis.http.options.AddressRule;
import dan200.computercraft.shared.ComputerCraftRegistry.ModBlocks; import dan200.computercraft.shared.Registry.ModBlocks;
import dan200.computercraft.shared.common.ColourableRecipe; import dan200.computercraft.shared.common.ColourableRecipe;
import dan200.computercraft.shared.computer.core.ClientComputerRegistry; import dan200.computercraft.shared.computer.core.ClientComputerRegistry;
import dan200.computercraft.shared.computer.core.ServerComputerRegistry; import dan200.computercraft.shared.computer.core.ServerComputerRegistry;
@@ -37,24 +36,20 @@ import net.minecraft.world.item.ItemStack;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static dan200.computercraft.shared.ComputerCraftRegistry.init; import static dan200.computercraft.shared.Registry.init;
public final class ComputerCraft implements ModInitializer public final class ComputerCraft implements ModInitializer
{ {
public static final String MOD_ID = "computercraft"; public static final String MOD_ID = "computercraft";
// Configuration fields
public static int computerSpaceLimit = 1000 * 1000; public static int computerSpaceLimit = 1000 * 1000;
public static int floppySpaceLimit = 125 * 1000; public static int floppySpaceLimit = 125 * 1000;
public static int maximumFilesOpen = 128; public static int maximumFilesOpen = 128;
public static boolean disableLua51Features = false; public static boolean disableLua51Features = false;
public static String defaultComputerSettings = ""; public static String defaultComputerSettings = "";
public static boolean debugEnable = true;
public static boolean logComputerErrors = true; public static boolean logComputerErrors = true;
public static boolean commandRequireCreative = true; public static boolean commandRequireCreative = true;
@@ -64,10 +59,11 @@ public final class ComputerCraft implements ModInitializer
public static boolean httpEnabled = true; public static boolean httpEnabled = true;
public static boolean httpWebsocketEnabled = true; public static boolean httpWebsocketEnabled = true;
public static List<AddressRule> httpRules = Collections.unmodifiableList( Arrays.asList( public static List<AddressRule> httpRules = List.of(
AddressRule.parse( "$private", null, Action.DENY.toPartial() ), AddressRule.parse( "$private", null, Action.DENY.toPartial() ),
AddressRule.parse( "*", null, Action.ALLOW.toPartial() ) AddressRule.parse( "*", null, Action.ALLOW.toPartial() )
) ); );
public static int httpMaxRequests = 16; public static int httpMaxRequests = 16;
public static int httpMaxWebsockets = 4; public static int httpMaxWebsockets = 4;
public static int httpDownloadBandwidth = 32 * 1024 * 1024; public static int httpDownloadBandwidth = 32 * 1024 * 1024;
@@ -80,7 +76,6 @@ public final class ComputerCraft implements ModInitializer
public static int modemHighAltitudeRangeDuringStorm = 384; public static int modemHighAltitudeRangeDuringStorm = 384;
public static int maxNotesPerTick = 8; public static int maxNotesPerTick = 8;
public static MonitorRenderer monitorRenderer = MonitorRenderer.BEST; public static MonitorRenderer monitorRenderer = MonitorRenderer.BEST;
public static double monitorDistanceSq = 4096;
public static int monitorDistance = 65; public static int monitorDistance = 65;
public static long monitorBandwidth = 1_000_000; public static long monitorBandwidth = 1_000_000;
@@ -98,6 +93,7 @@ public final class ComputerCraft implements ModInitializer
public static int pocketTermWidth = 26; public static int pocketTermWidth = 26;
public static int pocketTermHeight = 20; public static int pocketTermHeight = 20;
public static int monitorWidth = 8; public static int monitorWidth = 8;
public static int monitorHeight = 6; public static int monitorHeight = 6;

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft; package dan200.computercraft;
import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI;
@@ -35,7 +34,6 @@ import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.packs.resources.ReloadableResourceManager; import net.minecraft.server.packs.resources.ReloadableResourceManager;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@@ -59,36 +57,24 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
public static InputStream getResourceFile( String domain, String subPath ) public static InputStream getResourceFile( String domain, String subPath )
{ {
MinecraftServer server = GameInstanceUtils.getServer(); ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) GameInstanceUtils.getServer()).callGetResourceManager();
if( server != null ) try
{ {
ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) server).callGetResourceManager(); return manager.getResource( new ResourceLocation( domain, subPath ) ).getInputStream();
try }
{ catch( IOException ignored )
return manager.getResource( new ResourceLocation( domain, subPath ) ) {
.getInputStream(); return null;
}
catch( IOException ignored )
{
return null;
}
} }
return null;
} }
@Nonnull @Nonnull
@Override @Override
public String getInstalledVersion() public String getInstalledVersion()
{ {
if( version != null ) if( version != null ) return version;
{ return version = FabricLoader.getInstance().getModContainer( ComputerCraft.MOD_ID )
return version; .map( x -> x.getMetadata().getVersion().toString() )
}
return version = FabricLoader.getInstance()
.getModContainer( ComputerCraft.MOD_ID )
.map( x -> x.getMetadata()
.getVersion()
.toString() )
.orElse( "unknown" ); .orElse( "unknown" );
} }
@@ -114,14 +100,9 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
@Override @Override
public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath ) public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath )
{ {
MinecraftServer server = GameInstanceUtils.getServer(); ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) GameInstanceUtils.getServer()).callGetResourceManager();
if( server != null ) ResourceMount mount = ResourceMount.get( domain, subPath, manager );
{ return mount.exists( "" ) ? mount : null;
ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) server).callGetResourceManager();
ResourceMount mount = ResourceMount.get( domain, subPath, manager );
return mount.exists( "" ) ? mount : null;
}
return null;
} }
@Override @Override
@@ -130,12 +111,24 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
Peripherals.register( provider ); Peripherals.register( provider );
} }
@Override
public void registerGenericSource( @Nonnull GenericSource source )
{
GenericMethod.register( source );
}
@Override @Override
public void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade ) public void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade )
{ {
TurtleUpgrades.register( upgrade ); TurtleUpgrades.register( upgrade );
} }
@Override
public void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade )
{
PocketUpgrades.register( upgrade );
}
@Override @Override
public void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider ) public void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider )
{ {
@@ -154,18 +147,6 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
MediaProviders.register( provider ); MediaProviders.register( provider );
} }
@Override
public void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade )
{
PocketUpgrades.register( upgrade );
}
@Override
public void registerGenericSource( @Nonnull GenericSource source )
{
GenericMethod.register( source );
}
@Nonnull @Nonnull
@Override @Override
public IPacketNetwork getWirelessNetwork() public IPacketNetwork getWirelessNetwork()

View File

@@ -36,19 +36,14 @@ import javax.annotation.Nullable;
*/ */
public final class ComputerCraftAPI public final class ComputerCraftAPI
{ {
public static final String MOD_ID = "computercraft";
@Nonnull @Nonnull
public static String getInstalledVersion() public static String getInstalledVersion()
{ {
return getInstance().getInstalledVersion(); return getInstance().getInstalledVersion();
} }
@Nonnull
@Deprecated
public static String getAPIVersion()
{
return getInstalledVersion();
}
/** /**
* Creates a numbered directory in a subfolder of the save directory for a given world, and returns that number. * Creates a numbered directory in a subfolder of the save directory for a given world, and returns that number.
* *
@@ -139,9 +134,9 @@ public final class ComputerCraftAPI
} }
/** /**
* Registers a new turtle turtle for use in ComputerCraft. After calling this, * Registers a new turtle upgrade for use in ComputerCraft. After calling this,
* users should be able to craft Turtles with your new turtle. It is recommended to call * users should be able to craft Turtles with your upgrade's ItemStack. It is
* this during the load() method of your mod. * recommended to call this during the load() method of your mod.
* *
* @param upgrade The turtle upgrade to register. * @param upgrade The turtle upgrade to register.
* @see ITurtleUpgrade * @see ITurtleUpgrade
@@ -151,6 +146,19 @@ public final class ComputerCraftAPI
getInstance().registerTurtleUpgrade( upgrade ); getInstance().registerTurtleUpgrade( upgrade );
} }
/**
* Registers a new pocket upgrade for use in ComputerCraft. After calling this,
* users should be able to craft pocket computers with your upgrade's ItemStack. It is
* recommended to call this during the load() method of your mod.
*
* @param upgrade The pocket upgrade to register.
* @see IPocketUpgrade
*/
public static void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade )
{
getInstance().registerPocketUpgrade( upgrade );
}
/** /**
* Registers a bundled redstone provider to provide bundled redstone output for blocks. * Registers a bundled redstone provider to provide bundled redstone output for blocks.
* *
@@ -188,11 +196,6 @@ public final class ComputerCraftAPI
getInstance().registerMediaProvider( provider ); getInstance().registerMediaProvider( provider );
} }
public static void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade )
{
getInstance().registerPocketUpgrade( upgrade );
}
/** /**
* Attempt to get the game-wide wireless network. * Attempt to get the game-wide wireless network.
* *
@@ -273,14 +276,13 @@ public final class ComputerCraftAPI
void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade ); void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade );
void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade );
void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider ); void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider );
int getBundledRedstoneOutput( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ); int getBundledRedstoneOutput( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side );
void registerMediaProvider( @Nonnull IMediaProvider provider ); void registerMediaProvider( @Nonnull IMediaProvider provider );
void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade );
@Nonnull @Nonnull
IPacketNetwork getWirelessNetwork(); IPacketNetwork getWirelessNetwork();

View File

@@ -0,0 +1,65 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api;
import dan200.computercraft.ComputerCraft;
import net.fabricmc.fabric.api.tag.TagFactory;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.Tag;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
/**
* Tags provided by ComputerCraft.
*/
public class ComputerCraftTags
{
public static class Items
{
public static final Tag.Named<Item> COMPUTER = make( "computer" );
public static final Tag.Named<Item> TURTLE = make( "turtle" );
public static final Tag.Named<Item> WIRED_MODEM = make( "wired_modem" );
public static final Tag.Named<Item> MONITOR = make( "monitor" );
private static Tag.Named<Item> make( String name )
{
return TagFactory.ITEM.create( new ResourceLocation( ComputerCraft.MOD_ID, name ) );
}
}
public static class Blocks
{
public static final Tag.Named<Block> COMPUTER = make( "computer" );
public static final Tag.Named<Block> TURTLE = make( "turtle" );
public static final Tag.Named<Block> WIRED_MODEM = make( "wired_modem" );
public static final Tag.Named<Block> MONITOR = make( "monitor" );
/**
* Blocks which can be broken by any turtle tool.
*/
public static final Tag.Named<Block> TURTLE_ALWAYS_BREAKABLE = make( "turtle_always_breakable" );
/**
* Blocks which can be broken by the default shovel tool.
*/
public static final Tag.Named<Block> TURTLE_SHOVEL_BREAKABLE = make( "turtle_shovel_harvestable" );
/**
* Blocks which can be broken with the default sword tool.
*/
public static final Tag.Named<Block> TURTLE_SWORD_BREAKABLE = make( "turtle_sword_harvestable" );
/**
* Blocks which can be broken with the default hoe tool.
*/
public static final Tag.Named<Block> TURTLE_HOE_BREAKABLE = make( "turtle_hoe_harvestable" );
private static Tag.Named<Block> make( String name )
{
return TagFactory.BLOCK.create( new ResourceLocation( ComputerCraft.MOD_ID, name ) );
}
}
}

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.client; package dan200.computercraft.api.client;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;

View File

@@ -9,6 +9,8 @@ import dan200.computercraft.api.lua.LuaFunction;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Set;
/** /**
* The interface that defines a peripheral. * The interface that defines a peripheral.
@@ -30,6 +32,18 @@ public interface IPeripheral
@Nonnull @Nonnull
String getType(); String getType();
/**
* Return additional types/traits associated with this object.
*
* @return A collection of additional object traits.
* @see PeripheralType#getAdditionalTypes()
*/
@Nonnull
default Set<String> getAdditionalTypes()
{
return Collections.emptySet();
}
/** /**
* Is called when when a computer is attaching to the peripheral. * Is called when when a computer is attaching to the peripheral.
* *

View File

@@ -6,9 +6,13 @@
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
/** /**
* The type of a {@link GenericPeripheral}. * The type of a {@link GenericPeripheral}.
@@ -18,13 +22,19 @@ import javax.annotation.Nullable;
*/ */
public final class PeripheralType public final class PeripheralType
{ {
private static final PeripheralType UNTYPED = new PeripheralType( null ); private static final PeripheralType UNTYPED = new PeripheralType( null, Collections.emptySet() );
private final String type; private final String type;
private final Set<String> additionalTypes;
public PeripheralType( String type ) public PeripheralType( String type, Set<String> additionalTypes )
{ {
this.type = type; this.type = type;
this.additionalTypes = additionalTypes;
if( additionalTypes.contains( null ) )
{
throw new IllegalArgumentException( "All additional types must be non-null" );
}
} }
/** /**
@@ -46,7 +56,55 @@ public final class PeripheralType
public static PeripheralType ofType( @Nonnull String type ) public static PeripheralType ofType( @Nonnull String type )
{ {
if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" ); if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" );
return new PeripheralType( type ); return new PeripheralType( type, Collections.emptySet() );
}
/**
* Create a new non-empty peripheral type with additional traits.
*
* @param type The name of the type.
* @param additionalTypes Additional types, or "traits" of this peripheral. For instance, {@literal "inventory"}.
* @return The constructed peripheral type.
*/
public static PeripheralType ofType( @Nonnull String type, Collection<String> additionalTypes )
{
if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" );
return new PeripheralType( type, ImmutableSet.copyOf( additionalTypes ) );
}
/**
* Create a new non-empty peripheral type with additional traits.
*
* @param type The name of the type.
* @param additionalTypes Additional types, or "traits" of this peripheral. For instance, {@literal "inventory"}.
* @return The constructed peripheral type.
*/
public static PeripheralType ofType( @Nonnull String type, @Nonnull String... additionalTypes )
{
if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" );
return new PeripheralType( type, ImmutableSet.copyOf( additionalTypes ) );
}
/**
* Create a new peripheral type with no primary type but additional traits.
*
* @param additionalTypes Additional types, or "traits" of this peripheral. For instance, {@literal "inventory"}.
* @return The constructed peripheral type.
*/
public static PeripheralType ofAdditional( Collection<String> additionalTypes )
{
return new PeripheralType( null, ImmutableSet.copyOf( additionalTypes ) );
}
/**
* Create a new peripheral type with no primary type but additional traits.
*
* @param additionalTypes Additional types, or "traits" of this peripheral. For instance, {@literal "inventory"}.
* @return The constructed peripheral type.
*/
public static PeripheralType ofAdditional( @Nonnull String... additionalTypes )
{
return new PeripheralType( null, ImmutableSet.copyOf( additionalTypes ) );
} }
/** /**
@@ -59,4 +117,15 @@ public final class PeripheralType
{ {
return type; return type;
} }
/**
* Get any additional types or "traits" of this peripheral. These effectively act as a standard set of interfaces
* a peripheral might have.
*
* @return All additional types.
*/
public Set<String> getAdditionalTypes()
{
return additionalTypes;
}
} }

View File

@@ -6,7 +6,7 @@
package dan200.computercraft.api.pocket; package dan200.computercraft.api.pocket;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.IUpgradeBase; import dan200.computercraft.api.upgrades.IUpgradeBase;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;

View File

@@ -3,18 +3,13 @@
* Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
import dan200.computercraft.shared.util.NonNullSupplier; import dan200.computercraft.api.upgrades.IUpgradeBase;
import net.minecraft.Util;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ItemLike;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.function.Supplier;
/** /**
* A base class for {@link ITurtleUpgrade}s. * A base class for {@link ITurtleUpgrade}s.
@@ -26,9 +21,9 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade
private final ResourceLocation id; private final ResourceLocation id;
private final TurtleUpgradeType type; private final TurtleUpgradeType type;
private final String adjective; private final String adjective;
private final NonNullSupplier<ItemStack> stack; private final ItemStack stack;
protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, NonNullSupplier<ItemStack> stack ) protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, ItemStack stack )
{ {
this.id = id; this.id = id;
this.type = type; this.type = type;
@@ -36,39 +31,9 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade
this.stack = stack; this.stack = stack;
} }
protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, NonNullSupplier<ItemStack> stack )
{
this( id, type, Util.makeDescriptionId( "upgrade", id ) + ".adjective", stack );
}
protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, ItemStack stack )
{
this( id, type, adjective, () -> stack );
}
protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, ItemStack stack ) protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, ItemStack stack )
{ {
this( id, type, () -> stack ); this( id, type, IUpgradeBase.getDefaultAdjective( id ), stack );
}
protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, ItemLike item )
{
this( id, type, adjective, new CachedStack( () -> item ) );
}
protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, ItemLike item )
{
this( id, type, new CachedStack( () -> item ) );
}
protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, Supplier<? extends ItemLike> item )
{
this( id, type, adjective, new CachedStack( item ) );
}
protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, Supplier<? extends ItemLike> item )
{
this( id, type, new CachedStack( item ) );
} }
@Nonnull @Nonnull
@@ -96,32 +61,6 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade
@Override @Override
public final ItemStack getCraftingItem() public final ItemStack getCraftingItem()
{ {
return stack.get(); return stack;
}
/**
* A supplier which converts an item into an item stack.
*
* Constructing item stacks is somewhat expensive due to attaching capabilities. We cache it if given a consistent item.
*/
private static final class CachedStack implements NonNullSupplier<ItemStack>
{
private final Supplier<? extends ItemLike> provider;
private Item item;
private ItemStack stack;
CachedStack( Supplier<? extends ItemLike> provider )
{
this.provider = provider;
}
@Nonnull
@Override
public ItemStack get()
{
Item item = provider.get().asItem();
if( item == this.item && stack != null ) return stack;
return stack = new ItemStack( this.item = item );
}
} }
} }

View File

@@ -6,7 +6,7 @@
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.IUpgradeBase; import dan200.computercraft.api.upgrades.IUpgradeBase;
import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.client.TransformedModel;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;

View File

@@ -3,10 +3,11 @@
* Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api; package dan200.computercraft.api.upgrades;
import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade;
import net.minecraft.Util;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@@ -81,4 +82,18 @@ public interface IUpgradeBase
if( craftingShareTag == null ) return shareTag.isEmpty(); if( craftingShareTag == null ) return shareTag.isEmpty();
return shareTag.equals( craftingShareTag ); return shareTag.equals( craftingShareTag );
} }
/**
* Get a suitable default unlocalised adjective for an upgrade ID. This converts "modid:some_upgrade" to
* "upgrade.modid.some_upgrade.adjective".
*
* @param id The upgrade ID.
* @return The generated adjective.
* @see #getUnlocalisedAdjective()
*/
@Nonnull
static String getDefaultAdjective( @Nonnull ResourceLocation id )
{
return Util.makeDescriptionId( "upgrade", id ) + ".adjective";
}
} }

View File

@@ -3,11 +3,10 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client; package dan200.computercraft.client;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.Registry;
import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.common.IColouredItem;
import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.media.items.ItemDisk;
import dan200.computercraft.shared.media.items.ItemTreasureDisk; import dan200.computercraft.shared.media.items.ItemTreasureDisk;
@@ -34,6 +33,7 @@ import java.util.function.Consumer;
public final class ClientRegistry public final class ClientRegistry
{ {
private static final String[] EXTRA_MODELS = new String[] { private static final String[] EXTRA_MODELS = new String[] {
// Turtle upgrades
"turtle_modem_normal_off_left", "turtle_modem_normal_off_left",
"turtle_modem_normal_on_left", "turtle_modem_normal_on_left",
"turtle_modem_normal_off_right", "turtle_modem_normal_off_right",
@@ -49,6 +49,7 @@ public final class ClientRegistry
"turtle_speaker_upgrade_left", "turtle_speaker_upgrade_left",
"turtle_speaker_upgrade_right", "turtle_speaker_upgrade_right",
// Turtle block renderer
"turtle_colour", "turtle_colour",
"turtle_elf_overlay", "turtle_elf_overlay",
}; };
@@ -85,10 +86,10 @@ public final class ClientRegistry
{ {
ColorProviderRegistry.ITEM.register( ( stack, layer ) -> { ColorProviderRegistry.ITEM.register( ( stack, layer ) -> {
return layer == 1 ? ((ItemDisk) stack.getItem()).getColour( stack ) : 0xFFFFFF; return layer == 1 ? ((ItemDisk) stack.getItem()).getColour( stack ) : 0xFFFFFF;
}, ComputerCraftRegistry.ModItems.DISK ); }, Registry.ModItems.DISK );
ColorProviderRegistry.ITEM.register( ( stack, layer ) -> layer == 1 ? ItemTreasureDisk.getColour( stack ) : 0xFFFFFF, ColorProviderRegistry.ITEM.register( ( stack, layer ) -> layer == 1 ? ItemTreasureDisk.getColour( stack ) : 0xFFFFFF,
ComputerCraftRegistry.ModItems.TREASURE_DISK ); Registry.ModItems.TREASURE_DISK );
ColorProviderRegistry.ITEM.register( ( stack, layer ) -> { ColorProviderRegistry.ITEM.register( ( stack, layer ) -> {
switch( layer ) switch( layer )
@@ -102,12 +103,12 @@ public final class ClientRegistry
int light = ItemPocketComputer.getLightState( stack ); int light = ItemPocketComputer.getLightState( stack );
return light == -1 ? Colour.BLACK.getHex() : light; return light == -1 ? Colour.BLACK.getHex() : light;
} }
}, ComputerCraftRegistry.ModItems.POCKET_COMPUTER_NORMAL, ComputerCraftRegistry.ModItems.POCKET_COMPUTER_ADVANCED ); }, Registry.ModItems.POCKET_COMPUTER_NORMAL, Registry.ModItems.POCKET_COMPUTER_ADVANCED );
// Setup turtle colours // Setup turtle colours
ColorProviderRegistry.ITEM.register( ( stack, tintIndex ) -> tintIndex == 0 ? ((IColouredItem) stack.getItem()).getColour( stack ) : 0xFFFFFF, ColorProviderRegistry.ITEM.register( ( stack, tintIndex ) -> tintIndex == 0 ? ((IColouredItem) stack.getItem()).getColour( stack ) : 0xFFFFFF,
ComputerCraftRegistry.ModBlocks.TURTLE_NORMAL, Registry.ModBlocks.TURTLE_NORMAL,
ComputerCraftRegistry.ModBlocks.TURTLE_ADVANCED ); Registry.ModBlocks.TURTLE_ADVANCED );
} }
private static BakedModel bake( ModelBakery loader, UnbakedModel model, ResourceLocation identifier ) private static BakedModel bake( ModelBakery loader, UnbakedModel model, ResourceLocation identifier )

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client; package dan200.computercraft.client;
import dan200.computercraft.fabric.mixin.ChatComponentAccess; import dan200.computercraft.fabric.mixin.ChatComponentAccess;
@@ -25,17 +24,19 @@ public class ClientTableFormatter implements TableFormatter
{ {
public static final ClientTableFormatter INSTANCE = new ClientTableFormatter(); public static final ClientTableFormatter INSTANCE = new ClientTableFormatter();
private static Int2IntOpenHashMap lastHeights = new Int2IntOpenHashMap(); private static final Int2IntOpenHashMap lastHeights = new Int2IntOpenHashMap();
private static Font renderer()
{
return Minecraft.getInstance().font;
}
@Override @Override
@Nullable @Nullable
public Component getPadding( Component component, int width ) public Component getPadding( Component component, int width )
{ {
int extraWidth = width - getWidth( component ); int extraWidth = width - getWidth( component );
if( extraWidth <= 0 ) if( extraWidth <= 0 ) return null;
{
return null;
}
Font renderer = renderer(); Font renderer = renderer();
@@ -46,11 +47,6 @@ public class ClientTableFormatter implements TableFormatter
return ChatHelpers.coloured( StringUtils.repeat( ' ', spaces ) + StringUtils.repeat( (char) 712, extra ), ChatFormatting.GRAY ); return ChatHelpers.coloured( StringUtils.repeat( ' ', spaces ) + StringUtils.repeat( (char) 712, extra ), ChatFormatting.GRAY );
} }
private static Font renderer()
{
return Minecraft.getInstance().font;
}
@Override @Override
public int getColumnPadding() public int getColumnPadding()
{ {
@@ -71,7 +67,7 @@ public class ClientTableFormatter implements TableFormatter
// TODO: Trim the text if it goes over the allowed length // TODO: Trim the text if it goes over the allowed length
// int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() ); // int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() );
// List<ITextProperties> list = RenderComponentsUtil.func_238505_a_( component, maxWidth, mc.fontRenderer ); // List<ITextProperties> list = RenderComponentsUtil.wrapComponents( component, maxWidth, mc.fontRenderer );
// if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id ); // if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id );
((ChatComponentAccess) chat).callAddMessage( component, id ); ((ChatComponentAccess) chat).callAddMessage( component, id );
} }
@@ -86,10 +82,7 @@ public class ClientTableFormatter implements TableFormatter
int height = TableFormatter.super.display( table ); int height = TableFormatter.super.display( table );
lastHeights.put( table.getId(), height ); lastHeights.put( table.getId(), height );
for( int i = height; i < lastHeight; i++ ) for( int i = height; i < lastHeight; i++ ) ((ChatComponentAccess) chat).callRemoveById( i + table.getId() );
{
((ChatComponentAccess) chat).callRemoveById( i + table.getId() );
}
return height; return height;
} }
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client; package dan200.computercraft.client;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;

View File

@@ -36,7 +36,6 @@ import java.util.List;
public abstract class ComputerScreenBase<T extends ContainerComputerBase> extends AbstractContainerScreen<T> public abstract class ComputerScreenBase<T extends ContainerComputerBase> extends AbstractContainerScreen<T>
{ {
private static final Component OK = new TranslatableComponent( "gui.ok" ); private static final Component OK = new TranslatableComponent( "gui.ok" );
private static final Component CANCEL = new TranslatableComponent( "gui.cancel" ); private static final Component CANCEL = new TranslatableComponent( "gui.cancel" );
private static final Component OVERWRITE = new TranslatableComponent( "gui.computercraft.upload.overwrite_button" ); private static final Component OVERWRITE = new TranslatableComponent( "gui.computercraft.upload.overwrite_button" );
@@ -94,6 +93,7 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
return super.keyPressed( key, scancode, modifiers ); return super.keyPressed( key, scancode, modifiers );
} }
@Override @Override
public final void render( @Nonnull PoseStack stack, int mouseX, int mouseY, float partialTicks ) public final void render( @Nonnull PoseStack stack, int mouseX, int mouseY, float partialTicks )
{ {
@@ -105,9 +105,11 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
@Override @Override
public final boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY ) public final boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY )
{ {
return getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY ) || super.mouseDragged( x, y, button, deltaX, deltaY ); return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY ))
|| super.mouseDragged( x, y, button, deltaX, deltaY );
} }
@Override @Override
protected void renderLabels( @Nonnull PoseStack transform, int mouseX, int mouseY ) protected void renderLabels( @Nonnull PoseStack transform, int mouseX, int mouseY )
{ {
@@ -207,7 +209,7 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
private void continueUpload() private void continueUpload()
{ {
if( minecraft.screen instanceof OptionScreen ) ((OptionScreen) minecraft.screen).disable(); if( minecraft.screen instanceof OptionScreen screen ) screen.disable();
NetworkHandler.sendToServer( new ContinueUploadMessage( computer.getInstanceID(), true ) ); NetworkHandler.sendToServer( new ContinueUploadMessage( computer.getInstanceID(), true ) );
} }
@@ -224,5 +226,4 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
() -> minecraft.setScreen( this ) () -> minecraft.setScreen( this )
); );
} }
} }

View File

@@ -3,19 +3,17 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix4f; import com.mojang.math.Matrix4f;
import com.mojang.math.Transformation;
import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.render.RenderTypes; import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Palette; import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
@@ -24,25 +22,138 @@ import javax.annotation.Nullable;
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP; import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
/**
* Handles rendering fixed width text and computer terminals.
*
* 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,
* this accepts a lightmap coordinate as, unlike terminals, printed pages render fullbright.</li>
* <li>{@link #drawTerminalWithoutCursor}/{@link #drawCursor}: Draw a terminal without a cursor and then draw the cursor
* separately. This is used by the monitor renderer to render the terminal to a VBO and draw the cursor dynamically.
* </li>
* <li>{@link #drawTerminal}: Draw a terminal with a cursor. This is used by the various computer GUIs to render the
* whole term.</li>
* <li>{@link #drawBlocker}: When rendering a terminal using {@link RenderTypes#TERMINAL_WITHOUT_DEPTH} you need to
* render an additional "depth blocker" on top of the monitor.</li>
* </ul>
*/
public final class FixedWidthFontRenderer public final class FixedWidthFontRenderer
{ {
public static final ResourceLocation FONT = new ResourceLocation( "computercraft", "textures/gui/term_font.png" );
public static final int FONT_HEIGHT = 9; public static final int FONT_HEIGHT = 9;
public static final int FONT_WIDTH = 6; public static final int FONT_WIDTH = 6;
public static final float WIDTH = 256.0f; public static final float WIDTH = 256.0f;
public static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH; public static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH;
public static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH; public static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH;
private static final Matrix4f IDENTITY = Transformation.identity()
.getMatrix();
public static final ResourceLocation FONT = new ResourceLocation( "computercraft", "textures/gui/term_font.png" );
private FixedWidthFontRenderer() private FixedWidthFontRenderer()
{ {
} }
public static void drawString( @Nonnull Matrix4f transform, @Nonnull VertexConsumer renderer, float x, float y, @Nonnull TextBuffer text, public static float toGreyscale( double[] rgb )
@Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, {
float leftMarginSize, float rightMarginSize, int light ) return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3);
}
public static int getColour( char c, Colour def )
{
return 15 - Terminal.getColour( c, def );
}
private static void drawChar( Matrix4f transform, VertexConsumer buffer, float x, float y, int index, float r, float g, float b, int light )
{
// Short circuit to avoid the common case - the texture should be blank here after all.
if( index == '\0' || index == ' ' ) return;
int column = index % 16;
int row = index / 16;
int xStart = 1 + column * (FONT_WIDTH + 2);
int yStart = 1 + row * (FONT_HEIGHT + 2);
buffer.vertex( transform, x, y, 0f ).color( r, g, b, 1.0f ).uv( xStart / WIDTH, yStart / WIDTH ).uv2( light ).endVertex();
buffer.vertex( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).uv( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).uv2( light ).endVertex();
buffer.vertex( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).uv( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).uv2( light ).endVertex();
buffer.vertex( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).uv( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).uv2( light ).endVertex();
buffer.vertex( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).uv( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).uv2( light ).endVertex();
buffer.vertex( transform, x + FONT_WIDTH, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).uv( (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).uv2( light ).endVertex();
}
private static void drawQuad( Matrix4f transform, VertexConsumer buffer, float x, float y, float width, float height, float r, float g, float b )
{
buffer.vertex( transform, x, y, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_START ).endVertex();
buffer.vertex( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_END ).endVertex();
buffer.vertex( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_START ).endVertex();
buffer.vertex( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_START ).endVertex();
buffer.vertex( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_END ).endVertex();
buffer.vertex( transform, x + width, y + height, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_END ).endVertex();
}
private static void drawQuad( Matrix4f transform, VertexConsumer buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex )
{
double[] colour = palette.getColour( getColour( colourIndex, Colour.BLACK ) );
float r, g, b;
if( greyscale )
{
r = g = b = toGreyscale( colour );
}
else
{
r = (float) colour[0];
g = (float) colour[1];
b = (float) colour[2];
}
drawQuad( transform, buffer, x, y, width, height, r, g, b );
}
private static void drawBackground(
@Nonnull Matrix4f transform, @Nonnull VertexConsumer renderer, float x, float y,
@Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale,
float leftMarginSize, float rightMarginSize, float height
)
{
if( leftMarginSize > 0 )
{
drawQuad( transform, renderer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) );
}
if( rightMarginSize > 0 )
{
drawQuad( transform, renderer, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, greyscale, backgroundColour.charAt( backgroundColour.length() - 1 ) );
}
// Batch together runs of identical background cells.
int blockStart = 0;
char blockColour = '\0';
for( int i = 0; i < backgroundColour.length(); i++ )
{
char colourIndex = backgroundColour.charAt( i );
if( colourIndex == blockColour ) continue;
if( blockColour != '\0' )
{
drawQuad( transform, renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour );
}
blockColour = colourIndex;
blockStart = i;
}
if( blockColour != '\0' )
{
drawQuad( transform, renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour );
}
}
public static void drawString(
@Nonnull Matrix4f transform, @Nonnull VertexConsumer renderer, float x, float y,
@Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour,
@Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize, int light
)
{ {
if( backgroundColour != null ) if( backgroundColour != null )
{ {
@@ -66,223 +177,49 @@ public final class FixedWidthFontRenderer
// Draw char // Draw char
int index = text.charAt( i ); int index = text.charAt( i );
if( index > 255 ) if( index > 255 ) index = '?';
{
index = '?';
}
drawChar( transform, renderer, x + i * FONT_WIDTH, y, index, r, g, b, light ); drawChar( transform, renderer, x + i * FONT_WIDTH, y, index, r, g, b, light );
} }
} }
private static void drawBackground( @Nonnull Matrix4f transform, @Nonnull VertexConsumer renderer, float x, float y, public static void drawTerminalWithoutCursor(
@Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, float leftMarginSize, @Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y,
float rightMarginSize, float height ) @Nonnull Terminal terminal, boolean greyscale,
{ float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
if( leftMarginSize > 0 ) )
{
drawQuad( transform, renderer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) );
}
if( rightMarginSize > 0 )
{
drawQuad( transform,
renderer,
x + backgroundColour.length() * FONT_WIDTH,
y,
rightMarginSize,
height,
palette,
greyscale,
backgroundColour.charAt( backgroundColour.length() - 1 ) );
}
// Batch together runs of identical background cells.
int blockStart = 0;
char blockColour = '\0';
for( int i = 0; i < backgroundColour.length(); i++ )
{
char colourIndex = backgroundColour.charAt( i );
if( colourIndex == blockColour )
{
continue;
}
if( blockColour != '\0' )
{
drawQuad( transform, renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour );
}
blockColour = colourIndex;
blockStart = i;
}
if( blockColour != '\0' )
{
drawQuad( transform,
renderer,
x + blockStart * FONT_WIDTH,
y,
FONT_WIDTH * (backgroundColour.length() - blockStart),
height,
palette,
greyscale,
blockColour );
}
}
public static int getColour( char c, Colour def )
{
return 15 - Terminal.getColour( c, def );
}
public static float toGreyscale( double[] rgb )
{
return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3);
}
private static void drawChar( Matrix4f transform, VertexConsumer buffer, float x, float y, int index, float r, float g, float b, int light )
{
// Short circuit to avoid the common case - the texture should be blank here after all.
if( index == '\0' || index == ' ' )
{
return;
}
int column = index % 16;
int row = index / 16;
int xStart = 1 + column * (FONT_WIDTH + 2);
int yStart = 1 + row * (FONT_HEIGHT + 2);
buffer.vertex( transform, x, y, 0f )
.color( r, g, b, 1.0f )
.uv( xStart / WIDTH, yStart / WIDTH )
.uv2( light )
.endVertex();
buffer.vertex( transform, x, y + FONT_HEIGHT, 0f )
.color( r, g, b, 1.0f )
.uv( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH )
.uv2( light )
.endVertex();
buffer.vertex( transform, x + FONT_WIDTH, y, 0f )
.color( r, g, b, 1.0f )
.uv( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH )
.uv2( light )
.endVertex();
buffer.vertex( transform, x + FONT_WIDTH, y, 0f )
.color( r, g, b, 1.0f )
.uv( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH )
.uv2( light )
.endVertex();
buffer.vertex( transform, x, y + FONT_HEIGHT, 0f )
.color( r, g, b, 1.0f )
.uv( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH )
.uv2( light )
.endVertex();
buffer.vertex( transform, x + FONT_WIDTH, y + FONT_HEIGHT, 0f )
.color( r, g, b, 1.0f )
.uv( (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH )
.uv2( light )
.endVertex();
}
private static void drawQuad( Matrix4f transform, VertexConsumer buffer, float x, float y, float width, float height, Palette palette,
boolean greyscale, char colourIndex )
{
double[] colour = palette.getColour( getColour( colourIndex, Colour.BLACK ) );
float r, g, b;
if( greyscale )
{
r = g = b = toGreyscale( colour );
}
else
{
r = (float) colour[0];
g = (float) colour[1];
b = (float) colour[2];
}
drawQuad( transform, buffer, x, y, width, height, r, g, b );
}
private static void drawQuad( Matrix4f transform, VertexConsumer buffer, float x, float y, float width, float height, float r, float g, float b )
{
buffer.vertex( transform, x, y, 0 )
.color( r, g, b, 1.0f )
.uv( BACKGROUND_START, BACKGROUND_START )
.endVertex();
buffer.vertex( transform, x, y + height, 0 )
.color( r, g, b, 1.0f )
.uv( BACKGROUND_START, BACKGROUND_END )
.endVertex();
buffer.vertex( transform, x + width, y, 0 )
.color( r, g, b, 1.0f )
.uv( BACKGROUND_END, BACKGROUND_START )
.endVertex();
buffer.vertex( transform, x + width, y, 0 )
.color( r, g, b, 1.0f )
.uv( BACKGROUND_END, BACKGROUND_START )
.endVertex();
buffer.vertex( transform, x, y + height, 0 )
.color( r, g, b, 1.0f )
.uv( BACKGROUND_START, BACKGROUND_END )
.endVertex();
buffer.vertex( transform, x + width, y + height, 0 )
.color( r, g, b, 1.0f )
.uv( BACKGROUND_END, BACKGROUND_END )
.endVertex();
}
public static void drawTerminalWithoutCursor( @Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y,
@Nonnull Terminal terminal, boolean greyscale, float topMarginSize, float bottomMarginSize,
float leftMarginSize, float rightMarginSize )
{ {
Palette palette = terminal.getPalette(); Palette palette = terminal.getPalette();
int height = terminal.getHeight(); int height = terminal.getHeight();
// Top and bottom margins // Top and bottom margins
drawBackground( transform, drawBackground(
buffer, transform, buffer, x, y - topMarginSize,
x, terminal.getBackgroundColourLine( 0 ), palette, greyscale,
y - topMarginSize, leftMarginSize, rightMarginSize, topMarginSize
terminal.getBackgroundColourLine( 0 ), );
palette,
greyscale,
leftMarginSize,
rightMarginSize,
topMarginSize );
drawBackground( transform, drawBackground(
buffer, transform, buffer, x, y + height * FONT_HEIGHT,
x, terminal.getBackgroundColourLine( height - 1 ), palette, greyscale,
y + height * FONT_HEIGHT, leftMarginSize, rightMarginSize, bottomMarginSize
terminal.getBackgroundColourLine( height - 1 ), );
palette,
greyscale,
leftMarginSize,
rightMarginSize,
bottomMarginSize );
// The main text // The main text
for( int i = 0; i < height; i++ ) for( int i = 0; i < height; i++ )
{ {
drawString( transform, drawString(
buffer, transform, buffer, x, y + FixedWidthFontRenderer.FONT_HEIGHT * i,
x, terminal.getLine( i ), terminal.getTextColourLine( i ), terminal.getBackgroundColourLine( i ),
y + FixedWidthFontRenderer.FONT_HEIGHT * i, palette, greyscale, leftMarginSize, rightMarginSize, FULL_BRIGHT_LIGHTMAP
terminal.getLine( i ), );
terminal.getTextColourLine( i ),
terminal.getBackgroundColourLine( i ),
palette,
greyscale,
leftMarginSize,
rightMarginSize, FULL_BRIGHT_LIGHTMAP );
} }
} }
public static void drawCursor( @Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y, @Nonnull Terminal terminal, public static void drawCursor(
boolean greyscale ) @Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y,
@Nonnull Terminal terminal, boolean greyscale
)
{ {
Palette palette = terminal.getPalette(); Palette palette = terminal.getPalette();
int width = terminal.getWidth(); int width = terminal.getWidth();
@@ -309,52 +246,40 @@ public final class FixedWidthFontRenderer
} }
} }
public static void drawTerminal( @Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y, @Nonnull Terminal terminal, public static void drawTerminal(
boolean greyscale, float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize ) @Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y,
@Nonnull Terminal terminal, boolean greyscale,
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
)
{ {
drawTerminalWithoutCursor( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); drawTerminalWithoutCursor( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
drawCursor( transform, buffer, x, y, terminal, greyscale ); drawCursor( transform, buffer, x, y, terminal, greyscale );
} }
public static void drawTerminal( @Nonnull Matrix4f transform, float x, float y, @Nonnull Terminal terminal, boolean greyscale, float topMarginSize, public static void drawTerminal(
float bottomMarginSize, float leftMarginSize, float rightMarginSize ) @Nonnull Matrix4f transform, float x, float y, @Nonnull Terminal terminal, boolean greyscale,
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
)
{ {
MultiBufferSource.BufferSource renderer = Minecraft.getInstance() MultiBufferSource.BufferSource renderer = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() );
.renderBuffers()
.bufferSource();
VertexConsumer buffer = renderer.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ); VertexConsumer buffer = renderer.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH );
drawTerminal( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); drawTerminal( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
renderer.endBatch(); renderer.endBatch();
} }
public static void drawTerminal( float x, float y, @Nonnull Terminal terminal, boolean greyscale, float topMarginSize, float bottomMarginSize, public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull MultiBufferSource renderer, float x, float y, float width, float height )
float leftMarginSize, float rightMarginSize )
{
drawTerminal( IDENTITY, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
}
public static void drawEmptyTerminal( float x, float y, float width, float height )
{ {
Colour colour = Colour.BLACK; Colour colour = Colour.BLACK;
drawEmptyTerminal( IDENTITY, x, y, width, height ); drawQuad( transform, renderer.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() );
} }
public static void drawEmptyTerminal( @Nonnull Matrix4f transform, float x, float y, float width, float height ) public static void drawEmptyTerminal( @Nonnull Matrix4f transform, float x, float y, float width, float height )
{ {
MultiBufferSource.BufferSource renderer = Minecraft.getInstance() MultiBufferSource.BufferSource renderer = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() );
.renderBuffers()
.bufferSource();
drawEmptyTerminal( transform, renderer, x, y, width, height ); drawEmptyTerminal( transform, renderer, x, y, width, height );
renderer.endBatch(); renderer.endBatch();
} }
public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull MultiBufferSource renderer, float x, float y, float width,
float height )
{
Colour colour = Colour.BLACK;
drawQuad( transform, renderer.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() );
}
public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull MultiBufferSource renderer, float x, float y, float width, float height ) public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull MultiBufferSource renderer, float x, float y, float width, float height )
{ {
Colour colour = Colour.BLACK; Colour colour = Colour.BLACK;

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
@@ -20,14 +19,15 @@ import net.minecraft.world.entity.player.Inventory;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER; import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
import static dan200.computercraft.client.render.ComputerBorderRenderer.getTexture;
public final class GuiComputer<T extends ContainerComputerBase> extends ComputerScreenBase<T> public final class GuiComputer<T extends ContainerComputerBase> extends ComputerScreenBase<T>
{ {
private final int termWidth; private final int termWidth;
private final int termHeight; private final int termHeight;
private GuiComputer( T container, Inventory player, Component title, int termWidth, int termHeight ) private GuiComputer(
T container, Inventory player, Component title, int termWidth, int termHeight
)
{ {
super( container, player, title, BORDER ); super( container, player, title, BORDER );
this.termWidth = termWidth; this.termWidth = termWidth;
@@ -37,19 +37,31 @@ public final class GuiComputer<T extends ContainerComputerBase> extends Computer
imageHeight = WidgetTerminal.getHeight( termHeight ) + BORDER * 2; imageHeight = WidgetTerminal.getHeight( termHeight ) + BORDER * 2;
} }
@Nonnull
public static GuiComputer<ContainerComputerBase> create( ContainerComputerBase container, Inventory inventory, Component component ) public static GuiComputer<ContainerComputerBase> create( ContainerComputerBase container, Inventory inventory, Component component )
{ {
return new GuiComputer<>( container, inventory, component, ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight ); return new GuiComputer<>(
container, inventory, component,
ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight
);
} }
@Nonnull
public static GuiComputer<ContainerComputerBase> createPocket( ContainerComputerBase container, Inventory inventory, Component component ) public static GuiComputer<ContainerComputerBase> createPocket( ContainerComputerBase container, Inventory inventory, Component component )
{ {
return new GuiComputer<>( container, inventory, component, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ); return new GuiComputer<>(
container, inventory, component,
ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight
);
} }
@Nonnull
public static GuiComputer<ContainerViewComputer> createView( ContainerViewComputer container, Inventory inventory, Component component ) public static GuiComputer<ContainerViewComputer> createView( ContainerViewComputer container, Inventory inventory, Component component )
{ {
return new GuiComputer<>( container, inventory, component, container.getWidth(), container.getHeight() ); return new GuiComputer<>(
container, inventory, component,
container.getWidth(), container.getHeight()
);
} }
@Override @Override
@@ -63,9 +75,11 @@ public final class GuiComputer<T extends ContainerComputerBase> extends Computer
@Override @Override
public void renderBg( @Nonnull PoseStack stack, float partialTicks, int mouseX, int mouseY ) public void renderBg( @Nonnull PoseStack stack, float partialTicks, int mouseX, int mouseY )
{ {
// Draw a border around the terminal
ComputerBorderRenderer.render( ComputerBorderRenderer.render(
getTexture( family ), terminal.x, terminal.y, getBlitOffset(), ComputerBorderRenderer.getTexture( family ), terminal.x, terminal.y, getBlitOffset(),
RenderTypes.FULL_BRIGHT_LIGHTMAP, terminal.getWidth(), terminal.getHeight() ); RenderTypes.FULL_BRIGHT_LIGHTMAP, terminal.getWidth(), terminal.getHeight()
);
ComputerSidebar.renderBackground( stack, leftPos, topPos + sidebarYOffset ); ComputerSidebar.renderBackground( stack, leftPos, topPos + sidebarYOffset );
} }
} }

View File

@@ -3,14 +3,12 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
@@ -26,6 +24,14 @@ public class GuiDiskDrive extends AbstractContainerScreen<ContainerDiskDrive>
super( container, player, title ); super( container, player, title );
} }
@Override
protected void renderBg( @Nonnull PoseStack transform, float partialTicks, int mouseX, int mouseY )
{
RenderSystem.setShaderColor( 1.0F, 1.0F, 1.0F, 1.0F );
RenderSystem.setShaderTexture( 0, BACKGROUND );
blit( transform, leftPos, topPos, 0, 0, imageWidth, imageHeight );
}
@Override @Override
public void render( @Nonnull PoseStack transform, int mouseX, int mouseY, float partialTicks ) public void render( @Nonnull PoseStack transform, int mouseX, int mouseY, float partialTicks )
{ {
@@ -33,13 +39,4 @@ public class GuiDiskDrive extends AbstractContainerScreen<ContainerDiskDrive>
super.render( transform, mouseX, mouseY, partialTicks ); super.render( transform, mouseX, mouseY, partialTicks );
renderTooltip( transform, mouseX, mouseY ); renderTooltip( transform, mouseX, mouseY );
} }
@Override
protected void renderBg( @Nonnull PoseStack transform, float partialTicks, int mouseX, int mouseY )
{
RenderSystem.setShader( GameRenderer::getPositionTexShader );
RenderSystem.setShaderColor( 1.0F, 1.0F, 1.0F, 1.0F );
RenderSystem.setShaderTexture( 0, BACKGROUND );
blit( transform, leftPos, topPos, 0, 0, imageWidth, imageHeight );
}
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
@@ -25,14 +24,6 @@ public class GuiPrinter extends AbstractContainerScreen<ContainerPrinter>
super( container, player, title ); super( container, player, title );
} }
@Override
public void render( @Nonnull PoseStack stack, int mouseX, int mouseY, float partialTicks )
{
renderBackground( stack );
super.render( stack, mouseX, mouseY, partialTicks );
renderTooltip( stack, mouseX, mouseY );
}
@Override @Override
protected void renderBg( @Nonnull PoseStack transform, float partialTicks, int mouseX, int mouseY ) protected void renderBg( @Nonnull PoseStack transform, float partialTicks, int mouseX, int mouseY )
{ {
@@ -40,9 +31,14 @@ public class GuiPrinter extends AbstractContainerScreen<ContainerPrinter>
RenderSystem.setShaderTexture( 0, BACKGROUND ); RenderSystem.setShaderTexture( 0, BACKGROUND );
blit( transform, leftPos, topPos, 0, 0, imageWidth, imageHeight ); blit( transform, leftPos, topPos, 0, 0, imageWidth, imageHeight );
if( getMenu().isPrinting() ) if( getMenu().isPrinting() ) blit( transform, leftPos + 34, topPos + 21, 176, 0, 25, 45 );
{ }
blit( transform, leftPos + 34, topPos + 21, 176, 0, 25, 45 );
} @Override
public void render( @Nonnull PoseStack stack, int mouseX, int mouseY, float partialTicks )
{
renderBackground( stack );
super.render( stack, mouseX, mouseY, partialTicks );
renderTooltip( stack, mouseX, mouseY );
} }
} }

View File

@@ -3,16 +3,15 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.math.Matrix4f; import com.mojang.math.Matrix4f;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.media.items.ItemPrintout;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
@@ -40,54 +39,72 @@ public class GuiPrintout extends AbstractContainerScreen<ContainerHeldItem>
String[] text = ItemPrintout.getText( container.getStack() ); String[] text = ItemPrintout.getText( container.getStack() );
this.text = new TextBuffer[text.length]; this.text = new TextBuffer[text.length];
for( int i = 0; i < this.text.length; i++ ) for( int i = 0; i < this.text.length; i++ ) this.text[i] = new TextBuffer( text[i] );
{
this.text[i] = new TextBuffer( text[i] );
}
String[] colours = ItemPrintout.getColours( container.getStack() ); String[] colours = ItemPrintout.getColours( container.getStack() );
this.colours = new TextBuffer[colours.length]; this.colours = new TextBuffer[colours.length];
for( int i = 0; i < this.colours.length; i++ ) for( int i = 0; i < this.colours.length; i++ ) this.colours[i] = new TextBuffer( colours[i] );
{
this.colours[i] = new TextBuffer( colours[i] );
}
page = 0; page = 0;
pages = Math.max( this.text.length / ItemPrintout.LINES_PER_PAGE, 1 ); pages = Math.max( this.text.length / ItemPrintout.LINES_PER_PAGE, 1 );
book = ((ItemPrintout) container.getStack() book = ((ItemPrintout) container.getStack().getItem()).getType() == ItemPrintout.Type.BOOK;
.getItem()).getType() == ItemPrintout.Type.BOOK; }
@Override
public boolean keyPressed( int key, int scancode, int modifiers )
{
if( super.keyPressed( key, scancode, modifiers ) ) return true;
if( key == GLFW.GLFW_KEY_RIGHT )
{
if( page < pages - 1 ) page++;
return true;
}
if( key == GLFW.GLFW_KEY_LEFT )
{
if( page > 0 ) page--;
return true;
}
return false;
} }
@Override @Override
public boolean mouseScrolled( double x, double y, double delta ) public boolean mouseScrolled( double x, double y, double delta )
{ {
if( super.mouseScrolled( x, y, delta ) ) if( super.mouseScrolled( x, y, delta ) ) return true;
{
return true;
}
if( delta < 0 ) if( delta < 0 )
{ {
// Scroll up goes to the next page // Scroll up goes to the next page
if( page < pages - 1 ) if( page < pages - 1 ) page++;
{
page++;
}
return true; return true;
} }
if( delta > 0 ) if( delta > 0 )
{ {
// Scroll down goes to the previous page // Scroll down goes to the previous page
if( page > 0 ) if( page > 0 ) page--;
{
page--;
}
return true; return true;
} }
return false; return false;
} }
@Override
protected void renderBg( @Nonnull PoseStack transform, float partialTicks, int mouseX, int mouseY )
{
// Draw the printout
RenderSystem.setShaderColor( 1.0f, 1.0f, 1.0f, 1.0f );
RenderSystem.enableDepthTest();
MultiBufferSource.BufferSource renderer = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() );
Matrix4f matrix = transform.last().pose();
drawBorder( matrix, renderer, leftPos, topPos, getBlitOffset(), page, pages, book, FULL_BRIGHT_LIGHTMAP );
drawText( matrix, renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, text, colours );
renderer.endBatch();
}
@Override @Override
public void render( @Nonnull PoseStack stack, int mouseX, int mouseY, float partialTicks ) public void render( @Nonnull PoseStack stack, int mouseX, int mouseY, float partialTicks )
{ {
@@ -104,50 +121,4 @@ public class GuiPrintout extends AbstractContainerScreen<ContainerHeldItem>
{ {
// Skip rendering labels. // Skip rendering labels.
} }
@Override
protected void renderBg( @Nonnull PoseStack transform, float partialTicks, int mouseX, int mouseY )
{
// Draw the printout
RenderSystem.setShaderColor( 1.0f, 1.0f, 1.0f, 1.0f );
RenderSystem.enableDepthTest();
MultiBufferSource.BufferSource renderer = Minecraft.getInstance()
.renderBuffers()
.bufferSource();
Matrix4f matrix = transform.last()
.pose();
drawBorder( matrix, renderer, leftPos, topPos, getBlitOffset(), page, pages, book, FULL_BRIGHT_LIGHTMAP );
drawText( matrix, renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, text, colours );
renderer.endBatch();
}
@Override
public boolean keyPressed( int key, int scancode, int modifiers )
{
if( super.keyPressed( key, scancode, modifiers ) )
{
return true;
}
if( key == GLFW.GLFW_KEY_RIGHT )
{
if( page < pages - 1 )
{
page++;
}
return true;
}
if( key == GLFW.GLFW_KEY_LEFT )
{
if( page > 0 )
{
page--;
}
return true;
}
return false;
}
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
@@ -20,12 +19,12 @@ import net.minecraft.world.entity.player.Inventory;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import static dan200.computercraft.shared.turtle.inventory.ContainerTurtle.BORDER; import static dan200.computercraft.shared.turtle.inventory.ContainerTurtle.*;
public class GuiTurtle extends ComputerScreenBase<ContainerTurtle> public class GuiTurtle extends ComputerScreenBase<ContainerTurtle>
{ {
private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( "computercraft", "textures/gui/turtle_normal.png" ); private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/turtle_normal.png" );
private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( "computercraft", "textures/gui/turtle_advanced.png" ); private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/turtle_advanced.png" );
private static final int TEX_WIDTH = 254; private static final int TEX_WIDTH = 254;
private static final int TEX_HEIGHT = 217; private static final int TEX_HEIGHT = 217;
@@ -35,11 +34,10 @@ public class GuiTurtle extends ComputerScreenBase<ContainerTurtle>
public GuiTurtle( ContainerTurtle container, Inventory player, Component title ) public GuiTurtle( ContainerTurtle container, Inventory player, Component title )
{ {
super( container, player, title, BORDER ); super( container, player, title, BORDER );
family = container.getFamily(); family = container.getFamily();
imageWidth = TEX_WIDTH + ComputerSidebar.WIDTH; imageWidth = TEX_WIDTH + ComputerSidebar.WIDTH;
imageHeight = TEX_HEIGHT; imageHeight = TEX_HEIGHT;
} }
@Override @Override
@@ -52,23 +50,22 @@ public class GuiTurtle extends ComputerScreenBase<ContainerTurtle>
} }
@Override @Override
public void renderBg( @Nonnull PoseStack transform, float partialTicks, int mouseX, int mouseY ) protected void renderBg( @Nonnull PoseStack transform, float partialTicks, int mouseX, int mouseY )
{ {
boolean advanced = family == ComputerFamily.ADVANCED; boolean advanced = family == ComputerFamily.ADVANCED;
RenderSystem.setShaderTexture( 0, advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); RenderSystem.setShaderTexture( 0, advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
blit( transform, leftPos + ComputerSidebar.WIDTH, topPos, 0, 0, TEX_WIDTH, TEX_HEIGHT ); blit( transform, leftPos + ComputerSidebar.WIDTH, topPos, 0, 0, TEX_WIDTH, TEX_HEIGHT );
// Draw selection slot
int slot = getMenu().getSelectedSlot(); int slot = getMenu().getSelectedSlot();
if( slot >= 0 ) if( slot >= 0 )
{ {
RenderSystem.setShaderColor( 1.0F, 1.0F, 1.0F, 1.0F );
int slotX = slot % 4; int slotX = slot % 4;
int slotY = slot / 4; int slotY = slot / 4;
blit( transform, leftPos + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, topPos + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18, blit( transform,
0, leftPos + TURTLE_START_X - 2 + slotX * 18, topPos + PLAYER_START_Y - 2 + slotY * 18,
217, 0, 217, 24, 24
24, );
24 );
} }
RenderSystem.setShaderTexture( 0, advanced ? ComputerBorderRenderer.BACKGROUND_ADVANCED : ComputerBorderRenderer.BACKGROUND_NORMAL ); RenderSystem.setShaderTexture( 0, advanced ? ComputerBorderRenderer.BACKGROUND_ADVANCED : ComputerBorderRenderer.BACKGROUND_NORMAL );

View File

@@ -43,9 +43,10 @@ public class NoTermComputerScreen<T extends ContainerComputerBase> extends Scree
@Override @Override
protected void init() protected void init()
{ {
this.passEvents = true; passEvents = true; // Pass mouse vents through to the game's mouse handler.
minecraft.mouseHandler.grabMouse(); minecraft.mouseHandler.grabMouse();
minecraft.screen = this; minecraft.screen = this;
super.init(); super.init();
minecraft.keyboardHandler.setSendRepeatsToGui( true ); minecraft.keyboardHandler.setSendRepeatsToGui( true );
@@ -102,7 +103,7 @@ public class NoTermComputerScreen<T extends ContainerComputerBase> extends Scree
} }
@Override @Override
public void render( PoseStack transform, int mouseX, int mouseY, float partialTicks ) public void render( @Nonnull PoseStack transform, int mouseX, int mouseY, float partialTicks )
{ {
super.render( transform, mouseX, mouseY, partialTicks ); super.render( transform, mouseX, mouseY, partialTicks );

View File

@@ -49,9 +49,9 @@ public final class OptionScreen extends Screen
this.originalScreen = originalScreen; this.originalScreen = originalScreen;
} }
public static void show( Minecraft client, Component title, Component message, List<AbstractWidget> buttons, Runnable exit ) public static void show( Minecraft minecraft, Component title, Component message, List<AbstractWidget> buttons, Runnable exit )
{ {
client.setScreen( new OptionScreen( title, message, buttons, exit, unwrap( client.screen ) ) ); minecraft.setScreen( new OptionScreen( title, message, buttons, exit, unwrap( minecraft.screen ) ) );
} }
public static Screen unwrap( Screen screen ) public static Screen unwrap( Screen screen )

View File

@@ -8,7 +8,6 @@ package dan200.computercraft.client.gui.widgets;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.render.ComputerBorderRenderer; import dan200.computercraft.client.render.ComputerBorderRenderer;
import dan200.computercraft.shared.command.text.ChatHelpers;
import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ClientComputer;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.AbstractWidget;
@@ -55,10 +54,10 @@ public final class ComputerSidebar
TEXTURE, TEX_SIZE, TEX_SIZE, b -> toggleComputer( computer ), TEXTURE, TEX_SIZE, TEX_SIZE, b -> toggleComputer( computer ),
() -> computer.isOn() ? Arrays.asList( () -> computer.isOn() ? Arrays.asList(
new TranslatableComponent( "gui.computercraft.tooltip.turn_off" ), new TranslatableComponent( "gui.computercraft.tooltip.turn_off" ),
ChatHelpers.coloured( new TranslatableComponent( "gui.computercraft.tooltip.turn_off.key" ), ChatFormatting.GRAY ) new TranslatableComponent( "gui.computercraft.tooltip.turn_off.key" ).withStyle( ChatFormatting.GRAY )
) : Arrays.asList( ) : Arrays.asList(
new TranslatableComponent( "gui.computercraft.tooltip.turn_on" ), new TranslatableComponent( "gui.computercraft.tooltip.turn_on" ),
ChatHelpers.coloured( new TranslatableComponent( "gui.computercraft.tooltip.turn_off.key" ), ChatFormatting.GRAY ) new TranslatableComponent( "gui.computercraft.tooltip.turn_off.key" ).withStyle( ChatFormatting.GRAY )
) )
) ); ) );
@@ -69,7 +68,7 @@ public final class ComputerSidebar
TEXTURE, TEX_SIZE, TEX_SIZE, b -> computer.queueEvent( "terminate" ), TEXTURE, TEX_SIZE, TEX_SIZE, b -> computer.queueEvent( "terminate" ),
Arrays.asList( Arrays.asList(
new TranslatableComponent( "gui.computercraft.tooltip.terminate" ), new TranslatableComponent( "gui.computercraft.tooltip.terminate" ),
ChatHelpers.coloured( new TranslatableComponent( "gui.computercraft.tooltip.terminate.key" ), ChatFormatting.GRAY ) new TranslatableComponent( "gui.computercraft.tooltip.terminate.key" ).withStyle( ChatFormatting.GRAY )
) )
) ); ) );
} }

View File

@@ -7,6 +7,7 @@ package dan200.computercraft.client.gui.widgets;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import dan200.computercraft.shared.util.NonNullSupplier;
import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
@@ -16,7 +17,6 @@ import net.minecraft.resources.ResourceLocation;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.List; import java.util.List;
import java.util.function.IntSupplier; import java.util.function.IntSupplier;
import java.util.function.Supplier;
/** /**
* Version of {@link net.minecraft.client.gui.components.ImageButton} which allows changing some properties * Version of {@link net.minecraft.client.gui.components.ImageButton} which allows changing some properties
@@ -31,7 +31,7 @@ public class DynamicImageButton extends Button
private final int yDiffTex; private final int yDiffTex;
private final int textureWidth; private final int textureWidth;
private final int textureHeight; private final int textureHeight;
private final Supplier<List<Component>> tooltip; private final NonNullSupplier<List<Component>> tooltip;
public DynamicImageButton( public DynamicImageButton(
Screen screen, int x, int y, int width, int height, int xTexStart, int yTexStart, int yDiffTex, Screen screen, int x, int y, int width, int height, int xTexStart, int yTexStart, int yDiffTex,
@@ -50,7 +50,7 @@ public class DynamicImageButton extends Button
public DynamicImageButton( public DynamicImageButton(
Screen screen, int x, int y, int width, int height, IntSupplier xTexStart, int yTexStart, int yDiffTex, Screen screen, int x, int y, int width, int height, IntSupplier xTexStart, int yTexStart, int yDiffTex,
ResourceLocation texture, int textureWidth, int textureHeight, ResourceLocation texture, int textureWidth, int textureHeight,
OnPress onPress, Supplier<List<Component>> tooltip OnPress onPress, NonNullSupplier<List<Component>> tooltip
) )
{ {
super( x, y, width, height, TextComponent.EMPTY, onPress ); super( x, y, width, height, TextComponent.EMPTY, onPress );
@@ -76,7 +76,7 @@ public class DynamicImageButton extends Button
blit( stack, x, y, xTexStart.getAsInt(), yTex, width, height, textureWidth, textureHeight ); blit( stack, x, y, xTexStart.getAsInt(), yTex, width, height, textureWidth, textureHeight );
RenderSystem.enableDepthTest(); RenderSystem.enableDepthTest();
if( isHoveredOrFocused() ) renderToolTip( stack, mouseX, mouseY ); if( isHovered ) renderToolTip( stack, mouseX, mouseY );
} }
@Nonnull @Nonnull
@@ -87,11 +87,10 @@ public class DynamicImageButton extends Button
return tooltip.isEmpty() ? TextComponent.EMPTY : tooltip.get( 0 ); return tooltip.isEmpty() ? TextComponent.EMPTY : tooltip.get( 0 );
} }
// @Override @Override
public void renderToolTip( @Nonnull PoseStack stack, int mouseX, int mouseY ) public void renderToolTip( @Nonnull PoseStack stack, int mouseX, int mouseY )
{ {
List<Component> tooltip = this.tooltip.get(); List<Component> tooltip = this.tooltip.get();
if( !tooltip.isEmpty() ) if( !tooltip.isEmpty() )
{ {
screen.renderComponentTooltip( stack, tooltip, mouseX, mouseY ); screen.renderComponentTooltip( stack, tooltip, mouseX, mouseY );

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.gui.widgets; package dan200.computercraft.client.gui.widgets;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
@@ -65,15 +64,104 @@ public class WidgetTerminal extends AbstractWidget
if( ch >= 32 && ch <= 126 || ch >= 160 && ch <= 255 ) // printable chars in byte range if( ch >= 32 && ch <= 126 || ch >= 160 && ch <= 255 ) // printable chars in byte range
{ {
// Queue the "char" event // Queue the "char" event
queueEvent( "char", Character.toString( ch ) ); computer.queueEvent( "char", new Object[] { Character.toString( ch ) } );
} }
return true; return true;
} }
private boolean inTermRegion( double mouseX, double mouseY ) @Override
public boolean keyPressed( int key, int scancode, int modifiers )
{ {
return active && visible && mouseX >= innerX && mouseY >= innerY && mouseX < innerX + innerWidth && mouseY < innerY + innerHeight; if( key == GLFW.GLFW_KEY_ESCAPE ) return false;
if( (modifiers & GLFW.GLFW_MOD_CONTROL) != 0 )
{
switch( key )
{
case GLFW.GLFW_KEY_T:
if( terminateTimer < 0 ) terminateTimer = 0;
return true;
case GLFW.GLFW_KEY_S:
if( shutdownTimer < 0 ) shutdownTimer = 0;
return true;
case GLFW.GLFW_KEY_R:
if( rebootTimer < 0 ) rebootTimer = 0;
return true;
case GLFW.GLFW_KEY_V:
// Ctrl+V for paste
String clipboard = Minecraft.getInstance().keyboardHandler.getClipboard();
if( clipboard != null )
{
// Clip to the first occurrence of \r or \n
int newLineIndex1 = clipboard.indexOf( "\r" );
int newLineIndex2 = clipboard.indexOf( "\n" );
if( newLineIndex1 >= 0 && newLineIndex2 >= 0 )
{
clipboard = clipboard.substring( 0, Math.min( newLineIndex1, newLineIndex2 ) );
}
else if( newLineIndex1 >= 0 )
{
clipboard = clipboard.substring( 0, newLineIndex1 );
}
else if( newLineIndex2 >= 0 )
{
clipboard = clipboard.substring( 0, newLineIndex2 );
}
// Filter the string
clipboard = SharedConstants.filterText( clipboard );
if( !clipboard.isEmpty() )
{
// Clip to 512 characters and queue the event
if( clipboard.length() > 512 ) clipboard = clipboard.substring( 0, 512 );
computer.queueEvent( "paste", new Object[] { clipboard } );
}
return true;
}
}
}
if( key >= 0 && terminateTimer < 0 && rebootTimer < 0 && shutdownTimer < 0 )
{
// Queue the "key" event and add to the down set
boolean repeat = keysDown.get( key );
keysDown.set( key );
computer.keyDown( key, repeat );
}
return true;
}
@Override
public boolean keyReleased( int key, int scancode, int modifiers )
{
// Queue the "key_up" event and remove from the down set
if( key >= 0 && keysDown.get( key ) )
{
keysDown.set( key, false );
computer.keyUp( key );
}
switch( key )
{
case GLFW.GLFW_KEY_T:
terminateTimer = -1;
break;
case GLFW.GLFW_KEY_R:
rebootTimer = -1;
break;
case GLFW.GLFW_KEY_S:
shutdownTimer = -1;
break;
case GLFW.GLFW_KEY_LEFT_CONTROL:
case GLFW.GLFW_KEY_RIGHT_CONTROL:
terminateTimer = rebootTimer = shutdownTimer = -1;
break;
}
return true;
} }
@Override @Override
@@ -175,113 +263,27 @@ public class WidgetTerminal extends AbstractWidget
return true; return true;
} }
@Override private boolean inTermRegion( double mouseX, double mouseY )
public boolean keyPressed( int key, int scancode, int modifiers )
{ {
if( key == GLFW.GLFW_KEY_ESCAPE ) return active && visible && mouseX >= innerX && mouseY >= innerY && mouseX < innerX + innerWidth && mouseY < innerY + innerHeight;
{
return false;
}
if( (modifiers & GLFW.GLFW_MOD_CONTROL) != 0 )
{
switch( key )
{
case GLFW.GLFW_KEY_T:
if( terminateTimer < 0 )
{
terminateTimer = 0;
}
return true;
case GLFW.GLFW_KEY_S:
if( shutdownTimer < 0 )
{
shutdownTimer = 0;
}
return true;
case GLFW.GLFW_KEY_R:
if( rebootTimer < 0 )
{
rebootTimer = 0;
}
return true;
case GLFW.GLFW_KEY_V:
// Ctrl+V for paste
String clipboard = Minecraft.getInstance().keyboardHandler.getClipboard();
if( clipboard != null )
{
// Clip to the first occurrence of \r or \n
int newLineIndex1 = clipboard.indexOf( "\r" );
int newLineIndex2 = clipboard.indexOf( "\n" );
if( newLineIndex1 >= 0 && newLineIndex2 >= 0 )
{
clipboard = clipboard.substring( 0, Math.min( newLineIndex1, newLineIndex2 ) );
}
else if( newLineIndex1 >= 0 )
{
clipboard = clipboard.substring( 0, newLineIndex1 );
}
else if( newLineIndex2 >= 0 )
{
clipboard = clipboard.substring( 0, newLineIndex2 );
}
// Filter the string
clipboard = SharedConstants.filterText( clipboard );
if( !clipboard.isEmpty() )
{
// Clip to 512 characters and queue the event
if( clipboard.length() > 512 )
{
clipboard = clipboard.substring( 0, 512 );
}
queueEvent( "paste", clipboard );
}
return true;
}
}
}
if( key >= 0 && terminateTimer < 0 && rebootTimer < 0 && shutdownTimer < 0 )
{
// Queue the "key" event and add to the down set
boolean repeat = keysDown.get( key );
keysDown.set( key );
computer.keyDown( key, repeat );
}
return true;
} }
@Override public void update()
public boolean keyReleased( int key, int scancode, int modifiers )
{ {
// Queue the "key_up" event and remove from the down set if( terminateTimer >= 0 && terminateTimer < TERMINATE_TIME && (terminateTimer += 0.05f) > TERMINATE_TIME )
if( key >= 0 && keysDown.get( key ) )
{ {
keysDown.set( key, false ); computer.queueEvent( "terminate" );
computer.keyUp( key );
} }
switch( key ) if( shutdownTimer >= 0 && shutdownTimer < TERMINATE_TIME && (shutdownTimer += 0.05f) > TERMINATE_TIME )
{ {
case GLFW.GLFW_KEY_T: computer.shutdown();
terminateTimer = -1;
break;
case GLFW.GLFW_KEY_R:
rebootTimer = -1;
break;
case GLFW.GLFW_KEY_S:
shutdownTimer = -1;
break;
case GLFW.GLFW_KEY_LEFT_CONTROL:
case GLFW.GLFW_KEY_RIGHT_CONTROL:
terminateTimer = rebootTimer = shutdownTimer = -1;
break;
} }
return true; if( rebootTimer >= 0 && rebootTimer < TERMINATE_TIME && (rebootTimer += 0.05f) > TERMINATE_TIME )
{
computer.reboot();
}
} }
@Override @Override
@@ -307,44 +309,6 @@ public class WidgetTerminal extends AbstractWidget
} }
} }
@Override
public boolean isMouseOver( double x, double y )
{
return true;
}
private void queueEvent( String event, Object... args )
{
computer.queueEvent( event, args );
}
public void update()
{
if( terminateTimer >= 0 && terminateTimer < TERMINATE_TIME && (terminateTimer += 0.05f) > TERMINATE_TIME )
{
queueEvent( "terminate" );
}
if( shutdownTimer >= 0 && shutdownTimer < TERMINATE_TIME && (shutdownTimer += 0.05f) > TERMINATE_TIME )
{
computer.shutdown();
}
if( rebootTimer >= 0 && rebootTimer < TERMINATE_TIME && (rebootTimer += 0.05f) > TERMINATE_TIME )
{
computer.reboot();
}
}
private void queueEvent( String event )
{
ClientComputer computer = this.computer;
if( computer != null )
{
computer.queueEvent( event );
}
}
@Override @Override
public void render( @Nonnull PoseStack transform, int mouseX, int mouseY, float partialTicks ) public void render( @Nonnull PoseStack transform, int mouseX, int mouseY, float partialTicks )
{ {
@@ -362,9 +326,9 @@ public class WidgetTerminal extends AbstractWidget
} }
@Override @Override
public void updateNarration( NarrationElementOutput builder ) public void updateNarration( @Nonnull NarrationElementOutput output )
{ {
// I'm not sure what the right option is here.
} }
public static int getWidth( int termWidth ) public static int getWidth( int termWidth )

View File

@@ -15,7 +15,7 @@ import dan200.computercraft.client.render.TileEntityTurtleRenderer;
import dan200.computercraft.client.render.TurtleModelLoader; import dan200.computercraft.client.render.TurtleModelLoader;
import dan200.computercraft.client.render.TurtlePlayerRenderer; import dan200.computercraft.client.render.TurtlePlayerRenderer;
import dan200.computercraft.fabric.events.ClientUnloadWorldEvent; import dan200.computercraft.fabric.events.ClientUnloadWorldEvent;
import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.Registry;
import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.common.IColouredItem;
import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.common.TileGeneric;
@@ -73,17 +73,17 @@ public final class ComputerCraftProxyClient implements ClientModInitializer
registerContainers(); registerContainers();
// While turtles themselves are not transparent, their upgrades may be. // While turtles themselves are not transparent, their upgrades may be.
BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.TURTLE_NORMAL, RenderType.translucent() ); BlockRenderLayerMap.INSTANCE.putBlock( Registry.ModBlocks.TURTLE_NORMAL, RenderType.translucent() );
BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.TURTLE_ADVANCED, RenderType.translucent() ); BlockRenderLayerMap.INSTANCE.putBlock( Registry.ModBlocks.TURTLE_ADVANCED, RenderType.translucent() );
// Monitors' textures have transparent fronts and so count as cutouts. // Monitors' textures have transparent fronts and so count as cutouts.
BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.MONITOR_NORMAL, RenderType.cutout() ); BlockRenderLayerMap.INSTANCE.putBlock( Registry.ModBlocks.MONITOR_NORMAL, RenderType.cutout() );
BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.MONITOR_ADVANCED, RenderType.cutout() ); BlockRenderLayerMap.INSTANCE.putBlock( Registry.ModBlocks.MONITOR_ADVANCED, RenderType.cutout() );
// Setup TESRs // Setup TESRs
BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.MONITOR_NORMAL, TileEntityMonitorRenderer::new ); BlockEntityRendererRegistry.register( Registry.ModBlockEntities.MONITOR_NORMAL, TileEntityMonitorRenderer::new );
BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.MONITOR_ADVANCED, TileEntityMonitorRenderer::new ); BlockEntityRendererRegistry.register( Registry.ModBlockEntities.MONITOR_ADVANCED, TileEntityMonitorRenderer::new );
BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.TURTLE_NORMAL, TileEntityTurtleRenderer::new ); BlockEntityRendererRegistry.register( Registry.ModBlockEntities.TURTLE_NORMAL, TileEntityTurtleRenderer::new );
BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.TURTLE_ADVANCED, TileEntityTurtleRenderer::new ); BlockEntityRendererRegistry.register( Registry.ModBlockEntities.TURTLE_ADVANCED, TileEntityTurtleRenderer::new );
ClientSpriteRegistryCallback.event( InventoryMenu.BLOCK_ATLAS ) ClientSpriteRegistryCallback.event( InventoryMenu.BLOCK_ATLAS )
.register( ClientRegistry::onTextureStitchEvent ); .register( ClientRegistry::onTextureStitchEvent );
@@ -92,17 +92,17 @@ public final class ComputerCraftProxyClient implements ClientModInitializer
TurtleModelLoader.INSTANCE.loadModel( TurtleModelLoader.INSTANCE.loadModel(
name ) : null ); name ) : null );
EntityRendererRegistry.register( ComputerCraftRegistry.ModEntities.TURTLE_PLAYER, TurtlePlayerRenderer::new ); EntityRendererRegistry.register( Registry.ModEntities.TURTLE_PLAYER, TurtlePlayerRenderer::new );
registerItemProperty( "state", registerItemProperty( "state",
( stack, world, player, integer ) -> ItemPocketComputer.getState( stack ) ( stack, world, player, integer ) -> ItemPocketComputer.getState( stack )
.ordinal(), .ordinal(),
() -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_NORMAL, () -> Registry.ModItems.POCKET_COMPUTER_NORMAL,
() -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_ADVANCED ); () -> Registry.ModItems.POCKET_COMPUTER_ADVANCED );
registerItemProperty( "state", registerItemProperty( "state",
( stack, world, player, integer ) -> IColouredItem.getColourBasic( stack ) != -1 ? 1 : 0, ( stack, world, player, integer ) -> IColouredItem.getColourBasic( stack ) != -1 ? 1 : 0,
() -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_NORMAL, () -> Registry.ModItems.POCKET_COMPUTER_NORMAL,
() -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_ADVANCED ); () -> Registry.ModItems.POCKET_COMPUTER_ADVANCED );
ClientRegistry.onItemColours(); ClientRegistry.onItemColours();
initEvents(); initEvents();
@@ -111,18 +111,18 @@ public final class ComputerCraftProxyClient implements ClientModInitializer
// My IDE doesn't think so, but we do actually need these generics. // My IDE doesn't think so, but we do actually need these generics.
private static void registerContainers() private static void registerContainers()
{ {
ScreenRegistry.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register( ComputerCraftRegistry.ModContainers.COMPUTER, GuiComputer::create ); ScreenRegistry.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register( Registry.ModContainers.COMPUTER, GuiComputer::create );
ScreenRegistry.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER, ScreenRegistry.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register( Registry.ModContainers.POCKET_COMPUTER,
GuiComputer::createPocket ); GuiComputer::createPocket );
ScreenRegistry.<ContainerComputerBase, NoTermComputerScreen<ContainerComputerBase>>register( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER_NO_TERM, ScreenRegistry.<ContainerComputerBase, NoTermComputerScreen<ContainerComputerBase>>register( Registry.ModContainers.POCKET_COMPUTER_NO_TERM,
NoTermComputerScreen::new ); NoTermComputerScreen::new );
ScreenRegistry.<ContainerTurtle, GuiTurtle>register( ComputerCraftRegistry.ModContainers.TURTLE, GuiTurtle::new ); ScreenRegistry.<ContainerTurtle, GuiTurtle>register( Registry.ModContainers.TURTLE, GuiTurtle::new );
ScreenRegistry.<ContainerPrinter, GuiPrinter>register( ComputerCraftRegistry.ModContainers.PRINTER, GuiPrinter::new ); ScreenRegistry.<ContainerPrinter, GuiPrinter>register( Registry.ModContainers.PRINTER, GuiPrinter::new );
ScreenRegistry.<ContainerDiskDrive, GuiDiskDrive>register( ComputerCraftRegistry.ModContainers.DISK_DRIVE, GuiDiskDrive::new ); ScreenRegistry.<ContainerDiskDrive, GuiDiskDrive>register( Registry.ModContainers.DISK_DRIVE, GuiDiskDrive::new );
ScreenRegistry.<ContainerHeldItem, GuiPrintout>register( ComputerCraftRegistry.ModContainers.PRINTOUT, GuiPrintout::new ); ScreenRegistry.<ContainerHeldItem, GuiPrintout>register( Registry.ModContainers.PRINTOUT, GuiPrintout::new );
ScreenRegistry.<ContainerViewComputer, GuiComputer<ContainerViewComputer>>register( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, ScreenRegistry.<ContainerViewComputer, GuiComputer<ContainerViewComputer>>register( Registry.ModContainers.VIEW_COMPUTER,
GuiComputer::createView ); GuiComputer::createView );
} }

View File

@@ -3,14 +3,13 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix3f; import com.mojang.math.Matrix3f;
import com.mojang.math.Matrix4f; import com.mojang.math.Matrix4f;
import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.Registry;
import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable;
import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; import dan200.computercraft.shared.peripheral.modem.wired.CableShapes;
import dan200.computercraft.shared.util.WorldUtil; import dan200.computercraft.shared.util.WorldUtil;
@@ -33,35 +32,34 @@ public final class CableHighlightRenderer
{ {
} }
public static boolean drawHighlight( PoseStack stack, VertexConsumer consumer, Entity entity, double d, double e, double f, BlockPos pos, /*
BlockState state ) * Draw an outline for a specific part of a cable "Multipart".
*
* @see net.minecraft.client.renderer.LevelRenderer#renderHitOutline
*/
public static boolean drawHighlight( PoseStack stack, VertexConsumer buffer, Entity entity, double d, double e, double f, BlockPos pos, BlockState state )
{ {
HitResult hitResult = Minecraft.getInstance().hitResult;
Camera info = Minecraft.getInstance().gameRenderer.getMainCamera(); Camera info = Minecraft.getInstance().gameRenderer.getMainCamera();
// We only care about instances with both cable and modem. // We only care about instances with both cable and modem.
if( state.getBlock() != ComputerCraftRegistry.ModBlocks.CABLE || state.getValue( BlockCable.MODEM ) if( state.getBlock() != Registry.ModBlocks.CABLE || state.getValue( BlockCable.MODEM ).getFacing() == null || !state.getValue( BlockCable.CABLE ) )
.getFacing() == null || !state.getValue( BlockCable.CABLE ) )
{ {
return false; return false;
} }
HitResult hitResult = Minecraft.getInstance().hitResult;
Vec3 hitPos = hitResult != null ? hitResult.getLocation() : new Vec3( d, e, f ); Vec3 hitPos = hitResult != null ? hitResult.getLocation() : new Vec3( d, e, f );
VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hitPos.subtract( pos.getX(), pos.getY(), pos.getZ() ) )
hitPos.subtract( pos.getX(), ? CableShapes.getModemShape( state )
pos.getY(), : CableShapes.getCableShape( state );
pos.getZ() ) ) ? CableShapes.getModemShape( state ) : CableShapes.getCableShape(
state );
Vec3 cameraPos = info.getPosition(); Vec3 cameraPos = info.getPosition();
double xOffset = pos.getX() - cameraPos.x(); double xOffset = pos.getX() - cameraPos.x();
double yOffset = pos.getY() - cameraPos.y(); double yOffset = pos.getY() - cameraPos.y();
double zOffset = pos.getZ() - cameraPos.z(); double zOffset = pos.getZ() - cameraPos.z();
Matrix4f matrix4f = stack.last()
.pose(); Matrix4f matrix4f = stack.last().pose();
Matrix3f normal = stack.last().normal(); Matrix3f normal = stack.last().normal();
shape.forAllEdges( ( x1, y1, z1, x2, y2, z2 ) -> { shape.forAllEdges( ( x1, y1, z1, x2, y2, z2 ) -> {
float xDelta = (float) (x2 - x1); float xDelta = (float) (x2 - x1);
@@ -72,11 +70,13 @@ public final class CableHighlightRenderer
yDelta = yDelta / len; yDelta = yDelta / len;
zDelta = zDelta / len; zDelta = zDelta / len;
consumer.vertex( matrix4f, (float) (x1 + xOffset), (float) (y1 + yOffset), (float) (z1 + zOffset) ) buffer
.vertex( matrix4f, (float) (x1 + xOffset), (float) (y1 + yOffset), (float) (z1 + zOffset) )
.color( 0, 0, 0, 0.4f ) .color( 0, 0, 0, 0.4f )
.normal( normal, xDelta, yDelta, zDelta ) .normal( normal, xDelta, yDelta, zDelta )
.endVertex(); .endVertex();
consumer.vertex( matrix4f, (float) (x2 + xOffset), (float) (y2 + yOffset), (float) (z2 + zOffset) ) buffer
.vertex( matrix4f, (float) (x2 + xOffset), (float) (y2 + yOffset), (float) (z2 + zOffset) )
.color( 0, 0, 0, 0.4f ) .color( 0, 0, 0, 0.4f )
.normal( normal, xDelta, yDelta, zDelta ) .normal( normal, xDelta, yDelta, zDelta )
.endVertex(); .endVertex();

View File

@@ -22,15 +22,24 @@ public class ComputerBorderRenderer
public static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" ); public static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" );
public static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_command.png" ); public static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_command.png" );
public static final ResourceLocation BACKGROUND_COLOUR = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_colour.png" ); public static final ResourceLocation BACKGROUND_COLOUR = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_colour.png" );
private static final Matrix4f IDENTITY = new Matrix4f();
static
{
IDENTITY.setIdentity();
}
/** /**
* The margin between the terminal and its border. * The margin between the terminal and its border.
*/ */
public static final int MARGIN = 2; public static final int MARGIN = 2;
/** /**
* The width of the terminal border. * The width of the terminal border.
*/ */
public static final int BORDER = 12; public static final int BORDER = 12;
private static final Matrix4f IDENTITY = new Matrix4f();
private static final int CORNER_TOP_Y = 28; private static final int CORNER_TOP_Y = 28;
private static final int CORNER_BOTTOM_Y = CORNER_TOP_Y + BORDER; private static final int CORNER_BOTTOM_Y = CORNER_TOP_Y + BORDER;
private static final int CORNER_LEFT_X = BORDER; private static final int CORNER_LEFT_X = BORDER;
@@ -40,21 +49,16 @@ public class ComputerBorderRenderer
private static final int LIGHT_CORNER_Y = 80; private static final int LIGHT_CORNER_Y = 80;
public static final int LIGHT_HEIGHT = 8; public static final int LIGHT_HEIGHT = 8;
public static final int TEX_SIZE = 256; public static final int TEX_SIZE = 256;
private static final float TEX_SCALE = 1 / (float) TEX_SIZE; private static final float TEX_SCALE = 1 / (float) TEX_SIZE;
static
{
IDENTITY.setIdentity();
}
private final Matrix4f transform; private final Matrix4f transform;
private final VertexConsumer builder; private final VertexConsumer builder;
private final int light;
private final int z; private final int z;
private final float r, g, b; private final float r, g, b;
private final int light;
public ComputerBorderRenderer( Matrix4f transform, VertexConsumer builder, int z, int light, float r, float g, float b ) public ComputerBorderRenderer( Matrix4f transform, VertexConsumer builder, int z, int light, float r, float g, float b )
{ {
this.transform = transform; this.transform = transform;
@@ -82,14 +86,19 @@ public class ComputerBorderRenderer
} }
} }
public static RenderType getRenderType( ResourceLocation location )
{
// See note in RenderTypes about why we use text rather than anything intuitive.
return RenderType.text( location );
}
public static void render( ResourceLocation location, int x, int y, int z, int light, int width, int height ) public static void render( ResourceLocation location, int x, int y, int z, int light, int width, int height )
{ {
MultiBufferSource.BufferSource source = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() ); MultiBufferSource.BufferSource source = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() );
render( IDENTITY, source.getBuffer( RenderType.text( location ) ), x, y, z, light, width, height, false, 1, 1, 1 ); render( IDENTITY, source.getBuffer( getRenderType( location ) ), x, y, z, light, width, height, false, 1, 1, 1 );
source.endBatch(); source.endBatch();
} }
public static void render( Matrix4f transform, VertexConsumer buffer, int x, int y, int z, int light, int width, int height, boolean withLight, float r, float g, float b ) public static void render( Matrix4f transform, VertexConsumer buffer, int x, int y, int z, int light, int width, int height, boolean withLight, float r, float g, float b )
{ {
new ComputerBorderRenderer( transform, buffer, z, light, r, g, b ).doRender( x, y, width, height, withLight ); new ComputerBorderRenderer( transform, buffer, z, light, r, g, b ).doRender( x, y, width, height, withLight );
@@ -125,16 +134,16 @@ public class ComputerBorderRenderer
} }
} }
private void renderLine( int x, int y, int u, int v, int width, int height )
{
renderTexture( x, y, u, v, width, height, BORDER, BORDER );
}
private void renderCorner( int x, int y, int u, int v ) private void renderCorner( int x, int y, int u, int v )
{ {
renderTexture( x, y, u, v, BORDER, BORDER, BORDER, BORDER ); renderTexture( x, y, u, v, BORDER, BORDER, BORDER, BORDER );
} }
private void renderLine( int x, int y, int u, int v, int width, int height )
{
renderTexture( x, y, u, v, width, height, BORDER, BORDER );
}
private void renderTexture( int x, int y, int u, int v, int width, int height ) private void renderTexture( int x, int y, int u, int v, int width, int height )
{ {
renderTexture( x, y, u, v, width, height, width, height ); renderTexture( x, y, u, v, width, height, width, height );
@@ -142,25 +151,9 @@ public class ComputerBorderRenderer
private void renderTexture( int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight ) private void renderTexture( int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight )
{ {
builder.vertex( transform, x, y + height, z ) builder.vertex( transform, x, y + height, z ).color( r, g, b, 1.0f ).uv( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE ).uv2( light ).endVertex();
.color( r, g, b, 1.0f ) builder.vertex( transform, x + width, y + height, z ).color( r, g, b, 1.0f ).uv( (u + textureWidth) * TEX_SCALE, (v + textureHeight) * TEX_SCALE ).uv2( light ).endVertex();
.uv( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE ) builder.vertex( transform, x + width, y, z ).color( r, g, b, 1.0f ).uv( (u + textureWidth) * TEX_SCALE, v * TEX_SCALE ).uv2( light ).endVertex();
.uv2( light ) builder.vertex( transform, x, y, z ).color( r, g, b, 1.0f ).uv( u * TEX_SCALE, v * TEX_SCALE ).uv2( light ).endVertex();
.endVertex();
builder.vertex( transform, x + width, y + height, z )
.color( r, g, b, 1.0f )
.uv( (u + textureWidth) * TEX_SCALE, (v + textureHeight) * TEX_SCALE )
.uv2( light )
.endVertex();
builder.vertex( transform, x + width, y, z )
.color( r, g, b, 1.0f )
.uv( (u + textureWidth) * TEX_SCALE, v * TEX_SCALE )
.uv2( light )
.endVertex();
builder.vertex( transform, x, y, z )
.color( r, g, b, 1.0f )
.uv( u * TEX_SCALE, v * TEX_SCALE )
.uv2( light )
.endVertex();
} }
} }

View File

@@ -3,30 +3,36 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Vector3f; import com.mojang.math.Vector3f;
import dan200.computercraft.fabric.mixin.ItemInHandRendererAccess; import dan200.computercraft.fabric.mixin.ItemInHandRendererAccess;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ItemInHandRenderer; import net.minecraft.client.renderer.ItemInHandRenderer;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@Environment( EnvType.CLIENT )
public abstract class ItemMapLikeRenderer public abstract class ItemMapLikeRenderer
{ {
public void renderItemFirstPerson( /**
PoseStack transform, MultiBufferSource render, int lightTexture, InteractionHand hand, float pitch, float equipProgress, * The main rendering method for the item.
float swingProgress, ItemStack stack *
) * @param transform The matrix transformation stack
* @param render The buffer to render to
* @param stack The stack to render
* @param light The packed lightmap coordinates.
* @see ItemInHandRenderer#renderItem(LivingEntity, ItemStack, ItemTransforms.TransformType, boolean, PoseStack, MultiBufferSource, int)
*/
protected abstract void renderItem( PoseStack transform, MultiBufferSource render, ItemStack stack, int light );
public void renderItemFirstPerson( PoseStack transform, MultiBufferSource render, int lightTexture, InteractionHand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack )
{ {
Player player = Minecraft.getInstance().player; Player player = Minecraft.getInstance().player;
@@ -37,17 +43,60 @@ public abstract class ItemMapLikeRenderer
} }
else else
{ {
renderItemFirstPersonSide( transform, renderItemFirstPersonSide(
render, transform, render, lightTexture,
lightTexture,
hand == InteractionHand.MAIN_HAND ? player.getMainArm() : player.getMainArm().getOpposite(), hand == InteractionHand.MAIN_HAND ? player.getMainArm() : player.getMainArm().getOpposite(),
equipProgress, equipProgress, swingProgress, stack
swingProgress, );
stack );
} }
transform.popPose(); transform.popPose();
} }
/**
* Renders the item to one side of the player.
*
* @param transform The matrix transformation stack
* @param render The buffer to render to
* @param combinedLight The current light level
* @param side The side to render on
* @param equipProgress The equip progress of this item
* @param swingProgress The swing progress of this item
* @param stack The stack to render
* @see ItemInHandRenderer#renderOneHandedMap(PoseStack, MultiBufferSource, int, float, HumanoidArm, float, ItemStack)
*/
private void renderItemFirstPersonSide( PoseStack transform, MultiBufferSource render, int combinedLight, HumanoidArm side, float equipProgress, float swingProgress, ItemStack stack )
{
Minecraft minecraft = Minecraft.getInstance();
float offset = side == HumanoidArm.RIGHT ? 1f : -1f;
transform.translate( offset * 0.125f, -0.125f, 0f );
// If the player is not invisible then render a single arm
if( !minecraft.player.isInvisible() )
{
transform.pushPose();
transform.mulPose( Vector3f.ZP.rotationDegrees( offset * 10f ) );
((ItemInHandRendererAccess) minecraft.getItemInHandRenderer()).callRenderPlayerArm( transform, render, combinedLight, equipProgress, swingProgress, side );
transform.popPose();
}
// Setup the appropriate transformations. This is just copied from the
// corresponding method in ItemRenderer.
transform.pushPose();
transform.translate( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f );
float f1 = Mth.sqrt( swingProgress );
float f2 = Mth.sin( f1 * (float) Math.PI );
float f3 = -0.5f * f2;
float f4 = 0.4f * Mth.sin( f1 * ((float) Math.PI * 2f) );
float f5 = -0.3f * Mth.sin( swingProgress * (float) Math.PI );
transform.translate( offset * f3, f4 - 0.3f * f2, f5 );
transform.mulPose( Vector3f.XP.rotationDegrees( f2 * -45f ) );
transform.mulPose( Vector3f.YP.rotationDegrees( offset * f2 * -30f ) );
renderItem( transform, render, stack, combinedLight );
transform.popPose();
}
/** /**
* Render an item in the middle of the screen. * Render an item in the middle of the screen.
* *
@@ -58,9 +107,9 @@ public abstract class ItemMapLikeRenderer
* @param equipProgress The equip progress of this item * @param equipProgress The equip progress of this item
* @param swingProgress The swing progress of this item * @param swingProgress The swing progress of this item
* @param stack The stack to render * @param stack The stack to render
* @see ItemInHandRenderer#renderTwoHandedMap(PoseStack, MultiBufferSource, int, float, float, float)
*/ */
private void renderItemFirstPersonCenter( PoseStack transform, MultiBufferSource render, int combinedLight, float pitch, float equipProgress, private void renderItemFirstPersonCenter( PoseStack transform, MultiBufferSource render, int combinedLight, float pitch, float equipProgress, float swingProgress, ItemStack stack )
float swingProgress, ItemStack stack )
{ {
Minecraft minecraft = Minecraft.getInstance(); Minecraft minecraft = Minecraft.getInstance();
ItemInHandRenderer renderer = minecraft.getItemInHandRenderer(); ItemInHandRenderer renderer = minecraft.getItemInHandRenderer();
@@ -91,60 +140,4 @@ public abstract class ItemMapLikeRenderer
renderItem( transform, render, stack, combinedLight ); renderItem( transform, render, stack, combinedLight );
} }
/**
* Renders the item to one side of the player.
*
* @param transform The matrix transformation stack
* @param render The buffer to render to
* @param combinedLight The current light level
* @param side The side to render on
* @param equipProgress The equip progress of this item
* @param swingProgress The swing progress of this item
* @param stack The stack to render
*/
private void renderItemFirstPersonSide( PoseStack transform, MultiBufferSource render, int combinedLight, HumanoidArm side, float equipProgress,
float swingProgress, ItemStack stack )
{
Minecraft minecraft = Minecraft.getInstance();
float offset = side == HumanoidArm.RIGHT ? 1f : -1f;
transform.translate( offset * 0.125f, -0.125f, 0f );
// If the player is not invisible then render a single arm
if( !minecraft.player.isInvisible() )
{
transform.pushPose();
transform.mulPose( Vector3f.ZP.rotationDegrees( offset * 10f ) );
((ItemInHandRendererAccess) minecraft.getItemInHandRenderer())
.callRenderPlayerArm( transform, render, combinedLight, equipProgress, swingProgress, side );
transform.popPose();
}
// Setup the appropriate transformations. This is just copied from the
// corresponding method in ItemRenderer.
transform.pushPose();
transform.translate( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f );
float f1 = Mth.sqrt( swingProgress );
float f2 = Mth.sin( f1 * (float) Math.PI );
float f3 = -0.5f * f2;
float f4 = 0.4f * Mth.sin( f1 * ((float) Math.PI * 2f) );
float f5 = -0.3f * Mth.sin( swingProgress * (float) Math.PI );
transform.translate( offset * f3, f4 - 0.3f * f2, f5 );
transform.mulPose( Vector3f.XP.rotationDegrees( f2 * -45f ) );
transform.mulPose( Vector3f.YP.rotationDegrees( offset * f2 * -30f ) );
renderItem( transform, render, stack, combinedLight );
transform.popPose();
}
/**
* The main rendering method for the item.
*
* @param transform The matrix transformation stack
* @param render The buffer to render to
* @param stack The stack to render
* @param light TODO rebase
*/
protected abstract void renderItem( PoseStack transform, MultiBufferSource render, ItemStack stack, int light );
} }

View File

@@ -3,10 +3,8 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*; import com.mojang.blaze3d.vertex.*;
import com.mojang.math.Matrix4f; import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f; import com.mojang.math.Vector3f;
@@ -17,9 +15,7 @@ import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@@ -39,7 +35,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
} }
@Override @Override
protected void renderItem( PoseStack transform, MultiBufferSource render, ItemStack stack, int light ) protected void renderItem( PoseStack transform, MultiBufferSource renderer, ItemStack stack, int light )
{ {
ClientComputer computer = ItemPocketComputer.createClientComputer( stack ); ClientComputer computer = ItemPocketComputer.createClientComputer( stack );
Terminal terminal = computer == null ? null : computer.getTerminal(); Terminal terminal = computer == null ? null : computer.getTerminal();
@@ -67,7 +63,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
transform.scale( 0.5f, 0.5f, 0.5f ); transform.scale( 0.5f, 0.5f, 0.5f );
float scale = 0.75f / Math.max( width + BORDER * 2, height + BORDER * 2 + LIGHT_HEIGHT ); float scale = 0.75f / Math.max( width + BORDER * 2, height + BORDER * 2 + LIGHT_HEIGHT );
transform.scale( scale, scale, 0 ); transform.scale( scale, scale, -1.0f );
transform.translate( -0.5 * width, -0.5 * height, 0 ); transform.translate( -0.5 * width, -0.5 * height, 0 );
// Render the main frame // Render the main frame
@@ -75,26 +71,21 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
ComputerFamily family = item.getFamily(); ComputerFamily family = item.getFamily();
int frameColour = item.getColour( stack ); int frameColour = item.getColour( stack );
Matrix4f matrix = transform.last() Matrix4f matrix = transform.last().pose();
.pose(); renderFrame( matrix, renderer, family, frameColour, light, width, height );
renderFrame( matrix, render, family, frameColour, light, width, height );
// Render the light // Render the light
int lightColour = ItemPocketComputer.getLightState( stack ); int lightColour = ItemPocketComputer.getLightState( stack );
if( lightColour == -1 ) if( lightColour == -1 ) lightColour = Colour.BLACK.getHex();
{ renderLight( matrix, renderer, lightColour, width, height );
lightColour = Colour.BLACK.getHex();
}
renderLight( matrix, lightColour, width, height );
if( computer != null && terminal != null ) if( computer != null && terminal != null )
{ {
FixedWidthFontRenderer.drawTerminal( FixedWidthFontRenderer.drawTerminal(
matrix, render.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ), matrix, renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ),
MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN
); );
FixedWidthFontRenderer.drawBlocker( transform.last().pose(), render, 0, 0, width, height ); FixedWidthFontRenderer.drawBlocker( transform.last().pose(), renderer, 0, 0, width, height );
} }
else else
{ {
@@ -106,45 +97,26 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
private static void renderFrame( Matrix4f transform, MultiBufferSource render, ComputerFamily family, int colour, int light, int width, int height ) private static void renderFrame( Matrix4f transform, MultiBufferSource render, ComputerFamily family, int colour, int light, int width, int height )
{ {
RenderSystem.enableBlend();
Minecraft.getInstance()
.getTextureManager()
.bindForSetup( colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ) );
ResourceLocation texture = colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ); ResourceLocation texture = colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family );
float r = ((colour >>> 16) & 0xFF) / 255.0f; float r = ((colour >>> 16) & 0xFF) / 255.0f;
float g = ((colour >>> 8) & 0xFF) / 255.0f; float g = ((colour >>> 8) & 0xFF) / 255.0f;
float b = (colour & 0xFF) / 255.0f; float b = (colour & 0xFF) / 255.0f;
ComputerBorderRenderer.render( transform, render.getBuffer( RenderType.text( texture ) ), 0, 0, 0, light, width, height, true, r, g, b ); ComputerBorderRenderer.render( transform, render.getBuffer( ComputerBorderRenderer.getRenderType( texture ) ), 0, 0, 0, light, width, height, true, r, g, b );
} }
private static void renderLight( Matrix4f transform, int colour, int width, int height ) private static void renderLight( Matrix4f transform, MultiBufferSource render, int colour, int width, int height )
{ {
RenderSystem.disableTexture();
float r = ((colour >>> 16) & 0xFF) / 255.0f; float r = ((colour >>> 16) & 0xFF) / 255.0f;
float g = ((colour >>> 8) & 0xFF) / 255.0f; float g = ((colour >>> 8) & 0xFF) / 255.0f;
float b = (colour & 0xFF) / 255.0f; float b = (colour & 0xFF) / 255.0f;
float z = 0.001f;
Tesselator tessellator = Tesselator.getInstance(); VertexConsumer buffer = render.getBuffer( RenderTypes.POSITION_COLOR );
BufferBuilder buffer = tessellator.getBuilder(); buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).endVertex();
buffer.begin( VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR ); buffer.vertex( transform, width, height + LIGHT_HEIGHT + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).endVertex();
buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + BORDER / 2.0f, 0 ) buffer.vertex( transform, width, height + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).endVertex();
.color( r, g, b, 1.0f ) buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).endVertex();
.endVertex();
buffer.vertex( transform, width, height + LIGHT_HEIGHT + BORDER / 2.0f, 0 )
.color( r, g, b, 1.0f )
.endVertex();
buffer.vertex( transform, width, height + BORDER / 2.0f, 0 )
.color( r, g, b, 1.0f )
.endVertex();
buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0 )
.color( r, g, b, 1.0f )
.endVertex();
tessellator.end();
RenderSystem.enableTexture();
} }
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
@@ -30,6 +29,21 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
{ {
} }
public boolean renderInFrame( PoseStack matrixStack, MultiBufferSource consumerProvider, ItemStack stack, int light )
{
if( !(stack.getItem() instanceof ItemPrintout) ) return false;
// Move a little bit forward to ensure we're not clipping with the frame
matrixStack.translate( 0.0f, 0.0f, -0.001f );
matrixStack.mulPose( Vector3f.ZP.rotationDegrees( 180f ) );
matrixStack.scale( 0.95f, 0.95f, -0.95f );
matrixStack.translate( -0.5f, -0.5f, 0.0f );
drawPrintout( matrixStack, consumerProvider, stack, light );
return true;
}
@Override @Override
protected void renderItem( PoseStack transform, MultiBufferSource render, ItemStack stack, int light ) protected void renderItem( PoseStack transform, MultiBufferSource render, ItemStack stack, int light )
{ {
@@ -49,10 +63,7 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
double height = LINES_PER_PAGE * FONT_HEIGHT + Y_TEXT_MARGIN * 2; double height = LINES_PER_PAGE * FONT_HEIGHT + Y_TEXT_MARGIN * 2;
// Non-books will be left aligned // Non-books will be left aligned
if( !book ) if( !book ) width += offsetAt( pages );
{
width += offsetAt( pages );
}
double visualWidth = width, visualHeight = height; double visualWidth = width, visualHeight = height;
@@ -70,27 +81,11 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
transform.scale( scale, scale, scale ); transform.scale( scale, scale, scale );
transform.translate( (max - width) / 2.0, (max - height) / 2.0, 0.0 ); transform.translate( (max - width) / 2.0, (max - height) / 2.0, 0.0 );
Matrix4f matrix = transform.last() Matrix4f matrix = transform.last().pose();
.pose();
drawBorder( matrix, render, 0, 0, -0.01f, 0, pages, book, light ); drawBorder( matrix, render, 0, 0, -0.01f, 0, pages, book, light );
drawText( matrix, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, light, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) ); drawText(
} matrix, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, light,
ItemPrintout.getText( stack ), ItemPrintout.getColours( stack )
public boolean renderInFrame( PoseStack matrixStack, MultiBufferSource consumerProvider, ItemStack stack, int light ) );
{
if( !(stack.getItem() instanceof ItemPrintout) )
{
return false;
}
// Move a little bit forward to ensure we're not clipping with the frame
matrixStack.translate( 0.0f, 0.0f, -0.001f );
matrixStack.mulPose( Vector3f.ZP.rotationDegrees( 180f ) );
matrixStack.scale( 0.95f, 0.95f, -0.95f );
matrixStack.translate( -0.5f, -0.5f, 0.0f );
drawPrintout( matrixStack, consumerProvider, stack, light );
return true;
} }
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
@@ -27,8 +26,8 @@ import java.util.EnumSet;
import static net.minecraft.core.Direction.*; import static net.minecraft.core.Direction.*;
/** /**
* Overrides monitor highlighting to only render the outline of the <em>whole</em> monitor, rather than the current block. This means you do not get an * Overrides monitor highlighting to only render the outline of the <em>whole</em> monitor, rather than the current
* intrusive outline on top of the screen. * block. This means you do not get an intrusive outline on top of the screen.
*/ */
@Environment( EnvType.CLIENT ) @Environment( EnvType.CLIENT )
public final class MonitorHighlightRenderer public final class MonitorHighlightRenderer
@@ -37,115 +36,62 @@ public final class MonitorHighlightRenderer
{ {
} }
public static boolean drawHighlight( PoseStack matrixStack, VertexConsumer vertexConsumer, Entity entity, double d, double e, double f, BlockPos pos, BlockState blockState ) public static boolean drawHighlight( PoseStack transformStack, VertexConsumer buffer, Entity entity, double d, double e, double f, BlockPos pos, BlockState blockState )
{ {
// Preserve normal behaviour when crouching. // Preserve normal behaviour when crouching.
if( entity.isCrouching() ) if( entity.isCrouching() ) return false;
{
return false;
}
Level world = entity.getCommandSenderWorld(); Level world = entity.getCommandSenderWorld();
BlockEntity tile = world.getBlockEntity( pos ); BlockEntity tile = world.getBlockEntity( pos );
if( !(tile instanceof TileMonitor monitor) ) if( !(tile instanceof TileMonitor monitor) ) return false;
{
return false;
}
// Determine which sides are part of the external faces of the monitor, and so which need to be rendered. // Determine which sides are part of the external faces of the monitor, and so which need to be rendered.
EnumSet<Direction> faces = EnumSet.allOf( Direction.class ); EnumSet<Direction> faces = EnumSet.allOf( Direction.class );
Direction front = monitor.getFront(); Direction front = monitor.getFront();
faces.remove( front ); faces.remove( front );
if( monitor.getXIndex() != 0 ) if( monitor.getXIndex() != 0 ) faces.remove( monitor.getRight().getOpposite() );
{ if( monitor.getXIndex() != monitor.getWidth() - 1 ) faces.remove( monitor.getRight() );
faces.remove( monitor.getRight() if( monitor.getYIndex() != 0 ) faces.remove( monitor.getDown().getOpposite() );
.getOpposite() ); if( monitor.getYIndex() != monitor.getHeight() - 1 ) faces.remove( monitor.getDown() );
}
if( monitor.getXIndex() != monitor.getWidth() - 1 )
{
faces.remove( monitor.getRight() );
}
if( monitor.getYIndex() != 0 )
{
faces.remove( monitor.getDown()
.getOpposite() );
}
if( monitor.getYIndex() != monitor.getHeight() - 1 )
{
faces.remove( monitor.getDown() );
}
Vec3 cameraPos = Minecraft.getInstance().gameRenderer.getMainCamera() Vec3 cameraPos = Minecraft.getInstance().gameRenderer.getMainCamera().getPosition();
.getPosition(); transformStack.pushPose();
matrixStack.pushPose(); transformStack.translate( pos.getX() - cameraPos.x(), pos.getY() - cameraPos.y(), pos.getZ() - cameraPos.z() );
matrixStack.translate( pos.getX() - cameraPos.x(), pos.getY() - cameraPos.y(), pos.getZ() - cameraPos.z() );
// I wish I could think of a better way to do this // I wish I could think of a better way to do this
Matrix4f transform = matrixStack.last() Matrix4f transform = transformStack.last().pose();
.pose(); Matrix3f normal = transformStack.last().normal();
Matrix3f normal = matrixStack.last().normal(); if( faces.contains( NORTH ) || faces.contains( WEST ) ) line( buffer, transform, normal, 0, 0, 0, UP );
if( faces.contains( NORTH ) || faces.contains( WEST ) ) if( faces.contains( SOUTH ) || faces.contains( WEST ) ) line( buffer, transform, normal, 0, 0, 1, UP );
{ if( faces.contains( NORTH ) || faces.contains( EAST ) ) line( buffer, transform, normal, 1, 0, 0, UP );
line( vertexConsumer, transform, normal, 0, 0, 0, UP ); if( faces.contains( SOUTH ) || faces.contains( EAST ) ) line( buffer, transform, normal, 1, 0, 1, UP );
} if( faces.contains( NORTH ) || faces.contains( DOWN ) ) line( buffer, transform, normal, 0, 0, 0, EAST );
if( faces.contains( SOUTH ) || faces.contains( WEST ) ) if( faces.contains( SOUTH ) || faces.contains( DOWN ) ) line( buffer, transform, normal, 0, 0, 1, EAST );
{ if( faces.contains( NORTH ) || faces.contains( UP ) ) line( buffer, transform, normal, 0, 1, 0, EAST );
line( vertexConsumer, transform, normal, 0, 0, 1, UP ); if( faces.contains( SOUTH ) || faces.contains( UP ) ) line( buffer, transform, normal, 0, 1, 1, EAST );
} if( faces.contains( WEST ) || faces.contains( DOWN ) ) line( buffer, transform, normal, 0, 0, 0, SOUTH );
if( faces.contains( NORTH ) || faces.contains( EAST ) ) if( faces.contains( EAST ) || faces.contains( DOWN ) ) line( buffer, transform, normal, 1, 0, 0, SOUTH );
{ if( faces.contains( WEST ) || faces.contains( UP ) ) line( buffer, transform, normal, 0, 1, 0, SOUTH );
line( vertexConsumer, transform, normal, 1, 0, 0, UP ); if( faces.contains( EAST ) || faces.contains( UP ) ) line( buffer, transform, normal, 1, 1, 0, SOUTH );
}
if( faces.contains( SOUTH ) || faces.contains( EAST ) )
{
line( vertexConsumer, transform, normal, 1, 0, 1, UP );
}
if( faces.contains( NORTH ) || faces.contains( DOWN ) )
{
line( vertexConsumer, transform, normal, 0, 0, 0, EAST );
}
if( faces.contains( SOUTH ) || faces.contains( DOWN ) )
{
line( vertexConsumer, transform, normal, 0, 0, 1, EAST );
}
if( faces.contains( NORTH ) || faces.contains( UP ) )
{
line( vertexConsumer, transform, normal, 0, 1, 0, EAST );
}
if( faces.contains( SOUTH ) || faces.contains( UP ) )
{
line( vertexConsumer, transform, normal, 0, 1, 1, EAST );
}
if( faces.contains( WEST ) || faces.contains( DOWN ) )
{
line( vertexConsumer, transform, normal, 0, 0, 0, SOUTH );
}
if( faces.contains( EAST ) || faces.contains( DOWN ) )
{
line( vertexConsumer, transform, normal, 1, 0, 0, SOUTH );
}
if( faces.contains( WEST ) || faces.contains( UP ) )
{
line( vertexConsumer, transform, normal, 0, 1, 0, SOUTH );
}
if( faces.contains( EAST ) || faces.contains( UP ) )
{
line( vertexConsumer, transform, normal, 1, 1, 0, SOUTH );
}
matrixStack.popPose();
transformStack.popPose();
return true; return true;
} }
private static void line( VertexConsumer buffer, Matrix4f transform, Matrix3f normal, float x, float y, float z, Direction direction ) private static void line( VertexConsumer buffer, Matrix4f transform, Matrix3f normal, float x, float y, float z, Direction direction )
{ {
buffer.vertex( transform, x, y, z ) buffer
.vertex( transform, x, y, z )
.color( 0, 0, 0, 0.4f ) .color( 0, 0, 0, 0.4f )
.normal( normal, direction.getStepX(), direction.getStepY(), direction.getStepZ() ) .normal( normal, direction.getStepX(), direction.getStepY(), direction.getStepZ() )
.endVertex(); .endVertex();
buffer.vertex( transform, x + direction.getStepX(), y + direction.getStepY(), z + direction.getStepZ() ) buffer
.vertex( transform,
x + direction.getStepX(),
y + direction.getStepY(),
z + direction.getStepZ()
)
.color( 0, 0, 0, 0.4f ) .color( 0, 0, 0, 0.4f )
.normal( normal, direction.getStepX(), direction.getStepY(), direction.getStepZ() ) .normal( normal, direction.getStepX(), direction.getStepY(), direction.getStepZ() )
.endVertex(); .endVertex();

View File

@@ -29,13 +29,13 @@ public class MonitorTextureBufferShader extends ShaderInstance
private final Uniform width; private final Uniform width;
private final Uniform height; private final Uniform height;
public MonitorTextureBufferShader( ResourceProvider factory, String name, VertexFormat format ) throws IOException public MonitorTextureBufferShader( ResourceProvider provider, String name, VertexFormat format ) throws IOException
{ {
super( factory, name, format ); super( provider, name, format );
width = getUniformChecked( "Width" ); width = getUniformChecked( "Width" );
height = getUniformChecked( "Height" ); height = getUniformChecked( "Height" );
palette = new Uniform( "Palette", Uniform.UT_FLOAT3 /* UT_FLOAT3 */, 16 * 3, this ); palette = new Uniform( "Palette", Uniform.UT_FLOAT3, 16 * 3, this );
updateUniformLocation( palette ); updateUniformLocation( palette );
Uniform tbo = getUniformChecked( "Tbo" ); Uniform tbo = getUniformChecked( "Tbo" );

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
@@ -18,31 +17,38 @@ import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAG
public final class PrintoutRenderer public final class PrintoutRenderer
{ {
private static final float BG_SIZE = 256.0f;
/** /**
* Width of a page. * Width of a page.
*/ */
public static final int X_SIZE = 172; public static final int X_SIZE = 172;
/** /**
* Height of a page. * Height of a page.
*/ */
public static final int Y_SIZE = 209; public static final int Y_SIZE = 209;
/** /**
* Padding between the left and right of a page and the text. * Padding between the left and right of a page and the text.
*/ */
public static final int X_TEXT_MARGIN = 13; public static final int X_TEXT_MARGIN = 13;
/** /**
* Padding between the top and bottom of a page and the text. * Padding between the top and bottom of a page and the text.
*/ */
public static final int Y_TEXT_MARGIN = 11; public static final int Y_TEXT_MARGIN = 11;
/**
* Size of the leather cover.
*/
public static final int COVER_SIZE = 12;
private static final float BG_SIZE = 256.0f;
/** /**
* Width of the extra page texture. * Width of the extra page texture.
*/ */
private static final int X_FOLD_SIZE = 12; private static final int X_FOLD_SIZE = 12;
/**
* Size of the leather cover.
*/
public static final int COVER_SIZE = 12;
private static final int COVER_Y = Y_SIZE; private static final int COVER_Y = Y_SIZE;
private static final int COVER_X = X_SIZE + 4 * X_FOLD_SIZE; private static final int COVER_X = X_SIZE + 4 * X_FOLD_SIZE;
@@ -53,18 +59,11 @@ public final class PrintoutRenderer
VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_TEXT ); VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_TEXT );
for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ )
{ {
FixedWidthFontRenderer.drawString( transform, FixedWidthFontRenderer.drawString( transform, buffer,
buffer, x, y + line * FONT_HEIGHT, text[start + line], colours[start + line], null, Palette.DEFAULT,
x, false, 0, 0,
y + line * FONT_HEIGHT, light
text[start + line], );
colours[start + line],
null,
Palette.DEFAULT,
false,
0,
0,
light );
} }
} }
@@ -73,18 +72,12 @@ public final class PrintoutRenderer
VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_TEXT ); VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_TEXT );
for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ )
{ {
FixedWidthFontRenderer.drawString( transform, FixedWidthFontRenderer.drawString( transform, buffer,
buffer, x, y + line * FONT_HEIGHT,
x, new TextBuffer( text[start + line] ), new TextBuffer( colours[start + line] ),
y + line * FONT_HEIGHT, null, Palette.DEFAULT, false, 0, 0,
new TextBuffer( text[start + line] ), light
new TextBuffer( colours[start + line] ), );
null,
Palette.DEFAULT,
false,
0,
0,
light );
} }
} }
@@ -107,18 +100,11 @@ public final class PrintoutRenderer
drawTexture( transform, buffer, right, y - 8, z - 0.02f, COVER_X + COVER_SIZE, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2, light ); drawTexture( transform, buffer, right, y - 8, z - 0.02f, COVER_X + COVER_SIZE, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2, light );
// Draw centre panel (just stretched texture, sorry). // Draw centre panel (just stretched texture, sorry).
drawTexture( transform, drawTexture( transform, buffer,
buffer, x - offset, y, z - 0.02f, X_SIZE + offset * 2, Y_SIZE,
x - offset, COVER_X + COVER_SIZE / 2.0f, COVER_SIZE, COVER_SIZE, Y_SIZE,
y, light
z - 0.02f, );
X_SIZE + offset * 2,
Y_SIZE,
COVER_X + COVER_SIZE / 2.0f,
COVER_SIZE,
COVER_SIZE,
Y_SIZE,
light );
float borderX = left; float borderX = left;
while( borderX < right ) while( borderX < right )
@@ -134,26 +120,27 @@ public final class PrintoutRenderer
drawTexture( transform, buffer, x, y, z, X_FOLD_SIZE * 2, 0, X_SIZE / 2.0f, Y_SIZE, light ); drawTexture( transform, buffer, x, y, z, X_FOLD_SIZE * 2, 0, X_SIZE / 2.0f, Y_SIZE, light );
for( int n = 0; n <= leftPages; n++ ) for( int n = 0; n <= leftPages; n++ )
{ {
drawTexture( transform, buffer, x - offsetAt( n ), y, z - 1e-3f * n, drawTexture( transform, buffer,
x - offsetAt( n ), y, z - 1e-3f * n,
// Use the left "bold" fold for the outermost page // Use the left "bold" fold for the outermost page
n == leftPages ? 0 : X_FOLD_SIZE, 0, X_FOLD_SIZE, Y_SIZE, light ); n == leftPages ? 0 : X_FOLD_SIZE, 0,
X_FOLD_SIZE, Y_SIZE, light
);
} }
// Right half // Right half
drawTexture( transform, buffer, x + X_SIZE / 2.0f, y, z, X_FOLD_SIZE * 2 + X_SIZE / 2.0f, 0, X_SIZE / 2.0f, Y_SIZE, light ); drawTexture( transform, buffer, x + X_SIZE / 2.0f, y, z, X_FOLD_SIZE * 2 + X_SIZE / 2.0f, 0, X_SIZE / 2.0f, Y_SIZE, light );
for( int n = 0; n <= rightPages; n++ ) for( int n = 0; n <= rightPages; n++ )
{ {
drawTexture( transform, buffer, x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3f * n, drawTexture( transform, buffer,
x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3f * n,
// Two folds, then the main page. Use the right "bold" fold for the outermost page. // Two folds, then the main page. Use the right "bold" fold for the outermost page.
X_FOLD_SIZE * 2 + X_SIZE + (n == rightPages ? X_FOLD_SIZE : 0), 0, X_FOLD_SIZE, Y_SIZE, light ); X_FOLD_SIZE * 2 + X_SIZE + (n == rightPages ? X_FOLD_SIZE : 0), 0,
X_FOLD_SIZE, Y_SIZE, light
);
} }
} }
public static float offsetAt( int page )
{
return (float) (32 * (1 - Math.pow( 1.2, -page )));
}
private static void drawTexture( Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float u, float v, float width, float height, int light ) private static void drawTexture( Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float u, float v, float width, float height, int light )
{ {
vertex( buffer, matrix, x, y + height, z, u / BG_SIZE, (v + height) / BG_SIZE, light ); vertex( buffer, matrix, x, y + height, z, u / BG_SIZE, (v + height) / BG_SIZE, light );
@@ -162,8 +149,7 @@ public final class PrintoutRenderer
vertex( buffer, matrix, x, y, z, u / BG_SIZE, v / BG_SIZE, light ); vertex( buffer, matrix, x, y, z, u / BG_SIZE, v / BG_SIZE, light );
} }
private static void drawTexture( Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float width, float height, float u, float v, private static void drawTexture( Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float width, float height, float u, float v, float tWidth, float tHeight, int light )
float tWidth, float tHeight, int light )
{ {
vertex( buffer, matrix, x, y + height, z, u / BG_SIZE, (v + tHeight) / BG_SIZE, light ); vertex( buffer, matrix, x, y + height, z, u / BG_SIZE, (v + tHeight) / BG_SIZE, light );
vertex( buffer, matrix, x + width, y + height, z, (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE, light ); vertex( buffer, matrix, x + width, y + height, z, (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE, light );
@@ -175,4 +161,9 @@ public final class PrintoutRenderer
{ {
buffer.vertex( matrix, x, y, z ).color( 255, 255, 255, 255 ).uv( u, v ).uv2( light ).endVertex(); buffer.vertex( matrix, x, y, z ).color( 255, 255, 255, 255 ).uv( u, v ).uv2( light ).endVertex();
} }
public static float offsetAt( int page )
{
return (float) (32 * (1 - Math.pow( 1.2, -page )));
}
} }

View File

@@ -14,25 +14,26 @@ import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class RenderTypes public class RenderTypes
{ {
public static final int FULL_BRIGHT_LIGHTMAP = (0xF << 4) | (0xF << 20); public static final int FULL_BRIGHT_LIGHTMAP = (0xF << 4) | (0xF << 20);
@Nullable
public static MonitorTextureBufferShader monitorTboShader; public static MonitorTextureBufferShader monitorTboShader;
@Nullable
public static ShaderInstance terminalShader; public static ShaderInstance terminalShader;
public static final RenderType TERMINAL_WITHOUT_DEPTH = Types.TERMINAL_WITHOUT_DEPTH; public static final RenderType TERMINAL_WITHOUT_DEPTH = Types.TERMINAL_WITHOUT_DEPTH;
public static final RenderType MONITOR_TBO = Types.MONITOR_TBO; public static final RenderType TERMINAL_BLOCKER = Types.TERMINAL_BLOCKER;
public static final RenderType TERMINAL_BLOCKER = Types.BLOCKER;
public static final RenderType TERMINAL_WITH_DEPTH = Types.TERMINAL_WITH_DEPTH; public static final RenderType TERMINAL_WITH_DEPTH = Types.TERMINAL_WITH_DEPTH;
public static final RenderType MONITOR_TBO = Types.MONITOR_TBO;
public static final RenderType PRINTOUT_TEXT = Types.PRINTOUT_TEXT; public static final RenderType PRINTOUT_TEXT = Types.PRINTOUT_TEXT;
/**
* This looks wrong (it should be POSITION_COLOR_TEX_LIGHTMAP surely!) but the fragment/vertex shader for that
* appear to entirely ignore the lightmap.
*
* Note that vanilla maps do the same, so this isn't unreasonable.
*/
public static final RenderType PRINTOUT_BACKGROUND = RenderType.text( new ResourceLocation( "computercraft", "textures/gui/printout.png" ) ); public static final RenderType PRINTOUT_BACKGROUND = RenderType.text( new ResourceLocation( "computercraft", "textures/gui/printout.png" ) );
public static final RenderType POSITION_COLOR = Types.POSITION_COLOR; public static final RenderType POSITION_COLOR = Types.POSITION_COLOR;
@@ -53,24 +54,26 @@ public class RenderTypes
private static final class Types extends RenderStateShard private static final class Types extends RenderStateShard
{ {
private static final VertexFormat.Mode GL_MODE = VertexFormat.Mode.TRIANGLES; private static final RenderStateShard.TextureStateShard TERM_FONT_TEXTURE = new TextureStateShard(
private static final VertexFormat FORMAT = DefaultVertexFormat.POSITION_COLOR_TEX;
private static final ShaderStateShard TERM_SHADER = new ShaderStateShard( RenderTypes::getTerminalShader );
private static final RenderStateShard.TextureStateShard TERM_FONT_TEXTURE = new RenderStateShard.TextureStateShard(
FixedWidthFontRenderer.FONT, FixedWidthFontRenderer.FONT,
false, false // blur, minimap false, false // blur, minimap
); );
private static final VertexFormat TERM_FORMAT = DefaultVertexFormat.POSITION_COLOR_TEX;
private static final VertexFormat.Mode TERM_MODE = VertexFormat.Mode.TRIANGLES;
private static final ShaderStateShard TERM_SHADER = new ShaderStateShard( RenderTypes::getTerminalShader );
public static final RenderType MONITOR_TBO = RenderType.create( "monitor_tbo", DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.TRIANGLE_STRIP, 128, false, false, // useDelegate, needsSorting static final RenderType MONITOR_TBO = RenderType.create(
"monitor_tbo", DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.TRIANGLE_STRIP, 128,
false, false, // useDelegate, needsSorting
RenderType.CompositeState.builder() RenderType.CompositeState.builder()
.setTextureState( TERM_FONT_TEXTURE ) // blur, minimap .setTextureState( TERM_FONT_TEXTURE )
.setShaderState( new RenderStateShard.ShaderStateShard( RenderTypes::getMonitorTextureBufferShader ) ) .setShaderState( new ShaderStateShard( RenderTypes::getMonitorTextureBufferShader ) )
.setWriteMaskState( RenderType.COLOR_DEPTH_WRITE ) .setWriteMaskState( COLOR_WRITE )
.createCompositeState( false ) ); .createCompositeState( false )
);
static final RenderType TERMINAL_WITHOUT_DEPTH = RenderType.create( static final RenderType TERMINAL_WITHOUT_DEPTH = RenderType.create(
"terminal_without_depth", FORMAT, GL_MODE, 1024, "terminal_without_depth", TERM_FORMAT, TERM_MODE, 1024,
false, false, // useDelegate, needsSorting false, false, // useDelegate, needsSorting
RenderType.CompositeState.builder() RenderType.CompositeState.builder()
.setTextureState( TERM_FONT_TEXTURE ) .setTextureState( TERM_FONT_TEXTURE )
@@ -79,15 +82,18 @@ public class RenderTypes
.createCompositeState( false ) .createCompositeState( false )
); );
static final RenderType BLOCKER = RenderType.create( "terminal_blocker", FORMAT, GL_MODE, 256, false, false, // useDelegate, needsSorting static final RenderType TERMINAL_BLOCKER = RenderType.create(
"terminal_blocker", TERM_FORMAT, TERM_MODE, 256,
false, false, // useDelegate, needsSorting
RenderType.CompositeState.builder() RenderType.CompositeState.builder()
.setTextureState( TERM_FONT_TEXTURE ) .setTextureState( TERM_FONT_TEXTURE )
.setShaderState( TERM_SHADER ) .setShaderState( TERM_SHADER )
.setWriteMaskState( DEPTH_WRITE ) .setWriteMaskState( DEPTH_WRITE )
.createCompositeState( false ) ); .createCompositeState( false )
);
static final RenderType TERMINAL_WITH_DEPTH = RenderType.create( static final RenderType TERMINAL_WITH_DEPTH = RenderType.create(
"terminal_with_depth", FORMAT, GL_MODE, 1024, "terminal_with_depth", TERM_FORMAT, TERM_MODE, 1024,
false, false, // useDelegate, needsSorting false, false, // useDelegate, needsSorting
RenderType.CompositeState.builder() RenderType.CompositeState.builder()
.setTextureState( TERM_FONT_TEXTURE ) .setTextureState( TERM_FONT_TEXTURE )
@@ -95,8 +101,11 @@ public class RenderTypes
.createCompositeState( false ) .createCompositeState( false )
); );
/**
* A variant of {@link #TERMINAL_WITH_DEPTH} which uses the lightmap rather than rendering fullbright.
*/
static final RenderType PRINTOUT_TEXT = RenderType.create( static final RenderType PRINTOUT_TEXT = RenderType.create(
"printout_text", DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP, GL_MODE, 1024, "printout_text", DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP, TERM_MODE, 1024,
false, false, // useDelegate, needsSorting false, false, // useDelegate, needsSorting
RenderType.CompositeState.builder() RenderType.CompositeState.builder()
.setTextureState( TERM_FONT_TEXTURE ) .setTextureState( TERM_FONT_TEXTURE )

View File

@@ -3,10 +3,10 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.platform.MemoryTracker;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*; import com.mojang.blaze3d.vertex.*;
import com.mojang.math.Matrix4f; import com.mojang.math.Matrix4f;
@@ -35,27 +35,25 @@ import org.lwjgl.opengl.GL31;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import static com.mojang.blaze3d.platform.MemoryTracker.create;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*;
public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonitor> public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonitor>
{ {
/** /**
* {@link TileMonitor#RENDER_MARGIN}, but a tiny bit of additional padding to ensure that there is no space between the monitor frame and contents. * {@link TileMonitor#RENDER_MARGIN}, but a tiny bit of additional padding to ensure that there is no space between
* the monitor frame and contents.
*/ */
private static final float MARGIN = (float) (TileMonitor.RENDER_MARGIN * 1.1); private static final float MARGIN = (float) (TileMonitor.RENDER_MARGIN * 1.1);
private static final Matrix4f IDENTITY = Transformation.identity()
.getMatrix();
private static ByteBuffer tboContents; private static ByteBuffer tboContents;
private static final Matrix4f IDENTITY = Transformation.identity().getMatrix();
public TileEntityMonitorRenderer( BlockEntityRendererProvider.Context context ) public TileEntityMonitorRenderer( BlockEntityRendererProvider.Context context )
{ {
// super( context );
} }
@Override @Override
public void render( @Nonnull TileMonitor monitor, float partialTicks, @Nonnull PoseStack transform, @Nonnull MultiBufferSource renderer, public void render( @Nonnull TileMonitor monitor, float partialTicks, @Nonnull PoseStack transform, @Nonnull MultiBufferSource renderer, int lightmapCoord, int overlayLight )
int lightmapCoord, int overlayLight )
{ {
// Render from the origin monitor // Render from the origin monitor
ClientMonitor originTerminal = monitor.getClientMonitor(); ClientMonitor originTerminal = monitor.getClientMonitor();
@@ -86,15 +84,19 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
// Setup initial transform // Setup initial transform
transform.pushPose(); transform.pushPose();
transform.translate( originPos.getX() - monitorPos.getX() + 0.5, transform.translate(
originPos.getX() - monitorPos.getX() + 0.5,
originPos.getY() - monitorPos.getY() + 0.5, originPos.getY() - monitorPos.getY() + 0.5,
originPos.getZ() - monitorPos.getZ() + 0.5 ); originPos.getZ() - monitorPos.getZ() + 0.5
);
transform.mulPose( Vector3f.YN.rotationDegrees( yaw ) ); transform.mulPose( Vector3f.YN.rotationDegrees( yaw ) );
transform.mulPose( Vector3f.XP.rotationDegrees( pitch ) ); transform.mulPose( Vector3f.XP.rotationDegrees( pitch ) );
transform.translate( -0.5 + TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN, transform.translate(
-0.5 + TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN,
origin.getHeight() - 0.5 - (TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN) + 0, origin.getHeight() - 0.5 - (TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN) + 0,
0.50 ); 0.5
);
double xSize = origin.getWidth() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER); double xSize = origin.getWidth() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER);
double ySize = origin.getHeight() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER); double ySize = origin.getHeight() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER);
@@ -116,58 +118,56 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
// We don't draw the cursor with the VBO, as it's dynamic and so we'll end up refreshing far more than is // We don't draw the cursor with the VBO, as it's dynamic and so we'll end up refreshing far more than is
// reasonable. // reasonable.
FixedWidthFontRenderer.drawCursor( matrix, renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ), 0, 0, terminal, !originTerminal.isColour() ); FixedWidthFontRenderer.drawCursor(
matrix, renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ),
0, 0, terminal, !originTerminal.isColour()
);
transform.popPose(); transform.popPose();
// Draw the background blocker
FixedWidthFontRenderer.drawBlocker( FixedWidthFontRenderer.drawBlocker(
transform.last().pose(), renderer, transform.last().pose(), renderer,
-MARGIN, MARGIN, -MARGIN, MARGIN,
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2) (float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
); );
// Force a flush of the blocker. WorldRenderer.updateCameraAndRender will "finish" all the built-in
// buffers before calling renderer.finish, which means the blocker isn't actually rendered at that point!
renderer.getBuffer( RenderType.solid() ); renderer.getBuffer( RenderType.solid() );
} }
else else
{ {
FixedWidthFontRenderer.drawEmptyTerminal( transform.last() FixedWidthFontRenderer.drawEmptyTerminal(
.pose(), transform.last().pose(), renderer,
renderer, -MARGIN, MARGIN,
-MARGIN, (float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
MARGIN, );
(float) (xSize + 2 * MARGIN),
(float) -(ySize + MARGIN * 2) );
} }
transform.popPose(); transform.popPose();
} }
private static void renderTerminal( MultiBufferSource renderer, Matrix4f matrix, ClientMonitor monitor, float xMargin, float yMargin ) private static void renderTerminal( @Nonnull MultiBufferSource renderer, Matrix4f matrix, ClientMonitor monitor, float xMargin, float yMargin )
{ {
Terminal terminal = monitor.getTerminal(); Terminal terminal = monitor.getTerminal();
MonitorRenderer renderType = MonitorRenderer.current(); MonitorRenderer renderType = MonitorRenderer.current();
boolean redraw = monitor.pollTerminalChanged(); boolean redraw = monitor.pollTerminalChanged();
if( monitor.createBuffer( renderType ) ) if( monitor.createBuffer( renderType ) ) redraw = true;
{
redraw = true;
}
switch( renderType ) switch( renderType )
{ {
case TBO: case TBO:
{ {
int width = terminal.getWidth(), height = terminal.getHeight(); int width = terminal.getWidth(), height = terminal.getHeight();
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
if( redraw ) if( redraw )
{ {
int size = width * height * 3; int size = width * height * 3;
if( tboContents == null || tboContents.capacity() < size ) if( tboContents == null || tboContents.capacity() < size )
{ {
tboContents = create( size ); tboContents = MemoryTracker.create( size );
} }
ByteBuffer monitorBuffer = tboContents; ByteBuffer monitorBuffer = tboContents;
@@ -204,37 +204,34 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
tboVertex( buffer, matrix, pixelWidth + xMargin, -yMargin ); tboVertex( buffer, matrix, pixelWidth + xMargin, -yMargin );
tboVertex( buffer, matrix, pixelWidth + xMargin, pixelHeight + yMargin ); tboVertex( buffer, matrix, pixelWidth + xMargin, pixelHeight + yMargin );
// And force things to flush. We strictly speaking do this later on anyway for the cursor, but nice to
// be consistent.
renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ); renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH );
break; break;
} }
case VBO: case VBO:
{
VertexBuffer vbo = monitor.buffer; VertexBuffer vbo = monitor.buffer;
if( redraw ) if( redraw )
{ {
Tesselator tessellator = Tesselator.getInstance(); Tesselator tessellator = Tesselator.getInstance();
BufferBuilder builder = tessellator.getBuilder(); BufferBuilder builder = tessellator.getBuilder();
builder.begin( RenderTypes.TERMINAL_WITHOUT_DEPTH.mode(), RenderTypes.TERMINAL_WITHOUT_DEPTH.format() ); builder.begin( RenderTypes.TERMINAL_WITHOUT_DEPTH.mode(), RenderTypes.TERMINAL_WITHOUT_DEPTH.format() );
FixedWidthFontRenderer.drawTerminalWithoutCursor( IDENTITY, FixedWidthFontRenderer.drawTerminalWithoutCursor(
builder, IDENTITY, builder, 0, 0,
0, terminal, !monitor.isColour(), yMargin, yMargin, xMargin, xMargin
0, );
terminal,
!monitor.isColour(),
yMargin,
yMargin,
xMargin,
xMargin );
builder.end(); builder.end();
vbo.upload( builder ); vbo.upload( builder );
} }
renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ); renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH );
RenderTypes.TERMINAL_WITHOUT_DEPTH.setupRenderState(); RenderTypes.TERMINAL_WITHOUT_DEPTH.setupRenderState();
vbo.drawWithShader( matrix, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader() ); vbo.drawWithShader( matrix, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader() );
break; break;
}
} }
} }

View File

@@ -47,7 +47,7 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
private final Random random = new Random( 0 ); private final Random random = new Random( 0 );
BlockEntityRenderDispatcher renderer; private final BlockEntityRenderDispatcher renderer;
public TileEntityTurtleRenderer( BlockEntityRendererProvider.Context context ) public TileEntityTurtleRenderer( BlockEntityRendererProvider.Context context )
{ {
@@ -68,39 +68,28 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
public static ModelResourceLocation getTurtleOverlayModel( ResourceLocation overlay, boolean christmas ) public static ModelResourceLocation getTurtleOverlayModel( ResourceLocation overlay, boolean christmas )
{ {
if( overlay != null ) if( overlay != null ) return new ModelResourceLocation( overlay, "inventory" );
{ if( christmas ) return ELF_OVERLAY_MODEL;
return new ModelResourceLocation( overlay, "inventory" );
}
if( christmas )
{
return ELF_OVERLAY_MODEL;
}
return null; return null;
} }
@Override @Override
public void render( @Nonnull TileTurtle turtle, float partialTicks, @Nonnull PoseStack transform, @Nonnull MultiBufferSource buffers, public void render( @Nonnull TileTurtle turtle, float partialTicks, @Nonnull PoseStack transform, @Nonnull MultiBufferSource buffers, int lightmapCoord, int overlayLight )
int lightmapCoord, int overlayLight )
{ {
// Render the label // Render the label
String label = turtle.createProxy() String label = turtle.createProxy().getLabel();
.getLabel();
HitResult hit = renderer.cameraHitResult; HitResult hit = renderer.cameraHitResult;
if( label != null && hit.getType() == HitResult.Type.BLOCK && turtle.getBlockPos() if( label != null && hit.getType() == HitResult.Type.BLOCK && turtle.getBlockPos().equals( ((BlockHitResult) hit).getBlockPos() ) )
.equals( ((BlockHitResult) hit).getBlockPos() ) )
{ {
Minecraft mc = Minecraft.getInstance(); Minecraft mc = Minecraft.getInstance();
Font font = mc.font; Font font = mc.font;
transform.pushPose(); transform.pushPose();
transform.translate( 0.5, 1.2, 0.5 ); transform.translate( 0.5, 1.2, 0.5 );
transform.mulPose( mc.getEntityRenderDispatcher() transform.mulPose( mc.getEntityRenderDispatcher().cameraOrientation() );
.cameraOrientation() );
transform.scale( -0.025f, -0.025f, 0.025f ); transform.scale( -0.025f, -0.025f, 0.025f );
Matrix4f matrix = transform.last() Matrix4f matrix = transform.last().pose();
.pose();
int opacity = (int) (mc.options.getBackgroundOpacity( 0.25f ) * 255) << 24; int opacity = (int) (mc.options.getBackgroundOpacity( 0.25f ) * 255) << 24;
float width = -font.width( label ) / 2.0f; float width = -font.width( label ) / 2.0f;
font.drawInBatch( label, width, (float) 0, 0x20ffffff, false, matrix, buffers, true, opacity, lightmapCoord ); font.drawInBatch( label, width, (float) 0, 0x20ffffff, false, matrix, buffers, true, opacity, lightmapCoord );
@@ -147,14 +136,10 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
transform.popPose(); transform.popPose();
} }
private void renderUpgrade( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, TileTurtle turtle, private void renderUpgrade( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, TileTurtle turtle, TurtleSide side, float f )
TurtleSide side, float f )
{ {
ITurtleUpgrade upgrade = turtle.getUpgrade( side ); ITurtleUpgrade upgrade = turtle.getUpgrade( side );
if( upgrade == null ) if( upgrade == null ) return;
{
return;
}
transform.pushPose(); transform.pushPose();
float toolAngle = turtle.getToolRenderAngle( side, f ); float toolAngle = turtle.getToolRenderAngle( side, f );
@@ -170,18 +155,13 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
transform.popPose(); transform.popPose();
} }
private void renderModel( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, private void renderModel( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, ModelResourceLocation modelLocation, int[] tints )
ModelResourceLocation modelLocation, int[] tints )
{ {
ModelManager modelManager = Minecraft.getInstance() ModelManager modelManager = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getModelManager();
.getItemRenderer()
.getItemModelShaper()
.getModelManager();
renderModel( transform, renderer, lightmapCoord, overlayLight, modelManager.getModel( modelLocation ), tints ); renderModel( transform, renderer, lightmapCoord, overlayLight, modelManager.getModel( modelLocation ), tints );
} }
private void renderModel( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model, private void renderModel( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model, int[] tints )
int[] tints )
{ {
random.setSeed( 0 ); random.setSeed( 0 );
renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, null, random ), tints ); renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, null, random ), tints );
@@ -191,8 +171,7 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
} }
} }
private static void renderQuads( @Nonnull PoseStack transform, @Nonnull VertexConsumer buffer, int lightmapCoord, int overlayLight, private static void renderQuads( @Nonnull PoseStack transform, @Nonnull VertexConsumer buffer, int lightmapCoord, int overlayLight, List<BakedQuad> quads, int[] tints )
List<BakedQuad> quads, int[] tints )
{ {
PoseStack.Pose matrix = transform.last(); PoseStack.Pose matrix = transform.last();
@@ -202,10 +181,7 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
if( tints != null && bakedquad.isTinted() ) if( tints != null && bakedquad.isTinted() )
{ {
int idx = bakedquad.getTintIndex(); int idx = bakedquad.getTintIndex();
if( idx >= 0 && idx < tints.length ) if( idx >= 0 && idx < tints.length ) tint = tints[bakedquad.getTintIndex()];
{
tint = tints[bakedquad.getTintIndex()];
}
} }
float f = (float) (tint >> 16 & 255) / 255.0F; float f = (float) (tint >> 16 & 255) / 255.0F;

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Pair;

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.math.Transformation; import com.mojang.math.Transformation;
@@ -32,8 +31,7 @@ public class TurtleMultiModel implements BakedModel
private List<BakedQuad> generalQuads = null; private List<BakedQuad> generalQuads = null;
private final Map<Direction, List<BakedQuad>> faceQuads = new EnumMap<>( Direction.class ); private final Map<Direction, List<BakedQuad>> faceQuads = new EnumMap<>( Direction.class );
public TurtleMultiModel( BakedModel baseModel, BakedModel overlayModel, Transformation generalTransform, TransformedModel leftUpgradeModel, public TurtleMultiModel( BakedModel baseModel, BakedModel overlayModel, Transformation generalTransform, TransformedModel leftUpgradeModel, TransformedModel rightUpgradeModel )
TransformedModel rightUpgradeModel )
{ {
// Get the models // Get the models
this.baseModel = baseModel; this.baseModel = baseModel;
@@ -45,22 +43,17 @@ public class TurtleMultiModel implements BakedModel
@Nonnull @Nonnull
@Override @Override
@Deprecated
public List<BakedQuad> getQuads( BlockState state, Direction side, @Nonnull Random rand ) public List<BakedQuad> getQuads( BlockState state, Direction side, @Nonnull Random rand )
{ {
if( side != null ) if( side != null )
{ {
if( !faceQuads.containsKey( side ) ) if( !faceQuads.containsKey( side ) ) faceQuads.put( side, buildQuads( state, side, rand ) );
{
faceQuads.put( side, buildQuads( state, side, rand ) );
}
return faceQuads.get( side ); return faceQuads.get( side );
} }
else else
{ {
if( generalQuads == null ) if( generalQuads == null ) generalQuads = buildQuads( state, side, rand );
{
generalQuads = buildQuads( state, side, rand );
}
return generalQuads; return generalQuads;
} }
} }
@@ -70,24 +63,20 @@ public class TurtleMultiModel implements BakedModel
ArrayList<BakedQuad> quads = new ArrayList<>(); ArrayList<BakedQuad> quads = new ArrayList<>();
ModelTransformer.transformQuadsTo( quads, baseModel.getQuads( state, side, rand ), generalTransform.getMatrix() ); transformQuadsTo( quads, baseModel.getQuads( state, side, rand ), generalTransform );
if( overlayModel != null ) if( overlayModel != null )
{ {
ModelTransformer.transformQuadsTo( quads, overlayModel.getQuads( state, side, rand ), generalTransform.getMatrix() ); transformQuadsTo( quads, overlayModel.getQuads( state, side, rand ), generalTransform );
} }
if( leftUpgradeModel != null ) if( leftUpgradeModel != null )
{ {
Transformation upgradeTransform = generalTransform.compose( leftUpgradeModel.getMatrix() ); Transformation upgradeTransform = generalTransform.compose( leftUpgradeModel.getMatrix() );
ModelTransformer.transformQuadsTo( quads, leftUpgradeModel.getModel() transformQuadsTo( quads, leftUpgradeModel.getModel().getQuads( state, side, rand ), upgradeTransform );
.getQuads( state, side, rand ),
upgradeTransform.getMatrix() );
} }
if( rightUpgradeModel != null ) if( rightUpgradeModel != null )
{ {
Transformation upgradeTransform = generalTransform.compose( rightUpgradeModel.getMatrix() ); Transformation upgradeTransform = generalTransform.compose( rightUpgradeModel.getMatrix() );
ModelTransformer.transformQuadsTo( quads, rightUpgradeModel.getModel() transformQuadsTo( quads, rightUpgradeModel.getModel().getQuads( state, side, rand ), upgradeTransform );
.getQuads( state, side, rand ),
upgradeTransform.getMatrix() );
} }
quads.trimToSize(); quads.trimToSize();
return quads; return quads;
@@ -105,18 +94,18 @@ public class TurtleMultiModel implements BakedModel
return baseModel.isGui3d(); return baseModel.isGui3d();
} }
@Override
public boolean usesBlockLight()
{
return baseModel.usesBlockLight();
}
@Override @Override
public boolean isCustomRenderer() public boolean isCustomRenderer()
{ {
return baseModel.isCustomRenderer(); return baseModel.isCustomRenderer();
} }
@Override
public boolean usesBlockLight()
{
return baseModel.usesBlockLight();
}
@Nonnull @Nonnull
@Override @Override
@Deprecated @Deprecated
@@ -139,4 +128,9 @@ public class TurtleMultiModel implements BakedModel
{ {
return ItemOverrides.EMPTY; return ItemOverrides.EMPTY;
} }
private void transformQuadsTo( List<BakedQuad> output, List<BakedQuad> quads, Transformation transform )
{
ModelTransformer.transformQuadsTo( output, quads, transform.getMatrix() );
}
} }

View File

@@ -15,16 +15,10 @@ import net.minecraft.resources.ResourceLocation;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public class TurtlePlayerRenderer extends EntityRenderer<TurtlePlayer> public class TurtlePlayerRenderer extends EntityRenderer<TurtlePlayer>
{ //FIXME Make sure this isn't an issue. Context was EntityRenderDispatcher. {
public TurtlePlayerRenderer( EntityRendererProvider.Context context ) public TurtlePlayerRenderer( EntityRendererProvider.Context renderManager )
{
super( context );
}
@Override
public void render( @Nonnull TurtlePlayer entityIn, float entityYaw, float partialTicks, @Nonnull PoseStack transform,
@Nonnull MultiBufferSource buffer, int packedLightIn )
{ {
super( renderManager );
} }
@Nonnull @Nonnull
@@ -33,4 +27,9 @@ public class TurtlePlayerRenderer extends EntityRenderer<TurtlePlayer>
{ {
return ComputerBorderRenderer.BACKGROUND_NORMAL; return ComputerBorderRenderer.BACKGROUND_NORMAL;
} }
@Override
public void render( @Nonnull TurtlePlayer entityIn, float entityYaw, float partialTicks, @Nonnull PoseStack transform, @Nonnull MultiBufferSource buffer, int packedLightIn )
{
}
} }

View File

@@ -5,7 +5,6 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.google.common.base.Objects;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Transformation; import com.mojang.math.Transformation;
import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.client.TransformedModel;
@@ -50,59 +49,18 @@ public class TurtleSmartItemModel implements BakedModel
stack.translate( 0, 0, 1 ); stack.translate( 0, 0, 1 );
identity = Transformation.identity(); identity = Transformation.identity();
flip = new Transformation( stack.last() flip = new Transformation( stack.last().pose() );
.pose() );
} }
private static class TurtleModelCombination private static record TurtleModelCombination(
boolean colour,
ITurtleUpgrade leftUpgrade,
ITurtleUpgrade rightUpgrade,
ResourceLocation overlay,
boolean christmas,
boolean flip
)
{ {
final boolean colour;
final ITurtleUpgrade leftUpgrade;
final ITurtleUpgrade rightUpgrade;
final ResourceLocation overlay;
final boolean christmas;
final boolean flip;
TurtleModelCombination( boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, ResourceLocation overlay, boolean christmas,
boolean flip )
{
this.colour = colour;
this.leftUpgrade = leftUpgrade;
this.rightUpgrade = rightUpgrade;
this.overlay = overlay;
this.christmas = christmas;
this.flip = flip;
}
@Override
public boolean equals( Object other )
{
if( other == this )
{
return true;
}
if( !(other instanceof TurtleModelCombination otherCombo) )
{
return false;
}
return otherCombo.colour == colour && otherCombo.leftUpgrade == leftUpgrade && otherCombo.rightUpgrade == rightUpgrade && Objects.equal(
otherCombo.overlay, overlay ) && otherCombo.christmas == christmas && otherCombo.flip == flip;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 0;
result = prime * result + (colour ? 1 : 0);
result = prime * result + (leftUpgrade != null ? leftUpgrade.hashCode() : 0);
result = prime * result + (rightUpgrade != null ? rightUpgrade.hashCode() : 0);
result = prime * result + (overlay != null ? overlay.hashCode() : 0);
result = prime * result + (christmas ? 1 : 0);
result = prime * result + (flip ? 1 : 0);
return result;
}
} }
private final BakedModel familyModel; private final BakedModel familyModel;
@@ -121,7 +79,7 @@ public class TurtleSmartItemModel implements BakedModel
{ {
@Nonnull @Nonnull
@Override @Override
public BakedModel resolve( BakedModel originalModel, ItemStack stack, @Nullable ClientLevel world, @Nullable LivingEntity entity, int seed ) public BakedModel resolve( @Nonnull BakedModel originalModel, @Nonnull ItemStack stack, @Nullable ClientLevel world, @Nullable LivingEntity entity, int random )
{ {
ItemTurtle turtle = (ItemTurtle) stack.getItem(); ItemTurtle turtle = (ItemTurtle) stack.getItem();
int colour = turtle.getColour( stack ); int colour = turtle.getColour( stack );
@@ -134,21 +92,23 @@ public class TurtleSmartItemModel implements BakedModel
TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip ); TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip );
BakedModel model = cachedModels.get( combo ); BakedModel model = cachedModels.get( combo );
if( model == null ) if( model == null ) cachedModels.put( combo, model = buildModel( combo ) );
{
cachedModels.put( combo, model = buildModel( combo ) );
}
return model; return model;
} }
}; };
} }
@Nonnull
@Override
public ItemOverrides getOverrides()
{
return overrides;
}
private BakedModel buildModel( TurtleModelCombination combo ) private BakedModel buildModel( TurtleModelCombination combo )
{ {
Minecraft mc = Minecraft.getInstance(); Minecraft mc = Minecraft.getInstance();
ModelManager modelManager = mc.getItemRenderer() ModelManager modelManager = mc.getItemRenderer().getItemModelShaper().getModelManager();
.getItemModelShaper()
.getModelManager();
ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.overlay, combo.christmas ); ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.overlay, combo.christmas );
BakedModel baseModel = combo.colour ? colourModel : familyModel; BakedModel baseModel = combo.colour ? colourModel : familyModel;
@@ -179,12 +139,6 @@ public class TurtleSmartItemModel implements BakedModel
return familyModel.isGui3d(); return familyModel.isGui3d();
} }
@Override
public boolean usesBlockLight()
{
return familyModel.usesBlockLight();
}
@Override @Override
public boolean isCustomRenderer() public boolean isCustomRenderer()
{ {
@@ -192,17 +146,17 @@ public class TurtleSmartItemModel implements BakedModel
} }
@Override @Override
@Deprecated public boolean usesBlockLight()
public TextureAtlasSprite getParticleIcon()
{ {
return familyModel.getParticleIcon(); return familyModel.usesBlockLight();
} }
@Nonnull @Nonnull
@Override @Override
public ItemOverrides getOverrides() @Deprecated
public TextureAtlasSprite getParticleIcon()
{ {
return overrides; return familyModel.getParticleIcon();
} }
@Nonnull @Nonnull

View File

@@ -484,7 +484,7 @@ public class FSAPI implements ILuaAPI
* *
* This string is formatted like a normal path string, but can include any * This string is formatted like a normal path string, but can include any
* number of wildcards ({@code *}) to look for files matching anything. * number of wildcards ({@code *}) to look for files matching anything.
* For example, {@code rom/* /command*} will look for any path starting with * For example, <code>rom/&#42;/command*</code> will look for any path starting with
* {@code command} inside any subdirectory of {@code /rom}. * {@code command} inside any subdirectory of {@code /rom}.
* *
* @param path The wildcard-qualified path to search for. * @param path The wildcard-qualified path to search for.

View File

@@ -17,6 +17,7 @@ import dan200.computercraft.core.asm.NamedMethod;
import dan200.computercraft.core.asm.PeripheralMethod; import dan200.computercraft.core.asm.PeripheralMethod;
import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.core.tracking.TrackingField;
import dan200.computercraft.shared.util.LuaUtil;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -36,6 +37,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
private final IPeripheral peripheral; private final IPeripheral peripheral;
private final String type; private final String type;
private final Set<String> additionalTypes;
private final Map<String, PeripheralMethod> methodMap; private final Map<String, PeripheralMethod> methodMap;
private boolean attached; private boolean attached;
@@ -47,6 +49,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
attached = false; attached = false;
type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" ); type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" );
additionalTypes = peripheral.getAdditionalTypes();
methodMap = PeripheralAPI.getMethods( peripheral ); methodMap = PeripheralAPI.getMethods( peripheral );
} }
@@ -61,6 +64,11 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
return type; return type;
} }
public Set<String> getAdditionalTypes()
{
return additionalTypes;
}
public Collection<String> getMethods() public Collection<String> getMethods()
{ {
return methodMap.keySet(); return methodMap.keySet();
@@ -298,7 +306,23 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
synchronized( peripherals ) synchronized( peripherals )
{ {
PeripheralWrapper p = peripherals[side.ordinal()]; PeripheralWrapper p = peripherals[side.ordinal()];
if( p != null ) return new Object[] { p.getType() }; return p == null ? null : LuaUtil.consArray( p.getType(), p.getAdditionalTypes() );
}
}
@LuaFunction
public final Object[] hasType( String sideName, String type )
{
ComputerSide side = ComputerSide.valueOfInsensitive( sideName );
if( side == null ) return null;
synchronized( peripherals )
{
PeripheralWrapper p = peripherals[side.ordinal()];
if( p != null )
{
return new Object[] { p.getType().equals( type ) || p.getAdditionalTypes().contains( type ) };
}
} }
return null; return null;
} }

View File

@@ -100,7 +100,7 @@ public class BinaryWritableHandle extends HandleGeneric
try try
{ {
// Technically this is not needed // Technically this is not needed
if( writer instanceof FileChannel ) ((FileChannel) writer).force( false ); if( writer instanceof FileChannel channel ) channel.force( false );
} }
catch( IOException ignored ) catch( IOException ignored )
{ {

View File

@@ -153,7 +153,7 @@ public class WebsocketHandle implements Closeable
return MethodResult.of(); return MethodResult.of();
} }
else if( event.length >= 2 && timeoutId != -1 && Objects.equal( event[0], TIMER_EVENT ) else if( event.length >= 2 && timeoutId != -1 && Objects.equal( event[0], TIMER_EVENT )
&& event[1] instanceof Number && ((Number) event[1]).intValue() == timeoutId ) && event[1] instanceof Number id && id.intValue() == timeoutId )
{ {
// If we received a matching timer event then abort. // If we received a matching timer event then abort.
return MethodResult.of(); return MethodResult.of();

View File

@@ -5,7 +5,7 @@
*/ */
package dan200.computercraft.fabric.mixin; package dan200.computercraft.fabric.mixin;
import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.Registry;
import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
@@ -33,7 +33,7 @@ public class MixinServerPlayerGameMode
{ {
BlockPos pos = hitResult.getBlockPos(); BlockPos pos = hitResult.getBlockPos();
BlockState state = world.getBlockState( pos ); BlockState state = world.getBlockState( pos );
if( player.getMainHandItem().getItem() == ComputerCraftRegistry.ModItems.DISK && state.getBlock() == ComputerCraftRegistry.ModBlocks.DISK_DRIVE ) if( player.getMainHandItem().getItem() == Registry.ModItems.DISK && state.getBlock() == Registry.ModBlocks.DISK_DRIVE )
{ {
InteractionResult actionResult = state.use( world, player, hand, hitResult ); InteractionResult actionResult = state.use( world, player, hand, hitResult );
if( actionResult.consumesAction() ) if( actionResult.consumesAction() )

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared; package dan200.computercraft.shared;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
@@ -34,18 +33,9 @@ public final class BundledRedstone
return world.isInWorldBounds( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1; return world.isInWorldBounds( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1;
} }
public static int getOutput( Level world, BlockPos pos, Direction side )
{
int signal = getUnmaskedOutput( world, pos, side );
return signal >= 0 ? signal : 0;
}
private static int getUnmaskedOutput( Level world, BlockPos pos, Direction side ) private static int getUnmaskedOutput( Level world, BlockPos pos, Direction side )
{ {
if( !world.isInWorldBounds( pos ) ) if( !world.isInWorldBounds( pos ) ) return -1;
{
return -1;
}
// Try the providers in order: // Try the providers in order:
int combinedSignal = -1; int combinedSignal = -1;
@@ -67,4 +57,10 @@ public final class BundledRedstone
return combinedSignal; return combinedSignal;
} }
public static int getOutput( Level world, BlockPos pos, Direction side )
{
int signal = getUnmaskedOutput( world, pos, side );
return signal >= 0 ? signal : 0;
}
} }

View File

@@ -1,330 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.computer.blocks.BlockComputer;
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
import dan200.computercraft.shared.computer.blocks.TileComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import dan200.computercraft.shared.computer.items.ItemComputer;
import dan200.computercraft.shared.media.items.ItemDisk;
import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.media.items.ItemTreasureDisk;
import dan200.computercraft.shared.network.container.ComputerContainerData;
import dan200.computercraft.shared.network.container.ContainerData;
import dan200.computercraft.shared.network.container.HeldItemContainerData;
import dan200.computercraft.shared.network.container.ViewComputerContainerData;
import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive;
import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive;
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
import dan200.computercraft.shared.peripheral.modem.wired.*;
import dan200.computercraft.shared.peripheral.modem.wireless.BlockWirelessModem;
import dan200.computercraft.shared.peripheral.modem.wireless.TileWirelessModem;
import dan200.computercraft.shared.peripheral.monitor.BlockMonitor;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.peripheral.printer.BlockPrinter;
import dan200.computercraft.shared.peripheral.printer.ContainerPrinter;
import dan200.computercraft.shared.peripheral.printer.TilePrinter;
import dan200.computercraft.shared.peripheral.speaker.BlockSpeaker;
import dan200.computercraft.shared.peripheral.speaker.TileSpeaker;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.pocket.peripherals.PocketModem;
import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
import dan200.computercraft.shared.turtle.blocks.BlockTurtle;
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.core.TurtlePlayer;
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
import dan200.computercraft.shared.turtle.items.ItemTurtle;
import dan200.computercraft.shared.turtle.upgrades.*;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry;
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Material;
import java.util.function.BiFunction;
import static net.minecraft.core.Registry.BLOCK_ENTITY_TYPE;
public final class ComputerCraftRegistry
{
public static final String MOD_ID = ComputerCraft.MOD_ID;
public static void init()
{
Object[] o = {
ModTiles.CABLE,
ModBlocks.CABLE,
ModItems.CABLE,
ModEntities.TURTLE_PLAYER,
ModContainers.COMPUTER,
};
TurtleUpgrades.registerTurtleUpgrades();
PocketUpgrades.registerPocketUpgrades();
}
public static final class ModBlocks
{
public static final BlockComputer COMPUTER_NORMAL = register( "computer_normal",
new BlockComputer( properties(), ComputerFamily.NORMAL, ComputerCraftRegistry.ModTiles.COMPUTER_NORMAL ) );
public static final BlockComputer COMPUTER_ADVANCED = register( "computer_advanced",
new BlockComputer( properties(),
ComputerFamily.ADVANCED,
ComputerCraftRegistry.ModTiles.COMPUTER_ADVANCED ) );
public static final BlockComputer COMPUTER_COMMAND = register( "computer_command",
new BlockComputer( FabricBlockSettings.copyOf( Blocks.STONE )
.strength( -1, 6000000.0F ),
ComputerFamily.COMMAND,
ComputerCraftRegistry.ModTiles.COMPUTER_COMMAND ) );
public static final BlockTurtle TURTLE_NORMAL = register( "turtle_normal",
new BlockTurtle( turtleProperties(), ComputerFamily.NORMAL, ComputerCraftRegistry.ModTiles.TURTLE_NORMAL ) );
public static final BlockTurtle TURTLE_ADVANCED = register( "turtle_advanced",
new BlockTurtle( turtleProperties(), ComputerFamily.ADVANCED, ComputerCraftRegistry.ModTiles.TURTLE_ADVANCED ) );
public static final BlockSpeaker SPEAKER = register( "speaker", new BlockSpeaker( properties() ) );
public static final BlockDiskDrive DISK_DRIVE = register( "disk_drive", new BlockDiskDrive( properties() ) );
public static final BlockPrinter PRINTER = register( "printer", new BlockPrinter( properties() ) );
public static final BlockMonitor MONITOR_NORMAL = register( "monitor_normal", new BlockMonitor( properties(), ModTiles.MONITOR_NORMAL, false ) );
public static final BlockMonitor MONITOR_ADVANCED = register( "monitor_advanced", new BlockMonitor( properties(), ModTiles.MONITOR_ADVANCED, true ) );
public static final BlockWirelessModem WIRELESS_MODEM_NORMAL = register( "wireless_modem_normal",
new BlockWirelessModem( properties(), ComputerCraftRegistry.ModTiles.WIRELESS_MODEM_NORMAL, ComputerFamily.NORMAL ) );
public static final BlockWirelessModem WIRELESS_MODEM_ADVANCED = register( "wireless_modem_advanced",
new BlockWirelessModem( properties(), ComputerCraftRegistry.ModTiles.WIRELESS_MODEM_ADVANCED, ComputerFamily.ADVANCED ) );
public static final BlockWiredModemFull WIRED_MODEM_FULL = register( "wired_modem_full",
new BlockWiredModemFull( modemProperties(), ComputerCraftRegistry.ModTiles.WIRED_MODEM_FULL ) );
public static final BlockCable CABLE = register( "cable", new BlockCable( modemProperties() ) );
private static BlockBehaviour.Properties properties()
{
//return FabricBlockSettings.copyOf(Blocks.GLASS)
// .strength(2);
return BlockBehaviour.Properties.of( Material.GLASS )
.strength( 2F )
.sound( SoundType.STONE )
.noOcclusion();
}
private static BlockBehaviour.Properties turtleProperties()
{
return FabricBlockSettings.copyOf( Blocks.STONE )
.strength( 2.5f );
}
private static BlockBehaviour.Properties modemProperties()
{
return FabricBlockSettings.copyOf( Blocks.STONE )
.breakByHand( true )
.breakByTool( FabricToolTags.PICKAXES )
.strength( 1.5f );
}
public static <T extends Block> T register( String id, T value )
{
return Registry.register( Registry.BLOCK, new ResourceLocation( MOD_ID, id ), value );
}
}
public static class ModTiles
{
public static final BlockEntityType<TileMonitor> MONITOR_NORMAL = ofBlock( ModBlocks.MONITOR_NORMAL,
"monitor_normal",
( blockPos, blockState ) -> new TileMonitor( ModTiles.MONITOR_NORMAL, false, blockPos, blockState ) );
public static final BlockEntityType<TileMonitor> MONITOR_ADVANCED = ofBlock( ModBlocks.MONITOR_ADVANCED,
"monitor_advanced",
( blockPos, blockState ) -> new TileMonitor( ModTiles.MONITOR_ADVANCED, true, blockPos, blockState ) );
public static final BlockEntityType<TileComputer> COMPUTER_NORMAL = ofBlock( ModBlocks.COMPUTER_NORMAL,
"computer_normal",
( blockPos, blockState ) -> new TileComputer( ComputerFamily.NORMAL, ModTiles.COMPUTER_NORMAL, blockPos, blockState ) );
public static final BlockEntityType<TileComputer> COMPUTER_ADVANCED = ofBlock( ModBlocks.COMPUTER_ADVANCED,
"computer_advanced",
( blockPos, blockState ) -> new TileComputer( ComputerFamily.ADVANCED, ModTiles.COMPUTER_ADVANCED, blockPos, blockState ) );
public static final BlockEntityType<TileCommandComputer> COMPUTER_COMMAND = ofBlock( ModBlocks.COMPUTER_COMMAND,
"computer_command",
( blockPos, blockState ) -> new TileCommandComputer( ComputerFamily.COMMAND, ModTiles.COMPUTER_COMMAND, blockPos, blockState ) );
public static final BlockEntityType<TileTurtle> TURTLE_NORMAL = ofBlock( ModBlocks.TURTLE_NORMAL,
"turtle_normal",
( blockPos, blockState ) -> new TileTurtle( ModTiles.TURTLE_NORMAL, blockPos, blockState, ComputerFamily.NORMAL ) );
public static final BlockEntityType<TileTurtle> TURTLE_ADVANCED = ofBlock( ModBlocks.TURTLE_ADVANCED,
"turtle_advanced",
( blockPos, blockState ) -> new TileTurtle( ModTiles.TURTLE_ADVANCED, blockPos, blockState, ComputerFamily.ADVANCED ) );
public static final BlockEntityType<TileSpeaker> SPEAKER = ofBlock( ModBlocks.SPEAKER, "speaker",
( blockPos, blockState ) -> new TileSpeaker( ModTiles.SPEAKER, blockPos, blockState ) );
public static final BlockEntityType<TileDiskDrive> DISK_DRIVE = ofBlock( ModBlocks.DISK_DRIVE, "disk_drive",
( blockPos, blockState ) -> new TileDiskDrive( ModTiles.DISK_DRIVE, blockPos, blockState ) );
public static final BlockEntityType<TilePrinter> PRINTER = ofBlock( ModBlocks.PRINTER, "printer",
( blockPos, blockState ) -> new TilePrinter( ModTiles.PRINTER, blockPos, blockState ) );
public static final BlockEntityType<TileWiredModemFull> WIRED_MODEM_FULL = ofBlock( ModBlocks.WIRED_MODEM_FULL,
"wired_modem_full",
( blockPos, blockState ) -> new TileWiredModemFull( ModTiles.WIRED_MODEM_FULL, blockPos, blockState ) );
public static final BlockEntityType<TileCable> CABLE = ofBlock( ModBlocks.CABLE, "cable",
( blockPos, blockState ) -> new TileCable( ModTiles.CABLE, blockPos, blockState ) );
public static final BlockEntityType<TileWirelessModem> WIRELESS_MODEM_NORMAL = ofBlock( ModBlocks.WIRELESS_MODEM_NORMAL,
"wireless_modem_normal",
( blockPos, blockState ) -> new TileWirelessModem( ModTiles.WIRELESS_MODEM_NORMAL, false, blockPos, blockState ) );
public static final BlockEntityType<TileWirelessModem> WIRELESS_MODEM_ADVANCED = ofBlock( ModBlocks.WIRELESS_MODEM_ADVANCED,
"wireless_modem_advanced",
( blockPos, blockState ) -> new TileWirelessModem( ModTiles.WIRELESS_MODEM_ADVANCED, true, blockPos, blockState ) );
private static <T extends BlockEntity> BlockEntityType<T> ofBlock( Block block, String id, BiFunction<BlockPos, BlockState, T> factory )
{
BlockEntityType<T> blockEntityType = FabricBlockEntityTypeBuilder.create( factory::apply, block ).build();
return Registry.register( BLOCK_ENTITY_TYPE,
new ResourceLocation( MOD_ID, id ),
blockEntityType
);
}
}
public static final class ModItems
{
private static final CreativeModeTab mainItemGroup = ComputerCraft.MAIN_GROUP;
public static final ItemComputer COMPUTER_NORMAL = ofBlock( ModBlocks.COMPUTER_NORMAL, ItemComputer::new );
public static final ItemComputer COMPUTER_ADVANCED = ofBlock( ModBlocks.COMPUTER_ADVANCED, ItemComputer::new );
public static final ItemComputer COMPUTER_COMMAND = ofBlock( ModBlocks.COMPUTER_COMMAND, ItemComputer::new );
public static final ItemPocketComputer POCKET_COMPUTER_NORMAL = register( "pocket_computer_normal",
new ItemPocketComputer( properties().stacksTo( 1 ), ComputerFamily.NORMAL ) );
public static final ItemPocketComputer POCKET_COMPUTER_ADVANCED = register( "pocket_computer_advanced",
new ItemPocketComputer( properties().stacksTo( 1 ),
ComputerFamily.ADVANCED ) );
public static final ItemTurtle TURTLE_NORMAL = ofBlock( ModBlocks.TURTLE_NORMAL, ItemTurtle::new );
public static final ItemTurtle TURTLE_ADVANCED = ofBlock( ModBlocks.TURTLE_ADVANCED, ItemTurtle::new );
public static final ItemDisk DISK = register( "disk", new ItemDisk( properties().stacksTo( 1 ) ) );
public static final ItemTreasureDisk TREASURE_DISK = register( "treasure_disk", new ItemTreasureDisk( properties().stacksTo( 1 ) ) );
public static final ItemPrintout PRINTED_PAGE = register( "printed_page", new ItemPrintout( properties().stacksTo( 1 ), ItemPrintout.Type.PAGE ) );
public static final ItemPrintout PRINTED_PAGES = register( "printed_pages", new ItemPrintout( properties().stacksTo( 1 ), ItemPrintout.Type.PAGES ) );
public static final ItemPrintout PRINTED_BOOK = register( "printed_book", new ItemPrintout( properties().stacksTo( 1 ), ItemPrintout.Type.BOOK ) );
public static final BlockItem SPEAKER = ofBlock( ModBlocks.SPEAKER, BlockItem::new );
public static final BlockItem DISK_DRIVE = ofBlock( ModBlocks.DISK_DRIVE, BlockItem::new );
public static final BlockItem PRINTER = ofBlock( ModBlocks.PRINTER, BlockItem::new );
public static final BlockItem MONITOR_NORMAL = ofBlock( ModBlocks.MONITOR_NORMAL, BlockItem::new );
public static final BlockItem MONITOR_ADVANCED = ofBlock( ModBlocks.MONITOR_ADVANCED, BlockItem::new );
public static final BlockItem WIRELESS_MODEM_NORMAL = ofBlock( ModBlocks.WIRELESS_MODEM_NORMAL, BlockItem::new );
public static final BlockItem WIRELESS_MODEM_ADVANCED = ofBlock( ModBlocks.WIRELESS_MODEM_ADVANCED, BlockItem::new );
public static final BlockItem WIRED_MODEM_FULL = ofBlock( ModBlocks.WIRED_MODEM_FULL, BlockItem::new );
public static final ItemBlockCable.Cable CABLE = register( "cable", new ItemBlockCable.Cable( ModBlocks.CABLE, properties() ) );
public static final ItemBlockCable.WiredModem WIRED_MODEM = register( "wired_modem", new ItemBlockCable.WiredModem( ModBlocks.CABLE, properties() ) );
private static <B extends Block, I extends Item> I ofBlock( B parent, BiFunction<B, Item.Properties, I> supplier )
{
return Registry.register( Registry.ITEM, Registry.BLOCK.getKey( parent ), supplier.apply( parent, properties() ) );
}
private static Item.Properties properties()
{
return new Item.Properties().tab( mainItemGroup );
}
private static <T extends Item> T register( String id, T item )
{
return Registry.register( Registry.ITEM, new ResourceLocation( MOD_ID, id ), item );
}
}
public static class ModEntities
{
public static final EntityType<TurtlePlayer> TURTLE_PLAYER = Registry.register( Registry.ENTITY_TYPE,
new ResourceLocation( MOD_ID, "turtle_player" ),
EntityType.Builder.<TurtlePlayer>createNothing( MobCategory.MISC ).noSave()
.noSummon()
.sized(
0,
0 )
.build(
ComputerCraft.MOD_ID + ":turtle_player" ) );
}
public static class ModContainers
{
public static final MenuType<ContainerComputerBase> COMPUTER = ContainerData.toType( new ResourceLocation( MOD_ID, "computer" ), ModContainers.COMPUTER, ComputerContainerData::new, ComputerMenuWithoutInventory::new );
public static final MenuType<ContainerComputerBase> POCKET_COMPUTER = ContainerData.toType( new ResourceLocation( MOD_ID, "pocket_computer" ), ModContainers.POCKET_COMPUTER, ComputerContainerData::new, ComputerMenuWithoutInventory::new );
public static final MenuType<ContainerComputerBase> POCKET_COMPUTER_NO_TERM = ContainerData.toType( new ResourceLocation( MOD_ID, "pocket_computer_no_term" ), ModContainers.POCKET_COMPUTER_NO_TERM, ComputerContainerData::new, ComputerMenuWithoutInventory::new );
public static final MenuType<ContainerTurtle> TURTLE = ContainerData.toType( new ResourceLocation( MOD_ID, "turtle" ), ComputerContainerData::new, ContainerTurtle::new );
public static final MenuType<ContainerDiskDrive> DISK_DRIVE = registerSimple( "disk_drive", ContainerDiskDrive::new );
public static final MenuType<ContainerPrinter> PRINTER = registerSimple( "printer", ContainerPrinter::new );
public static final MenuType<ContainerHeldItem> PRINTOUT = ContainerData.toType( new ResourceLocation( MOD_ID, "printout" ), HeldItemContainerData::new, ContainerHeldItem::createPrintout );
public static final MenuType<ContainerViewComputer> VIEW_COMPUTER = ContainerData.toType( new ResourceLocation( MOD_ID, "view_computer" ), ViewComputerContainerData::new, ContainerViewComputer::new );
private static <T extends AbstractContainerMenu> MenuType<T> registerSimple( String id,
ScreenHandlerRegistry.SimpleClientHandlerFactory<T> function )
{
return ScreenHandlerRegistry.registerSimple( new ResourceLocation( MOD_ID, id ), function );
}
}
public static final class TurtleUpgrades
{
public static TurtleModem wirelessModemNormal = new TurtleModem( false, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ) );
public static TurtleModem wirelessModemAdvanced = new TurtleModem( true, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ) );
public static TurtleSpeaker speaker = new TurtleSpeaker( new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ) );
public static TurtleCraftingTable craftingTable = new TurtleCraftingTable( new ResourceLocation( "minecraft", "crafting_table" ) );
public static TurtleSword diamondSword = new TurtleSword( new ResourceLocation( "minecraft", "diamond_sword" ), Items.DIAMOND_SWORD );
public static TurtleShovel diamondShovel = new TurtleShovel( new ResourceLocation( "minecraft", "diamond_shovel" ), Items.DIAMOND_SHOVEL );
public static TurtleTool diamondPickaxe = new TurtleTool( new ResourceLocation( "minecraft", "diamond_pickaxe" ), Items.DIAMOND_PICKAXE );
public static TurtleAxe diamondAxe = new TurtleAxe( new ResourceLocation( "minecraft", "diamond_axe" ), Items.DIAMOND_AXE );
public static TurtleHoe diamondHoe = new TurtleHoe( new ResourceLocation( "minecraft", "diamond_hoe" ), Items.DIAMOND_HOE );
public static TurtleTool netheritePickaxe = new TurtleTool( new ResourceLocation( "minecraft", "netherite_pickaxe" ), Items.NETHERITE_PICKAXE );
public static void registerTurtleUpgrades()
{
ComputerCraftAPI.registerTurtleUpgrade( wirelessModemNormal );
ComputerCraftAPI.registerTurtleUpgrade( wirelessModemAdvanced );
ComputerCraftAPI.registerTurtleUpgrade( speaker );
ComputerCraftAPI.registerTurtleUpgrade( craftingTable );
ComputerCraftAPI.registerTurtleUpgrade( diamondSword );
ComputerCraftAPI.registerTurtleUpgrade( diamondShovel );
ComputerCraftAPI.registerTurtleUpgrade( diamondPickaxe );
ComputerCraftAPI.registerTurtleUpgrade( diamondAxe );
ComputerCraftAPI.registerTurtleUpgrade( diamondHoe );
ComputerCraftAPI.registerTurtleUpgrade( netheritePickaxe );
}
}
public static final class PocketUpgrades
{
public static PocketModem wirelessModemNormal = new PocketModem( false );
public static PocketModem wirelessModemAdvanced = new PocketModem( true );
public static PocketSpeaker speaker = new PocketSpeaker();
public static void registerPocketUpgrades()
{
ComputerCraftAPI.registerPocketUpgrade( wirelessModemNormal );
ComputerCraftAPI.registerPocketUpgrade( wirelessModemAdvanced );
ComputerCraftAPI.registerPocketUpgrade( speaker );
}
}
}

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared; package dan200.computercraft.shared;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
@@ -30,10 +29,7 @@ public final class MediaProviders
public static IMedia get( @Nonnull ItemStack stack ) public static IMedia get( @Nonnull ItemStack stack )
{ {
if( stack.isEmpty() ) if( stack.isEmpty() ) return null;
{
return null;
}
// Try the handlers in order: // Try the handlers in order:
for( IMediaProvider mediaProvider : providers ) for( IMediaProvider mediaProvider : providers )
@@ -41,10 +37,7 @@ public final class MediaProviders
try try
{ {
IMedia media = mediaProvider.getMedia( stack ); IMedia media = mediaProvider.getMedia( stack );
if( media != null ) if( media != null ) return media;
{
return media;
}
} }
catch( Exception e ) catch( Exception e )
{ {

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared; package dan200.computercraft.shared;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
@@ -47,10 +46,7 @@ public final class Peripherals
try try
{ {
IPeripheral peripheral = peripheralProvider.getPeripheral( world, pos, side ); IPeripheral peripheral = peripheralProvider.getPeripheral( world, pos, side );
if( peripheral != null ) if( peripheral != null ) return peripheral;
{
return peripheral;
}
} }
catch( Exception e ) catch( Exception e )
{ {

View File

@@ -15,6 +15,7 @@ import net.minecraft.world.item.ItemStack;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.*; import java.util.*;
import java.util.stream.Stream;
public final class PocketUpgrades public final class PocketUpgrades
{ {
@@ -72,17 +73,18 @@ public final class PocketUpgrades
return upgradeOwners.get( upgrade ); return upgradeOwners.get( upgrade );
} }
public static Iterable<IPocketUpgrade> getVanillaUpgrades()
{
List<IPocketUpgrade> vanilla = new ArrayList<>();
vanilla.add( ComputerCraftRegistry.PocketUpgrades.wirelessModemNormal );
vanilla.add( ComputerCraftRegistry.PocketUpgrades.wirelessModemAdvanced );
vanilla.add( ComputerCraftRegistry.PocketUpgrades.speaker );
return vanilla;
}
public static Iterable<IPocketUpgrade> getUpgrades() public static Iterable<IPocketUpgrade> getUpgrades()
{ {
return Collections.unmodifiableCollection( upgrades.values() ); return Collections.unmodifiableCollection( upgrades.values() );
} }
public static Stream<IPocketUpgrade> getVanillaUpgrades()
{
List<IPocketUpgrade> vanilla = Arrays.asList(
Registry.PocketUpgrades.wirelessModemNormal,
Registry.PocketUpgrades.wirelessModemAdvanced,
Registry.PocketUpgrades.speaker
);
return vanilla.stream();
}
} }

View File

@@ -0,0 +1,393 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.computer.blocks.BlockComputer;
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
import dan200.computercraft.shared.computer.blocks.TileComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import dan200.computercraft.shared.computer.items.ItemComputer;
import dan200.computercraft.shared.media.items.ItemDisk;
import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.media.items.ItemTreasureDisk;
import dan200.computercraft.shared.network.container.ComputerContainerData;
import dan200.computercraft.shared.network.container.ContainerData;
import dan200.computercraft.shared.network.container.HeldItemContainerData;
import dan200.computercraft.shared.network.container.ViewComputerContainerData;
import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive;
import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive;
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
import dan200.computercraft.shared.peripheral.modem.wired.*;
import dan200.computercraft.shared.peripheral.modem.wireless.BlockWirelessModem;
import dan200.computercraft.shared.peripheral.modem.wireless.TileWirelessModem;
import dan200.computercraft.shared.peripheral.monitor.BlockMonitor;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.peripheral.printer.BlockPrinter;
import dan200.computercraft.shared.peripheral.printer.ContainerPrinter;
import dan200.computercraft.shared.peripheral.printer.TilePrinter;
import dan200.computercraft.shared.peripheral.speaker.BlockSpeaker;
import dan200.computercraft.shared.peripheral.speaker.TileSpeaker;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.pocket.peripherals.PocketModem;
import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
import dan200.computercraft.shared.turtle.blocks.BlockTurtle;
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.core.TurtlePlayer;
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
import dan200.computercraft.shared.turtle.items.ItemTurtle;
import dan200.computercraft.shared.turtle.upgrades.*;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry;
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
import net.minecraft.core.BlockPos;
import net.minecraft.core.cauldron.CauldronInteraction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.item.*;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Material;
import java.util.function.BiFunction;
import static net.minecraft.core.Registry.BLOCK_ENTITY_TYPE;
public final class Registry
{
public static final String MOD_ID = ComputerCraft.MOD_ID;
public static void init()
{
TurtleUpgrades.registerTurtleUpgrades();
PocketUpgrades.registerPocketUpgrades();
CauldronInteraction.WATER.put( ModItems.TURTLE_NORMAL, ItemTurtle.CAULDRON_INTERACTION );
CauldronInteraction.WATER.put( ModItems.TURTLE_ADVANCED, ItemTurtle.CAULDRON_INTERACTION );
}
public static final class ModBlocks
{
public static <T extends Block> T register( String id, T value )
{
return net.minecraft.core.Registry.register( net.minecraft.core.Registry.BLOCK, new ResourceLocation( MOD_ID, id ), value );
}
public static final BlockMonitor MONITOR_NORMAL =
register( "monitor_normal", new BlockMonitor( properties(), () -> ModBlockEntities.MONITOR_NORMAL ) );
public static final BlockMonitor MONITOR_ADVANCED =
register( "monitor_advanced", new BlockMonitor( properties(), () -> ModBlockEntities.MONITOR_ADVANCED ) );
public static final BlockComputer COMPUTER_NORMAL =
register( "computer_normal", new BlockComputer( properties(), ComputerFamily.NORMAL, () -> ModBlockEntities.COMPUTER_NORMAL ) );
public static final BlockComputer COMPUTER_ADVANCED =
register( "computer_advanced", new BlockComputer( properties(), ComputerFamily.ADVANCED, () -> ModBlockEntities.COMPUTER_ADVANCED ) );
public static final BlockComputer COMPUTER_COMMAND =
register( "computer_command", new BlockComputer( FabricBlockSettings.copyOf( Blocks.STONE ).strength( -1, 6000000.0F ), ComputerFamily.COMMAND, () -> ModBlockEntities.COMPUTER_COMMAND ) );
public static final BlockTurtle TURTLE_NORMAL =
register( "turtle_normal", new BlockTurtle( turtleProperties(), ComputerFamily.NORMAL, () -> ModBlockEntities.TURTLE_NORMAL ) );
public static final BlockTurtle TURTLE_ADVANCED =
register( "turtle_advanced", new BlockTurtle( turtleProperties(), ComputerFamily.ADVANCED, () -> ModBlockEntities.TURTLE_ADVANCED ) );
public static final BlockSpeaker SPEAKER =
register( "speaker", new BlockSpeaker( properties() ) );
public static final BlockDiskDrive DISK_DRIVE =
register( "disk_drive", new BlockDiskDrive( properties() ) );
public static final BlockPrinter PRINTER =
register( "printer", new BlockPrinter( properties() ) );
public static final BlockWirelessModem WIRELESS_MODEM_NORMAL =
register( "wireless_modem_normal", new BlockWirelessModem( properties(), () -> ModBlockEntities.WIRELESS_MODEM_NORMAL ) );
public static final BlockWirelessModem WIRELESS_MODEM_ADVANCED =
register( "wireless_modem_advanced", new BlockWirelessModem( properties(), () -> ModBlockEntities.WIRELESS_MODEM_ADVANCED ) );
public static final BlockWiredModemFull WIRED_MODEM_FULL =
register( "wired_modem_full", new BlockWiredModemFull( modemProperties() ) );
public static final BlockCable CABLE =
register( "cable", new BlockCable( modemProperties() ) );
private static BlockBehaviour.Properties properties()
{
return BlockBehaviour.Properties.of( Material.GLASS ).strength( 2F ).sound( SoundType.STONE ).noOcclusion();
}
private static BlockBehaviour.Properties turtleProperties()
{
return FabricBlockSettings.copyOf( Blocks.STONE ).strength( 2.5f );
}
private static BlockBehaviour.Properties modemProperties()
{
return FabricBlockSettings.copyOf( Blocks.STONE ).breakByHand( true ).breakByTool( FabricToolTags.PICKAXES ).strength( 1.5f );
}
}
public static class ModBlockEntities
{
private static <T extends BlockEntity> BlockEntityType<T> ofBlock( Block block, String id, BiFunction<BlockPos, BlockState, T> factory )
{
BlockEntityType<T> blockEntityType = FabricBlockEntityTypeBuilder.create( factory::apply, block ).build();
return net.minecraft.core.Registry.register( BLOCK_ENTITY_TYPE, new ResourceLocation( MOD_ID, id ), blockEntityType );
}
public static final BlockEntityType<TileMonitor> MONITOR_NORMAL =
ofBlock( ModBlocks.MONITOR_NORMAL, "monitor_normal", ( blockPos, blockState ) -> new TileMonitor( ModBlockEntities.MONITOR_NORMAL, blockPos, blockState, false ) );
public static final BlockEntityType<TileMonitor> MONITOR_ADVANCED =
ofBlock( ModBlocks.MONITOR_ADVANCED, "monitor_advanced", ( blockPos, blockState ) -> new TileMonitor( ModBlockEntities.MONITOR_ADVANCED, blockPos, blockState, true ) );
public static final BlockEntityType<TileComputer> COMPUTER_NORMAL =
ofBlock( ModBlocks.COMPUTER_NORMAL, "computer_normal", ( blockPos, blockState ) -> new TileComputer( ModBlockEntities.COMPUTER_NORMAL, blockPos, blockState, ComputerFamily.NORMAL ) );
public static final BlockEntityType<TileComputer> COMPUTER_ADVANCED =
ofBlock( ModBlocks.COMPUTER_ADVANCED, "computer_advanced", ( blockPos, blockState ) -> new TileComputer( ModBlockEntities.COMPUTER_ADVANCED, blockPos, blockState, ComputerFamily.ADVANCED ) );
public static final BlockEntityType<TileCommandComputer> COMPUTER_COMMAND =
ofBlock( ModBlocks.COMPUTER_COMMAND, "computer_command", ( blockPos, blockState ) -> new TileCommandComputer( ModBlockEntities.COMPUTER_COMMAND, blockPos, blockState ) );
public static final BlockEntityType<TileTurtle> TURTLE_NORMAL =
ofBlock( ModBlocks.TURTLE_NORMAL, "turtle_normal", ( blockPos, blockState ) -> new TileTurtle( ModBlockEntities.TURTLE_NORMAL, blockPos, blockState, ComputerFamily.NORMAL ) );
public static final BlockEntityType<TileTurtle> TURTLE_ADVANCED =
ofBlock( ModBlocks.TURTLE_ADVANCED, "turtle_advanced", ( blockPos, blockState ) -> new TileTurtle( ModBlockEntities.TURTLE_ADVANCED, blockPos, blockState, ComputerFamily.ADVANCED ) );
public static final BlockEntityType<TileSpeaker> SPEAKER =
ofBlock( ModBlocks.SPEAKER, "speaker", ( blockPos, blockState ) -> new TileSpeaker( ModBlockEntities.SPEAKER, blockPos, blockState ) );
public static final BlockEntityType<TileDiskDrive> DISK_DRIVE =
ofBlock( ModBlocks.DISK_DRIVE, "disk_drive", ( blockPos, blockState ) -> new TileDiskDrive( ModBlockEntities.DISK_DRIVE, blockPos, blockState ) );
public static final BlockEntityType<TilePrinter> PRINTER =
ofBlock( ModBlocks.PRINTER, "printer", ( blockPos, blockState ) -> new TilePrinter( ModBlockEntities.PRINTER, blockPos, blockState ) );
public static final BlockEntityType<TileWiredModemFull> WIRED_MODEM_FULL =
ofBlock( ModBlocks.WIRED_MODEM_FULL, "wired_modem_full", ( blockPos, blockState ) -> new TileWiredModemFull( ModBlockEntities.WIRED_MODEM_FULL, blockPos, blockState ) );
public static final BlockEntityType<TileCable> CABLE =
ofBlock( ModBlocks.CABLE, "cable", ( blockPos, blockState ) -> new TileCable( ModBlockEntities.CABLE, blockPos, blockState ) );
public static final BlockEntityType<TileWirelessModem> WIRELESS_MODEM_NORMAL =
ofBlock( ModBlocks.WIRELESS_MODEM_NORMAL, "wireless_modem_normal", ( blockPos, blockState ) -> new TileWirelessModem( ModBlockEntities.WIRELESS_MODEM_NORMAL, blockPos, blockState, false ) );
public static final BlockEntityType<TileWirelessModem> WIRELESS_MODEM_ADVANCED =
ofBlock( ModBlocks.WIRELESS_MODEM_ADVANCED, "wireless_modem_advanced", ( blockPos, blockState ) -> new TileWirelessModem( ModBlockEntities.WIRELESS_MODEM_ADVANCED, blockPos, blockState, true ) );
}
public static final class ModItems
{
private static final CreativeModeTab mainItemGroup = ComputerCraft.MAIN_GROUP;
public static final ItemComputer COMPUTER_NORMAL =
ofBlock( ModBlocks.COMPUTER_NORMAL, ItemComputer::new );
public static final ItemComputer COMPUTER_ADVANCED =
ofBlock( ModBlocks.COMPUTER_ADVANCED, ItemComputer::new );
public static final ItemComputer COMPUTER_COMMAND =
ofBlock( ModBlocks.COMPUTER_COMMAND, ItemComputer::new );
public static final ItemPocketComputer POCKET_COMPUTER_NORMAL =
register( "pocket_computer_normal", new ItemPocketComputer( properties().stacksTo( 1 ), ComputerFamily.NORMAL ) );
public static final ItemPocketComputer POCKET_COMPUTER_ADVANCED =
register( "pocket_computer_advanced", new ItemPocketComputer( properties().stacksTo( 1 ), ComputerFamily.ADVANCED ) );
public static final ItemTurtle TURTLE_NORMAL =
ofBlock( ModBlocks.TURTLE_NORMAL, ItemTurtle::new );
public static final ItemTurtle TURTLE_ADVANCED =
ofBlock( ModBlocks.TURTLE_ADVANCED, ItemTurtle::new );
public static final ItemDisk DISK =
register( "disk", new ItemDisk( properties().stacksTo( 1 ) ) );
public static final ItemTreasureDisk TREASURE_DISK =
register( "treasure_disk", new ItemTreasureDisk( properties().stacksTo( 1 ) ) );
public static final ItemPrintout PRINTED_PAGE =
register( "printed_page", new ItemPrintout( properties().stacksTo( 1 ), ItemPrintout.Type.PAGE ) );
public static final ItemPrintout PRINTED_PAGES =
register( "printed_pages", new ItemPrintout( properties().stacksTo( 1 ), ItemPrintout.Type.PAGES ) );
public static final ItemPrintout PRINTED_BOOK =
register( "printed_book", new ItemPrintout( properties().stacksTo( 1 ), ItemPrintout.Type.BOOK ) );
public static final BlockItem SPEAKER =
ofBlock( ModBlocks.SPEAKER, BlockItem::new );
public static final BlockItem DISK_DRIVE =
ofBlock( ModBlocks.DISK_DRIVE, BlockItem::new );
public static final BlockItem PRINTER =
ofBlock( ModBlocks.PRINTER, BlockItem::new );
public static final BlockItem MONITOR_NORMAL =
ofBlock( ModBlocks.MONITOR_NORMAL, BlockItem::new );
public static final BlockItem MONITOR_ADVANCED =
ofBlock( ModBlocks.MONITOR_ADVANCED, BlockItem::new );
public static final BlockItem WIRELESS_MODEM_NORMAL =
ofBlock( ModBlocks.WIRELESS_MODEM_NORMAL, BlockItem::new );
public static final BlockItem WIRELESS_MODEM_ADVANCED =
ofBlock( ModBlocks.WIRELESS_MODEM_ADVANCED, BlockItem::new );
public static final BlockItem WIRED_MODEM_FULL =
ofBlock( ModBlocks.WIRED_MODEM_FULL, BlockItem::new );
public static final ItemBlockCable.Cable CABLE =
register( "cable", new ItemBlockCable.Cable( ModBlocks.CABLE, properties() ) );
public static final ItemBlockCable.WiredModem WIRED_MODEM =
register( "wired_modem", new ItemBlockCable.WiredModem( ModBlocks.CABLE, properties() ) );
private static <B extends Block, I extends Item> I ofBlock( B parent, BiFunction<B, Item.Properties, I> supplier )
{
return net.minecraft.core.Registry.register( net.minecraft.core.Registry.ITEM, net.minecraft.core.Registry.BLOCK.getKey( parent ), supplier.apply( parent, properties() ) );
}
private static Item.Properties properties()
{
return new Item.Properties().tab( mainItemGroup );
}
private static <T extends Item> T register( String id, T item )
{
return net.minecraft.core.Registry.register( net.minecraft.core.Registry.ITEM, new ResourceLocation( MOD_ID, id ), item );
}
}
public static class ModEntities
{
public static final EntityType<TurtlePlayer> TURTLE_PLAYER =
net.minecraft.core.Registry.register( net.minecraft.core.Registry.ENTITY_TYPE, new ResourceLocation( MOD_ID, "turtle_player" ),
EntityType.Builder.<TurtlePlayer>createNothing( MobCategory.MISC ).noSave().noSummon().sized( 0, 0 ).build( ComputerCraft.MOD_ID + ":turtle_player" ) );
}
public static class ModContainers
{
public static final MenuType<ContainerComputerBase> COMPUTER =
ContainerData.toType( new ResourceLocation( MOD_ID, "computer" ), ModContainers.COMPUTER, ComputerContainerData::new, ComputerMenuWithoutInventory::new );
public static final MenuType<ContainerComputerBase> POCKET_COMPUTER =
ContainerData.toType( new ResourceLocation( MOD_ID, "pocket_computer" ), ModContainers.POCKET_COMPUTER, ComputerContainerData::new, ComputerMenuWithoutInventory::new );
public static final MenuType<ContainerComputerBase> POCKET_COMPUTER_NO_TERM =
ContainerData.toType( new ResourceLocation( MOD_ID, "pocket_computer_no_term" ), ModContainers.POCKET_COMPUTER_NO_TERM, ComputerContainerData::new, ComputerMenuWithoutInventory::new );
public static final MenuType<ContainerTurtle> TURTLE =
ContainerData.toType( new ResourceLocation( MOD_ID, "turtle" ), ComputerContainerData::new, ContainerTurtle::new );
public static final MenuType<ContainerDiskDrive> DISK_DRIVE =
registerSimple( "disk_drive", ContainerDiskDrive::new );
public static final MenuType<ContainerPrinter> PRINTER =
registerSimple( "printer", ContainerPrinter::new );
public static final MenuType<ContainerHeldItem> PRINTOUT =
ContainerData.toType( new ResourceLocation( MOD_ID, "printout" ), HeldItemContainerData::new, ContainerHeldItem::createPrintout );
public static final MenuType<ContainerViewComputer> VIEW_COMPUTER =
ContainerData.toType( new ResourceLocation( MOD_ID, "view_computer" ), ViewComputerContainerData::new, ContainerViewComputer::new );
private static <T extends AbstractContainerMenu> MenuType<T> registerSimple( String id, ScreenHandlerRegistry.SimpleClientHandlerFactory<T> function )
{
return ScreenHandlerRegistry.registerSimple( new ResourceLocation( MOD_ID, id ), function );
}
}
public static final class TurtleUpgrades
{
public static TurtleModem wirelessModemNormal =
new TurtleModem( new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ), new ItemStack( ModItems.WIRELESS_MODEM_NORMAL ), false );
public static TurtleModem wirelessModemAdvanced =
new TurtleModem( new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ), new ItemStack( ModItems.WIRELESS_MODEM_ADVANCED ), true );
public static TurtleSpeaker speaker =
new TurtleSpeaker( new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ), new ItemStack( ModItems.SPEAKER ) );
public static TurtleCraftingTable craftingTable =
new TurtleCraftingTable( new ResourceLocation( "minecraft", "crafting_table" ), new ItemStack( Items.CRAFTING_TABLE ) );
public static TurtleSword diamondSword =
new TurtleSword( new ResourceLocation( "minecraft", "diamond_sword" ), Items.DIAMOND_SWORD, 9.0f );
public static TurtleShovel diamondShovel =
new TurtleShovel( new ResourceLocation( "minecraft", "diamond_shovel" ), Items.DIAMOND_SHOVEL, 1.0f );
public static TurtleTool diamondPickaxe =
new TurtleTool( new ResourceLocation( "minecraft", "diamond_pickaxe" ), Items.DIAMOND_PICKAXE, 1.0f );
public static TurtleAxe diamondAxe =
new TurtleAxe( new ResourceLocation( "minecraft", "diamond_axe" ), Items.DIAMOND_AXE, 6.0f );
public static TurtleHoe diamondHoe =
new TurtleHoe( new ResourceLocation( "minecraft", "diamond_hoe" ), Items.DIAMOND_HOE, 1.0f );
public static TurtleTool netheritePickaxe =
new TurtleTool( new ResourceLocation( "minecraft", "netherite_pickaxe" ), Items.NETHERITE_PICKAXE, 1.0f );
public static void registerTurtleUpgrades()
{
ComputerCraftAPI.registerTurtleUpgrade( wirelessModemNormal );
ComputerCraftAPI.registerTurtleUpgrade( wirelessModemAdvanced );
ComputerCraftAPI.registerTurtleUpgrade( speaker );
ComputerCraftAPI.registerTurtleUpgrade( craftingTable );
ComputerCraftAPI.registerTurtleUpgrade( diamondSword );
ComputerCraftAPI.registerTurtleUpgrade( diamondShovel );
ComputerCraftAPI.registerTurtleUpgrade( diamondPickaxe );
ComputerCraftAPI.registerTurtleUpgrade( diamondAxe );
ComputerCraftAPI.registerTurtleUpgrade( diamondHoe );
ComputerCraftAPI.registerTurtleUpgrade( netheritePickaxe );
}
}
public static final class PocketUpgrades
{
public static PocketModem wirelessModemNormal = new PocketModem( new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ), new ItemStack( ModItems.WIRELESS_MODEM_NORMAL ), false );
public static PocketModem wirelessModemAdvanced = new PocketModem( new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ), new ItemStack( ModItems.WIRELESS_MODEM_ADVANCED ), true );
public static PocketSpeaker speaker = new PocketSpeaker( new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ), new ItemStack( ModItems.SPEAKER ) );
public static void registerPocketUpgrades()
{
ComputerCraftAPI.registerPocketUpgrade( wirelessModemNormal );
ComputerCraftAPI.registerPocketUpgrade( wirelessModemAdvanced );
ComputerCraftAPI.registerPocketUpgrade( speaker );
}
}
}

View File

@@ -98,17 +98,17 @@ public final class TurtleUpgrades
{ {
vanilla = new ITurtleUpgrade[] { vanilla = new ITurtleUpgrade[] {
// ComputerCraft upgrades // ComputerCraft upgrades
ComputerCraftRegistry.TurtleUpgrades.wirelessModemNormal, Registry.TurtleUpgrades.wirelessModemNormal,
ComputerCraftRegistry.TurtleUpgrades.wirelessModemAdvanced, Registry.TurtleUpgrades.wirelessModemAdvanced,
ComputerCraftRegistry.TurtleUpgrades.speaker, Registry.TurtleUpgrades.speaker,
// Vanilla Minecraft upgrades // Vanilla Minecraft upgrades
ComputerCraftRegistry.TurtleUpgrades.diamondPickaxe, Registry.TurtleUpgrades.diamondPickaxe,
ComputerCraftRegistry.TurtleUpgrades.diamondAxe, Registry.TurtleUpgrades.diamondAxe,
ComputerCraftRegistry.TurtleUpgrades.diamondSword, Registry.TurtleUpgrades.diamondSword,
ComputerCraftRegistry.TurtleUpgrades.diamondShovel, Registry.TurtleUpgrades.diamondShovel,
ComputerCraftRegistry.TurtleUpgrades.diamondHoe, Registry.TurtleUpgrades.diamondHoe,
ComputerCraftRegistry.TurtleUpgrades.craftingTable, Registry.TurtleUpgrades.craftingTable,
}; };
} }

View File

@@ -6,7 +6,9 @@
package dan200.computercraft.shared.command; package dan200.computercraft.shared.command;
import dan200.computercraft.shared.util.IDAssigner; import dan200.computercraft.shared.util.IDAssigner;
import me.shedaniel.cloth.api.utils.v1.GameInstanceUtils;
import net.minecraft.Util; import net.minecraft.Util;
import net.minecraft.server.MinecraftServer;
import java.io.File; import java.io.File;
@@ -28,6 +30,9 @@ public final class ClientCommands
// Emulate the command on the client side // Emulate the command on the client side
if( message.startsWith( OPEN_COMPUTER ) ) if( message.startsWith( OPEN_COMPUTER ) )
{ {
MinecraftServer server = GameInstanceUtils.getServer();
if( server == null || server.isDedicatedServer() ) return false;
String idStr = message.substring( OPEN_COMPUTER.length() ).trim(); String idStr = message.substring( OPEN_COMPUTER.length() ).trim();
int id; int id;
try try
@@ -36,7 +41,7 @@ public final class ClientCommands
} }
catch( NumberFormatException ignore ) catch( NumberFormatException ignore )
{ {
return true; return false;
} }
File file = new File( IDAssigner.getDir(), "computer/" + id ); File file = new File( IDAssigner.getDir(), "computer/" + id );

View File

@@ -26,6 +26,7 @@ import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.TranslatableComponent;
@@ -82,15 +83,15 @@ public final class CommandComputerCraft
BlockPos pos = new BlockPos( source.getPosition() ); BlockPos pos = new BlockPos( source.getPosition() );
computers.sort( ( a, b ) -> { computers.sort( ( a, b ) -> {
if( a.getWorld() == b.getWorld() && a.getWorld() == world ) if( a.getLevel() == b.getLevel() && a.getLevel() == world )
{ {
return Double.compare( a.getPosition().distSqr( pos ), b.getPosition().distSqr( pos ) ); return Double.compare( a.getPosition().distSqr( pos ), b.getPosition().distSqr( pos ) );
} }
else if( a.getWorld() == world ) else if( a.getLevel() == world )
{ {
return -1; return -1;
} }
else if( b.getWorld() == world ) else if( b.getLevel() == world )
{ {
return 1; return 1;
} }
@@ -171,15 +172,14 @@ public final class CommandComputerCraft
.arg( "computer", oneComputer() ) .arg( "computer", oneComputer() )
.executes( context -> { .executes( context -> {
ServerComputer computer = getComputerArgument( context, "computer" ); ServerComputer computer = getComputerArgument( context, "computer" );
Level world = computer.getWorld(); Level world = computer.getLevel();
BlockPos pos = computer.getPosition(); BlockPos pos = computer.getPosition();
if( world == null || pos == null ) throw TP_NOT_THERE.create(); if( world == null || pos == null ) throw TP_NOT_THERE.create();
Entity entity = context.getSource().getEntityOrException(); Entity entity = context.getSource().getEntityOrException();
if( !(entity instanceof ServerPlayer) ) throw TP_NOT_PLAYER.create(); if( !(entity instanceof ServerPlayer player) ) throw TP_NOT_PLAYER.create();
ServerPlayer player = (ServerPlayer) entity;
if( player.getCommandSenderWorld() == world ) if( player.getCommandSenderWorld() == world )
{ {
player.connection.teleport( player.connection.teleport(
@@ -236,7 +236,7 @@ public final class CommandComputerCraft
@Nonnull @Nonnull
@Override @Override
public MutableComponent getDisplayName() public Component getDisplayName()
{ {
return new TranslatableComponent( "gui.computercraft.view_computer" ); return new TranslatableComponent( "gui.computercraft.view_computer" );
} }
@@ -292,7 +292,7 @@ public final class CommandComputerCraft
); );
} }
private static MutableComponent linkComputer( CommandSourceStack source, ServerComputer serverComputer, int computerId ) private static Component linkComputer( CommandSourceStack source, ServerComputer serverComputer, int computerId )
{ {
MutableComponent out = new TextComponent( "" ); MutableComponent out = new TextComponent( "" );
@@ -333,14 +333,14 @@ public final class CommandComputerCraft
if( UserLevel.OWNER.test( source ) && isPlayer( source ) ) if( UserLevel.OWNER.test( source ) && isPlayer( source ) )
{ {
MutableComponent linkPath = linkStorage( computerId ); Component linkPath = linkStorage( computerId );
if( linkPath != null ) out.append( " " ).append( linkPath ); if( linkPath != null ) out.append( " " ).append( linkPath );
} }
return out; return out;
} }
private static MutableComponent linkPosition( CommandSourceStack context, ServerComputer computer ) private static Component linkPosition( CommandSourceStack context, ServerComputer computer )
{ {
if( UserLevel.OP.test( context ) ) if( UserLevel.OP.test( context ) )
{ {
@@ -356,7 +356,7 @@ public final class CommandComputerCraft
} }
} }
private static MutableComponent linkStorage( int id ) private static Component linkStorage( int id )
{ {
File file = new File( IDAssigner.getDir(), "computer/" + id ); File file = new File( IDAssigner.getDir(), "computer/" + id );
if( !file.isDirectory() ) return null; if( !file.isDirectory() ) return null;
@@ -398,7 +398,7 @@ public final class CommandComputerCraft
timings.sort( Comparator.<ComputerTracker, Long>comparing( x -> x.get( sortField ) ).reversed() ); timings.sort( Comparator.<ComputerTracker, Long>comparing( x -> x.get( sortField ) ).reversed() );
MutableComponent[] headers = new MutableComponent[1 + fields.size()]; Component[] headers = new Component[1 + fields.size()];
headers[0] = translate( "commands.computercraft.track.dump.computer" ); headers[0] = translate( "commands.computercraft.track.dump.computer" );
for( int i = 0; i < fields.size(); i++ ) headers[i + 1] = translate( fields.get( i ).translationKey() ); for( int i = 0; i < fields.size(); i++ ) headers[i + 1] = translate( fields.get( i ).translationKey() );
TableBuilder table = new TableBuilder( TRACK_ID, headers ); TableBuilder table = new TableBuilder( TRACK_ID, headers );
@@ -408,9 +408,9 @@ public final class CommandComputerCraft
Computer computer = entry.getComputer(); Computer computer = entry.getComputer();
ServerComputer serverComputer = computer == null ? null : lookup.get( computer ); ServerComputer serverComputer = computer == null ? null : lookup.get( computer );
MutableComponent computerComponent = linkComputer( source, serverComputer, entry.getComputerId() ); Component computerComponent = linkComputer( source, serverComputer, entry.getComputerId() );
MutableComponent[] row = new MutableComponent[1 + fields.size()]; Component[] row = new Component[1 + fields.size()];
row[0] = computerComponent; row[0] = computerComponent;
for( int i = 0; i < fields.size(); i++ ) row[i + 1] = text( entry.getFormatted( fields.get( i ) ) ); for( int i = 0; i < fields.size(); i++ ) row[i + 1] = text( entry.getFormatted( fields.get( i ) ) );
table.row( row ); table.row( row );

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.command; package dan200.computercraft.shared.command;
import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContext;
@@ -27,12 +26,13 @@ public final class CommandUtils
public static boolean isPlayer( CommandSourceStack output ) public static boolean isPlayer( CommandSourceStack output )
{ {
Entity sender = output.getEntity(); Entity sender = output.getEntity();
return sender instanceof ServerPlayer && !(sender instanceof FakePlayer) && ((ServerPlayer) sender).connection != null; return sender instanceof ServerPlayer
&& !(sender instanceof FakePlayer)
&& ((ServerPlayer) sender).connection != null;
} }
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
public static CompletableFuture<Suggestions> suggestOnServer( CommandContext<?> context, SuggestionsBuilder builder, public static CompletableFuture<Suggestions> suggestOnServer( CommandContext<?> context, SuggestionsBuilder builder, Function<CommandContext<CommandSourceStack>, CompletableFuture<Suggestions>> supplier )
Function<CommandContext<CommandSourceStack>, CompletableFuture<Suggestions>> supplier )
{ {
Object source = context.getSource(); Object source = context.getSource();
if( !(source instanceof SharedSuggestionProvider) ) if( !(source instanceof SharedSuggestionProvider) )
@@ -49,26 +49,21 @@ public final class CommandUtils
} }
} }
public static <T> CompletableFuture<Suggestions> suggest( SuggestionsBuilder builder, T[] candidates, Function<T, String> toString )
{
return suggest( builder, Arrays.asList( candidates ), toString );
}
public static <T> CompletableFuture<Suggestions> suggest( SuggestionsBuilder builder, Iterable<T> candidates, Function<T, String> toString ) public static <T> CompletableFuture<Suggestions> suggest( SuggestionsBuilder builder, Iterable<T> candidates, Function<T, String> toString )
{ {
String remaining = builder.getRemaining() String remaining = builder.getRemaining().toLowerCase( Locale.ROOT );
.toLowerCase( Locale.ROOT );
for( T choice : candidates ) for( T choice : candidates )
{ {
String name = toString.apply( choice ); String name = toString.apply( choice );
if( !name.toLowerCase( Locale.ROOT ) if( !name.toLowerCase( Locale.ROOT ).startsWith( remaining ) ) continue;
.startsWith( remaining ) )
{
continue;
}
builder.suggest( name ); builder.suggest( name );
} }
return builder.buildFuture(); return builder.buildFuture();
} }
public static <T> CompletableFuture<Suggestions> suggest( SuggestionsBuilder builder, T[] candidates, Function<T, String> toString )
{
return suggest( builder, Arrays.asList( candidates ), toString );
}
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.command; package dan200.computercraft.shared.command;
import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType;
@@ -17,12 +16,15 @@ public final class Exceptions
public static final Dynamic2CommandExceptionType COMPUTER_ARG_MANY = translated2( "argument.computercraft.computer.many_matching" ); public static final Dynamic2CommandExceptionType COMPUTER_ARG_MANY = translated2( "argument.computercraft.computer.many_matching" );
public static final DynamicCommandExceptionType TRACKING_FIELD_ARG_NONE = translated1( "argument.computercraft.tracking_field.no_field" ); public static final DynamicCommandExceptionType TRACKING_FIELD_ARG_NONE = translated1( "argument.computercraft.tracking_field.no_field" );
public static final SimpleCommandExceptionType ARGUMENT_EXPECTED = translated( "argument.computercraft.argument_expected" );
static final SimpleCommandExceptionType NOT_TRACKING_EXCEPTION = translated( "commands.computercraft.track.stop.not_enabled" ); static final SimpleCommandExceptionType NOT_TRACKING_EXCEPTION = translated( "commands.computercraft.track.stop.not_enabled" );
static final SimpleCommandExceptionType NO_TIMINGS_EXCEPTION = translated( "commands.computercraft.track.dump.no_timings" ); static final SimpleCommandExceptionType NO_TIMINGS_EXCEPTION = translated( "commands.computercraft.track.dump.no_timings" );
static final SimpleCommandExceptionType TP_NOT_THERE = translated( "commands.computercraft.tp.not_there" ); static final SimpleCommandExceptionType TP_NOT_THERE = translated( "commands.computercraft.tp.not_there" );
static final SimpleCommandExceptionType TP_NOT_PLAYER = translated( "commands.computercraft.tp.not_player" ); static final SimpleCommandExceptionType TP_NOT_PLAYER = translated( "commands.computercraft.tp.not_player" );
public static final SimpleCommandExceptionType ARGUMENT_EXPECTED = translated( "argument.computercraft.argument_expected" );
private static SimpleCommandExceptionType translated( String key ) private static SimpleCommandExceptionType translated( String key )
{ {
return new SimpleCommandExceptionType( new TranslatableComponent( key ) ); return new SimpleCommandExceptionType( new TranslatableComponent( key ) );

View File

@@ -67,6 +67,6 @@ public enum UserLevel implements Predicate<CommandSourceStack>
Entity sender = source.getEntity(); Entity sender = source.getEntity();
return server.isDedicatedServer() return server.isDedicatedServer()
? source.getEntity() == null && source.hasPermission( 4 ) && source.getTextName().equals( "Server" ) ? source.getEntity() == null && source.hasPermission( 4 ) && source.getTextName().equals( "Server" )
: sender instanceof Player && ((Player) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ); : sender instanceof Player player && player.getGameProfile().getName().equalsIgnoreCase( server.getServerModName() );
} }
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.command.arguments; package dan200.computercraft.shared.command.arguments;
import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.arguments.ArgumentType;
@@ -15,17 +14,10 @@ import net.minecraft.resources.ResourceLocation;
public final class ArgumentSerializers public final class ArgumentSerializers
{ {
public static void register() @SuppressWarnings( "unchecked" )
private static <T extends ArgumentType<?>> void registerUnsafe( ResourceLocation id, Class<T> type, ArgumentSerializer<?> serializer )
{ {
register( new ResourceLocation( ComputerCraft.MOD_ID, "tracking_field" ), TrackingFieldArgumentType.trackingField() ); ArgumentTypes.register( id.toString(), type, (ArgumentSerializer<T>) serializer );
register( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ), ComputerArgumentType.oneComputer() );
register( new ResourceLocation( ComputerCraft.MOD_ID, "computers" ), ComputersArgumentType.class, new ComputersArgumentType.Serializer() );
registerUnsafe( new ResourceLocation( ComputerCraft.MOD_ID, "repeat" ), RepeatArgumentType.class, new RepeatArgumentType.Serializer() );
}
private static <T extends ArgumentType<?>> void register( ResourceLocation id, T instance )
{
registerUnsafe( id, instance.getClass(), new EmptyArgumentSerializer<>( () -> instance ) );
} }
private static <T extends ArgumentType<?>> void register( ResourceLocation id, Class<T> type, ArgumentSerializer<T> serializer ) private static <T extends ArgumentType<?>> void register( ResourceLocation id, Class<T> type, ArgumentSerializer<T> serializer )
@@ -33,9 +25,16 @@ public final class ArgumentSerializers
ArgumentTypes.register( id.toString(), type, serializer ); ArgumentTypes.register( id.toString(), type, serializer );
} }
@SuppressWarnings( "unchecked" ) private static <T extends ArgumentType<?>> void register( ResourceLocation id, T instance )
private static <T extends ArgumentType<?>> void registerUnsafe( ResourceLocation id, Class<T> type, ArgumentSerializer<?> serializer )
{ {
ArgumentTypes.register( id.toString(), type, (ArgumentSerializer<T>) serializer ); registerUnsafe( id, instance.getClass(), new EmptyArgumentSerializer<>( () -> instance ) );
}
public static void register()
{
register( new ResourceLocation( ComputerCraft.MOD_ID, "tracking_field" ), TrackingFieldArgumentType.trackingField() );
register( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ), ComputerArgumentType.oneComputer() );
register( new ResourceLocation( ComputerCraft.MOD_ID, "computers" ), ComputersArgumentType.class, new ComputersArgumentType.Serializer() );
registerUnsafe( new ResourceLocation( ComputerCraft.MOD_ID, "repeat" ), RepeatArgumentType.class, new RepeatArgumentType.Serializer() );
} }
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.command.arguments; package dan200.computercraft.shared.command.arguments;
import com.mojang.brigadier.Message; import com.mojang.brigadier.Message;
@@ -43,10 +42,7 @@ public abstract class ChoiceArgumentType<T> implements ArgumentType<T>
for( T choice : choices ) for( T choice : choices )
{ {
String choiceName = this.name.apply( choice ); String choiceName = this.name.apply( choice );
if( name.equals( choiceName ) ) if( name.equals( choiceName ) ) return choice;
{
return choice;
}
} }
reader.setCursor( start ); reader.setCursor( start );
@@ -56,16 +52,11 @@ public abstract class ChoiceArgumentType<T> implements ArgumentType<T>
@Override @Override
public <S> CompletableFuture<Suggestions> listSuggestions( CommandContext<S> context, SuggestionsBuilder builder ) public <S> CompletableFuture<Suggestions> listSuggestions( CommandContext<S> context, SuggestionsBuilder builder )
{ {
String remaining = builder.getRemaining() String remaining = builder.getRemaining().toLowerCase( Locale.ROOT );
.toLowerCase( Locale.ROOT );
for( T choice : choices ) for( T choice : choices )
{ {
String name = this.name.apply( choice ); String name = this.name.apply( choice );
if( !name.toLowerCase( Locale.ROOT ) if( !name.toLowerCase( Locale.ROOT ).startsWith( remaining ) ) continue;
.startsWith( remaining ) )
{
continue;
}
builder.suggest( name, tooltip.apply( choice ) ); builder.suggest( name, tooltip.apply( choice ) );
} }
@@ -76,10 +67,7 @@ public abstract class ChoiceArgumentType<T> implements ArgumentType<T>
public Collection<String> getExamples() public Collection<String> getExamples()
{ {
List<String> items = choices instanceof Collection<?> ? new ArrayList<>( ((Collection<T>) choices).size() ) : new ArrayList<>(); List<String> items = choices instanceof Collection<?> ? new ArrayList<>( ((Collection<T>) choices).size() ) : new ArrayList<>();
for( T choice : choices ) for( T choice : choices ) items.add( name.apply( choice ) );
{
items.add( name.apply( choice ) );
}
items.sort( Comparator.naturalOrder() ); items.sort( Comparator.naturalOrder() );
return items; return items;
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.command.arguments; package dan200.computercraft.shared.command.arguments;
import com.mojang.brigadier.StringReader; import com.mojang.brigadier.StringReader;
@@ -25,10 +24,6 @@ public final class ComputerArgumentType implements ArgumentType<ComputerArgument
{ {
private static final ComputerArgumentType INSTANCE = new ComputerArgumentType(); private static final ComputerArgumentType INSTANCE = new ComputerArgumentType();
private ComputerArgumentType()
{
}
public static ComputerArgumentType oneComputer() public static ComputerArgumentType oneComputer()
{ {
return INSTANCE; return INSTANCE;
@@ -36,27 +31,24 @@ public final class ComputerArgumentType implements ArgumentType<ComputerArgument
public static ServerComputer getComputerArgument( CommandContext<CommandSourceStack> context, String name ) throws CommandSyntaxException public static ServerComputer getComputerArgument( CommandContext<CommandSourceStack> context, String name ) throws CommandSyntaxException
{ {
return context.getArgument( name, ComputerSupplier.class ) return context.getArgument( name, ComputerSupplier.class ).unwrap( context.getSource() );
.unwrap( context.getSource() ); }
private ComputerArgumentType()
{
} }
@Override @Override
public ComputerSupplier parse( StringReader reader ) throws CommandSyntaxException public ComputerSupplier parse( StringReader reader ) throws CommandSyntaxException
{ {
int start = reader.getCursor(); int start = reader.getCursor();
ComputersSupplier supplier = ComputersArgumentType.someComputers() ComputersSupplier supplier = ComputersArgumentType.someComputers().parse( reader );
.parse( reader ); String selector = reader.getString().substring( start, reader.getCursor() );
String selector = reader.getString()
.substring( start, reader.getCursor() );
return s -> { return s -> {
Collection<ServerComputer> computers = supplier.unwrap( s ); Collection<ServerComputer> computers = supplier.unwrap( s );
if( computers.size() == 1 ) if( computers.size() == 1 ) return computers.iterator().next();
{
return computers.iterator()
.next();
}
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
boolean first = true; boolean first = true;
@@ -84,15 +76,13 @@ public final class ComputerArgumentType implements ArgumentType<ComputerArgument
@Override @Override
public <S> CompletableFuture<Suggestions> listSuggestions( CommandContext<S> context, SuggestionsBuilder builder ) public <S> CompletableFuture<Suggestions> listSuggestions( CommandContext<S> context, SuggestionsBuilder builder )
{ {
return ComputersArgumentType.someComputers() return ComputersArgumentType.someComputers().listSuggestions( context, builder );
.listSuggestions( context, builder );
} }
@Override @Override
public Collection<String> getExamples() public Collection<String> getExamples()
{ {
return ComputersArgumentType.someComputers() return ComputersArgumentType.someComputers().getExamples();
.getExamples();
} }
@FunctionalInterface @FunctionalInterface

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.command.arguments; package dan200.computercraft.shared.command.arguments;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
@@ -36,13 +35,9 @@ public final class ComputersArgumentType implements ArgumentType<ComputersArgume
private static final ComputersArgumentType MANY = new ComputersArgumentType( false ); private static final ComputersArgumentType MANY = new ComputersArgumentType( false );
private static final ComputersArgumentType SOME = new ComputersArgumentType( true ); private static final ComputersArgumentType SOME = new ComputersArgumentType( true );
private static final List<String> EXAMPLES = Arrays.asList( "0", "#0", "@Label", "~Advanced" ); private static final List<String> EXAMPLES = Arrays.asList(
private final boolean requireSome; "0", "#0", "@Label", "~Advanced"
);
private ComputersArgumentType( boolean requireSome )
{
this.requireSome = requireSome;
}
public static ComputersArgumentType manyComputers() public static ComputersArgumentType manyComputers()
{ {
@@ -56,18 +51,14 @@ public final class ComputersArgumentType implements ArgumentType<ComputersArgume
public static Collection<ServerComputer> getComputersArgument( CommandContext<CommandSourceStack> context, String name ) throws CommandSyntaxException public static Collection<ServerComputer> getComputersArgument( CommandContext<CommandSourceStack> context, String name ) throws CommandSyntaxException
{ {
return context.getArgument( name, ComputersSupplier.class ) return context.getArgument( name, ComputersSupplier.class ).unwrap( context.getSource() );
.unwrap( context.getSource() );
} }
public static Set<ServerComputer> unwrap( CommandSourceStack source, Collection<ComputersSupplier> suppliers ) throws CommandSyntaxException private final boolean requireSome;
private ComputersArgumentType( boolean requireSome )
{ {
Set<ServerComputer> computers = new HashSet<>(); this.requireSome = requireSome;
for( ComputersSupplier supplier : suppliers )
{
computers.addAll( supplier.unwrap( source ) );
}
return computers;
} }
@Override @Override
@@ -86,9 +77,7 @@ public final class ComputersArgumentType implements ArgumentType<ComputersArgume
{ {
reader.skip(); reader.skip();
String family = reader.readUnquotedString(); String family = reader.readUnquotedString();
computers = getComputers( x -> x.getFamily() computers = getComputers( x -> x.getFamily().name().equalsIgnoreCase( family ) );
.name()
.equalsIgnoreCase( family ) );
} }
else if( kind == '#' ) else if( kind == '#' )
{ {
@@ -107,14 +96,10 @@ public final class ComputersArgumentType implements ArgumentType<ComputersArgume
if( requireSome ) if( requireSome )
{ {
String selector = reader.getString() String selector = reader.getString().substring( start, reader.getCursor() );
.substring( start, reader.getCursor() );
return source -> { return source -> {
Collection<ServerComputer> matched = computers.unwrap( source ); Collection<ServerComputer> matched = computers.unwrap( source );
if( matched.isEmpty() ) if( matched.isEmpty() ) throw COMPUTER_ARG_NONE.create( selector );
{
throw COMPUTER_ARG_NONE.create( selector );
}
return matched; return matched;
}; };
} }
@@ -169,8 +154,7 @@ public final class ComputersArgumentType implements ArgumentType<ComputersArgume
for( ServerComputer computer : ComputerCraft.serverComputerRegistry.getComputers() ) for( ServerComputer computer : ComputerCraft.serverComputerRegistry.getComputers() )
{ {
String converted = renderer.apply( computer ); String converted = renderer.apply( computer );
if( converted != null && converted.toLowerCase( Locale.ROOT ) if( converted != null && converted.toLowerCase( Locale.ROOT ).startsWith( remaining ) )
.startsWith( remaining ) )
{ {
builder.suggest( converted ); builder.suggest( converted );
} }
@@ -179,16 +163,12 @@ public final class ComputersArgumentType implements ArgumentType<ComputersArgume
private static ComputersSupplier getComputers( Predicate<ServerComputer> predicate ) private static ComputersSupplier getComputers( Predicate<ServerComputer> predicate )
{ {
return s -> Collections.unmodifiableList( ComputerCraft.serverComputerRegistry.getComputers() return s -> Collections.unmodifiableList( ComputerCraft.serverComputerRegistry
.getComputers()
.stream() .stream()
.filter( predicate ) .filter( predicate )
.collect( Collectors.toList() ) ); .collect( Collectors.toList() )
} );
@FunctionalInterface
public interface ComputersSupplier
{
Collection<ServerComputer> unwrap( CommandSourceStack source ) throws CommandSyntaxException;
} }
public static class Serializer implements ArgumentSerializer<ComputersArgumentType> public static class Serializer implements ArgumentSerializer<ComputersArgumentType>
@@ -213,4 +193,17 @@ public final class ComputersArgumentType implements ArgumentType<ComputersArgume
json.addProperty( "requireSome", arg.requireSome ); json.addProperty( "requireSome", arg.requireSome );
} }
} }
@FunctionalInterface
public interface ComputersSupplier
{
Collection<ServerComputer> unwrap( CommandSourceStack source ) throws CommandSyntaxException;
}
public static Set<ServerComputer> unwrap( CommandSourceStack source, Collection<ComputersSupplier> suppliers ) throws CommandSyntaxException
{
Set<ServerComputer> computers = new HashSet<>();
for( ComputersSupplier supplier : suppliers ) computers.addAll( supplier.unwrap( source ) );
return computers;
}
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.command.arguments; package dan200.computercraft.shared.command.arguments;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
@@ -32,8 +31,8 @@ import java.util.function.BiConsumer;
/** /**
* Reads one argument multiple times. * Reads one argument multiple times.
* *
* Note that this must be the last element in an argument chain: in order to improve the quality of error messages, we will always try to consume another * Note that this must be the last element in an argument chain: in order to improve the quality of error messages,
* argument while there is input remaining. * we will always try to consume another argument while there is input remaining.
* *
* One problem with how parsers function, is that they must consume some input: and thus we * One problem with how parsers function, is that they must consume some input: and thus we
* *
@@ -73,10 +72,7 @@ public final class RepeatArgumentType<T, U> implements ArgumentType<List<T>>
while( true ) while( true )
{ {
reader.skipWhitespace(); reader.skipWhitespace();
if( !reader.canRead() ) if( !reader.canRead() ) break;
{
break;
}
int startParse = reader.getCursor(); int startParse = reader.getCursor();
appender.accept( out, child.parse( reader ) ); appender.accept( out, child.parse( reader ) );
@@ -91,10 +87,7 @@ public final class RepeatArgumentType<T, U> implements ArgumentType<List<T>>
// Note that each child may return an empty list, we just require that some actual input // Note that each child may return an empty list, we just require that some actual input
// was consumed. // was consumed.
// We should probably review that this is sensible in the future. // We should probably review that this is sensible in the future.
if( !hadSome ) if( !hadSome ) throw some.createWithContext( reader );
{
throw some.createWithContext( reader );
}
return Collections.unmodifiableList( out ); return Collections.unmodifiableList( out );
} }
@@ -118,10 +111,7 @@ public final class RepeatArgumentType<T, U> implements ArgumentType<List<T>>
int cursor = reader.getCursor(); int cursor = reader.getCursor();
reader.skipWhitespace(); reader.skipWhitespace();
if( cursor == reader.getCursor() ) if( cursor == reader.getCursor() ) break;
{
break;
}
previous = reader.getCursor(); previous = reader.getCursor();
} }
@@ -147,10 +137,7 @@ public final class RepeatArgumentType<T, U> implements ArgumentType<List<T>>
@Nonnull @Nonnull
@Override @Override
@SuppressWarnings( { @SuppressWarnings( { "unchecked", "rawtypes" } )
"unchecked",
"rawtypes"
} )
public RepeatArgumentType<?, ?> deserializeFromNetwork( @Nonnull FriendlyByteBuf buf ) public RepeatArgumentType<?, ?> deserializeFromNetwork( @Nonnull FriendlyByteBuf buf )
{ {
boolean isList = buf.readBoolean(); boolean isList = buf.readBoolean();
@@ -170,12 +157,8 @@ public final class RepeatArgumentType<T, U> implements ArgumentType<List<T>>
private static Component getMessage( RepeatArgumentType<?, ?> arg ) private static Component getMessage( RepeatArgumentType<?, ?> arg )
{ {
Message message = arg.some.create() Message message = arg.some.create().getRawMessage();
.getRawMessage(); if( message instanceof Component ) return (Component) message;
if( message instanceof Component )
{
return (Component) message;
}
return new TextComponent( message.getString() ); return new TextComponent( message.getString() );
} }
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.command.arguments; package dan200.computercraft.shared.command.arguments;
import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.core.tracking.TrackingField;
@@ -17,8 +16,7 @@ public final class TrackingFieldArgumentType extends ChoiceArgumentType<Tracking
private TrackingFieldArgumentType() private TrackingFieldArgumentType()
{ {
super( TrackingField.fields() super( TrackingField.fields().values(), TrackingField::id, x -> translate( x.translationKey() ), Exceptions.TRACKING_FIELD_ARG_NONE );
.values(), TrackingField::id, x -> translate( x.translationKey() ), Exceptions.TRACKING_FIELD_ARG_NONE );
} }
public static TrackingFieldArgumentType trackingField() public static TrackingFieldArgumentType trackingField()

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.command.builder; package dan200.computercraft.shared.command.builder;
import com.mojang.brigadier.Command; import com.mojang.brigadier.Command;
@@ -25,13 +24,14 @@ import static dan200.computercraft.shared.command.Exceptions.ARGUMENT_EXPECTED;
import static dan200.computercraft.shared.command.builder.HelpingArgumentBuilder.literal; import static dan200.computercraft.shared.command.builder.HelpingArgumentBuilder.literal;
/** /**
* An alternative way of building command nodes, so one does not have to nest. {@link ArgumentBuilder#then(CommandNode)}s. * An alternative way of building command nodes, so one does not have to nest.
* {@link ArgumentBuilder#then(CommandNode)}s.
* *
* @param <S> The command source we consume. * @param <S> The command source we consume.
*/ */
public class CommandBuilder<S> implements CommandNodeBuilder<S, Command<S>> public class CommandBuilder<S> implements CommandNodeBuilder<S, Command<S>>
{ {
private List<ArgumentBuilder<S, ?>> args = new ArrayList<>(); private final List<ArgumentBuilder<S, ?>> args = new ArrayList<>();
private Predicate<S> requires; private Predicate<S> requires;
public static CommandBuilder<CommandSourceStack> args() public static CommandBuilder<CommandSourceStack> args()
@@ -58,34 +58,38 @@ public class CommandBuilder<S> implements CommandNodeBuilder<S, Command<S>>
return this; return this;
} }
public <T> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argManyValue( String name, ArgumentType<T> type, T defaultValue )
{
return argManyValue( name, type, Collections.singletonList( defaultValue ) );
}
public <T> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argManyValue( String name, ArgumentType<T> type, List<T> empty ) public <T> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argManyValue( String name, ArgumentType<T> type, List<T> empty )
{ {
return argMany( name, type, () -> empty ); return argMany( name, type, () -> empty );
} }
public <T> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argManyValue( String name, ArgumentType<T> type, T defaultValue )
{
return argManyValue( name, type, Collections.singletonList( defaultValue ) );
}
public <T> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argMany( String name, ArgumentType<T> type, Supplier<List<T>> empty ) public <T> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argMany( String name, ArgumentType<T> type, Supplier<List<T>> empty )
{ {
return argMany( name, RepeatArgumentType.some( type, ARGUMENT_EXPECTED ), empty ); return argMany( name, RepeatArgumentType.some( type, ARGUMENT_EXPECTED ), empty );
} }
public <T> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argManyFlatten( String name, ArgumentType<List<T>> type, Supplier<List<T>> empty )
{
return argMany( name, RepeatArgumentType.someFlat( type, ARGUMENT_EXPECTED ), empty );
}
private <T, U> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argMany( String name, RepeatArgumentType<T, ?> type, Supplier<List<T>> empty ) private <T, U> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argMany( String name, RepeatArgumentType<T, ?> type, Supplier<List<T>> empty )
{ {
if( args.isEmpty() ) if( args.isEmpty() ) throw new IllegalStateException( "Cannot have empty arg chain builder" );
{
throw new IllegalStateException( "Cannot have empty arg chain builder" );
}
return command -> { return command -> {
// The node for no arguments // The node for no arguments
ArgumentBuilder<S, ?> tail = tail( ctx -> command.run( ctx, empty.get() ) ); ArgumentBuilder<S, ?> tail = tail( ctx -> command.run( ctx, empty.get() ) );
// The node for one or more arguments // The node for one or more arguments
ArgumentBuilder<S, ?> moreArg = RequiredArgumentBuilder.<S, List<T>>argument( name, type ).executes( ctx -> command.run( ctx, getList( ctx, name ) ) ); ArgumentBuilder<S, ?> moreArg = RequiredArgumentBuilder
.<S, List<T>>argument( name, type )
.executes( ctx -> command.run( ctx, getList( ctx, name ) ) );
// Chain all of them together! // Chain all of them together!
tail.then( moreArg ); tail.then( moreArg );
@@ -93,46 +97,31 @@ public class CommandBuilder<S> implements CommandNodeBuilder<S, Command<S>>
}; };
} }
private ArgumentBuilder<S, ?> tail( Command<S> command )
{
ArgumentBuilder<S, ?> defaultTail = args.get( args.size() - 1 );
defaultTail.executes( command );
if( requires != null )
{
defaultTail.requires( requires );
}
return defaultTail;
}
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
private static <T> List<T> getList( CommandContext<?> context, String name ) private static <T> List<T> getList( CommandContext<?> context, String name )
{ {
return (List<T>) context.getArgument( name, List.class ); return (List<T>) context.getArgument( name, List.class );
} }
private CommandNode<S> link( ArgumentBuilder<S, ?> tail )
{
for( int i = args.size() - 2; i >= 0; i-- )
{
tail = args.get( i )
.then( tail );
}
return tail.build();
}
public <T> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argManyFlatten( String name, ArgumentType<List<T>> type, Supplier<List<T>> empty )
{
return argMany( name, RepeatArgumentType.someFlat( type, ARGUMENT_EXPECTED ), empty );
}
@Override @Override
public CommandNode<S> executes( Command<S> command ) public CommandNode<S> executes( Command<S> command )
{ {
if( args.isEmpty() ) if( args.isEmpty() ) throw new IllegalStateException( "Cannot have empty arg chain builder" );
{
throw new IllegalStateException( "Cannot have empty arg chain builder" );
}
return link( tail( command ) ); return link( tail( command ) );
} }
private ArgumentBuilder<S, ?> tail( Command<S> command )
{
ArgumentBuilder<S, ?> defaultTail = args.get( args.size() - 1 );
defaultTail.executes( command );
if( requires != null ) defaultTail.requires( requires );
return defaultTail;
}
private CommandNode<S> link( ArgumentBuilder<S, ?> tail )
{
for( int i = args.size() - 2; i >= 0; i-- ) tail = args.get( i ).then( tail );
return tail.build();
}
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.command.builder; package dan200.computercraft.shared.command.builder;
import com.mojang.brigadier.Command; import com.mojang.brigadier.Command;
@@ -28,14 +27,11 @@ import static dan200.computercraft.shared.command.text.ChatHelpers.coloured;
import static dan200.computercraft.shared.command.text.ChatHelpers.translate; import static dan200.computercraft.shared.command.text.ChatHelpers.translate;
/** /**
* An alternative to {@link LiteralArgumentBuilder} which also provides a {@code /... help} command, and defaults to that command when no arguments are * An alternative to {@link LiteralArgumentBuilder} which also provides a {@code /... help} command, and defaults
* given. * to that command when no arguments are given.
*/ */
public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<CommandSourceStack> public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<CommandSourceStack>
{ {
private static final ChatFormatting HEADER = ChatFormatting.LIGHT_PURPLE;
private static final ChatFormatting SYNOPSIS = ChatFormatting.AQUA;
private static final ChatFormatting NAME = ChatFormatting.GREEN;
private final Collection<HelpingArgumentBuilder> children = new ArrayList<>(); private final Collection<HelpingArgumentBuilder> children = new ArrayList<>();
private HelpingArgumentBuilder( String literal ) private HelpingArgumentBuilder( String literal )
@@ -48,69 +44,16 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
return new HelpingArgumentBuilder( literal ); return new HelpingArgumentBuilder( literal );
} }
private static Command<CommandSourceStack> helpForChild( CommandNode<CommandSourceStack> node, String id, String command ) @Override
public LiteralArgumentBuilder<CommandSourceStack> executes( final Command<CommandSourceStack> command )
{ {
return context -> { throw new IllegalStateException( "Cannot use executes on a HelpingArgumentBuilder" );
context.getSource()
.sendSuccess( getHelp( context,
node,
id + "." + node.getName()
.replace( '-', '_' ),
command + " " + node.getName() ), false );
return 0;
};
}
private static Component getHelp( CommandContext<CommandSourceStack> context, CommandNode<CommandSourceStack> node, String id, String command )
{
// An ugly hack to extract usage information from the dispatcher. We generate a temporary node, generate
// the shorthand usage, and emit that.
CommandDispatcher<CommandSourceStack> dispatcher = context.getSource()
.getServer()
.getCommands()
.getDispatcher();
CommandNode<CommandSourceStack> temp = new LiteralCommandNode<>( "_", null, x -> true, null, null, false );
temp.addChild( node );
String usage = dispatcher.getSmartUsage( temp, context.getSource() )
.get( node )
.substring( node.getName()
.length() );
MutableComponent output = new TextComponent( "" ).append( coloured( "/" + command + usage, HEADER ) )
.append( " " )
.append( coloured( translate( "commands." + id + ".synopsis" ), SYNOPSIS ) )
.append( "\n" )
.append( translate( "commands." + id + ".desc" ) );
for( CommandNode<CommandSourceStack> child : node.getChildren() )
{
if( !child.getRequirement()
.test( context.getSource() ) || !(child instanceof LiteralCommandNode) )
{
continue;
}
output.append( "\n" );
MutableComponent component = coloured( child.getName(), NAME );
component.getStyle()
.withClickEvent( new ClickEvent( ClickEvent.Action.SUGGEST_COMMAND, "/" + command + " " + child.getName() ) );
output.append( component );
output.append( " - " )
.append( translate( "commands." + id + "." + child.getName() + ".synopsis" ) );
}
return output;
} }
@Override @Override
public LiteralArgumentBuilder<CommandSourceStack> then( final ArgumentBuilder<CommandSourceStack, ?> argument ) public LiteralArgumentBuilder<CommandSourceStack> then( final ArgumentBuilder<CommandSourceStack, ?> argument )
{ {
if( getRedirect() != null ) if( getRedirect() != null ) throw new IllegalStateException( "Cannot add children to a redirected node" );
{
throw new IllegalStateException( "Cannot add children to a redirected node" );
}
if( argument instanceof HelpingArgumentBuilder ) if( argument instanceof HelpingArgumentBuilder )
{ {
@@ -138,12 +81,6 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
return super.then( argument ); return super.then( argument );
} }
@Override
public LiteralArgumentBuilder<CommandSourceStack> executes( final Command<CommandSourceStack> command )
{
throw new IllegalStateException( "Cannot use executes on a HelpingArgumentBuilder" );
}
@Override @Override
public LiteralCommandNode<CommandSourceStack> build() public LiteralCommandNode<CommandSourceStack> build()
{ {
@@ -158,28 +95,24 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
private LiteralCommandNode<CommandSourceStack> buildImpl( String id, String command ) private LiteralCommandNode<CommandSourceStack> buildImpl( String id, String command )
{ {
HelpCommand helpCommand = new HelpCommand( id, command ); HelpCommand helpCommand = new HelpCommand( id, command );
LiteralCommandNode<CommandSourceStack> node = new LiteralCommandNode<>( getLiteral(), LiteralCommandNode<CommandSourceStack> node = new LiteralCommandNode<>( getLiteral(), helpCommand, getRequirement(), getRedirect(), getRedirectModifier(), isFork() );
helpCommand, getRequirement(),
getRedirect(), getRedirectModifier(), isFork() );
helpCommand.node = node; helpCommand.node = node;
// Set up a /... help command // Set up a /... help command
LiteralArgumentBuilder<CommandSourceStack> helpNode = LiteralArgumentBuilder<CommandSourceStack> helpNode = LiteralArgumentBuilder.<CommandSourceStack>literal( "help" )
LiteralArgumentBuilder.<CommandSourceStack>literal( "help" ).requires( x -> getArguments().stream() .requires( x -> getArguments().stream().anyMatch( y -> y.getRequirement().test( x ) ) )
.anyMatch( .executes( helpCommand );
y -> y.getRequirement()
.test(
x ) ) )
.executes( helpCommand );
// Add all normal command children to this and the help node // Add all normal command children to this and the help node
for( CommandNode<CommandSourceStack> child : getArguments() ) for( CommandNode<CommandSourceStack> child : getArguments() )
{ {
node.addChild( child ); node.addChild( child );
helpNode.then( LiteralArgumentBuilder.<CommandSourceStack>literal( child.getName() ).requires( child.getRequirement() ) helpNode.then( LiteralArgumentBuilder.<CommandSourceStack>literal( child.getName() )
.requires( child.getRequirement() )
.executes( helpForChild( child, id, command ) ) .executes( helpForChild( child, id, command ) )
.build() ); .build()
);
} }
// And add alternative versions of which forward instead // And add alternative versions of which forward instead
@@ -187,10 +120,12 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
{ {
LiteralCommandNode<CommandSourceStack> child = childBuilder.build( id, command ); LiteralCommandNode<CommandSourceStack> child = childBuilder.build( id, command );
node.addChild( child ); node.addChild( child );
helpNode.then( LiteralArgumentBuilder.<CommandSourceStack>literal( child.getName() ).requires( child.getRequirement() ) helpNode.then( LiteralArgumentBuilder.<CommandSourceStack>literal( child.getName() )
.requires( child.getRequirement() )
.executes( helpForChild( child, id, command ) ) .executes( helpForChild( child, id, command ) )
.redirect( child.getChild( "help" ) ) .redirect( child.getChild( "help" ) )
.build() ); .build()
);
} }
node.addChild( helpNode.build() ); node.addChild( helpNode.build() );
@@ -198,6 +133,10 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
return node; return node;
} }
private static final ChatFormatting HEADER = ChatFormatting.LIGHT_PURPLE;
private static final ChatFormatting SYNOPSIS = ChatFormatting.AQUA;
private static final ChatFormatting NAME = ChatFormatting.GREEN;
private static final class HelpCommand implements Command<CommandSourceStack> private static final class HelpCommand implements Command<CommandSourceStack>
{ {
private final String id; private final String id;
@@ -213,9 +152,54 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
@Override @Override
public int run( CommandContext<CommandSourceStack> context ) public int run( CommandContext<CommandSourceStack> context )
{ {
context.getSource() context.getSource().sendSuccess( getHelp( context, node, id, command ), false );
.sendSuccess( getHelp( context, node, id, command ), false );
return 0; return 0;
} }
} }
private static Command<CommandSourceStack> helpForChild( CommandNode<CommandSourceStack> node, String id, String command )
{
return context -> {
context.getSource().sendSuccess( getHelp( context, node, id + "." + node.getName().replace( '-', '_' ), command + " " + node.getName() ), false );
return 0;
};
}
private static Component getHelp( CommandContext<CommandSourceStack> context, CommandNode<CommandSourceStack> node, String id, String command )
{
// An ugly hack to extract usage information from the dispatcher. We generate a temporary node, generate
// the shorthand usage, and emit that.
CommandDispatcher<CommandSourceStack> dispatcher = context.getSource().getServer().getCommands().getDispatcher();
CommandNode<CommandSourceStack> temp = new LiteralCommandNode<>( "_", null, x -> true, null, null, false );
temp.addChild( node );
String usage = dispatcher.getSmartUsage( temp, context.getSource() ).get( node ).substring( node.getName().length() );
MutableComponent output = new TextComponent( "" )
.append( coloured( "/" + command + usage, HEADER ) )
.append( " " )
.append( coloured( translate( "commands." + id + ".synopsis" ), SYNOPSIS ) )
.append( "\n" )
.append( translate( "commands." + id + ".desc" ) );
for( CommandNode<CommandSourceStack> child : node.getChildren() )
{
if( !child.getRequirement().test( context.getSource() ) || !(child instanceof LiteralCommandNode) )
{
continue;
}
output.append( "\n" );
MutableComponent component = coloured( child.getName(), NAME );
component.getStyle().withClickEvent( new ClickEvent(
ClickEvent.Action.SUGGEST_COMMAND,
"/" + command + " " + child.getName()
) );
output.append( component );
output.append( " - " ).append( translate( "commands." + id + "." + child.getName() + ".synopsis" ) );
}
return output;
}
} }

View File

@@ -20,14 +20,12 @@ public final class ChatHelpers
public static MutableComponent coloured( String text, ChatFormatting colour ) public static MutableComponent coloured( String text, ChatFormatting colour )
{ {
MutableComponent component = new TextComponent( text == null ? "" : text ); return new TextComponent( text == null ? "" : text ).withStyle( colour );
component.setStyle( component.getStyle().withColor( colour ) );
return component;
} }
public static <T extends MutableComponent> T coloured( T component, ChatFormatting colour ) public static <T extends MutableComponent> T coloured( T component, ChatFormatting colour )
{ {
component.setStyle( component.getStyle().withColor( colour ) ); component.withStyle( colour );
return component; return component;
} }
@@ -46,10 +44,10 @@ public final class ChatHelpers
return new TranslatableComponent( text == null ? "" : text, args ); return new TranslatableComponent( text == null ? "" : text, args );
} }
public static MutableComponent list( MutableComponent... children ) public static MutableComponent list( Component... children )
{ {
MutableComponent component = new TextComponent( "" ); MutableComponent component = new TextComponent( "" );
for( MutableComponent child : children ) for( Component child : children )
{ {
component.append( child ); component.append( child );
} }
@@ -69,12 +67,12 @@ public final class ChatHelpers
: coloured( translate( "commands.computercraft.generic.no" ), ChatFormatting.RED ); : coloured( translate( "commands.computercraft.generic.no" ), ChatFormatting.RED );
} }
public static MutableComponent link( MutableComponent component, String command, MutableComponent toolTip ) public static Component link( MutableComponent component, String command, Component toolTip )
{ {
return link( component, new ClickEvent( ClickEvent.Action.RUN_COMMAND, command ), toolTip ); return link( component, new ClickEvent( ClickEvent.Action.RUN_COMMAND, command ), toolTip );
} }
public static MutableComponent link( MutableComponent component, ClickEvent click, MutableComponent toolTip ) public static Component link( Component component, ClickEvent click, Component toolTip )
{ {
Style style = component.getStyle(); Style style = component.getStyle();
@@ -82,9 +80,7 @@ public final class ChatHelpers
style = style.withClickEvent( click ); style = style.withClickEvent( click );
style = style.withHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, toolTip ) ); style = style.withHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, toolTip ) );
component.setStyle( style ); return component.copy().withStyle( style );
return component;
} }
public static MutableComponent header( String text ) public static MutableComponent header( String text )
@@ -95,9 +91,9 @@ public final class ChatHelpers
public static MutableComponent copy( String text ) public static MutableComponent copy( String text )
{ {
TextComponent name = new TextComponent( text ); TextComponent name = new TextComponent( text );
name.setStyle( name.getStyle() Style style = name.getStyle()
.withClickEvent( new ClickEvent( ClickEvent.Action.COPY_TO_CLIPBOARD, text ) ) .withClickEvent( new ClickEvent( ClickEvent.Action.COPY_TO_CLIPBOARD, text ) )
.withHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslatableComponent( "gui.computercraft.tooltip.copy" ) ) ) ); .withHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslatableComponent( "gui.computercraft.tooltip.copy" ) ) );
return name; return name.withStyle( style );
} }
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.command.text; package dan200.computercraft.shared.command.text;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
@@ -27,10 +26,7 @@ public class ServerTableFormatter implements TableFormatter
public Component getPadding( Component component, int width ) public Component getPadding( Component component, int width )
{ {
int extraWidth = width - getWidth( component ); int extraWidth = width - getWidth( component );
if( extraWidth <= 0 ) if( extraWidth <= 0 ) return null;
{
return null;
}
return new TextComponent( StringUtils.repeat( ' ', extraWidth ) ); return new TextComponent( StringUtils.repeat( ' ', extraWidth ) );
} }
@@ -43,8 +39,7 @@ public class ServerTableFormatter implements TableFormatter
@Override @Override
public int getWidth( Component component ) public int getWidth( Component component )
{ {
return component.getString() return component.getString().length();
.length();
} }
@Override @Override

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.command.text; package dan200.computercraft.shared.command.text;
import dan200.computercraft.shared.command.CommandUtils; import dan200.computercraft.shared.command.CommandUtils;
@@ -21,17 +20,14 @@ import java.util.List;
public class TableBuilder public class TableBuilder
{ {
private final int id; private final int id;
private int columns = -1;
private final Component[] headers; private final Component[] headers;
private final ArrayList<Component[]> rows = new ArrayList<>(); private final ArrayList<Component[]> rows = new ArrayList<>();
private int columns = -1;
private int additional; private int additional;
public TableBuilder( int id, @Nonnull Component... headers ) public TableBuilder( int id, @Nonnull Component... headers )
{ {
if( id < 0 ) if( id < 0 ) throw new IllegalArgumentException( "ID must be positive" );
{
throw new IllegalArgumentException( "ID must be positive" );
}
this.id = id; this.id = id;
this.headers = headers; this.headers = headers;
columns = headers.length; columns = headers.length;
@@ -39,47 +35,33 @@ public class TableBuilder
public TableBuilder( int id ) public TableBuilder( int id )
{ {
if( id < 0 ) if( id < 0 ) throw new IllegalArgumentException( "ID must be positive" );
{
throw new IllegalArgumentException( "ID must be positive" );
}
this.id = id; this.id = id;
headers = null; headers = null;
} }
public TableBuilder( int id, @Nonnull String... headers ) public TableBuilder( int id, @Nonnull String... headers )
{ {
if( id < 0 ) if( id < 0 ) throw new IllegalArgumentException( "ID must be positive" );
{
throw new IllegalArgumentException( "ID must be positive" );
}
this.id = id; this.id = id;
this.headers = new Component[headers.length]; this.headers = new Component[headers.length];
columns = headers.length; columns = headers.length;
for( int i = 0; i < headers.length; i++ ) for( int i = 0; i < headers.length; i++ ) this.headers[i] = ChatHelpers.header( headers[i] );
{
this.headers[i] = ChatHelpers.header( headers[i] );
}
} }
public void row( @Nonnull Component... row ) public void row( @Nonnull Component... row )
{ {
if( columns == -1 ) if( columns == -1 ) columns = row.length;
{ if( row.length != columns ) throw new IllegalArgumentException( "Row is the incorrect length" );
columns = row.length;
}
if( row.length != columns )
{
throw new IllegalArgumentException( "Row is the incorrect length" );
}
rows.add( row ); rows.add( row );
} }
/** /**
* Get the unique identifier for this table type. * Get the unique identifier for this table type.
* *
* When showing a table within Minecraft, previous instances of this table with the same ID will be removed from chat. * When showing a table within Minecraft, previous instances of this table with
* the same ID will be removed from chat.
* *
* @return This table's type. * @return This table's type.
*/ */
@@ -91,7 +73,8 @@ public class TableBuilder
/** /**
* Get the number of columns for this table. * Get the number of columns for this table.
* *
* This will be the same as {@link #getHeaders()}'s length if it is is non-{@code null}, otherwise the length of the first column. * This will be the same as {@link #getHeaders()}'s length if it is is non-{@code null},
* otherwise the length of the first column.
* *
* @return The number of columns. * @return The number of columns.
*/ */
@@ -122,6 +105,20 @@ public class TableBuilder
this.additional = additional; this.additional = additional;
} }
/**
* Trim this table to a given height.
*
* @param height The desired height.
*/
public void trim( int height )
{
if( rows.size() > height )
{
additional += rows.size() - height - 1;
rows.subList( height - 1, rows.size() ).clear();
}
}
public void display( CommandSourceStack source ) public void display( CommandSourceStack source )
{ {
if( CommandUtils.isPlayer( source ) ) if( CommandUtils.isPlayer( source ) )
@@ -135,19 +132,4 @@ public class TableBuilder
new ServerTableFormatter( source ).display( this ); new ServerTableFormatter( source ).display( this );
} }
} }
/**
* Trim this table to a given height.
*
* @param height The desired height.
*/
public void trim( int height )
{
if( rows.size() > height )
{
additional += rows.size() - height - 1;
rows.subList( height - 1, rows.size() )
.clear();
}
}
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.command.text; package dan200.computercraft.shared.command.text;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
@@ -21,12 +20,30 @@ public interface TableFormatter
Component SEPARATOR = coloured( "| ", ChatFormatting.GRAY ); Component SEPARATOR = coloured( "| ", ChatFormatting.GRAY );
Component HEADER = coloured( "=", ChatFormatting.GRAY ); Component HEADER = coloured( "=", ChatFormatting.GRAY );
/**
* Get additional padding for the component.
*
* @param component The component to pad
* @param width The desired width for the component
* @return The padding for this component, or {@code null} if none is needed.
*/
@Nullable
Component getPadding( Component component, int width );
/**
* Get the minimum padding between each column.
*
* @return The minimum padding.
*/
int getColumnPadding();
int getWidth( Component component );
void writeLine( int id, Component component );
default int display( TableBuilder table ) default int display( TableBuilder table )
{ {
if( table.getColumns() <= 0 ) if( table.getColumns() <= 0 ) return 0;
{
return 0;
}
int rowId = table.getId(); int rowId = table.getId();
int columns = table.getColumns(); int columns = table.getColumns();
@@ -35,10 +52,7 @@ public interface TableFormatter
Component[] headers = table.getHeaders(); Component[] headers = table.getHeaders();
if( headers != null ) if( headers != null )
{ {
for( int i = 0; i < columns; i++ ) for( int i = 0; i < columns; i++ ) maxWidths[i] = getWidth( headers[i] );
{
maxWidths[i] = getWidth( headers[i] );
}
} }
for( Component[] row : table.getRows() ) for( Component[] row : table.getRows() )
@@ -46,28 +60,19 @@ public interface TableFormatter
for( int i = 0; i < row.length; i++ ) for( int i = 0; i < row.length; i++ )
{ {
int width = getWidth( row[i] ); int width = getWidth( row[i] );
if( width > maxWidths[i] ) if( width > maxWidths[i] ) maxWidths[i] = width;
{
maxWidths[i] = width;
}
} }
} }
// Add a small amount of padding after each column // Add a small amount of padding after each column
{ {
int padding = getColumnPadding(); int padding = getColumnPadding();
for( int i = 0; i < maxWidths.length - 1; i++ ) for( int i = 0; i < maxWidths.length - 1; i++ ) maxWidths[i] += padding;
{
maxWidths[i] += padding;
}
} }
// And compute the total width // And compute the total width
int totalWidth = (columns - 1) * getWidth( SEPARATOR ); int totalWidth = (columns - 1) * getWidth( SEPARATOR );
for( int x : maxWidths ) for( int x : maxWidths ) totalWidth += x;
{
totalWidth += x;
}
if( headers != null ) if( headers != null )
{ {
@@ -76,10 +81,7 @@ public interface TableFormatter
{ {
line.append( headers[i] ); line.append( headers[i] );
Component padding = getPadding( headers[i], maxWidths[i] ); Component padding = getPadding( headers[i], maxWidths[i] );
if( padding != null ) if( padding != null ) line.append( padding );
{
line.append( padding );
}
line.append( SEPARATOR ); line.append( SEPARATOR );
} }
line.append( headers[columns - 1] ); line.append( headers[columns - 1] );
@@ -100,10 +102,7 @@ public interface TableFormatter
{ {
line.append( row[i] ); line.append( row[i] );
Component padding = getPadding( row[i], maxWidths[i] ); Component padding = getPadding( row[i], maxWidths[i] );
if( padding != null ) if( padding != null ) line.append( padding );
{
line.append( padding );
}
line.append( SEPARATOR ); line.append( SEPARATOR );
} }
line.append( row[columns - 1] ); line.append( row[columns - 1] );
@@ -117,25 +116,4 @@ public interface TableFormatter
return rowId - table.getId(); return rowId - table.getId();
} }
int getWidth( Component component );
/**
* Get the minimum padding between each column.
*
* @return The minimum padding.
*/
int getColumnPadding();
/**
* Get additional padding for the component.
*
* @param component The component to pad
* @param width The desired width for the component
* @return The padding for this component, or {@code null} if none is needed.
*/
@Nullable
Component getPadding( Component component, int width );
void writeLine( int id, Component component );
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.common; package dan200.computercraft.shared.common;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@@ -23,66 +22,45 @@ import net.minecraft.world.phys.BlockHitResult;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Random; import java.util.Random;
import java.util.function.Supplier;
public abstract class BlockGeneric extends BaseEntityBlock public abstract class BlockGeneric extends BaseEntityBlock
{ {
private final BlockEntityType<? extends TileGeneric> type; private final Supplier<? extends BlockEntityType<? extends TileGeneric>> type;
public BlockGeneric( Properties settings, BlockEntityType<? extends TileGeneric> type ) public BlockGeneric( Properties settings, Supplier<? extends BlockEntityType<? extends TileGeneric>> type )
{ {
super( settings ); super( settings );
this.type = type; this.type = type;
} }
public BlockEntityType<? extends TileGeneric> getType()
{
return type;
}
@Override
public RenderShape getRenderShape( BlockState state )
{
return RenderShape.MODEL;
}
@Override
@Deprecated
public final void neighborChanged( @Nonnull BlockState state, Level world, @Nonnull BlockPos pos, @Nonnull Block neighbourBlock,
@Nonnull BlockPos neighbourPos, boolean isMoving )
{
BlockEntity tile = world.getBlockEntity( pos );
if( tile instanceof TileGeneric )
{
((TileGeneric) tile).onNeighbourChange( neighbourPos );
}
}
@Override @Override
@Deprecated @Deprecated
public final void onRemove( @Nonnull BlockState block, @Nonnull Level world, @Nonnull BlockPos pos, BlockState replace, boolean bool ) public final void onRemove( @Nonnull BlockState block, @Nonnull Level world, @Nonnull BlockPos pos, BlockState replace, boolean bool )
{ {
if( block.getBlock() == replace.getBlock() ) if( block.getBlock() == replace.getBlock() ) return;
{
return;
}
BlockEntity tile = world.getBlockEntity( pos ); BlockEntity tile = world.getBlockEntity( pos );
super.onRemove( block, world, pos, replace, bool ); super.onRemove( block, world, pos, replace, bool );
world.removeBlockEntity( pos ); world.removeBlockEntity( pos );
if( tile instanceof TileGeneric ) if( tile instanceof TileGeneric generic ) generic.destroy();
{
((TileGeneric) tile).destroy();
}
} }
@Nonnull @Nonnull
@Override @Override
@Deprecated @Deprecated
public final InteractionResult use( @Nonnull BlockState state, Level world, @Nonnull BlockPos pos, @Nonnull Player player, @Nonnull InteractionHand hand, public final InteractionResult use( @Nonnull BlockState state, Level world, @Nonnull BlockPos pos, @Nonnull Player player, @Nonnull InteractionHand hand, @Nonnull BlockHitResult hit )
@Nonnull BlockHitResult hit )
{ {
BlockEntity tile = world.getBlockEntity( pos ); BlockEntity tile = world.getBlockEntity( pos );
return tile instanceof TileGeneric ? ((TileGeneric) tile).onActivate( player, hand, hit ) : InteractionResult.PASS; return tile instanceof TileGeneric generic ? generic.onActivate( player, hand, hit ) : InteractionResult.PASS;
}
@Override
@Deprecated
public final void neighborChanged( @Nonnull BlockState state, Level world, @Nonnull BlockPos pos, @Nonnull Block neighbourBlock, @Nonnull BlockPos neighbourPos, boolean isMoving )
{
BlockEntity tile = world.getBlockEntity( pos );
if( tile instanceof TileGeneric generic ) generic.onNeighbourChange( neighbourPos );
} }
@Override @Override
@@ -90,20 +68,21 @@ public abstract class BlockGeneric extends BaseEntityBlock
public void tick( @Nonnull BlockState state, ServerLevel world, @Nonnull BlockPos pos, @Nonnull Random rand ) public void tick( @Nonnull BlockState state, ServerLevel world, @Nonnull BlockPos pos, @Nonnull Random rand )
{ {
BlockEntity te = world.getBlockEntity( pos ); BlockEntity te = world.getBlockEntity( pos );
if( te instanceof TileGeneric ) if( te instanceof TileGeneric generic ) generic.blockTick();
{
((TileGeneric) te).blockTick();
}
} }
@Nullable @Nullable
@Override @Override
public BlockEntity newBlockEntity( BlockPos pos, BlockState state ) public BlockEntity newBlockEntity( @Nonnull BlockPos pos, @Nonnull BlockState state )
{ {
if( this.type != null ) return type.get().create( pos, state );
{ }
return type.create( pos, state );
} @Nonnull
return null; @Override
@Deprecated
public RenderShape getRenderShape( @Nonnull BlockState state )
{
return RenderShape.MODEL;
} }
} }

View File

@@ -3,12 +3,10 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.common; package dan200.computercraft.shared.common;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.network.client.TerminalState; import dan200.computercraft.shared.network.client.TerminalState;
import net.minecraft.nbt.CompoundTag;
public class ClientTerminal implements ITerminal public class ClientTerminal implements ITerminal
{ {
@@ -79,19 +77,4 @@ public class ClientTerminal implements ITerminal
terminalChanged = true; terminalChanged = true;
} }
} }
public void readDescription( CompoundTag nbt )
{
colour = nbt.getBoolean( "colour" );
if( nbt.contains( "terminal" ) )
{
CompoundTag terminal = nbt.getCompound( "terminal" );
resizeTerminal( terminal.getInt( "term_width" ), terminal.getInt( "term_height" ) );
this.terminal.readFromNBT( terminal );
}
else
{
deleteTerminal();
}
}
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.common; package dan200.computercraft.shared.common;
import dan200.computercraft.shared.util.ColourTracker; import dan200.computercraft.shared.util.ColourTracker;
@@ -21,8 +20,6 @@ import javax.annotation.Nonnull;
public final class ColourableRecipe extends CustomRecipe public final class ColourableRecipe extends CustomRecipe
{ {
public static final RecipeSerializer<?> SERIALIZER = new SimpleRecipeSerializer<>( ColourableRecipe::new );
private ColourableRecipe( ResourceLocation id ) private ColourableRecipe( ResourceLocation id )
{ {
super( id ); super( id );
@@ -36,17 +33,11 @@ public final class ColourableRecipe extends CustomRecipe
for( int i = 0; i < inv.getContainerSize(); i++ ) for( int i = 0; i < inv.getContainerSize(); i++ )
{ {
ItemStack stack = inv.getItem( i ); ItemStack stack = inv.getItem( i );
if( stack.isEmpty() ) if( stack.isEmpty() ) continue;
{
continue;
}
if( stack.getItem() instanceof IColouredItem ) if( stack.getItem() instanceof IColouredItem )
{ {
if( hasColourable ) if( hasColourable ) return false;
{
return false;
}
hasColourable = true; hasColourable = true;
} }
else if( ColourUtils.getStackColour( stack ) != null ) else if( ColourUtils.getStackColour( stack ) != null )
@@ -74,9 +65,11 @@ public final class ColourableRecipe extends CustomRecipe
{ {
ItemStack stack = inv.getItem( i ); ItemStack stack = inv.getItem( i );
if( stack.isEmpty() ) if( stack.isEmpty() ) continue;
if( stack.getItem() instanceof IColouredItem )
{ {
continue; colourable = stack;
} }
else else
{ {
@@ -104,4 +97,6 @@ public final class ColourableRecipe extends CustomRecipe
{ {
return SERIALIZER; return SERIALIZER;
} }
public static final SimpleRecipeSerializer<?> SERIALIZER = new SimpleRecipeSerializer<>( ColourableRecipe::new );
} }

View File

@@ -3,10 +3,9 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.common; package dan200.computercraft.shared.common;
import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.Registry;
import dan200.computercraft.shared.network.container.HeldItemContainerData; import dan200.computercraft.shared.network.container.HeldItemContainerData;
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
@@ -32,13 +31,12 @@ public class ContainerHeldItem extends AbstractContainerMenu
super( type, id ); super( type, id );
this.hand = hand; this.hand = hand;
stack = player.getItemInHand( hand ) stack = player.getItemInHand( hand ).copy();
.copy();
} }
public static ContainerHeldItem createPrintout( int id, Inventory inventory, HeldItemContainerData data ) public static ContainerHeldItem createPrintout( int id, Inventory inventory, HeldItemContainerData data )
{ {
return new ContainerHeldItem( ComputerCraftRegistry.ModContainers.PRINTOUT, id, inventory.player, data.getHand() ); return new ContainerHeldItem( Registry.ModContainers.PRINTOUT, id, inventory.player, data.getHand() );
} }
@Nonnull @Nonnull
@@ -50,10 +48,7 @@ public class ContainerHeldItem extends AbstractContainerMenu
@Override @Override
public boolean stillValid( @Nonnull Player player ) public boolean stillValid( @Nonnull Player player )
{ {
if( !player.isAlive() ) if( !player.isAlive() ) return false;
{
return false;
}
ItemStack stack = player.getItemInHand( hand ); ItemStack stack = player.getItemInHand( hand );
return stack == this.stack || !stack.isEmpty() && !this.stack.isEmpty() && stack.getItem() == this.stack.getItem(); return stack == this.stack || !stack.isEmpty() && !this.stack.isEmpty() && stack.getItem() == this.stack.getItem();

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.common; package dan200.computercraft.shared.common;
import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
@@ -24,11 +23,9 @@ public class DefaultBundledRedstoneProvider implements IBundledRedstoneProvider
public static int getDefaultBundledRedstoneOutput( Level world, BlockPos pos, Direction side ) public static int getDefaultBundledRedstoneOutput( Level world, BlockPos pos, Direction side )
{ {
Block block = world.getBlockState( pos ) Block block = world.getBlockState( pos ).getBlock();
.getBlock(); if( block instanceof IBundledRedstoneBlock generic )
if( block instanceof IBundledRedstoneBlock )
{ {
IBundledRedstoneBlock generic = (IBundledRedstoneBlock) block;
if( generic.getBundledRedstoneConnectivity( world, pos, side ) ) if( generic.getBundledRedstoneConnectivity( world, pos, side ) )
{ {
return generic.getBundledRedstoneOutput( world, pos, side ); return generic.getBundledRedstoneOutput( world, pos, side );

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.common; package dan200.computercraft.shared.common;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
@@ -18,12 +17,6 @@ public interface IColouredItem
return getColourBasic( stack ); return getColourBasic( stack );
} }
static int getColourBasic( ItemStack stack )
{
CompoundTag tag = stack.getTag();
return tag != null && tag.contains( NBT_COLOUR ) ? tag.getInt( NBT_COLOUR ) : -1;
}
default ItemStack withColour( ItemStack stack, int colour ) default ItemStack withColour( ItemStack stack, int colour )
{ {
ItemStack copy = stack.copy(); ItemStack copy = stack.copy();
@@ -31,20 +24,22 @@ public interface IColouredItem
return copy; return copy;
} }
static int getColourBasic( ItemStack stack )
{
CompoundTag tag = stack.getTag();
return tag != null && tag.contains( NBT_COLOUR ) ? tag.getInt( NBT_COLOUR ) : -1;
}
static void setColourBasic( ItemStack stack, int colour ) static void setColourBasic( ItemStack stack, int colour )
{ {
if( colour == -1 ) if( colour == -1 )
{ {
CompoundTag tag = stack.getTag(); CompoundTag tag = stack.getTag();
if( tag != null ) if( tag != null ) tag.remove( NBT_COLOUR );
{
tag.remove( NBT_COLOUR );
}
} }
else else
{ {
stack.getOrCreateTag() stack.getOrCreateTag().putInt( NBT_COLOUR, colour );
.putInt( NBT_COLOUR, colour );
} }
} }
} }

View File

@@ -3,20 +3,18 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.common; package dan200.computercraft.shared.common;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.network.client.TerminalState; import dan200.computercraft.shared.network.client.TerminalState;
import net.minecraft.nbt.CompoundTag;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
public class ServerTerminal implements ITerminal public class ServerTerminal implements ITerminal
{ {
private final boolean colour; private final boolean colour;
private final AtomicBoolean terminalChanged = new AtomicBoolean( false );
private Terminal terminal; private Terminal terminal;
private final AtomicBoolean terminalChanged = new AtomicBoolean( false );
private boolean terminalChangedLastFrame = false; private boolean terminalChangedLastFrame = false;
public ServerTerminal( boolean colour ) public ServerTerminal( boolean colour )
@@ -31,11 +29,6 @@ public class ServerTerminal implements ITerminal
terminal = new Terminal( terminalWidth, terminalHeight, this::markTerminalChanged ); terminal = new Terminal( terminalWidth, terminalHeight, this::markTerminalChanged );
} }
protected void markTerminalChanged()
{
terminalChanged.set( true );
}
protected void resize( int width, int height ) protected void resize( int width, int height )
{ {
if( terminal == null ) if( terminal == null )
@@ -58,6 +51,11 @@ public class ServerTerminal implements ITerminal
} }
} }
protected void markTerminalChanged()
{
terminalChanged.set( true );
}
public void update() public void update()
{ {
terminalChangedLastFrame = terminalChanged.getAndSet( false ); terminalChangedLastFrame = terminalChanged.getAndSet( false );
@@ -84,17 +82,4 @@ public class ServerTerminal implements ITerminal
{ {
return new TerminalState( colour, terminal ); return new TerminalState( colour, terminal );
} }
public void writeDescription( CompoundTag nbt )
{
nbt.putBoolean( "colour", colour );
if( terminal != null )
{
CompoundTag terminal = new CompoundTag();
terminal.putInt( "term_width", this.terminal.getWidth() );
terminal.putInt( "term_height", this.terminal.getHeight() );
this.terminal.writeToNBT( terminal );
nbt.put( "terminal", terminal );
}
}
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.common; package dan200.computercraft.shared.common;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@@ -14,6 +13,7 @@ import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
@@ -33,6 +33,7 @@ public abstract class TileGeneric extends BlockEntity
{ {
} }
// This is called by fabric event hook in ComputerCraftProxyCommon
public void onChunkUnloaded() public void onChunkUnloaded()
{ {
} }
@@ -42,7 +43,7 @@ public abstract class TileGeneric extends BlockEntity
setChanged(); setChanged();
BlockPos pos = getBlockPos(); BlockPos pos = getBlockPos();
BlockState state = getBlockState(); BlockState state = getBlockState();
getLevel().sendBlockUpdated( pos, state, state, 3 ); getLevel().sendBlockUpdated( pos, state, state, Block.UPDATE_ALL );
} }
@Nonnull @Nonnull
@@ -70,26 +71,19 @@ public abstract class TileGeneric extends BlockEntity
public boolean isUsable( Player player, boolean ignoreRange ) public boolean isUsable( Player player, boolean ignoreRange )
{ {
if( player == null || !player.isAlive() || getLevel().getBlockEntity( getBlockPos() ) != this ) if( player == null || !player.isAlive() || getLevel().getBlockEntity( getBlockPos() ) != this ) return false;
{ if( ignoreRange ) return true;
return false;
}
if( ignoreRange )
{
return true;
}
double range = getInteractRange( player ); double range = getInteractRange( player );
BlockPos pos = getBlockPos(); BlockPos pos = getBlockPos();
return player.getCommandSenderWorld() == getLevel() && player.distanceToSqr( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ) <= range * range; return player.getCommandSenderWorld() == getLevel() &&
player.distanceToSqr( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ) <= range * range;
} }
@Override @Override
public CompoundTag getUpdateTag() public CompoundTag getUpdateTag()
{ {
CompoundTag nbt = new CompoundTag(); return this.saveWithoutMetadata();
writeDescription( nbt );
return nbt;
} }
@Nullable @Nullable

View File

@@ -3,31 +3,32 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.apis; package dan200.computercraft.shared.computer.apis;
import com.google.common.collect.ImmutableMap;
import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode; import com.mojang.brigadier.tree.LiteralCommandNode;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.*; import dan200.computercraft.api.lua.*;
import dan200.computercraft.shared.computer.blocks.TileCommandComputer; import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
import dan200.computercraft.shared.peripheral.generic.data.BlockData;
import dan200.computercraft.shared.util.NBTUtil; import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands; import net.minecraft.commands.Commands;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Property;
import javax.annotation.Nonnull;
import java.util.*; import java.util.*;
/** /**
* @cc.module commands * @cc.module commands
* @cc.since 1.7
*/ */
public class CommandAPI implements ILuaAPI public class CommandAPI implements ILuaAPI
{ {
@@ -44,29 +45,14 @@ public class CommandAPI implements ILuaAPI
return new String[] { "commands" }; return new String[] { "commands" };
} }
/** private static Object createOutput( String output )
* Execute a specific command.
*
* @param command The command to execute.
* @return See {@code cc.treturn}.
* @cc.treturn boolean Whether the command executed successfully.
* @cc.treturn { string... } The output of this command, as a list of lines.
* @cc.treturn number|nil The number of "affected" objects, or `nil` if the command failed. The definition of this varies from command to command.
* @cc.usage Set the block above the command computer to stone.
* <pre>
* commands.exec("setblock ~ ~1 ~ minecraft:stone")
* </pre>
*/
@LuaFunction( mainThread = true )
public final Object[] exec( String command )
{ {
return doCommand( command ); return new Object[] { output };
} }
private Object[] doCommand( String command ) private Object[] doCommand( String command )
{ {
MinecraftServer server = computer.getLevel() MinecraftServer server = computer.getLevel().getServer();
.getServer();
if( server == null || !server.isCommandBlockEnabled() ) if( server == null || !server.isCommandBlockEnabled() )
{ {
return new Object[] { false, createOutput( "Command blocks disabled by server" ) }; return new Object[] { false, createOutput( "Command blocks disabled by server" ) };
@@ -82,36 +68,64 @@ public class CommandAPI implements ILuaAPI
} }
catch( Throwable t ) catch( Throwable t )
{ {
if( ComputerCraft.logComputerErrors ) if( ComputerCraft.logComputerErrors ) ComputerCraft.log.error( "Error running command.", t );
{
ComputerCraft.log.error( "Error running command.", t );
}
return new Object[] { false, createOutput( "Java Exception Thrown: " + t ) }; return new Object[] { false, createOutput( "Java Exception Thrown: " + t ) };
} }
} }
private static Object createOutput( String output ) private static Map<?, ?> getBlockInfo( Level world, BlockPos pos )
{ {
return new Object[] { output }; // Get the details of the block
BlockState state = world.getBlockState( pos );
Map<String, Object> table = BlockData.fill( new HashMap<>(), state );
BlockEntity tile = world.getBlockEntity( pos );
if( tile != null ) table.put( "nbt", NBTUtil.toLua( tile.saveWithFullMetadata() ) );
return table;
}
/**
* Execute a specific command.
*
* @param command The command to execute.
* @return See {@code cc.treturn}.
* @cc.treturn boolean Whether the command executed successfully.
* @cc.treturn { string... } The output of this command, as a list of lines.
* @cc.treturn number|nil The number of "affected" objects, or `nil` if the command failed. The definition of this
* varies from command to command.
* @cc.changed 1.71 Added return value with command output.
* @cc.changed 1.85.0 Added return value with the number of affected objects.
* @cc.usage Set the block above the command computer to stone.
* <pre>{@code
* commands.exec("setblock ~ ~1 ~ minecraft:stone")
* }</pre>
*/
@LuaFunction( mainThread = true )
public final Object[] exec( String command )
{
return doCommand( command );
} }
/** /**
* Asynchronously execute a command. * Asynchronously execute a command.
* *
* Unlike {@link #exec}, this will immediately return, instead of waiting for the command to execute. This allows you to run multiple commands at the * Unlike {@link #exec}, this will immediately return, instead of waiting for the
* same time. * command to execute. This allows you to run multiple commands at the same
* time.
* *
* When this command has finished executing, it will queue a `task_complete` event containing the result of executing this command (what {@link #exec} * When this command has finished executing, it will queue a `task_complete`
* would return). * event containing the result of executing this command (what {@link #exec} would
* return).
* *
* @param context The context this command executes under. * @param context The context this command executes under.
* @param command The command to execute. * @param command The command to execute.
* @return The "task id". When this command has been executed, it will queue a `task_complete` event with a matching id. * @return The "task id". When this command has been executed, it will queue a `task_complete` event with a matching id.
* @throws LuaException (hidden) If the task cannot be created. * @throws LuaException (hidden) If the task cannot be created.
* @cc.usage Asynchronously sets the block above the computer to stone. * @cc.usage Asynchronously sets the block above the computer to stone.
* <pre> * <pre>{@code
* commands.execAsync("~ ~1 ~ minecraft:stone") * commands.execAsync("setblock ~ ~1 ~ minecraft:stone")
* </pre> * }</pre>
* @cc.see parallel One may also use the parallel API to run multiple commands at once. * @cc.see parallel One may also use the parallel API to run multiple commands at once.
*/ */
@LuaFunction @LuaFunction
@@ -131,33 +145,21 @@ public class CommandAPI implements ILuaAPI
@LuaFunction( mainThread = true ) @LuaFunction( mainThread = true )
public final List<String> list( IArguments args ) throws LuaException public final List<String> list( IArguments args ) throws LuaException
{ {
MinecraftServer server = computer.getLevel() MinecraftServer server = computer.getLevel().getServer();
.getServer();
if( server == null ) if( server == null ) return Collections.emptyList();
{ CommandNode<CommandSourceStack> node = server.getCommands().getDispatcher().getRoot();
return Collections.emptyList();
}
CommandNode<CommandSourceStack> node = server.getCommands()
.getDispatcher()
.getRoot();
for( int j = 0; j < args.count(); j++ ) for( int j = 0; j < args.count(); j++ )
{ {
String name = args.getString( j ); String name = args.getString( j );
node = node.getChild( name ); node = node.getChild( name );
if( !(node instanceof LiteralCommandNode) ) if( !(node instanceof LiteralCommandNode) ) return Collections.emptyList();
{
return Collections.emptyList();
}
} }
List<String> result = new ArrayList<>(); List<String> result = new ArrayList<>();
for( CommandNode<?> child : node.getChildren() ) for( CommandNode<?> child : node.getChildren() )
{ {
if( child instanceof LiteralCommandNode<?> ) if( child instanceof LiteralCommandNode<?> ) result.add( child.getName() );
{
result.add( child.getName() );
}
} }
return result; return result;
} }
@@ -182,37 +184,47 @@ public class CommandAPI implements ILuaAPI
/** /**
* Get information about a range of blocks. * Get information about a range of blocks.
* *
* This returns the same information as @{getBlockInfo}, just for multiple blocks at once. * This returns the same information as @{getBlockInfo}, just for multiple
* blocks at once.
* *
* Blocks are traversed by ascending y level, followed by z and x - the returned table may be indexed using `x + z*width + y*depth*depth`. * Blocks are traversed by ascending y level, followed by z and x - the returned
* table may be indexed using `x + z*width + y*depth*depth`.
* *
* @param minX The start x coordinate of the range to query. * @param minX The start x coordinate of the range to query.
* @param minY The start y coordinate of the range to query. * @param minY The start y coordinate of the range to query.
* @param minZ The start z coordinate of the range to query. * @param minZ The start z coordinate of the range to query.
* @param maxX The end x coordinate of the range to query. * @param maxX The end x coordinate of the range to query.
* @param maxY The end y coordinate of the range to query. * @param maxY The end y coordinate of the range to query.
* @param maxZ The end z coordinate of the range to query. * @param maxZ The end z coordinate of the range to query.
* @param dimension The dimension to query (e.g. "minecraft:overworld"). Defaults to the current dimension.
* @return A list of information about each block. * @return A list of information about each block.
* @throws LuaException If the coordinates are not within the world. * @throws LuaException If the coordinates are not within the world.
* @throws LuaException If trying to get information about more than 4096 blocks. * @throws LuaException If trying to get information about more than 4096 blocks.
* @cc.since 1.76
* @cc.changed 1.99 Added {@code dimension} argument.
*/ */
@LuaFunction( mainThread = true ) @LuaFunction( mainThread = true )
public final List<Map<?, ?>> getBlockInfos( int minX, int minY, int minZ, int maxX, int maxY, int maxZ ) throws LuaException public final List<Map<?, ?>> getBlockInfos( int minX, int minY, int minZ, int maxX, int maxY, int maxZ, Optional<String> dimension ) throws LuaException
{ {
// Get the details of the block // Get the details of the block
Level world = computer.getLevel(); Level world = getLevel( dimension );
BlockPos min = new BlockPos( Math.min( minX, maxX ), Math.min( minY, maxY ), Math.min( minZ, maxZ ) ); BlockPos min = new BlockPos(
BlockPos max = new BlockPos( Math.max( minX, maxX ), Math.max( minY, maxY ), Math.max( minZ, maxZ ) ); Math.min( minX, maxX ),
if( !world.isInWorldBounds( min ) || !world.isInWorldBounds( max ) ) Math.min( minY, maxY ),
Math.min( minZ, maxZ )
);
BlockPos max = new BlockPos(
Math.max( minX, maxX ),
Math.max( minY, maxY ),
Math.max( minZ, maxZ )
);
if( world == null || !world.isInWorldBounds( min ) || !world.isInWorldBounds( max ) )
{ {
throw new LuaException( "Co-ordinates out of range" ); throw new LuaException( "Co-ordinates out of range" );
} }
int blocks = (max.getX() - min.getX() + 1) * (max.getY() - min.getY() + 1) * (max.getZ() - min.getZ() + 1); int blocks = (max.getX() - min.getX() + 1) * (max.getY() - min.getY() + 1) * (max.getZ() - min.getZ() + 1);
if( blocks > 4096 ) if( blocks > 4096 ) throw new LuaException( "Too many blocks" );
{
throw new LuaException( "Too many blocks" );
}
List<Map<?, ?>> results = new ArrayList<>( blocks ); List<Map<?, ?>> results = new ArrayList<>( blocks );
for( int y = min.getY(); y <= max.getY(); y++ ) for( int y = min.getY(); y <= max.getY(); y++ )
@@ -230,71 +242,45 @@ public class CommandAPI implements ILuaAPI
return results; return results;
} }
private static Map<?, ?> getBlockInfo( Level world, BlockPos pos )
{
// Get the details of the block
BlockState state = world.getBlockState( pos );
Block block = state.getBlock();
Map<Object, Object> table = new HashMap<>();
table.put( "name", Registry.BLOCK.getKey( block ).toString() );
table.put( "world", world.dimension() );
Map<Object, Object> stateTable = new HashMap<>();
for( ImmutableMap.Entry<Property<?>, Comparable<?>> entry : state.getValues().entrySet() )
{
Property<?> property = entry.getKey();
stateTable.put( property.getName(), getPropertyValue( property, entry.getValue() ) );
}
table.put( "state", stateTable );
BlockEntity tile = world.getBlockEntity( pos );
if( tile != null )
{
table.put( "nbt", NBTUtil.toLua( tile.saveWithFullMetadata() ) );
}
return table;
}
@SuppressWarnings( {
"unchecked",
"rawtypes"
} )
private static Object getPropertyValue( Property property, Comparable value )
{
if( value instanceof String || value instanceof Number || value instanceof Boolean )
{
return value;
}
return property.getName( value );
}
/** /**
* Get some basic information about a block. * Get some basic information about a block.
* *
* The returned table contains the current name, metadata and block state (as with @{turtle.inspect}). If there is a tile entity for that block, its NBT * The returned table contains the current name, metadata and block state (as
* with @{turtle.inspect}). If there is a tile entity for that block, its NBT
* will also be returned. * will also be returned.
* *
* @param x The x position of the block to query. * @param x The x position of the block to query.
* @param y The y position of the block to query. * @param y The y position of the block to query.
* @param z The z position of the block to query. * @param z The z position of the block to query.
* @param dimension The dimension to query (e.g. "minecraft:overworld"). Defaults to the current dimension.
* @return The given block's information. * @return The given block's information.
* @throws LuaException If the coordinates are not within the world, or are not currently loaded. * @throws LuaException If the coordinates are not within the world, or are not currently loaded.
* @cc.changed 1.76 Added block state info to return value
* @cc.changed 1.99 Added {@code dimension} argument.
*/ */
@LuaFunction( mainThread = true ) @LuaFunction( mainThread = true )
public final Map<?, ?> getBlockInfo( int x, int y, int z ) throws LuaException public final Map<?, ?> getBlockInfo( int x, int y, int z, Optional<String> dimension ) throws LuaException
{ {
// Get the details of the block Level level = getLevel( dimension );
Level world = computer.getLevel();
BlockPos position = new BlockPos( x, y, z ); BlockPos position = new BlockPos( x, y, z );
if( world.isInWorldBounds( position ) ) if( !level.isInWorldBounds( position ) ) throw new LuaException( "Co-ordinates out of range" );
{ return getBlockInfo( level, position );
return getBlockInfo( world, position ); }
}
else @Nonnull
{ private Level getLevel( @Nonnull Optional<String> id ) throws LuaException
throw new LuaException( "Co-ordinates out of range" ); {
} Level currentLevel = computer.getLevel();
if( currentLevel == null ) throw new LuaException( "No world exists" );
if( !id.isPresent() ) return currentLevel;
ResourceLocation dimensionId = ResourceLocation.tryParse( id.get() );
if( dimensionId == null ) throw new LuaException( "Invalid dimension name" );
Level level = currentLevel.getServer().getLevel( ResourceKey.create( Registry.DIMENSION_REGISTRY, dimensionId ) );
if( level == null ) throw new LuaException( "Unknown dimension" );
return level;
} }
} }

View File

@@ -3,19 +3,15 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.blocks; package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.shared.ComputerCraftRegistry;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.computer.items.ComputerItemFactory; import dan200.computercraft.shared.computer.items.ComputerItemFactory;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.StateDefinition;
@@ -25,26 +21,20 @@ import net.minecraft.world.level.block.state.properties.EnumProperty;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.function.Supplier;
public class BlockComputer extends BlockComputerBase<TileComputer> public class BlockComputer<T extends TileComputer> extends BlockComputerBase<T>
{ {
public static final EnumProperty<ComputerState> STATE = EnumProperty.create( "state", ComputerState.class ); public static final EnumProperty<ComputerState> STATE = EnumProperty.create( "state", ComputerState.class );
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
public BlockComputer( Properties settings, ComputerFamily family, BlockEntityType<? extends TileComputer> type ) public BlockComputer( Properties settings, ComputerFamily family, Supplier<BlockEntityType<T>> type )
{ {
super( settings, family, type ); super( settings, family, type );
registerDefaultState( defaultBlockState().setValue( FACING, Direction.NORTH ) registerDefaultState( defaultBlockState()
.setValue( STATE, ComputerState.OFF ) ); .setValue( FACING, Direction.NORTH )
} .setValue( STATE, ComputerState.OFF )
);
@Nullable
@Override
public BlockState getStateForPlacement( BlockPlaceContext placement )
{
return defaultBlockState().setValue( FACING,
placement.getHorizontalDirection()
.getOpposite() );
} }
@Override @Override
@@ -53,27 +43,17 @@ public class BlockComputer extends BlockComputerBase<TileComputer>
builder.add( FACING, STATE ); builder.add( FACING, STATE );
} }
@Nullable
@Override
public BlockState getStateForPlacement( BlockPlaceContext placement )
{
return defaultBlockState().setValue( FACING, placement.getHorizontalDirection().getOpposite() );
}
@Nonnull @Nonnull
@Override @Override
protected ItemStack getItem( TileComputerBase tile ) protected ItemStack getItem( TileComputerBase tile )
{ {
return tile instanceof TileComputer ? ComputerItemFactory.create( (TileComputer) tile ) : ItemStack.EMPTY; return tile instanceof TileComputer ? ComputerItemFactory.create( (TileComputer) tile ) : ItemStack.EMPTY;
} }
public BlockEntityType<? extends TileComputer> getTypeByFamily( ComputerFamily family )
{
return switch( family )
{
case COMMAND -> ComputerCraftRegistry.ModTiles.COMPUTER_COMMAND;
case ADVANCED -> ComputerCraftRegistry.ModTiles.COMPUTER_ADVANCED;
default -> ComputerCraftRegistry.ModTiles.COMPUTER_NORMAL;
};
}
@Nullable
@Override
public BlockEntity newBlockEntity( BlockPos pos, BlockState state )
{
return new TileComputer( getFamily(), getTypeByFamily( getFamily() ), pos, state );
}
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.blocks; package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
@@ -23,6 +22,7 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
@@ -33,17 +33,21 @@ import net.minecraft.world.phys.Vec3;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.function.Supplier;
public abstract class BlockComputerBase<T extends TileComputerBase> extends BlockGeneric implements IBundledRedstoneBlock public abstract class BlockComputerBase<T extends TileComputerBase> extends BlockGeneric implements IBundledRedstoneBlock
{ {
private static final ResourceLocation DROP = new ResourceLocation( ComputerCraft.MOD_ID, "computer" ); private static final ResourceLocation DROP = new ResourceLocation( ComputerCraft.MOD_ID, "computer" );
private final ComputerFamily family; private final ComputerFamily family;
protected final Supplier<BlockEntityType<T>> type;
private final BlockEntityTicker<T> serverTicker = ( level, pos, state, computer ) -> computer.serverTick();
protected BlockComputerBase( Properties settings, ComputerFamily family, BlockEntityType<? extends T> type ) protected BlockComputerBase( Properties settings, ComputerFamily family, Supplier<BlockEntityType<T>> type )
{ {
super( settings, type ); super( settings, type );
this.family = family; this.family = family;
this.type = type;
} }
@Override @Override
@@ -53,10 +57,7 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
super.onPlace( state, world, pos, oldState, isMoving ); super.onPlace( state, world, pos, oldState, isMoving );
BlockEntity tile = world.getBlockEntity( pos ); BlockEntity tile = world.getBlockEntity( pos );
if( tile instanceof TileComputerBase ) if( tile instanceof TileComputerBase computer ) computer.updateInputsImmediately();
{
((TileComputerBase) tile).updateInput();
}
} }
@Override @Override
@@ -66,39 +67,35 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
return true; return true;
} }
@Override
@Deprecated
public int getSignal( @Nonnull BlockState state, @Nonnull BlockGetter world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide )
{
return getDirectSignal( state, world, pos, incomingSide );
}
@Override @Override
@Deprecated @Deprecated
public int getDirectSignal( @Nonnull BlockState state, BlockGetter world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide ) public int getDirectSignal( @Nonnull BlockState state, BlockGetter world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide )
{ {
BlockEntity entity = world.getBlockEntity( pos ); BlockEntity entity = world.getBlockEntity( pos );
if( !(entity instanceof TileComputerBase) ) if( !(entity instanceof TileComputerBase computerEntity) ) return 0;
{
return 0;
}
TileComputerBase computerEntity = (TileComputerBase) entity;
ServerComputer computer = computerEntity.getServerComputer(); ServerComputer computer = computerEntity.getServerComputer();
if( computer == null ) if( computer == null ) return 0;
{
return 0;
}
ComputerSide localSide = computerEntity.remapToLocalSide( incomingSide.getOpposite() ); ComputerSide localSide = computerEntity.remapToLocalSide( incomingSide.getOpposite() );
return computer.getRedstoneOutput( localSide ); return computer.getRedstoneOutput( localSide );
} }
@Nonnull
protected abstract ItemStack getItem( TileComputerBase tile );
public ComputerFamily getFamily() public ComputerFamily getFamily()
{ {
return family; return family;
} }
@Override
@Deprecated
public int getSignal( @Nonnull BlockState state, @Nonnull BlockGetter world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide )
{
return getDirectSignal( state, world, pos, incomingSide );
}
@Override @Override
public boolean getBundledRedstoneConnectivity( Level world, BlockPos pos, Direction side ) public boolean getBundledRedstoneConnectivity( Level world, BlockPos pos, Direction side )
{ {
@@ -109,56 +106,15 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
public int getBundledRedstoneOutput( Level world, BlockPos pos, Direction side ) public int getBundledRedstoneOutput( Level world, BlockPos pos, Direction side )
{ {
BlockEntity entity = world.getBlockEntity( pos ); BlockEntity entity = world.getBlockEntity( pos );
if( !(entity instanceof TileComputerBase) ) if( !(entity instanceof TileComputerBase computerEntity) ) return 0;
{
return 0;
}
TileComputerBase computerEntity = (TileComputerBase) entity;
ServerComputer computer = computerEntity.getServerComputer(); ServerComputer computer = computerEntity.getServerComputer();
if( computer == null ) if( computer == null ) return 0;
{
return 0;
}
ComputerSide localSide = computerEntity.remapToLocalSide( side ); ComputerSide localSide = computerEntity.remapToLocalSide( side );
return computer.getBundledRedstoneOutput( localSide ); return computer.getBundledRedstoneOutput( localSide );
} }
@Override
public void playerDestroy( @Nonnull Level world, Player player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable BlockEntity tile,
@Nonnull ItemStack tool )
{
// Don't drop blocks here - see onBlockHarvested.
player.awardStat( Stats.BLOCK_MINED.get( this ) );
player.causeFoodExhaustion( 0.005F );
}
@Override
public void setPlacedBy( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, @Nonnull ItemStack stack )
{
super.setPlacedBy( world, pos, state, placer, stack );
BlockEntity tile = world.getBlockEntity( pos );
if( !world.isClientSide && tile instanceof IComputerTile && stack.getItem() instanceof IComputerItem )
{
IComputerTile computer = (IComputerTile) tile;
IComputerItem item = (IComputerItem) stack.getItem();
int id = item.getComputerID( stack );
if( id != -1 )
{
computer.setComputerID( id );
}
String label = item.getLabel( stack );
if( label != null )
{
computer.setLabel( label );
}
}
}
@Nonnull @Nonnull
@Override @Override
public ItemStack getCloneItemStack( BlockGetter world, BlockPos pos, BlockState state ) public ItemStack getCloneItemStack( BlockGetter world, BlockPos pos, BlockState state )
@@ -167,38 +123,33 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
if( tile instanceof TileComputerBase ) if( tile instanceof TileComputerBase )
{ {
ItemStack result = getItem( (TileComputerBase) tile ); ItemStack result = getItem( (TileComputerBase) tile );
if( !result.isEmpty() ) if( !result.isEmpty() ) return result;
{
return result;
}
} }
return super.getCloneItemStack( world, pos, state ); return super.getCloneItemStack( world, pos, state );
} }
@Nonnull @Override
protected abstract ItemStack getItem( TileComputerBase tile ); public void playerDestroy( @Nonnull Level world, Player player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable BlockEntity tile, @Nonnull ItemStack tool )
{
// Don't drop blocks here - see onBlockHarvested.
player.awardStat( Stats.BLOCK_MINED.get( this ) );
player.causeFoodExhaustion( 0.005F );
}
@Override @Override
public void playerWillDestroy( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull Player player ) public void playerWillDestroy( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull Player player )
{ {
// Call super as it is what provides sound and block break particles. Does not do anything else. if( !(world instanceof ServerLevel serverWorld) ) return;
super.playerWillDestroy( world, pos, state, player );
if( !(world instanceof ServerLevel) )
{
return;
}
ServerLevel serverWorld = (ServerLevel) world;
// We drop the item here instead of doing it in the harvest method, as we should // We drop the item here instead of doing it in the harvest method, as we should
// drop computers for creative players too. // drop computers for creative players too.
BlockEntity tile = world.getBlockEntity( pos ); BlockEntity tile = world.getBlockEntity( pos );
if( tile instanceof TileComputerBase ) if( tile instanceof TileComputerBase computer )
{ {
TileComputerBase computer = (TileComputerBase) tile; LootContext.Builder context = new LootContext.Builder( serverWorld )
LootContext.Builder context = new LootContext.Builder( serverWorld ).withRandom( world.random ) .withRandom( world.random )
.withParameter( LootContextParams.ORIGIN, Vec3.atCenterOf( pos ) ) .withParameter( LootContextParams.ORIGIN, Vec3.atCenterOf( pos ) )
.withParameter( LootContextParams.TOOL, player.getMainHandItem() ) .withParameter( LootContextParams.TOOL, player.getMainHandItem() )
.withParameter( LootContextParams.THIS_ENTITY, player ) .withParameter( LootContextParams.THIS_ENTITY, player )
@@ -213,15 +164,27 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
} }
} }
@Nullable
@Override @Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker( Level world, BlockState state, BlockEntityType<T> type ) public void setPlacedBy( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, @Nonnull ItemStack stack )
{ {
return world.isClientSide ? null : ( world1, pos, state1, tile ) -> { super.setPlacedBy( world, pos, state, placer, stack );
if( tile instanceof TileComputerBase computer )
{ BlockEntity tile = world.getBlockEntity( pos );
computer.serverTick(); if( !world.isClientSide && tile instanceof IComputerTile computer && stack.getItem() instanceof IComputerItem item )
} {
};
int id = item.getComputerID( stack );
if( id != -1 ) computer.setComputerID( id );
String label = item.getLabel( stack );
if( label != null ) computer.setLabel( label );
}
}
@Override
@Nullable
public <U extends BlockEntity> BlockEntityTicker<U> getTicker( @Nonnull Level level, @Nonnull BlockState state, @Nonnull BlockEntityType<U> type )
{
return level.isClientSide ? null : BaseEntityBlock.createTickerHelper( type, this.type.get(), serverTicker );
} }
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.blocks; package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.lua.LuaFunction;
@@ -16,8 +15,8 @@ import javax.annotation.Nullable;
/** /**
* A computer or turtle wrapped as a peripheral. * A computer or turtle wrapped as a peripheral.
* *
* This allows for basic interaction with adjacent computers. Computers wrapped as peripherals will have the type {@code computer} while turtles will be * This allows for basic interaction with adjacent computers. Computers wrapped as peripherals will have the type
* {@code turtle}. * {@code computer} while turtles will be {@code turtle}.
* *
* @cc.module computer * @cc.module computer
*/ */
@@ -39,19 +38,6 @@ public class ComputerPeripheral implements IPeripheral
return type; return type;
} }
@Nonnull
@Override
public Object getTarget()
{
return computer.getTile();
}
@Override
public boolean equals( IPeripheral other )
{
return other instanceof ComputerPeripheral && computer == ((ComputerPeripheral) other).computer;
}
/** /**
* Turn the other computer on. * Turn the other computer on.
*/ */
@@ -114,4 +100,17 @@ public class ComputerPeripheral implements IPeripheral
{ {
return computer.getLabel(); return computer.getLabel();
} }
@Override
public boolean equals( IPeripheral other )
{
return other instanceof ComputerPeripheral && computer == ((ComputerPeripheral) other).computer;
}
@Nonnull
@Override
public Object getTarget()
{
return computer.getTile();
}
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.blocks; package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IComputer;
@@ -14,7 +13,7 @@ import java.util.function.Supplier;
/** /**
* A proxy object for computer objects, delegating to {@link IComputer} or {@link TileComputer} where appropriate. * A proxy object for computer objects, delegating to {@link IComputer} or {@link TileComputer} where appropriate.
*/ */
public class ComputerProxy public final class ComputerProxy
{ {
private final Supplier<TileComputerBase> get; private final Supplier<TileComputerBase> get;
@@ -23,6 +22,11 @@ public class ComputerProxy
this.get = get; this.get = get;
} }
TileComputerBase getTile()
{
return get.get();
}
public void turnOn() public void turnOn()
{ {
TileComputerBase tile = getTile(); TileComputerBase tile = getTile();
@@ -37,11 +41,6 @@ public class ComputerProxy
} }
} }
protected TileComputerBase getTile()
{
return get.get();
}
public void shutdown() public void shutdown()
{ {
TileComputerBase tile = getTile(); TileComputerBase tile = getTile();

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.blocks; package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
@@ -32,75 +31,6 @@ import java.util.UUID;
public class TileCommandComputer extends TileComputer public class TileCommandComputer extends TileComputer
{ {
private final CommandReceiver receiver;
public TileCommandComputer( ComputerFamily family, BlockEntityType<? extends TileCommandComputer> type, BlockPos pos, BlockState state )
{
super( family, type, pos, state );
receiver = new CommandReceiver();
}
public CommandReceiver getReceiver()
{
return receiver;
}
public CommandSourceStack getSource()
{
ServerComputer computer = getServerComputer();
String name = "@";
if( computer != null )
{
String label = computer.getLabel();
if( label != null )
{
name = label;
}
}
return new CommandSourceStack( receiver,
new Vec3( worldPosition.getX() + 0.5, worldPosition.getY() + 0.5, worldPosition.getZ() + 0.5 ),
Vec2.ZERO,
(ServerLevel) getLevel(),
2,
name,
new TextComponent( name ),
getLevel().getServer(),
null );
}
@Override
protected ServerComputer createComputer( int instanceID, int id )
{
ServerComputer computer = super.createComputer( instanceID, id );
computer.addAPI( new CommandAPI( this ) );
return computer;
}
@Override
public boolean isUsable( Player player, boolean ignoreRange )
{
return isUsable( player ) && super.isUsable( player, ignoreRange );
}
public static boolean isUsable( Player player )
{
MinecraftServer server = player.getServer();
if( server == null || !server.isCommandBlockEnabled() )
{
player.displayClientMessage( new TranslatableComponent( "advMode.notEnabled" ), true );
return false;
}
else if( ComputerCraft.commandRequireCreative ? !player.canUseGameMasterBlocks() : !server.getPlayerList()
.isOp( player.getGameProfile() ) )
{
player.displayClientMessage( new TranslatableComponent( "advMode.notAllowed" ), true );
return false;
}
return true;
}
public class CommandReceiver implements CommandSource public class CommandReceiver implements CommandSource
{ {
private final Map<Integer, String> output = new HashMap<>(); private final Map<Integer, String> output = new HashMap<>();
@@ -129,8 +59,7 @@ public class TileCommandComputer extends TileComputer
@Override @Override
public boolean acceptsSuccess() public boolean acceptsSuccess()
{ {
return getLevel().getGameRules() return true;
.getBoolean( GameRules.RULE_SENDCOMMANDFEEDBACK );
} }
@Override @Override
@@ -142,8 +71,69 @@ public class TileCommandComputer extends TileComputer
@Override @Override
public boolean shouldInformAdmins() public boolean shouldInformAdmins()
{ {
return getLevel().getGameRules() return getLevel().getGameRules().getBoolean( GameRules.RULE_COMMANDBLOCKOUTPUT );
.getBoolean( GameRules.RULE_COMMANDBLOCKOUTPUT );
} }
} }
private final CommandReceiver receiver;
public TileCommandComputer( BlockEntityType<? extends TileComputer> type, BlockPos pos, BlockState state )
{
super( type, pos, state, ComputerFamily.COMMAND );
receiver = new CommandReceiver();
}
public CommandReceiver getReceiver()
{
return receiver;
}
public CommandSourceStack getSource()
{
ServerComputer computer = getServerComputer();
String name = "@";
if( computer != null )
{
String label = computer.getLabel();
if( label != null ) name = label;
}
return new CommandSourceStack( receiver,
new Vec3( worldPosition.getX() + 0.5, worldPosition.getY() + 0.5, worldPosition.getZ() + 0.5 ), Vec2.ZERO,
(ServerLevel) getLevel(), 2,
name, new TextComponent( name ),
getLevel().getServer(), null
);
}
@Override
protected ServerComputer createComputer( int instanceID, int id )
{
ServerComputer computer = super.createComputer( instanceID, id );
computer.addAPI( new CommandAPI( this ) );
return computer;
}
@Override
public boolean isUsable( Player player, boolean ignoreRange )
{
return isUsable( player ) && super.isUsable( player, ignoreRange );
}
public static boolean isUsable( Player player )
{
MinecraftServer server = player.getServer();
if( server == null || !server.isCommandBlockEnabled() )
{
player.displayClientMessage( new TranslatableComponent( "advMode.notEnabled" ), true );
return false;
}
else if( ComputerCraft.commandRequireCreative ? !player.canUseGameMasterBlocks() : !server.getPlayerList().isOp( player.getGameProfile() ) )
{
player.displayClientMessage( new TranslatableComponent( "advMode.notAllowed" ), true );
return false;
}
return true;
}
} }

View File

@@ -3,12 +3,11 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.blocks; package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.Registry;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.core.ServerComputer;
@@ -28,16 +27,35 @@ public class TileComputer extends TileComputerBase
{ {
private ComputerProxy proxy; private ComputerProxy proxy;
public TileComputer( ComputerFamily family, BlockEntityType<? extends TileComputer> type, BlockPos pos, BlockState state ) public TileComputer( BlockEntityType<? extends TileComputer> type, BlockPos pos, BlockState state, ComputerFamily family )
{ {
super( type, family, pos, state ); super( type, pos, state, family );
} }
public boolean isUsableByPlayer( Player player ) @Override
protected ServerComputer createComputer( int instanceID, int id )
{
ComputerFamily family = getFamily();
ServerComputer computer = new ServerComputer(
getLevel(), id, label, instanceID, family,
ComputerCraft.computerTermWidth,
ComputerCraft.computerTermHeight
);
computer.setPosition( getBlockPos() );
return computer;
}
protected boolean isUsableByPlayer( Player player )
{ {
return isUsable( player, false ); return isUsable( player, false );
} }
@Override
public Direction getDirection()
{
return getBlockState().getValue( BlockComputer.FACING );
}
@Override @Override
protected void updateBlockState( ComputerState newState ) protected void updateBlockState( ComputerState newState )
{ {
@@ -48,64 +66,21 @@ public class TileComputer extends TileComputerBase
} }
} }
@Override
public Direction getDirection()
{
return getBlockState().getValue( BlockComputer.FACING );
}
@Override @Override
protected ComputerSide remapLocalSide( ComputerSide localSide ) protected ComputerSide remapLocalSide( ComputerSide localSide )
{ {
// For legacy reasons, computers invert the meaning of "left" and "right". A computer's front is facing // For legacy reasons, computers invert the meaning of "left" and "right". A computer's front is facing
// towards you, but a turtle's front is facing the other way. // towards you, but a turtle's front is facing the other way.
if( localSide == ComputerSide.RIGHT ) if( localSide == ComputerSide.RIGHT ) return ComputerSide.LEFT;
{ if( localSide == ComputerSide.LEFT ) return ComputerSide.RIGHT;
return ComputerSide.LEFT;
}
if( localSide == ComputerSide.LEFT )
{
return ComputerSide.RIGHT;
}
return localSide; return localSide;
} }
@Override
protected ServerComputer createComputer( int instanceID, int id )
{
ComputerFamily family = getFamily();
ServerComputer computer = new ServerComputer( getLevel(),
id, label,
instanceID,
family,
ComputerCraft.computerTermWidth,
ComputerCraft.computerTermHeight );
computer.setPosition( getBlockPos() );
return computer;
}
@Override
public ComputerProxy createProxy()
{
if( proxy == null )
{
proxy = new ComputerProxy( () -> this )
{
@Override
protected TileComputerBase getTile()
{
return TileComputer.this;
}
};
}
return proxy;
}
@Nullable @Nullable
@Override @Override
public AbstractContainerMenu createMenu( int id, @Nonnull Inventory inventory, @Nonnull Player player ) public AbstractContainerMenu createMenu( int id, @Nonnull Inventory inventory, @Nonnull Player player )
{ {
return new ComputerMenuWithoutInventory( ComputerCraftRegistry.ModContainers.COMPUTER, id, inventory, this::isUsableByPlayer, createServerComputer(), getFamily() ); return new ComputerMenuWithoutInventory( Registry.ModContainers.COMPUTER, id, inventory, this::isUsableByPlayer, createServerComputer(), getFamily() );
} }
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.blocks; package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
@@ -28,6 +27,7 @@ import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
@@ -35,9 +35,6 @@ import net.minecraft.world.Nameable;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items; import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.RedStoneWireBlock;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
@@ -46,26 +43,40 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Objects; import java.util.Objects;
public abstract class TileComputerBase extends TileGeneric implements IComputerTile, IPeripheralTile, Nameable, public abstract class TileComputerBase extends TileGeneric implements IComputerTile, IPeripheralTile, Nameable, ExtendedScreenHandlerFactory
ExtendedScreenHandlerFactory
{ {
private static final String NBT_ID = "ComputerId"; private static final String NBT_ID = "ComputerId";
private static final String NBT_LABEL = "Label"; private static final String NBT_LABEL = "Label";
private static final String NBT_ON = "On"; private static final String NBT_ON = "On";
private final ComputerFamily family;
protected String label = null;
boolean startOn = false;
private int instanceID = -1; private int instanceID = -1;
private int computerID = -1; private int computerID = -1;
protected String label = null;
private boolean on = false; private boolean on = false;
boolean startOn = false;
private boolean fresh = false; private boolean fresh = false;
public TileComputerBase( BlockEntityType<? extends TileGeneric> type, ComputerFamily family, BlockPos pos, BlockState state ) private int invalidSides = 0;
private final ComputerFamily family;
private ComputerProxy proxy;
public TileComputerBase( BlockEntityType<? extends TileGeneric> type, BlockPos pos, BlockState state, ComputerFamily family )
{ {
super( type, pos, state ); super( type, pos, state );
this.family = family; this.family = family;
} }
protected void unload()
{
if( instanceID >= 0 )
{
if( !getLevel().isClientSide ) ComputerCraft.serverComputerRegistry.remove( instanceID );
instanceID = -1;
}
}
@Override @Override
public void destroy() public void destroy()
{ {
@@ -82,16 +93,16 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
unload(); unload();
} }
protected void unload() @Override
public void setRemoved()
{ {
if( instanceID >= 0 ) unload();
{ super.setRemoved();
if( !getLevel().isClientSide ) }
{
ComputerCraft.serverComputerRegistry.remove( instanceID ); protected boolean canNameWithTag( Player player )
} {
instanceID = -1; return false;
}
} }
@Nonnull @Nonnull
@@ -104,8 +115,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
// Label to rename computer // Label to rename computer
if( !getLevel().isClientSide ) if( !getLevel().isClientSide )
{ {
setLabel( currentItem.getHoverName() setLabel( currentItem.getHoverName().getString() );
.getString() );
currentItem.shrink( 1 ); currentItem.shrink( 1 );
} }
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
@@ -124,162 +134,32 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
return InteractionResult.PASS; return InteractionResult.PASS;
} }
protected boolean canNameWithTag( Player player )
{
return false;
}
public ServerComputer createServerComputer()
{
if( getLevel().isClientSide )
{
return null;
}
boolean changed = false;
if( instanceID < 0 )
{
instanceID = ComputerCraft.serverComputerRegistry.getUnusedInstanceID();
changed = true;
}
if( !ComputerCraft.serverComputerRegistry.contains( instanceID ) )
{
ServerComputer computer = createComputer( instanceID, computerID );
ComputerCraft.serverComputerRegistry.add( instanceID, computer );
fresh = true;
changed = true;
}
if( changed )
{
updateBlock();
updateInput();
}
return ComputerCraft.serverComputerRegistry.get( instanceID );
}
public ServerComputer getServerComputer()
{
return getLevel().isClientSide ? null : ComputerCraft.serverComputerRegistry.get( instanceID );
}
protected abstract ServerComputer createComputer( int instanceID, int id );
public void updateInput()
{
if( getLevel() == null || getLevel().isClientSide )
{
return;
}
// Update all sides
ServerComputer computer = getServerComputer();
if( computer == null )
{
return;
}
BlockPos pos = computer.getPosition();
for( Direction dir : DirectionUtil.FACINGS )
{
updateSideInput( computer, dir, pos.relative( dir ) );
}
}
private void updateSideInput( ServerComputer computer, Direction dir, BlockPos offset )
{
Direction offsetSide = dir.getOpposite();
ComputerSide localDir = remapToLocalSide( dir );
computer.setRedstoneInput( localDir, getRedstoneInput( level, offset, dir ) );
computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getLevel(), offset, offsetSide ) );
if( !isPeripheralBlockedOnSide( localDir ) )
{
IPeripheral peripheral = Peripherals.getPeripheral( getLevel(), offset, offsetSide );
computer.setPeripheral( localDir, peripheral );
}
}
protected ComputerSide remapToLocalSide( Direction globalSide )
{
return remapLocalSide( DirectionUtil.toLocal( getDirection(), globalSide ) );
}
/**
* Gets the redstone input for an adjacent block.
*
* @param world The world we exist in
* @param pos The position of the neighbour
* @param side The side we are reading from
* @return The effective redstone power
*/
protected static int getRedstoneInput( Level world, BlockPos pos, Direction side )
{
int power = world.getSignal( pos, side );
if( power >= 15 )
{
return power;
}
BlockState neighbour = world.getBlockState( pos );
return neighbour.getBlock() == Blocks.REDSTONE_WIRE ? Math.max( power, neighbour.getValue( RedStoneWireBlock.POWER ) ) : power;
}
protected boolean isPeripheralBlockedOnSide( ComputerSide localSide )
{
return false;
}
protected ComputerSide remapLocalSide( ComputerSide localSide )
{
return localSide;
}
protected abstract Direction getDirection();
@Override @Override
public void onNeighbourChange( @Nonnull BlockPos neighbour ) public void onNeighbourChange( @Nonnull BlockPos neighbour )
{ {
updateInput( neighbour ); updateInputAt( neighbour );
} }
@Override @Override
public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour ) public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour )
{ {
updateInput( neighbour ); updateInputAt( neighbour );
} }
@Override protected void serverTick()
protected void readDescription( @Nonnull CompoundTag nbt )
{
super.readDescription( nbt );
label = nbt.contains( NBT_LABEL ) ? nbt.getString( NBT_LABEL ) : null;
computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1;
}
@Override
protected void writeDescription( @Nonnull CompoundTag nbt )
{
super.writeDescription( nbt );
if( label != null )
{
nbt.putString( NBT_LABEL, label );
}
if( computerID >= 0 )
{
nbt.putInt( NBT_ID, computerID );
}
}
public void serverTick()
{ {
ServerComputer computer = createServerComputer(); ServerComputer computer = createServerComputer();
if( computer == null )
if( invalidSides != 0 )
{ {
return; for( Direction direction : DirectionUtil.FACINGS )
{
if( (invalidSides & (1 << direction.ordinal())) != 0 ) refreshPeripheral( computer, direction );
}
} }
// If the computer isn't on and should be, then turn it on // If the computer isn't on and should be, then turn it on
if( startOn || fresh && on ) if( startOn || (fresh && on) )
{ {
computer.turnOn(); computer.turnOn();
startOn = false; startOn = false;
@@ -292,33 +172,28 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
label = computer.getLabel(); label = computer.getLabel();
on = computer.isOn(); on = computer.isOn();
if( computer.hasOutputChanged() )
{
updateOutput();
}
// Update the block state if needed. We don't fire a block update intentionally, // Update the block state if needed. We don't fire a block update intentionally,
// as this only really is needed on the client side. // as this only really is needed on the client side.
updateBlockState( computer.getState() ); updateBlockState( computer.getState() );
if( computer.hasOutputChanged() ) // TODO: This should ideally be split up into label/id/on (which should save NBT and sync to client) and
{ // redstone (which should update outputs)
updateOutput(); if( computer.hasOutputChanged() ) updateOutput();
}
}
public void updateOutput()
{
// Update redstone
updateBlock();
for( Direction dir : DirectionUtil.FACINGS )
{
RedstoneUtil.propagateRedstoneOutput( getLevel(), getBlockPos(), dir );
}
} }
protected abstract void updateBlockState( ComputerState newState ); protected abstract void updateBlockState( ComputerState newState );
@Override
public void saveAdditional( @Nonnull CompoundTag nbt )
{
// Save ID, label and power state
if( computerID >= 0 ) nbt.putInt( NBT_ID, computerID );
if( label != null ) nbt.putString( NBT_LABEL, label );
nbt.putBoolean( NBT_ON, on );
super.saveAdditional( nbt );
}
@Override @Override
public void load( @Nonnull CompoundTag nbt ) public void load( @Nonnull CompoundTag nbt )
{ {
@@ -330,116 +205,137 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
on = startOn = nbt.getBoolean( NBT_ON ); on = startOn = nbt.getBoolean( NBT_ON );
} }
@Override protected boolean isPeripheralBlockedOnSide( ComputerSide localSide )
public void saveAdditional( @Nonnull CompoundTag nbt )
{ {
// Save ID, label and power state return false;
if( computerID >= 0 )
{
nbt.putInt( NBT_ID, computerID );
}
if( label != null )
{
nbt.putString( NBT_LABEL, label );
}
nbt.putBoolean( NBT_ON, on );
} }
@Override protected abstract Direction getDirection();
public void setRemoved()
protected ComputerSide remapToLocalSide( Direction globalSide )
{ {
unload(); return remapLocalSide( DirectionUtil.toLocal( getDirection(), globalSide ) );
super.setRemoved();
} }
private void updateInput( BlockPos neighbour ) protected ComputerSide remapLocalSide( ComputerSide localSide )
{ {
if( getLevel() == null || this.level.isClientSide ) return localSide;
{ }
return;
}
private void updateRedstoneInput( @Nonnull ServerComputer computer, Direction dir, BlockPos targetPos )
{
Direction offsetSide = dir.getOpposite();
ComputerSide localDir = remapToLocalSide( dir );
computer.setRedstoneInput( localDir, RedstoneUtil.getRedstoneInput( level, targetPos, dir ) );
computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getLevel(), targetPos, offsetSide ) );
}
private void refreshPeripheral( @Nonnull ServerComputer computer, Direction dir )
{
invalidSides &= ~(1 << dir.ordinal());
ComputerSide localDir = remapToLocalSide( dir );
if( isPeripheralBlockedOnSide( localDir ) ) return;
Direction offsetSide = dir.getOpposite();
IPeripheral peripheral = Peripherals.getPeripheral( getLevel(), getBlockPos().relative( dir ), offsetSide );
computer.setPeripheral( localDir, peripheral );
}
public void updateInputsImmediately()
{
ServerComputer computer = getServerComputer(); ServerComputer computer = getServerComputer();
if( computer == null ) if( computer != null ) updateInputsImmediately( computer );
}
/**
* Update all redstone and peripherals.
*
* This should only be really be called when the computer is being ticked (though there are some cases where it
* won't be), as peripheral scanning requires adjacent tiles to be in a "correct" state - which may not be the case
* if they're still updating!
*
* @param computer The current computer instance.
*/
private void updateInputsImmediately( @Nonnull ServerComputer computer )
{
BlockPos pos = getBlockPos();
for( Direction dir : DirectionUtil.FACINGS )
{ {
return; updateRedstoneInput( computer, dir, pos.relative( dir ) );
refreshPeripheral( computer, dir );
} }
}
private void updateInputAt( @Nonnull BlockPos neighbour )
{
ServerComputer computer = getServerComputer();
if( computer == null ) return;
for( Direction dir : DirectionUtil.FACINGS ) for( Direction dir : DirectionUtil.FACINGS )
{ {
BlockPos offset = worldPosition.relative( dir ); BlockPos offset = getBlockPos().relative( dir );
if( offset.equals( neighbour ) ) if( offset.equals( neighbour ) )
{ {
updateSideInput( computer, dir, offset ); updateRedstoneInput( computer, dir, offset );
invalidSides |= 1 << dir.ordinal();
return; return;
} }
} }
// If the position is not any adjacent one, update all inputs. // If the position is not any adjacent one, update all inputs. This is pretty terrible, but some redstone mods
this.updateInput(); // handle this incorrectly.
BlockPos pos = getBlockPos();
for( Direction dir : DirectionUtil.FACINGS ) updateRedstoneInput( computer, dir, pos.relative( dir ) );
invalidSides = (1 << 6) - 1; // Mark all peripherals as dirty.
} }
private void updateInput( Direction dir ) /**
* Update the block's state and propagate redstone output.
*/
public void updateOutput()
{ {
if( getLevel() == null || this.level.isClientSide ) updateBlock();
for( Direction dir : DirectionUtil.FACINGS )
{ {
return; RedstoneUtil.propagateRedstoneOutput( getLevel(), getBlockPos(), dir );
} }
ServerComputer computer = getServerComputer();
if( computer == null )
{
return;
}
updateSideInput( computer, dir, worldPosition.relative( dir ) );
} }
protected abstract ServerComputer createComputer( int instanceID, int id );
@Override @Override
public final int getComputerID() public final int getComputerID()
{ {
return computerID; return computerID;
} }
@Override
public final void setComputerID( int id )
{
if( this.level.isClientSide || computerID == id )
{
return;
}
computerID = id;
ServerComputer computer = getServerComputer();
if( computer != null )
{
computer.setID( computerID );
}
setChanged();
}
@Override @Override
public final String getLabel() public final String getLabel()
{ {
return label; return label;
} }
// Networking stuff @Override
public final void setComputerID( int id )
{
if( getLevel().isClientSide || computerID == id ) return;
computerID = id;
ServerComputer computer = getServerComputer();
if( computer != null ) computer.setID( computerID );
setChanged();
}
@Override @Override
public final void setLabel( String label ) public final void setLabel( String label )
{ {
if( this.level.isClientSide || Objects.equals( this.label, label ) ) if( getLevel().isClientSide || Objects.equals( this.label, label ) ) return;
{
return;
}
this.label = label; this.label = label;
ServerComputer computer = getServerComputer(); ServerComputer computer = getServerComputer();
if( computer != null ) if( computer != null ) computer.setLabel( label );
{
computer.setLabel( label );
}
setChanged(); setChanged();
} }
@@ -449,6 +345,64 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
return family; return family;
} }
@Nonnull
public ServerComputer createServerComputer()
{
if( getLevel().isClientSide ) throw new IllegalStateException( "Cannot access server computer on the client." );
boolean changed = false;
if( instanceID < 0 )
{
instanceID = ComputerCraft.serverComputerRegistry.getUnusedInstanceID();
changed = true;
}
ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instanceID );
if( computer == null )
{
computer = createComputer( instanceID, computerID );
ComputerCraft.serverComputerRegistry.add( instanceID, computer );
fresh = true;
changed = true;
}
if( changed ) updateInputsImmediately( computer );
return computer;
}
@Nullable
public ServerComputer getServerComputer()
{
return getLevel().isClientSide ? null : ComputerCraft.serverComputerRegistry.get( instanceID );
}
// Networking stuff
@Nonnull
@Override
public final ClientboundBlockEntityDataPacket getUpdatePacket()
{
return ClientboundBlockEntityDataPacket.create( this );
}
@Nonnull
@Override
public CompoundTag getUpdateTag()
{
// We need this for pick block on the client side.
CompoundTag nbt = super.getUpdateTag();
if( label != null ) nbt.putString( NBT_LABEL, label );
if( computerID >= 0 ) nbt.putInt( NBT_ID, computerID );
return nbt;
}
// @Override
// public void handleUpdateTag( @Nonnull CompoundTag nbt )
// {
// label = nbt.contains( NBT_LABEL ) ? nbt.getString( NBT_LABEL ) : null;
// computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1;
// }
protected void transferStateFrom( TileComputerBase copy ) protected void transferStateFrom( TileComputerBase copy )
{ {
if( copy.computerID != computerID || copy.instanceID != instanceID ) if( copy.computerID != computerID || copy.instanceID != instanceID )
@@ -468,17 +422,17 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
@Override @Override
public IPeripheral getPeripheral( Direction side ) public IPeripheral getPeripheral( Direction side )
{ {
return new ComputerPeripheral( "computer", createProxy() ); if( proxy == null ) proxy = new ComputerProxy( () -> this );
return new ComputerPeripheral( "computer", proxy );
} }
public abstract ComputerProxy createProxy();
@Nonnull @Nonnull
@Override @Override
public Component getName() public Component getName()
{ {
return hasCustomName() ? new TextComponent( label ) : new TranslatableComponent( getBlockState().getBlock() return hasCustomName()
.getDescriptionId() ); ? new TextComponent( label )
: new TranslatableComponent( getBlockState().getBlock().getDescriptionId() );
} }
@Override @Override
@@ -487,13 +441,6 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
return !Strings.isNullOrEmpty( label ); return !Strings.isNullOrEmpty( label );
} }
@Nonnull
@Override
public Component getDisplayName()
{
return Nameable.super.getDisplayName();
}
@Nullable @Nullable
@Override @Override
public Component getCustomName() public Component getCustomName()
@@ -501,6 +448,13 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
return hasCustomName() ? new TextComponent( label ) : null; return hasCustomName() ? new TextComponent( label ) : null;
} }
@Nonnull
@Override
public Component getDisplayName()
{
return Nameable.super.getDisplayName();
}
@Override @Override
public void writeScreenOpeningData( ServerPlayer serverPlayerEntity, FriendlyByteBuf packetByteBuf ) public void writeScreenOpeningData( ServerPlayer serverPlayerEntity, FriendlyByteBuf packetByteBuf )
{ {

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.core; package dan200.computercraft.shared.computer.core;
import dan200.computercraft.shared.common.ClientTerminal; import dan200.computercraft.shared.common.ClientTerminal;
@@ -19,7 +18,6 @@ public class ClientComputer extends ClientTerminal implements IComputer
private boolean blinking = false; private boolean blinking = false;
private CompoundTag userData = null; private CompoundTag userData = null;
public ClientComputer( int instanceID ) public ClientComputer( int instanceID )
{ {
super( false ); super( false );
@@ -45,6 +43,18 @@ public class ClientComputer extends ClientTerminal implements IComputer
return instanceID; return instanceID;
} }
@Override
public boolean isOn()
{
return on;
}
@Override
public boolean isCursorDisplayed()
{
return on && blinking;
}
@Override @Override
public void turnOn() public void turnOn()
{ {
@@ -73,24 +83,10 @@ public class ClientComputer extends ClientTerminal implements IComputer
NetworkHandler.sendToServer( new QueueEventServerMessage( instanceID, event, arguments ) ); NetworkHandler.sendToServer( new QueueEventServerMessage( instanceID, event, arguments ) );
} }
@Override
public boolean isOn()
{
return on;
}
@Override
public boolean isCursorDisplayed()
{
return on && blinking;
}
@Override @Override
public void keyDown( int key, boolean repeat ) public void keyDown( int key, boolean repeat )
{ {
NetworkHandler.sendToServer( new KeyEventServerMessage( instanceID, NetworkHandler.sendToServer( new KeyEventServerMessage( instanceID, repeat ? KeyEventServerMessage.TYPE_REPEAT : KeyEventServerMessage.TYPE_DOWN, key ) );
repeat ? KeyEventServerMessage.TYPE_REPEAT : KeyEventServerMessage.TYPE_DOWN,
key ) );
} }
@Override @Override

View File

@@ -3,10 +3,11 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.core; package dan200.computercraft.shared.computer.core;
public enum ComputerFamily public enum ComputerFamily
{ {
NORMAL, ADVANCED, COMMAND NORMAL,
ADVANCED,
COMMAND
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.core; package dan200.computercraft.shared.computer.core;
import java.util.Collection; import java.util.Collection;
@@ -13,23 +12,15 @@ import java.util.Random;
public class ComputerRegistry<T extends IComputer> public class ComputerRegistry<T extends IComputer>
{ {
private final Map<Integer, T> computers; private final Map<Integer, T> computers = new HashMap<>();
private int nextUnusedInstanceID; private int nextUnusedInstanceID;
private int sessionID; private int sessionID;
protected ComputerRegistry() protected ComputerRegistry()
{ {
computers = new HashMap<>();
reset(); reset();
} }
public void reset()
{
computers.clear();
nextUnusedInstanceID = 0;
sessionID = new Random().nextInt();
}
public int getSessionID() public int getSessionID()
{ {
return sessionID; return sessionID;
@@ -76,4 +67,11 @@ public class ComputerRegistry<T extends IComputer>
{ {
computers.remove( instanceID ); computers.remove( instanceID );
} }
public void reset()
{
computers.clear();
nextUnusedInstanceID = 0;
sessionID = new Random().nextInt();
}
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.core; package dan200.computercraft.shared.computer.core;
import net.minecraft.util.StringRepresentable; import net.minecraft.util.StringRepresentable;
@@ -12,7 +11,9 @@ import javax.annotation.Nonnull;
public enum ComputerState implements StringRepresentable public enum ComputerState implements StringRepresentable
{ {
OFF( "off", "" ), ON( "on", "_on" ), BLINKING( "blinking", "_blink" ); OFF( "off", "" ),
ON( "on", "_on" ),
BLINKING( "blinking", "_blink" );
private final String name; private final String name;
private final String texture; private final String texture;

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.core; package dan200.computercraft.shared.computer.core;
import dan200.computercraft.shared.common.ITerminal; import dan200.computercraft.shared.common.ITerminal;
@@ -12,30 +11,27 @@ public interface IComputer extends ITerminal, InputHandler
{ {
int getInstanceID(); int getInstanceID();
boolean isOn();
boolean isCursorDisplayed();
void turnOn(); void turnOn();
void shutdown(); void shutdown();
void reboot(); void reboot();
@Override
void queueEvent( String event, Object[] arguments );
default void queueEvent( String event ) default void queueEvent( String event )
{ {
queueEvent( event, null ); queueEvent( event, null );
} }
@Override
void queueEvent( String event, Object[] arguments );
default ComputerState getState() default ComputerState getState()
{ {
if( !isOn() ) if( !isOn() ) return ComputerState.OFF;
{
return ComputerState.OFF;
}
return isCursorDisplayed() ? ComputerState.BLINKING : ComputerState.ON; return isCursorDisplayed() ? ComputerState.BLINKING : ComputerState.ON;
} }
boolean isOn();
boolean isCursorDisplayed();
} }

View File

@@ -3,12 +3,12 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.core; package dan200.computercraft.shared.computer.core;
import dan200.computercraft.shared.computer.upload.FileSlice; import dan200.computercraft.shared.computer.upload.FileSlice;
import dan200.computercraft.shared.computer.upload.FileUpload; import dan200.computercraft.shared.computer.upload.FileUpload;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.AbstractContainerMenu;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -16,9 +16,9 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /**
* An instance of {@link Container} which provides a computer. You should implement this if you provide custom computers/GUIs to interact with them. * An instance of {@link AbstractContainerMenu} which provides a computer. You should implement this
* if you provide custom computers/GUIs to interact with them.
*/ */
//@FunctionalInterface
public interface IContainerComputer public interface IContainerComputer
{ {
/** /**

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.core; package dan200.computercraft.shared.computer.core;
import it.unimi.dsi.fastutil.ints.IntIterator; import it.unimi.dsi.fastutil.ints.IntIterator;
@@ -11,7 +10,8 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSet;
/** /**
* An {@link InputHandler} which keeps track of the current key and mouse state, and releases them when the container is closed. * An {@link InputHandler} which keeps track of the current key and mouse state, and releases them when the container
* is closed.
*/ */
public class InputState implements InputHandler public class InputState implements InputHandler
{ {
@@ -31,10 +31,7 @@ public class InputState implements InputHandler
public void queueEvent( String event, Object[] arguments ) public void queueEvent( String event, Object[] arguments )
{ {
IComputer computer = owner.getComputer(); IComputer computer = owner.getComputer();
if( computer != null ) if( computer != null ) computer.queueEvent( event, arguments );
{
computer.queueEvent( event, arguments );
}
} }
@Override @Override
@@ -42,10 +39,7 @@ public class InputState implements InputHandler
{ {
keysDown.add( key ); keysDown.add( key );
IComputer computer = owner.getComputer(); IComputer computer = owner.getComputer();
if( computer != null ) if( computer != null ) computer.keyDown( key, repeat );
{
computer.keyDown( key, repeat );
}
} }
@Override @Override
@@ -53,10 +47,7 @@ public class InputState implements InputHandler
{ {
keysDown.remove( key ); keysDown.remove( key );
IComputer computer = owner.getComputer(); IComputer computer = owner.getComputer();
if( computer != null ) if( computer != null ) computer.keyUp( key );
{
computer.keyUp( key );
}
} }
@Override @Override
@@ -67,10 +58,7 @@ public class InputState implements InputHandler
lastMouseDown = button; lastMouseDown = button;
IComputer computer = owner.getComputer(); IComputer computer = owner.getComputer();
if( computer != null ) if( computer != null ) computer.mouseClick( button, x, y );
{
computer.mouseClick( button, x, y );
}
} }
@Override @Override
@@ -81,10 +69,7 @@ public class InputState implements InputHandler
lastMouseDown = -1; lastMouseDown = -1;
IComputer computer = owner.getComputer(); IComputer computer = owner.getComputer();
if( computer != null ) if( computer != null ) computer.mouseUp( button, x, y );
{
computer.mouseUp( button, x, y );
}
} }
@Override @Override
@@ -95,10 +80,7 @@ public class InputState implements InputHandler
lastMouseDown = button; lastMouseDown = button;
IComputer computer = owner.getComputer(); IComputer computer = owner.getComputer();
if( computer != null ) if( computer != null ) computer.mouseDrag( button, x, y );
{
computer.mouseDrag( button, x, y );
}
} }
@Override @Override
@@ -108,10 +90,7 @@ public class InputState implements InputHandler
lastMouseY = y; lastMouseY = y;
IComputer computer = owner.getComputer(); IComputer computer = owner.getComputer();
if( computer != null ) if( computer != null ) computer.mouseScroll( direction, x, y );
{
computer.mouseScroll( direction, x, y );
}
} }
public void close() public void close()
@@ -120,15 +99,9 @@ public class InputState implements InputHandler
if( computer != null ) if( computer != null )
{ {
IntIterator keys = keysDown.iterator(); IntIterator keys = keysDown.iterator();
while( keys.hasNext() ) while( keys.hasNext() ) computer.keyUp( keys.nextInt() );
{
computer.keyUp( keys.nextInt() );
}
if( lastMouseDown != -1 ) if( lastMouseDown != -1 ) computer.mouseUp( lastMouseDown, lastMouseX, lastMouseY );
{
computer.mouseUp( lastMouseDown, lastMouseX, lastMouseY );
}
} }
keysDown.clear(); keysDown.clear();

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.core; package dan200.computercraft.shared.computer.core;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
@@ -24,6 +23,7 @@ import dan200.computercraft.shared.network.client.ComputerDataClientMessage;
import dan200.computercraft.shared.network.client.ComputerDeletedClientMessage; import dan200.computercraft.shared.network.client.ComputerDeletedClientMessage;
import dan200.computercraft.shared.network.client.ComputerTerminalClientMessage; import dan200.computercraft.shared.network.client.ComputerTerminalClientMessage;
import me.shedaniel.cloth.api.utils.v1.GameInstanceUtils; import me.shedaniel.cloth.api.utils.v1.GameInstanceUtils;
import net.minecraft.SharedConstants;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
@@ -38,32 +38,27 @@ import java.io.InputStream;
public class ServerComputer extends ServerTerminal implements IComputer, IComputerEnvironment public class ServerComputer extends ServerTerminal implements IComputer, IComputerEnvironment
{ {
private final int instanceID; private final int instanceID;
private Level level;
private BlockPos position;
private final ComputerFamily family; private final ComputerFamily family;
private final Computer computer; private final Computer computer;
private Level world;
private BlockPos position;
private CompoundTag userData; private CompoundTag userData;
private boolean changed; private boolean changed;
private boolean changedLastFrame; private boolean changedLastFrame;
private int ticksSincePing; private int ticksSincePing;
public ServerComputer( Level world, int computerID, String label, int instanceID, ComputerFamily family, int terminalWidth, int terminalHeight ) public ServerComputer( Level level, int computerID, String label, int instanceID, ComputerFamily family, int terminalWidth, int terminalHeight )
{ {
super( family != ComputerFamily.NORMAL, terminalWidth, terminalHeight ); super( family != ComputerFamily.NORMAL, terminalWidth, terminalHeight );
this.instanceID = instanceID; this.instanceID = instanceID;
this.world = world; this.level = level;
position = null;
this.family = family; this.family = family;
computer = new Computer( this, getTerminal(), computerID ); computer = new Computer( this, getTerminal(), computerID );
computer.setLabel( label ); computer.setLabel( label );
userData = null;
changed = false;
changedLastFrame = false;
ticksSincePing = 0;
} }
public ComputerFamily getFamily() public ComputerFamily getFamily()
@@ -71,14 +66,14 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
return family; return family;
} }
public Level getWorld() public Level getLevel()
{ {
return world; return level;
} }
public void setWorld( Level world ) public void setLevel( Level level )
{ {
this.world = world; this.level = level;
} }
public BlockPos getPosition() public BlockPos getPosition()
@@ -123,6 +118,11 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
return ticksSincePing > 100; return ticksSincePing > 100;
} }
public boolean hasOutputChanged()
{
return changedLastFrame;
}
public void unload() public void unload()
{ {
computer.unload(); computer.unload();
@@ -142,86 +142,94 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
changed = true; changed = true;
} }
public void broadcastState( boolean force )
{
if( hasOutputChanged() || force )
{
// Send computer state to all clients
MinecraftServer server = GameInstanceUtils.getServer();
if( server != null )
{
NetworkHandler.sendToAllPlayers( server, createComputerPacket() );
}
}
if( hasTerminalChanged() || force )
{
MinecraftServer server = GameInstanceUtils.getServer();
if( server != null )
{
// Send terminal state to clients who are currently interacting with the computer.
NetworkMessage packet = null;
for( Player player : server.getPlayerList()
.getPlayers() )
{
if( isInteracting( player ) )
{
if( packet == null )
{
packet = createTerminalPacket();
}
NetworkHandler.sendToPlayer( player, packet );
}
}
}
}
}
public boolean hasOutputChanged()
{
return changedLastFrame;
}
private NetworkMessage createComputerPacket() private NetworkMessage createComputerPacket()
{ {
return new ComputerDataClientMessage( this ); return new ComputerDataClientMessage( this );
} }
protected boolean isInteracting( Player player )
{
return getContainer( player ) != null;
}
protected NetworkMessage createTerminalPacket() protected NetworkMessage createTerminalPacket()
{ {
return new ComputerTerminalClientMessage( getInstanceID(), write() ); return new ComputerTerminalClientMessage( getInstanceID(), write() );
} }
@Nullable public void broadcastState( boolean force )
public IContainerComputer getContainer( Player player )
{ {
if( player == null ) if( hasOutputChanged() || force )
{ {
return null; // Send computer state to all clients
NetworkHandler.sendToAllPlayers( createComputerPacket() );
} }
AbstractContainerMenu container = player.containerMenu; if( hasTerminalChanged() || force )
if( !(container instanceof IContainerComputer) )
{ {
return null; // Send terminal state to clients who are currently interacting with the computer.
} MinecraftServer server = GameInstanceUtils.getServer();
IContainerComputer computerContainer = (IContainerComputer) container; NetworkMessage packet = null;
return computerContainer.getComputer() != this ? null : computerContainer; for( Player player : server.getPlayerList().getPlayers() )
{
if( isInteracting( player ) )
{
if( packet == null ) packet = createTerminalPacket();
NetworkHandler.sendToPlayer( player, packet );
}
}
}
} }
public void sendComputerState( Player player )
{
// Send state to client
NetworkHandler.sendToPlayer( player, createComputerPacket() );
}
public void sendTerminalState( Player player )
{
// Send terminal state to client
NetworkHandler.sendToPlayer( player, createTerminalPacket() );
}
public void broadcastDelete()
{
// Send deletion to client
NetworkHandler.sendToAllPlayers( new ComputerDeletedClientMessage( getInstanceID() ) );
}
public void setID( int id )
{
computer.setID( id );
}
// IComputer
@Override @Override
public int getInstanceID() public int getInstanceID()
{ {
return instanceID; return instanceID;
} }
public int getID()
{
return computer.getID();
}
public String getLabel()
{
return computer.getLabel();
}
@Override
public boolean isOn()
{
return computer.isOn();
}
@Override
public boolean isCursorDisplayed()
{
return computer.isOn() && computer.isBlinking();
}
@Override @Override
public void turnOn() public void turnOn()
{ {
@@ -229,8 +237,6 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
computer.turnOn(); computer.turnOn();
} }
// IComputer
@Override @Override
public void shutdown() public void shutdown()
{ {
@@ -252,82 +258,24 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
computer.queueEvent( event, arguments ); computer.queueEvent( event, arguments );
} }
@Override
public boolean isOn()
{
return computer.isOn();
}
@Override
public boolean isCursorDisplayed()
{
return computer.isOn() && computer.isBlinking();
}
public void sendComputerState( Player player )
{
// Send state to client
NetworkHandler.sendToPlayer( player, createComputerPacket() );
}
public void sendTerminalState( Player player )
{
// Send terminal state to client
NetworkHandler.sendToPlayer( player, createTerminalPacket() );
}
public void broadcastDelete()
{
// Send deletion to client
MinecraftServer server = GameInstanceUtils.getServer();
if( server != null )
{
NetworkHandler.sendToAllPlayers( server, new ComputerDeletedClientMessage( getInstanceID() ) );
}
}
public int getID()
{
return computer.getID();
}
public void setID( int id )
{
computer.setID( id );
}
public String getLabel()
{
return computer.getLabel();
}
public void setLabel( String label )
{
computer.setLabel( label );
}
public int getRedstoneOutput( ComputerSide side ) public int getRedstoneOutput( ComputerSide side )
{ {
return computer.getEnvironment() return computer.getEnvironment().getExternalRedstoneOutput( side );
.getExternalRedstoneOutput( side );
} }
public void setRedstoneInput( ComputerSide side, int level ) public void setRedstoneInput( ComputerSide side, int level )
{ {
computer.getEnvironment() computer.getEnvironment().setRedstoneInput( side, level );
.setRedstoneInput( side, level );
} }
public int getBundledRedstoneOutput( ComputerSide side ) public int getBundledRedstoneOutput( ComputerSide side )
{ {
return computer.getEnvironment() return computer.getEnvironment().getExternalBundledRedstoneOutput( side );
.getExternalBundledRedstoneOutput( side );
} }
public void setBundledRedstoneInput( ComputerSide side, int combination ) public void setBundledRedstoneInput( ComputerSide side, int combination )
{ {
computer.getEnvironment() computer.getEnvironment().setBundledRedstoneInput( side, combination );
.setBundledRedstoneInput( side, combination );
} }
public void addAPI( ILuaAPI api ) public void addAPI( ILuaAPI api )
@@ -335,62 +283,39 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
computer.addApi( api ); computer.addApi( api );
} }
// IComputerEnvironment implementation
public void setPeripheral( ComputerSide side, IPeripheral peripheral ) public void setPeripheral( ComputerSide side, IPeripheral peripheral )
{ {
computer.getEnvironment() computer.getEnvironment().setPeripheral( side, peripheral );
.setPeripheral( side, peripheral );
} }
public IPeripheral getPeripheral( ComputerSide side ) public IPeripheral getPeripheral( ComputerSide side )
{ {
return computer.getEnvironment() return computer.getEnvironment().getPeripheral( side );
.getPeripheral( side ); }
public void setLabel( String label )
{
computer.setLabel( label );
}
// IComputerEnvironment implementation
@Override
public double getTimeOfDay()
{
return (level.getDayTime() + 6000) % 24000 / 1000.0;
} }
@Override @Override
public int getDay() public int getDay()
{ {
return (int) ((world.getDayTime() + 6000) / 24000) + 1; return (int) ((level.getDayTime() + 6000) / 24000) + 1;
}
@Override
public double getTimeOfDay()
{
return (world.getDayTime() + 6000) % 24000 / 1000.0;
}
@Override
public long getComputerSpaceLimit()
{
return ComputerCraft.computerSpaceLimit;
}
@Nonnull
@Override
public String getHostString()
{
return String.format( "ComputerCraft %s (Minecraft %s)", ComputerCraftAPI.getInstalledVersion(), "1.16.4" );
}
@Nonnull
@Override
public String getUserAgent()
{
return ComputerCraft.MOD_ID + "/" + ComputerCraftAPI.getInstalledVersion();
}
@Override
public int assignNewID()
{
return ComputerCraftAPI.createUniqueNumberedSaveDir( world, "computer" );
} }
@Override @Override
public IWritableMount createSaveDirMount( String subPath, long capacity ) public IWritableMount createSaveDirMount( String subPath, long capacity )
{ {
return ComputerCraftAPI.createSaveDirMount( world, subPath, capacity ); return ComputerCraftAPI.createSaveDirMount( level, subPath, capacity );
} }
@Override @Override
@@ -404,4 +329,46 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
{ {
return ComputerCraftAPIImpl.getResourceFile( domain, subPath ); return ComputerCraftAPIImpl.getResourceFile( domain, subPath );
} }
@Override
public long getComputerSpaceLimit()
{
return ComputerCraft.computerSpaceLimit;
}
@Nonnull
@Override
public String getHostString()
{
return String.format( "ComputerCraft %s (Minecraft %s)", ComputerCraftAPI.getInstalledVersion(), SharedConstants.getCurrentVersion() );
}
@Nonnull
@Override
public String getUserAgent()
{
return ComputerCraft.MOD_ID + "/" + ComputerCraftAPI.getInstalledVersion();
}
@Override
public int assignNewID()
{
return ComputerCraftAPI.createUniqueNumberedSaveDir( level, "computer" );
}
@Nullable
public IContainerComputer getContainer( Player player )
{
if( player == null ) return null;
AbstractContainerMenu container = player.containerMenu;
if( !(container instanceof IContainerComputer computerContainer) ) return null;
return computerContainer.getComputer() != this ? null : computerContainer;
}
protected boolean isInteracting( Player player )
{
return getContainer( player ) != null;
}
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared.computer.core; package dan200.computercraft.shared.computer.core;
import java.util.Iterator; import java.util.Iterator;
@@ -35,18 +34,6 @@ public class ServerComputerRegistry extends ComputerRegistry<ServerComputer>
} }
} }
@Override
public void reset()
{
//System.out.println( "RESET SERVER COMPUTERS" );
for( ServerComputer computer : getComputers() )
{
computer.unload();
}
super.reset();
//System.out.println( getComputers().size() + " SERVER COMPUTERS" );
}
@Override @Override
public void add( int instanceID, ServerComputer computer ) public void add( int instanceID, ServerComputer computer )
{ {
@@ -70,19 +57,25 @@ public class ServerComputerRegistry extends ComputerRegistry<ServerComputer>
//System.out.println( getComputers().size() + " SERVER COMPUTERS" ); //System.out.println( getComputers().size() + " SERVER COMPUTERS" );
} }
@Override
public void reset()
{
//System.out.println( "RESET SERVER COMPUTERS" );
for( ServerComputer computer : getComputers() )
{
computer.unload();
}
super.reset();
//System.out.println( getComputers().size() + " SERVER COMPUTERS" );
}
public ServerComputer lookup( int computerID ) public ServerComputer lookup( int computerID )
{ {
if( computerID < 0 ) if( computerID < 0 ) return null;
{
return null;
}
for( ServerComputer computer : getComputers() ) for( ServerComputer computer : getComputers() )
{ {
if( computer.getID() == computerID ) if( computer.getID() == computerID ) return computer;
{
return computer;
}
} }
return null; return null;
} }

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