diff --git a/README.md b/README.md index ee3c63844..ab2cb561f 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ dependencies { } dependencies { - implementation "org.squiddev:cc-tweaked:${mc_version}-${cct_version}" + implementation "org.squiddev:cc-tweaked-${mc_version}:${cct_version}" } ``` diff --git a/build.gradle b/build.gradle index 85e1367db..141258105 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ buildscript { plugins { id 'fabric-loom' version '0.2.0-SNAPSHOT' id 'com.matthewprenger.cursegradle' version '1.2.0' + id "com.github.breadmoirai.github-release" version "2.2.4" } apply plugin: 'org.ajoberstar.grgit' @@ -299,6 +300,20 @@ uploadArchives { } } +githubRelease { + token project.hasProperty('githubApiKey') ? project.githubApiKey : '' + owner 'SquidDev-CC' + repo 'CC-Tweaked' + targetCommitish (mc_version == "1.12.2" ? "master" : mc_version) + + tagName "v${mc_version}-${mod_version}" + releaseName "[${mc_version}] ${mod_version}" + body '' + prerelease true + + releaseAssets.from(jar.archivePath) +} + test { useJUnitPlatform() testLogging { diff --git a/gradle.properties b/gradle.properties index 4c629ac70..95c4436be 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.82.0 +mod_version=1.82.1 # Minecraft properties mc_version=19w14a diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java index 48fd022bc..c1dd6c526 100644 --- a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java +++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java @@ -33,6 +33,7 @@ import net.minecraft.world.BlockView; import net.minecraft.world.World; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.File; public final class ComputerCraftAPIImpl implements IComputerCraftAPI @@ -43,6 +44,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI { } + @Nonnull @Override public String getInstalledVersion() { @@ -110,6 +112,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI PocketUpgrades.register( upgrade ); } + @Nonnull @Override public IPacketNetwork getWirelessNetwork() { @@ -122,12 +125,14 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI ApiFactories.register( factory ); } + @Nonnull @Override public IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element ) { return new WiredNode( element ); } + @Nullable @Override public IWiredElement getWiredElementAt( @Nonnull BlockView world, @Nonnull BlockPos pos, @Nonnull Direction side ) { diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index a54989c99..625d18be3 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -266,12 +266,15 @@ public final class ComputerCraftAPI public interface IComputerCraftAPI { + @Nonnull String getInstalledVersion(); int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath ); + @Nullable IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity ); + @Nullable IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath ); void registerPeripheralProvider( @Nonnull IPeripheralProvider provider ); @@ -286,12 +289,15 @@ public final class ComputerCraftAPI void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade ); + @Nonnull IPacketNetwork getWirelessNetwork(); void registerAPIFactory( @Nonnull ILuaAPIFactory factory ); + @Nonnull IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element ); + @Nullable IWiredElement getWiredElementAt( @Nonnull BlockView world, @Nonnull BlockPos pos, @Nonnull Direction side ); } } diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java index 52d95fd2a..30c31bf4b 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java @@ -40,18 +40,6 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer { } - /* - @SubscribeEvent - public static void renderItem( RenderSpecificHandEvent event ) - { - ItemStack stack = event.getItemStack(); - if( !(stack.getItem() instanceof ItemPocketComputer) ) return; - - event.setCanceled( true ); - INSTANCE.renderItemFirstPerson( event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() ); - } - */ - @Override protected void renderItem( ItemStack stack ) { diff --git a/src/main/java/dan200/computercraft/client/render/RenderOverlayCable.java b/src/main/java/dan200/computercraft/client/render/RenderOverlayCable.java index 2f2de841e..b23af1889 100644 --- a/src/main/java/dan200/computercraft/client/render/RenderOverlayCable.java +++ b/src/main/java/dan200/computercraft/client/render/RenderOverlayCable.java @@ -68,7 +68,8 @@ public final class RenderOverlayCable double z = player.prevZ + (player.z - player.prevZ) * partialTicks; VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), mc.hitResult.getPos().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) - ? CableShapes.getModemShape( state ) : CableShapes.getCableShape( state ); + ? CableShapes.getModemShape( state ) + : CableShapes.getCableShape( state ); WorldRenderer.drawShapeOutline( shape, pos.getX() - x, pos.getY() - y, pos.getZ() - z, 0.0F, 0.0F, 0.0F, 0.4F ); diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java index 2cde012c6..35eb88965 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java @@ -12,6 +12,7 @@ import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant; import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; import dan200.computercraft.shared.peripheral.modem.wired.TileCable; +import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.client.MinecraftClient; @@ -25,7 +26,6 @@ import net.minecraft.client.texture.Sprite; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.shape.VoxelShape; import net.minecraft.world.World; import org.lwjgl.opengl.GL11; @@ -56,8 +56,7 @@ public class TileEntityCableRenderer extends BlockEntityRenderer Block block = state.getBlock(); if( block != ComputerCraft.Blocks.cable ) return; - VoxelShape shape = CableShapes.getModemShape( state ); - state = te.hasModem() && shape.getBoundingBox().expand( 0.02, 0.02, 0.02 ).contains( hit.getPos().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) + state = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getPos().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ? block.getDefaultState().with( BlockCable.MODEM, state.get( BlockCable.MODEM ) ) : state.with( BlockCable.MODEM, CableModemVariant.None ); diff --git a/src/main/java/dan200/computercraft/core/apis/ApiFactories.java b/src/main/java/dan200/computercraft/core/apis/ApiFactories.java index d4b0adc66..e37b7b594 100644 --- a/src/main/java/dan200/computercraft/core/apis/ApiFactories.java +++ b/src/main/java/dan200/computercraft/core/apis/ApiFactories.java @@ -6,13 +6,13 @@ package dan200.computercraft.core.apis; -import com.google.common.base.Preconditions; import dan200.computercraft.api.lua.ILuaAPIFactory; import javax.annotation.Nonnull; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; +import java.util.Objects; public final class ApiFactories { @@ -25,7 +25,7 @@ public final class ApiFactories public static synchronized void register( @Nonnull ILuaAPIFactory factory ) { - Preconditions.checkNotNull( factory, "provider cannot be null" ); + Objects.requireNonNull( factory, "provider cannot be null" ); factories.add( factory ); } diff --git a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java index 693a4ede4..52341b92b 100644 --- a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java +++ b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java @@ -6,7 +6,6 @@ package dan200.computercraft.core.apis; -import com.google.common.base.Preconditions; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.peripheral.IComputerAccess; @@ -121,7 +120,7 @@ public abstract class ComputerAccess implements IComputerAccess @Override public void queueEvent( @Nonnull final String event, final Object[] arguments ) { - Preconditions.checkNotNull( event, "event cannot be null" ); + Objects.requireNonNull( event, "event cannot be null" ); m_environment.queueEvent( event, arguments ); } diff --git a/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java b/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java index 4cb3670a9..92ef98d32 100644 --- a/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java +++ b/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java @@ -8,6 +8,7 @@ package dan200.computercraft.core.apis; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IWorkMonitor; +import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.IComputerEnvironment; import dan200.computercraft.core.filesystem.FileSystem; import dan200.computercraft.core.terminal.Terminal; @@ -18,16 +19,10 @@ import javax.annotation.Nullable; public interface IAPIEnvironment { - String[] SIDE_NAMES = new String[] { - "bottom", "top", "back", "front", "right", "left", - }; - - int SIDE_COUNT = 6; - @FunctionalInterface interface IPeripheralChangeListener { - void onPeripheralChanged( int side, @Nullable IPeripheral newPeripheral ); + void onPeripheralChanged( ComputerSide side, @Nullable IPeripheral newPeripheral ); } int getComputerID(); @@ -49,22 +44,22 @@ public interface IAPIEnvironment void queueEvent( String event, Object[] args ); - void setOutput( int side, int output ); + void setOutput( ComputerSide side, int output ); - int getOutput( int side ); + int getOutput( ComputerSide side ); - int getInput( int side ); + int getInput( ComputerSide side ); - void setBundledOutput( int side, int output ); + void setBundledOutput( ComputerSide side, int output ); - int getBundledOutput( int side ); + int getBundledOutput( ComputerSide side ); - int getBundledInput( int side ); + int getBundledInput( ComputerSide side ); void setPeripheralChangeListener( @Nullable IPeripheralChangeListener listener ); @Nullable - IPeripheral getPeripheral( int side ); + IPeripheral getPeripheral( ComputerSide side ); String getLabel(); diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index 6066cc7b0..eb77fe12b 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -12,6 +12,7 @@ import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.tracking.TrackingField; import javax.annotation.Nonnull; @@ -245,32 +246,33 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange // IPeripheralChangeListener @Override - public void onPeripheralChanged( int side, IPeripheral newPeripheral ) + public void onPeripheralChanged( ComputerSide side, IPeripheral newPeripheral ) { synchronized( m_peripherals ) { - if( m_peripherals[side] != null ) + int index = side.ordinal(); + if( m_peripherals[index] != null ) { // Queue a detachment - final PeripheralWrapper wrapper = m_peripherals[side]; + final PeripheralWrapper wrapper = m_peripherals[index]; if( wrapper.isAttached() ) wrapper.detach(); // Queue a detachment event - m_environment.queueEvent( "peripheral_detach", new Object[] { IAPIEnvironment.SIDE_NAMES[side] } ); + m_environment.queueEvent( "peripheral_detach", new Object[] { side.getName() } ); } // Assign the new peripheral - m_peripherals[side] = newPeripheral == null ? null - : new PeripheralWrapper( newPeripheral, IAPIEnvironment.SIDE_NAMES[side] ); + m_peripherals[index] = newPeripheral == null ? null + : new PeripheralWrapper( newPeripheral, side.getName() ); - if( m_peripherals[side] != null ) + if( m_peripherals[index] != null ) { // Queue an attachment - final PeripheralWrapper wrapper = m_peripherals[side]; + final PeripheralWrapper wrapper = m_peripherals[index]; if( m_running && !wrapper.isAttached() ) wrapper.attach(); // Queue an attachment event - m_environment.queueEvent( "peripheral", new Object[] { IAPIEnvironment.SIDE_NAMES[side] } ); + m_environment.queueEvent( "peripheral", new Object[] { side.getName() } ); } } } @@ -337,16 +339,13 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange { // isPresent boolean present = false; - int side = parseSide( args ); - if( side >= 0 ) + ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) ); + if( side != null ) { synchronized( m_peripherals ) { - PeripheralWrapper p = m_peripherals[side]; - if( p != null ) - { - present = true; - } + PeripheralWrapper p = m_peripherals[side.ordinal()]; + if( p != null ) present = true; } } return new Object[] { present }; @@ -354,21 +353,14 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange case 1: { // getType - String type = null; - int side = parseSide( args ); - if( side >= 0 ) + ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) ); + if( side != null ) { + String type = null; synchronized( m_peripherals ) { - PeripheralWrapper p = m_peripherals[side]; - if( p != null ) - { - type = p.getType(); - } - } - if( type != null ) - { - return new Object[] { type }; + PeripheralWrapper p = m_peripherals[side.ordinal()]; + if( p != null ) return new Object[] { p.getType() }; } } return null; @@ -377,12 +369,12 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange { // getMethods String[] methods = null; - int side = parseSide( args ); - if( side >= 0 ) + ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) ); + if( side != null ) { synchronized( m_peripherals ) { - PeripheralWrapper p = m_peripherals[side]; + PeripheralWrapper p = m_peripherals[side.ordinal()]; if( p != null ) { methods = p.getMethods(); @@ -403,16 +395,16 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange case 3: { // call - int side = parseSide( args ); + ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) ); String methodName = getString( args, 1 ); Object[] methodArgs = Arrays.copyOfRange( args, 2, args.length ); - if( side >= 0 ) + if( side != null ) { PeripheralWrapper p; synchronized( m_peripherals ) { - p = m_peripherals[side]; + p = m_peripherals[side.ordinal()]; } if( p != null ) { @@ -425,19 +417,4 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange return null; } } - - // Privates - - private int parseSide( Object[] args ) throws LuaException - { - String side = getString( args, 0 ); - for( int n = 0; n < IAPIEnvironment.SIDE_NAMES.length; n++ ) - { - if( side.equals( IAPIEnvironment.SIDE_NAMES[n] ) ) - { - return n; - } - } - return -1; - } } diff --git a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java index 2ce68a58c..d36ba9186 100644 --- a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java @@ -9,6 +9,7 @@ package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.core.computer.ComputerSide; import javax.annotation.Nonnull; import java.util.HashMap; @@ -64,56 +65,40 @@ public class RedstoneAPI implements ILuaAPI { // getSides Map table = new HashMap<>(); - for( int i = 0; i < IAPIEnvironment.SIDE_NAMES.length; i++ ) + for( int i = 0; i < ComputerSide.NAMES.length; i++ ) { - table.put( i + 1, IAPIEnvironment.SIDE_NAMES[i] ); + table.put( i + 1, ComputerSide.NAMES[i] ); } return new Object[] { table }; } case 1: { // setOutput - int side = parseSide( args ); + ComputerSide side = parseSide( args ); boolean output = getBoolean( args, 1 ); m_environment.setOutput( side, output ? 15 : 0 ); return null; } - case 2: - { - // getOutput - int side = parseSide( args ); - return new Object[] { m_environment.getOutput( side ) > 0 }; - } - case 3: - { - // getInput - int side = parseSide( args ); - return new Object[] { m_environment.getInput( side ) > 0 }; - } + case 2: // getOutput + return new Object[] { m_environment.getOutput( parseSide( args ) ) > 0 }; + case 3: // getInput + return new Object[] { m_environment.getInput( parseSide( args ) ) > 0 }; case 4: { // setBundledOutput - int side = parseSide( args ); + ComputerSide side = parseSide( args ); int output = getInt( args, 1 ); m_environment.setBundledOutput( side, output ); return null; } - case 5: - { - // getBundledOutput - int side = parseSide( args ); - return new Object[] { m_environment.getBundledOutput( side ) }; - } - case 6: - { - // getBundledInput - int side = parseSide( args ); - return new Object[] { m_environment.getBundledInput( side ) }; - } + case 5: // getBundledOutput + return new Object[] { m_environment.getBundledOutput( parseSide( args ) ) }; + case 6: // getBundledInput + return new Object[] { m_environment.getBundledInput( parseSide( args ) ) }; case 7: { // testBundledInput - int side = parseSide( args ); + ComputerSide side = parseSide( args ); int mask = getInt( args, 1 ); int input = m_environment.getBundledInput( side ); return new Object[] { (input & mask) == mask }; @@ -122,7 +107,7 @@ public class RedstoneAPI implements ILuaAPI case 9: { // setAnalogOutput/setAnalogueOutput - int side = parseSide( args ); + ComputerSide side = parseSide( args ); int output = getInt( args, 1 ); if( output < 0 || output > 15 ) { @@ -132,34 +117,20 @@ public class RedstoneAPI implements ILuaAPI return null; } case 10: - case 11: - { - // getAnalogOutput/getAnalogueOutput - int side = parseSide( args ); - return new Object[] { m_environment.getOutput( side ) }; - } + case 11: // getAnalogOutput/getAnalogueOutput + return new Object[] { m_environment.getOutput( parseSide( args ) ) }; case 12: - case 13: - { - // getAnalogInput/getAnalogueInput - int side = parseSide( args ); - return new Object[] { m_environment.getInput( side ) }; - } + case 13: // getAnalogInput/getAnalogueInput + return new Object[] { m_environment.getInput( parseSide( args ) ) }; default: return null; } } - private static int parseSide( Object[] args ) throws LuaException + private static ComputerSide parseSide( Object[] args ) throws LuaException { - String side = getString( args, 0 ); - for( int n = 0; n < IAPIEnvironment.SIDE_NAMES.length; n++ ) - { - if( side.equals( IAPIEnvironment.SIDE_NAMES[n] ) ) - { - return n; - } - } - throw new LuaException( "Invalid side." ); + ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) ); + if( side == null ) throw new LuaException( "Invalid side." ); + return side; } } diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java index 9fe3d5f48..78350d411 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java @@ -338,7 +338,7 @@ final class ComputerExecutor } } - private FileSystem createFileSystem() + IWritableMount getRootMount() { if( rootMount == null ) { @@ -347,11 +347,15 @@ final class ComputerExecutor computer.getComputerEnvironment().getComputerSpaceLimit() ); } + return rootMount; + } + private FileSystem createFileSystem() + { FileSystem filesystem = null; try { - filesystem = new FileSystem( "hdd", rootMount ); + filesystem = new FileSystem( "hdd", getRootMount() ); IMount romMount = getRomMount(); if( romMount == null ) diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerSide.java b/src/main/java/dan200/computercraft/core/computer/ComputerSide.java new file mode 100644 index 000000000..d2937fd3b --- /dev/null +++ b/src/main/java/dan200/computercraft/core/computer/ComputerSide.java @@ -0,0 +1,56 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.computer; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * A side on a computer. Unlike {@link net.minecraft.util.EnumFacing}, this is relative to the direction the computer is + * facing.. + */ +public enum ComputerSide +{ + BOTTOM( "bottom" ), + TOP( "top" ), + BACK( "back" ), + FRONT( "front" ), + RIGHT( "right" ), + LEFT( "left" ); + + public static final String[] NAMES = new String[] { "bottom", "top", "back", "front", "right", "left" }; + + public static final int COUNT = 6; + + private static final ComputerSide[] VALUES = values(); + + private final String name; + + ComputerSide( String name ) {this.name = name;} + + @Nonnull + public static ComputerSide valueOf( int side ) + { + return VALUES[side]; + } + + @Nullable + public static ComputerSide valueOfInsensitive( @Nonnull String name ) + { + for( ComputerSide side : VALUES ) + { + if( side.name.equalsIgnoreCase( name ) ) return side; + } + + return null; + } + + public String getName() + { + return name; + } +} diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java b/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java index e6c39ec83..94eead340 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java @@ -26,12 +26,12 @@ import javax.annotation.Nullable; */ public class ComputerSystem extends ComputerAccess implements IComputerSystem { - private final IAPIEnvironment m_environment; + private final IAPIEnvironment environment; ComputerSystem( IAPIEnvironment environment ) { super( environment ); - this.m_environment = environment; + this.environment = environment; } @Nonnull @@ -45,7 +45,7 @@ public class ComputerSystem extends ComputerAccess implements IComputerSystem @Override public IFileSystem getFileSystem() { - FileSystem fs = m_environment.getFileSystem(); + FileSystem fs = environment.getFileSystem(); return fs == null ? null : fs.getMountWrapper(); } @@ -53,6 +53,6 @@ public class ComputerSystem extends ComputerAccess implements IComputerSystem @Override public String getLabel() { - return m_environment.getLabel(); + return environment.getLabel(); } } diff --git a/src/main/java/dan200/computercraft/core/computer/Environment.java b/src/main/java/dan200/computercraft/core/computer/Environment.java index e1612dd6d..b23ad377e 100644 --- a/src/main/java/dan200/computercraft/core/computer/Environment.java +++ b/src/main/java/dan200/computercraft/core/computer/Environment.java @@ -41,17 +41,17 @@ public final class Environment implements IAPIEnvironment private final Computer computer; private boolean internalOutputChanged = false; - private final int[] internalOutput = new int[SIDE_COUNT]; - private final int[] internalBundledOutput = new int[SIDE_COUNT]; + private final int[] internalOutput = new int[ComputerSide.COUNT]; + private final int[] internalBundledOutput = new int[ComputerSide.COUNT]; - private final int[] externalOutput = new int[SIDE_COUNT]; - private final int[] externalBundledOutput = new int[SIDE_COUNT]; + private final int[] externalOutput = new int[ComputerSide.COUNT]; + private final int[] externalBundledOutput = new int[ComputerSide.COUNT]; private boolean inputChanged = false; - private final int[] input = new int[SIDE_COUNT]; - private final int[] bundledInput = new int[SIDE_COUNT]; + private final int[] input = new int[ComputerSide.COUNT]; + private final int[] bundledInput = new int[ComputerSide.COUNT]; - private final IPeripheral[] peripherals = new IPeripheral[SIDE_COUNT]; + private final IPeripheral[] peripherals = new IPeripheral[ComputerSide.COUNT]; private IPeripheralChangeListener peripheralListener = null; Environment( Computer computer ) @@ -111,85 +111,89 @@ public final class Environment implements IAPIEnvironment } @Override - public int getInput( int side ) + public int getInput( ComputerSide side ) { - return input[side]; + return input[side.ordinal()]; } @Override - public int getBundledInput( int side ) + public int getBundledInput( ComputerSide side ) { - return bundledInput[side]; + return bundledInput[side.ordinal()]; } @Override - public void setOutput( int side, int output ) + public void setOutput( ComputerSide side, int output ) { + int index = side.ordinal(); synchronized( internalOutput ) { - if( internalOutput[side] != output ) + if( internalOutput[index] != output ) { - internalOutput[side] = output; + internalOutput[index] = output; internalOutputChanged = true; } } } @Override - public int getOutput( int side ) + public int getOutput( ComputerSide side ) { synchronized( internalOutput ) { - return computer.isOn() ? internalOutput[side] : 0; + return computer.isOn() ? internalOutput[side.ordinal()] : 0; } } @Override - public void setBundledOutput( int side, int output ) + public void setBundledOutput( ComputerSide side, int output ) { + int index = side.ordinal(); synchronized( internalOutput ) { - if( internalBundledOutput[side] != output ) + if( internalBundledOutput[index] != output ) { - internalBundledOutput[side] = output; + internalBundledOutput[index] = output; internalOutputChanged = true; } } } @Override - public int getBundledOutput( int side ) + public int getBundledOutput( ComputerSide side ) { synchronized( internalOutput ) { - return computer.isOn() ? internalBundledOutput[side] : 0; + return computer.isOn() ? internalBundledOutput[side.ordinal()] : 0; } } - public int getExternalRedstoneOutput( int side ) + public int getExternalRedstoneOutput( ComputerSide side ) { - return computer.isOn() ? externalOutput[side] : 0; + return computer.isOn() ? externalOutput[side.ordinal()] : 0; } - public int getExternalBundledRedstoneOutput( int side ) + public int getExternalBundledRedstoneOutput( ComputerSide side ) { - return computer.isOn() ? externalBundledOutput[side] : 0; + return computer.isOn() ? externalBundledOutput[side.ordinal()] : 0; } - public void setRedstoneInput( int side, int level ) + public void setRedstoneInput( ComputerSide side, int level ) { - if( input[side] != level ) + int index = side.ordinal(); + if( input[index] != level ) { - input[side] = level; + input[index] = level; inputChanged = true; } } - public void setBundledRedstoneInput( int side, int combination ) + public void setBundledRedstoneInput( ComputerSide side, int combination ) { - if( bundledInput[side] != combination ) + int index = side.ordinal(); + if( bundledInput[index] != combination ) { - bundledInput[side] = combination; + bundledInput[index] = combination; inputChanged = true; } } @@ -222,7 +226,7 @@ public final class Environment implements IAPIEnvironment boolean changed = false; - for( int i = 0; i < SIDE_COUNT; i++ ) + for( int i = 0; i < ComputerSide.COUNT; i++ ) { if( externalOutput[i] != internalOutput[i] ) { @@ -255,24 +259,25 @@ public final class Environment implements IAPIEnvironment } @Override - public IPeripheral getPeripheral( int side ) + public IPeripheral getPeripheral( ComputerSide side ) { synchronized( peripherals ) { - return peripherals[side]; + return peripherals[side.ordinal()]; } } - public void setPeripheral( int side, IPeripheral peripheral ) + public void setPeripheral( ComputerSide side, IPeripheral peripheral ) { synchronized( peripherals ) { - IPeripheral existing = peripherals[side]; + int index = side.ordinal(); + IPeripheral existing = peripherals[index]; if( (existing == null && peripheral != null) || (existing != null && peripheral == null) || (existing != null && !existing.equals( peripheral )) ) { - peripherals[side] = peripheral; + peripherals[index] = peripheral; if( peripheralListener != null ) peripheralListener.onPeripheralChanged( side, peripheral ); } } diff --git a/src/main/java/dan200/computercraft/shared/BundledRedstone.java b/src/main/java/dan200/computercraft/shared/BundledRedstone.java index 84ae84ae4..dda37859e 100644 --- a/src/main/java/dan200/computercraft/shared/BundledRedstone.java +++ b/src/main/java/dan200/computercraft/shared/BundledRedstone.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared; -import com.google.common.base.Preconditions; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider; @@ -16,6 +15,7 @@ import net.minecraft.world.World; import javax.annotation.Nonnull; import java.util.LinkedHashSet; +import java.util.Objects; import java.util.Set; public final class BundledRedstone @@ -26,7 +26,7 @@ public final class BundledRedstone public static void register( @Nonnull IBundledRedstoneProvider provider ) { - Preconditions.checkNotNull( provider, "provider cannot be null" ); + Objects.requireNonNull( provider, "provider cannot be null" ); providers.add( provider ); } diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index 7356ee196..3052c9a77 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -11,8 +11,8 @@ import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.exceptions.CommandSyntaxException; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.core.apis.IAPIEnvironment; import dan200.computercraft.core.computer.Computer; +import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.tracking.ComputerTracker; import dan200.computercraft.core.tracking.Tracking; import dan200.computercraft.core.tracking.TrackingContext; @@ -117,12 +117,12 @@ public final class CommandComputerCraft table.row( header( "Position" ), linkPosition( context.getSource(), computer ) ); table.row( header( "Family" ), text( computer.getFamily().toString() ) ); - for( int i = 0; i < 6; i++ ) + for( ComputerSide side : ComputerSide.values() ) { - IPeripheral peripheral = computer.getPeripheral( i ); + IPeripheral peripheral = computer.getPeripheral( side ); if( peripheral != null ) { - table.row( header( "Peripheral " + IAPIEnvironment.SIDE_NAMES[i] ), text( peripheral.getType() ) ); + table.row( header( "Peripheral " + side.getName() ), text( peripheral.getType() ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/command/Exceptions.java b/src/main/java/dan200/computercraft/shared/command/Exceptions.java index eb48f7345..78862dbb2 100644 --- a/src/main/java/dan200/computercraft/shared/command/Exceptions.java +++ b/src/main/java/dan200/computercraft/shared/command/Exceptions.java @@ -16,7 +16,7 @@ public final class Exceptions public static final DynamicCommandExceptionType COMPUTER_ARG_NONE = translated1( "argument.computercraft.computer.no_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.tacking_field.no_field" ); + public static final DynamicCommandExceptionType TRACKING_FIELD_ARG_NONE = translated1( "argument.computercraft.tracking_field.no_field" ); 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" ); diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java index 7c215dd06..6f581268a 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -7,6 +7,7 @@ package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.common.BlockGeneric; import dan200.computercraft.shared.common.IBundledRedstoneBlock; import dan200.computercraft.shared.computer.core.ComputerFamily; @@ -65,9 +66,8 @@ public abstract class BlockComputerBase extends Bloc ServerComputer computer = computerEntity.getServerComputer(); if( computer == null ) return 0; - Direction localSide = computerEntity.remapToLocalSide( incomingSide.getOpposite() ); - return computerEntity.isRedstoneBlockedOnSide( localSide ) ? 0 : - computer.getRedstoneOutput( localSide.getId() ); + ComputerSide localSide = computerEntity.remapToLocalSide( incomingSide.getOpposite() ); + return computerEntity.isRedstoneBlockedOnSide( localSide ) ? 0 : computer.getRedstoneOutput( localSide ); } @Nonnull @@ -105,9 +105,8 @@ public abstract class BlockComputerBase extends Bloc ServerComputer computer = computerEntity.getServerComputer(); if( computer == null ) return 0; - Direction localSide = computerEntity.remapToLocalSide( side ); - return computerEntity.isRedstoneBlockedOnSide( localSide ) ? 0 : - computer.getBundledRedstoneOutput( localSide.getId() ); + ComputerSide localSide = computerEntity.remapToLocalSide( side ); + return computerEntity.isRedstoneBlockedOnSide( localSide ) ? 0 : computer.getBundledRedstoneOutput( localSide ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java index c802ea896..4aba3626e 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -7,6 +7,7 @@ package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; @@ -95,8 +96,12 @@ public class TileComputer extends TileComputerBase } @Override - protected Direction remapLocalSide( Direction localSide ) + protected ComputerSide remapLocalSide( ComputerSide localSide ) { - return localSide.getAxis() == Direction.Axis.X ? localSide.getOpposite() : localSide; + // 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. + if( localSide == ComputerSide.RIGHT ) return ComputerSide.LEFT; + if( localSide == ComputerSide.LEFT ) return ComputerSide.RIGHT; + return localSide; } } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index 753309cb2..c6ede7a3b 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -9,6 +9,7 @@ package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralTile; +import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.BundledRedstone; import dan200.computercraft.shared.Peripherals; import dan200.computercraft.shared.common.TileGeneric; @@ -201,24 +202,24 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT m_on = m_startOn = nbt.getBoolean( NBT_ON ); } - protected boolean isPeripheralBlockedOnSide( Direction localSide ) + protected boolean isPeripheralBlockedOnSide( ComputerSide localSide ) { return false; } - protected boolean isRedstoneBlockedOnSide( Direction localSide ) + protected boolean isRedstoneBlockedOnSide( ComputerSide localSide ) { return false; } protected abstract Direction getDirection(); - protected Direction remapToLocalSide( Direction globalSide ) + protected ComputerSide remapToLocalSide( Direction globalSide ) { return remapLocalSide( DirectionUtil.toLocal( getDirection(), globalSide ) ); } - protected Direction remapLocalSide( Direction localSide ) + protected ComputerSide remapLocalSide( ComputerSide localSide ) { return localSide; } @@ -226,15 +227,15 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT private void updateSideInput( ServerComputer computer, Direction dir, BlockPos offset ) { Direction offsetSide = dir.getOpposite(); - Direction localDir = remapToLocalSide( dir ); + ComputerSide localDir = remapToLocalSide( dir ); if( !isRedstoneBlockedOnSide( localDir ) ) { - computer.setRedstoneInput( localDir.getId(), getWorld().getEmittedRedstonePower( offset, dir ) ); - computer.setBundledRedstoneInput( localDir.getId(), BundledRedstone.getOutput( getWorld(), offset, offsetSide ) ); + computer.setRedstoneInput( localDir, getWorld().getEmittedRedstonePower( offset, dir ) ); + computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getWorld(), offset, offsetSide ) ); } if( !isPeripheralBlockedOnSide( localDir ) ) { - computer.setPeripheral( localDir.getId(), Peripherals.getPeripheral( getWorld(), offset, offsetSide ) ); + computer.setPeripheral( localDir, Peripherals.getPeripheral( getWorld(), offset, offsetSide ) ); } } @@ -260,7 +261,6 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT ServerComputer computer = getServerComputer(); if( computer == null ) return; - // Find the appropriate side and update. BlockPos pos = computer.getPosition(); for( Direction dir : DirectionUtil.FACINGS ) { @@ -271,6 +271,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT break; } } + + // If the position is not any adjacent one, update all inputs. + updateInput(); } public void updateOutput() diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index 9012ff749..a74ccd817 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -14,6 +14,7 @@ import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.apis.IAPIEnvironment; import dan200.computercraft.core.computer.Computer; +import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.IComputerEnvironment; import dan200.computercraft.shared.common.ServerTerminal; import dan200.computercraft.shared.network.NetworkHandler; @@ -264,22 +265,22 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput m_computer.queueEvent( event, arguments ); } - public int getRedstoneOutput( int side ) + public int getRedstoneOutput( ComputerSide side ) { return m_computer.getEnvironment().getExternalRedstoneOutput( side ); } - public void setRedstoneInput( int side, int level ) + public void setRedstoneInput( ComputerSide side, int level ) { m_computer.getEnvironment().setRedstoneInput( side, level ); } - public int getBundledRedstoneOutput( int side ) + public int getBundledRedstoneOutput( ComputerSide side ) { return m_computer.getEnvironment().getExternalBundledRedstoneOutput( side ); } - public void setBundledRedstoneInput( int side, int combination ) + public void setBundledRedstoneInput( ComputerSide side, int combination ) { m_computer.getEnvironment().setBundledRedstoneInput( side, combination ); } @@ -289,12 +290,12 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput m_computer.addApi( api ); } - public void setPeripheral( int side, IPeripheral peripheral ) + public void setPeripheral( ComputerSide side, IPeripheral peripheral ) { m_computer.getEnvironment().setPeripheral( side, peripheral ); } - public IPeripheral getPeripheral( int side ) + public IPeripheral getPeripheral( ComputerSide side ) { return m_computer.getEnvironment().getPeripheral( side ); } diff --git a/src/main/java/dan200/computercraft/shared/mixin/MixinFirstPersonRenderer.java b/src/main/java/dan200/computercraft/shared/mixin/MixinFirstPersonRenderer.java index a490ff96c..35702b427 100644 --- a/src/main/java/dan200/computercraft/shared/mixin/MixinFirstPersonRenderer.java +++ b/src/main/java/dan200/computercraft/shared/mixin/MixinFirstPersonRenderer.java @@ -26,7 +26,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; public class MixinFirstPersonRenderer implements MixedFirstPersonRenderer { @Shadow - private float getMapAngle ( float pitch ) + private float getMapAngle( float pitch ) { return 0; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java index bb7ef589c..2724a4f92 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java @@ -11,6 +11,7 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.shared.common.BlockGeneric; import dan200.computercraft.shared.util.WaterloggableBlock; +import dan200.computercraft.shared.util.WorldUtil; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.block.Block; @@ -113,8 +114,7 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock ItemStack item; - AxisAlignedBB bb = cable.getModemBounds(); - if( WorldUtil.isVecInsideInclusive( bb, hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ) + if( WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ) { newState = state.with( MODEM, CableModemVariant.None ); item = new ItemStack( ComputerCraft.Items.wiredModem ); @@ -154,10 +154,8 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock if( modem == null ) return new ItemStack( ComputerCraft.Items.cable ); // We've a modem and cable, so try to work out which one we're interacting with - BlockEntity tile = world.getBlockEntity( pos ); HitResult hit = MinecraftClient.getInstance().hitResult; - return tile instanceof TileCable && hit != null && - CableShapes.getModemShape( state ).getBoundingBox().contains( hit.getPos().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) + return hit != null && WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getPos().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ? new ItemStack( ComputerCraft.Items.wiredModem ) : new ItemStack( ComputerCraft.Items.cable ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index 8b3b9035c..19a4ad6ec 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -318,15 +318,16 @@ public class TileCable extends TileGeneric implements IPeripheralTile IWiredElement element = ComputerCraftAPI.getWiredElementAt( world, offset, facing.getOpposite() ); if( element == null ) continue; + IWiredNode node = element.getNode(); if( BlockCable.canConnectIn( state, facing ) ) { // If we can connect to it then do so - m_node.connectTo( element.getNode() ); + m_node.connectTo( node ); } - else if( m_node.getNetwork() == element.getNode().getNetwork() ) + else if( m_node.getNetwork() == node.getNetwork() ) { // Otherwise if we're on the same network then attempt to void it. - m_node.disconnectFrom( element.getNode() ); + m_node.disconnectFrom( node ); } } } @@ -400,7 +401,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile return !m_destroyed && hasModem() && side == getDirection() ? m_modem : null; } - public boolean hasCable() + boolean hasCable() { return getCachedState().get( BlockCable.CABLE ); } @@ -410,7 +411,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile return getCachedState().get( BlockCable.MODEM ) != CableModemVariant.None; } - boolean canAttachPeripheral() + private boolean canAttachPeripheral() { return hasCable() && hasModem(); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 4d188567a..e4b597422 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.base.Objects; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.ComputerCraftAPIImpl; +import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.network.wired.IWiredElement; import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.peripheral.IPeripheral; @@ -271,10 +271,9 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile BlockPos offset = current.offset( facing ); if( !world.isBlockLoaded( offset ) ) continue; - IWiredElement element = ComputerCraftAPIImpl.INSTANCE.getWiredElementAt( world, offset, facing.getOpposite() ); + IWiredElement element = ComputerCraftAPI.getWiredElementAt( world, offset, facing.getOpposite() ); if( element == null ) continue; - // If we can connect to it then do so m_node.connectTo( element.getNode() ); } } @@ -347,7 +346,11 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile @Override public LazyOptional getCapability( @Nonnull Capability capability, @Nullable Direction facing ) { - if( capability == CapabilityWiredElement.CAPABILITY ) return m_elementCap.cast(); + if( capability == CapabilityWiredElement.CAPABILITY ) + { + if( elementCap == null ) elementCap = LazyOptional.of( () -> m_element ); + return elementCap.cast(); + } return super.getCapability( capability, facing ); } */ diff --git a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index a49956b6c..f9d2669be 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -10,6 +10,7 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.pocket.IPocketAccess; import dan200.computercraft.api.pocket.IPocketUpgrade; +import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; @@ -123,14 +124,14 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces public void invalidatePeripheral() { IPeripheral peripheral = m_upgrade == null ? null : m_upgrade.createPeripheral( this ); - setPeripheral( 2, peripheral ); + setPeripheral( ComputerSide.BACK, peripheral ); } @Nonnull @Override public Map getUpgrades() { - return m_upgrade == null ? Collections.emptyMap() : Collections.singletonMap( m_upgrade.getUpgradeID(), getPeripheral( 2 ) ); + return m_upgrade == null ? Collections.emptyMap() : Collections.singletonMap( m_upgrade.getUpgradeID(), getPeripheral( ComputerSide.BACK ) ); } public IPocketUpgrade getUpgrade() diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index 58d473a05..67a804430 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -12,6 +12,7 @@ import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.pocket.IPocketUpgrade; +import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.PocketUpgrades; import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.computer.core.ClientComputer; @@ -120,7 +121,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I // Update pocket upgrade if( upgrade != null ) { - upgrade.update( computer, computer.getPeripheral( 2 ) ); + upgrade.update( computer, computer.getPeripheral( ComputerSide.BACK ) ); } } } @@ -149,7 +150,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I if( upgrade != null ) { computer.updateValues( player, stack, upgrade ); - stop = upgrade.onRightClick( world, computer, computer.getPeripheral( 2 ) ); + stop = upgrade.onRightClick( world, computer, computer.getPeripheral( ComputerSide.BACK ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index 5a570ab58..7321310cc 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -12,6 +12,7 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; +import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.computer.blocks.ComputerPeripheral; import dan200.computercraft.shared.computer.blocks.ComputerProxy; @@ -150,9 +151,6 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default @Override public boolean onActivate( PlayerEntity player, Hand hand, BlockHitResult hit ) { - // Request description from server - // requestTileEntityUpdate(); - // Apply dye ItemStack currentItem = player.getStackInHand( hand ); if( !currentItem.isEmpty() ) @@ -313,13 +311,13 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default } @Override - protected boolean isPeripheralBlockedOnSide( Direction localSide ) + protected boolean isPeripheralBlockedOnSide( ComputerSide localSide ) { return hasPeripheralUpgradeOnSide( localSide ); } @Override - protected boolean isRedstoneBlockedOnSide( Direction localSide ) + protected boolean isRedstoneBlockedOnSide( ComputerSide localSide ) { return false; } @@ -557,15 +555,15 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default // Privates - private boolean hasPeripheralUpgradeOnSide( Direction side ) + private boolean hasPeripheralUpgradeOnSide( ComputerSide side ) { ITurtleUpgrade upgrade; switch( side ) { - case WEST: + case RIGHT: upgrade = getUpgrade( TurtleSide.Right ); break; - case EAST: + case LEFT: upgrade = getUpgrade( TurtleSide.Left ); break; default: diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 9b64779a8..a4f503e69 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -13,6 +13,7 @@ import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.*; +import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.computer.blocks.ComputerProxy; import dan200.computercraft.shared.computer.blocks.TileComputerBase; @@ -729,15 +730,15 @@ public class TurtleBrain implements ITurtleAccess : 0.0f; } - private static int toDirection( TurtleSide side ) + private static ComputerSide toDirection( TurtleSide side ) { switch( side ) { case Left: - return 5; + return ComputerSide.LEFT; case Right: default: - return 4; + return ComputerSide.RIGHT; } } diff --git a/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java b/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java index bbe46af54..d38b06406 100644 --- a/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java @@ -6,6 +6,7 @@ package dan200.computercraft.shared.util; +import dan200.computercraft.core.computer.ComputerSide; import net.minecraft.util.math.Direction; public final class DirectionUtil @@ -14,28 +15,16 @@ public final class DirectionUtil public static final Direction[] FACINGS = Direction.values(); - public static Direction toLocal( Direction front, Direction relative ) + public static ComputerSide toLocal( Direction front, Direction dir ) { - if( relative.getAxis() == Direction.Axis.Y ) return relative; - if( front.getAxis() == Direction.Axis.Y ) front = Direction.NORTH; - if( relative == front ) - { - return Direction.SOUTH; - } - else if( relative == front.getOpposite() ) - { - return Direction.NORTH; - } - else if( relative == front.rotateYCounterclockwise() ) - { - return Direction.EAST; - } - else - { - return Direction.WEST; - } + if( dir == front ) return ComputerSide.FRONT; + if( dir == front.getOpposite() ) return ComputerSide.BACK; + if( dir == front.rotateYCounterclockwise() ) return ComputerSide.LEFT; + if( dir == front.rotateYClockwise() ) return ComputerSide.RIGHT; + if( dir == Direction.UP ) return ComputerSide.TOP; + return ComputerSide.BOTTOM; } public static float toPitchAngle( Direction dir ) diff --git a/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java b/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java index 36b854746..bbdfe31f8 100644 --- a/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java @@ -15,17 +15,10 @@ public final class RedstoneUtil { public static void propagateRedstoneOutput( World world, BlockPos pos, Direction side ) { - // Propagate ordinary output + // Propagate ordinary output. See BlockRedstoneDiode.notifyNeighbors BlockState block = world.getBlockState( pos ); BlockPos neighbourPos = pos.offset( side ); - BlockState neighbour = world.getBlockState( neighbourPos ); - if( !neighbour.isAir() ) - { - world.updateNeighbor( neighbourPos, block.getBlock(), pos ); - if( neighbour.isSimpleFullBlock( world, neighbourPos ) ) - { - world.updateNeighborsExcept( neighbourPos, block.getBlock(), side.getOpposite() ); - } - } + world.updateNeighbor( neighbourPos, block.getBlock(), pos ); + world.updateNeighborsExcept( neighbourPos, block.getBlock(), side.getOpposite() ); } } diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index 49d8a098f..39b7227ef 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -41,7 +41,7 @@ public final class WorldUtil public static boolean isVecInside( VoxelShape shape, Vec3d vec ) { if( shape.isEmpty() ) return false; - // return shape.contains( pos.x, pos.y, pos.z ); + // AxisAlignedBB.contains, but without strict inequalities. BoundingBox bb = shape.getBoundingBox(); return vec.x >= bb.minX && vec.x <= bb.maxX && vec.y >= bb.minY && vec.y <= bb.maxY && vec.z >= bb.minZ && vec.z <= bb.maxZ; } diff --git a/src/main/resources/assets/computercraft/lang/de_de.json b/src/main/resources/assets/computercraft/lang/de_de.json index 329d6d17b..14a8ae879 100644 --- a/src/main/resources/assets/computercraft/lang/de_de.json +++ b/src/main/resources/assets/computercraft/lang/de_de.json @@ -1,4 +1,5 @@ { + "itemGroup.computercraft": "CC: Tweaked", "block.computercraft.computer_normal": "Computer", "block.computercraft.computer_advanced": "Erweiterter Computer", @@ -50,6 +51,99 @@ "chat.computercraft.wired_modem.peripheral_connected": "Peripheriegerät \"%s\" mit dem Netzwerk verbunden", "chat.computercraft.wired_modem.peripheral_disconnected": "Peripheriegerät \"%s\" vom Netzwerk getrennt", + "commands.computercraft.synopsis": "Verschiedene Befehle um Computer zu kontrollieren.", + "commands.computercraft.desc": "Der /computercraft Befehl enthält verschiedene Werkzeuge um Computer zu debuggen, kontrollieren oder mit ihnen zu interagieren.", + + "commands.computercraft.help.synopsis": "Zeigt die Hilfe für den angegebenen Befehl", + "commands.computercraft.help.desc": "", + "commands.computercraft.help.no_children": "%s hat keine Unterbefehle", + "commands.computercraft.help.no_command": "Unbekannter Befehl '%s'", + + "commands.computercraft.dump.synopsis": "Zeigt den Status eines Computers.", + "commands.computercraft.dump.desc": "Zeigt den Status aller Computer oder genauere Informationen über einen angegebenen Computer. Der Computer kann entweder über seine Instanz ID (z.B. 123), seine Computer ID (z.B. #123) oder seinen Namen (z.B. \"@Mein Computer\") angegeben werden.", + "commands.computercraft.dump.action": "Zeigt mehr Informationen über einen Computer", + + "commands.computercraft.shutdown.synopsis": "Fährt den Computer aus der Ferne herunter.", + "commands.computercraft.shutdown.desc": "Fährt die angegebenen Computer herunter. Falls keine Computer angegeben sind, werden alle heruntergefahren. Der Computer kann entweder über seine Instanz ID (z.B. 123), seine Computer ID (z.B. #123) oder seinen Namen (z.B. \"@Mein Computer\") angegeben werden.", + "commands.computercraft.shutdown.done": "Fährt die Computer %s/%s herunter", + + "commands.computercraft.turn_on.synopsis": "Fährt einen Computer aus der Ferne hoch.", + "commands.computercraft.turn_on.desc": "Fährt die angegebenen Computer hoch. Der Computer kann entweder über seine Instanz ID (z.B. 123), seine Computer ID (z.B. #123) oder seinen Namen (z.B. \"@Mein Computer\") angegeben werden.", + "commands.computercraft.turn_on.done": "Fährt die Computer %s/%s hoch", + + "commands.computercraft.tp.synopsis": "Teleportiert dich zum angegebenen Computer.", + "commands.computercraft.tp.desc": "Teleportiert dich zum Standort eines Computers. Der Computer kann entweder über seine Instanz ID (z.B. 123), seine Computer ID (z.B. #123) oder seinen Namen (z.B. \"@Mein Computer\") angegeben werden.", + "commands.computercraft.tp.action": "Teleportiert dich zum Computer", + "commands.computercraft.tp.not_player": "Konnte Terminal für Nicht-Spieler nicht öffnen", + "commands.computercraft.tp.not_there": "Konnte Computer in der Welt nicht finden", + + "commands.computercraft.view.synopsis": "Zeigt das Terminal eines Computers.", + "commands.computercraft.view.desc": "Zeigt das Terminal eines Computers. Dies ermöglicht, den Computer aus der Ferne zu steuern. Ein Zugriff auf das Inventar eines Turtles ist dadurch allerdings nicht möglich. Der Computer kann entweder über seine Instanz ID (z.B. 123), seine Computer ID (z.B. #123) oder seinen Namen (z.B. \"@Mein Computer\") angegeben werden.", + "commands.computercraft.view.action": "Zeigt den Computer", + "commands.computercraft.view.not_player": "Konnte Terminal für Nicht-Spieler nicht öffnen", + + "commands.computercraft.track.synopsis": "Zeichnet die Laufzeiten von Computern auf.", + "commands.computercraft.track.desc": "Zeichnet die Laufzeiten von Computern und wie viele Events ausgelöst werden auf. Die Ausgabe der Informationen ist ähnlich zu /forge track, was beim aufspüren von Lags sehr hilfreich sein kann.", + + "commands.computercraft.track.start.synopsis": "Startet die Aufzeichnung von Computern", + "commands.computercraft.track.start.desc": "Startet die Aufzeichnung der Laufzeiten und Anzahl der Events aller Computer. Dadurch werden die Ergebnisse der letzten Male verworfen.", + "commands.computercraft.track.start.stop": "Führe %s aus um die Aufzeichnung zu stoppen und die Ergebnisse anzusehen", + + "commands.computercraft.track.stop.synopsis": "Stoppt die Aufzeichnung aller Computer", + "commands.computercraft.track.stop.desc": "Stopt die Aufzeichnung aller Computer Events und Laufzeiten", + "commands.computercraft.track.stop.action": "Klicke um die Aufzeichnung zu stoppen", + "commands.computercraft.track.stop.not_enabled": "Momentan werden keine Computer aufgezeichnet", + + "commands.computercraft.track.dump.synopsis": "Gibt die aktuellen Ergebnisse der Aufzeichnung aus", + "commands.computercraft.track.dump.desc": "Gibt die aktuellen Ergebnisse der Aufzeichnung aus.", + "commands.computercraft.track.dump.no_timings": "Keine Zeitangaben verfügbar", + "commands.computercraft.track.dump.computer": "Computer", + + "commands.computercraft.reload.synopsis": "Liest die Konfigurationsdatei von ComputerCraft neu ein", + "commands.computercraft.reload.desc": "Liest die Konfigurationsdatei von ComputerCraft neu ein", + "commands.computercraft.reload.done": "Die Konfigurationsdatei wurde erfolgreich neu eingelesen", + + "commands.computercraft.queue.synopsis": "Sendet ein computer_command Event an einen Befehlscomputer", + "commands.computercraft.queue.desc": "Sendet ein computer_command Event zusammen mit optionalen Argumenten an einen Befehlscomputer. Dieser Befehl wurde als eine Computerfreundliche Version von /trigger für Mapdesigner designed. Jeder Spieler kann diesen Befehl ausführen, weshalb er sich perfekt für ein Klickevent von z.B. Schildern oder Büchern eignet.", + + "commands.computercraft.generic.no_position": "", + "commands.computercraft.generic.position": "%s, %s, %s", + "commands.computercraft.generic.yes": "J", + "commands.computercraft.generic.no": "N", + "commands.computercraft.generic.exception": "Unbehandelte Ausnahme (%s)", + "commands.computercraft.generic.additional_rows": "%d zusätzliche Zeilen…", + + "argument.computercraft.computer.no_matching": "Kein Computer passt auf '%s'", + "argument.computercraft.computer.many_matching": "Mehrere Computer passen auf '%s' (Instanzen %s)", + + "argument.computercraft.tracking_field.no_field": "Unbekanntes Feld '%s'", + + "tracking_field.computercraft.tasks.name": "Aufgaben", + "tracking_field.computercraft.total.name": "Gesamtzeit", + "tracking_field.computercraft.average.name": "Durchschnittliche Zeit", + "tracking_field.computercraft.max.name": "Maximale Zeit", + + "tracking_field.computercraft.server_count.name": "Anzahl der Server-Tasks", + "tracking_field.computercraft.server_time.name": "Server-Task-Zeit", + + "tracking_field.computercraft.peripheral.name": "Peripheriegeräte Aufrufe", + "tracking_field.computercraft.fs.name": "Dateisystem Operationen", + "tracking_field.computercraft.turtle.name": "Turtle Operationen", + + "tracking_field.computercraft.http.name": "HTTP-Requests", + "tracking_field.computercraft.http_upload.name": "HTTP Upload", + "tracking_field.computercraft.http_download.name": "HTTT Download", + + "tracking_field.computercraft.websocket_incoming.name": "Websocket eingehend", + "tracking_field.computercraft.websocket_outgoing.name": "Websocket ausgehend", + + "tracking_field.computercraft.coroutines_created.name": "Koroutinen erstellt", + "tracking_field.computercraft.coroutines_dead.name": "Koroutinen gelöscht", + + "gui.computercraft.tooltip.copy": "In die Zwischenablage kopieren", + "gui.computercraft.tooltip.computer_id": "(Computer ID: %s)", + "gui.computercraft.tooltip.disk_id": "(Disketten ID: %s)", + "gui.computercraft.config.computer_space_limit": "Speicherplatz von Computern (bytes)", "gui.computercraft.config.floppy_space_limit": "Speicherplatz von Disketten (bytes)", "gui.computercraft.config.maximum_open_files": "Maximalanzahl an gleichzeitig offenen Dateien je Computer", @@ -58,11 +152,25 @@ "gui.computercraft.config.debug_enabled": "Debug-Library aktivieren", "gui.computercraft.config.log_computer_errors": "Peripheriefehler loggen", + "gui.computercraft.config.execution": "Ausführung", + "gui.computercraft.config.execution.computer_threads": "Computer Threads", + "gui.computercraft.config.execution.max_main_global_time": "Globales Servertick Zeitlimit", + "gui.computercraft.config.execution.max_main_computer_time": "Computer Servertick Zeitlimit", + + "gui.computercraft.config.http": "HTTP", "gui.computercraft.config.http.enabled": "HTTP-API aktivieren", "gui.computercraft.config.http.websocket_enabled": "HTTP-Websockets aktivieren", "gui.computercraft.config.http.whitelist": "HTTP-Whitelist", "gui.computercraft.config.http.blacklist": "HTTP-Blacklist", + "gui.computercraft.config.http.timeout": "Zeitüberschreitung", + "gui.computercraft.config.http.max_requests": "Maximale Anzahl gleichzeitiger Anfragen", + "gui.computercraft.config.http.max_download": "Maximale Antwortgröße", + "gui.computercraft.config.http.max_upload": "Maximale Anfragegröße", + "gui.computercraft.config.http.max_websockets": "Maximale Anzahl gleichzeitiger Websockets", + "gui.computercraft.config.http.max_websocket_message": "Maximale Größe der Websocket-Nachricht", + + "gui.computercraft.config.peripheral": "Peripheriegeräte", "gui.computercraft.config.peripheral.command_block_enabled": "Befehlsblöcke als Peripheriegerät erlauben", "gui.computercraft.config.peripheral.modem_range": "Modemreichweite (normal)", "gui.computercraft.config.peripheral.modem_high_altitude_range": "Modemreichweite (in großer Höhe)", @@ -70,6 +178,7 @@ "gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm": "Modemreichweite (in großer Höhe bei schlechtem Wetter)", "gui.computercraft.config.peripheral.max_notes_per_tick": "Maximalanzahl an Noten, die ein Computer gleichzeitig spielen kann", + "gui.computercraft.config.turtle": "Turtles", "gui.computercraft.config.turtle.need_fuel": "Treibstoffverbrauch aktivieren", "gui.computercraft.config.turtle.normal_fuel_limit": "Treibstofflimit von Turtles", "gui.computercraft.config.turtle.advanced_fuel_limit": "Treibstofflimit von Erweiterten Turtles", diff --git a/src/main/resources/assets/computercraft/lang/en_us.json b/src/main/resources/assets/computercraft/lang/en_us.json index 049ad6375..8dd1bc9f0 100644 --- a/src/main/resources/assets/computercraft/lang/en_us.json +++ b/src/main/resources/assets/computercraft/lang/en_us.json @@ -116,7 +116,7 @@ "argument.computercraft.computer.no_matching": "No computers matching '%s'", "argument.computercraft.computer.many_matching": "Multiple computers matching '%s' (instances %s)", - "argument.computercraft.tacking_field.no_field": "Unknown field '%s'", + "argument.computercraft.tracking_field.no_field": "Unknown field '%s'", "argument.computercraft.argument_expected": "Argument expected", diff --git a/src/test/resources/test-rom/spec/apis/colors_spec.lua b/src/test/resources/test-rom/spec/apis/colors_spec.lua new file mode 100644 index 000000000..d1271b625 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/colors_spec.lua @@ -0,0 +1,43 @@ +describe("The colors library", function() + it("colors.combine", function() + expect(colors.combine(colors.red, colors.brown, colors.green)):equals(0x7000) + end) + + describe("colors.subtract", function() + it("subtracts colours", function() + expect(colors.subtract(0x7000, colors.green)):equals(0x5000) + expect(colors.subtract(0x5000, colors.red)):equals(0x1000) + end) + it("does nothing when color is not present", function() + expect(colors.subtract(0x1000, colors.red)):equals(0x1000) + end) + it("accepts multiple arguments", function() + expect(colors.subtract(0x7000, colors.red, colors.green, colors.red)):equals(0x1000) + end) + end) + + describe("colors.test", function() + it("returns true when present", function() + expect(colors.test(0x7000, colors.green)):equals(true) + end) + it("returns false when absent", function() + expect(colors.test(0x5000, colors.green)):equals(false) + end) + it("allows multiple colors", function() + expect(colors.test(0x7000, 0x5000)):equals(true) + end) + end) + + it("colors.packRGB", function() + expect(colors.packRGB(0.3, 0.5, 0.6)):equals(0x4c7f99) + end) + + it("colors.unpackRGB", function() + expect({ colors.unpackRGB(0x4c7f99) }):same { 0x4c / 0xFF, 0x7f / 0xFF, 0.6 } + end) + + it("colors.rgb8", function() + expect(colors.rgb8(0.3, 0.5, 0.6)):equals(0x4c7f99) + expect({ colors.rgb8(0x4c7f99) }):same { 0x4c / 0xFF, 0x7f / 0xFF, 0.6 } + end) +end )