diff --git a/build.gradle b/build.gradle index ccf90db0f..038df84f4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,7 @@ - -// For those who want the bleeding edge buildscript { repositories { jcenter() + mavenCentral() maven { name = "forge" url = "http://files.minecraftforge.net/maven" @@ -10,17 +9,17 @@ } dependencies { classpath 'com.google.code.gson:gson:2.8.1' - classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' - classpath 'net.sf.proguard:proguard-gradle:6.1.0beta1' + classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.115' + classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' } } plugins { - id 'com.matthewprenger.cursegradle' version '1.0.10' + id 'com.matthewprenger.cursegradle' version '1.2.0' } -apply plugin: 'net.minecraftforge.gradle.forge' +apply plugin: 'net.minecraftforge.gradle' apply plugin: 'org.ajoberstar.grgit' apply plugin: 'maven-publish' apply plugin: 'maven' @@ -31,18 +30,41 @@ archivesBaseName = "cc-tweaked-${mc_version}" minecraft { - version = "${mc_version}-${forge_version}" - runDir = "run" - replace '${version}', mod_version + runs { + client { + workingDirectory project.file('run') + property 'forge.logging.markers', 'REGISTRIES' + property 'forge.logging.console.level', 'debug' - mappings = mappings_version - makeObfSourceJar = false + mods { + computercraft { + source sourceSets.main + } + } + } + + server { + workingDirectory project.file('run') + property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' + property 'forge.logging.console.level', 'debug' + + mods { + computercraft { + source sourceSets.main + } + } + } + } + + mappings channel: 'snapshot', version: "${mappings_version}".toString() + + accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg') } repositories { maven { name "JEI" - url "http://dvs1.progwml6.com/files/maven" + url "http://dvs1.progwml6.com/files/maven" } maven { name "SquidDev" @@ -65,11 +87,13 @@ } dependencies { - deobfProvided "mezz.jei:jei_1.12.2:4.15.0.269:api" - deobfProvided "pl.asie:Charset-Lib:0.5.4.6" - deobfProvided "MCMultiPart2:MCMultiPart:2.5.3" + minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" - runtime "mezz.jei:jei_1.12.2:4.15.0.269" + compileOnly "mezz.jei:jei-1.13.2:5.0.0.8:api" + // deobfProvided "pl.asie:Charset-Lib:0.5.4.6" + // deobfProvided "MCMultiPart2:MCMultiPart:2.5.3" + + deobf "mezz.jei:jei-1.13.2:5.0.0.8" shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT' @@ -79,6 +103,15 @@ deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0" } +sourceSets { + main { + java { + exclude 'dan200/computercraft/shared/integration/mcmp' + exclude 'dan200/computercraft/shared/integration/charset' + } + } +} + javadoc { include "dan200/computercraft/api/**/*.java" } @@ -87,7 +120,13 @@ dependsOn javadoc manifest { - attributes('FMLAT': 'computercraft_at.cfg') + attributes(["Specification-Title": "computercraft", + "Specification-Vendor": "SquidDev", + "Specification-Version": "25.0", + "Implementation-Title": "CC: Tweaked", + "Implementation-Version": "${mod_version}", + "Implementation-Vendor" :"SquidDev", + "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")]) } from (sourceSets.main.allSource) { @@ -132,6 +171,10 @@ task proguard(type: ProGuardTask, dependsOn: jar) { // Preserve the constructors in Cobalt library class, as we init them via reflection keepclassmembers 'class org.squiddev.cobalt.lib.** { (...); }' + + // LWJGL and Apache bundle Java 9 versions, which is great, but rather breaks Proguard + dontwarn 'module-info' + dontwarn 'org.apache.**,org.lwjgl.**' } task proguardMove(dependsOn: proguard) { @@ -147,7 +190,7 @@ task proguardMove(dependsOn: proguard) { } } -reobfJar.dependsOn proguardMove + processResources { inputs.property "version", mod_version @@ -169,8 +212,8 @@ task proguardMove(dependsOn: proguard) { inputs.property "commithash", hash from(sourceSets.main.resources.srcDirs) { - include 'mcmod.info' - include 'assets/computercraft/lua/rom/help/credits.txt' + include 'META-INF/mods.toml' + include 'data/computercraft/lua/rom/help/credits.txt' expand 'version': mod_version, 'mcversion': mc_version, @@ -178,12 +221,12 @@ task proguardMove(dependsOn: proguard) { } from(sourceSets.main.resources.srcDirs) { - exclude 'mcmod.info' - exclude 'assets/computercraft/lua/rom/help/credits.txt' + exclude 'META-INF/mods.toml' + exclude 'data/computercraft/lua/rom/help/credits.txt' } } -task compressJson(dependsOn: extractAnnotationsJar) { +task compressJson(dependsOn: jar) { group "compact" description "Minifies all JSON files, stripping whitespace" @@ -225,6 +268,7 @@ task compressJson(dependsOn: extractAnnotationsJar) { assemble.dependsOn compressJson +/* curseforge { apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : '' project { @@ -233,12 +277,13 @@ task compressJson(dependsOn: extractAnnotationsJar) { changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${project.version})." } } +*/ publishing { publications { mavenJava(MavenPublication) { from components.java - artifact sourceJar + // artifact sourceJar } } } @@ -295,10 +340,10 @@ task compressJson(dependsOn: extractAnnotationsJar) { } gradle.projectsEvaluated { + reobfJar.dependsOn proguardMove + tasks.withType(JavaCompile) { - options.compilerArgs << "-Xlint" << "-Xlint:-processing" << "-Werror" + options.compilerArgs << "-Xlint" << "-Xlint:-processing" // Causes Forge build to fail << "-Werror" } } -runClient.outputs.upToDateWhen { false } -runServer.outputs.upToDateWhen { false } diff --git a/gradle.properties b/gradle.properties index 0c76c812c..2c0e51d49 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,6 +2,6 @@ mod_version=1.82.0 # Minecraft properties -mc_version=1.12.2 -forge_version=14.23.4.2749 -mappings_version=snapshot_20180724 +mc_version=1.13.2 +forge_version=25.0.100 +mappings_version=20190327-1.13.2 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 27768f1bb..28861d273 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ea720f986..a95009c3b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip diff --git a/src/main/java/dan200/computercraft/CCTweaked.java b/src/main/java/dan200/computercraft/CCTweaked.java deleted file mode 100644 index 1ee227a4d..000000000 --- a/src/main/java/dan200/computercraft/CCTweaked.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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; - -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.network.NetworkCheckHandler; -import net.minecraftforge.fml.relauncher.Side; - -import java.util.Map; - -/** - * A stub mod for CC: Tweaked. This doesn't have any functionality (everything of note is done in - * {@link ComputerCraft}), but people may depend on this if they require CC: Tweaked functionality. - */ -@Mod( - modid = "cctweaked", name = ComputerCraft.NAME, version = ComputerCraft.VERSION, - acceptableRemoteVersions = "*" -) -public class CCTweaked -{ - @NetworkCheckHandler - public boolean onNetworkConnect( Map mods, Side side ) - { - return true; - } -} diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index ae6fca8f4..a881b4a96 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -7,99 +7,50 @@ package dan200.computercraft; import dan200.computercraft.api.filesystem.IMount; -import dan200.computercraft.api.filesystem.IWritableMount; -import dan200.computercraft.api.lua.ILuaAPIFactory; -import dan200.computercraft.api.media.IMedia; -import dan200.computercraft.api.media.IMediaProvider; -import dan200.computercraft.api.network.IPacketNetwork; -import dan200.computercraft.api.network.wired.IWiredElement; -import dan200.computercraft.api.network.wired.IWiredNode; -import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.api.peripheral.IPeripheralProvider; -import dan200.computercraft.api.permissions.ITurtlePermissionProvider; -import dan200.computercraft.api.pocket.IPocketUpgrade; -import dan200.computercraft.api.redstone.IBundledRedstoneProvider; -import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.core.apis.AddressPredicate; -import dan200.computercraft.core.apis.ApiFactories; import dan200.computercraft.core.apis.http.websocket.Websocket; -import dan200.computercraft.core.computer.MainThread; -import dan200.computercraft.core.filesystem.ComboMount; -import dan200.computercraft.core.filesystem.FileMount; -import dan200.computercraft.core.filesystem.JarMount; -import dan200.computercraft.core.tracking.Tracking; -import dan200.computercraft.shared.*; -import dan200.computercraft.shared.computer.blocks.BlockCommandComputer; +import dan200.computercraft.core.filesystem.ResourceMount; +import dan200.computercraft.shared.Config; import dan200.computercraft.shared.computer.blocks.BlockComputer; import dan200.computercraft.shared.computer.core.ClientComputerRegistry; import dan200.computercraft.shared.computer.core.ServerComputerRegistry; -import dan200.computercraft.shared.computer.items.ItemCommandComputer; import dan200.computercraft.shared.computer.items.ItemComputer; -import dan200.computercraft.shared.media.items.ItemDiskExpanded; -import dan200.computercraft.shared.media.items.ItemDiskLegacy; +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.peripheral.common.BlockPeripheral; -import dan200.computercraft.shared.peripheral.common.ItemPeripheral; +import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; import dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull; -import dan200.computercraft.shared.peripheral.modem.wired.ItemCable; -import dan200.computercraft.shared.peripheral.modem.wireless.BlockAdvancedModem; -import dan200.computercraft.shared.peripheral.modem.wireless.ItemAdvancedModem; -import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; +import dan200.computercraft.shared.peripheral.modem.wired.ItemBlockCable; +import dan200.computercraft.shared.peripheral.modem.wireless.BlockWirelessModem; +import dan200.computercraft.shared.peripheral.monitor.BlockMonitor; +import dan200.computercraft.shared.peripheral.printer.BlockPrinter; +import dan200.computercraft.shared.peripheral.speaker.BlockSpeaker; 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.proxy.ComputerCraftProxyCommon; import dan200.computercraft.shared.turtle.blocks.BlockTurtle; -import dan200.computercraft.shared.turtle.items.ItemTurtleAdvanced; -import dan200.computercraft.shared.turtle.items.ItemTurtleLegacy; -import dan200.computercraft.shared.turtle.items.ItemTurtleNormal; +import dan200.computercraft.shared.turtle.items.ItemTurtle; import dan200.computercraft.shared.turtle.upgrades.*; -import dan200.computercraft.shared.util.CreativeTabMain; -import dan200.computercraft.shared.util.IDAssigner; -import dan200.computercraft.shared.util.IoUtil; -import dan200.computercraft.shared.wired.CapabilityWiredElement; -import dan200.computercraft.shared.wired.WiredNode; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemBlock; -import net.minecraft.item.ItemStack; -import net.minecraft.server.MinecraftServer; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockAccess; -import net.minecraft.world.World; -import net.minecraftforge.common.DimensionManager; -import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraft.resources.IReloadableResourceManager; +import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.SidedProxy; -import net.minecraftforge.fml.common.event.*; -import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.server.ServerLifecycleHooks; +import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.io.*; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; +import java.io.IOException; +import java.io.InputStream; import java.util.EnumSet; -import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -@Mod( - modid = ComputerCraft.MOD_ID, name = ComputerCraft.NAME, version = ComputerCraft.VERSION, - guiFactory = "dan200.computercraft.client.gui.GuiConfigCC$Factory", - dependencies = "required:forge@[14.23.4.2746,)" -) -public class ComputerCraft +@Mod( ComputerCraft.MOD_ID ) +public final class ComputerCraft { public static final String MOD_ID = "computercraft"; - static final String VERSION = "${version}"; - static final String NAME = "CC: Tweaked"; + + public static final int DATAFIXER_VERSION = 0; // Configuration options public static final String[] DEFAULT_HTTP_WHITELIST = new String[] { "*" }; @@ -161,46 +112,54 @@ public class ComputerCraft // Blocks and Items public static final class Blocks { - public static BlockComputer computer; - public static BlockCommandComputer commandComputer; + public static BlockComputer computerNormal; + public static BlockComputer computerAdvanced; + public static BlockComputer computerCommand; - public static BlockTurtle turtle; - public static BlockTurtle turtleExpanded; + public static BlockTurtle turtleNormal; public static BlockTurtle turtleAdvanced; - public static BlockPeripheral peripheral; - public static BlockCable cable; - public static BlockAdvancedModem advancedModem; + public static BlockSpeaker speaker; + public static BlockDiskDrive diskDrive; + public static BlockPrinter printer; + + public static BlockMonitor monitorNormal; + public static BlockMonitor monitorAdvanced; + + public static BlockWirelessModem wirelessModemNormal; + public static BlockWirelessModem wirelessModemAdvanced; + public static BlockWiredModemFull wiredModemFull; + public static BlockCable cable; } public static final class Items { - public static ItemComputer computer; - public static ItemCommandComputer commandComputer; + public static ItemComputer computerNormal; + public static ItemComputer computerAdvanced; + public static ItemComputer computerCommand; - public static ItemTurtleLegacy turtle; - public static ItemTurtleNormal turtleExpanded; - public static ItemTurtleAdvanced turtleAdvanced; + public static ItemPocketComputer pocketComputerNormal; + public static ItemPocketComputer pocketComputerAdvanced; - public static ItemPocketComputer pocketComputer; + public static ItemTurtle turtleNormal; + public static ItemTurtle turtleAdvanced; - public static ItemDiskLegacy disk; - public static ItemDiskExpanded diskExpanded; + public static ItemDisk disk; public static ItemTreasureDisk treasureDisk; - public static ItemPrintout printout; + public static ItemPrintout printedPage; + public static ItemPrintout printedPages; + public static ItemPrintout printedBook; - public static ItemPeripheral peripheral; - public static ItemAdvancedModem advancedModem; - public static ItemCable cable; - public static ItemBlock wiredModemFull; + public static ItemBlockCable.Cable cable; + public static ItemBlockCable.WiredModem wiredModem; } public static final class TurtleUpgrades { - public static TurtleModem wirelessModem; - public static TurtleModem advancedModem; + public static TurtleModem wirelessModemNormal; + public static TurtleModem wirelessModemAdvanced; public static TurtleSpeaker speaker; public static TurtleCraftingTable craftingTable; @@ -213,445 +172,45 @@ public static final class TurtleUpgrades public static final class PocketUpgrades { - public static PocketModem wirelessModem; - public static PocketModem advancedModem; + public static PocketModem wirelessModemNormal; + public static PocketModem wirelessModemAdvanced; public static PocketSpeaker speaker; - - @Deprecated - public static PocketSpeaker pocketSpeaker; - } - - @Deprecated - public static final class Upgrades - { - public static TurtleModem advancedModem; } // Registries public static final ClientComputerRegistry clientComputerRegistry = new ClientComputerRegistry(); public static final ServerComputerRegistry serverComputerRegistry = new ServerComputerRegistry(); - // Creative - public static CreativeTabMain mainCreativeTab; - // Logging - public static Logger log; + public static final Logger log = LogManager.getLogger( MOD_ID ); - // Peripheral providers. This is still here to ensure compatibility with Plethora and Computronics - public static List peripheralProviders = new ArrayList<>(); - - // Implementation - @Mod.Instance( ComputerCraft.MOD_ID ) - public static ComputerCraft instance; - - @SidedProxy( - clientSide = "dan200.computercraft.client.proxy.ComputerCraftProxyClient", - serverSide = "dan200.computercraft.shared.proxy.ComputerCraftProxyCommon" - ) - private static ComputerCraftProxyCommon proxy; - - @Mod.EventHandler - public void preInit( FMLPreInitializationEvent event ) + public ComputerCraft() { - log = event.getModLog(); - - // Load config - Config.load( event.getSuggestedConfigurationFile() ); - - proxy.preInit(); - } - - @Mod.EventHandler - public void init( FMLInitializationEvent event ) - { - proxy.init(); - } - - @Mod.EventHandler - public void onServerStarting( FMLServerStartingEvent event ) - { - ComputerCraftProxyCommon.initServer( event.getServer() ); - } - - @Mod.EventHandler - public void onServerStart( FMLServerStartedEvent event ) - { - if( FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER ) - { - ComputerCraft.serverComputerRegistry.reset(); - WirelessNetwork.resetNetworks(); - MainThread.reset(); - Tracking.reset(); - } - } - - @Mod.EventHandler - public void onServerStopped( FMLServerStoppedEvent event ) - { - if( FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER ) - { - ComputerCraft.serverComputerRegistry.reset(); - WirelessNetwork.resetNetworks(); - MainThread.reset(); - Tracking.reset(); - } + Config.load(); } public static String getVersion() { - return VERSION; + return "${version}"; } - private static File getBaseDir() + static IMount createResourceMount( String domain, String subPath ) { - return FMLCommonHandler.instance().getMinecraftServerInstance().getDataDirectory(); + IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager(); + ResourceMount mount = new ResourceMount( domain, subPath, manager ); + return mount.exists( "" ) ? mount : null; } - private static File getResourcePackDir() - { - return new File( getBaseDir(), "resourcepacks" ); - } - - @Deprecated - public static void registerPermissionProvider( ITurtlePermissionProvider provider ) - { - TurtlePermissions.register( provider ); - } - - @Deprecated - public static void registerPocketUpgrade( IPocketUpgrade upgrade ) - { - dan200.computercraft.shared.PocketUpgrades.register( upgrade ); - } - - @Deprecated - public static void registerPeripheralProvider( IPeripheralProvider provider ) - { - Peripherals.register( provider ); - } - - @Deprecated - public static void registerBundledRedstoneProvider( IBundledRedstoneProvider provider ) - { - BundledRedstone.register( provider ); - } - - @Deprecated - public static void registerMediaProvider( IMediaProvider provider ) - { - MediaProviders.register( provider ); - } - - @Deprecated - public static void registerAPIFactory( ILuaAPIFactory factory ) - { - ApiFactories.register( factory ); - } - - @Deprecated - public static IWiredNode createWiredNodeForElement( IWiredElement element ) - { - return new WiredNode( element ); - } - - @Deprecated - public static IWiredElement getWiredElementAt( IBlockAccess world, BlockPos pos, EnumFacing side ) - { - TileEntity tile = world.getTileEntity( pos ); - return tile != null && tile.hasCapability( CapabilityWiredElement.CAPABILITY, side ) - ? tile.getCapability( CapabilityWiredElement.CAPABILITY, side ) - : null; - } - - @Deprecated - public static int getDefaultBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side ) - { - return BundledRedstone.getDefaultOutput( world, pos, side ); - } - - @Deprecated - public static IPacketNetwork getWirelessNetwork() - { - return WirelessNetwork.getUniversal(); - } - - @Deprecated - public static int createUniqueNumberedSaveDir( World world, String parentSubPath ) - { - return IDAssigner.getNextIDFromDirectory( parentSubPath ); - } - - @Deprecated - public static IWritableMount createSaveDirMount( World world, String subPath, long capacity ) + public static InputStream getResourceFile( String domain, String subPath ) { + IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager(); try { - return new FileMount( new File( getWorldDir(), subPath ), capacity ); + return manager.getResource( new ResourceLocation( domain, subPath ) ).getInputStream(); } - catch( Exception e ) + catch( IOException ignored ) { return null; } } - - @Deprecated - public static IMount createResourceMount( Class modClass, String domain, String subPath ) - { - // Start building list of mounts - List mounts = new ArrayList<>(); - subPath = "assets/" + domain + "/" + subPath; - - // Mount from debug dir - File codeDir = getDebugCodeDir( modClass ); - if( codeDir != null ) - { - File subResource = new File( codeDir, subPath ); - if( subResource.exists() ) - { - IMount resourcePackMount = new FileMount( subResource, 0 ); - mounts.add( resourcePackMount ); - } - } - - // Mount from mod jar - File modJar = getContainingJar( modClass ); - if( modJar != null ) - { - try - { - mounts.add( new JarMount( modJar, subPath ) ); - } - catch( IOException | RuntimeException e ) - { - ComputerCraft.log.error( "Could not load mount from mod jar", e ); - } - } - - // Mount from resource packs - File resourcePackDir = getResourcePackDir(); - if( resourcePackDir.exists() && resourcePackDir.isDirectory() ) - { - String[] resourcePacks = resourcePackDir.list(); - for( String resourcePackName : resourcePacks ) - { - try - { - File resourcePack = new File( resourcePackDir, resourcePackName ); - if( !resourcePack.isDirectory() ) - { - // Mount a resource pack from a jar - mounts.add( new JarMount( resourcePack, subPath ) ); - } - else - { - // Mount a resource pack from a folder - File subResource = new File( resourcePack, subPath ); - if( subResource.exists() ) mounts.add( new FileMount( subResource, 0 ) ); - } - } - catch( IOException | RuntimeException e ) - { - ComputerCraft.log.error( "Could not load resource pack '" + resourcePackName + "'", e ); - } - } - } - - // Return the combination of all the mounts found - if( mounts.size() >= 2 ) - { - IMount[] mountArray = new IMount[mounts.size()]; - mounts.toArray( mountArray ); - return new ComboMount( mountArray ); - } - else if( mounts.size() == 1 ) - { - return mounts.get( 0 ); - } - else - { - return null; - } - } - - public static InputStream getResourceFile( Class modClass, String domain, String subPath ) - { - // Start searching in possible locations - subPath = "assets/" + domain + "/" + subPath; - - // Look in resource packs - File resourcePackDir = getResourcePackDir(); - if( resourcePackDir.exists() && resourcePackDir.isDirectory() ) - { - String[] resourcePacks = resourcePackDir.list(); - for( String resourcePackPath : resourcePacks ) - { - File resourcePack = new File( resourcePackDir, resourcePackPath ); - if( resourcePack.isDirectory() ) - { - // Mount a resource pack from a folder - File subResource = new File( resourcePack, subPath ); - if( subResource.exists() && subResource.isFile() ) - { - try - { - return new FileInputStream( subResource ); - } - catch( FileNotFoundException ignored ) - { - } - } - } - else - { - ZipFile zipFile = null; - try - { - final ZipFile zip = zipFile = new ZipFile( resourcePack ); - ZipEntry entry = zipFile.getEntry( subPath ); - if( entry != null ) - { - // Return a custom InputStream which will close the original zip when finished. - return new FilterInputStream( zipFile.getInputStream( entry ) ) - { - @Override - public void close() throws IOException - { - super.close(); - zip.close(); - } - }; - } - else - { - IoUtil.closeQuietly( zipFile ); - } - } - catch( IOException e ) - { - if( zipFile != null ) IoUtil.closeQuietly( zipFile ); - } - } - } - } - - // Look in debug dir - File codeDir = getDebugCodeDir( modClass ); - if( codeDir != null ) - { - File subResource = new File( codeDir, subPath ); - if( subResource.exists() && subResource.isFile() ) - { - try - { - return new FileInputStream( subResource ); - } - catch( FileNotFoundException ignored ) - { - } - } - } - - // Look in class loader - return modClass.getClassLoader().getResourceAsStream( subPath ); - } - - private static File getContainingJar( Class modClass ) - { - String path = modClass.getProtectionDomain().getCodeSource().getLocation().getPath(); - int bangIndex = path.indexOf( '!' ); - if( bangIndex >= 0 ) - { - path = path.substring( 0, bangIndex ); - } - - URL url; - try - { - url = new URL( path ); - } - catch( MalformedURLException e1 ) - { - return null; - } - - File file; - try - { - file = new File( url.toURI() ); - } - catch( URISyntaxException e ) - { - file = new File( url.getPath() ); - } - return file; - } - - private static File getDebugCodeDir( Class modClass ) - { - String path = modClass.getProtectionDomain().getCodeSource().getLocation().getPath(); - int bangIndex = path.indexOf( '!' ); - return bangIndex >= 0 ? null : new File( new File( path ).getParentFile(), "../.." ); - } - - @Deprecated - public static void registerTurtleUpgrade( ITurtleUpgrade upgrade ) - { - dan200.computercraft.shared.TurtleUpgrades.register( upgrade ); - } - - public static File getWorldDir() - { - return DimensionManager.getCurrentSaveRootDirectory(); - } - - //region Compatibility - @Deprecated - public static File getWorldDir( World world ) - { - return DimensionManager.getCurrentSaveRootDirectory(); - } - - @Deprecated - public static IMedia getMedia( ItemStack stack ) - { - return MediaProviders.get( stack ); - } - - @Deprecated - public static IPocketUpgrade getPocketUpgrade( ItemStack stack ) - { - return dan200.computercraft.shared.PocketUpgrades.get( stack ); - } - - @Deprecated - public static ITurtleUpgrade getTurtleUpgrade( ItemStack stack ) - { - return dan200.computercraft.shared.TurtleUpgrades.get( stack ); - } - - @Deprecated - public static IPocketUpgrade getPocketUpgrade( String id ) - { - return dan200.computercraft.shared.PocketUpgrades.get( id ); - } - - @Deprecated - public static ITurtleUpgrade getTurtleUpgrade( String id ) - { - return dan200.computercraft.shared.TurtleUpgrades.get( id ); - } - - @Deprecated - public static IPeripheral getPeripheralAt( World world, BlockPos pos, EnumFacing side ) - { - return Peripherals.getPeripheral( world, pos, side ); - } - - @Deprecated - public static boolean canPlayerUseCommands( EntityPlayer player ) - { - MinecraftServer server = player.getServer(); - return server != null && server.getPlayerList().canSendCommands( player.getGameProfile() ); - } - //endregion } diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java new file mode 100644 index 000000000..a817feae2 --- /dev/null +++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java @@ -0,0 +1,140 @@ +/* + * 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; + +import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI; +import dan200.computercraft.api.filesystem.IMount; +import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.api.lua.ILuaAPIFactory; +import dan200.computercraft.api.media.IMediaProvider; +import dan200.computercraft.api.network.IPacketNetwork; +import dan200.computercraft.api.network.wired.IWiredElement; +import dan200.computercraft.api.network.wired.IWiredNode; +import dan200.computercraft.api.peripheral.IPeripheralProvider; +import dan200.computercraft.api.pocket.IPocketUpgrade; +import dan200.computercraft.api.redstone.IBundledRedstoneProvider; +import dan200.computercraft.api.turtle.ITurtleUpgrade; +import dan200.computercraft.core.apis.ApiFactories; +import dan200.computercraft.core.filesystem.FileMount; +import dan200.computercraft.shared.*; +import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; +import dan200.computercraft.shared.util.IDAssigner; +import dan200.computercraft.shared.wired.CapabilityWiredElement; +import dan200.computercraft.shared.wired.WiredNode; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.World; +import net.minecraftforge.common.util.LazyOptional; + +import javax.annotation.Nonnull; +import java.io.File; + +public final class ComputerCraftAPIImpl implements IComputerCraftAPI +{ + public static final ComputerCraftAPIImpl INSTANCE = new ComputerCraftAPIImpl(); + + private ComputerCraftAPIImpl() + { + } + + @Override + public String getInstalledVersion() + { + return "${version}"; + } + + @Override + public int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath ) + { + return IDAssigner.getNextId( parentSubPath ); + } + + @Override + public IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity ) + { + try + { + return new FileMount( new File( IDAssigner.getDir(), subPath ), capacity ); + } + catch( Exception e ) + { + return null; + } + } + + @Override + public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath ) + { + return ComputerCraft.createResourceMount( domain, subPath ); + } + + @Override + public void registerPeripheralProvider( @Nonnull IPeripheralProvider provider ) + { + Peripherals.register( provider ); + } + + @Override + public void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade ) + { + TurtleUpgrades.register( upgrade ); + } + + @Override + public void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider ) + { + BundledRedstone.register( provider ); + } + + @Override + public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ) + { + return BundledRedstone.getDefaultOutput( world, pos, side ); + } + + @Override + public void registerMediaProvider( @Nonnull IMediaProvider provider ) + { + MediaProviders.register( provider ); + } + + @Override + public void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade ) + { + PocketUpgrades.register( upgrade ); + } + + @Override + public IPacketNetwork getWirelessNetwork() + { + return WirelessNetwork.getUniversal(); + } + + @Override + public void registerAPIFactory( @Nonnull ILuaAPIFactory factory ) + { + ApiFactories.register( factory ); + } + + @Override + public IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element ) + { + return new WiredNode( element ); + } + + @Override + public IWiredElement getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ) + { + TileEntity tile = world.getTileEntity( pos ); + if( tile == null ) return null; + + LazyOptional element = tile.getCapability( CapabilityWiredElement.CAPABILITY, side ); + return CapabilityWiredElement.unwrap( element ); + } +} diff --git a/src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java b/src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java index ab9f86b50..db6ce3474 100644 --- a/src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java @@ -8,10 +8,10 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleUpgradeType; -import net.minecraft.block.Block; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.util.IItemProvider; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Util; import javax.annotation.Nonnull; @@ -23,43 +23,31 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade { private final ResourceLocation id; - private final int legacyId; private final TurtleUpgradeType type; private final String adjective; private final ItemStack stack; - protected AbstractTurtleUpgrade( ResourceLocation id, int legacyId, TurtleUpgradeType type, String adjective, ItemStack stack ) + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, ItemStack stack ) { this.id = id; - this.legacyId = legacyId; this.type = type; this.adjective = adjective; this.stack = stack; } - protected AbstractTurtleUpgrade( ResourceLocation id, int legacyId, TurtleUpgradeType type, String adjective, Item item ) + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, IItemProvider item ) { - this( id, legacyId, type, adjective, new ItemStack( item ) ); + this( id, type, adjective, new ItemStack( item ) ); } - protected AbstractTurtleUpgrade( ResourceLocation id, int legacyId, TurtleUpgradeType type, String adjective, Block block ) + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, ItemStack stack ) { - this( id, legacyId, type, adjective, new ItemStack( block ) ); + this( id, type, Util.makeTranslationKey( "upgrade", id ) + ".adjective", stack ); } - protected AbstractTurtleUpgrade( ResourceLocation id, int legacyId, TurtleUpgradeType type, ItemStack stack ) + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, IItemProvider item ) { - this( id, legacyId, type, "upgrade." + id + ".adjective", stack ); - } - - protected AbstractTurtleUpgrade( ResourceLocation id, int legacyId, TurtleUpgradeType type, Item item ) - { - this( id, legacyId, type, new ItemStack( item ) ); - } - - protected AbstractTurtleUpgrade( ResourceLocation id, int legacyId, TurtleUpgradeType type, Block block ) - { - this( id, legacyId, type, new ItemStack( block ) ); + this( id, type, new ItemStack( item ) ); } @Nonnull @@ -69,12 +57,6 @@ public final ResourceLocation getUpgradeID() return id; } - @Override - public final int getLegacyUpgradeID() - { - return legacyId; - } - @Nonnull @Override public final String getUnlocalisedAdjective() diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index 6f9713808..b7495154e 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -17,18 +17,16 @@ import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralProvider; -import dan200.computercraft.api.permissions.ITurtlePermissionProvider; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import dan200.computercraft.api.turtle.ITurtleUpgrade; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockAccess; +import net.minecraft.world.IBlockReader; import net.minecraft.world.World; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.lang.reflect.Method; /** * The static entry point to the ComputerCraft API. @@ -37,28 +35,10 @@ */ public final class ComputerCraftAPI { - public static boolean isInstalled() - { - findCC(); - return computerCraft != null; - } - @Nonnull public static String getInstalledVersion() { - findCC(); - if( computerCraft_getVersion != null ) - { - try - { - return (String) computerCraft_getVersion.invoke( null ); - } - catch( Exception e ) - { - // It failed - } - } - return ""; + return getInstance().getInstalledVersion(); } @Nonnull @@ -82,19 +62,7 @@ public static String getAPIVersion() */ public static int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath ) { - findCC(); - if( computerCraft_createUniqueNumberedSaveDir != null ) - { - try - { - return (Integer) computerCraft_createUniqueNumberedSaveDir.invoke( null, world, parentSubPath ); - } - catch( Exception e ) - { - // It failed - } - } - return -1; + return getInstance().createUniqueNumberedSaveDir( world, parentSubPath ); } /** @@ -118,55 +86,54 @@ public static int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull St @Nullable public static IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity ) { - findCC(); - if( computerCraft_createSaveDirMount != null ) - { - try - { - return (IWritableMount) computerCraft_createSaveDirMount.invoke( null, world, subPath, capacity ); - } - catch( Exception e ) - { - // It failed - } - } - return null; + return getInstance().createSaveDirMount( world, subPath, capacity ); } /** * Creates a file system mount to a resource folder, and returns it. * - * Use in conjunction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a resource folder - * onto a computer's file system. + * Use in conjunction with {@link IComputerAccess#mount} or {@link IComputerAccess#mountWritable} to mount a + * resource folder onto a computer's file system. * - * The files in this mount will be a combination of files in the specified mod jar, and resource packs that contain + * The files in this mount will be a combination of files in all mod jar, and data packs that contain * resources with the same domain and path. * - * @param modClass A class in whose jar to look first for the resources to mount. Using your main mod class is recommended. eg: MyMod.class - * @param domain The domain under which to look for resources. eg: "mymod". - * @param subPath The domain under which to look for resources. eg: "mymod/lua/myfiles". - * @return The mount, or {@code null} if it could be created for some reason. Use IComputerAccess.mount() or - * IComputerAccess.mountWritable() to mount this on a Computers' file system. + * @param domain The domain under which to look for resources. eg: "mymod". + * @param subPath The subPath under which to look for resources. eg: "lua/myfiles". + * @return The mount, or {@code null} if it could be created for some reason. * @see IComputerAccess#mount(String, IMount) * @see IComputerAccess#mountWritable(String, IWritableMount) * @see IMount */ @Nullable - public static IMount createResourceMount( @Nonnull Class modClass, @Nonnull String domain, @Nonnull String subPath ) + public static IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath ) { - findCC(); - if( computerCraft_createResourceMount != null ) - { - try - { - return (IMount) computerCraft_createResourceMount.invoke( null, modClass, domain, subPath ); - } - catch( Exception e ) - { - // It failed - } - } - return null; + return getInstance().createResourceMount( domain, subPath ); + } + + /** + * Creates a file system mount to a resource folder, and returns it. + * + * Use in conjunction with {@link IComputerAccess#mount} or {@link IComputerAccess#mountWritable} to mount a + * resource folder onto a computer's file system. + * + * The files in this mount will be a combination of files in all mod jar, and data packs that contain + * resources with the same domain and path. + * + * @param klass The mod class to which the files belong. + * @param domain The domain under which to look for resources. eg: "mymod". + * @param subPath The subPath under which to look for resources. eg: "lua/myfiles". + * @return The mount, or {@code null} if it could be created for some reason. + * @see IComputerAccess#mount(String, IMount) + * @see IComputerAccess#mountWritable(String, IWritableMount) + * @see IMount + * @deprecated Use {@link #createResourceMount(String, String)} instead. + */ + @Nullable + @Deprecated + public static IMount createResourceMount( Class klass, @Nonnull String domain, @Nonnull String subPath ) + { + return getInstance().createResourceMount( domain, subPath ); } /** @@ -178,18 +145,7 @@ public static IMount createResourceMount( @Nonnull Class modClass, @Nonnull S */ public static void registerPeripheralProvider( @Nonnull IPeripheralProvider provider ) { - findCC(); - if( computerCraft_registerPeripheralProvider != null ) - { - try - { - computerCraft_registerPeripheralProvider.invoke( null, provider ); - } - catch( Exception e ) - { - // It failed - } - } + getInstance().registerPeripheralProvider( provider ); } /** @@ -202,21 +158,7 @@ public static void registerPeripheralProvider( @Nonnull IPeripheralProvider prov */ public static void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade ) { - if( upgrade != null ) - { - findCC(); - if( computerCraft_registerTurtleUpgrade != null ) - { - try - { - computerCraft_registerTurtleUpgrade.invoke( null, upgrade ); - } - catch( Exception e ) - { - // It failed - } - } - } + getInstance().registerTurtleUpgrade( upgrade ); } /** @@ -227,18 +169,7 @@ public static void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade ) */ public static void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider ) { - findCC(); - if( computerCraft_registerBundledRedstoneProvider != null ) - { - try - { - computerCraft_registerBundledRedstoneProvider.invoke( null, provider ); - } - catch( Exception e ) - { - // It failed - } - } + getInstance().registerBundledRedstoneProvider( provider ); } /** @@ -253,19 +184,7 @@ public static void registerBundledRedstoneProvider( @Nonnull IBundledRedstonePro */ public static int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ) { - findCC(); - if( computerCraft_getDefaultBundledRedstoneOutput != null ) - { - try - { - return (Integer) computerCraft_getDefaultBundledRedstoneOutput.invoke( null, world, pos, side ); - } - catch( Exception e ) - { - // It failed - } - } - return -1; + return getInstance().getBundledRedstoneOutput( world, pos, side ); } /** @@ -276,58 +195,12 @@ public static int getBundledRedstoneOutput( @Nonnull World world, @Nonnull Block */ public static void registerMediaProvider( @Nonnull IMediaProvider provider ) { - findCC(); - if( computerCraft_registerMediaProvider != null ) - { - try - { - computerCraft_registerMediaProvider.invoke( null, provider ); - } - catch( Exception e ) - { - // It failed - } - } - } - - /** - * Registers a permission provider to restrict where turtles can move or build. - * - * @param provider The turtle permission provider to register. - * @see ITurtlePermissionProvider - * @deprecated Prefer using {@link dan200.computercraft.api.turtle.event.TurtleBlockEvent} or the standard Forge events. - */ - @Deprecated - public static void registerPermissionProvider( @Nonnull ITurtlePermissionProvider provider ) - { - findCC(); - if( computerCraft_registerPermissionProvider != null ) - { - try - { - computerCraft_registerPermissionProvider.invoke( null, provider ); - } - catch( Exception e ) - { - // It failed - } - } + getInstance().registerMediaProvider( provider ); } public static void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade ) { - findCC(); - if( computerCraft_registerPocketUpgrade != null ) - { - try - { - computerCraft_registerPocketUpgrade.invoke( null, upgrade ); - } - catch( Exception e ) - { - // It failed - } - } + getInstance().registerPocketUpgrade( upgrade ); } /** @@ -337,36 +210,12 @@ public static void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade ) */ public static IPacketNetwork getWirelessNetwork() { - findCC(); - if( computerCraft_getWirelessNetwork != null ) - { - try - { - return (IPacketNetwork) computerCraft_getWirelessNetwork.invoke( null ); - } - catch( Exception e ) - { - // It failed; - } - } - - return null; + return getInstance().getWirelessNetwork(); } - public static void registerAPIFactory( @Nonnull ILuaAPIFactory upgrade ) + public static void registerAPIFactory( @Nonnull ILuaAPIFactory factory ) { - findCC(); - if( computerCraft_registerAPIFactory != null ) - { - try - { - computerCraft_registerAPIFactory.invoke( null, upgrade ); - } - catch( Exception e ) - { - // It failed - } - } + getInstance().registerAPIFactory( factory ); } /** @@ -379,22 +228,7 @@ public static void registerAPIFactory( @Nonnull ILuaAPIFactory upgrade ) @Nonnull public static IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element ) { - findCC(); - if( computerCraft_createWiredNodeForElement != null ) - { - try - { - return (IWiredNode) computerCraft_createWiredNodeForElement.invoke( null, element ); - } - catch( ReflectiveOperationException e ) - { - throw new IllegalStateException( "Error creating wired node", e ); - } - } - else - { - throw new IllegalStateException( "ComputerCraft cannot be found" ); - } + return getInstance().createWiredNodeForElement( element ); } /** @@ -407,117 +241,57 @@ public static IWiredNode createWiredNodeForElement( @Nonnull IWiredElement eleme * @see IWiredElement#getNode() */ @Nullable - public static IWiredElement getWiredElementAt( @Nonnull IBlockAccess world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ) + public static IWiredElement getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ) { - findCC(); - if( computerCraft_getWiredElementAt != null ) - { - try - { - return (IWiredElement) computerCraft_getWiredElementAt.invoke( null, world, pos, side ); - } - catch( ReflectiveOperationException ignored ) - { - } - } - - return null; + return getInstance().getWiredElementAt( world, pos, side ); } - // The functions below here are private, and are used to interface with the non-API ComputerCraft classes. - // Reflection is used here so you can develop your mod without decompiling ComputerCraft and including - // it in your solution, and so your mod won't crash if ComputerCraft is installed. + private static IComputerCraftAPI instance; - private static void findCC() + @Nonnull + private static IComputerCraftAPI getInstance() { - if( !ccSearched ) - { - try - { - computerCraft = Class.forName( "dan200.computercraft.ComputerCraft" ); - computerCraft_getVersion = findCCMethod( "getVersion", new Class[] { - } ); - computerCraft_createUniqueNumberedSaveDir = findCCMethod( "createUniqueNumberedSaveDir", new Class[] { - World.class, String.class - } ); - computerCraft_createSaveDirMount = findCCMethod( "createSaveDirMount", new Class[] { - World.class, String.class, Long.TYPE - } ); - computerCraft_createResourceMount = findCCMethod( "createResourceMount", new Class[] { - Class.class, String.class, String.class - } ); - computerCraft_registerPeripheralProvider = findCCMethod( "registerPeripheralProvider", new Class[] { - IPeripheralProvider.class - } ); - computerCraft_registerTurtleUpgrade = findCCMethod( "registerTurtleUpgrade", new Class[] { - ITurtleUpgrade.class - } ); - computerCraft_registerBundledRedstoneProvider = findCCMethod( "registerBundledRedstoneProvider", new Class[] { - IBundledRedstoneProvider.class - } ); - computerCraft_getDefaultBundledRedstoneOutput = findCCMethod( "getDefaultBundledRedstoneOutput", new Class[] { - World.class, BlockPos.class, EnumFacing.class - } ); - computerCraft_registerMediaProvider = findCCMethod( "registerMediaProvider", new Class[] { - IMediaProvider.class - } ); - computerCraft_registerPermissionProvider = findCCMethod( "registerPermissionProvider", new Class[] { - ITurtlePermissionProvider.class - } ); - computerCraft_registerPocketUpgrade = findCCMethod( "registerPocketUpgrade", new Class[] { - IPocketUpgrade.class - } ); - computerCraft_getWirelessNetwork = findCCMethod( "getWirelessNetwork", new Class[] { - } ); - computerCraft_registerAPIFactory = findCCMethod( "registerAPIFactory", new Class[] { - ILuaAPIFactory.class - } ); - computerCraft_createWiredNodeForElement = findCCMethod( "createWiredNodeForElement", new Class[] { - IWiredElement.class - } ); - computerCraft_getWiredElementAt = findCCMethod( "getWiredElementAt", new Class[] { - IBlockAccess.class, BlockPos.class, EnumFacing.class - } ); - } - catch( Exception e ) - { - System.err.println( "ComputerCraftAPI: ComputerCraft not found." ); - } - finally - { - ccSearched = true; - } - } - } + if( instance != null ) return instance; - private static Method findCCMethod( String name, Class[] args ) - { try { - return computerCraft != null ? computerCraft.getMethod( name, args ) : null; + return instance = (IComputerCraftAPI) Class.forName( "dan200.computercraft.ComputerCraftAPIImpl" ) + .getField( "INSTANCE" ).get( null ); } - catch( NoSuchMethodException e ) + catch( ReflectiveOperationException e ) { - System.err.println( "ComputerCraftAPI: ComputerCraft method " + name + " not found." ); - return null; + throw new IllegalStateException( "Cannot find ComputerCraft API", e ); } } - private static boolean ccSearched = false; - private static Class computerCraft = null; - private static Method computerCraft_getVersion = null; - private static Method computerCraft_createUniqueNumberedSaveDir = null; - private static Method computerCraft_createSaveDirMount = null; - private static Method computerCraft_createResourceMount = null; - private static Method computerCraft_registerPeripheralProvider = null; - private static Method computerCraft_registerTurtleUpgrade = null; - private static Method computerCraft_registerBundledRedstoneProvider = null; - private static Method computerCraft_getDefaultBundledRedstoneOutput = null; - private static Method computerCraft_registerMediaProvider = null; - private static Method computerCraft_registerPermissionProvider = null; - private static Method computerCraft_registerPocketUpgrade = null; - private static Method computerCraft_getWirelessNetwork = null; - private static Method computerCraft_registerAPIFactory = null; - private static Method computerCraft_createWiredNodeForElement = null; - private static Method computerCraft_getWiredElementAt = null; + public interface IComputerCraftAPI + { + String getInstalledVersion(); + + int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath ); + + IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity ); + + IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath ); + + void registerPeripheralProvider( @Nonnull IPeripheralProvider provider ); + + void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade ); + + void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider ); + + int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ); + + void registerMediaProvider( @Nonnull IMediaProvider provider ); + + void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade ); + + IPacketNetwork getWirelessNetwork(); + + void registerAPIFactory( @Nonnull ILuaAPIFactory factory ); + + IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element ); + + IWiredElement getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ); + } } diff --git a/src/main/java/dan200/computercraft/api/filesystem/package-info.java b/src/main/java/dan200/computercraft/api/filesystem/package-info.java deleted file mode 100644 index 8b1cf52cb..000000000 --- a/src/main/java/dan200/computercraft/api/filesystem/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. 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. - */ - -@API( owner = "ComputerCraft", provides = "ComputerCraft|API|FileSystem", apiVersion = "${version}" ) -package dan200.computercraft.api.filesystem; - -import net.minecraftforge.fml.common.API; diff --git a/src/main/java/dan200/computercraft/api/lua/package-info.java b/src/main/java/dan200/computercraft/api/lua/package-info.java deleted file mode 100644 index 2a9020719..000000000 --- a/src/main/java/dan200/computercraft/api/lua/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. 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. - */ - -@API( owner = "ComputerCraft", provides = "ComputerCraft|API|Lua", apiVersion = "${version}" ) -package dan200.computercraft.api.lua; - -import net.minecraftforge.fml.common.API; diff --git a/src/main/java/dan200/computercraft/api/media/package-info.java b/src/main/java/dan200/computercraft/api/media/package-info.java deleted file mode 100644 index 6381b11c9..000000000 --- a/src/main/java/dan200/computercraft/api/media/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. 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. - */ - -@API( owner = "ComputerCraft", provides = "ComputerCraft|API|Media", apiVersion = "${version}" ) -package dan200.computercraft.api.media; - -import net.minecraftforge.fml.common.API; diff --git a/src/main/java/dan200/computercraft/api/network/package-info.java b/src/main/java/dan200/computercraft/api/network/package-info.java deleted file mode 100644 index 35b8cc5a9..000000000 --- a/src/main/java/dan200/computercraft/api/network/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. 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. - */ - -@API( owner = "ComputerCraft", provides = "ComputerCraft|API|Network", apiVersion = "${version}" ) -package dan200.computercraft.api.network; - -import net.minecraftforge.fml.common.API; diff --git a/src/main/java/dan200/computercraft/api/network/wired/package-info.java b/src/main/java/dan200/computercraft/api/network/wired/package-info.java deleted file mode 100644 index c45eef432..000000000 --- a/src/main/java/dan200/computercraft/api/network/wired/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. 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. - */ - -@API( owner = "ComputerCraft", provides = "ComputerCraft|API|Network|Wired", apiVersion = "${version}" ) -package dan200.computercraft.api.network.wired; - -import net.minecraftforge.fml.common.API; diff --git a/src/main/java/dan200/computercraft/api/package-info.java b/src/main/java/dan200/computercraft/api/package-info.java deleted file mode 100644 index e23d7219a..000000000 --- a/src/main/java/dan200/computercraft/api/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. 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. - */ - -@API( owner = "ComputerCraft", provides = "ComputerCraft|API", apiVersion = "${version}" ) -package dan200.computercraft.api; - -import net.minecraftforge.fml.common.API; diff --git a/src/main/java/dan200/computercraft/api/peripheral/package-info.java b/src/main/java/dan200/computercraft/api/peripheral/package-info.java deleted file mode 100644 index b2456ea1a..000000000 --- a/src/main/java/dan200/computercraft/api/peripheral/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. 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. - */ - -@API( owner = "ComputerCraft", provides = "ComputerCraft|API|Peripheral", apiVersion = "${version}" ) -package dan200.computercraft.api.peripheral; - -import net.minecraftforge.fml.common.API; diff --git a/src/main/java/dan200/computercraft/api/permissions/ITurtlePermissionProvider.java b/src/main/java/dan200/computercraft/api/permissions/ITurtlePermissionProvider.java deleted file mode 100644 index 355f86720..000000000 --- a/src/main/java/dan200/computercraft/api/permissions/ITurtlePermissionProvider.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. 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.permissions; - -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -import javax.annotation.Nonnull; - -/** - * This interface is used to restrict where turtles can move or build. - * - * Turtles will call these methods before attempting to perform an action, allowing them to be cancelled. - * - * @see dan200.computercraft.api.ComputerCraftAPI#registerPermissionProvider(ITurtlePermissionProvider) - */ -public interface ITurtlePermissionProvider -{ - /** - * Determine whether a block can be entered by a turtle. - * - * @param world The world the block exists in - * @param pos The location of the block. - * @return Whether the turtle can move into this block. - */ - boolean isBlockEnterable( @Nonnull World world, @Nonnull BlockPos pos ); - - /** - * Determine whether a block can be modified by a turtle. - * - * This includes breaking and placing blocks. - * - * @param world The world the block exists in - * @param pos The location of the block. - * @return Whether the turtle can modify this block. - */ - boolean isBlockEditable( @Nonnull World world, @Nonnull BlockPos pos ); -} diff --git a/src/main/java/dan200/computercraft/api/permissions/package-info.java b/src/main/java/dan200/computercraft/api/permissions/package-info.java deleted file mode 100755 index 3516bad1b..000000000 --- a/src/main/java/dan200/computercraft/api/permissions/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. 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. - */ - -@API( owner = "ComputerCraft", provides = "ComputerCraft|API|Permissions", apiVersion = "${version}" ) -package dan200.computercraft.api.permissions; - -import net.minecraftforge.fml.common.API; diff --git a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java index 5f345a894..04fe6b6c9 100644 --- a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java @@ -7,7 +7,9 @@ package dan200.computercraft.api.pocket; import net.minecraft.item.ItemStack; +import net.minecraft.util.IItemProvider; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Util; import javax.annotation.Nonnull; @@ -29,9 +31,14 @@ protected AbstractPocketUpgrade( ResourceLocation id, String adjective, ItemStac this.stack = stack; } - protected AbstractPocketUpgrade( ResourceLocation id, ItemStack stack ) + protected AbstractPocketUpgrade( ResourceLocation id, String adjective, IItemProvider item ) { - this( id, "upgrade." + id + ".adjective", stack ); + this( id, adjective, new ItemStack( item ) ); + } + + protected AbstractPocketUpgrade( ResourceLocation id, IItemProvider item ) + { + this( id, Util.makeTranslationKey( "upgrade", id ) + ".adjective", new ItemStack( item ) ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java index eec0d23f4..beeda54fe 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java @@ -23,22 +23,12 @@ public interface IPocketAccess /** * Gets the entity holding this item. * - * @return The holding entity. This may be {@code null}. - * @deprecated Use {@link #getValidEntity()} where possible. - */ - @Nullable - @Deprecated - Entity getEntity(); - - /** - * Gets the entity holding this item with additional safety checks. - * * This must be called on the server thread. * * @return The holding entity, or {@code null} if none exists. */ @Nullable - Entity getValidEntity(); + Entity getEntity(); /** * Get the colour of this pocket computer as a RGB number. diff --git a/src/main/java/dan200/computercraft/api/redstone/package-info.java b/src/main/java/dan200/computercraft/api/redstone/package-info.java deleted file mode 100644 index 06526b70c..000000000 --- a/src/main/java/dan200/computercraft/api/redstone/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. 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. - */ - -@API( owner = "ComputerCraft", provides = "ComputerCraft|API|Redstone", apiVersion = "${version}" ) -package dan200.computercraft.api.redstone; - -import net.minecraftforge.fml.common.API; diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java index 2c74d2543..1c29fd097 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -54,8 +54,7 @@ public interface ITurtleAccess * @param world The new world to move it to * @param pos The new position to move it to. * @return Whether the movement was successful. It may fail if the block was not loaded or the block placement - * was cancelled. Note this will not check - * {@link dan200.computercraft.api.permissions.ITurtlePermissionProvider#isBlockEnterable(World, BlockPos)}. + * was cancelled. * @throws UnsupportedOperationException When attempting to teleport on the client side. */ boolean teleportTo( @Nonnull World world, @Nonnull BlockPos pos ); diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java index c28fcae74..bfbe36a45 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -10,15 +10,15 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.event.TurtleAttackEvent; import dan200.computercraft.api.turtle.event.TurtleBlockEvent; -import net.minecraft.client.renderer.block.model.IBakedModel; -import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.event.entity.player.AttackEntityEvent; import net.minecraftforge.event.world.BlockEvent; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; @@ -44,17 +44,6 @@ public interface ITurtleUpgrade @Nonnull ResourceLocation getUpgradeID(); - /** - * Gets a numerical identifier representing this type of turtle upgrade, - * for backwards compatibility with pre-1.76 worlds. If your upgrade was - * not released for older ComputerCraft versions, you can return -1 here. - * The turtle will fail registration if an already used positive ID is specified. - * - * @return The legacy ID, or -1 if is needed. - * @see ComputerCraftAPI#registerTurtleUpgrade(ITurtleUpgrade) - */ - int getLegacyUpgradeID(); - /** * Return an unlocalised string to describe this type of turtle in turtle item names. * @@ -133,7 +122,7 @@ default TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull Tur * Called to obtain the model to be used when rendering a turtle peripheral. * * This can be obtained from {@link net.minecraft.client.renderer.ItemModelMesher#getItemModel(ItemStack)}, - * {@link net.minecraft.client.renderer.block.model.ModelManager#getModel(ModelResourceLocation)} or any other + * {@link net.minecraft.client.renderer.model.ModelManager#getModel(ModelResourceLocation)} or any other * source. * * @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models! @@ -142,7 +131,7 @@ default TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull Tur * a transformation of {@code null} has the same effect as the identify matrix. */ @Nonnull - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) Pair getModel( @Nullable ITurtleAccess turtle, @Nonnull TurtleSide side ); /** diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java index a26a12a0f..76e69eebe 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java @@ -8,7 +8,7 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleCommandResult; -import net.minecraftforge.fml.common.eventhandler.Cancelable; +import net.minecraftforge.eventbus.api.Cancelable; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java index 8b67a4455..ec47e308a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java @@ -7,7 +7,7 @@ package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.turtle.ITurtleAccess; -import net.minecraftforge.fml.common.eventhandler.Event; +import net.minecraftforge.eventbus.api.Event; import javax.annotation.Nonnull; import java.util.Objects; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/package-info.java b/src/main/java/dan200/computercraft/api/turtle/event/package-info.java deleted file mode 100644 index 58ae3f05c..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. 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. - */ - -@API( owner = "ComputerCraft", provides = "ComputerCraft|API|Turtle|Event", apiVersion = "${version}" ) -package dan200.computercraft.api.turtle.event; - -import net.minecraftforge.fml.common.API; diff --git a/src/main/java/dan200/computercraft/api/turtle/package-info.java b/src/main/java/dan200/computercraft/api/turtle/package-info.java deleted file mode 100644 index b278aa1a3..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. 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. - */ - -@API( owner = "ComputerCraft", provides = "ComputerCraft|API|Turtle", apiVersion = "${version}" ) -package dan200.computercraft.api.turtle; - -import net.minecraftforge.fml.common.API; diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index da81a77bb..ff4bcfd66 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -8,104 +8,81 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.render.TurtleModelLoader; -import dan200.computercraft.shared.media.items.ItemDiskLegacy; +import dan200.computercraft.shared.common.IColouredItem; +import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; -import dan200.computercraft.shared.turtle.items.ItemTurtleBase; import dan200.computercraft.shared.util.Colour; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.ItemMeshDefinition; -import net.minecraft.client.renderer.block.model.IBakedModel; -import net.minecraft.client.renderer.block.model.ModelBakery; -import net.minecraft.client.renderer.block.model.ModelResourceLocation; -import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.model.IUnbakedModel; +import net.minecraft.client.renderer.model.ModelResourceLocation; +import net.minecraft.client.renderer.model.ModelRotation; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; +import net.minecraft.resources.IResourceManager; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ColorHandlerEvent; import net.minecraftforge.client.event.ModelBakeEvent; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.event.TextureStitchEvent; -import net.minecraftforge.client.model.IModel; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.client.model.ModelLoaderRegistry; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.relauncher.Side; -import javax.annotation.Nonnull; +import java.util.HashSet; +import java.util.Map; /** * Registers textures and models for items. */ -@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT ) +@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) public final class ClientRegistry { private static final String[] EXTRA_MODELS = new String[] { - "turtle_modem_off_left", - "turtle_modem_on_left", - "turtle_modem_off_right", - "turtle_modem_on_right", + "turtle_modem_normal_off_left", + "turtle_modem_normal_on_left", + "turtle_modem_normal_off_right", + "turtle_modem_normal_on_right", + + "turtle_modem_advanced_off_left", + "turtle_modem_advanced_on_left", + "turtle_modem_advanced_off_right", + "turtle_modem_advanced_on_right", "turtle_crafting_table_left", "turtle_crafting_table_right", - "advanced_turtle_modem_off_left", - "advanced_turtle_modem_on_left", - "advanced_turtle_modem_off_right", - "advanced_turtle_modem_on_right", + "turtle_speaker_upgrade_left", "turtle_speaker_upgrade_right", - "turtle_white", + "turtle_colour", "turtle_elf_overlay", }; + private static final String[] EXTRA_TEXTURES = new String[] { + // TODO: Gather these automatically from the model. I'm unable to get this working with Forge's current + // model loading code. + "block/turtle_colour", + "block/turtle_elf_overlay", + "block/turtle_crafty_face", + "block/turtle_speaker_face", + }; + private ClientRegistry() {} @SubscribeEvent public static void registerModels( ModelRegistryEvent event ) { ModelLoaderRegistry.registerLoader( TurtleModelLoader.INSTANCE ); - - // Register item models - registerUniversalItemModel( ComputerCraft.Items.computer, "computer" ); - registerItemModel( ComputerCraft.Items.commandComputer, 0, "command_computer" ); - - registerItemModel( ComputerCraft.Items.pocketComputer, 0, "pocket_computer" ); - registerItemModel( ComputerCraft.Items.pocketComputer, 1, "advanced_pocket_computer" ); - - registerItemModel( ComputerCraft.Items.peripheral, 0, "peripheral" ); - registerItemModel( ComputerCraft.Items.peripheral, 1, "wireless_modem" ); - registerItemModel( ComputerCraft.Items.peripheral, 2, "monitor" ); - registerItemModel( ComputerCraft.Items.peripheral, 3, "printer" ); - registerItemModel( ComputerCraft.Items.peripheral, 4, "advanced_monitor" ); - registerItemModel( ComputerCraft.Items.cable, 0, "cable" ); - registerItemModel( ComputerCraft.Items.cable, 1, "wired_modem" ); - registerItemModel( ComputerCraft.Items.advancedModem, 0, "advanced_modem" ); - registerItemModel( ComputerCraft.Items.peripheral, 5, "speaker" ); - registerItemModel( ComputerCraft.Items.wiredModemFull, 0, "wired_modem_full" ); - - registerUniversalItemModel( ComputerCraft.Items.disk, "disk" ); - registerItemModel( ComputerCraft.Items.diskExpanded, 0, "disk_expanded" ); - registerItemModel( ComputerCraft.Items.treasureDisk, 0, "treasure_disk" ); - - registerItemModel( ComputerCraft.Items.printout, 0, "printout" ); - registerItemModel( ComputerCraft.Items.printout, 1, "pages" ); - registerItemModel( ComputerCraft.Items.printout, 2, "book" ); - - registerUniversalItemModel( ComputerCraft.Items.turtle, "turtle" ); - registerUniversalItemModel( ComputerCraft.Items.turtleExpanded, "turtle" ); - registerUniversalItemModel( ComputerCraft.Items.turtleAdvanced, "turtle_advanced" ); } @SubscribeEvent public static void onTextureStitchEvent( TextureStitchEvent.Pre event ) { - // Load all textures for the extra models - TextureMap map = event.getMap(); - for( String upgrade : EXTRA_MODELS ) + IResourceManager manager = Minecraft.getInstance().getResourceManager(); + for( String extra : EXTRA_TEXTURES ) { - IModel model = ModelLoaderRegistry.getModelOrMissing( new ResourceLocation( "computercraft", "block/" + upgrade ) ); - for( ResourceLocation texture : model.getTextures() ) map.registerSprite( texture ); + event.getMap().registerSprite( manager, new ResourceLocation( ComputerCraft.MOD_ID, extra ) ); } } @@ -113,73 +90,73 @@ public static void onTextureStitchEvent( TextureStitchEvent.Pre event ) public static void onModelBakeEvent( ModelBakeEvent event ) { // Load all extra models - for( String model : EXTRA_MODELS ) loadBlockModel( event, model ); + ModelLoader loader = event.getModelLoader(); + Map registry = event.getModelRegistry(); + + for( String model : EXTRA_MODELS ) + { + IBakedModel bakedModel = bake( loader, loader.getUnbakedModel( new ResourceLocation( ComputerCraft.MOD_ID, "item/" + model ) ) ); + + if( bakedModel != null ) + { + registry.put( + new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, model ), "inventory" ), + bakedModel + ); + } + } + + // And load the custom turtle models in too. + registry.put( + new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_normal" ), "inventory" ), + bake( loader, TurtleModelLoader.INSTANCE.loadModel( new ResourceLocation( ComputerCraft.MOD_ID, "item/turtle_normal" ) ) ) + ); + + registry.put( + new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ), "inventory" ), + bake( loader, TurtleModelLoader.INSTANCE.loadModel( new ResourceLocation( ComputerCraft.MOD_ID, "item/turtle_advanced" ) ) ) + ); } @SubscribeEvent public static void onItemColours( ColorHandlerEvent.Item event ) { - event.getItemColors().registerItemColorHandler( - ( stack, layer ) -> layer == 1 ? ((ItemDiskLegacy) stack.getItem()).getColour( stack ) : 0xFFFFFF, - ComputerCraft.Items.disk, ComputerCraft.Items.diskExpanded + event.getItemColors().register( + ( stack, layer ) -> layer == 1 ? ((ItemDisk) stack.getItem()).getColour( stack ) : 0xFFFFFF, + ComputerCraft.Items.disk ); - event.getItemColors().registerItemColorHandler( ( stack, layer ) -> { + event.getItemColors().register( ( stack, layer ) -> { switch( layer ) { case 0: default: return 0xFFFFFF; case 1: // Frame colour - return ComputerCraft.Items.pocketComputer.getColour( stack ); + return IColouredItem.getColourBasic( stack ); case 2: // Light colour { int light = ItemPocketComputer.getLightState( stack ); return light == -1 ? Colour.Black.getHex() : light; } } - }, ComputerCraft.Items.pocketComputer ); + }, ComputerCraft.Items.pocketComputerNormal, ComputerCraft.Items.pocketComputerAdvanced ); // Setup turtle colours - event.getItemColors().registerItemColorHandler( - ( stack, tintIndex ) -> tintIndex == 0 ? ((ItemTurtleBase) stack.getItem()).getColour( stack ) : 0xFFFFFF, - ComputerCraft.Blocks.turtle, ComputerCraft.Blocks.turtleExpanded, ComputerCraft.Blocks.turtleAdvanced + event.getItemColors().register( + ( stack, tintIndex ) -> tintIndex == 0 ? ((IColouredItem) stack.getItem()).getColour( stack ) : 0xFFFFFF, + ComputerCraft.Blocks.turtleNormal, ComputerCraft.Blocks.turtleAdvanced ); } - private static void registerItemModel( Item item, int damage, String name ) + private static IBakedModel bake( ModelLoader loader, IUnbakedModel model ) { - ResourceLocation location = new ResourceLocation( ComputerCraft.MOD_ID, name ); - final ModelResourceLocation res = new ModelResourceLocation( location, "inventory" ); - ModelBakery.registerItemVariants( item, location ); - ModelLoader.setCustomModelResourceLocation( item, damage, res ); - } + model.getTextures( loader::getUnbakedModel, new HashSet<>() ); - private static void registerUniversalItemModel( Item item, String mainModel ) - { - ResourceLocation mainLocation = new ResourceLocation( ComputerCraft.MOD_ID, mainModel ); - ModelBakery.registerItemVariants( item, mainLocation ); - - final ModelResourceLocation mainModelLocation = new ModelResourceLocation( mainLocation, "inventory" ); - ModelLoader.setCustomMeshDefinition( item, new ItemMeshDefinition() - { - @Nonnull - @Override - public ModelResourceLocation getModelLocation( @Nonnull ItemStack stack ) - { - return mainModelLocation; - } - } ); - } - - private static void loadBlockModel( ModelBakeEvent event, String name ) - { - IModel model = ModelLoaderRegistry.getModelOrMissing( new ResourceLocation( ComputerCraft.MOD_ID, "block/" + name ) ); - IBakedModel bakedModel = model.bake( - model.getDefaultState(), DefaultVertexFormats.ITEM, - location -> Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( location.toString() ) + return model.bake( + loader::getUnbakedModel, + ModelLoader.defaultTextureGetter(), + ModelRotation.X0_Y0, false, DefaultVertexFormats.BLOCK ); - - event.getModelRegistry().putObject( new ModelResourceLocation( ComputerCraft.MOD_ID + ":" + name, "inventory" ), bakedModel ); } } diff --git a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java index 6e2e159dd..1445cd87d 100644 --- a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java +++ b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java @@ -30,7 +30,7 @@ public class ClientTableFormatter implements TableFormatter private static FontRenderer renderer() { - return Minecraft.getMinecraft().fontRenderer; + return Minecraft.getInstance().fontRenderer; } @Override @@ -42,7 +42,7 @@ public ITextComponent getPadding( ITextComponent component, int width ) FontRenderer renderer = renderer(); - float spaceWidth = renderer.getCharWidth( ' ' ); + float spaceWidth = renderer.getStringWidth( " " ); int spaces = MathHelper.floor( extraWidth / spaceWidth ); int extra = extraWidth - (int) (spaces * spaceWidth); @@ -64,11 +64,11 @@ public int getWidth( ITextComponent component ) @Override public void writeLine( int id, ITextComponent component ) { - Minecraft mc = Minecraft.getMinecraft(); + Minecraft mc = Minecraft.getInstance(); GuiNewChat chat = mc.ingameGUI.getChatGUI(); // Trim the text if it goes over the allowed length - int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getChatScale() ); + int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() ); List list = GuiUtilRenderComponents.splitText( component, maxWidth, mc.fontRenderer, false, false ); if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id ); } @@ -76,7 +76,7 @@ public void writeLine( int id, ITextComponent component ) @Override public int display( TableBuilder table ) { - GuiNewChat chat = Minecraft.getMinecraft().ingameGUI.getChatGUI(); + GuiNewChat chat = Minecraft.getInstance().ingameGUI.getChatGUI(); int lastHeight = lastHeights.get( table.getId() ); diff --git a/src/main/java/dan200/computercraft/client/FrameInfo.java b/src/main/java/dan200/computercraft/client/FrameInfo.java index 3a9123ab1..0466b8684 100644 --- a/src/main/java/dan200/computercraft/client/FrameInfo.java +++ b/src/main/java/dan200/computercraft/client/FrameInfo.java @@ -7,12 +7,12 @@ package dan200.computercraft.client; import dan200.computercraft.ComputerCraft; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; -import net.minecraftforge.fml.relauncher.Side; -@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT ) +@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) public final class FrameInfo { private static int tick; diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index 97c83afc7..b2e22db05 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -39,7 +39,7 @@ public static FixedWidthFontRenderer instance() private FixedWidthFontRenderer() { - m_textureManager = Minecraft.getMinecraft().getTextureManager(); + m_textureManager = Minecraft.getInstance().getTextureManager(); } private static void greyscaleify( double[] rgb ) @@ -195,6 +195,6 @@ public int getStringWidth( String s ) public void bindFont() { m_textureManager.bindTexture( FONT ); - GlStateManager.glTexParameteri( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); + GlStateManager.texParameteri( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index 73599a9c5..e0e7ee6fe 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -8,23 +8,19 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.WidgetTerminal; +import dan200.computercraft.client.gui.widgets.WidgetWrapper; import dan200.computercraft.shared.computer.blocks.TileComputer; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputer; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.inventory.Container; import net.minecraft.util.ResourceLocation; -import org.lwjgl.input.Keyboard; -import org.lwjgl.input.Mouse; - -import java.io.IOException; public class GuiComputer extends GuiContainer { - private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/corners.png" ); + private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( "computercraft", "textures/gui/corners_normal.png" ); private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( "computercraft", "textures/gui/corners_advanced.png" ); private static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation( "computercraft", "textures/gui/corners_command.png" ); @@ -32,7 +28,9 @@ public class GuiComputer extends GuiContainer private final ClientComputer m_computer; private final int m_termWidth; private final int m_termHeight; - private WidgetTerminal m_terminal; + + private WidgetTerminal terminal; + private WidgetWrapper terminalWrapper; public GuiComputer( Container container, ComputerFamily family, ClientComputer computer, int termWidth, int termHeight ) { @@ -41,13 +39,7 @@ public GuiComputer( Container container, ComputerFamily family, ClientComputer c m_computer = computer; m_termWidth = termWidth; m_termHeight = termHeight; - m_terminal = null; - } - - @Deprecated - public GuiComputer( Container container, ComputerFamily family, IComputer computer, int termWidth, int termHeight ) - { - this( container, family, (ClientComputer) computer, termWidth, termHeight ); + terminal = null; } public GuiComputer( TileComputer computer ) @@ -62,103 +54,60 @@ public GuiComputer( TileComputer computer ) } @Override - public void initGui() + protected void initGui() { - super.initGui(); - Keyboard.enableRepeatEvents( true ); + mc.keyboardListener.enableRepeatEvents( true ); - m_terminal = new WidgetTerminal( 0, 0, m_termWidth, m_termHeight, () -> m_computer, 2, 2, 2, 2 ); - m_terminal.setAllowFocusLoss( false ); - xSize = m_terminal.getWidth() + 24; - ySize = m_terminal.getHeight() + 24; + int termPxWidth = m_termWidth * FixedWidthFontRenderer.FONT_WIDTH; + int termPxHeight = m_termHeight * FixedWidthFontRenderer.FONT_HEIGHT; + + xSize = termPxWidth + 4 + 24; + ySize = termPxHeight + 4 + 24; + + super.initGui(); + + terminal = new WidgetTerminal( mc, () -> m_computer, m_termWidth, m_termHeight, 2, 2, 2, 2 ); + terminalWrapper = new WidgetWrapper( terminal, 2 + 12 + guiLeft, 2 + 12 + guiTop, termPxWidth, termPxHeight ); + + children.add( terminalWrapper ); + setFocused( terminalWrapper ); } @Override public void onGuiClosed() { super.onGuiClosed(); - Keyboard.enableRepeatEvents( false ); + children.remove( terminal ); + terminal = null; + mc.keyboardListener.enableRepeatEvents( false ); } @Override - public void updateScreen() + public void tick() { - super.updateScreen(); - m_terminal.update(); + super.tick(); + terminal.update(); } @Override - protected void keyTyped( char c, int k ) throws IOException - { - if( k == 1 ) - { - super.keyTyped( c, k ); - } - else - { - if( m_terminal.onKeyTyped( c, k ) ) keyHandled = true; - } - } - - @Override - protected void mouseClicked( int x, int y, int button ) - { - int startX = (width - m_terminal.getWidth()) / 2; - int startY = (height - m_terminal.getHeight()) / 2; - m_terminal.mouseClicked( x - startX, y - startY, button ); - } - - @Override - public void handleMouseInput() throws IOException - { - super.handleMouseInput(); - - int x = Mouse.getEventX() * width / mc.displayWidth; - int y = height - Mouse.getEventY() * height / mc.displayHeight - 1; - int startX = (width - m_terminal.getWidth()) / 2; - int startY = (height - m_terminal.getHeight()) / 2; - m_terminal.handleMouseInput( x - startX, y - startY ); - } - - @Override - public void handleKeyboardInput() throws IOException - { - super.handleKeyboardInput(); - if( m_terminal.onKeyboardInput() ) keyHandled = true; - } - - @Override - protected void drawGuiContainerForegroundLayer( int par1, int par2 ) - { - } - - @Override - protected void drawGuiContainerBackgroundLayer( float var1, int var2, int var3 ) - { - } - - @Override - public void drawScreen( int mouseX, int mouseY, float partialTicks ) + public void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) { // Work out where to draw - int startX = (width - m_terminal.getWidth()) / 2; - int startY = (height - m_terminal.getHeight()) / 2; - int endX = startX + m_terminal.getWidth(); - int endY = startY + m_terminal.getHeight(); - - // Draw background - drawDefaultBackground(); + int startX = terminalWrapper.getX() - 2; + int startY = terminalWrapper.getY() - 2; + int endX = startX + terminalWrapper.getWidth() + 4; + int endY = startY + terminalWrapper.getHeight() + 4; // Draw terminal - m_terminal.draw( mc, startX, startY, mouseX, mouseY ); + terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() ); // Draw a border around the terminal - GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); + GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); switch( m_family ) { case Normal: default: - mc.getTextureManager().bindTexture( BACKGROUND ); + mc.getTextureManager().bindTexture( BACKGROUND_NORMAL ); break; case Advanced: mc.getTextureManager().bindTexture( BACKGROUND_ADVANCED ); @@ -179,4 +128,26 @@ public void drawScreen( int mouseX, int mouseY, float partialTicks ) drawTexturedModalRect( startX - 12, startY, 0, 28, 12, endY - startY ); drawTexturedModalRect( endX, startY, 36, 28, 12, endY - startY ); } + + @Override + public void render( int mouseX, int mouseY, float partialTicks ) + { + drawDefaultBackground(); + super.render( mouseX, mouseY, partialTicks ); + renderHoveredToolTip( mouseX, mouseY ); + } + + @Override + public 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 ); + } + + @Override + public boolean mouseReleased( double x, double y, int button ) + { + return (getFocused() != null && getFocused().mouseReleased( x, y, button )) + || super.mouseReleased( x, y, button ); + } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiConfigCC.java b/src/main/java/dan200/computercraft/client/gui/GuiConfigCC.java deleted file mode 100644 index 2eb6d4107..000000000 --- a/src/main/java/dan200/computercraft/client/gui/GuiConfigCC.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.client.gui; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.Config; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiScreen; -import net.minecraftforge.fml.client.IModGuiFactory; -import net.minecraftforge.fml.client.config.GuiConfig; - -import java.util.Set; - -public class GuiConfigCC extends GuiConfig -{ - public GuiConfigCC( GuiScreen parentScreen ) - { - super( parentScreen, Config.getConfigElements(), ComputerCraft.MOD_ID, false, false, "CC: Tweaked" ); - } - - public static class Factory implements IModGuiFactory - { - @Override - public void initialize( Minecraft minecraft ) - { - } - - @Override - public boolean hasConfigGui() - { - return true; - } - - @Override - public GuiScreen createConfigGui( GuiScreen parentScreen ) - { - return new GuiConfigCC( parentScreen ); - } - - @Override - public Set runtimeGuiCategories() - { - return null; - } - } -} diff --git a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java index 5aa49544e..ab4284839 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java @@ -14,7 +14,7 @@ public class GuiDiskDrive extends GuiContainer { - private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/diskdrive.png" ); + private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/disk_drive.png" ); private final ContainerDiskDrive m_container; @@ -27,24 +27,24 @@ public GuiDiskDrive( ContainerDiskDrive container ) @Override protected void drawGuiContainerForegroundLayer( int mouseX, int mouseY ) { - String title = m_container.getDiskDrive().getDisplayName().getUnformattedText(); - fontRenderer.drawString( title, (xSize - fontRenderer.getStringWidth( title )) / 2, 6, 0x404040 ); + String title = m_container.getDiskDrive().getDisplayName().getString(); + fontRenderer.drawString( title, (xSize - fontRenderer.getStringWidth( title )) / 2.0f, 6, 0x404040 ); fontRenderer.drawString( I18n.format( "container.inventory" ), 8, ySize - 96 + 2, 0x404040 ); } @Override protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) { - GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F ); + GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); mc.getTextureManager().bindTexture( BACKGROUND ); drawTexturedModalRect( guiLeft, guiTop, 0, 0, xSize, ySize ); } @Override - public void drawScreen( int mouseX, int mouseY, float partialTicks ) + public void render( int mouseX, int mouseY, float partialTicks ) { drawDefaultBackground(); - super.drawScreen( mouseX, mouseY, partialTicks ); + super.render( mouseX, mouseY, partialTicks ); renderHoveredToolTip( mouseX, mouseY ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java index 8f11c287c..e3781ae96 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java @@ -7,19 +7,28 @@ package dan200.computercraft.client.gui; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.media.inventory.ContainerHeldItem; +import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; public class GuiPocketComputer extends GuiComputer { - public GuiPocketComputer( ContainerHeldItem container ) + public GuiPocketComputer( ContainerPocketComputer container ) { super( container, - ComputerCraft.Items.pocketComputer.getFamily( container.getStack() ), + getFamily( container.getStack() ), ItemPocketComputer.createClientComputer( container.getStack() ), ComputerCraft.terminalWidth_pocketComputer, ComputerCraft.terminalHeight_pocketComputer ); } + + private static ComputerFamily getFamily( ItemStack stack ) + { + Item item = stack.getItem(); + return item instanceof ItemPocketComputer ? ((ItemPocketComputer) item).getFamily() : ComputerFamily.Normal; + } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java index f4723ac0c..80e146f52 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java @@ -27,15 +27,15 @@ public GuiPrinter( ContainerPrinter container ) @Override protected void drawGuiContainerForegroundLayer( int mouseX, int mouseY ) { - String title = container.getPrinter().getDisplayName().getUnformattedText(); - fontRenderer.drawString( title, (xSize - fontRenderer.getStringWidth( title )) / 2, 6, 0x404040 ); + String title = container.getPrinter().getDisplayName().getString(); + fontRenderer.drawString( title, (xSize - fontRenderer.getStringWidth( title )) / 2.0f, 6, 0x404040 ); fontRenderer.drawString( I18n.format( "container.inventory" ), 8, ySize - 96 + 2, 0x404040 ); } @Override protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) { - GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F ); + GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); mc.getTextureManager().bindTexture( BACKGROUND ); drawTexturedModalRect( guiLeft, guiTop, 0, 0, xSize, ySize ); @@ -43,10 +43,10 @@ protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, } @Override - public void drawScreen( int mouseX, int mouseY, float partialTicks ) + public void render( int mouseX, int mouseY, float partialTicks ) { drawDefaultBackground(); - super.drawScreen( mouseX, mouseY, partialTicks ); + super.render( mouseX, mouseY, partialTicks ); renderHoveredToolTip( mouseX, mouseY ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index 5c2ec49ea..f1349bc74 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -7,13 +7,11 @@ package dan200.computercraft.client.gui; import dan200.computercraft.core.terminal.TextBuffer; -import dan200.computercraft.shared.media.inventory.ContainerHeldItem; +import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.media.items.ItemPrintout; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; -import org.lwjgl.input.Mouse; - -import java.io.IOException; +import org.lwjgl.glfw.GLFW; import static dan200.computercraft.client.render.PrintoutRenderer.*; @@ -41,63 +39,70 @@ public GuiPrintout( ContainerHeldItem container ) m_page = 0; m_pages = Math.max( m_text.length / ItemPrintout.LINES_PER_PAGE, 1 ); - m_book = ItemPrintout.getType( container.getStack() ) == ItemPrintout.Type.Book; + m_book = ((ItemPrintout) container.getStack().getItem()).getType() == ItemPrintout.Type.BOOK; } @Override - protected void keyTyped( char c, int k ) throws IOException + public boolean keyPressed( int key, int scancode, int modifiers ) { - super.keyTyped( c, k ); + if( super.keyPressed( key, scancode, modifiers ) ) return true; - if( k == 205 ) + if( key == GLFW.GLFW_KEY_RIGHT ) { - // Right if( m_page < m_pages - 1 ) m_page++; + return true; } - else if( k == 203 ) + + if( key == GLFW.GLFW_KEY_LEFT ) { - // Left if( m_page > 0 ) m_page--; + return true; } + + return false; } @Override - public void handleMouseInput() throws IOException + public boolean mouseScrolled( double delta ) { - super.handleMouseInput(); - - int mouseWheelChange = Mouse.getEventDWheel(); - if( mouseWheelChange < 0 ) + if( super.mouseScrolled( delta ) ) return true; + if( delta < 0 ) { // Scroll up goes to the next page if( m_page < m_pages - 1 ) m_page++; + return true; } - else if( mouseWheelChange > 0 ) + + if( delta > 0 ) { // Scroll down goes to the previous page if( m_page > 0 ) m_page--; + return true; } + + return false; } @Override - protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) + public void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) { // Draw the printout - GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); + GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); + GlStateManager.enableDepthTest(); drawBorder( guiLeft, guiTop, zLevel, m_page, m_pages, m_book ); drawText( guiLeft + X_TEXT_MARGIN, guiTop + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours ); } @Override - public void drawScreen( int mouseX, int mouseY, float partialTicks ) + public void render( int mouseX, int mouseY, float partialTicks ) { // We must take the background further back in order to not overlap with our printed pages. zLevel--; drawDefaultBackground(); zLevel++; - super.drawScreen( mouseX, mouseY, partialTicks ); + super.render( mouseX, mouseY, partialTicks ); renderHoveredToolTip( mouseX, mouseY ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 80f283889..9274fd26d 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -8,29 +8,27 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.WidgetTerminal; +import dan200.computercraft.client.gui.widgets.WidgetWrapper; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; -import net.minecraft.client.Minecraft; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.ResourceLocation; -import org.lwjgl.input.Keyboard; -import org.lwjgl.input.Mouse; - -import java.io.IOException; public class GuiTurtle extends GuiContainer { - private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( "computercraft", "textures/gui/turtle.png" ); + private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( "computercraft", "textures/gui/turtle_normal.png" ); private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( "computercraft", "textures/gui/turtle_advanced.png" ); private ContainerTurtle m_container; private final ComputerFamily m_family; private final ClientComputer m_computer; - private WidgetTerminal m_terminalGui; + + private WidgetTerminal terminal; + private WidgetWrapper terminalWrapper; public GuiTurtle( TileTurtle turtle, ContainerTurtle container ) { @@ -45,78 +43,48 @@ public GuiTurtle( TileTurtle turtle, ContainerTurtle container ) } @Override - public void initGui() + protected void initGui() { super.initGui(); - Keyboard.enableRepeatEvents( true ); - m_terminalGui = new WidgetTerminal( - guiLeft + 8, - guiTop + 8, + mc.keyboardListener.enableRepeatEvents( true ); + + int termPxWidth = ComputerCraft.terminalWidth_turtle * FixedWidthFontRenderer.FONT_WIDTH; + int termPxHeight = ComputerCraft.terminalHeight_turtle * FixedWidthFontRenderer.FONT_HEIGHT; + + terminal = new WidgetTerminal( + mc, () -> m_computer, ComputerCraft.terminalWidth_turtle, ComputerCraft.terminalHeight_turtle, - () -> m_computer, 2, 2, 2, 2 ); - m_terminalGui.setAllowFocusLoss( false ); + terminalWrapper = new WidgetWrapper( terminal, 2 + 8 + guiLeft, 2 + 8 + guiTop, termPxWidth, termPxHeight ); + + children.add( terminalWrapper ); + setFocused( terminalWrapper ); } @Override public void onGuiClosed() { - super.onGuiClosed(); - Keyboard.enableRepeatEvents( false ); + children.remove( terminal ); + terminal = null; + mc.keyboardListener.enableRepeatEvents( false ); } @Override - public void updateScreen() + public void tick() { - super.updateScreen(); - m_terminalGui.update(); + super.tick(); + terminal.update(); } - @Override - protected void keyTyped( char c, int k ) throws IOException - { - if( k == 1 ) - { - super.keyTyped( c, k ); - } - else - { - if( m_terminalGui.onKeyTyped( c, k ) ) keyHandled = true; - } - } - - @Override - protected void mouseClicked( int x, int y, int button ) throws IOException - { - super.mouseClicked( x, y, button ); - m_terminalGui.mouseClicked( x, y, button ); - } - - @Override - public void handleMouseInput() throws IOException - { - super.handleMouseInput(); - int x = Mouse.getEventX() * width / mc.displayWidth; - int y = height - Mouse.getEventY() * height / mc.displayHeight - 1; - m_terminalGui.handleMouseInput( x, y ); - } - - @Override - public void handleKeyboardInput() throws IOException - { - super.handleKeyboardInput(); - if( m_terminalGui.onKeyboardInput() ) keyHandled = true; - } - - protected void drawSelectionSlot( boolean advanced ) + private void drawSelectionSlot( boolean advanced ) { // Draw selection slot int slot = m_container.getSelectedSlot(); if( slot >= 0 ) { - GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F ); + GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); int slotX = slot % 4; int slotY = slot / 4; mc.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); @@ -129,10 +97,10 @@ protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, { // Draw term boolean advanced = m_family == ComputerFamily.Advanced; - m_terminalGui.draw( Minecraft.getMinecraft(), 0, 0, mouseX, mouseY ); + terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() ); // Draw border/inventory - GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F ); + GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); mc.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); drawTexturedModalRect( guiLeft, guiTop, 0, 0, xSize, ySize ); @@ -140,10 +108,10 @@ protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, } @Override - public void drawScreen( int mouseX, int mouseY, float partialTicks ) + public void render( int mouseX, int mouseY, float partialTicks ) { drawDefaultBackground(); - super.drawScreen( mouseX, mouseY, partialTicks ); + super.render( mouseX, mouseY, partialTicks ); renderHoveredToolTip( mouseX, mouseY ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/Widget.java b/src/main/java/dan200/computercraft/client/gui/widgets/Widget.java deleted file mode 100644 index f556a0043..000000000 --- a/src/main/java/dan200/computercraft/client/gui/widgets/Widget.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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.client.gui.widgets; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Gui; - -public abstract class Widget extends Gui -{ - private int m_xPosition; - private int m_yPosition; - private int m_width; - private int m_height; - - protected Widget( int x, int y, int width, int height ) - { - m_xPosition = x; - m_yPosition = y; - m_width = width; - m_height = height; - } - - public int getXPosition() - { - return m_xPosition; - } - - public int getYPosition() - { - return m_yPosition; - } - - public int getWidth() - { - return m_width; - } - - public int getHeight() - { - return m_height; - } - - public void update() - { - } - - public void draw( Minecraft mc, int xOrigin, int yOrigin, int mouseX, int mouseY ) - { - } - - public void handleMouseInput( int mouseX, int mouseY ) - { - } - - public boolean onKeyboardInput() - { - return false; - } - - @Deprecated - public void handleKeyboardInput() - { - onKeyboardInput(); - } - - public void mouseClicked( int mouseX, int mouseY, int mouseButton ) - { - } - - public boolean onKeyTyped( char c, int k ) - { - return false; - } - - @Deprecated - public void keyTyped( char c, int k ) - { - onKeyTyped( c, k ); - } -} diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java index d0a72a42a..3f75ccbe3 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java @@ -10,371 +10,349 @@ import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.TextBuffer; +import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.IComputer; -import dan200.computercraft.shared.computer.core.IComputerContainer; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.IGuiEventListener; +import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.util.ChatAllowedCharacters; -import org.lwjgl.input.Keyboard; -import org.lwjgl.input.Mouse; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.SharedConstants; +import org.lwjgl.glfw.GLFW; +import org.lwjgl.opengl.GL11; -import java.util.ArrayList; +import java.util.BitSet; +import java.util.function.Supplier; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.BACKGROUND; -public class WidgetTerminal extends Widget +public class WidgetTerminal implements IGuiEventListener { private static final float TERMINATE_TIME = 0.5f; - private final IComputerContainer m_computer; + private final Minecraft client; - private float m_terminateTimer = 0.0f; - private float m_rebootTimer = 0.0f; - private float m_shutdownTimer = 0.0f; + private final Supplier computer; + private final int termWidth; + private final int termHeight; - private int m_lastClickButton = -1; - private int m_lastClickX = -1; - private int m_lastClickY = -1; + private float terminateTimer = -1; + private float rebootTimer = -1; + private float shutdownTimer = -1; - private boolean m_focus = false; - private boolean m_allowFocusLoss = true; + private int lastMouseButton = -1; + private int lastMouseX = -1; + private int lastMouseY = -1; - private int m_leftMargin; - private int m_rightMargin; - private int m_topMargin; - private int m_bottomMargin; + private final int leftMargin; + private final int rightMargin; + private final int topMargin; + private final int bottomMargin; - private final ArrayList m_keysDown = new ArrayList<>(); + private final BitSet keysDown = new BitSet( 256 ); - public WidgetTerminal( int x, int y, int termWidth, int termHeight, IComputerContainer computer, int leftMargin, int rightMargin, int topMargin, int bottomMargin ) + public WidgetTerminal( Minecraft client, Supplier computer, int termWidth, int termHeight, int leftMargin, int rightMargin, int topMargin, int bottomMargin ) { - super( - x, y, - leftMargin + rightMargin + termWidth * FixedWidthFontRenderer.FONT_WIDTH, - topMargin + bottomMargin + termHeight * FixedWidthFontRenderer.FONT_HEIGHT - ); - - m_computer = computer; - - m_leftMargin = leftMargin; - m_rightMargin = rightMargin; - m_topMargin = topMargin; - m_bottomMargin = bottomMargin; - } - - public void setAllowFocusLoss( boolean allowFocusLoss ) - { - m_allowFocusLoss = allowFocusLoss; - m_focus = m_focus || !allowFocusLoss; + this.client = client; + this.computer = computer; + this.termWidth = termWidth; + this.termHeight = termHeight; + this.leftMargin = leftMargin; + this.rightMargin = rightMargin; + this.topMargin = topMargin; + this.bottomMargin = bottomMargin; } @Override - public boolean onKeyTyped( char ch, int key ) + public boolean charTyped( char ch, int modifiers ) { - if( m_focus ) + if( ch >= 32 && ch <= 126 || ch >= 160 && ch <= 255 ) // printable chars in byte range { - // Ctrl+V for paste - if( ch == 22 ) + // Queue the "char" event + queueEvent( "char", Character.toString( ch ) ); + } + + return true; + } + + @Override + public boolean keyPressed( int key, int scancode, int modifiers ) + { + if( key == GLFW.GLFW_KEY_ESCAPE ) return false; + if( (modifiers & GLFW.GLFW_MOD_CONTROL) != 0 ) + { + switch( key ) { - String clipboard = GuiScreen.getClipboardString(); - 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 ); - } + 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; - // Filter the string - clipboard = ChatAllowedCharacters.filterAllowedCharacters( clipboard ); - - if( !clipboard.isEmpty() ) + case GLFW.GLFW_KEY_V: + // Ctrl+V for paste + String clipboard = client.keyboardListener.getClipboardString(); + if( clipboard != null ) { - // Clip to 512 characters - if( clipboard.length() > 512 ) + // 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, 512 ); + 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 ); } - // Queue the "paste" event - queueEvent( "paste", new Object[] { clipboard } ); - } - } - return true; - } + // Filter the string + clipboard = SharedConstants.filterAllowedCharacters( clipboard ); + if( !clipboard.isEmpty() ) + { + // Clip to 512 characters and queue the event + if( clipboard.length() > 512 ) clipboard = clipboard.substring( 0, 512 ); + queueEvent( "paste", clipboard ); + } - // Regular keys normally - if( m_terminateTimer <= 0.0f && m_rebootTimer <= 0.0f && m_shutdownTimer <= 0.0f ) + 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 ); + IComputer computer = this.computer.get(); + if( computer != null ) 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 ); + IComputer computer = this.computer.get(); + if( computer != null ) 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 + public boolean mouseClicked( double mouseX, double mouseY, int button ) + { + ClientComputer computer = this.computer.get(); + if( computer == null || !computer.isColour() || button < 0 || button > 2 ) return false; + + Terminal term = computer.getTerminal(); + if( term != null ) + { + int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH); + int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT); + charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); + charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); + + computer.mouseClick( button + 1, charX + 1, charY + 1 ); + + lastMouseButton = button; + lastMouseX = charX; + lastMouseY = charY; + } + + return true; + } + + @Override + public boolean mouseReleased( double mouseX, double mouseY, int button ) + { + ClientComputer computer = this.computer.get(); + if( computer == null || !computer.isColour() || button < 0 || button > 2 ) return false; + + Terminal term = computer.getTerminal(); + if( term != null ) + { + int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH); + int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT); + charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); + charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); + + if( lastMouseButton == button ) { - boolean repeat = Keyboard.isRepeatEvent(); - boolean handled = false; - if( key > 0 ) - { - if( !repeat ) - { - m_keysDown.add( key ); - } - - // Queue the "key" event - IComputer computer = m_computer.getComputer(); - if( computer != null ) computer.keyDown( key, repeat ); - handled = true; - } - - if( (ch >= 32 && ch <= 126) || (ch >= 160 && ch <= 255) ) // printable chars in byte range - { - // Queue the "char" event - queueEvent( "char", new Object[] { Character.toString( ch ) } ); - handled = true; - } - - return handled; + computer.mouseUp( lastMouseButton + 1, charX + 1, charY + 1 ); + lastMouseButton = -1; } + + lastMouseX = charX; + lastMouseY = charY; } return false; } @Override - public void mouseClicked( int mouseX, int mouseY, int button ) + public boolean mouseDragged( double mouseX, double mouseY, int button, double v2, double v3 ) { - if( mouseX >= getXPosition() && mouseX < getXPosition() + getWidth() && - mouseY >= getYPosition() && mouseY < getYPosition() + getHeight() ) + ClientComputer computer = this.computer.get(); + if( computer == null || !computer.isColour() || button < 0 || button > 2 ) return false; + + Terminal term = computer.getTerminal(); + if( term != null ) { - if( !m_focus && button == 0 ) - { - m_focus = true; - } + int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH); + int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT); + charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); + charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); - if( m_focus ) - { - IComputer computer = m_computer.getComputer(); - if( computer != null && computer.isColour() && button >= 0 && button <= 2 ) - { - Terminal term = computer.getTerminal(); - if( term != null ) - { - int charX = (mouseX - (getXPosition() + m_leftMargin)) / FixedWidthFontRenderer.FONT_WIDTH; - int charY = (mouseY - (getYPosition() + m_topMargin)) / FixedWidthFontRenderer.FONT_HEIGHT; - charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); - charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); + computer.mouseDrag( button + 1, charX + 1, charY + 1 ); - computer.mouseClick( button + 1, charX + 1, charY + 1 ); - - m_lastClickButton = button; - m_lastClickX = charX; - m_lastClickY = charY; - } - } - } - } - else - { - if( m_focus && button == 0 && m_allowFocusLoss ) - { - m_focus = false; - } + lastMouseX = charX; + lastMouseY = charY; + lastMouseButton = button; } + + return false; } @Override - public boolean onKeyboardInput() + public boolean mouseScrolled( double delta ) { - boolean handled = false; - for( int i = m_keysDown.size() - 1; i >= 0; --i ) + ClientComputer computer = this.computer.get(); + if( computer == null || !computer.isColour() ) return false; + + if( lastMouseX >= 0 && lastMouseY >= 0 && delta != 0 ) { - int key = m_keysDown.get( i ); - if( !Keyboard.isKeyDown( key ) ) - { - m_keysDown.remove( i ); - if( m_focus ) - { - // Queue the "key_up" event - IComputer computer = m_computer.getComputer(); - if( computer != null ) computer.keyUp( key ); - handled = true; - } - } + queueEvent( "mouse_scroll", delta < 0 ? 1 : -1, lastMouseX + 1, lastMouseY + 1 ); } - return handled; + return true; } - @Override - public void handleMouseInput( int mouseX, int mouseY ) - { - IComputer computer = m_computer.getComputer(); - if( mouseX >= getXPosition() && mouseX < getXPosition() + getWidth() && - mouseY >= getYPosition() && mouseY < getYPosition() + getHeight() && - computer != null && computer.isColour() ) - { - Terminal term = computer.getTerminal(); - if( term != null ) - { - int charX = (mouseX - (getXPosition() + m_leftMargin)) / FixedWidthFontRenderer.FONT_WIDTH; - int charY = (mouseY - (getYPosition() + m_topMargin)) / FixedWidthFontRenderer.FONT_HEIGHT; - charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); - charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); - - if( m_lastClickButton >= 0 && !Mouse.isButtonDown( m_lastClickButton ) ) - { - if( m_focus ) computer.mouseUp( m_lastClickButton + 1, charX + 1, charY + 1 ); - m_lastClickButton = -1; - } - - int wheelChange = Mouse.getEventDWheel(); - if( wheelChange == 0 && m_lastClickButton == -1 ) - { - return; - } - - if( m_focus ) - { - if( wheelChange < 0 ) - { - computer.mouseScroll( 1, charX + 1, charY + 1 ); - } - else if( wheelChange > 0 ) - { - computer.mouseScroll( -1, charX + 1, charY + 1 ); - } - - if( m_lastClickButton >= 0 && (charX != m_lastClickX || charY != m_lastClickY) ) - { - computer.mouseDrag( m_lastClickButton + 1, charX + 1, charY + 1 ); - m_lastClickX = charX; - m_lastClickY = charY; - } - } - } - } - } - - @Override public void update() { - // Handle special keys - if( m_focus && (Keyboard.isKeyDown( 29 ) || Keyboard.isKeyDown( 157 )) ) + if( terminateTimer >= 0 && terminateTimer < TERMINATE_TIME && (terminateTimer += 0.05f) > TERMINATE_TIME ) { - // Ctrl+T for terminate - if( Keyboard.isKeyDown( 20 ) ) - { - if( m_terminateTimer < TERMINATE_TIME ) - { - m_terminateTimer += 0.05f; - if( m_terminateTimer >= TERMINATE_TIME ) queueEvent( "terminate" ); - } - } - else - { - m_terminateTimer = 0.0f; - } - - // Ctrl+R for reboot - if( Keyboard.isKeyDown( 19 ) ) - { - if( m_rebootTimer < TERMINATE_TIME ) - { - m_rebootTimer += 0.05f; - if( m_rebootTimer >= TERMINATE_TIME ) - { - IComputer computer = m_computer.getComputer(); - if( computer != null ) computer.reboot(); - } - } - } - else - { - m_rebootTimer = 0.0f; - } - - // Ctrl+S for shutdown - if( Keyboard.isKeyDown( 31 ) ) - { - if( m_shutdownTimer < TERMINATE_TIME ) - { - m_shutdownTimer += 0.05f; - if( m_shutdownTimer >= TERMINATE_TIME ) - { - IComputer computer = m_computer.getComputer(); - if( computer != null ) computer.shutdown(); - } - } - } - else - { - m_shutdownTimer = 0.0f; - } + queueEvent( "terminate" ); } - else + + if( shutdownTimer >= 0 && shutdownTimer < TERMINATE_TIME && (shutdownTimer += 0.05f) > TERMINATE_TIME ) { - m_terminateTimer = 0.0f; - m_rebootTimer = 0.0f; - m_shutdownTimer = 0.0f; + ClientComputer computer = this.computer.get(); + if( computer != null ) computer.shutdown(); + } + + if( rebootTimer >= 0 && rebootTimer < TERMINATE_TIME && (rebootTimer += 0.05f) > TERMINATE_TIME ) + { + ClientComputer computer = this.computer.get(); + if( computer != null ) computer.reboot(); } } @Override - public void draw( Minecraft mc, int xOrigin, int yOrigin, int mouseX, int mouseY ) + public void focusChanged( boolean focused ) { - int startX = xOrigin + getXPosition(); - int startY = yOrigin + getYPosition(); + if( !focused ) + { + // When blurring, we should make all keys go up + for( int key = 0; key < keysDown.size(); key++ ) + { + if( keysDown.get( key ) ) queueEvent( "key_up", key ); + } + keysDown.clear(); - synchronized( m_computer ) + // When blurring, we should make the last mouse button go up + if( lastMouseButton > 0 ) + { + IComputer computer = this.computer.get(); + if( computer != null ) computer.mouseUp( lastMouseButton + 1, lastMouseX + 1, lastMouseY + 1 ); + lastMouseButton = -1; + } + + shutdownTimer = terminateTimer = rebootTimer = -1; + } + } + + public void draw( int originX, int originY ) + { + synchronized( computer ) { // Draw the screen contents - IComputer computer = m_computer.getComputer(); + ClientComputer computer = this.computer.get(); Terminal terminal = computer != null ? computer.getTerminal() : null; if( terminal != null ) { // Draw the terminal boolean greyscale = !computer.isColour(); - Palette palette = terminal.getPalette(); // Get the data from the terminal first // Unfortunately we have to keep the lock for the whole of drawing, so the text doesn't change under us. FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance(); - boolean tblink = m_focus && terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink(); + boolean tblink = terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink(); int tw = terminal.getWidth(); int th = terminal.getHeight(); int tx = terminal.getCursorX(); int ty = terminal.getCursorY(); - int x = startX + m_leftMargin; - int y = startY + m_topMargin; - // Draw margins TextBuffer emptyLine = new TextBuffer( ' ', tw ); - if( m_topMargin > 0 ) + if( topMargin > 0 ) { - fontRenderer.drawString( emptyLine, x, startY, terminal.getTextColourLine( 0 ), terminal.getBackgroundColourLine( 0 ), m_leftMargin, m_rightMargin, greyscale, palette ); + fontRenderer.drawString( emptyLine, originX, originY - topMargin, + terminal.getTextColourLine( 0 ), terminal.getBackgroundColourLine( 0 ), + leftMargin, rightMargin, greyscale, palette ); } - if( m_bottomMargin > 0 ) + + if( bottomMargin > 0 ) { - fontRenderer.drawString( emptyLine, x, startY + 2 * m_bottomMargin + (th - 1) * FixedWidthFontRenderer.FONT_HEIGHT, terminal.getTextColourLine( th - 1 ), terminal.getBackgroundColourLine( th - 1 ), m_leftMargin, m_rightMargin, greyscale, palette ); + fontRenderer.drawString( emptyLine, originX, originY + bottomMargin + (th - 1) * FixedWidthFontRenderer.FONT_HEIGHT, + terminal.getTextColourLine( th - 1 ), terminal.getBackgroundColourLine( th - 1 ), + leftMargin, rightMargin, greyscale, palette ); } // Draw lines + int y = originY; for( int line = 0; line < th; line++ ) { TextBuffer text = terminal.getLine( line ); TextBuffer colour = terminal.getTextColourLine( line ); TextBuffer backgroundColour = terminal.getBackgroundColourLine( line ); - fontRenderer.drawString( text, x, y, colour, backgroundColour, m_leftMargin, m_rightMargin, greyscale, palette ); + fontRenderer.drawString( text, originX, y, colour, backgroundColour, leftMargin, rightMargin, greyscale, palette ); y += FixedWidthFontRenderer.FONT_HEIGHT; } @@ -385,8 +363,8 @@ public void draw( Minecraft mc, int xOrigin, int yOrigin, int mouseX, int mouseY fontRenderer.drawString( cursor, - x + FixedWidthFontRenderer.FONT_WIDTH * tx, - startY + m_topMargin + FixedWidthFontRenderer.FONT_HEIGHT * ty, + originX + FixedWidthFontRenderer.FONT_WIDTH * tx, + originY + FixedWidthFontRenderer.FONT_HEIGHT * ty, cursorColour, null, 0, 0, greyscale, @@ -397,16 +375,29 @@ public void draw( Minecraft mc, int xOrigin, int yOrigin, int mouseX, int mouseY else { // Draw a black background - mc.getTextureManager().bindTexture( BACKGROUND ); Colour black = Colour.Black; - GlStateManager.color( black.getR(), black.getG(), black.getB(), 1.0f ); + GlStateManager.color4f( black.getR(), black.getG(), black.getB(), 1.0f ); try { - drawTexturedModalRect( startX, startY, 0, 0, getWidth(), getHeight() ); + int x = originX - leftMargin; + int y = originY - rightMargin; + int width = termWidth * FixedWidthFontRenderer.FONT_WIDTH + leftMargin + rightMargin; + int height = termHeight * FixedWidthFontRenderer.FONT_HEIGHT + topMargin + bottomMargin; + + client.getTextureManager().bindTexture( BACKGROUND ); + + Tessellator tesslector = Tessellator.getInstance(); + BufferBuilder buffer = tesslector.getBuffer(); + buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX ); + buffer.pos( x, y + height, 0 ).tex( 0 / 256.0, height / 256.0 ).endVertex(); + buffer.pos( x + width, y + height, 0 ).tex( width / 256.0, height / 256.0 ).endVertex(); + buffer.pos( x + width, y, 0 ).tex( width / 256.0, 0 / 256.0 ).endVertex(); + buffer.pos( x, y, 0 ).tex( 0 / 256.0, 0 / 256.0 ).endVertex(); + tesslector.draw(); } finally { - GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); + GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); } } } @@ -414,13 +405,13 @@ public void draw( Minecraft mc, int xOrigin, int yOrigin, int mouseX, int mouseY private void queueEvent( String event ) { - IComputer computer = m_computer.getComputer(); + ClientComputer computer = this.computer.get(); if( computer != null ) computer.queueEvent( event ); } - private void queueEvent( String event, Object[] args ) + private void queueEvent( String event, Object... args ) { - IComputer computer = m_computer.getComputer(); + ClientComputer computer = this.computer.get(); if( computer != null ) computer.queueEvent( event, args ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java new file mode 100644 index 000000000..b657983a0 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java @@ -0,0 +1,104 @@ +/* + * 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.client.gui.widgets; + +import net.minecraft.client.gui.IGuiEventListener; + +public class WidgetWrapper implements IGuiEventListener +{ + private final IGuiEventListener listener; + private final int x; + private final int y; + private final int width; + private final int height; + + public WidgetWrapper( IGuiEventListener listener, int x, int y, int width, int height ) + { + this.listener = listener; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + @Override + public void focusChanged( boolean b ) + { + listener.focusChanged( b ); + } + + @Override + public boolean canFocus() + { + return listener.canFocus(); + } + + @Override + public boolean mouseClicked( double x, double y, int button ) + { + double dx = x - this.x, dy = y - this.y; + return dx >= 0 && dx < width && dy >= 0 && dy < height && listener.mouseClicked( dx, dy, button ); + } + + @Override + public boolean mouseReleased( double x, double y, int button ) + { + double dx = x - this.x, dy = y - this.y; + return dx >= 0 && dx < width && dy >= 0 && dy < height && listener.mouseReleased( dx, dy, button ); + } + + @Override + public boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY ) + { + double dx = x - this.x, dy = y - this.y; + return dx >= 0 && dx < width && dy >= 0 && dy < height && listener.mouseDragged( dx, dy, button, deltaX, deltaY ); + } + + @Override + public boolean mouseScrolled( double delta ) + { + return listener.mouseScrolled( delta ); + } + + @Override + public boolean keyPressed( int key, int scancode, int modifiers ) + { + return listener.keyPressed( key, scancode, modifiers ); + } + + @Override + public boolean keyReleased( int key, int scancode, int modifiers ) + { + return listener.keyReleased( key, scancode, modifiers ); + } + + @Override + public boolean charTyped( char character, int modifiers ) + { + return listener.charTyped( character, modifiers ); + } + + public int getX() + { + return x; + } + + public int getY() + { + return y; + } + + public int getWidth() + { + return width; + } + + public int getHeight() + { + return height; + } +} diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index b71d0e3c0..841ad57da 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -7,56 +7,89 @@ package dan200.computercraft.client.proxy; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.client.gui.*; import dan200.computercraft.client.render.TileEntityCableRenderer; import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer; -import dan200.computercraft.shared.command.CommandCopy; +import dan200.computercraft.shared.computer.blocks.TileComputer; +import dan200.computercraft.shared.computer.core.ClientComputer; +import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; +import dan200.computercraft.shared.network.container.*; import dan200.computercraft.shared.peripheral.modem.wired.TileCable; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; -import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon; import dan200.computercraft.shared.turtle.blocks.TileTurtle; -import net.minecraftforge.client.ClientCommandHandler; +import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.event.world.WorldEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.ExtensionPoint; +import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -public class ComputerCraftProxyClient extends ComputerCraftProxyCommon +import java.util.function.BiFunction; + +@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD ) +public final class ComputerCraftProxyClient { - @Override - public void preInit() + @SubscribeEvent + public static void setupClient( FMLClientSetupEvent event ) { - super.preInit(); + registerContainers(); - // Register any client-specific commands - ClientCommandHandler.instance.registerCommand( CommandCopy.INSTANCE ); - } - - @Override - public void init() - { - super.init(); - - // Setup renderers + // Setup TESRs ClientRegistry.bindTileEntitySpecialRenderer( TileMonitor.class, new TileEntityMonitorRenderer() ); ClientRegistry.bindTileEntitySpecialRenderer( TileCable.class, new TileEntityCableRenderer() ); ClientRegistry.bindTileEntitySpecialRenderer( TileTurtle.class, new TileEntityTurtleRenderer() ); } - @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT ) + private static void registerContainers() + { + ContainerType.registerGui( TileEntityContainerType::computer, ( packet, player ) -> + new GuiComputer( (TileComputer) packet.getTileEntity( player ) ) ); + ContainerType.registerGui( TileEntityContainerType::diskDrive, GuiDiskDrive::new ); + ContainerType.registerGui( TileEntityContainerType::printer, GuiPrinter::new ); + ContainerType.registerGui( TileEntityContainerType::turtle, ( packet, player ) -> { + TileTurtle turtle = (TileTurtle) packet.getTileEntity( player ); + return new GuiTurtle( turtle, new ContainerTurtle( player.inventory, turtle.getAccess(), turtle.getClientComputer() ) ); + } ); + + ContainerType.registerGui( PocketComputerContainerType::new, GuiPocketComputer::new ); + ContainerType.registerGui( PrintoutContainerType::new, GuiPrintout::new ); + ContainerType.registerGui( ViewComputerContainerType::new, ( packet, player ) -> { + ClientComputer computer = ComputerCraft.clientComputerRegistry.get( packet.instanceId ); + if( computer == null ) + { + ComputerCraft.clientComputerRegistry.add( packet.instanceId, computer = new ClientComputer( packet.instanceId ) ); + } + + ContainerViewComputer container = new ContainerViewComputer( computer ); + return new GuiComputer( container, packet.family, computer, packet.width, packet.height ); + } ); + + ModLoadingContext.get().registerExtensionPoint( ExtensionPoint.GUIFACTORY, () -> packet -> { + ContainerType type = ContainerType.factories.get( packet.getId() ).get(); + if( packet.getAdditionalData() != null ) type.fromBytes( packet.getAdditionalData() ); + return ((BiFunction, EntityPlayer, GuiContainer>) ContainerType.guiFactories.get( packet.getId() )) + .apply( type, Minecraft.getInstance().player ); + } ); + } + + @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) public static final class ForgeHandlers { @SubscribeEvent public static void onWorldUnload( WorldEvent.Unload event ) { - if( event.getWorld().isRemote ) + if( event.getWorld().isRemote() ) { ClientMonitor.destroyAll(); } } } - - } diff --git a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java index 8780a5bec..a9226a71e 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java @@ -7,8 +7,8 @@ package dan200.computercraft.client.render; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.FirstPersonRenderer; import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.ItemRenderer; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; @@ -21,13 +21,13 @@ public abstract class ItemMapLikeRenderer * The main rendering method for the item * * @param stack The stack to render - * @see ItemRenderer#renderMapFirstPerson(ItemStack) + * @see FirstPersonRenderer#renderMapFirstPerson(ItemStack) */ protected abstract void renderItem( ItemStack stack ); protected void renderItemFirstPerson( EnumHand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack ) { - EntityPlayer player = Minecraft.getMinecraft().player; + EntityPlayer player = Minecraft.getInstance().player; GlStateManager.pushMatrix(); if( hand == EnumHand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() ) @@ -51,35 +51,35 @@ protected void renderItemFirstPerson( EnumHand hand, float pitch, float equipPro * @param equipProgress The equip progress of this item * @param swingProgress The swing progress of this item * @param stack The stack to render - * @see ItemRenderer#renderMapFirstPersonSide(float, EnumHandSide, float, ItemStack) + * @see FirstPersonRenderer#renderMapFirstPersonSide(float, EnumHandSide, float, ItemStack) */ private void renderItemFirstPersonSide( EnumHandSide side, float equipProgress, float swingProgress, ItemStack stack ) { - Minecraft minecraft = Minecraft.getMinecraft(); + Minecraft minecraft = Minecraft.getInstance(); float offset = side == EnumHandSide.RIGHT ? 1f : -1f; - GlStateManager.translate( offset * 0.125f, -0.125f, 0f ); + GlStateManager.translatef( offset * 0.125f, -0.125f, 0f ); // If the player is not invisible then render a single arm if( !minecraft.player.isInvisible() ) { GlStateManager.pushMatrix(); - GlStateManager.rotate( offset * 10f, 0f, 0f, 1f ); - minecraft.getItemRenderer().renderArmFirstPerson( equipProgress, swingProgress, side ); + GlStateManager.rotatef( offset * 10f, 0f, 0f, 1f ); + minecraft.getFirstPersonRenderer().renderArmFirstPerson( equipProgress, swingProgress, side ); GlStateManager.popMatrix(); } // Setup the appropriate transformations. This is just copied from the // corresponding method in ItemRenderer. GlStateManager.pushMatrix(); - GlStateManager.translate( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f ); + GlStateManager.translatef( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f ); float f1 = MathHelper.sqrt( swingProgress ); float f2 = MathHelper.sin( f1 * (float) Math.PI ); float f3 = -0.5f * f2; float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) ); float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI ); - GlStateManager.translate( offset * f3, f4 - 0.3f * f2, f5 ); - GlStateManager.rotate( f2 * -45f, 1f, 0f, 0f ); - GlStateManager.rotate( offset * f2 * -30f, 0f, 1f, 0f ); + GlStateManager.translatef( offset * f3, f4 - 0.3f * f2, f5 ); + GlStateManager.rotatef( f2 * -45f, 1f, 0f, 0f ); + GlStateManager.rotatef( offset * f2 * -30f, 0f, 1f, 0f ); renderItem( stack ); @@ -93,25 +93,25 @@ private void renderItemFirstPersonSide( EnumHandSide side, float equipProgress, * @param equipProgress The equip progress of this item * @param swingProgress The swing progress of this item * @param stack The stack to render - * @see ItemRenderer#renderMapFirstPerson(float, float, float) + * @see FirstPersonRenderer#renderMapFirstPerson(float, float, float) */ private void renderItemFirstPersonCenter( float pitch, float equipProgress, float swingProgress, ItemStack stack ) { - ItemRenderer itemRenderer = Minecraft.getMinecraft().getItemRenderer(); + FirstPersonRenderer renderer = Minecraft.getInstance().getFirstPersonRenderer(); // Setup the appropriate transformations. This is just copied from the // corresponding method in ItemRenderer. float swingRt = MathHelper.sqrt( swingProgress ); float tX = -0.2f * MathHelper.sin( swingProgress * (float) Math.PI ); float tZ = -0.4f * MathHelper.sin( swingRt * (float) Math.PI ); - GlStateManager.translate( 0f, -tX / 2f, tZ ); - float pitchAngle = itemRenderer.getMapAngleFromPitch( pitch ); - GlStateManager.translate( 0f, 0.04f + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f ); - GlStateManager.rotate( pitchAngle * -85f, 1f, 0f, 0f ); - itemRenderer.renderArms(); + GlStateManager.translatef( 0f, -tX / 2f, tZ ); + float pitchAngle = renderer.getMapAngleFromPitch( pitch ); + GlStateManager.translatef( 0f, 0.04f + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f ); + GlStateManager.rotatef( pitchAngle * -85f, 1f, 0f, 0f ); + renderer.renderArms(); float rX = MathHelper.sin( swingRt * (float) Math.PI ); - GlStateManager.rotate( rX * 20f, 1f, 0f, 0f ); - GlStateManager.scale( 2f, 2f, 2f ); + GlStateManager.rotatef( rX * 20f, 1f, 0f, 0f ); + GlStateManager.scalef( 2f, 2f, 2f ); renderItem( stack ); } diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java index 02d0049a3..a44cb7b16 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java @@ -16,17 +16,17 @@ import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.RenderItem; -import net.minecraft.client.renderer.block.model.IBakedModel; -import net.minecraft.client.renderer.block.model.ItemCameraTransforms; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.item.ItemStack; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.event.RenderSpecificHandEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.relauncher.Side; import org.lwjgl.opengl.GL11; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; @@ -35,7 +35,7 @@ /** * Emulates map rendering for pocket computers */ -@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT ) +@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) public final class ItemPocketRenderer extends ItemMapLikeRenderer { private static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer(); @@ -61,9 +61,9 @@ protected void renderItem( ItemStack stack ) // in ItemRenderer GlStateManager.disableLighting(); - GlStateManager.rotate( 180f, 0f, 1f, 0f ); - GlStateManager.rotate( 180f, 0f, 0f, 1f ); - GlStateManager.scale( 0.5, 0.5, 0.5 ); + GlStateManager.rotatef( 180f, 0f, 1f, 0f ); + GlStateManager.rotatef( 180f, 0f, 0f, 1f ); + GlStateManager.scalef( 0.5f, 0.5f, 0.5f ); ClientComputer computer = ItemPocketComputer.createClientComputer( stack ); @@ -72,28 +72,28 @@ protected void renderItem( ItemStack stack ) // we display the pocket light and other such decorations. GlStateManager.pushMatrix(); - GlStateManager.scale( 1.0f, -1.0f, 1.0f ); + GlStateManager.scalef( 1.0f, -1.0f, 1.0f ); - Minecraft minecraft = Minecraft.getMinecraft(); + Minecraft minecraft = Minecraft.getInstance(); TextureManager textureManager = minecraft.getTextureManager(); - RenderItem renderItem = minecraft.getRenderItem(); + ItemRenderer renderItem = minecraft.getItemRenderer(); // Copy of RenderItem#renderItemModelIntoGUI but without the translation or scaling textureManager.bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE ); textureManager.getTexture( TextureMap.LOCATION_BLOCKS_TEXTURE ).setBlurMipmap( false, false ); GlStateManager.enableRescaleNormal(); - GlStateManager.enableAlpha(); + GlStateManager.enableAlphaTest(); GlStateManager.alphaFunc( GL11.GL_GREATER, 0.1F ); GlStateManager.enableBlend(); GlStateManager.blendFunc( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA ); - GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F ); + GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); IBakedModel baked = renderItem.getItemModelWithOverrides( stack, null, null ); - baked = ForgeHooksClient.handleCameraTransforms( baked, ItemCameraTransforms.TransformType.GUI, false ); + baked = ForgeHooksClient.handleCameraTransforms( baked, TransformType.GUI, false ); renderItem.renderItem( stack, baked ); - GlStateManager.disableAlpha(); + GlStateManager.disableAlphaTest(); GlStateManager.disableRescaleNormal(); GlStateManager.popMatrix(); @@ -108,13 +108,13 @@ protected void renderItem( ItemStack stack ) synchronized( terminal ) { GlStateManager.pushMatrix(); - GlStateManager.disableDepth(); + GlStateManager.disableDepthTest(); // Reset the position to be at the top left corner of the pocket computer // Note we translate towards the screen slightly too. - GlStateManager.translate( -8 / 16.0, -8 / 16.0, 0.5 / 16.0 ); + GlStateManager.translated( -8 / 16.0, -8 / 16.0, 0.5 / 16.0 ); // Translate to the top left of the screen. - GlStateManager.translate( 4 / 16.0, 3 / 16.0, 0 ); + GlStateManager.translated( 4 / 16.0, 3 / 16.0, 0 ); // Work out the scaling required to resize the terminal in order to fit on the computer final int margin = 2; @@ -126,7 +126,7 @@ protected void renderItem( ItemStack stack ) // The grid is 8 * 8 wide, so we start with a base of 1/2 (8 / 16). double scale = 1.0 / 2.0 / max; - GlStateManager.scale( scale, scale, scale ); + GlStateManager.scaled( scale, scale, scale ); // The margin/start positions are determined in order for the terminal to be centred. int startX = (max - width) / 2 + margin; @@ -160,7 +160,7 @@ protected void renderItem( ItemStack stack ) ); } - GlStateManager.enableDepth(); + GlStateManager.enableDepthTest(); GlStateManager.popMatrix(); } } diff --git a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java index e82d47218..ab8eb2670 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java @@ -10,11 +10,11 @@ import dan200.computercraft.shared.media.items.ItemPrintout; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.ItemStack; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.RenderItemInFrameEvent; import net.minecraftforge.client.event.RenderSpecificHandEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.relauncher.Side; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; @@ -25,7 +25,7 @@ /** * Emulates map and item-frame rendering for printouts */ -@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT ) +@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) public final class ItemPrintoutRenderer extends ItemMapLikeRenderer { private static final ItemPrintoutRenderer INSTANCE = new ItemPrintoutRenderer(); @@ -38,10 +38,9 @@ private ItemPrintoutRenderer() public static void onRenderInHand( RenderSpecificHandEvent event ) { ItemStack stack = event.getItemStack(); - if( stack.getItem() != ComputerCraft.Items.printout ) return; + if( !(stack.getItem() instanceof ItemPrintout) ) return; event.setCanceled( true ); - INSTANCE.renderItemFirstPerson( event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() ); } @@ -49,13 +48,13 @@ public static void onRenderInHand( RenderSpecificHandEvent event ) protected void renderItem( ItemStack stack ) { // Setup various transformations. Note that these are partially adapated from the corresponding method - // in ItemRenderer.renderMapFirstPerson + // in FirstPersonRenderer.renderFirstPersonMap GlStateManager.disableLighting(); - GlStateManager.rotate( 180f, 0f, 1f, 0f ); - GlStateManager.rotate( 180f, 0f, 0f, 1f ); - GlStateManager.scale( 0.42f, 0.42f, -0.42f ); - GlStateManager.translate( -0.5f, -0.48f, 0.0f ); + GlStateManager.rotatef( 180f, 0f, 1f, 0f ); + GlStateManager.rotatef( 180f, 0f, 0f, 1f ); + GlStateManager.scalef( 0.42f, 0.42f, -0.42f ); + GlStateManager.translatef( -0.5f, -0.48f, 0.0f ); drawPrintout( stack ); @@ -66,17 +65,17 @@ protected void renderItem( ItemStack stack ) public static void onRenderInFrame( RenderItemInFrameEvent event ) { ItemStack stack = event.getItem(); - if( stack.getItem() != ComputerCraft.Items.printout ) return; + if( !(stack.getItem() instanceof ItemPrintout) ) return; event.setCanceled( true ); GlStateManager.disableLighting(); // Move a little bit forward to ensure we're not clipping with the frame - GlStateManager.translate( 0.0f, 0.0f, -0.001f ); - GlStateManager.rotate( 180f, 0f, 0f, 1f ); - GlStateManager.scale( 0.95f, 0.95f, -0.95f ); - GlStateManager.translate( -0.5f, -0.5f, 0.0f ); + GlStateManager.translatef( 0.0f, 0.0f, -0.001f ); + GlStateManager.rotatef( 180f, 0f, 0f, 1f ); + GlStateManager.scalef( 0.95f, 0.95f, -0.95f ); + GlStateManager.translatef( -0.5f, -0.5f, 0.0f ); drawPrintout( stack ); @@ -87,7 +86,7 @@ public static void onRenderInFrame( RenderItemInFrameEvent event ) private static void drawPrintout( ItemStack stack ) { int pages = ItemPrintout.getPageCount( stack ); - boolean book = ItemPrintout.getType( stack ) == ItemPrintout.Type.Book; + boolean book = ((ItemPrintout) stack.getItem()).getType() == ItemPrintout.Type.BOOK; double width = LINE_MAX_LENGTH * FONT_WIDTH + X_TEXT_MARGIN * 2; double height = LINES_PER_PAGE * FONT_HEIGHT + Y_TEXT_MARGIN * 2; @@ -108,8 +107,8 @@ private static void drawPrintout( ItemStack stack ) // Scale the printout to fit correctly. double scale = 1.0 / max; - GlStateManager.scale( scale, scale, scale ); - GlStateManager.translate( (max - width) / 2.0f, (max - height) / 2.0f, 0.0f ); + GlStateManager.scaled( scale, scale, scale ); + GlStateManager.translated( (max - width) / 2.0, (max - height) / 2.0, 0.0 ); drawBorder( 0, 0, -0.01, 0, pages, book ); drawText( X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) ); diff --git a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java index 7f67c3178..5c3ec9013 100644 --- a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java +++ b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java @@ -6,7 +6,7 @@ package dan200.computercraft.client.render; -import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.util.EnumFacing; diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java index 0fd97e80a..07e9af310 100644 --- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -74,10 +74,10 @@ public static void drawText( int x, int y, int start, TextBuffer[] text, TextBuf public static void drawText( int x, int y, int start, String[] text, String[] colours ) { - GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); + GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); GlStateManager.enableBlend(); GlStateManager.enableTexture2D(); - GlStateManager.tryBlendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO ); + GlStateManager.blendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO ); FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance(); @@ -89,12 +89,12 @@ public static void drawText( int x, int y, int start, String[] text, String[] co public static void drawBorder( double x, double y, double z, int page, int pages, boolean isBook ) { - GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); + GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); GlStateManager.enableBlend(); GlStateManager.enableTexture2D(); - GlStateManager.tryBlendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO ); + GlStateManager.blendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO ); - Minecraft.getMinecraft().getTextureManager().bindTexture( BG ); + Minecraft.getInstance().getTextureManager().bindTexture( BG ); Tessellator tessellator = Tessellator.getInstance(); BufferBuilder buffer = tessellator.getBuffer(); diff --git a/src/main/java/dan200/computercraft/client/render/RenderOverlayCable.java b/src/main/java/dan200/computercraft/client/render/RenderOverlayCable.java index 0d06d30b9..e3af18ce3 100644 --- a/src/main/java/dan200/computercraft/client/render/RenderOverlayCable.java +++ b/src/main/java/dan200/computercraft/client/render/RenderOverlayCable.java @@ -7,216 +7,81 @@ package dan200.computercraft.client.render; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.peripheral.PeripheralType; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; -import dan200.computercraft.shared.peripheral.modem.wired.CableBounds; +import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.block.state.IBlockState; -import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.DrawBlockHighlightEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.relauncher.Side; import org.lwjgl.opengl.GL11; -@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT ) +@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) public final class RenderOverlayCable { - private static final float EXPAND = 0.002f; - private static final double MIN = CableBounds.MIN - EXPAND; - private static final double MAX = CableBounds.MAX + EXPAND; - private RenderOverlayCable() { } + /** + * Draw an outline for a specific part of a cable "Multipart". + * + * @param event The event to observe + * @see WorldRenderer#drawSelectionBox(EntityPlayer, RayTraceResult, int, float) + */ @SubscribeEvent public static void drawHighlight( DrawBlockHighlightEvent event ) { - if( event.getTarget().typeOfHit != RayTraceResult.Type.BLOCK ) return; + if( event.getTarget().type != RayTraceResult.Type.BLOCK ) return; BlockPos pos = event.getTarget().getBlockPos(); World world = event.getPlayer().getEntityWorld(); IBlockState state = world.getBlockState( pos ); - if( state.getBlock() != ComputerCraft.Blocks.cable ) return; - state = state.getActualState( world, pos ); + // We only care about instances with both cable and modem. + if( state.getBlock() != ComputerCraft.Blocks.cable || state.get( BlockCable.MODEM ).getFacing() == null || !state.get( BlockCable.CABLE ) ) + { + return; + } event.setCanceled( true ); - PeripheralType type = BlockCable.getPeripheralType( state ); + + EntityPlayer player = event.getPlayer(); + Minecraft mc = Minecraft.getInstance(); + float partialTicks = event.getPartialTicks(); GlStateManager.enableBlend(); - GlStateManager.tryBlendFuncSeparate( GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0 ); - GlStateManager.color( 0.0f, 0.0f, 0.0f, 0.4f ); - GL11.glLineWidth( 2.0F ); + GlStateManager.blendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO ); + GlStateManager.lineWidth( Math.max( 2.5F, mc.mainWindow.getFramebufferWidth() / 1920.0F * 2.5F ) ); GlStateManager.disableTexture2D(); GlStateManager.depthMask( false ); + GlStateManager.matrixMode( GL11.GL_PROJECTION ); GlStateManager.pushMatrix(); + GlStateManager.scalef( 1.0F, 1.0F, 0.999F ); - { - EntityPlayer player = event.getPlayer(); - double x = player.lastTickPosX + (player.posX - player.lastTickPosX) * event.getPartialTicks(); - double y = player.lastTickPosY + (player.posY - player.lastTickPosY) * event.getPartialTicks(); - double z = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * event.getPartialTicks(); + double x = player.lastTickPosX + (player.posX - player.lastTickPosX) * partialTicks; + double y = player.lastTickPosY + (player.posY - player.lastTickPosY) * partialTicks; + double z = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks; - GlStateManager.translate( -x + pos.getX(), -y + pos.getY(), -z + pos.getZ() ); - } + VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), event.getTarget().hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) + ? CableShapes.getModemShape( state ) : CableShapes.getCableShape( state ); - if( type != PeripheralType.Cable && WorldUtil.isVecInsideInclusive( CableBounds.getModemBounds( state ), event.getTarget().hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ) - { - RenderGlobal.drawSelectionBoundingBox( CableBounds.getModemBounds( state ), 0, 0, 0, 0.4f ); - } - else - { - int flags = 0; - - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - - for( EnumFacing facing : EnumFacing.VALUES ) - { - if( BlockCable.doesConnectVisually( state, world, pos, facing ) ) - { - flags |= 1 << facing.ordinal(); - - - switch( facing.getAxis() ) - { - case X: - { - double offset = facing == EnumFacing.WEST ? -EXPAND : 1 + EXPAND; - double centre = facing == EnumFacing.WEST ? MIN : MAX; - - buffer.begin( GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION ); - buffer.pos( offset, MIN, MIN ).endVertex(); - buffer.pos( offset, MAX, MIN ).endVertex(); - buffer.pos( offset, MAX, MAX ).endVertex(); - buffer.pos( offset, MIN, MAX ).endVertex(); - buffer.pos( offset, MIN, MIN ).endVertex(); - tessellator.draw(); - - buffer.begin( GL11.GL_LINES, DefaultVertexFormats.POSITION ); - buffer.pos( offset, MIN, MIN ).endVertex(); - buffer.pos( centre, MIN, MIN ).endVertex(); - buffer.pos( offset, MAX, MIN ).endVertex(); - buffer.pos( centre, MAX, MIN ).endVertex(); - buffer.pos( offset, MAX, MAX ).endVertex(); - buffer.pos( centre, MAX, MAX ).endVertex(); - buffer.pos( offset, MIN, MAX ).endVertex(); - buffer.pos( centre, MIN, MAX ).endVertex(); - tessellator.draw(); - break; - } - case Y: - { - double offset = facing == EnumFacing.DOWN ? -EXPAND : 1 + EXPAND; - double centre = facing == EnumFacing.DOWN ? MIN : MAX; - - buffer.begin( GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION ); - buffer.pos( MIN, offset, MIN ).endVertex(); - buffer.pos( MAX, offset, MIN ).endVertex(); - buffer.pos( MAX, offset, MAX ).endVertex(); - buffer.pos( MIN, offset, MAX ).endVertex(); - buffer.pos( MIN, offset, MIN ).endVertex(); - tessellator.draw(); - - buffer.begin( GL11.GL_LINES, DefaultVertexFormats.POSITION ); - buffer.pos( MIN, offset, MIN ).endVertex(); - buffer.pos( MIN, centre, MIN ).endVertex(); - buffer.pos( MAX, offset, MIN ).endVertex(); - buffer.pos( MAX, centre, MIN ).endVertex(); - buffer.pos( MAX, offset, MAX ).endVertex(); - buffer.pos( MAX, centre, MAX ).endVertex(); - buffer.pos( MIN, offset, MAX ).endVertex(); - buffer.pos( MIN, centre, MAX ).endVertex(); - tessellator.draw(); - break; - } - case Z: - { - double offset = facing == EnumFacing.NORTH ? -EXPAND : 1 + EXPAND; - double centre = facing == EnumFacing.NORTH ? MIN : MAX; - - buffer.begin( GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION ); - buffer.pos( MIN, MIN, offset ).endVertex(); - buffer.pos( MAX, MIN, offset ).endVertex(); - buffer.pos( MAX, MAX, offset ).endVertex(); - buffer.pos( MIN, MAX, offset ).endVertex(); - buffer.pos( MIN, MIN, offset ).endVertex(); - tessellator.draw(); - - buffer.begin( GL11.GL_LINES, DefaultVertexFormats.POSITION ); - buffer.pos( MIN, MIN, offset ).endVertex(); - buffer.pos( MIN, MIN, centre ).endVertex(); - buffer.pos( MAX, MIN, offset ).endVertex(); - buffer.pos( MAX, MIN, centre ).endVertex(); - buffer.pos( MAX, MAX, offset ).endVertex(); - buffer.pos( MAX, MAX, centre ).endVertex(); - buffer.pos( MIN, MAX, offset ).endVertex(); - buffer.pos( MIN, MAX, centre ).endVertex(); - tessellator.draw(); - break; - } - } - } - } - - buffer.begin( GL11.GL_LINES, DefaultVertexFormats.POSITION ); - - draw( buffer, flags, EnumFacing.WEST, EnumFacing.DOWN, EnumFacing.Axis.Z ); - draw( buffer, flags, EnumFacing.WEST, EnumFacing.UP, EnumFacing.Axis.Z ); - draw( buffer, flags, EnumFacing.EAST, EnumFacing.DOWN, EnumFacing.Axis.Z ); - draw( buffer, flags, EnumFacing.EAST, EnumFacing.UP, EnumFacing.Axis.Z ); - - draw( buffer, flags, EnumFacing.WEST, EnumFacing.NORTH, EnumFacing.Axis.Y ); - draw( buffer, flags, EnumFacing.WEST, EnumFacing.SOUTH, EnumFacing.Axis.Y ); - draw( buffer, flags, EnumFacing.EAST, EnumFacing.NORTH, EnumFacing.Axis.Y ); - draw( buffer, flags, EnumFacing.EAST, EnumFacing.SOUTH, EnumFacing.Axis.Y ); - - draw( buffer, flags, EnumFacing.DOWN, EnumFacing.NORTH, EnumFacing.Axis.X ); - draw( buffer, flags, EnumFacing.DOWN, EnumFacing.SOUTH, EnumFacing.Axis.X ); - draw( buffer, flags, EnumFacing.UP, EnumFacing.NORTH, EnumFacing.Axis.X ); - draw( buffer, flags, EnumFacing.UP, EnumFacing.SOUTH, EnumFacing.Axis.X ); - - tessellator.draw(); - } + WorldRenderer.drawShape( shape, pos.getX() - x, pos.getY() - y, pos.getZ() - z, 0.0F, 0.0F, 0.0F, 0.4F ); GlStateManager.popMatrix(); + GlStateManager.matrixMode( GL11.GL_MODELVIEW ); GlStateManager.depthMask( true ); GlStateManager.enableTexture2D(); GlStateManager.disableBlend(); } - - private static void draw( BufferBuilder buffer, int flags, EnumFacing a, EnumFacing b, EnumFacing.Axis other ) - { - if( ((flags >> a.ordinal()) & 1) != ((flags >> b.ordinal()) & 1) ) return; - - double offA = a.getAxisDirection() == EnumFacing.AxisDirection.NEGATIVE ? MIN : MAX; - double offB = b.getAxisDirection() == EnumFacing.AxisDirection.NEGATIVE ? MIN : MAX; - switch( other ) - { - case X: - buffer.pos( MIN, offA, offB ).endVertex(); - buffer.pos( MAX, offA, offB ).endVertex(); - break; - case Y: - buffer.pos( offA, MIN, offB ).endVertex(); - buffer.pos( offA, MAX, offB ).endVertex(); - break; - case Z: - buffer.pos( offA, offB, MIN ).endVertex(); - buffer.pos( offA, offB, MAX ).endVertex(); - break; - } - } } diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java index 16eb83c45..983de24b1 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java @@ -7,46 +7,48 @@ package dan200.computercraft.client.render; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.peripheral.PeripheralType; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; -import dan200.computercraft.shared.peripheral.modem.wired.BlockCableModemVariant; -import dan200.computercraft.shared.peripheral.modem.wired.CableBounds; +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.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.World; import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.MinecraftForgeClient; import org.lwjgl.opengl.GL11; import javax.annotation.Nonnull; +import java.util.Random; /** * Render breaking animation only over part of a {@link TileCable}. */ -public class TileEntityCableRenderer extends TileEntitySpecialRenderer +public class TileEntityCableRenderer extends TileEntityRenderer { + private static final Random random = new Random(); + @Override - public void render( @Nonnull TileCable te, double x, double y, double z, float partialTicks, int destroyStage, float alpha ) + public void render( @Nonnull TileCable te, double x, double y, double z, float partialTicks, int destroyStage ) { if( destroyStage < 0 ) return; BlockPos pos = te.getPos(); - Minecraft mc = Minecraft.getMinecraft(); + Minecraft mc = Minecraft.getInstance(); RayTraceResult hit = mc.objectMouseOver; if( hit == null || !hit.getBlockPos().equals( pos ) ) return; @@ -58,18 +60,12 @@ public void render( @Nonnull TileCable te, double x, double y, double z, float p Block block = state.getBlock(); if( block != ComputerCraft.Blocks.cable ) return; - state = state.getActualState( world, pos ); - if( te.getPeripheralType() != PeripheralType.Cable && WorldUtil.isVecInsideInclusive( CableBounds.getModemBounds( state ), hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ) - { - state = block.getDefaultState().withProperty( BlockCable.MODEM, state.getValue( BlockCable.MODEM ) ); - } - else - { - state = state.withProperty( BlockCable.MODEM, BlockCableModemVariant.None ); - } + VoxelShape shape = CableShapes.getModemShape( state ); + state = te.hasModem() && shape.getBoundingBox().grow( 0.02, 0.02, 0.02 ).contains( hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) + ? block.getDefaultState().with( BlockCable.MODEM, state.get( BlockCable.MODEM ) ) + : state.with( BlockCable.MODEM, CableModemVariant.None ); IBakedModel model = mc.getBlockRendererDispatcher().getModelForState( state ); - if( model == null ) return; preRenderDamagedBlocks(); @@ -81,11 +77,11 @@ public void render( @Nonnull TileCable te, double x, double y, double z, float p ForgeHooksClient.setRenderLayer( block.getRenderLayer() ); // See BlockRendererDispatcher#renderBlockDamage - TextureAtlasSprite breakingTexture = mc.getTextureMapBlocks().getAtlasSprite( "minecraft:blocks/destroy_stage_" + destroyStage ); - Minecraft.getMinecraft().getBlockRendererDispatcher().getBlockModelRenderer().renderModel( + TextureAtlasSprite breakingTexture = mc.getTextureMap().getSprite( DESTROY_STAGES[destroyStage] ); + mc.getBlockRendererDispatcher().getBlockModelRenderer().renderModel( world, ForgeHooksClient.getDamageModel( model, breakingTexture, state, world, pos ), - state, pos, buffer, true + state, pos, buffer, true, random, state.getPositionRandom( pos ) ); ForgeHooksClient.setRenderLayer( BlockRenderLayer.SOLID ); @@ -97,30 +93,30 @@ public void render( @Nonnull TileCable te, double x, double y, double z, float p } /** - * @see RenderGlobal#preRenderDamagedBlocks() + * @see WorldRenderer#preRenderDamagedBlocks() */ private void preRenderDamagedBlocks() { GlStateManager.disableLighting(); GlStateManager.enableBlend(); - GlStateManager.tryBlendFuncSeparate( GlStateManager.SourceFactor.DST_COLOR, GlStateManager.DestFactor.SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO ); + GlStateManager.blendFuncSeparate( GlStateManager.SourceFactor.DST_COLOR, GlStateManager.DestFactor.SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO ); GlStateManager.enableBlend(); - GlStateManager.color( 1.0F, 1.0F, 1.0F, 0.5F ); - GlStateManager.doPolygonOffset( -3.0F, -3.0F ); + GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 0.5F ); + GlStateManager.polygonOffset( -3.0F, -3.0F ); GlStateManager.enablePolygonOffset(); GlStateManager.alphaFunc( 516, 0.1F ); - GlStateManager.enableAlpha(); + GlStateManager.enableAlphaTest(); GlStateManager.pushMatrix(); } /** - * @see RenderGlobal#postRenderDamagedBlocks() + * @see WorldRenderer#postRenderDamagedBlocks() */ private void postRenderDamagedBlocks() { - GlStateManager.disableAlpha(); - GlStateManager.doPolygonOffset( 0.0F, 0.0F ); + GlStateManager.disableAlphaTest(); + GlStateManager.polygonOffset( 0.0F, 0.0F ); GlStateManager.disablePolygonOffset(); GlStateManager.disablePolygonOffset(); GlStateManager.depthMask( true ); diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index f5b7a498d..3ac9ce6fa 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -20,16 +20,16 @@ import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import org.lwjgl.opengl.GL11; -public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer +public class TileEntityMonitorRenderer extends TileEntityRenderer { @Override - public void render( TileMonitor tileEntity, double posX, double posY, double posZ, float f, int i, float f2 ) + public void render( TileMonitor tileEntity, double posX, double posY, double posZ, float f, int i ) { if( tileEntity != null ) { @@ -73,19 +73,19 @@ private static void renderMonitorAt( TileMonitor monitor, double posX, double po try { // Setup initial transform - GlStateManager.translate( posX + 0.5, posY + 0.5, posZ + 0.5 ); - GlStateManager.rotate( -yaw, 0.0f, 1.0f, 0.0f ); - GlStateManager.rotate( pitch, 1.0f, 0.0f, 0.0f ); - GlStateManager.translate( + GlStateManager.translated( posX + 0.5, posY + 0.5, posZ + 0.5 ); + GlStateManager.rotatef( -yaw, 0.0f, 1.0f, 0.0f ); + GlStateManager.rotatef( pitch, 1.0f, 0.0f, 0.0f ); + GlStateManager.translated( -0.5 + TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN, - origin.getHeight() - 0.5 - (TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN), + origin.getHeight() - 0.5 - (TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN) + 0, 0.5 ); double xSize = origin.getWidth() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER); double ySize = origin.getHeight() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER); // Get renderers - Minecraft mc = Minecraft.getMinecraft(); + Minecraft mc = Minecraft.getInstance(); Tessellator tessellator = Tessellator.getInstance(); BufferBuilder renderer = tessellator.getBuffer(); @@ -94,9 +94,9 @@ private static void renderMonitorAt( TileMonitor monitor, double posX, double po // Draw the contents GlStateManager.depthMask( false ); - OpenGlHelper.setLightmapTextureCoords( OpenGlHelper.lightmapTexUnit, 0xFF, 0xFF ); + OpenGlHelper.glMultiTexCoord2f( OpenGlHelper.GL_TEXTURE1, 0xFFFF, 0xFFFF ); GlStateManager.disableLighting(); - mc.entityRenderer.disableLightmap(); + mc.gameRenderer.disableLightmap(); try { Terminal terminal = originTerminal.getTerminal(); @@ -124,14 +124,14 @@ private static void renderMonitorAt( TileMonitor monitor, double posX, double po { double xScale = xSize / (width * FixedWidthFontRenderer.FONT_WIDTH); double yScale = ySize / (height * FixedWidthFontRenderer.FONT_HEIGHT); - GlStateManager.scale( xScale, -yScale, 1.0 ); + GlStateManager.scaled( xScale, -yScale, 1.0 ); // Draw background mc.getTextureManager().bindTexture( FixedWidthFontRenderer.BACKGROUND ); if( redraw ) { // Build background display list - GlStateManager.glNewList( originTerminal.renderDisplayLists[0], GL11.GL_COMPILE ); + GlStateManager.newList( originTerminal.renderDisplayLists[0], GL11.GL_COMPILE ); try { double marginXSize = TileMonitor.RENDER_MARGIN / xScale; @@ -142,10 +142,10 @@ private static void renderMonitorAt( TileMonitor monitor, double posX, double po GlStateManager.pushMatrix(); try { - GlStateManager.scale( 1.0, marginSquash, 1.0 ); - GlStateManager.translate( 0.0, -marginYSize / marginSquash, 0.0 ); + GlStateManager.scaled( 1.0, marginSquash, 1.0 ); + GlStateManager.translated( 0.0, -marginYSize / marginSquash, 0.0 ); fontRenderer.drawStringBackgroundPart( 0, 0, terminal.getBackgroundColourLine( 0 ), marginXSize, marginXSize, greyscale, palette ); - GlStateManager.translate( 0.0, (marginYSize + height * FixedWidthFontRenderer.FONT_HEIGHT) / marginSquash, 0.0 ); + GlStateManager.translated( 0.0, (marginYSize + height * FixedWidthFontRenderer.FONT_HEIGHT) / marginSquash, 0.0 ); fontRenderer.drawStringBackgroundPart( 0, 0, terminal.getBackgroundColourLine( height - 1 ), marginXSize, marginXSize, greyscale, palette ); } finally @@ -167,7 +167,7 @@ private static void renderMonitorAt( TileMonitor monitor, double posX, double po } finally { - GlStateManager.glEndList(); + GlStateManager.endList(); } } GlStateManager.callList( originTerminal.renderDisplayLists[0] ); @@ -178,7 +178,7 @@ private static void renderMonitorAt( TileMonitor monitor, double posX, double po if( redraw ) { // Build text display list - GlStateManager.glNewList( originTerminal.renderDisplayLists[1], GL11.GL_COMPILE ); + GlStateManager.newList( originTerminal.renderDisplayLists[1], GL11.GL_COMPILE ); try { // Lines @@ -195,7 +195,7 @@ private static void renderMonitorAt( TileMonitor monitor, double posX, double po } finally { - GlStateManager.glEndList(); + GlStateManager.endList(); } } GlStateManager.callList( originTerminal.renderDisplayLists[1] ); @@ -206,7 +206,7 @@ private static void renderMonitorAt( TileMonitor monitor, double posX, double po if( redraw ) { // Build cursor display list - GlStateManager.glNewList( originTerminal.renderDisplayLists[2], GL11.GL_COMPILE ); + GlStateManager.newList( originTerminal.renderDisplayLists[2], GL11.GL_COMPILE ); try { // Cursor @@ -227,7 +227,7 @@ private static void renderMonitorAt( TileMonitor monitor, double posX, double po } finally { - GlStateManager.glEndList(); + GlStateManager.endList(); } } if( FrameInfo.getGlobalCursorBlink() ) @@ -262,7 +262,7 @@ private static void renderMonitorAt( TileMonitor monitor, double posX, double po finally { GlStateManager.depthMask( true ); - mc.entityRenderer.enableLightmap(); + mc.gameRenderer.enableLightmap(); GlStateManager.enableLighting(); } @@ -285,7 +285,7 @@ private static void renderMonitorAt( TileMonitor monitor, double posX, double po } finally { - GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); + GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); GlStateManager.popMatrix(); } } diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java index 32a24606b..a4d35a7f0 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java @@ -10,20 +10,21 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.blocks.TileTurtle; +import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.HolidayUtil; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.block.model.IBakedModel; -import net.minecraft.client.renderer.block.model.ModelManager; -import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.client.renderer.model.BakedQuad; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.model.ModelManager; +import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.client.renderer.texture.TextureMap; -import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.util.EnumFacing; @@ -36,16 +37,17 @@ import javax.vecmath.Matrix4f; import java.util.List; +import java.util.Random; -public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer +public class TileEntityTurtleRenderer extends TileEntityRenderer { - private static final ModelResourceLocation NORMAL_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle", "inventory" ); + private static final ModelResourceLocation NORMAL_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_normal", "inventory" ); private static final ModelResourceLocation ADVANCED_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_advanced", "inventory" ); - private static final ModelResourceLocation COLOUR_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_white", "inventory" ); + private static final ModelResourceLocation COLOUR_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_colour", "inventory" ); private static final ModelResourceLocation ELF_OVERLAY_MODEL = new ModelResourceLocation( "computercraft:turtle_elf_overlay", "inventory" ); @Override - public void render( TileTurtle tileEntity, double posX, double posY, double posZ, float partialTicks, int breaking, float f2 ) + public void render( TileTurtle tileEntity, double posX, double posY, double posZ, float partialTicks, int breaking ) { if( tileEntity != null ) renderTurtleAt( tileEntity, posX, posY, posZ, partialTicks ); } @@ -85,7 +87,7 @@ private void renderTurtleAt( TileTurtle turtle, double posX, double posY, double if( label != null && rendererDispatcher.cameraHitResult != null && turtle.getPos().equals( rendererDispatcher.cameraHitResult.getBlockPos() ) ) { setLightmapDisabled( true ); - EntityRenderer.drawNameplate( + GameRenderer.drawNameplate( getFontRenderer(), label, (float) posX + 0.5F, (float) posY + 1.2F, (float) posZ + 0.5F, 0, rendererDispatcher.entityYaw, rendererDispatcher.entityPitch, false, false @@ -96,22 +98,21 @@ private void renderTurtleAt( TileTurtle turtle, double posX, double posY, double GlStateManager.pushMatrix(); try { - IBlockState state = turtle.getWorld().getBlockState( turtle.getPos() ); + IBlockState state = turtle.getBlockState(); // Setup the transform Vec3d offset = turtle.getRenderOffset( partialTicks ); float yaw = turtle.getRenderYaw( partialTicks ); - GlStateManager.translate( posX + offset.x, posY + offset.y, posZ + offset.z ); - + GlStateManager.translated( posX + offset.x, posY + offset.y, posZ + offset.z ); // Render the turtle - GlStateManager.translate( 0.5f, 0.5f, 0.5f ); - GlStateManager.rotate( 180.0f - yaw, 0.0f, 1.0f, 0.0f ); + GlStateManager.translatef( 0.5f, 0.5f, 0.5f ); + GlStateManager.rotatef( 180.0f - yaw, 0.0f, 1.0f, 0.0f ); if( label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )) ) { // Flip the model and swap the cull face as winding order will have changed. - GlStateManager.scale( 1.0f, -1.0f, 1.0f ); + GlStateManager.scalef( 1.0f, -1.0f, 1.0f ); GlStateManager.cullFace( GlStateManager.CullFace.FRONT ); } - GlStateManager.translate( -0.5f, -0.5f, -0.5f ); + GlStateManager.translatef( -0.5f, -0.5f, -0.5f ); // Render the turtle int colour = turtle.getColour(); ComputerFamily family = turtle.getFamily(); @@ -151,7 +152,7 @@ private void renderTurtleAt( TileTurtle turtle, double posX, double posY, double } } - private static void renderUpgrade( IBlockState state, TileTurtle turtle, TurtleSide side, float f ) + private void renderUpgrade( IBlockState state, TileTurtle turtle, TurtleSide side, float f ) { ITurtleUpgrade upgrade = turtle.getUpgrade( side ); if( upgrade != null ) @@ -160,9 +161,9 @@ private static void renderUpgrade( IBlockState state, TileTurtle turtle, TurtleS try { float toolAngle = turtle.getToolRenderAngle( side, f ); - GlStateManager.translate( 0.0f, 0.5f, 0.5f ); - GlStateManager.rotate( -toolAngle, 1.0f, 0.0f, 0.0f ); - GlStateManager.translate( 0.0f, -0.5f, -0.5f ); + GlStateManager.translatef( 0.0f, 0.5f, 0.5f ); + GlStateManager.rotatef( -toolAngle, 1.0f, 0.0f, 0.0f ); + GlStateManager.translatef( 0.0f, -0.5f, -0.5f ); Pair pair = upgrade.getModel( turtle.getAccess(), side ); if( pair != null ) @@ -184,22 +185,22 @@ private static void renderUpgrade( IBlockState state, TileTurtle turtle, TurtleS } } - private static void renderModel( IBlockState state, ModelResourceLocation modelLocation, int[] tints ) + private void renderModel( IBlockState state, ModelResourceLocation modelLocation, int[] tints ) { - Minecraft mc = Minecraft.getMinecraft(); - ModelManager modelManager = mc.getRenderItem().getItemModelMesher().getModelManager(); + Minecraft mc = Minecraft.getInstance(); + ModelManager modelManager = mc.getItemRenderer().getItemModelMesher().getModelManager(); renderModel( state, modelManager.getModel( modelLocation ), tints ); } - private static void renderModel( IBlockState state, IBakedModel model, int[] tints ) + private void renderModel( IBlockState state, IBakedModel model, int[] tints ) { - Minecraft mc = Minecraft.getMinecraft(); + Random random = new Random( 0 ); Tessellator tessellator = Tessellator.getInstance(); - mc.getTextureManager().bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE ); - renderQuads( tessellator, model.getQuads( state, null, 0 ), tints ); - for( EnumFacing facing : EnumFacing.VALUES ) + rendererDispatcher.textureManager.bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE ); + renderQuads( tessellator, model.getQuads( state, null, random ), tints ); + for( EnumFacing facing : DirectionUtil.FACINGS ) { - renderQuads( tessellator, model.getQuads( state, facing, 0 ), tints ); + renderQuads( tessellator, model.getQuads( state, facing, random ), tints ); } } diff --git a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java index cfd1e60ce..c1198e983 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java @@ -6,26 +6,29 @@ package dan200.computercraft.client.render; -import com.google.common.collect.ImmutableMap; import dan200.computercraft.ComputerCraft; -import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.model.IUnbakedModel; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.vertex.VertexFormat; -import net.minecraft.client.resources.IResourceManager; +import net.minecraft.resources.IResourceManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.client.model.ICustomModelLoader; -import net.minecraftforge.client.model.IModel; -import net.minecraftforge.client.model.ModelLoaderRegistry; import net.minecraftforge.common.model.IModelState; import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Collection; +import java.util.Set; import java.util.function.Function; +import java.util.stream.Collectors; public final class TurtleModelLoader implements ICustomModelLoader { - private static final ResourceLocation NORMAL_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle" ); - private static final ResourceLocation ADVANCED_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/advanced_turtle" ); - private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_white" ); + private static final ResourceLocation NORMAL_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_normal" ); + private static final ResourceLocation ADVANCED_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_advanced" ); + private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_colour" ); public static final TurtleModelLoader INSTANCE = new TurtleModelLoader(); @@ -42,80 +45,57 @@ public void onResourceManagerReload( @Nonnull IResourceManager manager ) public boolean accepts( @Nonnull ResourceLocation name ) { return name.getNamespace().equals( ComputerCraft.MOD_ID ) - && (name.getPath().equals( "turtle" ) || name.getPath().equals( "turtle_advanced" )); + && (name.getPath().equals( "item/turtle_normal" ) || name.getPath().equals( "item/turtle_advanced" )); } @Nonnull @Override - public IModel loadModel( @Nonnull ResourceLocation name ) throws Exception + public IUnbakedModel loadModel( @Nonnull ResourceLocation name ) { if( name.getNamespace().equals( ComputerCraft.MOD_ID ) ) { - IModel colourModel = ModelLoaderRegistry.getModel( COLOUR_TURTLE_MODEL ); switch( name.getPath() ) { - case "turtle": - return new TurtleModel( ModelLoaderRegistry.getModel( NORMAL_TURTLE_MODEL ), colourModel ); - case "turtle_advanced": - return new TurtleModel( ModelLoaderRegistry.getModel( ADVANCED_TURTLE_MODEL ), colourModel ); + case "item/turtle_normal": + return new TurtleModel( NORMAL_TURTLE_MODEL ); + case "item/turtle_advanced": + return new TurtleModel( ADVANCED_TURTLE_MODEL ); } } throw new IllegalStateException( "Loader does not accept " + name ); } - private static final class TurtleModel implements IModel + private static final class TurtleModel implements IUnbakedModel { - private final IModel family; - private final IModel colour; + private final ResourceLocation family; - private TurtleModel( IModel family, IModel colour ) + private TurtleModel( ResourceLocation family ) {this.family = family;} + + @Nonnull + @Override + public Collection getDependencies() { - this.family = family; - this.colour = colour; + return Arrays.asList( family, COLOUR_TURTLE_MODEL ); } @Nonnull @Override - public IBakedModel bake( @Nonnull IModelState state, @Nonnull VertexFormat format, @Nonnull Function function ) + public Collection getTextures( @Nonnull Function modelGetter, @Nonnull Set missingTextureErrors ) + { + return getDependencies().stream() + .flatMap( x -> modelGetter.apply( x ).getTextures( modelGetter, missingTextureErrors ).stream() ) + .collect( Collectors.toSet() ); + } + + @Nullable + @Override + public IBakedModel bake( @Nonnull Function modelGetter, @Nonnull Function spriteGetter, @Nonnull IModelState state, boolean uvlock, @Nonnull VertexFormat format ) { return new TurtleSmartItemModel( - family.bake( state, format, function ), - colour.bake( state, format, function ) + modelGetter.apply( family ).bake( modelGetter, spriteGetter, state, uvlock, format ), + modelGetter.apply( COLOUR_TURTLE_MODEL ).bake( modelGetter, spriteGetter, state, uvlock, format ) ); } - - private TurtleModel copy( IModel family, IModel colour ) - { - return this.family == family && this.colour == colour ? this : new TurtleModel( family, colour ); - } - - @Nonnull - @Override - public IModel smoothLighting( boolean value ) - { - return copy( family.smoothLighting( value ), colour.smoothLighting( value ) ); - } - - @Nonnull - @Override - public IModel gui3d( boolean value ) - { - return copy( family.gui3d( value ), colour.gui3d( value ) ); - } - - @Nonnull - @Override - public IModel uvlock( boolean value ) - { - return copy( family.uvlock( value ), colour.uvlock( value ) ); - } - - @Nonnull - @Override - public IModel retexture( ImmutableMap textures ) - { - return copy( family.retexture( textures ), colour.retexture( textures ) ); - } } } diff --git a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java index 183e47f4b..b29158056 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java @@ -7,19 +7,16 @@ package dan200.computercraft.client.render; import net.minecraft.block.state.IBlockState; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.block.model.IBakedModel; -import net.minecraft.client.renderer.block.model.ItemCameraTransforms; -import net.minecraft.client.renderer.block.model.ItemOverrideList; +import net.minecraft.client.renderer.model.BakedQuad; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.model.ItemCameraTransforms; +import net.minecraft.client.renderer.model.ItemOverrideList; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.util.EnumFacing; import javax.annotation.Nonnull; import javax.vecmath.Matrix4f; -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class TurtleMultiModel implements IBakedModel { @@ -47,7 +44,7 @@ public TurtleMultiModel( IBakedModel baseModel, IBakedModel overlayModel, Matrix @Nonnull @Override - public List getQuads( IBlockState state, EnumFacing side, long rand ) + public List getQuads( IBlockState state, EnumFacing side, @Nonnull Random rand ) { if( side != null ) { @@ -61,7 +58,7 @@ public List getQuads( IBlockState state, EnumFacing side, long rand ) } } - private List buildQuads( IBlockState state, EnumFacing side, long rand ) + private List buildQuads( IBlockState state, EnumFacing side, Random rand ) { ArrayList quads = new ArrayList<>(); ModelTransformer.transformQuadsTo( quads, m_baseModel.getQuads( state, side, rand ), m_generalTransform ); @@ -134,6 +131,6 @@ public ItemCameraTransforms getItemCameraTransforms() @Override public ItemOverrideList getOverrides() { - return ItemOverrideList.NONE; + return ItemOverrideList.EMPTY; } } diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java index 9ef6144fc..bbf5f34ff 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java @@ -9,12 +9,12 @@ import com.google.common.base.Objects; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; -import dan200.computercraft.shared.turtle.items.ItemTurtleBase; +import dan200.computercraft.shared.turtle.items.ItemTurtle; import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.HolidayUtil; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.model.*; +import net.minecraft.client.renderer.model.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.ItemStack; @@ -26,9 +26,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.vecmath.Matrix4f; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Random; public class TurtleSmartItemModel implements IBakedModel { @@ -106,13 +106,13 @@ public TurtleSmartItemModel( IBakedModel familyModel, IBakedModel colourModel ) this.colourModel = colourModel; m_cachedModels = new HashMap<>(); - m_overrides = new ItemOverrideList( new ArrayList<>() ) + m_overrides = new ItemOverrideList() { @Nonnull @Override - public IBakedModel handleItemState( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity ) + public IBakedModel getModelWithOverrides( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity ) { - ItemTurtleBase turtle = (ItemTurtleBase) stack.getItem(); + ItemTurtle turtle = (ItemTurtle) stack.getItem(); int colour = turtle.getColour( stack ); ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.Left ); ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.Right ); @@ -138,8 +138,8 @@ public ItemOverrideList getOverrides() private IBakedModel buildModel( TurtleModelCombination combo ) { - Minecraft mc = Minecraft.getMinecraft(); - ModelManager modelManager = mc.getRenderItem().getItemModelMesher().getModelManager(); + Minecraft mc = Minecraft.getInstance(); + ModelManager modelManager = mc.getItemRenderer().getItemModelMesher().getModelManager(); ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.m_overlay, combo.m_christmas ); IBakedModel baseModel = combo.m_colour ? colourModel : familyModel; @@ -167,7 +167,7 @@ else if( rightModel != null ) @Nonnull @Override - public List getQuads( IBlockState state, EnumFacing facing, long rand ) + public List getQuads( IBlockState state, EnumFacing facing, @Nonnull Random rand ) { return familyModel.getQuads( state, facing, rand ); } diff --git a/src/main/java/dan200/computercraft/core/apis/AddressPredicate.java b/src/main/java/dan200/computercraft/core/apis/AddressPredicate.java index 72ed01b79..430017dad 100644 --- a/src/main/java/dan200/computercraft/core/apis/AddressPredicate.java +++ b/src/main/java/dan200/computercraft/core/apis/AddressPredicate.java @@ -12,6 +12,7 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; @@ -50,6 +51,11 @@ public boolean contains( InetAddress address ) private final List ranges; public AddressPredicate( String... filters ) + { + this( Arrays.asList( filters ) ); + } + + public AddressPredicate( Iterable filters ) { List wildcards = this.wildcards = new ArrayList<>(); List ranges = this.ranges = new ArrayList<>(); diff --git a/src/main/java/dan200/computercraft/core/apis/ApiFactories.java b/src/main/java/dan200/computercraft/core/apis/ApiFactories.java index 54b55cc86..d4b0adc66 100644 --- a/src/main/java/dan200/computercraft/core/apis/ApiFactories.java +++ b/src/main/java/dan200/computercraft/core/apis/ApiFactories.java @@ -23,7 +23,7 @@ private ApiFactories() private static final Collection factories = new LinkedHashSet<>(); private static final Collection factoriesView = Collections.unmodifiableCollection( factories ); - public static void register( @Nonnull ILuaAPIFactory factory ) + public static synchronized void register( @Nonnull ILuaAPIFactory factory ) { Preconditions.checkNotNull( factory, "provider cannot be null" ); factories.add( factory ); diff --git a/src/main/java/dan200/computercraft/core/computer/Computer.java b/src/main/java/dan200/computercraft/core/computer/Computer.java index fc1c9609c..5c54e325d 100644 --- a/src/main/java/dan200/computercraft/core/computer/Computer.java +++ b/src/main/java/dan200/computercraft/core/computer/Computer.java @@ -8,7 +8,6 @@ import com.google.common.base.Objects; import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IWorkMonitor; import dan200.computercraft.core.apis.IAPIEnvironment; import dan200.computercraft.core.filesystem.FileSystem; @@ -218,32 +217,4 @@ public void addApi( ILuaAPI api ) { executor.addApi( api ); } - - @Deprecated - public IPeripheral getPeripheral( int side ) - { - return internalEnvironment.getPeripheral( side ); - } - - @Deprecated - public void setPeripheral( int side, IPeripheral peripheral ) - { - internalEnvironment.setPeripheral( side, peripheral ); - } - - @Deprecated - public void addAPI( dan200.computercraft.core.apis.ILuaAPI api ) - { - addApi( api ); - } - - @Deprecated - @SuppressWarnings( "unused" ) - public void advance( double dt ) - { - tick(); - } - - @Deprecated - public static final String[] s_sideNames = IAPIEnvironment.SIDE_NAMES; } diff --git a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java new file mode 100644 index 000000000..caf97ce71 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java @@ -0,0 +1,275 @@ +/* + * 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.filesystem; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.io.ByteStreams; +import dan200.computercraft.api.filesystem.IMount; +import dan200.computercraft.core.apis.handles.ArrayByteChannel; +import net.minecraft.resources.IReloadableResourceManager; +import net.minecraft.resources.IResource; +import net.minecraft.resources.IResourceManager; +import net.minecraft.resources.IResourceManagerReloadListener; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.resource.IResourceType; +import net.minecraftforge.resource.ISelectiveResourceReloadListener; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; + +public class ResourceMount implements IMount +{ + /** + * Only cache files smaller than 1MiB. + */ + private static final int MAX_CACHED_SIZE = 1 << 20; + + /** + * Limit the entire cache to 64MiB. + */ + private static final int MAX_CACHE_SIZE = 64 << 20; + + private static final byte[] TEMP_BUFFER = new byte[8192]; + + /** + * We maintain a cache of the contents of all files in the mount. This allows us to allow + * seeking within ROM files, and reduces the amount we need to access disk for computer startup. + */ + private static final Cache CONTENTS_CACHE = CacheBuilder.newBuilder() + .concurrencyLevel( 4 ) + .expireAfterAccess( 60, TimeUnit.SECONDS ) + .maximumWeight( MAX_CACHE_SIZE ) + .weakKeys() + .weigher( ( k, v ) -> v.length ) + .build(); + + private final String namespace; + private final String subPath; + private final IReloadableResourceManager manager; + + @Nullable + private FileEntry root; + + public ResourceMount( String namespace, String subPath, IReloadableResourceManager manager ) + { + this.namespace = namespace; + this.subPath = subPath; + this.manager = manager; + + Listener.INSTANCE.add( manager, this ); + if( root == null ) load(); + } + + private void load() + { + boolean hasAny = false; + FileEntry newRoot = new FileEntry( new ResourceLocation( namespace, subPath ) ); + for( ResourceLocation file : manager.getAllResourceLocations( subPath, s -> true ) ) + { + if( !file.getNamespace().equals( namespace ) ) continue; + + String localPath = FileSystem.toLocal( file.getPath(), subPath ); + create( newRoot, localPath ); + hasAny = true; + } + + root = hasAny ? newRoot : null; + } + + private FileEntry get( String path ) + { + FileEntry lastEntry = root; + int lastIndex = 0; + + while( lastEntry != null && lastIndex < path.length() ) + { + int nextIndex = path.indexOf( '/', lastIndex ); + if( nextIndex < 0 ) nextIndex = path.length(); + + lastEntry = lastEntry.children == null ? null : lastEntry.children.get( path.substring( lastIndex, nextIndex ) ); + lastIndex = nextIndex + 1; + } + + return lastEntry; + } + + private void create( FileEntry lastEntry, String path ) + { + int lastIndex = 0; + while( lastIndex < path.length() ) + { + int nextIndex = path.indexOf( '/', lastIndex ); + if( nextIndex < 0 ) nextIndex = path.length(); + + String part = path.substring( lastIndex, nextIndex ); + if( lastEntry.children == null ) lastEntry.children = new HashMap<>(); + + FileEntry nextEntry = lastEntry.children.get( part ); + if( nextEntry == null ) + { + lastEntry.children.put( part, nextEntry = new FileEntry( new ResourceLocation( namespace, subPath + "/" + path ) ) ); + } + + lastEntry = nextEntry; + lastIndex = nextIndex + 1; + } + } + + @Override + public boolean exists( @Nonnull String path ) + { + return get( path ) != null; + } + + @Override + public boolean isDirectory( @Nonnull String path ) + { + FileEntry file = get( path ); + return file != null && file.isDirectory(); + } + + @Override + public void list( @Nonnull String path, @Nonnull List contents ) throws IOException + { + FileEntry file = get( path ); + if( file == null || !file.isDirectory() ) throw new IOException( "/" + path + ": Not a directory" ); + + file.list( contents ); + } + + @Override + public long getSize( @Nonnull String path ) throws IOException + { + FileEntry file = get( path ); + if( file != null ) + { + if( file.size != -1 ) return file.size; + if( file.isDirectory() ) return file.size = 0; + + byte[] contents = CONTENTS_CACHE.getIfPresent( file ); + if( contents != null ) return file.size = contents.length; + + try + { + IResource resource = manager.getResource( file.identifier ); + InputStream s = resource.getInputStream(); + int total = 0, read = 0; + do + { + total += read; + read = s.read( TEMP_BUFFER ); + } while( read > 0 ); + + return file.size = total; + } + catch( IOException e ) + { + return file.size = 0; + } + } + + throw new IOException( "/" + path + ": No such file" ); + } + + @Nonnull + @Override + @Deprecated + public InputStream openForRead( @Nonnull String path ) throws IOException + { + return Channels.newInputStream( openChannelForRead( path ) ); + } + + @Nonnull + @Override + public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException + { + FileEntry file = get( path ); + if( file != null && !file.isDirectory() ) + { + byte[] contents = CONTENTS_CACHE.getIfPresent( file ); + if( contents != null ) return new ArrayByteChannel( contents ); + + try( InputStream stream = manager.getResource( file.identifier ).getInputStream() ) + { + if( stream.available() > MAX_CACHED_SIZE ) return Channels.newChannel( stream ); + + contents = ByteStreams.toByteArray( stream ); + CONTENTS_CACHE.put( file, contents ); + return new ArrayByteChannel( contents ); + } + catch( FileNotFoundException ignored ) + { + } + } + + throw new IOException( "/" + path + ": No such file" ); + } + + private static class FileEntry + { + final ResourceLocation identifier; + Map children; + long size = -1; + + FileEntry( ResourceLocation identifier ) + { + this.identifier = identifier; + } + + boolean isDirectory() + { + return children != null; + } + + void list( List contents ) + { + if( children != null ) contents.addAll( children.keySet() ); + } + } + + /** + * A {@link IResourceManagerReloadListener} which reloads any associated mounts. + * + * While people should really be keeping a permanent reference to this, some people construct it every + * method call, so let's make this as small as possible. + */ + static class Listener implements ISelectiveResourceReloadListener + { + private static final Listener INSTANCE = new Listener(); + + private final Set mounts = Collections.newSetFromMap( new WeakHashMap<>() ); + private final Set managers = Collections.newSetFromMap( new WeakHashMap<>() ); + + @Override + public void onResourceManagerReload( @Nonnull IResourceManager manager ) + { + // FIXME: Remove this. We need this patch in order to prevent trying to load ReloadRequirements. + onResourceManagerReload( manager, x -> true ); + } + + @Override + public synchronized void onResourceManagerReload( @Nonnull IResourceManager manager, @Nonnull Predicate predicate ) + { + for( ResourceMount mount : mounts ) mount.load(); + } + + synchronized void add( IReloadableResourceManager manager, ResourceMount mount ) + { + if( managers.add( manager ) ) manager.addReloadListener( this ); + mounts.add( mount ); + } + } +} diff --git a/src/main/java/dan200/computercraft/core/terminal/Terminal.java b/src/main/java/dan200/computercraft/core/terminal/Terminal.java index 50719cc73..a0229f53a 100644 --- a/src/main/java/dan200/computercraft/core/terminal/Terminal.java +++ b/src/main/java/dan200/computercraft/core/terminal/Terminal.java @@ -336,16 +336,16 @@ public final void clearChanged() public synchronized NBTTagCompound writeToNBT( NBTTagCompound nbt ) { - nbt.setInteger( "term_cursorX", m_cursorX ); - nbt.setInteger( "term_cursorY", m_cursorY ); - nbt.setBoolean( "term_cursorBlink", m_cursorBlink ); - nbt.setInteger( "term_textColour", m_cursorColour ); - nbt.setInteger( "term_bgColour", m_cursorBackgroundColour ); + nbt.putInt( "term_cursorX", m_cursorX ); + nbt.putInt( "term_cursorY", m_cursorY ); + nbt.putBoolean( "term_cursorBlink", m_cursorBlink ); + nbt.putInt( "term_textColour", m_cursorColour ); + nbt.putInt( "term_bgColour", m_cursorBackgroundColour ); for( int n = 0; n < m_height; n++ ) { - nbt.setString( "term_text_" + n, m_text[n].toString() ); - nbt.setString( "term_textColour_" + n, m_textColour[n].toString() ); - nbt.setString( "term_textBgColour_" + n, m_backgroundColour[n].toString() ); + nbt.putString( "term_text_" + n, m_text[n].toString() ); + nbt.putString( "term_textColour_" + n, m_textColour[n].toString() ); + nbt.putString( "term_textBgColour_" + n, m_backgroundColour[n].toString() ); } if( m_palette != null ) { @@ -356,26 +356,26 @@ public synchronized NBTTagCompound writeToNBT( NBTTagCompound nbt ) public synchronized void readFromNBT( NBTTagCompound nbt ) { - m_cursorX = nbt.getInteger( "term_cursorX" ); - m_cursorY = nbt.getInteger( "term_cursorY" ); + m_cursorX = nbt.getInt( "term_cursorX" ); + m_cursorY = nbt.getInt( "term_cursorY" ); m_cursorBlink = nbt.getBoolean( "term_cursorBlink" ); - m_cursorColour = nbt.getInteger( "term_textColour" ); - m_cursorBackgroundColour = nbt.getInteger( "term_bgColour" ); + m_cursorColour = nbt.getInt( "term_textColour" ); + m_cursorBackgroundColour = nbt.getInt( "term_bgColour" ); for( int n = 0; n < m_height; n++ ) { m_text[n].fill( ' ' ); - if( nbt.hasKey( "term_text_" + n ) ) + if( nbt.contains( "term_text_" + n ) ) { m_text[n].write( nbt.getString( "term_text_" + n ) ); } m_textColour[n].fill( base16.charAt( m_cursorColour ) ); - if( nbt.hasKey( "term_textColour_" + n ) ) + if( nbt.contains( "term_textColour_" + n ) ) { m_textColour[n].write( nbt.getString( "term_textColour_" + n ) ); } m_backgroundColour[n].fill( base16.charAt( m_cursorBackgroundColour ) ); - if( nbt.hasKey( "term_textBgColour_" + n ) ) + if( nbt.contains( "term_textBgColour_" + n ) ) { m_backgroundColour[n].write( nbt.getString( "term_textBgColour_" + n ) ); } diff --git a/src/main/java/dan200/computercraft/core/tracking/Tracker.java b/src/main/java/dan200/computercraft/core/tracking/Tracker.java index f0eb0144b..3d9957235 100644 --- a/src/main/java/dan200/computercraft/core/tracking/Tracker.java +++ b/src/main/java/dan200/computercraft/core/tracking/Tracker.java @@ -10,11 +10,6 @@ public interface Tracker { - @Deprecated - default void addTiming( Computer computer, long time ) - { - } - /** * Report how long a task executed on the computer thread took. * @@ -25,8 +20,6 @@ default void addTiming( Computer computer, long time ) */ default void addTaskTiming( Computer computer, long time ) { - //noinspection deprecation - addTiming( computer, time ); } /** diff --git a/src/main/java/dan200/computercraft/core/tracking/TrackingField.java b/src/main/java/dan200/computercraft/core/tracking/TrackingField.java index 9618dd171..9b4fec82a 100644 --- a/src/main/java/dan200/computercraft/core/tracking/TrackingField.java +++ b/src/main/java/dan200/computercraft/core/tracking/TrackingField.java @@ -6,8 +6,6 @@ package dan200.computercraft.core.tracking; -import dan200.computercraft.shared.util.StringUtil; - import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -15,31 +13,29 @@ public final class TrackingField { - public static final String TRANSLATE_PREFIX = "tracking_field.computercraft."; - private static final Map fields = new HashMap<>(); - public static final TrackingField TASKS = TrackingField.of( "tasks", "Tasks", x -> String.format( "%4d", x ) ); - public static final TrackingField TOTAL_TIME = TrackingField.of( "total", "Total time", x -> String.format( "%7.1fms", x / 1e6 ) ); - public static final TrackingField AVERAGE_TIME = TrackingField.of( "average", "Average time", x -> String.format( "%4.1fms", x / 1e6 ) ); - public static final TrackingField MAX_TIME = TrackingField.of( "max", "Max time", x -> String.format( "%5.1fms", x / 1e6 ) ); + public static final TrackingField TASKS = TrackingField.of( "tasks", x -> String.format( "%4d", x ) ); + public static final TrackingField TOTAL_TIME = TrackingField.of( "total", x -> String.format( "%7.1fms", x / 1e6 ) ); + public static final TrackingField AVERAGE_TIME = TrackingField.of( "average", x -> String.format( "%4.1fms", x / 1e6 ) ); + public static final TrackingField MAX_TIME = TrackingField.of( "max", x -> String.format( "%5.1fms", x / 1e6 ) ); - public static final TrackingField SERVER_COUNT = TrackingField.of( "server_count", "Server task count", x -> String.format( "%4d", x ) ); - public static final TrackingField SERVER_TIME = TrackingField.of( "server_time", "Server task time", x -> String.format( "%7.1fms", x / 1e6 ) ); + public static final TrackingField SERVER_COUNT = TrackingField.of( "server_count", x -> String.format( "%4d", x ) ); + public static final TrackingField SERVER_TIME = TrackingField.of( "server_time", x -> String.format( "%7.1fms", x / 1e6 ) ); - public static final TrackingField PERIPHERAL_OPS = TrackingField.of( "peripheral", "Peripheral calls", TrackingField::formatDefault ); - public static final TrackingField FS_OPS = TrackingField.of( "fs", "Filesystem operations", TrackingField::formatDefault ); - public static final TrackingField TURTLE_OPS = TrackingField.of( "turtle", "Turtle operations", TrackingField::formatDefault ); + public static final TrackingField PERIPHERAL_OPS = TrackingField.of( "peripheral", TrackingField::formatDefault ); + public static final TrackingField FS_OPS = TrackingField.of( "fs", TrackingField::formatDefault ); + public static final TrackingField TURTLE_OPS = TrackingField.of( "turtle", TrackingField::formatDefault ); - public static final TrackingField HTTP_REQUESTS = TrackingField.of( "http", "HTTP requests", TrackingField::formatDefault ); - public static final TrackingField HTTP_UPLOAD = TrackingField.of( "http_upload", "HTTP upload", TrackingField::formatBytes ); - public static final TrackingField HTTP_DOWNLOAD = TrackingField.of( "http_download", "HTTP download", TrackingField::formatBytes ); + public static final TrackingField HTTP_REQUESTS = TrackingField.of( "http", TrackingField::formatDefault ); + public static final TrackingField HTTP_UPLOAD = TrackingField.of( "http_upload", TrackingField::formatBytes ); + public static final TrackingField HTTP_DOWNLOAD = TrackingField.of( "http_download", TrackingField::formatBytes ); - public static final TrackingField WEBSOCKET_INCOMING = TrackingField.of( "websocket_incoming", "Websocket incoming", TrackingField::formatBytes ); - public static final TrackingField WEBSOCKET_OUTGOING = TrackingField.of( "websocket_outgoing", "Websocket outgoing", TrackingField::formatBytes ); + public static final TrackingField WEBSOCKET_INCOMING = TrackingField.of( "websocket_incoming", TrackingField::formatBytes ); + public static final TrackingField WEBSOCKET_OUTGOING = TrackingField.of( "websocket_outgoing", TrackingField::formatBytes ); - public static final TrackingField COROUTINES_CREATED = TrackingField.of( "coroutines_created", "Coroutines created", x -> String.format( "%4d", x ) ); - public static final TrackingField COROUTINES_DISPOSED = TrackingField.of( "coroutines_dead", "Coroutines disposed", x -> String.format( "%4d", x ) ); + public static final TrackingField COROUTINES_CREATED = TrackingField.of( "coroutines_created", x -> String.format( "%4d", x ) ); + public static final TrackingField COROUTINES_DISPOSED = TrackingField.of( "coroutines_dead", x -> String.format( "%4d", x ) ); private final String id; private final String translationKey; @@ -55,12 +51,6 @@ public String translationKey() return translationKey; } - @Deprecated - public String displayName() - { - return StringUtil.translate( translationKey() ); - } - private TrackingField( String id, LongFunction format ) { this.id = id; @@ -73,7 +63,7 @@ public String format( long value ) return format.apply( value ); } - public static TrackingField of( String id, String displayName, LongFunction format ) + public static TrackingField of( String id, LongFunction format ) { TrackingField field = new TrackingField( id, format ); fields.put( id, field ); diff --git a/src/main/java/dan200/computercraft/shared/BundledRedstone.java b/src/main/java/dan200/computercraft/shared/BundledRedstone.java index 1cf8dbdeb..78ee64eac 100644 --- a/src/main/java/dan200/computercraft/shared/BundledRedstone.java +++ b/src/main/java/dan200/computercraft/shared/BundledRedstone.java @@ -24,7 +24,7 @@ public final class BundledRedstone private BundledRedstone() {} - public static void register( @Nonnull IBundledRedstoneProvider provider ) + public static synchronized void register( @Nonnull IBundledRedstoneProvider provider ) { Preconditions.checkNotNull( provider, "provider cannot be null" ); providers.add( provider ); @@ -32,12 +32,12 @@ public static void register( @Nonnull IBundledRedstoneProvider provider ) public static int getDefaultOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ) { - return world.isValid( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1; + return World.isValid( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1; } private static int getUnmaskedOutput( World world, BlockPos pos, EnumFacing side ) { - if( !world.isValid( pos ) ) return -1; + if( !World.isValid( pos ) ) return -1; // Try the providers in order: int combinedSignal = -1; diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index e1051a55e..5d3b60f6c 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -12,496 +12,333 @@ import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.core.apis.AddressPredicate; import dan200.computercraft.core.apis.http.websocket.Websocket; -import net.minecraftforge.common.config.ConfigCategory; -import net.minecraftforge.common.config.ConfigElement; -import net.minecraftforge.common.config.Configuration; -import net.minecraftforge.common.config.Property; -import net.minecraftforge.fml.client.config.IConfigElement; +import net.minecraftforge.common.ForgeConfigSpec; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.config.ModConfig; -import java.io.File; -import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; -import java.util.Map; -import java.util.Set; import java.util.concurrent.TimeUnit; import static dan200.computercraft.ComputerCraft.DEFAULT_HTTP_BLACKLIST; import static dan200.computercraft.ComputerCraft.DEFAULT_HTTP_WHITELIST; +import static net.minecraftforge.common.ForgeConfigSpec.Builder; +import static net.minecraftforge.common.ForgeConfigSpec.ConfigValue; +@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD ) public final class Config { private static final int MODEM_MAX_RANGE = 100000; - private static final String CATEGORY_GENERAL = "general"; - private static final String CATEGORY_EXECUTION = "execution"; - private static final String CATEGORY_HTTP = "http"; - private static final String CATEGORY_PERIPHERAL = "peripheral"; - private static final String CATEGORY_TURTLE = "turtle"; + private static final String TRANSLATION_PREFIX = "gui.computercraft.config."; - private static Configuration config; + private static ConfigValue computerSpaceLimit; + private static ConfigValue floppySpaceLimit; + private static ConfigValue maximumFilesOpen; + private static ConfigValue disableLua51Features; + private static ConfigValue defaultComputerSettings; + private static ConfigValue debugEnabled; + private static ConfigValue logComputerErrors; - private static Property computerSpaceLimit; - private static Property floppySpaceLimit; - private static Property maximumFilesOpen; - private static Property disableLua51Features; - private static Property defaultComputerSettings; - private static Property debugEnabled; - private static Property logComputerErrors; + private static ConfigValue computerThreads; + private static ConfigValue maxMainGlobalTime; + private static ConfigValue maxMainComputerTime; - private static Property computerThreads; - private static Property maxMainGlobalTime; - private static Property maxMainComputerTime; + private static ConfigValue httpEnabled; + private static ConfigValue httpWebsocketEnabled; + private static ConfigValue> httpWhitelist; + private static ConfigValue> httpBlacklist; - private static Property httpEnable; - private static Property httpWebsocketEnable; - private static Property httpWhitelist; - private static Property httpBlacklist; + private static ConfigValue httpTimeout; + private static ConfigValue httpMaxRequests; + private static ConfigValue httpMaxDownload; + private static ConfigValue httpMaxUpload; + private static ConfigValue httpMaxWebsockets; + private static ConfigValue httpMaxWebsocketMessage; - private static Property httpTimeout; - private static Property httpMaxRequests; - private static Property httpMaxDownload; - private static Property httpMaxUpload; - private static Property httpMaxWebsockets; - private static Property httpMaxWebsocketMessage; + private static ConfigValue commandBlockEnabled; + private static ConfigValue modemRange; + private static ConfigValue modemHighAltitudeRange; + private static ConfigValue modemRangeDuringStorm; + private static ConfigValue modemHighAltitudeRangeDuringStorm; + private static ConfigValue maxNotesPerTick; - private static Property commandBlockEnabled; - private static Property modemRange; - private static Property modemHighAltitudeRange; - private static Property modemRangeDuringStorm; - private static Property modemHighAltitudeRangeDuringStorm; - private static Property maxNotesPerTick; + private static ConfigValue turtlesNeedFuel; + private static ConfigValue turtleFuelLimit; + private static ConfigValue advancedTurtleFuelLimit; + private static ConfigValue turtlesObeyBlockProtection; + private static ConfigValue turtlesCanPush; + private static ConfigValue> turtleDisabledActions; - private static Property turtlesNeedFuel; - private static Property turtleFuelLimit; - private static Property advancedTurtleFuelLimit; - private static Property turtlesObeyBlockProtection; - private static Property turtlesCanPush; - private static Property turtleDisabledActions; + private static final ForgeConfigSpec spec; private Config() {} - public static void load( File configFile ) + static { - config = new Configuration( configFile, ComputerCraft.getVersion() ); - - config.load(); + Builder builder = new Builder(); { // General computers - renameProperty( CATEGORY_GENERAL, "computerSpaceLimit", CATEGORY_GENERAL, "computer_space_limit" ); - renameProperty( CATEGORY_GENERAL, "floppySpaceLimit", CATEGORY_GENERAL, "floppy_space_limit" ); - renameProperty( CATEGORY_GENERAL, "maximumFilesOpen", CATEGORY_GENERAL, "maximum_open_files" ); - renameProperty( CATEGORY_GENERAL, "debug_enable", CATEGORY_GENERAL, "debug_enabled" ); - renameProperty( CATEGORY_GENERAL, "logPeripheralErrors", CATEGORY_GENERAL, "log_computer_errors" ); + computerSpaceLimit = builder + .comment( "The disk space limit for computers and turtles, in bytes" ) + .translation( TRANSLATION_PREFIX + "computer_space_limit" ) + .define( "computer_space_limit", ComputerCraft.computerSpaceLimit ); - computerSpaceLimit = config.get( CATEGORY_GENERAL, "computer_space_limit", ComputerCraft.computerSpaceLimit ); - computerSpaceLimit.setComment( "The disk space limit for computers and turtles, in bytes" ); + floppySpaceLimit = builder + .comment( "The disk space limit for floppy disks, in bytes" ) + .translation( TRANSLATION_PREFIX + "floppy_space_limit" ) + .define( "floppy_space_limit", ComputerCraft.floppySpaceLimit ); - floppySpaceLimit = config.get( CATEGORY_GENERAL, "floppy_space_limit", ComputerCraft.floppySpaceLimit ); - floppySpaceLimit.setComment( "The disk space limit for floppy disks, in bytes" ); + maximumFilesOpen = builder + .comment( "Set how many files a computer can have open at the same time. Set to 0 for unlimited." ) + .translation( TRANSLATION_PREFIX + "maximum_open_files" ) + .defineInRange( "maximum_open_files", ComputerCraft.maximumFilesOpen, 0, Integer.MAX_VALUE ); - maximumFilesOpen = config.get( CATEGORY_GENERAL, "maximum_open_files", ComputerCraft.maximumFilesOpen ); - maximumFilesOpen.setComment( "Set how many files a computer can have open at the same time. Set to 0 for unlimited." ); - maximumFilesOpen.setMinValue( 0 ); + disableLua51Features = builder + .comment( "Set this to true to disable Lua 5.1 functions that will be removed in a future update. " + + "Useful for ensuring forward compatibility of your programs now." ) + .define( "disable_lua51_features", ComputerCraft.disable_lua51_features ); - disableLua51Features = config.get( CATEGORY_GENERAL, "disable_lua51_features", ComputerCraft.disable_lua51_features ); - disableLua51Features.setComment( "Set this to true to disable Lua 5.1 functions that will be removed in a future " + - "update. Useful for ensuring forward compatibility of your programs now." ); + defaultComputerSettings = builder + .comment( "A comma separated list of default system settings to set on new computers. Example: " + + "\"shell.autocomplete=false,lua.autocomplete=false,edit.autocomplete=false\" will disable all " + + "autocompletion" ) + .define( "default_computer_settings", ComputerCraft.default_computer_settings ); - defaultComputerSettings = config.get( CATEGORY_GENERAL, "default_computer_settings", ComputerCraft.default_computer_settings ); - defaultComputerSettings.setComment( "A comma separated list of default system settings to set on new computers. Example: " + - "\"shell.autocomplete=false,lua.autocomplete=false,edit.autocomplete=false\" will disable all autocompletion" ); + debugEnabled = builder + .comment( "Enable Lua's debug library. This is sandboxed to each computer, so is generally safe to be used by players." ) + .define( "debug_enabled", ComputerCraft.debug_enable ); - debugEnabled = config.get( CATEGORY_GENERAL, "debug_enabled", ComputerCraft.debug_enable ); - debugEnabled.setComment( "Enable Lua's debug library. This is sandboxed to each computer, so is generally safe to be used by players." ); - - logComputerErrors = config.get( CATEGORY_GENERAL, "log_computer_errors", ComputerCraft.logPeripheralErrors ); - logComputerErrors.setComment( "Log exceptions thrown by peripherals and other Lua objects.\n" + - "This makes it easier for mod authors to debug problems, but may result in log spam should people use buggy methods." ); - - setOrder( - CATEGORY_GENERAL, - computerSpaceLimit, floppySpaceLimit, maximumFilesOpen, - disableLua51Features, defaultComputerSettings, debugEnabled, logComputerErrors - ); + logComputerErrors = builder + .comment( "Log exceptions thrown by peripherals and other Lua objects.\n" + + "This makes it easier for mod authors to debug problems, but may result in log spam should people use buggy methods." ) + .define( "log_computer_errors", ComputerCraft.logPeripheralErrors ); } - { // Execution - renameProperty( CATEGORY_GENERAL, "computer_threads", CATEGORY_EXECUTION, "computer_threads" ); + { + builder.comment( "Controls execution behaviour of computers. This is largely intended for fine-tuning " + + "servers, and generally shouldn't need to be touched" ); + builder.push( "execution" ); - config.getCategory( CATEGORY_EXECUTION ) - .setComment( "Controls execution behaviour of computers. This is largely intended for fine-tuning " + - "servers, and generally shouldn't need to be touched" ); + computerThreads = builder + .comment( "Set the number of threads computers can run on. A higher number means more computers can run " + + "at once, but may induce lag.\n" + + "Please note that some mods may not work with a thread count higher than 1. Use with caution." ) + .worldRestart() + .defineInRange( "computer_threads", ComputerCraft.computer_threads, 1, Integer.MAX_VALUE ); - computerThreads = config.get( CATEGORY_EXECUTION, "computer_threads", ComputerCraft.computer_threads ); - computerThreads - .setMinValue( 1 ) - .setRequiresMcRestart( true ) - .setComment( "Set the number of threads computers can run on. A higher number means more computers can " + - "run at once, but may induce lag.\n" + - "Please note that some mods may not work with a thread count higher than 1. Use with caution." ); + maxMainGlobalTime = builder + .comment( "The maximum time that can be spent executing tasks in a single tick, in milliseconds.\n" + + "Note, we will quite possibly go over this limit, as there's no way to tell how long a will take " + + "- this aims to be the upper bound of the average time." ) + .defineInRange( "max_main_global_time", TimeUnit.NANOSECONDS.toMillis( ComputerCraft.maxMainGlobalTime ), 1, Long.MAX_VALUE ); - maxMainGlobalTime = config.get( CATEGORY_EXECUTION, "max_main_global_time", (int) TimeUnit.NANOSECONDS.toMillis( ComputerCraft.maxMainGlobalTime ) ); - maxMainGlobalTime - .setMinValue( 1 ) - .setComment( "The maximum time that can be spent executing tasks in a single tick, in milliseconds.\n" + - "Note, we will quite possibly go over this limit, as there's no way to tell how long a will take - this aims " + - "to be the upper bound of the average time." ); + maxMainComputerTime = builder + .comment( "The ideal maximum time a computer can execute for in a tick, in milliseconds.\n" + + "Note, we will quite possibly go over this limit, as there's no way to tell how long a will take " + + "- this aims to be the upper bound of the average time." ) + .defineInRange( "max_main_computer_time", TimeUnit.NANOSECONDS.toMillis( ComputerCraft.maxMainComputerTime ), 1, Long.MAX_VALUE ); - maxMainComputerTime = config.get( CATEGORY_EXECUTION, "max_main_computer_time", (int) TimeUnit.NANOSECONDS.toMillis( ComputerCraft.maxMainComputerTime ) ); - maxMainComputerTime - .setMinValue( 1 ) - .setComment( "The ideal maximum time a computer can execute for in a tick, in milliseconds.\n" + - "Note, we will quite possibly go over this limit, as there's no way to tell how long a will take - this aims " + - "to be the upper bound of the average time." ); - - setOrder( - CATEGORY_EXECUTION, - computerThreads, maxMainGlobalTime, maxMainComputerTime - ); + builder.pop(); } { // HTTP - renameProperty( CATEGORY_GENERAL, "http_enable", CATEGORY_HTTP, "enabled" ); - renameProperty( CATEGORY_GENERAL, "http_websocket_enable", CATEGORY_HTTP, "websocket_enabled" ); - renameProperty( CATEGORY_GENERAL, "http_whitelist", CATEGORY_HTTP, "whitelist" ); - renameProperty( CATEGORY_GENERAL, "http_blacklist", CATEGORY_HTTP, "blacklist" ); + builder.comment( "Controls the HTTP API" ); + builder.push( "http" ); - config.getCategory( CATEGORY_HTTP ) - .setComment( "Controls the HTTP API" ); + httpEnabled = builder + .comment( "Enable the \"http\" API on Computers (see \"http_whitelist\" and \"http_blacklist\" for more " + + "fine grained control than this)" ) + .define( "enabled", ComputerCraft.http_enable ); - httpEnable = config.get( CATEGORY_HTTP, "enabled", ComputerCraft.http_enable ); - httpEnable.setComment( "Enable the \"http\" API on Computers (see \"http_whitelist\" and \"http_blacklist\" for " + - "more fine grained control than this)" ); + httpWebsocketEnabled = builder + .comment( "Enable use of http websockets. This requires the \"http_enable\" option to also be true." ) + .define( "websocket_enabled", ComputerCraft.http_websocket_enable ); - httpWebsocketEnable = config.get( CATEGORY_HTTP, "websocket_enabled", ComputerCraft.http_websocket_enable ); - httpWebsocketEnable.setComment( "Enable use of http websockets. This requires the \"http_enable\" option to also be true." ); + httpWhitelist = builder + .comment( "A list of wildcards for domains or IP ranges that can be accessed through the \"http\" API on Computers.\n" + + "Set this to \"*\" to access to the entire internet. Example: \"*.pastebin.com\" will restrict access to just subdomains of pastebin.com.\n" + + "You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ) + .defineList( "whitelist", Arrays.asList( DEFAULT_HTTP_WHITELIST ), x -> true ); - httpWhitelist = config.get( CATEGORY_HTTP, "whitelist", DEFAULT_HTTP_WHITELIST ); - httpWhitelist.setComment( "A list of wildcards for domains or IP ranges that can be accessed through the " + - "\"http\" API on Computers.\n" + - "Set this to \"*\" to access to the entire internet. Example: \"*.pastebin.com\" will restrict access to " + - "just subdomains of pastebin.com.\n" + - "You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ); + httpBlacklist = builder + .comment( "A list of wildcards for domains or IP ranges that cannot be accessed through the \"http\" API on Computers.\n" + + "If this is empty then all whitelisted domains will be accessible. Example: \"*.github.com\" will block access to all subdomains of github.com.\n" + + "You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ) + .defineList( "blacklist", Arrays.asList( DEFAULT_HTTP_BLACKLIST ), x -> true ); - httpBlacklist = config.get( CATEGORY_HTTP, "blacklist", DEFAULT_HTTP_BLACKLIST ); - httpBlacklist.setComment( "A list of wildcards for domains or IP ranges that cannot be accessed through the " + - "\"http\" API on Computers.\n" + - "If this is empty then all whitelisted domains will be accessible. Example: \"*.github.com\" will block " + - "access to all subdomains of github.com.\n" + - "You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ); + httpTimeout = builder + .comment( "The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." ) + .defineInRange( "timeout", ComputerCraft.httpTimeout, 0, Integer.MAX_VALUE ); - httpTimeout = config.get( CATEGORY_HTTP, "timeout", ComputerCraft.httpTimeout ); - httpTimeout.setComment( "The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." ); - httpTimeout.setMinValue( 0 ); + httpMaxRequests = builder + .comment( "The number of http requests a computer can make at one time. Additional requests will be queued, and sent when the running requests have finished. Set to 0 for unlimited." ) + .defineInRange( "max_requests", ComputerCraft.httpMaxRequests, 0, Integer.MAX_VALUE ); - httpMaxRequests = config.get( CATEGORY_HTTP, "max_requests", ComputerCraft.httpMaxRequests ); - httpMaxRequests.setComment( "The number of http requests a computer can make at one time. Additional requests " + - "will be queued, and sent when the running requests have finished. Set to 0 for unlimited." ); - httpMaxRequests.setMinValue( 0 ); + httpMaxDownload = builder + .comment( "The maximum size (in bytes) that a computer can download in a single request. Note that responses may receive more data than allowed, but this data will not be returned to the client." ) + .defineInRange( "max_download", ComputerCraft.httpMaxDownload, 0, Long.MAX_VALUE ); - httpMaxDownload = config.get( CATEGORY_HTTP, "max_download", (int) ComputerCraft.httpMaxDownload ); - httpMaxDownload.setComment( "The maximum size (in bytes) that a computer can download in a single request. " + - "Note that responses may receive more data than allowed, but this data will not be returned to the client." ); - httpMaxDownload.setMinValue( 0 ); + httpMaxUpload = builder + .comment( "The maximum size (in bytes) that a computer can upload in a single request. This includes headers and POST text." ) + .defineInRange( "max_upload", ComputerCraft.httpMaxUpload, 0, Long.MAX_VALUE ); - httpMaxUpload = config.get( CATEGORY_HTTP, "max_upload", (int) ComputerCraft.httpMaxUpload ); - httpMaxUpload.setComment( "The maximum size (in bytes) that a computer can upload in a single request. This " + - "includes headers and POST text." ); - httpMaxUpload.setMinValue( 0 ); + httpMaxWebsockets = builder + .comment( "The number of websockets a computer can have open at one time. Set to 0 for unlimited." ) + .defineInRange( "max_websockets", ComputerCraft.httpMaxWebsockets, 1, Integer.MAX_VALUE ); - httpMaxWebsockets = config.get( CATEGORY_HTTP, "max_websockets", ComputerCraft.httpMaxWebsockets ); - httpMaxWebsockets.setComment( "The number of websockets a computer can have open at one time. Set to 0 for unlimited." ); - httpMaxWebsockets.setMinValue( 1 ); + httpMaxWebsocketMessage = builder + .comment( "The maximum size (in bytes) that a computer can send or receive in one websocket packet." ) + .defineInRange( "max_websocket_message", ComputerCraft.httpMaxWebsocketMessage, 0, Websocket.MAX_MESSAGE_SIZE ); - httpMaxWebsocketMessage = config.get( CATEGORY_HTTP, "max_websocket_message", ComputerCraft.httpMaxWebsocketMessage ); - httpMaxWebsocketMessage.setComment( "The maximum size (in bytes) that a computer can send or receive in one websocket packet." ); - httpMaxWebsocketMessage.setMinValue( 0 ); - httpMaxWebsocketMessage.setMaxValue( Websocket.MAX_MESSAGE_SIZE ); - - setOrder( - CATEGORY_HTTP, - httpEnable, httpWebsocketEnable, httpWhitelist, httpBlacklist, - httpTimeout, httpMaxRequests, httpMaxDownload, httpMaxUpload, httpMaxWebsockets, httpMaxWebsocketMessage - ); + builder.pop(); } { // Peripherals - renameProperty( CATEGORY_GENERAL, "enableCommandBlock", CATEGORY_PERIPHERAL, "command_block_enabled" ); - renameProperty( CATEGORY_GENERAL, "modem_range", CATEGORY_PERIPHERAL, "modem_range" ); - renameProperty( CATEGORY_GENERAL, "modem_highAltitudeRange", CATEGORY_PERIPHERAL, "modem_high_altitude_range" ); - renameProperty( CATEGORY_GENERAL, "modem_rangeDuringStorm", CATEGORY_PERIPHERAL, "modem_range_during_storm" ); - renameProperty( CATEGORY_GENERAL, "modem_highAltitudeRangeDuringStorm", CATEGORY_PERIPHERAL, "modem_high_altitude_range_during_storm" ); - renameProperty( CATEGORY_GENERAL, "maxNotesPerTick", CATEGORY_PERIPHERAL, "max_notes_per_tick" ); + builder.comment( "Various options relating to peripherals." ); + builder.push( "peripheral" ); - config.getCategory( CATEGORY_PERIPHERAL ) - .setComment( "Various options relating to peripherals." ); + commandBlockEnabled = builder + .comment( "Enable Command Block peripheral support" ) + .define( "command_block_enabled", ComputerCraft.enableCommandBlock ); - commandBlockEnabled = config.get( CATEGORY_PERIPHERAL, "command_block_enabled", ComputerCraft.enableCommandBlock ); - commandBlockEnabled.setComment( "Enable Command Block peripheral support" ); + modemRange = builder + .comment( "The range of Wireless Modems at low altitude in clear weather, in meters" ) + .defineInRange( "modem_range", ComputerCraft.modem_range, 0, MODEM_MAX_RANGE ); - modemRange = config.get( CATEGORY_PERIPHERAL, "modem_range", ComputerCraft.modem_range ); - modemRange.setComment( "The range of Wireless Modems at low altitude in clear weather, in meters" ); - modemRange.setMinValue( 0 ); - modemRange.setMaxValue( MODEM_MAX_RANGE ); + modemHighAltitudeRange = builder + .comment( "The range of Wireless Modems at maximum altitude in clear weather, in meters" ) + .defineInRange( "modem_high_altitude_range", ComputerCraft.modem_highAltitudeRange, 0, MODEM_MAX_RANGE ); - modemHighAltitudeRange = config.get( CATEGORY_PERIPHERAL, "modem_high_altitude_range", ComputerCraft.modem_highAltitudeRange ); - modemHighAltitudeRange.setComment( "The range of Wireless Modems at maximum altitude in clear weather, in meters" ); - modemHighAltitudeRange.setMinValue( 0 ); - modemHighAltitudeRange.setMaxValue( MODEM_MAX_RANGE ); + modemRangeDuringStorm = builder + .comment( "The range of Wireless Modems at low altitude in stormy weather, in meters" ) + .defineInRange( "modem_range_during_storm", ComputerCraft.modem_rangeDuringStorm, 0, MODEM_MAX_RANGE ); - modemRangeDuringStorm = config.get( CATEGORY_PERIPHERAL, "modem_range_during_storm", ComputerCraft.modem_rangeDuringStorm ); - modemRangeDuringStorm.setComment( "The range of Wireless Modems at low altitude in stormy weather, in meters" ); - modemRangeDuringStorm.setMinValue( 0 ); - modemRangeDuringStorm.setMaxValue( MODEM_MAX_RANGE ); + modemHighAltitudeRangeDuringStorm = builder + .comment( "The range of Wireless Modems at maximum altitude in stormy weather, in meters" ) + .defineInRange( "modem_high_altitude_range_during_storm", ComputerCraft.modem_highAltitudeRangeDuringStorm, 0, MODEM_MAX_RANGE ); - modemHighAltitudeRangeDuringStorm = config.get( CATEGORY_PERIPHERAL, "modem_high_altitude_range_during_storm", ComputerCraft.modem_highAltitudeRangeDuringStorm ); - modemHighAltitudeRangeDuringStorm.setComment( "The range of Wireless Modems at maximum altitude in stormy weather, in meters" ); - modemHighAltitudeRangeDuringStorm.setMinValue( 0 ); - modemHighAltitudeRangeDuringStorm.setMaxValue( MODEM_MAX_RANGE ); + maxNotesPerTick = builder + .comment( "Maximum amount of notes a speaker can play at once" ) + .defineInRange( "max_notes_per_tick", ComputerCraft.maxNotesPerTick, 1, Integer.MAX_VALUE ); - maxNotesPerTick = config.get( CATEGORY_PERIPHERAL, "max_notes_per_tick", ComputerCraft.maxNotesPerTick ); - maxNotesPerTick.setComment( "Maximum amount of notes a speaker can play at once" ); - maxNotesPerTick.setMinValue( 1 ); - - setOrder( - CATEGORY_PERIPHERAL, - commandBlockEnabled, modemRange, modemHighAltitudeRange, modemRangeDuringStorm, modemHighAltitudeRangeDuringStorm, maxNotesPerTick - ); + builder.pop(); } { // Turtles - renameProperty( CATEGORY_GENERAL, "turtlesNeedFuel", CATEGORY_TURTLE, "need_fuel" ); - renameProperty( CATEGORY_GENERAL, "turtleFuelLimit", CATEGORY_TURTLE, "normal_fuel_limit" ); - renameProperty( CATEGORY_GENERAL, "advancedTurtleFuelLimit", CATEGORY_TURTLE, "advanced_fuel_limit" ); - renameProperty( CATEGORY_GENERAL, "turtlesObeyBlockProtection", CATEGORY_TURTLE, "obey_block_protection" ); - renameProperty( CATEGORY_GENERAL, "turtlesCanPush", CATEGORY_TURTLE, "can_push" ); - renameProperty( CATEGORY_GENERAL, "turtle_disabled_actions", CATEGORY_TURTLE, "disabled_actions" ); + builder.comment( "Various options relating to turtles." ); + builder.push( "turtle" ); - config.getCategory( CATEGORY_HTTP ) - .setComment( "Various options relating to turtles." ); + turtlesNeedFuel = builder + .comment( "Set whether Turtles require fuel to move" ) + .define( "need_fuel", ComputerCraft.turtlesNeedFuel ); - turtlesNeedFuel = config.get( CATEGORY_TURTLE, "need_fuel", ComputerCraft.turtlesNeedFuel ); - turtlesNeedFuel.setComment( "Set whether Turtles require fuel to move" ); + turtleFuelLimit = builder + .comment( "The fuel limit for Turtles" ) + .defineInRange( "normal_fuel_limit", ComputerCraft.turtleFuelLimit, 0, Integer.MAX_VALUE ); - turtleFuelLimit = config.get( CATEGORY_TURTLE, "normal_fuel_limit", ComputerCraft.turtleFuelLimit ); - turtleFuelLimit.setComment( "The fuel limit for Turtles" ); - turtleFuelLimit.setMinValue( 0 ); + advancedTurtleFuelLimit = builder + .comment( "The fuel limit for Advanced Turtles" ) + .defineInRange( "advanced_fuel_limit", ComputerCraft.advancedTurtleFuelLimit, 0, Integer.MAX_VALUE ); - advancedTurtleFuelLimit = config.get( CATEGORY_TURTLE, "advanced_fuel_limit", ComputerCraft.advancedTurtleFuelLimit ); - advancedTurtleFuelLimit.setComment( "The fuel limit for Advanced Turtles" ); - advancedTurtleFuelLimit.setMinValue( 0 ); + turtlesObeyBlockProtection = builder + .comment( "If set to true, Turtles will be unable to build, dig, or enter protected areas (such as near the server spawn point)" ) + .define( "obey_block_protection", ComputerCraft.turtlesObeyBlockProtection ); - turtlesObeyBlockProtection = config.get( CATEGORY_TURTLE, "obey_block_protection", ComputerCraft.turtlesObeyBlockProtection ); - turtlesObeyBlockProtection.setComment( "If set to true, Turtles will be unable to build, dig, or enter protected " + - "areas (such as near the server spawn point)" ); + turtlesCanPush = builder + .comment( "If set to true, Turtles will push entities out of the way instead of stopping if there is space to do so" ) + .define( "can_push", ComputerCraft.turtlesCanPush ); - turtlesCanPush = config.get( CATEGORY_TURTLE, "can_push", ComputerCraft.turtlesCanPush ); - turtlesCanPush.setComment( "If set to true, Turtles will push entities out of the way instead of stopping if " + - "there is space to do so" ); + turtleDisabledActions = builder + .comment( "A list of turtle actions which are disabled." ) + .defineList( "disabled_actions", Collections.emptyList(), x -> x instanceof String && getAction( (String) x ) != null ); - turtleDisabledActions = config.get( CATEGORY_TURTLE, "disabled_actions", new String[0] ); - turtleDisabledActions.setComment( "A list of turtle actions which are disabled." ); - - setOrder( - CATEGORY_TURTLE, - turtlesNeedFuel, turtleFuelLimit, advancedTurtleFuelLimit, turtlesObeyBlockProtection, turtlesCanPush, turtleDisabledActions - ); + builder.pop(); } - for( String child : config.getCategoryNames() ) - { - setupLanguage( - config.getCategory( child ), - child.equals( CATEGORY_GENERAL ) ? "gui.computercraft:config" : "gui.computercraft:config." + child - ); - } - - sync(); + spec = builder.build(); } - private static void setOrder( String category, Property... properties ) + public static void load() { - List names = new ArrayList<>( properties.length ); - for( Property property : properties ) names.add( property.getName() ); - config.getCategory( category ).setPropertyOrder( names ); - } - - private static void renameProperty( String oldCat, String oldProp, String newCat, String newProp ) - { - if( !config.hasCategory( oldCat ) ) return; - - ConfigCategory cat = config.getCategory( oldCat ); - if( !cat.containsKey( oldProp ) ) return; - - Property prop = cat.remove( oldProp ); - prop.setName( newProp ); - config.getCategory( newCat ).put( newProp, prop ); - - // Clean up old categories - if( cat.isEmpty() ) config.removeCategory( cat ); - } - - private static void setupLanguage( ConfigCategory category, String key ) - { - category.setLanguageKey( key ); - for( Property property : category.getOrderedValues() ) - { - property.setLanguageKey( key + "." + property.getName() ); - } - - for( ConfigCategory child : category.getChildren() ) - { - setupLanguage( child, key + "." + child.getName() ); - } - } - - public static void reload() - { - Configuration newConfig = new Configuration( config.getConfigFile(), ComputerCraft.getVersion() ); - Set oldCategories = config.getCategoryNames(), newCategories = newConfig.getCategoryNames(); - - // Sync any categories on the original config - for( String category : oldCategories ) - { - if( newCategories.contains( category ) ) - { - reloadCategory( config.getCategory( category ), newConfig.getCategory( category ) ); - } - else - { - for( Property property : config.getCategory( category ).getValues().values() ) property.setToDefault(); - } - } - - // And drop any unexpected ones. - for( String category : newCategories ) - { - if( !oldCategories.contains( category ) ) - { - ComputerCraft.log.warn( "Cannot sync unknown config category {}", category ); - } - } - - sync(); - } - - private static void reloadCategory( ConfigCategory oldCat, ConfigCategory newCat ) - { - // Copy the config values across to the original config. - for( Map.Entry child : newCat.getValues().entrySet() ) - { - Property oldProperty = oldCat.get( child.getKey() ), newProperty = child.getValue(); - if( oldProperty.getType() != newProperty.getType() || oldProperty.isList() != newProperty.isList() ) - { - ComputerCraft.log.warn( - "Cannot sync config property {} (type changed from {} to {})", - child.getKey(), getType( oldProperty ), getType( newProperty ) - ); - continue; - } - - if( oldProperty.isList() ) - { - oldProperty.setValues( oldProperty.getStringList() ); - } - else - { - oldProperty.setValue( newProperty.getString() ); - } - } - - // Reset any missing properties. - for( Map.Entry child : oldCat.getValues().entrySet() ) - { - if( !newCat.containsKey( child.getKey() ) ) child.getValue().setToDefault(); - } - } - - private static String getType( Property property ) - { - return property.getType() + (property.isList() ? " list" : ""); + ModLoadingContext.get().registerConfig( ModConfig.Type.COMMON, spec ); } public static void sync() { // General - ComputerCraft.computerSpaceLimit = computerSpaceLimit.getInt(); - ComputerCraft.floppySpaceLimit = floppySpaceLimit.getInt(); - ComputerCraft.maximumFilesOpen = Math.max( 0, maximumFilesOpen.getInt() ); - ComputerCraft.disable_lua51_features = disableLua51Features.getBoolean(); - ComputerCraft.default_computer_settings = defaultComputerSettings.getString(); - ComputerCraft.debug_enable = debugEnabled.getBoolean(); - ComputerCraft.logPeripheralErrors = logComputerErrors.getBoolean(); + ComputerCraft.computerSpaceLimit = computerSpaceLimit.get(); + ComputerCraft.floppySpaceLimit = floppySpaceLimit.get(); + ComputerCraft.maximumFilesOpen = maximumFilesOpen.get(); + ComputerCraft.disable_lua51_features = disableLua51Features.get(); + ComputerCraft.default_computer_settings = defaultComputerSettings.get(); + ComputerCraft.debug_enable = debugEnabled.get(); + ComputerCraft.computer_threads = computerThreads.get(); + ComputerCraft.logPeripheralErrors = logComputerErrors.get(); // Execution - ComputerCraft.computer_threads = computerThreads.getInt(); - ComputerCraft.maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos( Math.max( 1, maxMainGlobalTime.getLong() ) ); - ComputerCraft.maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos( Math.max( 1, maxMainComputerTime.getLong() ) ); + ComputerCraft.computer_threads = computerThreads.get(); + ComputerCraft.maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos( maxMainGlobalTime.get() ); + ComputerCraft.maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos( maxMainComputerTime.get() ); // HTTP - ComputerCraft.http_enable = httpEnable.getBoolean(); - ComputerCraft.http_websocket_enable = httpWebsocketEnable.getBoolean(); - ComputerCraft.http_whitelist = new AddressPredicate( httpWhitelist.getStringList() ); - ComputerCraft.http_blacklist = new AddressPredicate( httpBlacklist.getStringList() ); + ComputerCraft.http_enable = httpEnabled.get(); + ComputerCraft.http_websocket_enable = httpWebsocketEnabled.get(); + ComputerCraft.http_whitelist = new AddressPredicate( httpWhitelist.get() ); + ComputerCraft.http_blacklist = new AddressPredicate( httpBlacklist.get() ); - ComputerCraft.httpTimeout = Math.max( 0, httpTimeout.getInt() ); - ComputerCraft.httpMaxRequests = Math.max( 1, httpMaxRequests.getInt() ); - ComputerCraft.httpMaxDownload = Math.max( 0, httpMaxDownload.getLong() ); - ComputerCraft.httpMaxUpload = Math.max( 0, httpMaxUpload.getLong() ); - ComputerCraft.httpMaxWebsockets = Math.max( 1, httpMaxWebsockets.getInt() ); - ComputerCraft.httpMaxWebsocketMessage = Math.max( 0, httpMaxWebsocketMessage.getInt() ); + ComputerCraft.httpTimeout = httpTimeout.get(); + ComputerCraft.httpMaxRequests = httpMaxRequests.get(); + ComputerCraft.httpMaxDownload = httpMaxDownload.get(); + ComputerCraft.httpMaxUpload = httpMaxUpload.get(); + ComputerCraft.httpMaxWebsockets = httpMaxWebsockets.get(); + ComputerCraft.httpMaxWebsocketMessage = httpMaxWebsocketMessage.get(); // Peripheral - ComputerCraft.enableCommandBlock = commandBlockEnabled.getBoolean(); - ComputerCraft.maxNotesPerTick = Math.max( 1, maxNotesPerTick.getInt() ); - ComputerCraft.modem_range = Math.min( modemRange.getInt(), MODEM_MAX_RANGE ); - ComputerCraft.modem_highAltitudeRange = Math.min( modemHighAltitudeRange.getInt(), MODEM_MAX_RANGE ); - ComputerCraft.modem_rangeDuringStorm = Math.min( modemRangeDuringStorm.getInt(), MODEM_MAX_RANGE ); - ComputerCraft.modem_highAltitudeRangeDuringStorm = Math.min( modemHighAltitudeRangeDuringStorm.getInt(), MODEM_MAX_RANGE ); + ComputerCraft.enableCommandBlock = commandBlockEnabled.get(); + ComputerCraft.maxNotesPerTick = maxNotesPerTick.get(); + ComputerCraft.modem_range = modemRange.get(); + ComputerCraft.modem_highAltitudeRange = modemHighAltitudeRange.get(); + ComputerCraft.modem_rangeDuringStorm = modemRangeDuringStorm.get(); + ComputerCraft.modem_highAltitudeRangeDuringStorm = modemHighAltitudeRangeDuringStorm.get(); // Turtles - ComputerCraft.turtlesNeedFuel = turtlesNeedFuel.getBoolean(); - ComputerCraft.turtleFuelLimit = turtleFuelLimit.getInt(); - ComputerCraft.advancedTurtleFuelLimit = advancedTurtleFuelLimit.getInt(); - ComputerCraft.turtlesObeyBlockProtection = turtlesObeyBlockProtection.getBoolean(); - ComputerCraft.turtlesCanPush = turtlesCanPush.getBoolean(); + ComputerCraft.turtlesNeedFuel = turtlesNeedFuel.get(); + ComputerCraft.turtleFuelLimit = turtleFuelLimit.get(); + ComputerCraft.advancedTurtleFuelLimit = advancedTurtleFuelLimit.get(); + ComputerCraft.turtlesObeyBlockProtection = turtlesObeyBlockProtection.get(); + ComputerCraft.turtlesCanPush = turtlesCanPush.get(); ComputerCraft.turtleDisabledActions.clear(); - Converter converter = CaseFormat.LOWER_CAMEL.converterTo( CaseFormat.UPPER_UNDERSCORE ); - for( String value : turtleDisabledActions.getStringList() ) - { - try - { - ComputerCraft.turtleDisabledActions.add( TurtleAction.valueOf( converter.convert( value ) ) ); - } - catch( IllegalArgumentException e ) - { - ComputerCraft.log.error( "Unknown turtle action " + value ); - } - } - - config.save(); + for( String value : turtleDisabledActions.get() ) ComputerCraft.turtleDisabledActions.add( getAction( value ) ); } - public static List getConfigElements() + @SubscribeEvent + public static void sync( ModConfig.Loading event ) { - ArrayList elements = new ArrayList<>(); - - // Add all child categories - for( String categoryName : config.getCategoryNames() ) - { - if( categoryName.equals( CATEGORY_GENERAL ) ) continue; - ConfigCategory category = config.getCategory( categoryName ); - elements.add( new ConfigElement( category ) ); - } - - // Add the general category - for( Property property : config.getCategory( CATEGORY_GENERAL ).getOrderedValues() ) - { - elements.add( new ConfigElement( property ) ); - } - - return elements; + sync(); } + @SubscribeEvent + public static void sync( ModConfig.ConfigReloading event ) + { + sync(); + } + + private static final Converter converter = CaseFormat.LOWER_CAMEL.converterTo( CaseFormat.UPPER_UNDERSCORE ); + + private static TurtleAction getAction( String value ) + { + try + { + return TurtleAction.valueOf( converter.convert( value ) ); + } + catch( IllegalArgumentException e ) + { + return null; + } + } } diff --git a/src/main/java/dan200/computercraft/shared/MediaProviders.java b/src/main/java/dan200/computercraft/shared/MediaProviders.java index 42c272975..a0addc710 100644 --- a/src/main/java/dan200/computercraft/shared/MediaProviders.java +++ b/src/main/java/dan200/computercraft/shared/MediaProviders.java @@ -22,7 +22,7 @@ public final class MediaProviders private MediaProviders() {} - public static void register( @Nonnull IMediaProvider provider ) + public static synchronized void register( @Nonnull IMediaProvider provider ) { Objects.requireNonNull( provider, "provider cannot be null" ); providers.add( provider ); diff --git a/src/main/java/dan200/computercraft/shared/Peripherals.java b/src/main/java/dan200/computercraft/shared/Peripherals.java index 4e499b8c1..960ae0c0a 100644 --- a/src/main/java/dan200/computercraft/shared/Peripherals.java +++ b/src/main/java/dan200/computercraft/shared/Peripherals.java @@ -15,23 +15,24 @@ import javax.annotation.Nonnull; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.Objects; public final class Peripherals { - private static final Collection providers = ComputerCraft.peripheralProviders; + private static final Collection providers = new LinkedHashSet<>(); private Peripherals() {} - public static void register( @Nonnull IPeripheralProvider provider ) + public static synchronized void register( @Nonnull IPeripheralProvider provider ) { Objects.requireNonNull( provider, "provider cannot be null" ); - if( !providers.contains( provider ) ) providers.add( provider ); + providers.add( provider ); } public static IPeripheral getPeripheral( World world, BlockPos pos, EnumFacing side ) { - return world.isValid( pos ) && !world.isRemote ? getPeripheralAt( world, pos, side ) : null; + return World.isValid( pos ) && !world.isRemote ? getPeripheralAt( world, pos, side ) : null; } private static IPeripheral getPeripheralAt( World world, BlockPos pos, EnumFacing side ) diff --git a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java index fbd9eeb22..9a665e981 100644 --- a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java @@ -10,8 +10,8 @@ import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.shared.util.InventoryUtil; import net.minecraft.item.ItemStack; -import net.minecraftforge.fml.common.Loader; -import net.minecraftforge.fml.common.ModContainer; +import net.minecraftforge.fml.ModContainer; +import net.minecraftforge.fml.ModLoadingContext; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -24,7 +24,7 @@ public final class PocketUpgrades private PocketUpgrades() {} - public static void register( @Nonnull IPocketUpgrade upgrade ) + public static synchronized void register( @Nonnull IPocketUpgrade upgrade ) { Objects.requireNonNull( upgrade, "upgrade cannot be null" ); @@ -37,7 +37,7 @@ public static void register( @Nonnull IPocketUpgrade upgrade ) upgrades.put( id, upgrade ); - ModContainer mc = Loader.instance().activeModContainer(); + ModContainer mc = ModLoadingContext.get().getActiveContainer(); if( mc != null && mc.getModId() != null ) upgradeOwners.put( upgrade, mc.getModId() ); } @@ -74,8 +74,8 @@ public static String getOwner( IPocketUpgrade upgrade ) public static Iterable getVanillaUpgrades() { List vanilla = new ArrayList<>(); - vanilla.add( ComputerCraft.PocketUpgrades.wirelessModem ); - vanilla.add( ComputerCraft.PocketUpgrades.advancedModem ); + vanilla.add( ComputerCraft.PocketUpgrades.wirelessModemNormal ); + vanilla.add( ComputerCraft.PocketUpgrades.wirelessModemAdvanced ); vanilla.add( ComputerCraft.PocketUpgrades.speaker ); return vanilla; } diff --git a/src/main/java/dan200/computercraft/shared/Registry.java b/src/main/java/dan200/computercraft/shared/Registry.java index d9d78db4f..5c36d45e4 100644 --- a/src/main/java/dan200/computercraft/shared/Registry.java +++ b/src/main/java/dan200/computercraft/shared/Registry.java @@ -8,52 +8,53 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; -import dan200.computercraft.shared.computer.blocks.BlockCommandComputer; 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.items.ItemCommandComputer; +import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.items.ItemComputer; -import dan200.computercraft.shared.media.items.ItemDiskExpanded; -import dan200.computercraft.shared.media.items.ItemDiskLegacy; +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.peripheral.common.BlockPeripheral; -import dan200.computercraft.shared.peripheral.common.ItemPeripheral; +import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive; import dan200.computercraft.shared.peripheral.modem.wired.*; -import dan200.computercraft.shared.peripheral.modem.wireless.BlockAdvancedModem; -import dan200.computercraft.shared.peripheral.modem.wireless.ItemAdvancedModem; -import dan200.computercraft.shared.peripheral.modem.wireless.TileAdvancedModem; +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.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.blocks.TileTurtleAdvanced; -import dan200.computercraft.shared.turtle.blocks.TileTurtleExpanded; -import dan200.computercraft.shared.turtle.items.ItemTurtleAdvanced; -import dan200.computercraft.shared.turtle.items.ItemTurtleLegacy; -import dan200.computercraft.shared.turtle.items.ItemTurtleNormal; +import dan200.computercraft.shared.turtle.core.TurtlePlayer; +import dan200.computercraft.shared.turtle.items.ItemTurtle; import dan200.computercraft.shared.turtle.upgrades.*; +import dan200.computercraft.shared.util.CreativeTabMain; import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.entity.EntityType; import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemGroup; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.ResourceLocation; import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.registry.GameRegistry; import net.minecraftforge.registries.IForgeRegistry; -@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID ) +@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD ) public final class Registry { + private static final ItemGroup mainItemGroup = new CreativeTabMain(); + private Registry() { } @@ -64,61 +65,120 @@ public static void registerBlocks( RegistryEvent.Register event ) IForgeRegistry registry = event.getRegistry(); // Computers - ComputerCraft.Blocks.computer = new BlockComputer(); - ComputerCraft.Blocks.commandComputer = new BlockCommandComputer(); - - registry.registerAll( - ComputerCraft.Blocks.computer.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ), - ComputerCraft.Blocks.commandComputer.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "command_computer" ) ) + ComputerCraft.Blocks.computerNormal = new BlockComputer( + Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.0f ), + ComputerFamily.Normal, TileComputer.FACTORY_NORMAL ); - // Turtle - ComputerCraft.Blocks.turtle = new BlockTurtle(); - ComputerCraft.Blocks.turtleExpanded = new BlockTurtle(); - ComputerCraft.Blocks.turtleAdvanced = new BlockTurtle(); + ComputerCraft.Blocks.computerAdvanced = new BlockComputer( + Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.0f ), + ComputerFamily.Advanced, TileComputer.FACTORY_ADVANCED + ); + + ComputerCraft.Blocks.computerCommand = new BlockComputer( + Block.Properties.create( Material.ROCK ).hardnessAndResistance( -1, 6000000.0F ), + ComputerFamily.Command, TileCommandComputer.FACTORY + ); registry.registerAll( - ComputerCraft.Blocks.turtle.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ), - ComputerCraft.Blocks.turtleExpanded.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_expanded" ) ), + ComputerCraft.Blocks.computerNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer_normal" ) ), + ComputerCraft.Blocks.computerAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer_advanced" ) ), + ComputerCraft.Blocks.computerCommand.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer_command" ) ) + ); + + // Turtles + ComputerCraft.Blocks.turtleNormal = new BlockTurtle( + Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.5f ), + ComputerFamily.Normal, TileTurtle.FACTORY_NORMAL + ); + + ComputerCraft.Blocks.turtleAdvanced = new BlockTurtle( + Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.5f ), + ComputerFamily.Advanced, TileTurtle.FACTORY_ADVANCED + ); + + registry.registerAll( + ComputerCraft.Blocks.turtleNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_normal" ) ), ComputerCraft.Blocks.turtleAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ) ) ); - // Peripheral - ComputerCraft.Blocks.peripheral = new BlockPeripheral(); - registry.register( ComputerCraft.Blocks.peripheral.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "peripheral" ) ) ); + // Peripherals + ComputerCraft.Blocks.speaker = new BlockSpeaker( + Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ) + ); - // Cable - ComputerCraft.Blocks.cable = new BlockCable(); - registry.register( ComputerCraft.Blocks.cable.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "cable" ) ) ); + ComputerCraft.Blocks.diskDrive = new BlockDiskDrive( + Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ) + ); - // Advanced modem - ComputerCraft.Blocks.advancedModem = new BlockAdvancedModem(); - registry.register( ComputerCraft.Blocks.advancedModem.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "advanced_modem" ) ) ); + ComputerCraft.Blocks.monitorNormal = new BlockMonitor( + Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ), + TileMonitor.FACTORY_NORMAL + ); - // Full block modem - ComputerCraft.Blocks.wiredModemFull = new BlockWiredModemFull(); - registry.register( ComputerCraft.Blocks.wiredModemFull.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full" ) ) ); + ComputerCraft.Blocks.monitorAdvanced = new BlockMonitor( + Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ), + TileMonitor.FACTORY_ADVANCED + ); - registerTileEntities(); + ComputerCraft.Blocks.printer = new BlockPrinter( + Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ) + ); + + ComputerCraft.Blocks.wirelessModemNormal = new BlockWirelessModem( + Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ), + TileWirelessModem.FACTORY_NORMAL + ); + + ComputerCraft.Blocks.wirelessModemAdvanced = new BlockWirelessModem( + Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ), + TileWirelessModem.FACTORY_ADVANCED + ); + + ComputerCraft.Blocks.wiredModemFull = new BlockWiredModemFull( + Block.Properties.create( Material.ROCK ).hardnessAndResistance( 1.5f ) + ); + + ComputerCraft.Blocks.cable = new BlockCable( + Block.Properties.create( Material.ROCK ).hardnessAndResistance( 1.5f ) + ); + + registry.registerAll( + ComputerCraft.Blocks.speaker.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ) ), + ComputerCraft.Blocks.diskDrive.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk_drive" ) ), + ComputerCraft.Blocks.monitorNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "monitor_normal" ) ), + ComputerCraft.Blocks.monitorAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "monitor_advanced" ) ), + ComputerCraft.Blocks.printer.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printer" ) ), + ComputerCraft.Blocks.wirelessModemNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ) ), + ComputerCraft.Blocks.wirelessModemAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ) ), + ComputerCraft.Blocks.wiredModemFull.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full" ) ), + ComputerCraft.Blocks.cable.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "cable" ) ) + ); } - private static void registerTileEntities() + @SubscribeEvent + public static void registerTileEntities( RegistryEvent.Register> event ) { - GameRegistry.registerTileEntity( TileComputer.class, new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ); - GameRegistry.registerTileEntity( TileCommandComputer.class, new ResourceLocation( ComputerCraft.MOD_ID, "command_computer" ) ); + IForgeRegistry> registry = event.getRegistry(); - GameRegistry.registerTileEntity( TileTurtle.class, new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ); - GameRegistry.registerTileEntity( TileTurtleExpanded.class, new ResourceLocation( ComputerCraft.MOD_ID, "turtleex" ) ); - GameRegistry.registerTileEntity( TileTurtleAdvanced.class, new ResourceLocation( ComputerCraft.MOD_ID, "turtleadv" ) ); + // Computers + registry.registerAll( TileComputer.FACTORY_NORMAL, TileComputer.FACTORY_ADVANCED, TileCommandComputer.FACTORY ); - GameRegistry.registerTileEntity( TileDiskDrive.class, new ResourceLocation( ComputerCraft.MOD_ID, "diskdrive" ) ); - GameRegistry.registerTileEntity( TileWirelessModem.class, new ResourceLocation( ComputerCraft.MOD_ID, "wirelessmodem" ) ); - GameRegistry.registerTileEntity( TileMonitor.class, new ResourceLocation( ComputerCraft.MOD_ID, "monitor" ) ); - GameRegistry.registerTileEntity( TilePrinter.class, new ResourceLocation( ComputerCraft.MOD_ID, "ccprinter" ) ); - GameRegistry.registerTileEntity( TileCable.class, new ResourceLocation( ComputerCraft.MOD_ID, "wiredmodem" ) ); - GameRegistry.registerTileEntity( TileAdvancedModem.class, new ResourceLocation( ComputerCraft.MOD_ID, "advanced_modem" ) ); - GameRegistry.registerTileEntity( TileSpeaker.class, new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ) ); - GameRegistry.registerTileEntity( TileWiredModemFull.class, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full" ) ); + // Turtles + registry.registerAll( TileTurtle.FACTORY_NORMAL, TileTurtle.FACTORY_ADVANCED ); + + // Peripherals + registry.registerAll( + TileSpeaker.FACTORY, + TileDiskDrive.FACTORY, + TileMonitor.FACTORY_NORMAL, + TileMonitor.FACTORY_ADVANCED, + TilePrinter.FACTORY, + TileWirelessModem.FACTORY_NORMAL, + TileWirelessModem.FACTORY_ADVANCED, + TileWiredModemFull.FACTORY, + TileCable.FACTORY + ); } private static T setupItemBlock( T item ) @@ -127,203 +187,128 @@ private static T setupItemBlock( T item ) return item; } + private static Item.Properties defaultItem() + { + return new Item.Properties().group( mainItemGroup ); + } + @SubscribeEvent public static void registerItems( RegistryEvent.Register event ) { IForgeRegistry registry = event.getRegistry(); - // Computers - ComputerCraft.Items.computer = new ItemComputer( ComputerCraft.Blocks.computer ); - ComputerCraft.Items.commandComputer = new ItemCommandComputer( ComputerCraft.Blocks.commandComputer ); + // Computer + ComputerCraft.Items.computerNormal = new ItemComputer( ComputerCraft.Blocks.computerNormal, defaultItem() ); + ComputerCraft.Items.computerAdvanced = new ItemComputer( ComputerCraft.Blocks.computerAdvanced, defaultItem() ); + ComputerCraft.Items.computerCommand = new ItemComputer( ComputerCraft.Blocks.computerCommand, defaultItem() ); registry.registerAll( - setupItemBlock( ComputerCraft.Items.computer ), - setupItemBlock( ComputerCraft.Items.commandComputer ) - ); - - // Pocket computer - ComputerCraft.Items.pocketComputer = new ItemPocketComputer(); - registry.register( - ComputerCraft.Items.pocketComputer.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer" ) ) + setupItemBlock( ComputerCraft.Items.computerNormal ), + setupItemBlock( ComputerCraft.Items.computerAdvanced ), + setupItemBlock( ComputerCraft.Items.computerCommand ) ); // Turtle - ComputerCraft.Items.turtle = new ItemTurtleLegacy( ComputerCraft.Blocks.turtle ); - ComputerCraft.Items.turtleExpanded = new ItemTurtleNormal( ComputerCraft.Blocks.turtleExpanded ); - ComputerCraft.Items.turtleAdvanced = new ItemTurtleAdvanced( ComputerCraft.Blocks.turtleAdvanced ); - + ComputerCraft.Items.turtleNormal = new ItemTurtle( ComputerCraft.Blocks.turtleNormal, defaultItem() ); + ComputerCraft.Items.turtleAdvanced = new ItemTurtle( ComputerCraft.Blocks.turtleAdvanced, defaultItem() ); registry.registerAll( - setupItemBlock( ComputerCraft.Items.turtle ), - setupItemBlock( ComputerCraft.Items.turtleExpanded ), + setupItemBlock( ComputerCraft.Items.turtleNormal ), setupItemBlock( ComputerCraft.Items.turtleAdvanced ) ); - // Printouts - ComputerCraft.Items.printout = new ItemPrintout(); - registry.register( ComputerCraft.Items.printout.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printout" ) ) ); + // Pocket computer + ComputerCraft.Items.pocketComputerNormal = new ItemPocketComputer( defaultItem().maxStackSize( 1 ), ComputerFamily.Normal ); + ComputerCraft.Items.pocketComputerAdvanced = new ItemPocketComputer( defaultItem().maxStackSize( 1 ), ComputerFamily.Advanced ); - // Disks - ComputerCraft.Items.disk = new ItemDiskLegacy(); - ComputerCraft.Items.diskExpanded = new ItemDiskExpanded(); - ComputerCraft.Items.treasureDisk = new ItemTreasureDisk(); + registry.registerAll( + ComputerCraft.Items.pocketComputerNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_normal" ) ), + ComputerCraft.Items.pocketComputerAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_advanced" ) ) + ); + + // Floppy disk + ComputerCraft.Items.disk = new ItemDisk( defaultItem().maxStackSize( 1 ) ); + ComputerCraft.Items.treasureDisk = new ItemTreasureDisk( defaultItem().maxStackSize( 1 ) ); registry.registerAll( ComputerCraft.Items.disk.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk" ) ), - ComputerCraft.Items.diskExpanded.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk_expanded" ) ), ComputerCraft.Items.treasureDisk.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "treasure_disk" ) ) ); - // Peripherals - ComputerCraft.Items.peripheral = new ItemPeripheral( ComputerCraft.Blocks.peripheral ); - ComputerCraft.Items.advancedModem = new ItemAdvancedModem( ComputerCraft.Blocks.advancedModem ); - ComputerCraft.Items.cable = new ItemCable( ComputerCraft.Blocks.cable ); - ComputerCraft.Items.wiredModemFull = new ItemWiredModemFull( ComputerCraft.Blocks.wiredModemFull ); + // Printouts + ComputerCraft.Items.printedPage = new ItemPrintout( defaultItem().maxStackSize( 1 ), ItemPrintout.Type.PAGE ); + ComputerCraft.Items.printedPages = new ItemPrintout( defaultItem().maxStackSize( 1 ), ItemPrintout.Type.PAGES ); + ComputerCraft.Items.printedBook = new ItemPrintout( defaultItem().maxStackSize( 1 ), ItemPrintout.Type.BOOK ); registry.registerAll( - setupItemBlock( ComputerCraft.Items.peripheral ), - setupItemBlock( ComputerCraft.Items.advancedModem ), - setupItemBlock( ComputerCraft.Items.cable ), - setupItemBlock( ComputerCraft.Items.wiredModemFull ) + ComputerCraft.Items.printedPage.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printed_page" ) ), + ComputerCraft.Items.printedPages.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printed_pages" ) ), + ComputerCraft.Items.printedBook.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printed_book" ) ) + ); + + // Peripherals + registry.registerAll( + setupItemBlock( new ItemBlock( ComputerCraft.Blocks.speaker, defaultItem() ) ), + setupItemBlock( new ItemBlock( ComputerCraft.Blocks.diskDrive, defaultItem() ) ), + setupItemBlock( new ItemBlock( ComputerCraft.Blocks.printer, defaultItem() ) ), + setupItemBlock( new ItemBlock( ComputerCraft.Blocks.monitorNormal, defaultItem() ) ), + setupItemBlock( new ItemBlock( ComputerCraft.Blocks.monitorAdvanced, defaultItem() ) ), + setupItemBlock( new ItemBlock( ComputerCraft.Blocks.wirelessModemNormal, defaultItem() ) ), + setupItemBlock( new ItemBlock( ComputerCraft.Blocks.wirelessModemAdvanced, defaultItem() ) ), + setupItemBlock( new ItemBlock( ComputerCraft.Blocks.wiredModemFull, defaultItem() ) ) + ); + + ComputerCraft.Items.cable = new ItemBlockCable.Cable( ComputerCraft.Blocks.cable, defaultItem() ); + ComputerCraft.Items.wiredModem = new ItemBlockCable.WiredModem( ComputerCraft.Blocks.cable, defaultItem() ); + registry.registerAll( + ComputerCraft.Items.cable.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "cable" ) ), + ComputerCraft.Items.wiredModem.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem" ) ) ); registerTurtleUpgrades(); registerPocketUpgrades(); - registerLegacyUpgrades(); } private static void registerTurtleUpgrades() { // Upgrades - ComputerCraft.TurtleUpgrades.wirelessModem = new TurtleModem( false, new ResourceLocation( "computercraft", "wireless_modem" ), 1 ); - TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.wirelessModem ); + ComputerCraft.TurtleUpgrades.wirelessModemNormal = new TurtleModem( false, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ) ); + TurtleUpgrades.register( ComputerCraft.TurtleUpgrades.wirelessModemNormal ); - ComputerCraft.TurtleUpgrades.advancedModem = new TurtleModem( true, new ResourceLocation( "computercraft", "advanced_modem" ), -1 ); - TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.advancedModem ); + ComputerCraft.TurtleUpgrades.wirelessModemAdvanced = new TurtleModem( true, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ) ); + ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.wirelessModemAdvanced ); - ComputerCraft.TurtleUpgrades.speaker = new TurtleSpeaker( new ResourceLocation( "computercraft", "speaker" ), 8 ); - TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.speaker ); + ComputerCraft.TurtleUpgrades.speaker = new TurtleSpeaker( new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ) ); + ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.speaker ); - ComputerCraft.TurtleUpgrades.craftingTable = new TurtleCraftingTable( new ResourceLocation( "minecraft", "crafting_table" ), 2 ); - TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.craftingTable ); + ComputerCraft.TurtleUpgrades.craftingTable = new TurtleCraftingTable( new ResourceLocation( "minecraft", "crafting_table" ) ); + ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.craftingTable ); - ComputerCraft.TurtleUpgrades.diamondSword = new TurtleSword( new ResourceLocation( "minecraft", "diamond_sword" ), 3, Items.DIAMOND_SWORD ); - TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondSword ); + ComputerCraft.TurtleUpgrades.diamondSword = new TurtleSword( new ResourceLocation( "minecraft", "diamond_sword" ), Items.DIAMOND_SWORD ); + ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.diamondSword ); - ComputerCraft.TurtleUpgrades.diamondShovel = new TurtleShovel( new ResourceLocation( "minecraft", "diamond_shovel" ), 4, Items.DIAMOND_SHOVEL ); - TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondShovel ); + ComputerCraft.TurtleUpgrades.diamondShovel = new TurtleShovel( new ResourceLocation( "minecraft", "diamond_shovel" ), Items.DIAMOND_SHOVEL ); + ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.diamondShovel ); - ComputerCraft.TurtleUpgrades.diamondPickaxe = new TurtleTool( new ResourceLocation( "minecraft", "diamond_pickaxe" ), 5, Items.DIAMOND_PICKAXE ); - TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondPickaxe ); + ComputerCraft.TurtleUpgrades.diamondPickaxe = new TurtleTool( new ResourceLocation( "minecraft", "diamond_pickaxe" ), Items.DIAMOND_PICKAXE ); + ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.diamondPickaxe ); - ComputerCraft.TurtleUpgrades.diamondAxe = new TurtleAxe( new ResourceLocation( "minecraft", "diamond_axe" ), 6, Items.DIAMOND_AXE ); - TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondAxe ); + ComputerCraft.TurtleUpgrades.diamondAxe = new TurtleAxe( new ResourceLocation( "minecraft", "diamond_axe" ), Items.DIAMOND_AXE ); + ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.diamondAxe ); - ComputerCraft.TurtleUpgrades.diamondHoe = new TurtleHoe( new ResourceLocation( "minecraft", "diamond_hoe" ), 7, Items.DIAMOND_HOE ); - TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondHoe ); + ComputerCraft.TurtleUpgrades.diamondHoe = new TurtleHoe( new ResourceLocation( "minecraft", "diamond_hoe" ), Items.DIAMOND_HOE ); + ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.diamondHoe ); } private static void registerPocketUpgrades() { - // Register pocket upgrades - ComputerCraft.PocketUpgrades.wirelessModem = new PocketModem( false ); - ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.wirelessModem ); - ComputerCraft.PocketUpgrades.advancedModem = new PocketModem( true ); - ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.advancedModem ); - - ComputerCraft.PocketUpgrades.speaker = new PocketSpeaker(); - ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.speaker ); - } - - @SuppressWarnings( "deprecation" ) - private static void registerLegacyUpgrades() - { - ComputerCraft.PocketUpgrades.pocketSpeaker = ComputerCraft.PocketUpgrades.speaker; - ComputerCraft.Upgrades.advancedModem = ComputerCraft.TurtleUpgrades.advancedModem; + ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.wirelessModemNormal = new PocketModem( false ) ); + ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.wirelessModemAdvanced = new PocketModem( true ) ); + ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.speaker = new PocketSpeaker() ); } @SubscribeEvent - public static void remapItems( RegistryEvent.MissingMappings mappings ) + public static void registerEntities( RegistryEvent.Register> registry ) { - // We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower. - for( RegistryEvent.MissingMappings.Mapping mapping : mappings.getAllMappings() ) - { - String domain = mapping.key.getNamespace(); - if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue; - - String key = mapping.key.getPath(); - if( key.equalsIgnoreCase( "CC-Computer" ) ) - { - mapping.remap( ComputerCraft.Items.computer ); - } - else if( key.equalsIgnoreCase( "CC-Peripheral" ) ) - { - mapping.remap( ComputerCraft.Items.peripheral ); - } - else if( key.equalsIgnoreCase( "CC-Cable" ) ) - { - mapping.remap( ComputerCraft.Items.cable ); - } - else if( key.equalsIgnoreCase( "diskExpanded" ) ) - { - mapping.remap( ComputerCraft.Items.diskExpanded ); - } - else if( key.equalsIgnoreCase( "treasureDisk" ) ) - { - mapping.remap( ComputerCraft.Items.treasureDisk ); - } - else if( key.equalsIgnoreCase( "pocketComputer" ) ) - { - mapping.remap( ComputerCraft.Items.pocketComputer ); - } - else if( key.equalsIgnoreCase( "CC-Turtle" ) ) - { - mapping.remap( ComputerCraft.Items.turtle ); - } - else if( key.equalsIgnoreCase( "CC-TurtleExpanded" ) ) - { - mapping.remap( ComputerCraft.Items.turtleExpanded ); - } - else if( key.equalsIgnoreCase( "CC-TurtleAdvanced" ) ) - { - mapping.remap( ComputerCraft.Items.turtleAdvanced ); - } - } - } - - @SubscribeEvent - public static void remapBlocks( RegistryEvent.MissingMappings mappings ) - { - // We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower. - for( RegistryEvent.MissingMappings.Mapping mapping : mappings.getAllMappings() ) - { - String domain = mapping.key.getNamespace(); - if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue; - - String key = mapping.key.getPath(); - if( key.equalsIgnoreCase( "CC-Computer" ) ) - { - mapping.remap( ComputerCraft.Blocks.computer ); - } - else if( key.equalsIgnoreCase( "CC-Peripheral" ) ) - { - mapping.remap( ComputerCraft.Blocks.peripheral ); - } - else if( key.equalsIgnoreCase( "CC-Cable" ) ) - { - mapping.remap( ComputerCraft.Blocks.cable ); - } - else if( key.equalsIgnoreCase( "CC-Turtle" ) ) - { - mapping.remap( ComputerCraft.Blocks.turtle ); - } - else if( key.equalsIgnoreCase( "CC-TurtleExpanded" ) ) - { - mapping.remap( ComputerCraft.Blocks.turtleExpanded ); - } - else if( key.equalsIgnoreCase( "CC-TurtleAdvanced" ) ) - { - mapping.remap( ComputerCraft.Blocks.turtleAdvanced ); - } - } + registry.getRegistry().register( TurtlePlayer.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_player" ) ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java index 14629fac0..f28c421cf 100644 --- a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java +++ b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java @@ -6,65 +6,28 @@ package dan200.computercraft.shared; -import com.google.common.base.Preconditions; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.permissions.ITurtlePermissionProvider; import dan200.computercraft.api.turtle.event.TurtleActionEvent; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; - -import javax.annotation.Nonnull; -import java.util.Collection; -import java.util.LinkedHashSet; @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID ) public final class TurtlePermissions { - private static final Collection providers = new LinkedHashSet<>(); - - private TurtlePermissions() - { - } - - public static void register( @Nonnull ITurtlePermissionProvider upgrade ) - { - Preconditions.checkNotNull( upgrade, "upgrade cannot be null" ); - - providers.add( upgrade ); - } - public static boolean isBlockEnterable( World world, BlockPos pos, EntityPlayer player ) { - MinecraftServer server = player.getServer(); - if( server != null && !world.isRemote && server.isBlockProtected( world, pos, player ) ) - { - return false; - } - - for( ITurtlePermissionProvider provider : providers ) - { - if( !provider.isBlockEnterable( world, pos ) ) return false; - } - return true; + MinecraftServer server = world.getServer(); + return server == null || world.isRemote || !server.isBlockProtected( world, pos, player ); } public static boolean isBlockEditable( World world, BlockPos pos, EntityPlayer player ) { - MinecraftServer server = player.getServer(); - if( server != null && !world.isRemote && server.isBlockProtected( world, pos, player ) ) - { - return false; - } - - for( ITurtlePermissionProvider provider : providers ) - { - if( !provider.isBlockEditable( world, pos ) ) return false; - } - return true; + MinecraftServer server = world.getServer(); + return server == null || world.isRemote || !server.isBlockProtected( world, pos, player ); } @SubscribeEvent diff --git a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java index 921be39d9..63fb3f478 100644 --- a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java @@ -10,11 +10,9 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.util.InventoryUtil; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minecraft.item.ItemStack; -import net.minecraftforge.fml.common.Loader; -import net.minecraftforge.fml.common.ModContainer; +import net.minecraftforge.fml.ModContainer; +import net.minecraftforge.fml.ModLoadingContext; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -23,7 +21,6 @@ public final class TurtleUpgrades { private static final Map upgrades = new HashMap<>(); - private static final Int2ObjectMap legacyUpgrades = new Int2ObjectOpenHashMap<>(); private static final IdentityHashMap upgradeOwners = new IdentityHashMap<>(); private TurtleUpgrades() {} @@ -32,73 +29,25 @@ public static void register( @Nonnull ITurtleUpgrade upgrade ) { Objects.requireNonNull( upgrade, "upgrade cannot be null" ); - int id = upgrade.getLegacyUpgradeID(); - if( id >= 0 && id < 64 ) - { - String message = getMessage( upgrade, "Legacy UpgradeID '" + id + "' is reserved by ComputerCraft" ); - ComputerCraft.log.error( message ); - throw new RuntimeException( message ); - } - - registerInternal( upgrade ); - } - - static void registerInternal( ITurtleUpgrade upgrade ) - { - Objects.requireNonNull( upgrade, "upgrade cannot be null" ); - - // Check conditions - int legacyId = upgrade.getLegacyUpgradeID(); - if( legacyId >= 0 ) - { - if( legacyId >= Short.MAX_VALUE ) - { - String message = getMessage( upgrade, "UpgradeID '" + legacyId + "' is out of range" ); - ComputerCraft.log.error( message ); - throw new RuntimeException( message ); - } - - ITurtleUpgrade existing = legacyUpgrades.get( legacyId ); - if( existing != null ) - { - String message = getMessage( upgrade, "UpgradeID '" + legacyId + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" ); - ComputerCraft.log.error( message ); - throw new RuntimeException( message ); - } - } - String id = upgrade.getUpgradeID().toString(); ITurtleUpgrade existing = upgrades.get( id ); if( existing != null ) { - String message = getMessage( upgrade, "UpgradeID '" + id + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" ); - ComputerCraft.log.error( message ); - throw new RuntimeException( message ); + throw new IllegalStateException( "Error registering '" + upgrade.getUnlocalisedAdjective() + " Turle'. UpgradeID '" + id + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" ); } - // Register - if( legacyId >= 0 ) legacyUpgrades.put( legacyId, upgrade ); upgrades.put( id, upgrade ); - ModContainer mc = Loader.instance().activeModContainer(); + ModContainer mc = ModLoadingContext.get().getActiveContainer(); if( mc != null && mc.getModId() != null ) upgradeOwners.put( upgrade, mc.getModId() ); } - private static String getMessage( ITurtleUpgrade upgrade, String rest ) - { - return "Error registering '" + upgrade.getUnlocalisedAdjective() + " Turtle'. " + rest; - } public static ITurtleUpgrade get( String id ) { return upgrades.get( id ); } - public static ITurtleUpgrade get( int id ) - { - return legacyUpgrades.get( id ); - } - public static ITurtleUpgrade get( @Nonnull ItemStack stack ) { if( stack.isEmpty() ) return null; @@ -118,15 +67,20 @@ public static ITurtleUpgrade get( @Nonnull ItemStack stack ) public static Iterable getVanillaUpgrades() { List vanilla = new ArrayList<>(); + + + // ComputerCraft upgrades + vanilla.add( ComputerCraft.TurtleUpgrades.wirelessModemNormal ); + vanilla.add( ComputerCraft.TurtleUpgrades.wirelessModemAdvanced ); + vanilla.add( ComputerCraft.TurtleUpgrades.speaker ); + + // Vanilla Minecraft upgrades vanilla.add( ComputerCraft.TurtleUpgrades.diamondPickaxe ); vanilla.add( ComputerCraft.TurtleUpgrades.diamondAxe ); vanilla.add( ComputerCraft.TurtleUpgrades.diamondSword ); vanilla.add( ComputerCraft.TurtleUpgrades.diamondShovel ); vanilla.add( ComputerCraft.TurtleUpgrades.diamondHoe ); vanilla.add( ComputerCraft.TurtleUpgrades.craftingTable ); - vanilla.add( ComputerCraft.TurtleUpgrades.wirelessModem ); - vanilla.add( ComputerCraft.TurtleUpgrades.advancedModem ); - vanilla.add( ComputerCraft.TurtleUpgrades.speaker ); return vanilla; } diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index 9ead7a0af..db1c6f3a3 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -6,7 +6,9 @@ package dan200.computercraft.shared.command; -import com.google.common.collect.Sets; +import com.mojang.brigadier.CommandDispatcher; +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; @@ -15,30 +17,37 @@ import dan200.computercraft.core.tracking.Tracking; import dan200.computercraft.core.tracking.TrackingContext; import dan200.computercraft.core.tracking.TrackingField; -import dan200.computercraft.shared.Config; -import dan200.computercraft.shared.command.framework.*; import dan200.computercraft.shared.command.text.TableBuilder; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.Containers; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; +import net.minecraft.command.CommandSource; import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.server.MinecraftServer; +import net.minecraft.network.play.server.SPacketPlayerPosLook; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; import net.minecraft.world.World; +import net.minecraft.world.WorldServer; import javax.annotation.Nonnull; import java.util.*; -import java.util.function.Consumer; +import static dan200.computercraft.shared.command.CommandUtils.isPlayer; +import static dan200.computercraft.shared.command.Exceptions.*; +import static dan200.computercraft.shared.command.arguments.ComputerArgumentType.getComputerArgument; +import static dan200.computercraft.shared.command.arguments.ComputerArgumentType.oneComputer; +import static dan200.computercraft.shared.command.arguments.ComputersArgumentType.*; +import static dan200.computercraft.shared.command.arguments.TrackingFieldArgumentType.trackingField; +import static dan200.computercraft.shared.command.builder.CommandBuilder.args; +import static dan200.computercraft.shared.command.builder.CommandBuilder.command; +import static dan200.computercraft.shared.command.builder.HelpingArgumentBuilder.choice; import static dan200.computercraft.shared.command.text.ChatHelpers.*; +import static net.minecraft.command.Commands.literal; -public final class CommandComputerCraft extends CommandDelegate +public final class CommandComputerCraft { public static final UUID SYSTEM_UUID = new UUID( 0, 0 ); @@ -46,335 +55,209 @@ public final class CommandComputerCraft extends CommandDelegate private static final int DUMP_SINGLE_ID = 1844510720; private static final int TRACK_ID = 373882880; - public CommandComputerCraft() + private CommandComputerCraft() { - super( create() ); } - private static ISubCommand create() + public static void register( CommandDispatcher dispatcher ) { - CommandRoot root = new CommandRoot( "computercraft" ); - - root.register( new SubCommandBase( "dump", UserLevel.OWNER_OP ) - { - @Override - public void execute( @Nonnull CommandContext context, @Nonnull List arguments ) throws CommandException - { - if( arguments.isEmpty() ) - { + dispatcher.register( choice( "computercraft" ) + .then( literal( "dump" ) + .requires( UserLevel.OWNER_OP ) + .executes( context -> { TableBuilder table = new TableBuilder( DUMP_LIST_ID, "Computer", "On", "Position" ); + CommandSource source = context.getSource(); List computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() ); // Unless we're on a server, limit the number of rows we can send. - if( !(context.getSender() instanceof MinecraftServer) ) - { - World world = context.getSender().getEntityWorld(); - BlockPos pos = context.getSender().getPosition(); + World world = source.getWorld(); + BlockPos pos = new BlockPos( source.getPos() ); - computers.sort( ( a, b ) -> { - if( a.getWorld() == b.getWorld() && a.getWorld() == world ) - { - return Double.compare( a.getPosition().distanceSq( pos ), b.getPosition().distanceSq( pos ) ); - } - else if( a.getWorld() == world ) - { - return -1; - } - else if( b.getWorld() == world ) - { - return 1; - } - else - { - return Integer.compare( a.getInstanceID(), b.getInstanceID() ); - } - } ); - } + computers.sort( ( a, b ) -> { + if( a.getWorld() == b.getWorld() && a.getWorld() == world ) + { + return Double.compare( a.getPosition().distanceSq( pos ), b.getPosition().distanceSq( pos ) ); + } + else if( a.getWorld() == world ) + { + return -1; + } + else if( b.getWorld() == world ) + { + return 1; + } + else + { + return Integer.compare( a.getInstanceID(), b.getInstanceID() ); + } + } ); for( ServerComputer computer : computers ) { table.row( - linkComputer( context, computer, computer.getID() ), + linkComputer( source, computer, computer.getID() ), bool( computer.isOn() ), - linkPosition( context, computer ) + linkPosition( source, computer ) ); } - table.display( context.getSender() ); - } - else if( arguments.size() == 1 ) - { - ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) ); + table.display( context.getSource() ); + return computers.size(); + } ) + .then( args() + .arg( "computer", oneComputer() ) + .executes( context -> { + ServerComputer computer = getComputerArgument( context, "computer" ); - TableBuilder table = new TableBuilder( DUMP_SINGLE_ID ); - table.row( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) ); - table.row( header( "Id" ), text( Integer.toString( computer.getID() ) ) ); - table.row( header( "Label" ), text( computer.getLabel() ) ); - table.row( header( "On" ), bool( computer.isOn() ) ); - table.row( header( "Position" ), linkPosition( context, computer ) ); - table.row( header( "Family" ), text( computer.getFamily().toString() ) ); + TableBuilder table = new TableBuilder( DUMP_SINGLE_ID ); + table.row( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) ); + table.row( header( "Id" ), text( Integer.toString( computer.getID() ) ) ); + table.row( header( "Label" ), text( computer.getLabel() ) ); + table.row( header( "On" ), bool( computer.isOn() ) ); + table.row( header( "Position" ), linkPosition( context.getSource(), computer ) ); + table.row( header( "Family" ), text( computer.getFamily().toString() ) ); - for( int i = 0; i < 6; i++ ) - { - IPeripheral peripheral = computer.getPeripheral( i ); - if( peripheral != null ) + for( int i = 0; i < 6; i++ ) { - table.row( header( "Peripheral " + IAPIEnvironment.SIDE_NAMES[i] ), text( peripheral.getType() ) ); + IPeripheral peripheral = computer.getPeripheral( i ); + if( peripheral != null ) + { + table.row( header( "Peripheral " + IAPIEnvironment.SIDE_NAMES[i] ), text( peripheral.getType() ) ); + } } - } - table.display( context.getSender() ); - } - else - { - throw new CommandException( context.getFullUsage() ); - } - } + table.display( context.getSource() ); + return 1; + } ) ) ) - @Nonnull - @Override - public List getCompletion( @Nonnull CommandContext context, @Nonnull List arguments ) - { - return arguments.size() == 1 - ? ComputerSelector.completeComputer( arguments.get( 0 ) ) - : Collections.emptyList(); - } - } ); - - root.register( new SubCommandBase( "shutdown", UserLevel.OWNER_OP ) - { - @Override - public void execute( @Nonnull CommandContext context, @Nonnull List arguments ) throws CommandException - { - withComputers( arguments, computers -> { + .then( command( "shutdown" ) + .requires( UserLevel.OWNER_OP ) + .argManyValue( "computers", manyComputers(), s -> ComputerCraft.serverComputerRegistry.getComputers() ) + .executes( ( context, computers ) -> { int shutdown = 0; - for( ServerComputer computer : computers ) + for( ServerComputer computer : unwrap( context.getSource(), computers ) ) { if( computer.isOn() ) shutdown++; computer.shutdown(); } - context.getSender().sendMessage( translate( "commands.computercraft.shutdown.done", shutdown, computers.size() ) ); - } ); - } + context.getSource().sendFeedback( translate( "commands.computercraft.shutdown.done", shutdown, computers.size() ), false ); + return shutdown; + } ) ) - @Nonnull - @Override - public List getCompletion( @Nonnull CommandContext context, @Nonnull List arguments ) - { - return arguments.isEmpty() - ? Collections.emptyList() - : ComputerSelector.completeComputer( arguments.get( arguments.size() - 1 ) ); - } - } ); - - root.register( new SubCommandBase( "turn-on", UserLevel.OWNER_OP ) - { - @Override - public void execute( @Nonnull CommandContext context, @Nonnull List arguments ) throws CommandException - { - withComputers( arguments, computers -> { + .then( command( "turn-on" ) + .requires( UserLevel.OWNER_OP ) + .argManyValue( "computers", manyComputers(), s -> ComputerCraft.serverComputerRegistry.getComputers() ) + .executes( ( context, computers ) -> { int on = 0; - for( ServerComputer computer : computers ) + for( ServerComputer computer : unwrap( context.getSource(), computers ) ) { if( !computer.isOn() ) on++; computer.turnOn(); } - context.getSender().sendMessage( translate( "commands.computercraft.turn_on.done", on, computers.size() ) ); - } ); - } + context.getSource().sendFeedback( translate( "commands.computercraft.turn_on.done", on, computers.size() ), false ); + return on; + } ) ) - @Nonnull - @Override - public List getCompletion( @Nonnull CommandContext context, @Nonnull List arguments ) - { - return arguments.isEmpty() - ? Collections.emptyList() - : ComputerSelector.completeComputer( arguments.get( arguments.size() - 1 ) ); - } - } ); + .then( command( "tp" ) + .requires( UserLevel.OP ) + .arg( "computer", oneComputer() ) + .executes( context -> { + ServerComputer computer = getComputerArgument( context, "computer" ); + World world = computer.getWorld(); + BlockPos pos = computer.getPosition(); - root.register( new SubCommandBase( "tp", UserLevel.OP ) - { - @Override - public void execute( @Nonnull CommandContext context, @Nonnull List arguments ) throws CommandException - { - if( arguments.size() != 1 ) throw new CommandException( context.getFullUsage() ); + if( world == null || pos == null ) throw TP_NOT_THERE.create(); - ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) ); - World world = computer.getWorld(); - BlockPos pos = computer.getPosition(); + Entity entity = context.getSource().assertIsEntity(); + if( !(entity instanceof EntityPlayerMP) ) throw TP_NOT_PLAYER.create(); - if( world == null || pos == null ) throw new CommandException( "commands.computercraft.tp.not_there" ); - - ICommandSender sender = context.getSender(); - if( !(sender instanceof Entity) ) throw new CommandException( "commands.computercraft.tp.not_entity" ); - - if( sender instanceof EntityPlayerMP ) - { - EntityPlayerMP entity = (EntityPlayerMP) sender; - if( entity.getEntityWorld() != world ) + EntityPlayerMP player = (EntityPlayerMP) entity; + if( player.getEntityWorld() == world ) { - context.getServer().getPlayerList().changePlayerDimension( entity, world.provider.getDimension() ); + player.connection.setPlayerLocation( pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0, EnumSet.noneOf( SPacketPlayerPosLook.EnumFlags.class ) ); + } + else + { + player.teleport( (WorldServer) world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0 ); } - entity.setPositionAndUpdate( pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5 ); - } - else - { - Entity entity = (Entity) sender; - if( entity.getEntityWorld() != world ) + return 1; + } ) ) + + .then( command( "queue" ) + .requires( UserLevel.ANYONE ) + .arg( "computer", manyComputers() ) + .argManyValue( "args", StringArgumentType.string(), Collections.emptyList() ) + .executes( ( ctx, args ) -> { + Collection computers = getComputersArgument( ctx, "computer" ); + Object[] rest = args.toArray(); + + int queued = 0; + for( ServerComputer computer : computers ) { - entity.changeDimension( world.provider.getDimension() ); + if( computer.getFamily() == ComputerFamily.Command && computer.isOn() ) + { + computer.queueEvent( "computer_command", rest ); + queued++; + } } - entity.setLocationAndAngles( - pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, - entity.rotationYaw, entity.rotationPitch - ); - } - } + return queued; + } ) ) - @Nonnull - @Override - public List getCompletion( @Nonnull CommandContext context, @Nonnull List arguments ) - { - return arguments.size() == 1 - ? ComputerSelector.completeComputer( arguments.get( 0 ) ) - : Collections.emptyList(); - } - } ); + .then( command( "view" ) + .requires( UserLevel.OP ) + .arg( "computer", oneComputer() ) + .executes( context -> { + EntityPlayerMP player = context.getSource().asPlayer(); + ServerComputer computer = getComputerArgument( context, "computer" ); + Containers.openComputerGUI( player, computer ); + return 1; + } ) ) - root.register( new SubCommandBase( "view", UserLevel.OP ) - { - @Override - public void execute( @Nonnull CommandContext context, @Nonnull List arguments ) throws CommandException - { - if( arguments.size() != 1 ) throw new CommandException( context.getFullUsage() ); + .then( choice( "track" ) + .then( command( "start" ) + .requires( UserLevel.OWNER_OP ) + .executes( context -> { + getTimingContext( context.getSource() ).start(); - ICommandSender sender = context.getSender(); - if( !(sender instanceof EntityPlayerMP) ) - { - throw new CommandException( "commands.computercraft.view.not_player" ); - } + String stopCommand = "/computercraft track stop"; + context.getSource().sendFeedback( translate( "commands.computercraft.track.start.stop", + link( text( stopCommand ), stopCommand, translate( "commands.computercraft.track.stop.action" ) ) ), false ); + return 1; + } ) ) - ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) ); - Containers.openComputerGUI( (EntityPlayerMP) sender, computer ); - } + .then( command( "stop" ) + .requires( UserLevel.OWNER_OP ) + .executes( context -> { + TrackingContext timings = getTimingContext( context.getSource() ); + if( !timings.stop() ) throw NOT_TRACKING_EXCEPTION.create(); + displayTimings( context.getSource(), timings.getImmutableTimings(), TrackingField.AVERAGE_TIME, DEFAULT_FIELDS ); + return 1; + } ) ) - @Nonnull - @Override - public List getCompletion( @Nonnull CommandContext context, @Nonnull List arguments ) - { - return arguments.size() == 1 - ? ComputerSelector.completeComputer( arguments.get( 0 ) ) - : Collections.emptyList(); - } - } ); + .then( command( "dump" ) + .requires( UserLevel.OWNER_OP ) + .argManyValue( "fields", trackingField(), DEFAULT_FIELDS ) + .executes( ( context, fields ) -> { + TrackingField sort; + if( fields.size() == 1 && DEFAULT_FIELDS.contains( fields.get( 0 ) ) ) + { + sort = fields.get( 0 ); + fields = DEFAULT_FIELDS; + } + else + { + sort = fields.get( 0 ); + } - root.register( new CommandRoot( "track" ).register( new SubCommandBase( "start", UserLevel.OWNER_OP ) - { - @Override - public void execute( @Nonnull CommandContext context, @Nonnull List arguments ) - { - getTimingContext( context ).start(); - - String stopCommand = "/" + context.parent().getFullPath() + " stop"; - context.getSender().sendMessage( list( - translate( "commands.computercraft.track.start.stop", - link( text( stopCommand ), stopCommand, translate( "commands.computercraft.track.stop.action" ) ) ) - ) ); - } - } ).register( new SubCommandBase( "stop", UserLevel.OWNER_OP ) - { - @Override - public void execute( @Nonnull CommandContext context, @Nonnull List arguments ) throws CommandException - { - TrackingContext timings = getTimingContext( context ); - if( !timings.stop() ) throw new CommandException( "commands.computercraft.track.stop.not_enabled" ); - displayTimings( context, timings.getImmutableTimings(), TrackingField.AVERAGE_TIME ); - } - } ).register( new SubCommandBase( "dump", UserLevel.OWNER_OP ) - { - @Override - public void execute( @Nonnull CommandContext context, @Nonnull List arguments ) throws CommandException - { - TrackingField field = TrackingField.AVERAGE_TIME; - if( arguments.size() >= 1 ) - { - field = TrackingField.fields().get( arguments.get( 0 ) ); - if( field == null ) - { - throw new CommandException( "commands.computercraft.track.dump.no_field", arguments.get( 0 ) ); - } - } - - displayTimings( context, getTimingContext( context ).getImmutableTimings(), field ); - } - - @Nonnull - @Override - public List getCompletion( @Nonnull CommandContext context, @Nonnull List arguments ) - { - if( arguments.size() == 1 ) - { - String match = arguments.get( 0 ); - - List out = new ArrayList<>(); - for( String key : TrackingField.fields().keySet() ) - { - if( CommandBase.doesStringStartWith( match, key ) ) out.add( key ); - } - - out.sort( Comparator.naturalOrder() ); - return out; - } - else - { - return super.getCompletion( context, arguments ); - } - } - } ) ); - - root.register( new SubCommandBase( "reload", UserLevel.OWNER_OP ) - { - @Override - public void execute( @Nonnull CommandContext context, @Nonnull List arguments ) - { - Config.reload(); - context.getSender().sendMessage( translate( "commands.computercraft.reload.done" ) ); - } - } ); - - root.register( new SubCommandBase( "queue", UserLevel.ANYONE ) - { - @Override - public void execute( @Nonnull CommandContext context, @Nonnull List arguments ) throws CommandException - { - if( arguments.size() < 1 ) throw new CommandException( context.getFullUsage() ); - - String selector = arguments.get( 0 ); - Object[] rest = arguments.subList( 1, arguments.size() ).toArray(); - - boolean found = false; - for( ServerComputer computer : ComputerSelector.getComputers( selector ) ) - { - if( computer.getFamily() != ComputerFamily.Command || !computer.isOn() ) continue; - found = true; - computer.queueEvent( "computer_command", rest ); - } - - if( !found ) - { - throw new CommandException( "commands.computercraft.argument.no_matching", selector ); - } - } - } ); - - return root; + return displayTimings( context.getSource(), sort, fields ); + } ) ) ) + ); } - private static ITextComponent linkComputer( CommandContext context, ServerComputer serverComputer, int computerId ) + private static ITextComponent linkComputer( CommandSource source, ServerComputer serverComputer, int computerId ) { ITextComponent out = new TextComponentString( "" ); @@ -396,7 +279,7 @@ private static ITextComponent linkComputer( CommandContext context, ServerComput out.appendText( " (id " + computerId + ")" ); // And, if we're a player, some useful links - if( serverComputer != null && UserLevel.OP.canExecute( context ) && context.fromPlayer() ) + if( serverComputer != null && UserLevel.OP.test( source ) && isPlayer( source ) ) { out .appendText( " " ) @@ -416,9 +299,9 @@ private static ITextComponent linkComputer( CommandContext context, ServerComput return out; } - private static ITextComponent linkPosition( CommandContext context, ServerComputer computer ) + private static ITextComponent linkPosition( CommandSource context, ServerComputer computer ) { - if( UserLevel.OP.canExecute( context ) ) + if( UserLevel.OP.test( context ) ) { return link( position( computer.getPosition() ), @@ -432,22 +315,23 @@ private static ITextComponent linkPosition( CommandContext context, ServerComput } } - private static TrackingContext getTimingContext( CommandContext context ) + @Nonnull + private static TrackingContext getTimingContext( CommandSource source ) { - Entity entity = context.getSender().getCommandSenderEntity(); - if( entity instanceof EntityPlayerMP ) - { - return Tracking.getContext( entity.getUniqueID() ); - } - else - { - return Tracking.getContext( SYSTEM_UUID ); - } + Entity entity = source.getEntity(); + return entity instanceof EntityPlayer ? Tracking.getContext( entity.getUniqueID() ) : Tracking.getContext( SYSTEM_UUID ); } - private static void displayTimings( CommandContext context, List timings, TrackingField field ) throws CommandException + private static final List DEFAULT_FIELDS = Arrays.asList( TrackingField.TASKS, TrackingField.TOTAL_TIME, TrackingField.AVERAGE_TIME, TrackingField.MAX_TIME ); + + private static int displayTimings( CommandSource source, TrackingField sortField, List fields ) throws CommandSyntaxException { - if( timings.isEmpty() ) throw new CommandException( "commands.computercraft.track.dump.no_timings" ); + return displayTimings( source, getTimingContext( source ).getTimings(), sortField, fields ); + } + + private static int displayTimings( CommandSource source, @Nonnull List timings, @Nonnull TrackingField sortField, @Nonnull List fields ) throws CommandSyntaxException + { + if( timings.isEmpty() ) throw NO_TIMINGS_EXCEPTION.create(); Map lookup = new HashMap<>(); int maxId = 0, maxInstance = 0; @@ -459,74 +343,27 @@ private static void displayTimings( CommandContext context, List maxId ) maxId = server.getID(); } - timings.sort( Comparator.comparing( x -> x.get( field ) ).reversed() ); + timings.sort( Comparator.comparing( x -> x.get( sortField ) ).reversed() ); - boolean defaultLayout = field == TrackingField.TASKS || field == TrackingField.TOTAL_TIME - || field == TrackingField.AVERAGE_TIME || field == TrackingField.MAX_TIME; - - - TableBuilder table = defaultLayout ? new TableBuilder( - TRACK_ID, - translate( "commands.computercraft.track.dump.computer" ), - translate( TrackingField.TASKS.translationKey() ), - translate( TrackingField.TOTAL_TIME.translationKey() ), - translate( TrackingField.AVERAGE_TIME.translationKey() ), - translate( TrackingField.MAX_TIME.translationKey() ) - ) : new TableBuilder( - TRACK_ID, - translate( "commands.computercraft.track.dump.computer" ), - translate( field.translationKey() ) - ); + ITextComponent[] headers = new ITextComponent[1 + fields.size()]; + headers[0] = translate( "commands.computercraft.track.dump.computer" ); + for( int i = 0; i < fields.size(); i++ ) headers[i + 1] = translate( fields.get( i ).translationKey() ); + TableBuilder table = new TableBuilder( TRACK_ID, headers ); for( ComputerTracker entry : timings ) { Computer computer = entry.getComputer(); ServerComputer serverComputer = computer == null ? null : lookup.get( computer ); - ITextComponent computerComponent = linkComputer( context, serverComputer, entry.getComputerId() ); + ITextComponent computerComponent = linkComputer( source, serverComputer, entry.getComputerId() ); - if( defaultLayout ) - { - table.row( - computerComponent, - text( entry.getFormatted( TrackingField.TASKS ) ), - text( entry.getFormatted( TrackingField.TOTAL_TIME ) ), - text( entry.getFormatted( TrackingField.AVERAGE_TIME ) ), - text( entry.getFormatted( TrackingField.MAX_TIME ) ) - ); - } - else - { - table.row( computerComponent, text( entry.getFormatted( field ) ) ); - } + ITextComponent[] row = new ITextComponent[1 + fields.size()]; + row[0] = computerComponent; + for( int i = 0; i < fields.size(); i++ ) row[i + 1] = text( entry.getFormatted( fields.get( i ) ) ); + table.row( row ); } - table.display( context.getSender() ); - } - - private static void withComputers( List selectors, Consumer> action ) throws CommandException - { - Set computers = Sets.newHashSet(); - List failed = new ArrayList<>(); - if( selectors.isEmpty() ) - { - computers.addAll( ComputerCraft.serverComputerRegistry.getComputers() ); - } - else - { - for( String selector : selectors ) - { - List selected = ComputerSelector.getComputers( selector ); - computers.addAll( selected ); - if( selected.isEmpty() ) failed.add( selector ); - } - } - - action.accept( computers ); - - if( !failed.isEmpty() ) - { - throw new CommandException( "commands.computercraft.argument.no_matching", String.join( ", ", failed ) ); - } + table.display( source ); + return timings.size(); } } diff --git a/src/main/java/dan200/computercraft/shared/command/CommandCopy.java b/src/main/java/dan200/computercraft/shared/command/CommandCopy.java index 5e598d8d3..47ede7da2 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandCopy.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandCopy.java @@ -6,73 +6,61 @@ package dan200.computercraft.shared.command; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.command.CommandBase; -import net.minecraft.command.ICommandSender; -import net.minecraft.server.MinecraftServer; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import dan200.computercraft.ComputerCraft; +import net.minecraft.client.Minecraft; +import net.minecraft.command.CommandSource; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.util.text.event.ClickEvent; import net.minecraft.util.text.event.HoverEvent; -import net.minecraftforge.client.IClientCommand; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.ClientChatEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; -import javax.annotation.Nonnull; +import static net.minecraft.command.Commands.argument; +import static net.minecraft.command.Commands.literal; -public final class CommandCopy extends CommandBase implements IClientCommand +@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) +public final class CommandCopy { - public static final CommandCopy INSTANCE = new CommandCopy(); - - /** - * We start with a "~" so we're less likely to show up on completions. - */ - private static final String NAME = "~computercraft_copy"; + private static final String PREFIX = "/computercraft copy "; private CommandCopy() { } - @Override - public boolean allowUsageWithoutPrefix( ICommandSender sender, String message ) + public static void register( CommandDispatcher registry ) { - return false; + registry.register( literal( "computercraft" ) + .then( literal( "copy" ) ) + .then( argument( "message", StringArgumentType.greedyString() ) ) + .executes( context -> { + Minecraft.getInstance().keyboardListener.setClipboardString( context.getArgument( "message", String.class ) ); + return 1; + } ) + ); } - @Nonnull - @Override - public String getName() + @SubscribeEvent + public static void onClientSendMessage( ClientChatEvent event ) { - return NAME; - } - - @Nonnull - @Override - public String getUsage( @Nonnull ICommandSender sender ) - { - return "/" + NAME + " "; - } - - @Override - public int getRequiredPermissionLevel() - { - return 0; - } - - @Override - @SideOnly( Side.CLIENT ) - public void execute( @Nonnull MinecraftServer server, @Nonnull ICommandSender sender, @Nonnull String[] args ) - { - String message = String.join( " ", args ); - if( !message.isEmpty() ) GuiScreen.setClipboardString( message ); + // Emulate the command on the client side + if( event.getMessage().startsWith( PREFIX ) ) + { + Minecraft.getInstance().keyboardListener.setClipboardString( event.getMessage().substring( PREFIX.length() ) ); + event.setCanceled( true ); + } } public static ITextComponent createCopyText( String text ) { TextComponentString name = new TextComponentString( text ); name.getStyle() - .setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/" + NAME + " " + text ) ) + .setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, PREFIX + text ) ) .setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TextComponentTranslation( "gui.computercraft.tooltip.copy" ) ) ); return name; } diff --git a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java index 73061cb97..378c4d623 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java @@ -6,18 +6,65 @@ package dan200.computercraft.shared.command; -import net.minecraft.command.ICommandSender; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.command.CommandSource; +import net.minecraft.command.ISuggestionProvider; +import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.common.util.FakePlayer; +import java.util.Arrays; +import java.util.Locale; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; + public final class CommandUtils { private CommandUtils() {} - public static boolean isPlayer( ICommandSender sender ) + public static boolean isPlayer( CommandSource output ) { + Entity sender = output.getEntity(); return sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer) && ((EntityPlayerMP) sender).connection != null; } + + @SuppressWarnings( "unchecked" ) + public static CompletableFuture suggestOnServer( CommandContext context, SuggestionsBuilder builder, Function, CompletableFuture> supplier ) + { + Object source = context.getSource(); + if( !(source instanceof ISuggestionProvider) ) + { + return Suggestions.empty(); + } + else if( source instanceof CommandSource ) + { + return supplier.apply( (CommandContext) context ); + } + else + { + return ((ISuggestionProvider) source).getSuggestionsFromServer( (CommandContext) context, builder ); + } + } + + public static CompletableFuture suggest( SuggestionsBuilder builder, Iterable candidates, Function toString ) + { + String remaining = builder.getRemaining().toLowerCase( Locale.ROOT ); + for( T choice : candidates ) + { + String name = toString.apply( choice ); + if( !name.toLowerCase( Locale.ROOT ).startsWith( remaining ) ) continue; + builder.suggest( name ); + } + + return builder.buildFuture(); + } + + public static CompletableFuture suggest( SuggestionsBuilder builder, T[] candidates, Function toString ) + { + return suggest( builder, Arrays.asList( candidates ), toString ); + } } diff --git a/src/main/java/dan200/computercraft/shared/command/ComputerSelector.java b/src/main/java/dan200/computercraft/shared/command/ComputerSelector.java deleted file mode 100644 index 444fa6596..000000000 --- a/src/main/java/dan200/computercraft/shared/command/ComputerSelector.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * 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.shared.command; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.core.ServerComputer; -import net.minecraft.command.CommandException; - -import java.util.*; -import java.util.function.Predicate; - -final class ComputerSelector -{ - private ComputerSelector() {} - - private static List getComputers( Predicate predicate ) - { - // We copy it to prevent concurrent modifications. - ArrayList computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() ); - computers.removeIf( predicate.negate() ); - return computers; - } - - static ServerComputer getComputer( String selector ) throws CommandException - { - List computers = getComputers( selector ); - if( computers.isEmpty() ) - { - throw new CommandException( "commands.computercraft.argument.no_matching", selector ); - } - else if( computers.size() == 1 ) - { - return computers.get( 0 ); - } - else - { - StringBuilder builder = new StringBuilder(); - - for( int i = 0; i < computers.size(); i++ ) - { - if( i > 0 ) builder.append( ", " ); - builder.append( computers.get( i ).getInstanceID() ); - } - - throw new CommandException( "commands.computercraft.argument.many_matching", selector, builder.toString() ); - } - } - - static List getComputers( String selector ) throws CommandException - { - if( !selector.isEmpty() && selector.charAt( 0 ) == '#' ) - { - selector = selector.substring( 1 ); - - int id; - try - { - id = Integer.parseInt( selector ); - } - catch( NumberFormatException e ) - { - throw new CommandException( "commands.computercraft.argument.not_number", selector ); - } - - return getComputers( x -> x.getID() == id ); - } - else if( !selector.isEmpty() && selector.charAt( 0 ) == '@' ) - { - String label = selector.substring( 1 ); - return getComputers( x -> Objects.equals( label, x.getLabel() ) ); - } - else if( !selector.isEmpty() && selector.charAt( 0 ) == '~' ) - { - String familyName = selector.substring( 1 ); - return getComputers( x -> x.getFamily().name().equalsIgnoreCase( familyName ) ); - } - else - { - int instance; - try - { - instance = Integer.parseInt( selector ); - } - catch( NumberFormatException e ) - { - throw new CommandException( "commands.computercraft.argument.not_number", selector ); - } - - ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instance ); - return computer == null ? Collections.emptyList() : Collections.singletonList( computer ); - } - } - - static List completeComputer( String selector ) - { - TreeSet options = Sets.newTreeSet(); - - // We copy it to prevent concurrent modifications. - List computers = Lists.newArrayList( ComputerCraft.serverComputerRegistry.getComputers() ); - - if( !selector.isEmpty() && selector.charAt( 0 ) == '#' ) - { - selector = selector.substring( 1 ); - - for( ServerComputer computer : computers ) - { - String id = Integer.toString( computer.getID() ); - if( id.startsWith( selector ) ) options.add( "#" + id ); - } - } - else if( !selector.isEmpty() && selector.charAt( 0 ) == '@' ) - { - String label = selector.substring( 1 ); - for( ServerComputer computer : computers ) - { - String thisLabel = computer.getLabel(); - if( thisLabel != null && thisLabel.startsWith( label ) ) options.add( "@" + thisLabel ); - } - } - else if( !selector.isEmpty() && selector.charAt( 0 ) == '~' ) - { - String familyName = selector.substring( 1 ).toLowerCase( Locale.ENGLISH ); - for( ComputerFamily family : ComputerFamily.values() ) - { - if( family.name().toLowerCase( Locale.ENGLISH ).startsWith( familyName ) ) - { - options.add( "~" + family.name() ); - } - } - } - else - { - for( ServerComputer computer : computers ) - { - String id = Integer.toString( computer.getInstanceID() ); - if( id.startsWith( selector ) ) options.add( id ); - } - } - - if( options.size() > 100 ) - { - ArrayList result = Lists.newArrayListWithCapacity( 100 ); - for( String element : options ) - { - if( result.size() > 100 ) break; - result.add( element ); - } - - return result; - } - else - { - return Lists.newArrayList( options ); - } - } -} diff --git a/src/main/java/dan200/computercraft/shared/command/Exceptions.java b/src/main/java/dan200/computercraft/shared/command/Exceptions.java new file mode 100644 index 000000000..a1a45b802 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/command/Exceptions.java @@ -0,0 +1,43 @@ +/* + * 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.shared.command; + +import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import net.minecraft.util.text.TextComponentTranslation; + +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" ); + + 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 TP_NOT_THERE = translated( "commands.computercraft.tp.not_there" ); + 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 ) + { + return new SimpleCommandExceptionType( new TextComponentTranslation( key ) ); + } + + private static DynamicCommandExceptionType translated1( String key ) + { + return new DynamicCommandExceptionType( x -> new TextComponentTranslation( key, x ) ); + } + + private static Dynamic2CommandExceptionType translated2( String key ) + { + return new Dynamic2CommandExceptionType( ( x, y ) -> new TextComponentTranslation( key, x, y ) ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/command/UserLevel.java b/src/main/java/dan200/computercraft/shared/command/UserLevel.java index 52eddde4b..7a24bc1fe 100644 --- a/src/main/java/dan200/computercraft/shared/command/UserLevel.java +++ b/src/main/java/dan200/computercraft/shared/command/UserLevel.java @@ -6,15 +6,17 @@ package dan200.computercraft.shared.command; -import dan200.computercraft.shared.command.framework.CommandContext; -import net.minecraft.command.ICommandSender; -import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.command.CommandSource; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.server.MinecraftServer; +import java.util.function.Predicate; + /** * The level a user must be at in order to execute a command. */ -public enum UserLevel +public enum UserLevel implements Predicate { /** * Only can be used by the owner of the server: namely the server console or the player in SSP. @@ -51,20 +53,21 @@ public int toLevel() } } - public boolean canExecute( CommandContext context ) + @Override + public boolean test( CommandSource source ) { if( this == ANYONE ) return true; // We *always* allow level 0 stuff, even if the - MinecraftServer server = context.getServer(); - ICommandSender sender = context.getSender(); + MinecraftServer server = source.getServer(); + Entity sender = source.getEntity(); - if( server.isSinglePlayer() && sender instanceof EntityPlayerMP && - ((EntityPlayerMP) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerOwner() ) ) + if( server.isSinglePlayer() && sender instanceof EntityPlayer && + ((EntityPlayer) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ) ) { if( this == OWNER || this == OWNER_OP ) return true; } - return sender.canUseCommand( toLevel(), context.getRootCommand() ); + return source.hasPermissionLevel( toLevel() ); } } diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java b/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java new file mode 100644 index 000000000..ad8837024 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java @@ -0,0 +1,41 @@ +/* + * 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.shared.command.arguments; + +import com.mojang.brigadier.arguments.ArgumentType; +import dan200.computercraft.ComputerCraft; +import net.minecraft.command.arguments.ArgumentSerializer; +import net.minecraft.command.arguments.ArgumentTypes; +import net.minecraft.command.arguments.IArgumentSerializer; +import net.minecraft.util.ResourceLocation; + +public final class ArgumentSerializers +{ + @SuppressWarnings( "unchecked" ) + private static > void registerUnsafe( ResourceLocation id, Class type, IArgumentSerializer serializer ) + { + ArgumentTypes.register( id, type, (IArgumentSerializer) serializer ); + } + + private static > void register( ResourceLocation id, Class type, IArgumentSerializer serializer ) + { + ArgumentTypes.register( id, type, serializer ); + } + + private static > void register( ResourceLocation id, T instance ) + { + registerUnsafe( id, instance.getClass(), new ArgumentSerializer<>( () -> 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() ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ChoiceArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ChoiceArgumentType.java new file mode 100644 index 000000000..16d8f8f26 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ChoiceArgumentType.java @@ -0,0 +1,75 @@ +/* + * 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.shared.command.arguments; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; + +public abstract class ChoiceArgumentType implements ArgumentType +{ + private final Iterable choices; + private final Function name; + private final Function tooltip; + private final DynamicCommandExceptionType exception; + + protected ChoiceArgumentType( Iterable choices, Function name, Function tooltip, DynamicCommandExceptionType exception ) + { + this.choices = choices; + this.name = name; + this.tooltip = tooltip; + this.exception = exception; + } + + @Override + public T parse( StringReader reader ) throws CommandSyntaxException + { + int start = reader.getCursor(); + String name = reader.readUnquotedString(); + + for( T choice : choices ) + { + String choiceName = this.name.apply( choice ); + if( name.equals( choiceName ) ) return choice; + } + + reader.setCursor( start ); + throw exception.createWithContext( reader, name ); + } + + @Override + public CompletableFuture listSuggestions( CommandContext context, SuggestionsBuilder builder ) + { + String remaining = builder.getRemaining().toLowerCase( Locale.ROOT ); + for( T choice : choices ) + { + String name = this.name.apply( choice ); + if( !name.toLowerCase( Locale.ROOT ).startsWith( remaining ) ) continue; + builder.suggest( name, tooltip.apply( choice ) ); + } + + return builder.buildFuture(); + } + + @Override + public Collection getExamples() + { + List items = choices instanceof Collection ? new ArrayList<>( ((Collection) choices).size() ) : new ArrayList<>(); + for( T choice : choices ) items.add( name.apply( choice ) ); + items.sort( Comparator.naturalOrder() ); + return items; + } +} diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java new file mode 100644 index 000000000..cd07d381b --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java @@ -0,0 +1,94 @@ +/* + * 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.shared.command.arguments; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import dan200.computercraft.shared.command.arguments.ComputersArgumentType.ComputersSupplier; +import dan200.computercraft.shared.computer.core.ServerComputer; +import net.minecraft.command.CommandSource; + +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import static dan200.computercraft.shared.command.Exceptions.COMPUTER_ARG_MANY; + +public final class ComputerArgumentType implements ArgumentType +{ + private static final ComputerArgumentType INSTANCE = new ComputerArgumentType(); + + public static ComputerArgumentType oneComputer() + { + return INSTANCE; + } + + public static ServerComputer getComputerArgument( CommandContext context, String name ) throws CommandSyntaxException + { + return context.getArgument( name, ComputerSupplier.class ).unwrap( context.getSource() ); + } + + private ComputerArgumentType() + { + } + + @Override + public ComputerSupplier parse( StringReader reader ) throws CommandSyntaxException + { + int start = reader.getCursor(); + ComputersSupplier supplier = ComputersArgumentType.someComputers().parse( reader ); + String selector = reader.getString().substring( start, reader.getCursor() ); + + return s -> { + Collection computers = supplier.unwrap( s ); + + if( computers.size() == 1 ) return computers.iterator().next(); + + StringBuilder builder = new StringBuilder(); + boolean first = true; + for( ServerComputer computer : computers ) + { + if( first ) + { + first = false; + } + else + { + builder.append( ", " ); + } + + builder.append( computer.getInstanceID() ); + } + + + // We have an incorrect number of computers: reset and throw an error + reader.setCursor( start ); + throw COMPUTER_ARG_MANY.createWithContext( reader, selector, builder.toString() ); + }; + } + + @Override + public CompletableFuture listSuggestions( CommandContext context, SuggestionsBuilder builder ) + { + return ComputersArgumentType.someComputers().listSuggestions( context, builder ); + } + + @Override + public Collection getExamples() + { + return ComputersArgumentType.someComputers().getExamples(); + } + + @FunctionalInterface + public interface ComputerSupplier + { + ServerComputer unwrap( CommandSource source ) throws CommandSyntaxException; + } +} diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java new file mode 100644 index 000000000..a89f7a74c --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java @@ -0,0 +1,210 @@ +/* + * 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.shared.command.arguments; + +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.ServerComputer; +import net.minecraft.command.CommandSource; +import net.minecraft.command.arguments.IArgumentSerializer; +import net.minecraft.network.PacketBuffer; + +import javax.annotation.Nonnull; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static dan200.computercraft.shared.command.CommandUtils.suggest; +import static dan200.computercraft.shared.command.CommandUtils.suggestOnServer; +import static dan200.computercraft.shared.command.Exceptions.COMPUTER_ARG_NONE; + +public final class ComputersArgumentType implements ArgumentType +{ + private static final ComputersArgumentType MANY = new ComputersArgumentType( false ); + private static final ComputersArgumentType SOME = new ComputersArgumentType( true ); + + private static final List EXAMPLES = Arrays.asList( + "0", "#0", "@Label", "~Advanced" + ); + + public static ComputersArgumentType manyComputers() + { + return MANY; + } + + public static ComputersArgumentType someComputers() + { + return SOME; + } + + public static Collection getComputersArgument( CommandContext context, String name ) throws CommandSyntaxException + { + return context.getArgument( name, ComputersSupplier.class ).unwrap( context.getSource() ); + } + + private final boolean requireSome; + + private ComputersArgumentType( boolean requireSome ) + { + this.requireSome = requireSome; + } + + @Override + public ComputersSupplier parse( StringReader reader ) throws CommandSyntaxException + { + int start = reader.getCursor(); + char kind = reader.peek(); + ComputersSupplier computers; + if( kind == '@' ) + { + reader.skip(); + String label = reader.readUnquotedString(); + computers = getComputers( x -> Objects.equals( label, x.getLabel() ) ); + } + else if( kind == '~' ) + { + reader.skip(); + String family = reader.readUnquotedString(); + computers = getComputers( x -> x.getFamily().name().equalsIgnoreCase( family ) ); + } + else if( kind == '#' ) + { + reader.skip(); + int id = reader.readInt(); + computers = getComputers( x -> x.getID() == id ); + } + else + { + int instance = reader.readInt(); + computers = s -> { + ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instance ); + return computer == null ? Collections.emptyList() : Collections.singletonList( computer ); + }; + } + + if( requireSome ) + { + String selector = reader.getString().substring( start, reader.getCursor() ); + return source -> { + Collection matched = computers.unwrap( source ); + if( matched.isEmpty() ) throw COMPUTER_ARG_NONE.create( selector ); + return matched; + }; + } + else + { + return computers; + } + } + + @Override + public CompletableFuture listSuggestions( CommandContext context, SuggestionsBuilder builder ) + { + String remaining = builder.getRemaining(); + + // We can run this one on the client, for obvious reasons. + if( remaining.startsWith( "~" ) ) + { + return suggest( builder, ComputerFamily.values(), x -> "~" + x.name() ); + } + + // Verify we've a command source and we're running on the server + return suggestOnServer( context, builder, s -> { + if( remaining.startsWith( "@" ) ) + { + suggestComputers( builder, remaining, x -> { + String label = x.getLabel(); + return label == null ? null : "@" + label; + } ); + } + else if( remaining.startsWith( "#" ) ) + { + suggestComputers( builder, remaining, c -> "#" + c.getID() ); + } + else + { + suggestComputers( builder, remaining, c -> Integer.toString( c.getInstanceID() ) ); + } + + return builder.buildFuture(); + } ); + } + + @Override + public Collection getExamples() + { + return EXAMPLES; + } + + private static void suggestComputers( SuggestionsBuilder builder, String remaining, Function renderer ) + { + remaining = remaining.toLowerCase( Locale.ROOT ); + for( ServerComputer computer : ComputerCraft.serverComputerRegistry.getComputers() ) + { + String converted = renderer.apply( computer ); + if( converted != null && converted.toLowerCase( Locale.ROOT ).startsWith( remaining ) ) + { + builder.suggest( converted ); + } + } + } + + private static ComputersSupplier getComputers( Predicate predicate ) + { + return s -> Collections.unmodifiableList( ComputerCraft.serverComputerRegistry + .getComputers() + .stream() + .filter( predicate ) + .collect( Collectors.toList() ) + ); + } + + public static class Serializer implements IArgumentSerializer + { + + @Override + public void write( @Nonnull ComputersArgumentType arg, @Nonnull PacketBuffer buf ) + { + buf.writeBoolean( arg.requireSome ); + } + + @Nonnull + @Override + public ComputersArgumentType read( @Nonnull PacketBuffer buf ) + { + return buf.readBoolean() ? SOME : MANY; + } + + @Override + public void write( @Nonnull ComputersArgumentType arg, @Nonnull JsonObject json ) + { + json.addProperty( "requireSome", arg.requireSome ); + } + } + + @FunctionalInterface + public interface ComputersSupplier + { + Collection unwrap( CommandSource source ) throws CommandSyntaxException; + } + + public static Set unwrap( CommandSource source, Collection suppliers ) throws CommandSyntaxException + { + Set computers = new HashSet<>(); + for( ComputersSupplier supplier : suppliers ) computers.addAll( supplier.unwrap( source ) ); + return computers; + } +} diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java new file mode 100644 index 000000000..6311ffd07 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java @@ -0,0 +1,166 @@ +/* + * 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.shared.command.arguments; + +import com.google.gson.JsonObject; +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.command.arguments.ArgumentTypes; +import net.minecraft.command.arguments.IArgumentSerializer; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentString; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; + +/** + * 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 argument while there is input remaining. + * + * One problem with how parsers function, is that they must consume some input: and thus we + * + * @param The type of each value returned + * @param The type of the inner parser. This will normally be a {@link List} or {@code T}. + */ +public final class RepeatArgumentType implements ArgumentType> +{ + private final ArgumentType child; + private final BiConsumer, U> appender; + private final boolean flatten; + private final SimpleCommandExceptionType some; + + private RepeatArgumentType( ArgumentType child, BiConsumer, U> appender, boolean flatten, SimpleCommandExceptionType some ) + { + this.child = child; + this.appender = appender; + this.flatten = flatten; + this.some = some; + } + + public static RepeatArgumentType some( ArgumentType appender, SimpleCommandExceptionType missing ) + { + return new RepeatArgumentType<>( appender, List::add, true, missing ); + } + + public static RepeatArgumentType> someFlat( ArgumentType> appender, SimpleCommandExceptionType missing ) + { + return new RepeatArgumentType<>( appender, List::addAll, true, missing ); + } + + @Override + public List parse( StringReader reader ) throws CommandSyntaxException + { + boolean hadSome = false; + List out = new ArrayList<>(); + while( true ) + { + reader.skipWhitespace(); + if( !reader.canRead() ) break; + + int startParse = reader.getCursor(); + appender.accept( out, child.parse( reader ) ); + hadSome = true; + + if( reader.getCursor() == startParse ) + { + throw new IllegalStateException( child + " did not consume any input on " + reader.getRemaining() ); + } + } + + // Note that each child may return an empty list, we just require that some actual input + // was consumed. + // We should probably review that this is sensible in the future. + if( !hadSome ) throw some.createWithContext( reader ); + + return Collections.unmodifiableList( out ); + } + + @Override + public CompletableFuture listSuggestions( CommandContext context, SuggestionsBuilder builder ) + { + StringReader reader = new StringReader( builder.getInput() ); + reader.setCursor( builder.getStart() ); + int previous = reader.getCursor(); + while( reader.canRead() ) + { + try + { + child.parse( reader ); + } + catch( CommandSyntaxException e ) + { + break; + } + + int cursor = reader.getCursor(); + reader.skipWhitespace(); + if( cursor == reader.getCursor() ) break; + previous = reader.getCursor(); + } + + reader.setCursor( previous ); + return child.listSuggestions( context, builder.createOffset( previous ) ); + } + + @Override + public Collection getExamples() + { + return child.getExamples(); + } + + public static class Serializer implements IArgumentSerializer> + { + @Override + public void write( @Nonnull RepeatArgumentType arg, @Nonnull PacketBuffer buf ) + { + buf.writeBoolean( arg.flatten ); + ArgumentTypes.serialize( buf, arg.child ); + buf.writeTextComponent( getMessage( arg ) ); + } + + @Nonnull + @Override + @SuppressWarnings( { "unchecked", "rawtypes" } ) + public RepeatArgumentType read( @Nonnull PacketBuffer buf ) + { + boolean isList = buf.readBoolean(); + ArgumentType child = ArgumentTypes.deserialize( buf ); + ITextComponent message = buf.readTextComponent(); + BiConsumer, ?> appender = isList ? ( list, x ) -> list.addAll( (Collection) x ) : List::add; + return new RepeatArgumentType( child, appender, isList, new SimpleCommandExceptionType( message ) ); + } + + @Override + public void write( @Nonnull RepeatArgumentType arg, @Nonnull JsonObject json ) + { + json.addProperty( "flatten", arg.flatten ); + json.addProperty( "child", "<>" ); // TODO: Potentially serialize this using reflection. + json.addProperty( "error", ITextComponent.Serializer.toJson( getMessage( arg ) ) ); + } + + private static ITextComponent getMessage( RepeatArgumentType arg ) + { + Message message = arg.some.create().getRawMessage(); + if( message instanceof ITextComponent ) return (ITextComponent) message; + return new TextComponentString( message.getString() ); + } + } +} diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/TrackingFieldArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/TrackingFieldArgumentType.java new file mode 100644 index 000000000..209a8d343 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/command/arguments/TrackingFieldArgumentType.java @@ -0,0 +1,27 @@ +/* + * 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.shared.command.arguments; + +import dan200.computercraft.core.tracking.TrackingField; +import dan200.computercraft.shared.command.Exceptions; + +import static dan200.computercraft.shared.command.text.ChatHelpers.translate; + +public final class TrackingFieldArgumentType extends ChoiceArgumentType +{ + private static final TrackingFieldArgumentType INSTANCE = new TrackingFieldArgumentType(); + + private TrackingFieldArgumentType() + { + super( TrackingField.fields().values(), TrackingField::id, x -> translate( x.translationKey() ), Exceptions.TRACKING_FIELD_ARG_NONE ); + } + + public static TrackingFieldArgumentType trackingField() + { + return INSTANCE; + } +} diff --git a/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java b/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java new file mode 100644 index 000000000..97d08d27c --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java @@ -0,0 +1,20 @@ +/* + * 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.shared.command.builder; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +/** + * A {@link Command} which accepts an argument + */ +@FunctionalInterface +public interface ArgCommand +{ + int run( CommandContext ctx, T arg ) throws CommandSyntaxException; +} diff --git a/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java new file mode 100644 index 000000000..bb1e607ab --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java @@ -0,0 +1,126 @@ +/* + * 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.shared.command.builder; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.tree.CommandNode; +import dan200.computercraft.shared.command.arguments.RepeatArgumentType; +import net.minecraft.command.CommandSource; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import static dan200.computercraft.shared.command.Exceptions.ARGUMENT_EXPECTED; +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. + */ +public class CommandBuilder implements CommandNodeBuilder> +{ + private List> args = new ArrayList<>(); + private Predicate requires; + + public static CommandBuilder args() + { + return new CommandBuilder<>(); + } + + public static CommandBuilder command( String literal ) + { + CommandBuilder builder = new CommandBuilder<>(); + builder.args.add( literal( literal ) ); + return builder; + } + + public CommandBuilder requires( Predicate predicate ) + { + requires = requires == null ? predicate : requires.and( predicate ); + return this; + } + + public CommandBuilder arg( String name, ArgumentType type ) + { + args.add( RequiredArgumentBuilder.argument( name, type ) ); + return this; + } + + public CommandNodeBuilder>> argManyValue( String name, ArgumentType type, List empty ) + { + return argMany( name, type, () -> empty ); + } + + public CommandNodeBuilder>> argManyValue( String name, ArgumentType type, T defaultValue ) + { + return argManyValue( name, type, Collections.singletonList( defaultValue ) ); + } + + public CommandNodeBuilder>> argMany( String name, ArgumentType type, Supplier> empty ) + { + return argMany( name, RepeatArgumentType.some( type, ARGUMENT_EXPECTED ), empty ); + } + + public CommandNodeBuilder>> argManyFlatten( String name, ArgumentType> type, Supplier> empty ) + { + return argMany( name, RepeatArgumentType.someFlat( type, ARGUMENT_EXPECTED ), empty ); + } + + private CommandNodeBuilder>> argMany( String name, RepeatArgumentType type, Supplier> empty ) + { + if( args.isEmpty() ) throw new IllegalStateException( "Cannot have empty arg chain builder" ); + + return command -> { + // The node for no arguments + ArgumentBuilder tail = tail( ctx -> command.run( ctx, empty.get() ) ); + + // The node for one or more arguments + ArgumentBuilder moreArg = RequiredArgumentBuilder + .>argument( name, type ) + .executes( ctx -> command.run( ctx, getList( ctx, name ) ) ); + + // Chain all of them together! + tail.then( moreArg ); + return link( tail ); + }; + } + + @SuppressWarnings( "unchecked" ) + private static List getList( CommandContext context, String name ) + { + return (List) context.getArgument( name, List.class ); + } + + @Override + public CommandNode executes( Command command ) + { + if( args.isEmpty() ) throw new IllegalStateException( "Cannot have empty arg chain builder" ); + + return link( tail( command ) ); + } + + private ArgumentBuilder tail( Command command ) + { + ArgumentBuilder defaultTail = args.get( args.size() - 1 ); + defaultTail.executes( command ); + if( requires != null ) defaultTail.requires( requires ); + return defaultTail; + } + + private CommandNode link( ArgumentBuilder tail ) + { + for( int i = args.size() - 2; i >= 0; i-- ) tail = args.get( i ).then( tail ); + return tail.build(); + } +} diff --git a/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java new file mode 100644 index 000000000..4b34ca483 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java @@ -0,0 +1,24 @@ +/* + * 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.shared.command.builder; + +import com.mojang.brigadier.tree.CommandNode; + +/** + * A builder which generates a {@link CommandNode} from the provided action. + */ +@FunctionalInterface +public interface CommandNodeBuilder +{ + /** + * Generate a command node which executes this command. + * + * @param command The command to run + * @return The constructed node. + */ + CommandNode executes( T command ); +} diff --git a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java new file mode 100644 index 000000000..6fa685443 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java @@ -0,0 +1,205 @@ +/* + * 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.shared.command.builder; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.tree.CommandNode; +import com.mojang.brigadier.tree.LiteralCommandNode; +import net.minecraft.command.CommandSource; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.event.ClickEvent; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Collection; + +import static dan200.computercraft.shared.command.text.ChatHelpers.coloured; +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 given. + */ +public final class HelpingArgumentBuilder extends LiteralArgumentBuilder +{ + private final Collection children = new ArrayList<>(); + + private HelpingArgumentBuilder( String literal ) + { + super( literal ); + } + + public static HelpingArgumentBuilder choice( String literal ) + { + return new HelpingArgumentBuilder( literal ); + } + + @Override + public LiteralArgumentBuilder executes( final Command command ) + { + throw new IllegalStateException( "Cannot use executes on a HelpingArgumentBuilder" ); + } + + @Override + public LiteralArgumentBuilder then( final ArgumentBuilder argument ) + { + if( getRedirect() != null ) throw new IllegalStateException( "Cannot add children to a redirected node" ); + + if( argument instanceof HelpingArgumentBuilder ) + { + children.add( (HelpingArgumentBuilder) argument ); + } + else if( argument instanceof LiteralArgumentBuilder ) + { + super.then( argument ); + } + else + { + throw new IllegalStateException( "HelpingArgumentBuilder can only accept literal children" ); + } + + return this; + } + + @Override + public LiteralArgumentBuilder then( CommandNode argument ) + { + if( !(argument instanceof LiteralCommandNode) ) + { + throw new IllegalStateException( "HelpingArgumentBuilder can only accept literal children" ); + } + return super.then( argument ); + } + + @Override + public LiteralCommandNode build() + { + return buildImpl( getLiteral().replace( '-', '_' ), getLiteral() ); + } + + private LiteralCommandNode build( @Nonnull String id, @Nonnull String command ) + { + return buildImpl( id + "." + getLiteral().replace( '-', '_' ), command + " " + getLiteral() ); + } + + private LiteralCommandNode buildImpl( String id, String command ) + { + HelpCommand helpCommand = new HelpCommand( id, command ); + LiteralCommandNode node = new LiteralCommandNode<>( getLiteral(), helpCommand, getRequirement(), getRedirect(), getRedirectModifier(), isFork() ); + helpCommand.node = node; + + // Set up a /... help command + LiteralArgumentBuilder helpNode = LiteralArgumentBuilder.literal( "help" ) + .requires( x -> getArguments().stream().anyMatch( y -> y.getRequirement().test( x ) ) ) + .executes( helpCommand ); + + // Add all normal command children to this and the help node + for( CommandNode child : getArguments() ) + { + node.addChild( child ); + + helpNode.then( LiteralArgumentBuilder.literal( child.getName() ) + .requires( child.getRequirement() ) + .executes( helpForChild( child, id, command ) ) + .build() + ); + } + + // And add alternative versions of which forward instead + for( HelpingArgumentBuilder childBuilder : children ) + { + LiteralCommandNode child = childBuilder.build( id, command ); + node.addChild( child ); + helpNode.then( LiteralArgumentBuilder.literal( child.getName() ) + .requires( child.getRequirement() ) + .executes( helpForChild( child, id, command ) ) + .redirect( child.getChild( "help" ) ) + .build() + ); + } + + node.addChild( helpNode.build() ); + + return node; + } + + private static final TextFormatting HEADER = TextFormatting.LIGHT_PURPLE; + private static final TextFormatting SYNOPSIS = TextFormatting.AQUA; + private static final TextFormatting NAME = TextFormatting.GREEN; + + private static final class HelpCommand implements Command + { + private final String id; + private final String command; + LiteralCommandNode node; + + private HelpCommand( String id, String command ) + { + this.id = id; + this.command = command; + } + + @Override + public int run( CommandContext context ) + { + context.getSource().sendFeedback( getHelp( context, node, id, command ), false ); + return 0; + } + } + + private static Command helpForChild( CommandNode node, String id, String command ) + { + return context -> { + context.getSource().sendFeedback( getHelp( context, node, id + "." + node.getName().replace( '-', '_' ), command + " " + node.getName() ), false ); + return 0; + }; + } + + private static ITextComponent getHelp( CommandContext context, CommandNode 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 dispatcher = context.getSource().getServer().getCommandManager().getDispatcher(); + CommandNode 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() ); + + ITextComponent output = new TextComponentString( "" ) + .appendSibling( coloured( "/" + command + usage, HEADER ) ) + .appendText( " " ) + .appendSibling( coloured( translate( "commands." + id + ".synopsis" ), SYNOPSIS ) ) + .appendText( "\n" ) + .appendSibling( translate( "commands." + id + ".desc" ) ); + + for( CommandNode child : node.getChildren() ) + { + if( !child.getRequirement().test( context.getSource() ) || !(child instanceof LiteralCommandNode) ) + { + continue; + } + + output.appendText( "\n" ); + + ITextComponent component = coloured( child.getName(), NAME ); + component.getStyle().setClickEvent( new ClickEvent( + ClickEvent.Action.SUGGEST_COMMAND, + "/" + command + " " + child.getName() + ) ); + output.appendSibling( component ); + + output.appendText( " - " ).appendSibling( translate( "commands." + id + "." + child.getName() + ".synopsis" ) ); + } + + return output; + } +} diff --git a/src/main/java/dan200/computercraft/shared/command/framework/CommandContext.java b/src/main/java/dan200/computercraft/shared/command/framework/CommandContext.java deleted file mode 100644 index c6c6e4d4a..000000000 --- a/src/main/java/dan200/computercraft/shared/command/framework/CommandContext.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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.shared.command.framework; - -import com.google.common.collect.Lists; -import dan200.computercraft.shared.util.StringUtil; -import net.minecraft.command.ICommandSender; -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.server.MinecraftServer; -import net.minecraftforge.common.util.FakePlayer; - -import java.util.Collections; -import java.util.List; - -/** - * Represents the way a command was invoked, including the command sender, the current server and - * the "path" to this command. - */ -public final class CommandContext -{ - private final MinecraftServer server; - private final ICommandSender sender; - private final List path; - - public CommandContext( MinecraftServer server, ICommandSender sender, ISubCommand initial ) - { - this.server = server; - this.sender = sender; - path = Collections.singletonList( initial ); - } - - private CommandContext( MinecraftServer server, ICommandSender sender, List path ) - { - this.server = server; - this.sender = sender; - this.path = path; - } - - public CommandContext enter( ISubCommand child ) - { - List newPath = Lists.newArrayListWithExpectedSize( path.size() + 1 ); - newPath.addAll( path ); - newPath.add( child ); - return new CommandContext( server, sender, newPath ); - } - - public CommandContext parent() - { - if( path.size() == 1 ) throw new IllegalStateException( "No parent command" ); - return new CommandContext( server, sender, path.subList( 0, path.size() - 1 ) ); - } - - public String getFullPath() - { - StringBuilder out = new StringBuilder(); - boolean first = true; - for( ISubCommand command : path ) - { - if( first ) - { - first = false; - } - else - { - out.append( ' ' ); - } - - out.append( command.getName() ); - } - - return out.toString(); - } - - public String getFullUsage() - { - return "/" + getFullPath() + " " + StringUtil.translate( path.get( path.size() - 1 ).getUsage( this ) ); - } - - public List getPath() - { - return Collections.unmodifiableList( path ); - } - - public String getRootCommand() - { - return path.get( 0 ).getName(); - } - - public MinecraftServer getServer() - { - return server; - } - - public ICommandSender getSender() - { - return sender; - } - - public boolean fromPlayer() - { - return sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer); - } -} diff --git a/src/main/java/dan200/computercraft/shared/command/framework/CommandDelegate.java b/src/main/java/dan200/computercraft/shared/command/framework/CommandDelegate.java deleted file mode 100644 index ef26a5e2f..000000000 --- a/src/main/java/dan200/computercraft/shared/command/framework/CommandDelegate.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.shared.command.framework; - -import dan200.computercraft.ComputerCraft; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommand; -import net.minecraft.command.ICommandSender; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.math.BlockPos; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * {@link ICommand} which delegates to a {@link ISubCommand}. - */ -public class CommandDelegate implements ICommand -{ - private final ISubCommand command; - - public CommandDelegate( ISubCommand command ) - { - this.command = command; - } - - @Nonnull - @Override - public String getName() - { - return command.getName(); - } - - @Nonnull - @Override - public String getUsage( @Nonnull ICommandSender sender ) - { - return new CommandContext( sender.getServer(), sender, command ).getFullUsage(); - } - - @Nonnull - @Override - public List getAliases() - { - return Collections.emptyList(); - } - - @Override - public void execute( @Nonnull MinecraftServer server, @Nonnull ICommandSender sender, @Nonnull String[] args ) throws CommandException - { - try - { - command.execute( new CommandContext( server, sender, command ), Arrays.asList( args ) ); - } - catch( CommandException e ) - { - throw e; - } - catch( Throwable e ) - { - ComputerCraft.log.error( "Unhandled exception in command", e ); - throw new CommandException( "commands.computercraft.generic.exception", e.toString() ); - } - } - - @Nonnull - @Override - public List getTabCompletions( @Nonnull MinecraftServer server, @Nonnull ICommandSender sender, @Nonnull String[] args, @Nullable BlockPos pos ) - { - return command.getCompletion( new CommandContext( server, sender, command ), Arrays.asList( args ) ); - } - - @Override - public boolean checkPermission( @Nonnull MinecraftServer server, @Nonnull ICommandSender sender ) - { - return command.checkPermission( new CommandContext( server, sender, command ) ); - } - - @Override - public boolean isUsernameIndex( @Nonnull String[] args, int index ) - { - return false; - } - - @Override - public int compareTo( @Nonnull ICommand o ) - { - return getName().compareTo( o.getName() ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/command/framework/CommandRoot.java b/src/main/java/dan200/computercraft/shared/command/framework/CommandRoot.java deleted file mode 100644 index 23cea8b6b..000000000 --- a/src/main/java/dan200/computercraft/shared/command/framework/CommandRoot.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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.shared.command.framework; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import dan200.computercraft.shared.command.text.ChatHelpers; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; - -import javax.annotation.Nonnull; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * A command which delegates to a series of sub commands - */ -public class CommandRoot implements ISubCommand -{ - private final String name; - private ISubCommand parent; - private final Map subCommands = Maps.newHashMap(); - - public CommandRoot( String name ) - { - this.name = name; - register( new SubCommandHelp( this ) ); - } - - public CommandRoot register( ISubCommand command ) - { - subCommands.put( command.getName(), command ); - if( command instanceof SubCommandBase ) - { - ((SubCommandBase) command).setParent( this ); - } - else if( command instanceof CommandRoot ) - { - ((CommandRoot) command).setParent( this ); - } - - return this; - } - - @Nonnull - @Override - public String getName() - { - return name; - } - - @Nonnull - @Override - public String getFullName() - { - return parent == null ? name : parent.getFullName() + "." + name; - } - - @Nonnull - @Override - public String getUsage( CommandContext context ) - { - StringBuilder out = new StringBuilder( "<" ); - boolean first = true; - for( ISubCommand command : subCommands.values() ) - { - if( command.checkPermission( context ) ) - { - if( first ) - { - first = false; - } - else - { - out.append( "|" ); - } - - out.append( command.getName() ); - } - } - - return out.append( ">" ).toString(); - } - - @Override - public boolean checkPermission( @Nonnull CommandContext context ) - { - for( ISubCommand command : subCommands.values() ) - { - if( !(command instanceof SubCommandHelp) && command.checkPermission( context ) ) return true; - } - return false; - } - - public Map getSubCommands() - { - return Collections.unmodifiableMap( subCommands ); - } - - @Override - public void execute( @Nonnull CommandContext context, @Nonnull List arguments ) throws CommandException - { - if( arguments.isEmpty() ) - { - context.getSender().sendMessage( ChatHelpers.getHelp( context, this, context.getFullPath() ) ); - } - else - { - ISubCommand command = subCommands.get( arguments.get( 0 ) ); - if( command == null || !command.checkPermission( context ) ) - { - throw new CommandException( context.getFullUsage() ); - } - - command.execute( context.enter( command ), arguments.subList( 1, arguments.size() ) ); - } - } - - @Nonnull - @Override - public List getCompletion( @Nonnull CommandContext context, @Nonnull List arguments ) - { - if( arguments.isEmpty() ) - { - return Lists.newArrayList( subCommands.keySet() ); - } - else if( arguments.size() == 1 ) - { - List list = Lists.newArrayList(); - String match = arguments.get( 0 ); - - for( ISubCommand command : subCommands.values() ) - { - if( CommandBase.doesStringStartWith( match, command.getName() ) && command.checkPermission( context ) ) - { - list.add( command.getName() ); - } - } - - return list; - } - else - { - ISubCommand command = subCommands.get( arguments.get( 0 ) ); - if( command == null || !command.checkPermission( context ) ) return Collections.emptyList(); - - return command.getCompletion( context, arguments.subList( 1, arguments.size() ) ); - } - } - - void setParent( @Nonnull ISubCommand parent ) - { - if( this.parent != null ) throw new IllegalStateException( "Cannot have multiple parents" ); - this.parent = parent; - } -} diff --git a/src/main/java/dan200/computercraft/shared/command/framework/ISubCommand.java b/src/main/java/dan200/computercraft/shared/command/framework/ISubCommand.java deleted file mode 100644 index 828b31683..000000000 --- a/src/main/java/dan200/computercraft/shared/command/framework/ISubCommand.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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.shared.command.framework; - -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommand; -import net.minecraft.command.ICommandSender; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.math.BlockPos; - -import javax.annotation.Nonnull; -import java.util.Collections; -import java.util.List; - -/** - * A slightly different implementation of {@link ICommand} which is delegated to. - */ -public interface ISubCommand -{ - /** - * Get the name of this command - * - * @return The name of this command - * @see ICommand#getName() - */ - @Nonnull - String getName(); - - /** - * Get the full name of this command. This is equal to the command parent's full name, plus this command's name. - * - * @return The full name of this command - * @see ISubCommand#getName() - */ - @Nonnull - String getFullName(); - - /** - * Get the usage of this command - * - * @param context The context this command is executed in - * @return The usage of this command - * @see ICommand#getUsage(ICommandSender) - */ - @Nonnull - default String getUsage( CommandContext context ) - { - return "commands." + getFullName() + ".usage"; - } - - /** - * Determine whether a given command sender has permission to execute this command. - * - * @param context The current command context. - * @return Whether this command can be executed. - * @see ICommand#checkPermission(MinecraftServer, ICommandSender) - */ - boolean checkPermission( @Nonnull CommandContext context ); - - /** - * Execute this command - * - * @param context The current command context. - * @param arguments The arguments passed @throws CommandException When an error occurs - * @see ICommand#execute(MinecraftServer, ICommandSender, String[]) - */ - void execute( @Nonnull CommandContext context, @Nonnull List arguments ) throws CommandException; - - /** - * Get a list of possible completions - * - * @param context The current command context. - * @param arguments The arguments passed. You should complete the last one. - * @return List of possible completions - * @see ICommand#getTabCompletions(MinecraftServer, ICommandSender, String[], BlockPos) - */ - @Nonnull - default List getCompletion( @Nonnull CommandContext context, @Nonnull List arguments ) - { - return Collections.emptyList(); - } -} diff --git a/src/main/java/dan200/computercraft/shared/command/framework/SubCommandBase.java b/src/main/java/dan200/computercraft/shared/command/framework/SubCommandBase.java deleted file mode 100644 index b741ee0e4..000000000 --- a/src/main/java/dan200/computercraft/shared/command/framework/SubCommandBase.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.shared.command.framework; - -import dan200.computercraft.shared.command.UserLevel; - -import javax.annotation.Nonnull; - -public abstract class SubCommandBase implements ISubCommand -{ - private final String name; - private final String id; - private final UserLevel level; - private ISubCommand parent; - - protected SubCommandBase( String name, UserLevel level ) - { - this.name = name; - id = name.replace( '-', '_' ); - this.level = level; - } - - @Nonnull - @Override - public String getName() - { - return name; - } - - @Nonnull - @Override - public String getFullName() - { - return parent == null ? id : parent.getFullName() + "." + id; - } - - @Override - public boolean checkPermission( @Nonnull CommandContext context ) - { - return level.canExecute( context ); - } - - void setParent( ISubCommand parent ) - { - if( this.parent != null ) throw new IllegalStateException( "Cannot have multiple parents" ); - this.parent = parent; - } -} diff --git a/src/main/java/dan200/computercraft/shared/command/framework/SubCommandHelp.java b/src/main/java/dan200/computercraft/shared/command/framework/SubCommandHelp.java deleted file mode 100644 index 532849754..000000000 --- a/src/main/java/dan200/computercraft/shared/command/framework/SubCommandHelp.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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.shared.command.framework; - -import com.google.common.collect.Lists; -import dan200.computercraft.shared.command.text.ChatHelpers; -import joptsimple.internal.Strings; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; - -import javax.annotation.Nonnull; -import java.util.Collections; -import java.util.List; - -class SubCommandHelp implements ISubCommand -{ - private final CommandRoot branchCommand; - - SubCommandHelp( CommandRoot branchCommand ) - { - this.branchCommand = branchCommand; - } - - @Nonnull - @Override - public String getName() - { - return "help"; - } - - @Nonnull - @Override - public String getFullName() - { - return "computercraft.help"; - } - - @Override - public boolean checkPermission( @Nonnull CommandContext context ) - { - return true; - } - - @Override - public void execute( @Nonnull CommandContext context, @Nonnull List arguments ) throws CommandException - { - ISubCommand command = branchCommand; - - for( int i = 0; i < arguments.size(); i++ ) - { - String commandName = arguments.get( i ); - if( command instanceof CommandRoot ) - { - command = ((CommandRoot) command).getSubCommands().get( commandName ); - } - else - { - throw new CommandException( "commands.computercraft.help.no_children", Strings.join( arguments.subList( 0, i ), " " ) ); - } - - if( command == null ) - { - throw new CommandException( "commands.computercraft.help.no_command", Strings.join( arguments.subList( 0, i + 1 ), " " ) ); - } - } - - StringBuilder prefix = new StringBuilder( context.parent().getFullPath() ); - for( String argument : arguments ) - { - prefix.append( ' ' ).append( argument ); - } - context.getSender().sendMessage( ChatHelpers.getHelp( context, command, prefix.toString() ) ); - } - - @Nonnull - @Override - public List getCompletion( @Nonnull CommandContext context, @Nonnull List arguments ) - { - CommandRoot command = branchCommand; - - for( int i = 0; i < arguments.size() - 1; i++ ) - { - String commandName = arguments.get( i ); - ISubCommand subCommand = command.getSubCommands().get( commandName ); - - if( subCommand instanceof CommandRoot ) - { - command = (CommandRoot) subCommand; - } - else - { - return Collections.emptyList(); - } - } - - if( arguments.isEmpty() ) - { - return Lists.newArrayList( command.getSubCommands().keySet() ); - } - else - { - List list = Lists.newArrayList(); - String match = arguments.get( arguments.size() - 1 ); - - for( String entry : command.getSubCommands().keySet() ) - { - if( CommandBase.doesStringStartWith( match, entry ) ) - { - list.add( entry ); - } - } - - return list; - } - } -} diff --git a/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java b/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java index 3b61a6cc8..a3119a992 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java +++ b/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java @@ -6,9 +6,6 @@ package dan200.computercraft.shared.command.text; -import dan200.computercraft.shared.command.framework.CommandContext; -import dan200.computercraft.shared.command.framework.CommandRoot; -import dan200.computercraft.shared.command.framework.ISubCommand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.*; import net.minecraft.util.text.event.ClickEvent; @@ -20,8 +17,6 @@ public final class ChatHelpers { private static final TextFormatting HEADER = TextFormatting.LIGHT_PURPLE; - private static final TextFormatting SYNOPSIS = TextFormatting.AQUA; - private static final TextFormatting NAME = TextFormatting.GREEN; private ChatHelpers() {} @@ -63,41 +58,6 @@ public static ITextComponent list( ITextComponent... children ) return component; } - public static ITextComponent getHelp( CommandContext context, ISubCommand command, String prefix ) - { - - ITextComponent output = new TextComponentString( "" ) - .appendSibling( - coloured( "/" + prefix, HEADER ) - .appendSibling( translate( command.getUsage( context ) ) ) - ) - .appendText( " " ) - .appendSibling( coloured( translate( "commands." + command.getFullName() + ".synopsis" ), SYNOPSIS ) ) - .appendText( "\n" ) - .appendSibling( translate( "commands." + command.getFullName() + ".desc" ) ); - - if( command instanceof CommandRoot ) - { - for( ISubCommand subCommand : ((CommandRoot) command).getSubCommands().values() ) - { - if( !subCommand.checkPermission( context ) ) continue; - - output.appendText( "\n" ); - - ITextComponent component = coloured( subCommand.getName(), NAME ); - component.getStyle().setClickEvent( new ClickEvent( - ClickEvent.Action.SUGGEST_COMMAND, - "/" + prefix + " " + subCommand.getName() - ) ); - output.appendSibling( component ); - - output.appendText( " - " ).appendSibling( translate( "commands." + subCommand.getFullName() + ".synopsis" ) ); - } - } - - return output; - } - public static ITextComponent position( BlockPos pos ) { if( pos == null ) return translate( "commands.computercraft.generic.no_position" ); diff --git a/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java b/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java index 53c79e888..41eeb6029 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java +++ b/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java @@ -6,7 +6,7 @@ package dan200.computercraft.shared.command.text; -import net.minecraft.command.ICommandSender; +import net.minecraft.command.CommandSource; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; import org.apache.commons.lang3.StringUtils; @@ -15,9 +15,9 @@ public class ServerTableFormatter implements TableFormatter { - private final ICommandSender source; + private final CommandSource source; - public ServerTableFormatter( ICommandSender source ) + public ServerTableFormatter( CommandSource source ) { this.source = source; } @@ -40,12 +40,12 @@ public int getColumnPadding() @Override public int getWidth( ITextComponent component ) { - return component.getUnformattedText().length(); + return component.getString().length(); } @Override public void writeLine( int id, ITextComponent component ) { - source.sendMessage( component ); + source.sendFeedback( component, false ); } } diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java b/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java index 62fd7fc9f..13e08d9c2 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java @@ -9,7 +9,7 @@ import dan200.computercraft.shared.command.CommandUtils; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.client.ChatTableClientMessage; -import net.minecraft.command.ICommandSender; +import net.minecraft.command.CommandSource; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.util.text.ITextComponent; @@ -120,12 +120,12 @@ public void trim( int height ) } } - public void display( ICommandSender source ) + public void display( CommandSource source ) { if( CommandUtils.isPlayer( source ) ) { trim( 18 ); - NetworkHandler.sendToPlayer( (EntityPlayerMP) source, new ChatTableClientMessage( this ) ); + NetworkHandler.sendToPlayer( (EntityPlayerMP) source.getEntity(), new ChatTableClientMessage( this ) ); } else { diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java index eaa7f63f2..0b3ec2322 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java @@ -93,7 +93,7 @@ default int display( TableBuilder table ) // it a tad prettier. int rowCharWidth = getWidth( HEADER ); int rowWidth = totalWidth / rowCharWidth + (totalWidth % rowCharWidth == 0 ? 0 : 1); - writeLine( rowId++, coloured( StringUtils.repeat( HEADER.getUnformattedText(), rowWidth ), TextFormatting.GRAY ) ); + writeLine( rowId++, coloured( StringUtils.repeat( HEADER.getString(), rowWidth ), TextFormatting.GRAY ) ); } for( ITextComponent[] row : table.getRows() ) @@ -118,4 +118,3 @@ default int display( TableBuilder table ) return rowId - table.getId(); } } - diff --git a/src/main/java/dan200/computercraft/shared/common/BlockDirectional.java b/src/main/java/dan200/computercraft/shared/common/BlockDirectional.java deleted file mode 100644 index beecc70b4..000000000 --- a/src/main/java/dan200/computercraft/shared/common/BlockDirectional.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.shared.common; - -import net.minecraft.block.material.Material; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockAccess; -import net.minecraft.world.World; - -public abstract class BlockDirectional extends BlockGeneric -{ - protected BlockDirectional( Material material ) - { - super( material ); - } - - public EnumFacing getDirection( IBlockAccess world, BlockPos pos ) - { - TileEntity tile = world.getTileEntity( pos ); - if( tile instanceof IDirectionalTile ) - { - IDirectionalTile directional = (IDirectionalTile) tile; - return directional.getDirection(); - } - return EnumFacing.NORTH; - } - - public void setDirection( World world, BlockPos pos, EnumFacing dir ) - { - TileEntity tile = world.getTileEntity( pos ); - if( tile instanceof IDirectionalTile ) - { - IDirectionalTile directional = (IDirectionalTile) tile; - directional.setDirection( dir ); - } - } -} diff --git a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java index bc60d2f0e..a7a9420df 100644 --- a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java @@ -8,42 +8,46 @@ import net.minecraft.block.Block; import net.minecraft.block.ITileEntityProvider; -import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockAccess; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorldReader; import net.minecraft.world.World; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Random; public abstract class BlockGeneric extends Block implements ITileEntityProvider { - protected BlockGeneric( Material material ) + private final TileEntityType type; + + public BlockGeneric( Properties settings, TileEntityType type ) { - super( material ); - hasTileEntity = true; + super( settings ); + this.type = type; } - protected abstract TileGeneric createTile( IBlockState state ); - - protected abstract TileGeneric createTile( int damage ); - @Override - public final void breakBlock( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull IBlockState newState ) + @Deprecated + public final void onReplaced( @Nonnull IBlockState block, @Nonnull World world, @Nonnull BlockPos pos, IBlockState replace, boolean bool ) { + if( block.getBlock() == replace.getBlock() ) return; + TileEntity tile = world.getTileEntity( pos ); - super.breakBlock( world, pos, newState ); + super.onReplaced( block, world, pos, replace, bool ); world.removeTileEntity( pos ); if( tile instanceof TileGeneric ) ((TileGeneric) tile).destroy(); } @Override - public final boolean onBlockActivated( World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ ) + @Deprecated + public final boolean onBlockActivated( IBlockState state, World world, BlockPos pos, EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ ) { TileEntity tile = world.getTileEntity( pos ); return tile instanceof TileGeneric && ((TileGeneric) tile).onActivate( player, hand, side, hitX, hitY, hitZ ); @@ -59,80 +63,24 @@ public final void neighborChanged( IBlockState state, World world, BlockPos pos, } @Override - public final void onNeighborChange( IBlockAccess world, BlockPos pos, BlockPos neighbour ) + public final void onNeighborChange( IBlockState state, IWorldReader world, BlockPos pos, BlockPos neighbour ) { TileEntity tile = world.getTileEntity( pos ); if( tile instanceof TileGeneric ) ((TileGeneric) tile).onNeighbourTileEntityChange( neighbour ); } @Override - public void updateTick( World world, BlockPos pos, IBlockState state, Random rand ) + @Deprecated + public void tick( IBlockState state, World world, BlockPos pos, Random rand ) { TileEntity te = world.getTileEntity( pos ); - if( te instanceof TileGeneric ) ((TileGeneric) te).updateTick(); + if( te instanceof TileGeneric ) ((TileGeneric) te).blockTick(); } + @Nullable @Override - @Deprecated - public final boolean canProvidePower( IBlockState state ) + public TileEntity createNewTileEntity( @Nonnull IBlockReader world ) { - return true; - } - - @Override - public final boolean canConnectRedstone( IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing side ) - { - TileEntity tile = world.getTileEntity( pos ); - return tile instanceof TileGeneric && ((TileGeneric) tile).getRedstoneConnectivity( side ); - } - - @Override - @Deprecated - public final int getStrongPower( IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing oppositeSide ) - { - TileEntity tile = world.getTileEntity( pos ); - return tile instanceof TileGeneric && tile.hasWorld() ? ((TileGeneric) tile).getRedstoneOutput( oppositeSide.getOpposite() ) : 0; - } - - @Override - @Deprecated - public final int getWeakPower( IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing oppositeSide ) - { - return getStrongPower( state, world, pos, oppositeSide ); - } - - public boolean getBundledRedstoneConnectivity( World world, BlockPos pos, EnumFacing side ) - { - TileEntity tile = world.getTileEntity( pos ); - return tile instanceof TileGeneric && ((TileGeneric) tile).getBundledRedstoneConnectivity( side ); - } - - public int getBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side ) - { - TileEntity tile = world.getTileEntity( pos ); - return tile instanceof TileGeneric && tile.hasWorld() ? ((TileGeneric) tile).getBundledRedstoneOutput( side ) : 0; - } - - @Nonnull - @Override - public final TileEntity createTileEntity( @Nonnull World world, @Nonnull IBlockState state ) - { - return createTile( state ); - } - - @Nonnull - @Override - public final TileEntity createNewTileEntity( @Nonnull World world, int damage ) - { - return createTile( damage ); - } - - @Override - @Deprecated - public boolean isSideSolid( IBlockState state, @Nonnull IBlockAccess world, @Nonnull BlockPos pos, EnumFacing side ) - { - // We need to override this as the default implementation uses isNormalCube, which returns false if - // it can provide power. - return isFullCube( state ); + return type.create(); } } diff --git a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java index 56f86c18b..4e7ad3791 100644 --- a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java @@ -50,10 +50,10 @@ public boolean isColour() public void readDescription( NBTTagCompound nbt ) { m_colour = nbt.getBoolean( "colour" ); - if( nbt.hasKey( "terminal" ) ) + if( nbt.contains( "terminal" ) ) { - NBTTagCompound terminal = nbt.getCompoundTag( "terminal" ); - resizeTerminal( terminal.getInteger( "term_width" ), terminal.getInteger( "term_height" ) ); + NBTTagCompound terminal = nbt.getCompound( "terminal" ); + resizeTerminal( terminal.getInt( "term_width" ), terminal.getInt( "term_height" ) ); m_terminal.readFromNBT( terminal ); } else diff --git a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java index c975b259a..d17d95e25 100644 --- a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java +++ b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java @@ -6,24 +6,30 @@ package dan200.computercraft.shared.common; -import com.google.gson.JsonObject; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.util.AbstractRecipe; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.ColourTracker; import dan200.computercraft.shared.util.ColourUtils; -import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.EnumDyeColor; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.item.crafting.RecipeSerializers; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; -import net.minecraftforge.common.crafting.IRecipeFactory; -import net.minecraftforge.common.crafting.JsonContext; -import net.minecraftforge.registries.IForgeRegistryEntry; import javax.annotation.Nonnull; -public class ColourableRecipe extends IForgeRegistryEntry.Impl implements IRecipe +public class ColourableRecipe extends AbstractRecipe { + public ColourableRecipe( ResourceLocation id ) + { + super( id ); + } + @Override - public boolean matches( @Nonnull InventoryCrafting inv, @Nonnull World worldIn ) + public boolean matches( @Nonnull IInventory inv, @Nonnull World world ) { boolean hasColourable = false; boolean hasDye = false; @@ -37,7 +43,7 @@ public boolean matches( @Nonnull InventoryCrafting inv, @Nonnull World worldIn ) if( hasColourable ) return false; hasColourable = true; } - else if( ColourUtils.getStackColour( stack ) >= 0 ) + else if( ColourUtils.getStackColour( stack ) != null ) { hasDye = true; } @@ -52,7 +58,7 @@ else if( ColourUtils.getStackColour( stack ) >= 0 ) @Nonnull @Override - public ItemStack getCraftingResult( @Nonnull InventoryCrafting inv ) + public ItemStack getCraftingResult( @Nonnull IInventory inv ) { ItemStack colourable = ItemStack.EMPTY; @@ -70,10 +76,10 @@ public ItemStack getCraftingResult( @Nonnull InventoryCrafting inv ) } else { - int index = ColourUtils.getStackColour( stack ); - if( index < 0 ) continue; + EnumDyeColor dye = ColourUtils.getStackColour( stack ); + if( dye == null ) continue; - Colour colour = Colour.values()[index]; + Colour colour = Colour.fromInt( 15 - dye.getId() ); tracker.addColour( colour.getR(), colour.getG(), colour.getB() ); } } @@ -89,24 +95,13 @@ public boolean canFit( int x, int y ) } @Override - public boolean isDynamic() - { - return true; - } - @Nonnull - @Override - public ItemStack getRecipeOutput() + public IRecipeSerializer getSerializer() { - return ItemStack.EMPTY; + return SERIALIZER; } - public static class Factory implements IRecipeFactory - { - @Override - public IRecipe parse( JsonContext jsonContext, JsonObject jsonObject ) - { - return new ColourableRecipe(); - } - } + public static final IRecipeSerializer SERIALIZER = new RecipeSerializers.SimpleSerializer<>( + ComputerCraft.MOD_ID + ":colour", ColourableRecipe::new + ); } diff --git a/src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java similarity index 91% rename from src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java rename to src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java index 4daa4fe34..af4f46983 100644 --- a/src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java +++ b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java @@ -4,7 +4,7 @@ * Send enquiries to dratcliffe@gmail.com */ -package dan200.computercraft.shared.media.inventory; +package dan200.computercraft.shared.common; import dan200.computercraft.shared.util.InventoryUtil; import net.minecraft.entity.player.EntityPlayer; @@ -34,7 +34,7 @@ public ItemStack getStack() @Override public boolean canInteractWith( @Nonnull EntityPlayer player ) { - if( !player.isEntityAlive() ) return false; + if( !player.isAlive() ) return false; ItemStack stack = player.getHeldItem( m_hand ); return stack == m_stack || !stack.isEmpty() && !m_stack.isEmpty() && stack.getItem() == m_stack.getItem(); diff --git a/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java b/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java index 8d5667173..5b0a26148 100644 --- a/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java @@ -25,9 +25,9 @@ public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos public static int getDefaultBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side ) { Block block = world.getBlockState( pos ).getBlock(); - if( block instanceof BlockGeneric ) + if( block instanceof IBundledRedstoneBlock ) { - BlockGeneric generic = (BlockGeneric) block; + IBundledRedstoneBlock generic = (IBundledRedstoneBlock) block; if( generic.getBundledRedstoneConnectivity( world, pos, side ) ) { return generic.getBundledRedstoneOutput( world, pos, side ); diff --git a/src/main/java/dan200/computercraft/shared/common/IDirectionalTile.java b/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java similarity index 50% rename from src/main/java/dan200/computercraft/shared/common/IDirectionalTile.java rename to src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java index 781784eea..d6212dbed 100644 --- a/src/main/java/dan200/computercraft/shared/common/IDirectionalTile.java +++ b/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java @@ -7,10 +7,12 @@ package dan200.computercraft.shared.common; import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; -public interface IDirectionalTile +public interface IBundledRedstoneBlock { - EnumFacing getDirection(); + boolean getBundledRedstoneConnectivity( World world, BlockPos pos, EnumFacing side ); - void setDirection( EnumFacing dir ); + int getBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side ); } diff --git a/src/main/java/dan200/computercraft/shared/common/IColouredItem.java b/src/main/java/dan200/computercraft/shared/common/IColouredItem.java index e0988ad12..9fe5ca6cf 100644 --- a/src/main/java/dan200/computercraft/shared/common/IColouredItem.java +++ b/src/main/java/dan200/computercraft/shared/common/IColouredItem.java @@ -11,7 +11,7 @@ public interface IColouredItem { - String NBT_COLOUR = "colour"; + String NBT_COLOUR = "Color"; default int getColour( ItemStack stack ) { @@ -27,21 +27,20 @@ default ItemStack withColour( ItemStack stack, int colour ) static int getColourBasic( ItemStack stack ) { - NBTTagCompound tag = stack.getTagCompound(); - return tag != null && tag.hasKey( NBT_COLOUR ) ? tag.getInteger( NBT_COLOUR ) : -1; + NBTTagCompound tag = stack.getTag(); + return tag != null && tag.contains( NBT_COLOUR ) ? tag.getInt( NBT_COLOUR ) : -1; } static void setColourBasic( ItemStack stack, int colour ) { - NBTTagCompound tag = stack.getTagCompound(); if( colour == -1 ) { - if( tag != null ) tag.removeTag( NBT_COLOUR ); + NBTTagCompound tag = stack.getTag(); + if( tag != null ) tag.remove( NBT_COLOUR ); } else { - if( tag == null ) stack.setTagCompound( tag = new NBTTagCompound() ); - tag.setInteger( NBT_COLOUR, colour ); + stack.getOrCreateTag().putInt( NBT_COLOUR, colour ); } } } diff --git a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java index b007ef86c..0898a3844 100644 --- a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java @@ -88,14 +88,14 @@ public boolean isColour() public void writeDescription( NBTTagCompound nbt ) { - nbt.setBoolean( "colour", m_colour ); + nbt.putBoolean( "colour", m_colour ); if( m_terminal != null ) { NBTTagCompound terminal = new NBTTagCompound(); - terminal.setInteger( "term_width", m_terminal.getWidth() ); - terminal.setInteger( "term_height", m_terminal.getHeight() ); + terminal.putInt( "term_width", m_terminal.getWidth() ); + terminal.putInt( "term_height", m_terminal.getHeight() ); m_terminal.writeToNBT( terminal ); - nbt.setTag( "terminal", terminal ); + nbt.put( "terminal", terminal ); } } } diff --git a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java index 850bf844c..2b01a2be1 100644 --- a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java @@ -6,51 +6,37 @@ package dan200.computercraft.shared.common; -import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; import javax.annotation.Nonnull; -import javax.annotation.Nullable; public abstract class TileGeneric extends TileEntity { + public TileGeneric( TileEntityType type ) + { + super( type ); + } + public void destroy() { } - @Nullable - public BlockGeneric getBlock() - { - Block block = getBlockType(); - return block instanceof BlockGeneric ? (BlockGeneric) block : null; - } - - protected final IBlockState getBlockState() - { - return getWorld().getBlockState( getPos() ); - } - public final void updateBlock() { markDirty(); BlockPos pos = getPos(); - IBlockState state = getWorld().getBlockState( pos ); + IBlockState state = getBlockState(); getWorld().markBlockRangeForRenderUpdate( pos, pos ); - getWorld().notifyBlockUpdate( getPos(), state, state, 3 ); - } - - protected final void setBlockState( IBlockState newState ) - { - getWorld().setBlockState( getPos(), newState, 3 ); + getWorld().notifyBlockUpdate( pos, state, state, 3 ); } public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ ) @@ -58,45 +44,18 @@ public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, return false; } - @Deprecated - public void onNeighbourChange() - { - } - - @SuppressWarnings( "deprecation" ) public void onNeighbourChange( @Nonnull BlockPos neighbour ) { - onNeighbourChange(); } public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour ) { } - protected void updateTick() + protected void blockTick() { } - public boolean getRedstoneConnectivity( EnumFacing side ) - { - return false; - } - - public int getRedstoneOutput( EnumFacing side ) - { - return 0; - } - - public boolean getBundledRedstoneConnectivity( @Nonnull EnumFacing side ) - { - return false; - } - - public int getBundledRedstoneOutput( @Nonnull EnumFacing side ) - { - return 0; - } - protected double getInteractRange( EntityPlayer player ) { return 8.0; @@ -104,7 +63,7 @@ protected double getInteractRange( EntityPlayer player ) public boolean isUsable( EntityPlayer player, boolean ignoreRange ) { - if( player == null || !player.isEntityAlive() || getWorld().getTileEntity( getPos() ) != this ) return false; + if( player == null || !player.isAlive() || getWorld().getTileEntity( getPos() ) != this ) return false; if( ignoreRange ) return true; double range = getInteractRange( player ); @@ -121,18 +80,13 @@ protected void readDescription( @Nonnull NBTTagCompound nbt ) { } - @Override - public boolean shouldRefresh( World world, BlockPos pos, @Nonnull IBlockState oldState, @Nonnull IBlockState newState ) - { - return newState.getBlock() != oldState.getBlock(); - } - + @Nonnull @Override public final SPacketUpdateTileEntity getUpdatePacket() { NBTTagCompound nbt = new NBTTagCompound(); writeDescription( nbt ); - return new SPacketUpdateTileEntity( getPos(), 0, nbt ); + return new SPacketUpdateTileEntity( pos, 0, nbt ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index 5ebf305c9..d14dc2bd4 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -7,6 +7,8 @@ package dan200.computercraft.shared.computer.apis; import com.google.common.collect.ImmutableMap; +import com.mojang.brigadier.tree.CommandNode; +import com.mojang.brigadier.tree.LiteralCommandNode; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; @@ -14,16 +16,16 @@ import dan200.computercraft.shared.computer.blocks.TileCommandComputer; import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.block.Block; -import net.minecraft.block.properties.IProperty; import net.minecraft.block.state.IBlockState; -import net.minecraft.command.ICommand; -import net.minecraft.command.ICommandManager; -import net.minecraft.command.ICommandSender; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.server.MinecraftServer; +import net.minecraft.state.IProperty; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.registries.ForgeRegistries; import javax.annotation.Nonnull; import java.util.Collections; @@ -73,19 +75,19 @@ private static Map createOutput( String output ) private Object[] doCommand( String command ) { - MinecraftServer server = m_computer.getWorld().getMinecraftServer(); + MinecraftServer server = m_computer.getWorld().getServer(); if( server == null || !server.isCommandBlockEnabled() ) { return new Object[] { false, createOutput( "Command blocks disabled by server" ) }; } - ICommandManager commandManager = server.getCommandManager(); - TileCommandComputer.CommandSender sender = m_computer.getCommandSender(); + Commands commandManager = server.getCommandManager(); + TileCommandComputer.CommandReceiver receiver = m_computer.getReceiver(); try { - sender.clearOutput(); - int result = commandManager.executeCommand( sender, command ); - return new Object[] { result > 0, sender.copyOutput() }; + receiver.clearOutput(); + int result = commandManager.handleCommand( m_computer.getSource(), command ); + return new Object[] { result > 0, receiver.copyOutput() }; } catch( Throwable t ) { @@ -100,12 +102,11 @@ private static Object getBlockInfo( World world, BlockPos pos ) IBlockState state = world.getBlockState( pos ); Block block = state.getBlock(); - Map table = new HashMap<>( 3 ); - table.put( "name", Block.REGISTRY.getNameForObject( block ).toString() ); - table.put( "metadata", block.getMetaFromState( state ) ); + Map table = new HashMap<>(); + table.put( "name", ForgeRegistries.BLOCKS.getKey( block ).toString() ); Map stateTable = new HashMap<>(); - for( ImmutableMap.Entry, Comparable> entry : state.getActualState( world, pos ).getProperties().entrySet() ) + for( ImmutableMap.Entry, Comparable> entry : state.getValues().entrySet() ) { IProperty property = entry.getKey(); stateTable.put( property.getName(), getPropertyValue( property, entry.getValue() ) ); @@ -113,7 +114,7 @@ private static Object getBlockInfo( World world, BlockPos pos ) table.put( "state", stateTable ); TileEntity tile = world.getTileEntity( pos ); - if( tile != null ) table.put( "nbt", NBTUtil.toLua( tile.writeToNBT( new NBTTagCompound() ) ) ); + if( tile != null ) table.put( "nbt", NBTUtil.toLua( tile.write( new NBTTagCompound() ) ) ); return table; } @@ -141,37 +142,26 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O long taskID = context.issueMainThreadTask( () -> doCommand( command ) ); return new Object[] { taskID }; } - case 2: // list + case 2: + // list return context.executeMainThreadTask( () -> { + MinecraftServer server = m_computer.getWorld().getServer(); + + if( server == null ) return new Object[] { Collections.emptyMap() }; + CommandNode node = server.getCommandManager().getDispatcher().getRoot(); + for( int j = 0; j < arguments.length; j++ ) + { + String name = getString( arguments, j ); + node = node.getChild( name ); + if( !(node instanceof LiteralCommandNode) ) return new Object[] { Collections.emptyMap() }; + } + int i = 1; Map result = new HashMap<>(); - MinecraftServer server = m_computer.getWorld().getMinecraftServer(); - if( server != null ) + for( CommandNode child : node.getChildren() ) { - ICommandManager commandManager = server.getCommandManager(); - ICommandSender commandSender = m_computer.getCommandSender(); - Map commands = commandManager.getCommands(); - for( Map.Entry entry : commands.entrySet() ) - { - String name = entry.getKey(); - ICommand command = entry.getValue(); - try - { - if( command.checkPermission( server, commandSender ) ) - { - result.put( i++, name ); - } - } - catch( Throwable t ) - { - // Ignore buggy command - if( ComputerCraft.logPeripheralErrors ) - { - ComputerCraft.log.error( "Error checking permissions of command.", t ); - } - } - } + if( child instanceof LiteralCommandNode ) result.put( i++, child.getName() ); } return new Object[] { result }; } ); @@ -204,7 +194,7 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O Math.max( minY, maxY ), Math.max( minZ, maxZ ) ); - if( !world.isValid( min ) || !world.isValid( max ) ) + if( !World.isValid( min ) || !World.isValid( max ) ) { throw new LuaException( "Co-ordinates out or range" ); } @@ -239,7 +229,7 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O // Get the details of the block World world = m_computer.getWorld(); BlockPos position = new BlockPos( x, y, z ); - if( world.isValid( position ) ) + if( World.isValid( position ) ) { return new Object[] { getBlockInfo( world, position ) }; } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockCommandComputer.java deleted file mode 100644 index 1067ec711..000000000 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockCommandComputer.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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.shared.computer.blocks; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.items.ComputerItemFactory; -import net.minecraft.block.BlockHorizontal; -import net.minecraft.block.material.Material; -import net.minecraft.block.properties.PropertyDirection; -import net.minecraft.block.properties.PropertyEnum; -import net.minecraft.block.state.BlockStateContainer; -import net.minecraft.block.state.IBlockState; -import net.minecraft.item.ItemStack; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockAccess; - -import javax.annotation.Nonnull; - -public class BlockCommandComputer extends BlockComputerBase -{ - // Statics - - public static final class Properties - { - public static final PropertyDirection FACING = BlockHorizontal.FACING; - public static final PropertyEnum STATE = PropertyEnum.create( "state", ComputerState.class ); - } - - // Members - - public BlockCommandComputer() - { - super( Material.IRON ); - setBlockUnbreakable(); - setResistance( 6000000.0F ); - setTranslationKey( "computercraft:command_computer" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - setDefaultState( blockState.getBaseState() - .withProperty( Properties.FACING, EnumFacing.NORTH ) - .withProperty( Properties.STATE, ComputerState.Off ) - ); - } - - @Nonnull - @Override - protected BlockStateContainer createBlockState() - { - return new BlockStateContainer( this, Properties.FACING, Properties.STATE ); - } - - @Nonnull - @Override - @Deprecated - public IBlockState getStateFromMeta( int meta ) - { - EnumFacing dir = EnumFacing.byIndex( meta & 0x7 ); - if( dir.getAxis() == EnumFacing.Axis.Y ) - { - dir = EnumFacing.NORTH; - } - return getDefaultState().withProperty( Properties.FACING, dir ); - } - - @Override - public int getMetaFromState( IBlockState state ) - { - return state.getValue( Properties.FACING ).getIndex(); - } - - @Nonnull - @Override - @Deprecated - public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos ) - { - TileEntity tile = world.getTileEntity( pos ); - return state.withProperty( Properties.STATE, tile instanceof TileComputer ? ((TileComputer) tile).getState() : ComputerState.Off ); - } - - @Override - protected IBlockState getDefaultBlockState( ComputerFamily family, EnumFacing placedSide ) - { - return getDefaultState().withProperty( Properties.FACING, placedSide ); - } - - @Override - public ComputerFamily getFamily( int damage ) - { - return ComputerFamily.Command; - } - - @Override - public ComputerFamily getFamily( IBlockState state ) - { - return ComputerFamily.Command; - } - - @Override - protected TileComputer createTile( ComputerFamily family ) - { - return new TileCommandComputer(); - } - - @Nonnull - @Override - protected ItemStack getItem( TileComputerBase tile ) - { - return tile instanceof TileCommandComputer ? ComputerItemFactory.create( (TileComputer) tile ) : ItemStack.EMPTY; - } -} diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java index 9306cee1c..41b68cd8c 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java @@ -6,130 +6,48 @@ package dan200.computercraft.shared.computer.blocks; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.items.ComputerItemFactory; -import net.minecraft.block.BlockHorizontal; -import net.minecraft.block.material.Material; -import net.minecraft.block.properties.PropertyBool; -import net.minecraft.block.properties.PropertyDirection; -import net.minecraft.block.properties.PropertyEnum; -import net.minecraft.block.state.BlockStateContainer; +import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; +import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; -import net.minecraft.tileentity.TileEntity; +import net.minecraft.state.DirectionProperty; +import net.minecraft.state.EnumProperty; +import net.minecraft.state.StateContainer; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockAccess; import javax.annotation.Nonnull; +import javax.annotation.Nullable; -public class BlockComputer extends BlockComputerBase +public class BlockComputer extends BlockComputerBase { - // Statics - public static final class Properties - { - public static final PropertyDirection FACING = BlockHorizontal.FACING; - public static final PropertyBool ADVANCED = PropertyBool.create( "advanced" ); - public static final PropertyEnum STATE = PropertyEnum.create( "state", ComputerState.class ); - } + public static final EnumProperty STATE = EnumProperty.create( "state", ComputerState.class ); + public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; - // Members - - public BlockComputer() + public BlockComputer( Properties settings, ComputerFamily family, TileEntityType type ) { - super( Material.ROCK ); - setHardness( 2.0f ); - setTranslationKey( "computercraft:computer" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - setDefaultState( blockState.getBaseState() - .withProperty( Properties.FACING, EnumFacing.NORTH ) - .withProperty( Properties.ADVANCED, false ) - .withProperty( Properties.STATE, ComputerState.Off ) + super( settings, family, type ); + setDefaultState( getDefaultState() + .with( FACING, EnumFacing.NORTH ) + .with( STATE, ComputerState.OFF ) ); } - @Nonnull @Override - protected BlockStateContainer createBlockState() + protected void fillStateContainer( StateContainer.Builder builder ) { - return new BlockStateContainer( this, Properties.FACING, Properties.ADVANCED, Properties.STATE ); + builder.add( FACING, STATE ); } - @Nonnull + @Nullable @Override - @Deprecated - public IBlockState getStateFromMeta( int meta ) + public IBlockState getStateForPlacement( BlockItemUseContext placement ) { - EnumFacing dir = EnumFacing.byIndex( meta & 0x7 ); - if( dir.getAxis() == EnumFacing.Axis.Y ) - { - dir = EnumFacing.NORTH; - } - - IBlockState state = getDefaultState().withProperty( Properties.FACING, dir ); - if( meta > 8 ) - { - state = state.withProperty( Properties.ADVANCED, true ); - } - else - { - state = state.withProperty( Properties.ADVANCED, false ); - } - return state; - } - - @Override - public int getMetaFromState( IBlockState state ) - { - int meta = state.getValue( Properties.FACING ).getIndex(); - if( state.getValue( Properties.ADVANCED ) ) - { - meta += 8; - } - return meta; - } - - @Override - protected IBlockState getDefaultBlockState( ComputerFamily family, EnumFacing placedSide ) - { - return getDefaultState() - .withProperty( Properties.FACING, placedSide ) - .withProperty( Properties.ADVANCED, family == ComputerFamily.Advanced ); - } - - @Nonnull - @Override - @Deprecated - public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos ) - { - TileEntity tile = world.getTileEntity( pos ); - return state.withProperty( Properties.STATE, tile instanceof TileComputer ? ((TileComputer) tile).getState() : ComputerState.Off ); - } - - @Override - public ComputerFamily getFamily( int damage ) - { - return ComputerCraft.Items.computer.getFamily( damage ); - } - - @Override - public ComputerFamily getFamily( IBlockState state ) - { - if( state.getValue( Properties.ADVANCED ) ) - { - return ComputerFamily.Advanced; - } - else - { - return ComputerFamily.Normal; - } - } - - @Override - protected TileComputer createTile( ComputerFamily family ) - { - return new TileComputer(); + return getDefaultState().with( FACING, placement.getPlacementHorizontalFacing().getOpposite() ); } @Nonnull 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 f0aee2848..ab7e2f48a 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -6,91 +6,113 @@ package dan200.computercraft.shared.computer.blocks; -import dan200.computercraft.shared.common.BlockDirectional; +import dan200.computercraft.shared.common.BlockGeneric; +import dan200.computercraft.shared.common.IBundledRedstoneBlock; import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.items.IComputerItem; -import dan200.computercraft.shared.util.DirectionUtil; -import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.fluid.IFluidState; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.EnumFacing; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; -import net.minecraft.world.IBlockAccess; +import net.minecraft.world.IBlockReader; import net.minecraft.world.World; import javax.annotation.Nonnull; -public abstract class BlockComputerBase extends BlockDirectional +public abstract class BlockComputerBase extends BlockGeneric implements IBundledRedstoneBlock { - public BlockComputerBase( Material material ) + private final ComputerFamily family; + + protected BlockComputerBase( Properties settings, ComputerFamily family, TileEntityType type ) { - super( material ); + super( settings, type ); + this.family = family; } - @Override - public void onBlockAdded( World world, BlockPos pos, IBlockState state ) - { - super.onBlockAdded( world, pos, state ); - updateInput( world, pos ); - } - - @Override - public void setDirection( World world, BlockPos pos, EnumFacing dir ) - { - super.setDirection( world, pos, dir ); - updateInput( world, pos ); - } - - protected abstract IBlockState getDefaultBlockState( ComputerFamily family, EnumFacing placedSide ); - - protected abstract ComputerFamily getFamily( int damage ); - - protected abstract ComputerFamily getFamily( IBlockState state ); - - protected abstract TileComputerBase createTile( ComputerFamily family ); - - @Nonnull - protected abstract ItemStack getItem( TileComputerBase tile ); - - @Nonnull @Override @Deprecated - public final IBlockState getStateForPlacement( World world, BlockPos pos, EnumFacing side, float hitX, float hitY, float hitZ, int damage, EntityLivingBase placer ) + public void onBlockAdded( IBlockState state, World world, BlockPos pos, IBlockState oldState ) { - return getDefaultBlockState( getFamily( damage ), DirectionUtil.fromEntityRot( placer ) ); - } + super.onBlockAdded( state, world, pos, oldState ); - @Override - public final TileComputerBase createTile( IBlockState state ) - { - return createTile( getFamily( state ) ); - } - - @Override - public final TileComputerBase createTile( int damage ) - { - return createTile( getFamily( damage ) ); - } - - public final ComputerFamily getFamily( IBlockAccess world, BlockPos pos ) - { - return getFamily( world.getBlockState( pos ) ); - } - - private static void updateInput( IBlockAccess world, BlockPos pos ) - { TileEntity tile = world.getTileEntity( pos ); if( tile instanceof TileComputerBase ) ((TileComputerBase) tile).updateInput(); } @Override + @Deprecated + public boolean canProvidePower( IBlockState state ) + { + return true; + } + + @Override + @Deprecated + public int getStrongPower( IBlockState state, IBlockReader world, BlockPos pos, EnumFacing incomingSide ) + { + TileEntity entity = world.getTileEntity( pos ); + if( !(entity instanceof TileComputerBase) ) return 0; + + TileComputerBase computerEntity = (TileComputerBase) entity; + ServerComputer computer = computerEntity.getServerComputer(); + if( computer == null ) return 0; + + EnumFacing localSide = computerEntity.remapToLocalSide( incomingSide.getOpposite() ); + return computerEntity.isRedstoneBlockedOnSide( localSide ) ? 0 : + computer.getRedstoneOutput( localSide.getIndex() ); + } + @Nonnull - public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult target, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player ) + protected abstract ItemStack getItem( TileComputerBase tile ); + + public ComputerFamily getFamily() + { + return family; + } + + @Override + @Deprecated + public int getWeakPower( IBlockState state, IBlockReader world, BlockPos pos, EnumFacing incomingSide ) + { + return getStrongPower( state, world, pos, incomingSide ); + } + + @Override + public boolean getBundledRedstoneConnectivity( World world, BlockPos pos, EnumFacing side ) + { + TileEntity entity = world.getTileEntity( pos ); + if( !(entity instanceof TileComputerBase) ) return false; + + TileComputerBase computerEntity = (TileComputerBase) entity; + return !computerEntity.isRedstoneBlockedOnSide( computerEntity.remapToLocalSide( side ) ); + } + + @Override + public int getBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side ) + { + TileEntity entity = world.getTileEntity( pos ); + if( !(entity instanceof TileComputerBase) ) return 0; + + TileComputerBase computerEntity = (TileComputerBase) entity; + ServerComputer computer = computerEntity.getServerComputer(); + if( computer == null ) return 0; + + EnumFacing localSide = computerEntity.remapToLocalSide( side ); + return computerEntity.isRedstoneBlockedOnSide( localSide ) ? 0 : + computer.getBundledRedstoneOutput( localSide.getIndex() ); + } + + @Nonnull + @Override + public ItemStack getPickBlock( IBlockState state, RayTraceResult target, IBlockReader world, BlockPos pos, EntityPlayer player ) { TileEntity tile = world.getTileEntity( pos ); if( tile instanceof TileComputerBase ) @@ -103,12 +125,13 @@ public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult target } @Override - public final void dropBlockAsItemWithChance( World world, @Nonnull BlockPos pos, @Nonnull IBlockState state, float chance, int fortune ) + @Deprecated + public final void dropBlockAsItemWithChance( @Nonnull IBlockState state, World world, @Nonnull BlockPos pos, float change, int fortune ) { } @Override - public final void getDrops( @Nonnull NonNullList drops, IBlockAccess world, BlockPos pos, @Nonnull IBlockState state, int fortune ) + public final void getDrops( IBlockState state, NonNullList drops, World world, BlockPos pos, int fortune ) { TileEntity tile = world.getTileEntity( pos ); if( tile instanceof TileComputerBase ) @@ -119,7 +142,7 @@ public final void getDrops( @Nonnull NonNullList drops, IBlockAccess } @Override - public boolean removedByPlayer( @Nonnull IBlockState state, World world, @Nonnull BlockPos pos, @Nonnull EntityPlayer player, boolean willHarvest ) + public boolean removedByPlayer( IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest, IFluidState fluid ) { if( !world.isRemote ) { @@ -129,14 +152,14 @@ public boolean removedByPlayer( @Nonnull IBlockState state, World world, @Nonnul if( tile instanceof TileComputerBase ) { TileComputerBase computer = (TileComputerBase) tile; - if( !player.capabilities.isCreativeMode || computer.getLabel() != null ) + if( !player.abilities.isCreativeMode || computer.getLabel() != null ) { spawnAsEntity( world, pos, getItem( computer ) ); } } } - return super.removedByPlayer( state, world, pos, player, willHarvest ); + return super.removedByPlayer( state, world, pos, player, willHarvest, fluid ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java b/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java index 8c341df33..868fdceb3 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.core.IComputer; public interface IComputerTile { @@ -20,7 +19,4 @@ public interface IComputerTile void setLabel( String label ); ComputerFamily getFamily(); - - @Deprecated - IComputer getComputer(); } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java index b538d5971..8a203ce45 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java @@ -6,21 +6,23 @@ package dan200.computercraft.shared.computer.blocks; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.apis.CommandAPI; +import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; -import io.netty.buffer.ByteBuf; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.Entity; +import dan200.computercraft.shared.util.NamedBlockEntityType; +import net.minecraft.command.CommandSource; +import net.minecraft.command.ICommandSource; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.server.MinecraftServer; -import net.minecraft.tileentity.CommandBlockBaseLogic; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.BlockPos; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.Vec2f; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentTranslation; -import net.minecraft.world.World; +import net.minecraft.world.WorldServer; import javax.annotation.Nonnull; import java.util.HashMap; @@ -28,134 +30,84 @@ public class TileCommandComputer extends TileComputer { - public class CommandSender extends CommandBlockBaseLogic - { - private Map m_outputTable; + public static final NamedBlockEntityType FACTORY = NamedBlockEntityType.create( + new ResourceLocation( ComputerCraft.MOD_ID, "command_computer" ), + f -> new TileCommandComputer( ComputerFamily.Command, f ) + ); - public CommandSender() - { - m_outputTable = new HashMap<>(); - } + public class CommandReceiver implements ICommandSource + { + private final Map output = new HashMap<>(); public void clearOutput() { - m_outputTable.clear(); + output.clear(); } public Map getOutput() { - return m_outputTable; + return output; } public Map copyOutput() { - return new HashMap<>( m_outputTable ); - } - - // ICommandSender - - @Nonnull - @Override - public ITextComponent getDisplayName() - { - String label = getLabel(); - return new TextComponentString( label != null ? label : "@" ); + return new HashMap<>( output ); } @Override - public void sendMessage( @Nonnull ITextComponent chatComponent ) + public void sendMessage( @Nonnull ITextComponent textComponent ) { - m_outputTable.put( m_outputTable.size() + 1, chatComponent.getUnformattedText() ); + output.put( output.size() + 1, textComponent.getString() ); } @Override - public boolean canUseCommand( int level, String command ) + public boolean shouldReceiveFeedback() { - return level <= 2; - } - - @Nonnull - @Override - public BlockPos getPosition() - { - return getPos(); - } - - @Nonnull - @Override - public Vec3d getPositionVector() - { - BlockPos pos = getPosition(); - return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); - } - - @Nonnull - @Override - public World getEntityWorld() - { - return getWorld(); + return getWorld().getGameRules().getBoolean( "sendCommandFeedback" ); } @Override - public MinecraftServer getServer() + public boolean shouldReceiveErrors() { - return getWorld().getMinecraftServer(); + return true; } @Override - public Entity getCommandSenderEntity() - { - return null; - } - - // CommandBlockLogic members intentionally left empty - // The only reason we extend it at all is so that "gameRule commandBlockOutput" applies to us - - @Override - public void updateCommand() - { - } - - @Override - public int getCommandBlockType() - { - return 0; - } - - @Override - public void fillInInfo( @Nonnull ByteBuf buf ) + public boolean allowLogging() { + return getWorld().getGameRules().getBoolean( "commandBlockOutput" ); } } - private CommandSender m_commandSender; + private final CommandReceiver receiver; - public TileCommandComputer() + public TileCommandComputer( ComputerFamily family, TileEntityType type ) { - m_commandSender = new CommandSender(); + super( family, type ); + receiver = new CommandReceiver(); } - @Override - public EnumFacing getDirection() + public CommandReceiver getReceiver() { - IBlockState state = getBlockState(); - return state.getValue( BlockCommandComputer.Properties.FACING ); + return receiver; } - @Override - public void setDirection( EnumFacing dir ) + public CommandSource getSource() { - if( dir.getAxis() == EnumFacing.Axis.Y ) + ServerComputer computer = getServerComputer(); + String name = "@"; + if( computer != null ) { - dir = EnumFacing.NORTH; + String label = computer.getLabel(); + if( label != null ) name = label; } - setBlockState( getBlockState().withProperty( BlockCommandComputer.Properties.FACING, dir ) ); - updateInput(); - } - public CommandSender getCommandSender() - { - return m_commandSender; + return new CommandSource( receiver, + new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ), Vec2f.ZERO, + (WorldServer) getWorld(), 2, + name, new TextComponentString( name ), + getWorld().getServer(), null + ); } @Override @@ -172,12 +124,12 @@ public boolean isUsable( EntityPlayer player, boolean ignoreRange ) MinecraftServer server = player.getServer(); if( server == null || !server.isCommandBlockEnabled() ) { - player.sendMessage( new TextComponentTranslation( "advMode.notEnabled" ) ); + player.sendStatusMessage( new TextComponentTranslation( "advMode.notEnabled" ), true ); return false; } else if( !player.canUseCommandBlock() ) { - player.sendMessage( new TextComponentTranslation( "advMode.notAllowed" ) ); + player.sendStatusMessage( new TextComponentTranslation( "advMode.notAllowed" ), true ); return false; } else 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 e19f265ca..6f132cd98 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -8,32 +8,41 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.Containers; +import dan200.computercraft.shared.util.NamedBlockEntityType; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.EnumFacing; - -import javax.annotation.Nonnull; +import net.minecraft.util.ResourceLocation; public class TileComputer extends TileComputerBase { - private static final String TAG_STATE = "state"; + public static final NamedBlockEntityType FACTORY_NORMAL = NamedBlockEntityType.create( + new ResourceLocation( ComputerCraft.MOD_ID, "computer_normal" ), + f -> new TileComputer( ComputerFamily.Normal, f ) + ); + + public static final NamedBlockEntityType FACTORY_ADVANCED = NamedBlockEntityType.create( + new ResourceLocation( ComputerCraft.MOD_ID, "computer_advanced" ), + f -> new TileComputer( ComputerFamily.Advanced, f ) + ); private ComputerProxy m_proxy; - private ComputerState state = ComputerState.Off; + + public TileComputer( ComputerFamily family, TileEntityType type ) + { + super( type, family ); + } @Override protected ServerComputer createComputer( int instanceID, int id ) { ComputerFamily family = getFamily(); ServerComputer computer = new ServerComputer( - getWorld(), - id, - m_label, - instanceID, - family, + getWorld(), id, m_label, instanceID, family, ComputerCraft.terminalWidth_computer, ComputerCraft.terminalHeight_computer ); @@ -64,65 +73,30 @@ public void openGUI( EntityPlayer player ) Containers.openComputerGUI( player, this ); } - @Override - protected void writeDescription( @Nonnull NBTTagCompound nbt ) - { - super.writeDescription( nbt ); - nbt.setInteger( TAG_STATE, state.ordinal() ); - } - - @Override - protected final void readDescription( @Nonnull NBTTagCompound nbt ) - { - super.readDescription( nbt ); - state = ComputerState.valueOf( nbt.getInteger( TAG_STATE ) ); - updateBlock(); - } - public boolean isUsableByPlayer( EntityPlayer player ) { return isUsable( player, false ); } @Override - public void update() + public EnumFacing getDirection() { - super.update(); - if( !world.isRemote ) + return getBlockState().get( BlockComputer.FACING ); + } + + @Override + protected void updateBlockState( ComputerState newState ) + { + IBlockState existing = getBlockState(); + if( existing.get( BlockComputer.STATE ) != newState ) { - ServerComputer computer = getServerComputer(); - state = computer == null ? ComputerState.Off : computer.getState(); + getWorld().setBlockState( getPos(), existing.with( BlockComputer.STATE, newState ), 3 ); } } - // IDirectionalTile - @Override - public EnumFacing getDirection() + protected EnumFacing remapLocalSide( EnumFacing localSide ) { - IBlockState state = getBlockState(); - return state.getValue( BlockComputer.Properties.FACING ); - } - - @Override - public void setDirection( EnumFacing dir ) - { - if( dir.getAxis() == EnumFacing.Axis.Y ) dir = EnumFacing.NORTH; - setBlockState( getBlockState().withProperty( BlockComputer.Properties.FACING, dir ) ); - updateInput(); - } - - // For legacy reasons, computers invert the meaning of "left" and "right" - private static final int[] s_remapSide = new int[] { 0, 1, 2, 3, 5, 4 }; - - @Override - protected int remapLocalSide( int localSide ) - { - return s_remapSide[localSide]; - } - - public ComputerState getState() - { - return state; + return localSide.getAxis() == EnumFacing.Axis.X ? localSide.getOpposite() : 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 70545de15..e50c9aa9d 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -11,35 +11,38 @@ import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.BundledRedstone; import dan200.computercraft.shared.Peripherals; -import dan200.computercraft.shared.common.IDirectionalTile; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.core.IComputer; +import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.RedstoneUtil; import joptsimple.internal.Strings; -import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; +import net.minecraft.util.INameable; import net.minecraft.util.ITickable; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextComponentTranslation; -import net.minecraft.world.IWorldNameable; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Objects; -public abstract class TileComputerBase extends TileGeneric implements IComputerTile, IDirectionalTile, ITickable, IPeripheralTile, IWorldNameable +public abstract class TileComputerBase extends TileGeneric implements IComputerTile, ITickable, IPeripheralTile, INameable { + private static final String NBT_ID = "ComputerId"; + private static final String NBT_LABEL = "Label"; + private static final String NBT_INSTANCE = "InstanceId"; + private static final String NBT_ON = "On"; + private int m_instanceID = -1; private int m_computerID = -1; protected String m_label = null; @@ -47,11 +50,12 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT boolean m_startOn = false; private boolean m_fresh = false; - @Override - public BlockComputerBase getBlock() + private final ComputerFamily family; + + public TileComputerBase( TileEntityType type, ComputerFamily family ) { - Block block = super.getBlock(); - return block instanceof BlockComputerBase ? (BlockComputerBase) block : null; + super( type ); + this.family = family; } protected void unload() @@ -67,23 +71,23 @@ protected void unload() public void destroy() { unload(); - for( EnumFacing dir : EnumFacing.VALUES ) + for( EnumFacing dir : DirectionUtil.FACINGS ) { RedstoneUtil.propagateRedstoneOutput( getWorld(), getPos(), dir ); } } @Override - public void onChunkUnload() + public void onChunkUnloaded() { unload(); } @Override - public void invalidate() + public void remove() { unload(); - super.invalidate(); + super.remove(); } public abstract void openGUI( EntityPlayer player ); @@ -102,7 +106,7 @@ public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, // Label to rename computer if( !getWorld().isRemote ) { - setLabel( currentItem.getDisplayName() ); + setLabel( currentItem.getDisplayName().getString() ); currentItem.shrink( 1 ); } return true; @@ -120,51 +124,6 @@ else if( !player.isSneaking() ) return false; } - @Override - public boolean getRedstoneConnectivity( EnumFacing side ) - { - if( side == null ) return false; - int localDir = remapLocalSide( DirectionUtil.toLocal( this, side.getOpposite() ) ); - return !isRedstoneBlockedOnSide( localDir ); - } - - @Override - public int getRedstoneOutput( EnumFacing side ) - { - int localDir = remapLocalSide( DirectionUtil.toLocal( this, side ) ); - if( !isRedstoneBlockedOnSide( localDir ) && getWorld() != null && !getWorld().isRemote ) - { - ServerComputer computer = getServerComputer(); - if( computer != null ) return computer.getRedstoneOutput( localDir ); - } - return 0; - } - - @Override - public boolean getBundledRedstoneConnectivity( @Nonnull EnumFacing side ) - { - int localDir = remapLocalSide( DirectionUtil.toLocal( this, side ) ); - return !isRedstoneBlockedOnSide( localDir ); - } - - @Override - public int getBundledRedstoneOutput( @Nonnull EnumFacing side ) - { - int localDir = remapLocalSide( DirectionUtil.toLocal( this, side ) ); - if( !isRedstoneBlockedOnSide( localDir ) ) - { - if( !getWorld().isRemote ) - { - ServerComputer computer = getServerComputer(); - if( computer != null ) - { - return computer.getBundledRedstoneOutput( localDir ); - } - } - } - return 0; - } - @Override public void onNeighbourChange( @Nonnull BlockPos neighbour ) { @@ -178,27 +137,34 @@ public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour ) } @Override - public void update() + public void tick() { if( !getWorld().isRemote ) { ServerComputer computer = createServerComputer(); - if( computer != null ) + if( computer == null ) return; + + // If the computer isn't on and should be, then turn it on + if( m_startOn || (m_fresh && m_on) ) { - if( m_startOn || (m_fresh && m_on) ) - { - computer.turnOn(); - m_startOn = false; - } - computer.keepAlive(); - - m_fresh = false; - m_computerID = computer.getID(); - m_label = computer.getLabel(); - m_on = computer.isOn(); - - if( computer.hasOutputChanged() ) updateOutput(); + computer.turnOn(); + m_startOn = false; } + + computer.keepAlive(); + + m_fresh = false; + m_computerID = computer.getID(); + m_label = computer.getLabel(); + m_on = computer.isOn(); + + if( computer.hasOutputChanged() ) updateOutput(); + + // Update the block state if needed. We don't fire a block update intentionally, + // as this only really is needed on the client side. + updateBlockState( computer.getState() ); + + if( computer.hasOutputChanged() ) updateOutput(); } else { @@ -207,69 +173,49 @@ public void update() } } + protected abstract void updateBlockState( ComputerState newState ); + @Nonnull @Override - public NBTTagCompound writeToNBT( NBTTagCompound nbt ) + public NBTTagCompound write( NBTTagCompound nbt ) { // Save ID, label and power state - if( m_computerID >= 0 ) - { - nbt.setInteger( "computerID", m_computerID ); - } - if( m_label != null ) - { - nbt.setString( "label", m_label ); - } - nbt.setBoolean( "on", m_on ); - return super.writeToNBT( nbt ); + if( m_computerID >= 0 ) nbt.putInt( NBT_ID, m_computerID ); + if( m_label != null ) nbt.putString( NBT_LABEL, m_label ); + nbt.putBoolean( NBT_ON, m_on ); + + return super.write( nbt ); } @Override - public void readFromNBT( NBTTagCompound nbt ) + public void read( NBTTagCompound nbt ) { - super.readFromNBT( nbt ); + super.read( nbt ); - // Load ID - int id = -1; - if( nbt.hasKey( "computerID" ) ) - { - // Post-1.6 computers - id = nbt.getInteger( "computerID" ); - } - else if( nbt.hasKey( "userDir" ) ) - { - // Pre-1.6 computers - String userDir = nbt.getString( "userDir" ); - try - { - id = Integer.parseInt( userDir ); - } - catch( NumberFormatException e ) - { - // Ignore badly formatted data - } - } - m_computerID = id; - - // Load label - m_label = nbt.hasKey( "label" ) ? nbt.getString( "label" ) : null; - - // Load power state - m_startOn = nbt.getBoolean( "on" ); - m_on = m_startOn; + // Load ID, label and power state + m_computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; + m_label = nbt.contains( NBT_LABEL ) ? nbt.getString( NBT_LABEL ) : null; + m_on = m_startOn = nbt.getBoolean( NBT_ON ); } - protected boolean isPeripheralBlockedOnSide( int localSide ) + protected boolean isPeripheralBlockedOnSide( EnumFacing localSide ) { return false; } - protected boolean isRedstoneBlockedOnSide( int localSide ) + protected boolean isRedstoneBlockedOnSide( EnumFacing localSide ) { return false; } - protected int remapLocalSide( int localSide ) + protected abstract EnumFacing getDirection(); + + protected EnumFacing remapToLocalSide( EnumFacing globalSide ) + { + return remapLocalSide( DirectionUtil.toLocal( getDirection(), globalSide ) ); + } + + protected EnumFacing remapLocalSide( EnumFacing localSide ) { return localSide; } @@ -277,15 +223,15 @@ protected int remapLocalSide( int localSide ) private void updateSideInput( ServerComputer computer, EnumFacing dir, BlockPos offset ) { EnumFacing offsetSide = dir.getOpposite(); - int localDir = remapLocalSide( DirectionUtil.toLocal( this, dir ) ); + EnumFacing localDir = remapToLocalSide( dir ); if( !isRedstoneBlockedOnSide( localDir ) ) { - computer.setRedstoneInput( localDir, getWorld().getRedstonePower( offset, dir ) ); - computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getWorld(), offset, offsetSide ) ); + computer.setRedstoneInput( localDir.getIndex(), getWorld().getRedstonePower( offset, dir ) ); + computer.setBundledRedstoneInput( localDir.getIndex(), BundledRedstone.getOutput( getWorld(), offset, offsetSide ) ); } if( !isPeripheralBlockedOnSide( localDir ) ) { - computer.setPeripheral( localDir, Peripherals.getPeripheral( getWorld(), offset, offsetSide ) ); + computer.setPeripheral( localDir.getIndex(), Peripherals.getPeripheral( getWorld(), offset, offsetSide ) ); } } @@ -293,33 +239,33 @@ public void updateInput() { if( getWorld() == null || getWorld().isRemote ) return; - // Update redstone and peripherals + // Update all sides ServerComputer computer = getServerComputer(); if( computer == null ) return; BlockPos pos = computer.getPosition(); - for( EnumFacing dir : EnumFacing.VALUES ) + for( EnumFacing dir : DirectionUtil.FACINGS ) { updateSideInput( computer, dir, pos.offset( dir ) ); } } - public void updateInput( BlockPos neighbour ) + private void updateInput( BlockPos neighbour ) { if( getWorld() == null || getWorld().isRemote ) return; ServerComputer computer = getServerComputer(); - if( computer != null ) + if( computer == null ) return; + + // Find the appropriate side and update. + BlockPos pos = computer.getPosition(); + for( EnumFacing dir : DirectionUtil.FACINGS ) { - BlockPos pos = computer.getPosition(); - for( EnumFacing dir : EnumFacing.VALUES ) + BlockPos offset = pos.offset( dir ); + if( offset.equals( neighbour ) ) { - BlockPos offset = pos.offset( dir ); - if( offset.equals( neighbour ) ) - { - updateSideInput( computer, dir, offset ); - break; - } + updateSideInput( computer, dir, offset ); + break; } } } @@ -328,7 +274,7 @@ public void updateOutput() { // Update redstone updateBlock(); - for( EnumFacing dir : EnumFacing.VALUES ) + for( EnumFacing dir : DirectionUtil.FACINGS ) { RedstoneUtil.propagateRedstoneOutput( getWorld(), getPos(), dir ); } @@ -338,8 +284,6 @@ public void updateOutput() public abstract ComputerProxy createProxy(); - // IComputerTile - @Override public final int getComputerID() { @@ -377,15 +321,7 @@ public final void setLabel( String label ) @Override public ComputerFamily getFamily() { - BlockComputerBase block = getBlock(); - return block != null ? block.getFamily( getWorld(), getPos() ) : ComputerFamily.Normal; - } - - @Override - @Deprecated - public IComputer getComputer() - { - return getWorld().isRemote ? getClientComputer() : getServerComputer(); + return family; } public ServerComputer createServerComputer() @@ -441,18 +377,19 @@ public ClientComputer getClientComputer() protected void writeDescription( @Nonnull NBTTagCompound nbt ) { super.writeDescription( nbt ); - nbt.setInteger( "instanceID", createServerComputer().getInstanceID() ); - if( m_label != null ) nbt.setString( "label", m_label ); - if( m_computerID >= 0 ) nbt.setInteger( "computerID", m_computerID ); + + if( m_computerID >= 0 ) nbt.putInt( NBT_ID, m_computerID ); + if( m_label != null ) nbt.putString( NBT_LABEL, m_label ); + nbt.putInt( NBT_INSTANCE, createServerComputer().getInstanceID() ); } @Override protected void readDescription( @Nonnull NBTTagCompound nbt ) { super.readDescription( nbt ); - m_instanceID = nbt.getInteger( "instanceID" ); - m_label = nbt.hasKey( "label" ) ? nbt.getString( "label" ) : null; - m_computerID = nbt.hasKey( "computerID" ) ? nbt.getInteger( "computerID" ) : -1; + m_instanceID = nbt.contains( NBT_INSTANCE ) ? nbt.getInt( NBT_INSTANCE ) : -1; + m_label = nbt.contains( NBT_LABEL ) ? nbt.getString( NBT_LABEL ) : null; + m_computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; } protected void transferStateFrom( TileComputerBase copy ) @@ -479,9 +416,9 @@ public IPeripheral getPeripheral( @Nonnull EnumFacing side ) @Nonnull @Override - public String getName() + public ITextComponent getName() { - return hasCustomName() ? m_label : getBlockType().getTranslationKey(); + return hasCustomName() ? new TextComponentString( m_label ) : getBlockState().getBlock().getNameTextComponent(); } @Override @@ -490,10 +427,10 @@ public boolean hasCustomName() return !Strings.isNullOrEmpty( m_label ); } - @Nonnull + @Nullable @Override - public ITextComponent getDisplayName() + public ITextComponent getCustomName() { - return hasCustomName() ? new TextComponentString( getName() ) : new TextComponentTranslation( getName() ); + return hasCustomName() ? new TextComponentString( m_label ) : null; } } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java index b3f2fdfc7..7c029380d 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java @@ -8,7 +8,6 @@ import com.google.common.base.Objects; import dan200.computercraft.shared.common.ClientTerminal; -import dan200.computercraft.shared.computer.blocks.ComputerState; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.server.*; import net.minecraft.nbt.NBTTagCompound; @@ -60,20 +59,6 @@ public int getInstanceID() return m_instanceID; } - @Override - @Deprecated - public int getID() - { - return -1; - } - - @Override - @Deprecated - public String getLabel() - { - return null; - } - @Override public boolean isOn() { @@ -156,8 +141,8 @@ public void setState( ComputerState state, NBTTagCompound userData ) boolean oldBlinking = m_blinking; NBTTagCompound oldUserData = m_userData; - m_on = state != ComputerState.Off; - m_blinking = state == ComputerState.Blinking; + m_on = state != ComputerState.OFF; + m_blinking = state == ComputerState.BLINKING; m_userData = userData; m_changed |= m_on != oldOn || m_blinking != oldBlinking || !Objects.equal( m_userData, oldUserData ); diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java index c8ed459af..30fa94f3c 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java @@ -10,6 +10,5 @@ public enum ComputerFamily { Normal, Advanced, - @Deprecated Beginners, Command } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerState.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java similarity index 55% rename from src/main/java/dan200/computercraft/shared/computer/blocks/ComputerState.java rename to src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java index f719b0919..88dc8e752 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerState.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java @@ -4,7 +4,7 @@ * Send enquiries to dratcliffe@gmail.com */ -package dan200.computercraft.shared.computer.blocks; +package dan200.computercraft.shared.computer.core; import net.minecraft.util.IStringSerializable; @@ -12,14 +12,9 @@ public enum ComputerState implements IStringSerializable { - Off( "off" ), - On( "on" ), - Blinking( "blinking" ); - - private static final ComputerState[] VALUES = ComputerState.values(); - - // TODO: Move to dan200.computercraft.shared.computer.core in the future. We can't do it now - // as Plethora depends on it. + OFF( "off" ), + ON( "on" ), + BLINKING( "blinking" ); private final String name; @@ -40,10 +35,5 @@ public String toString() { return name; } - - public static ComputerState valueOf( int ordinal ) - { - return ordinal < 0 || ordinal >= VALUES.length ? ComputerState.Off : VALUES[ordinal]; - } } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java index 3d8a21b01..249d5b7c9 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java @@ -7,18 +7,11 @@ package dan200.computercraft.shared.computer.core; import dan200.computercraft.shared.common.ITerminal; -import dan200.computercraft.shared.computer.blocks.ComputerState; public interface IComputer extends ITerminal, InputHandler { int getInstanceID(); - @Deprecated - int getID(); - - @Deprecated - String getLabel(); - boolean isOn(); boolean isCursorDisplayed(); @@ -39,7 +32,7 @@ default void queueEvent( String event ) default ComputerState getState() { - if( !isOn() ) return ComputerState.Off; - return isCursorDisplayed() ? ComputerState.Blinking : ComputerState.On; + if( !isOn() ) return ComputerState.OFF; + return isCursorDisplayed() ? ComputerState.BLINKING : ComputerState.ON; } } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/IComputerContainer.java b/src/main/java/dan200/computercraft/shared/computer/core/IComputerContainer.java deleted file mode 100644 index 7654eaa25..000000000 --- a/src/main/java/dan200/computercraft/shared/computer/core/IComputerContainer.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * 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.shared.computer.core; - -@FunctionalInterface -public interface IComputerContainer -{ - IComputer getComputer(); -} 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 1a7cab3b6..59d634823 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -17,19 +17,18 @@ import dan200.computercraft.core.computer.IComputerEnvironment; import dan200.computercraft.shared.common.ServerTerminal; import dan200.computercraft.shared.network.NetworkHandler; +import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.client.ComputerDataClientMessage; import dan200.computercraft.shared.network.client.ComputerDeletedClientMessage; import dan200.computercraft.shared.network.client.ComputerTerminalClientMessage; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.inventory.Container; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.Loader; -import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.server.ServerLifecycleHooks; +import net.minecraftforge.versions.mcp.MCPVersion; import javax.annotation.Nullable; import java.io.InputStream; @@ -148,12 +147,12 @@ public void updateUserData() m_changed = true; } - private IMessage createComputerPacket() + private NetworkMessage createComputerPacket() { return new ComputerDataClientMessage( this ); } - protected IMessage createTerminalPacket() + protected NetworkMessage createTerminalPacket() { NBTTagCompound tagCompound = new NBTTagCompound(); writeDescription( tagCompound ); @@ -171,18 +170,12 @@ public void broadcastState( boolean force ) if( hasTerminalChanged() || force ) { // Send terminal state to clients who are currently interacting with the computer. - FMLCommonHandler handler = FMLCommonHandler.instance(); - if( handler != null ) + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + + NetworkMessage packet = createTerminalPacket(); + for( EntityPlayer player : server.getPlayerList().getPlayers() ) { - IMessage packet = createTerminalPacket(); - MinecraftServer server = handler.getMinecraftServerInstance(); - for( EntityPlayerMP player : server.getPlayerList().getPlayers() ) - { - if( isInteracting( player ) ) - { - NetworkHandler.sendToPlayer( player, packet ); - } - } + if( isInteracting( player ) ) NetworkHandler.sendToPlayer( player, packet ); } } } @@ -218,15 +211,11 @@ public int getInstanceID() return m_instanceID; } - @Override - @SuppressWarnings( "deprecation" ) public int getID() { return m_computer.getID(); } - @Override - @SuppressWarnings( "deprecation" ) public String getLabel() { return m_computer.getLabel(); @@ -297,12 +286,6 @@ public void addAPI( ILuaAPI api ) m_computer.addApi( api ); } - @Deprecated - public void addAPI( dan200.computercraft.core.apis.ILuaAPI api ) - { - m_computer.addAPI( api ); - } - public void setPeripheral( int side, IPeripheral peripheral ) { m_computer.getEnvironment().setPeripheral( side, peripheral ); @@ -323,13 +306,13 @@ public void setLabel( String label ) @Override public double getTimeOfDay() { - return (m_world.getWorldTime() + 6000) % 24000 / 1000.0; + return (m_world.getGameTime() + 6000) % 24000 / 1000.0; } @Override public int getDay() { - return (int) ((m_world.getWorldTime() + 6000) / 24000) + 1; + return (int) ((m_world.getGameTime() + 6000) / 24000) + 1; } @Override @@ -341,13 +324,13 @@ public IWritableMount createSaveDirMount( String subPath, long capacity ) @Override public IMount createResourceMount( String domain, String subPath ) { - return ComputerCraftAPI.createResourceMount( ComputerCraft.class, domain, subPath ); + return ComputerCraftAPI.createResourceMount( domain, subPath ); } @Override public InputStream createResourceFile( String domain, String subPath ) { - return ComputerCraft.getResourceFile( ComputerCraft.class, domain, subPath ); + return ComputerCraft.getResourceFile( domain, subPath ); } @Override @@ -359,7 +342,7 @@ public long getComputerSpaceLimit() @Override public String getHostString() { - return "ComputerCraft ${version} (Minecraft " + Loader.MC_VERSION + ")"; + return "ComputerCraft ${version} (Minecraft " + MCPVersion.getMCVersion() + ")"; } @Override diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java index 60d995e5d..098fc2959 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java @@ -52,12 +52,12 @@ public boolean canInteractWith( @Nonnull EntityPlayer player ) MinecraftServer server = player.getServer(); if( server == null || !server.isCommandBlockEnabled() ) { - player.sendMessage( new TextComponentTranslation( "advMode.notEnabled" ) ); + player.sendStatusMessage( new TextComponentTranslation( "advMode.notEnabled" ), false ); return false; } else if( !player.canUseCommandBlock() ) { - player.sendMessage( new TextComponentTranslation( "advMode.notAllowed" ) ); + player.sendStatusMessage( new TextComponentTranslation( "advMode.notAllowed" ), false ); return false; } } diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java index 847355e60..0b0337b01 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java @@ -31,10 +31,11 @@ public static ItemStack create( int id, String label, ComputerFamily family ) switch( family ) { case Normal: + return ComputerCraft.Items.computerNormal.create( id, label ); case Advanced: - return ComputerCraft.Items.computer.create( id, label, family ); + return ComputerCraft.Items.computerAdvanced.create( id, label ); case Command: - return ComputerCraft.Items.commandComputer.create( id, label, family ); + return ComputerCraft.Items.computerCommand.create( id, label ); default: return ItemStack.EMPTY; } diff --git a/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java b/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java index 8c85b704c..d243dc50a 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java @@ -14,20 +14,20 @@ public interface IComputerItem { - String NBT_ID = "computerID"; + String NBT_ID = "ComputerId"; default int getComputerID( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTagCompound(); - return nbt != null && nbt.hasKey( NBT_ID ) ? nbt.getInteger( NBT_ID ) : -1; + NBTTagCompound nbt = stack.getTag(); + return nbt != null && nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; } default String getLabel( @Nonnull ItemStack stack ) { - return stack.hasDisplayName() ? stack.getDisplayName() : null; + return stack.hasDisplayName() ? stack.getDisplayName().getString() : null; } - ComputerFamily getFamily( @Nonnull ItemStack stack ); + ComputerFamily getFamily(); ItemStack withFamily( @Nonnull ItemStack stack, @Nonnull ComputerFamily family ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemCommandComputer.java deleted file mode 100644 index 2ebe4f9e5..000000000 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemCommandComputer.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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.shared.computer.items; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import net.minecraft.block.Block; -import net.minecraft.creativetab.CreativeTabs; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.NonNullList; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public class ItemCommandComputer extends ItemComputer -{ - public ItemCommandComputer( Block block ) - { - super( block ); - setMaxStackSize( 64 ); - setHasSubtypes( true ); - setTranslationKey( "computercraft:command_computer" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - } - - @Override - public ItemStack create( int id, String label, ComputerFamily family ) - { - // Ignore types we can't handle - if( family != ComputerFamily.Command ) - { - return null; - } - - // Build the stack - ItemStack result = new ItemStack( this, 1, 0 ); - - if( id >= 0 ) - { - NBTTagCompound nbt = new NBTTagCompound(); - nbt.setInteger( "computerID", id ); - result.setTagCompound( nbt ); - } - - if( label != null ) - { - result.setStackDisplayName( label ); - } - - return result; - } - - @Override - public void getSubItems( @Nullable CreativeTabs tabs, @Nonnull NonNullList list ) - { - if( !isInCreativeTab( tabs ) ) return; - list.add( ComputerItemFactory.create( -1, null, ComputerFamily.Command ) ); - } - - // IComputerItem implementation - - @Override - public int getComputerID( @Nonnull ItemStack stack ) - { - if( stack.hasTagCompound() && stack.getTagCompound().hasKey( "computerID" ) ) - { - return stack.getTagCompound().getInteger( "computerID" ); - } - return -1; - } - - @Override - public ComputerFamily getFamily( int damage ) - { - return ComputerFamily.Command; - } -} diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java index e20a660a2..6c36c8ae5 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java @@ -6,116 +6,33 @@ package dan200.computercraft.shared.computer.items; -import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.computer.blocks.BlockComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; -import net.minecraft.block.Block; -import net.minecraft.creativetab.CreativeTabs; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.NonNullList; -import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.TextComponentString; import javax.annotation.Nonnull; -import javax.annotation.Nullable; public class ItemComputer extends ItemComputerBase { - public static final int HIGHEST_DAMAGE_VALUE_ID = 16382; - - public ItemComputer( Block block ) + public ItemComputer( BlockComputer block, Properties settings ) { - super( block ); - setMaxStackSize( 64 ); - setHasSubtypes( true ); - setTranslationKey( "computercraft:computer" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - addPropertyOverride( new ResourceLocation( ComputerCraft.MOD_ID, "family" ), ( stack, world, player ) -> - getFamily( stack ) == ComputerFamily.Advanced ? 1 : 0 ); + super( block, settings ); } - public ItemStack create( int id, String label, ComputerFamily family ) + public ItemStack create( int id, String label ) { - // Ignore types we can't handle - if( family != ComputerFamily.Normal && family != ComputerFamily.Advanced ) - { - return null; - } - - // Build the damage - int damage = 0; - if( id >= 0 && id <= ItemComputer.HIGHEST_DAMAGE_VALUE_ID ) - { - damage = id + 1; - } - if( family == ComputerFamily.Advanced ) - { - damage += 0x4000; - } - - // Return the stack - ItemStack result = new ItemStack( this, 1, damage ); - if( id > ItemComputer.HIGHEST_DAMAGE_VALUE_ID ) - { - NBTTagCompound nbt = new NBTTagCompound(); - nbt.setInteger( "computerID", id ); - result.setTagCompound( nbt ); - } - if( label != null ) - { - result.setStackDisplayName( label ); - } + ItemStack result = new ItemStack( this ); + if( id >= 0 ) result.getOrCreateTag().putInt( NBT_ID, id ); + if( label != null ) result.setDisplayName( new TextComponentString( label ) ); return result; } - @Override - public void getSubItems( @Nullable CreativeTabs tabs, @Nonnull NonNullList list ) - { - if( !isInCreativeTab( tabs ) ) return; - list.add( ComputerItemFactory.create( -1, null, ComputerFamily.Normal ) ); - list.add( ComputerItemFactory.create( -1, null, ComputerFamily.Advanced ) ); - } - - @Nonnull - @Override - public String getTranslationKey( @Nonnull ItemStack stack ) - { - switch( getFamily( stack ) ) - { - case Normal: - default: - return "tile.computercraft:computer"; - case Advanced: - return "tile.computercraft:advanced_computer"; - case Command: - return "tile.computercraft:command_computer"; - } - } - - // IComputerItem implementation - - @Override - public int getComputerID( @Nonnull ItemStack stack ) - { - if( stack.hasTagCompound() && stack.getTagCompound().hasKey( "computerID" ) ) - { - return stack.getTagCompound().getInteger( "computerID" ); - } - else - { - int damage = stack.getItemDamage() & 0x3fff; - return damage - 1; - } - } - @Override public ItemStack withFamily( @Nonnull ItemStack stack, @Nonnull ComputerFamily family ) { - return ComputerItemFactory.create( getComputerID( stack ), getLabel( stack ), family ); - } - - @Override - public ComputerFamily getFamily( int damage ) - { - return (damage & 0x4000) == 0 ? ComputerFamily.Normal : ComputerFamily.Advanced; + ItemStack result = ComputerItemFactory.create( getComputerID( stack ), null, family ); + if( stack.hasDisplayName() ) result.setDisplayName( stack.getDisplayName() ); + return result; } } diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java index 7171e741e..377e41959 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java @@ -10,12 +10,15 @@ import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.media.IMedia; +import dan200.computercraft.shared.computer.blocks.BlockComputerBase; import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.util.StringUtil; -import net.minecraft.block.Block; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -24,26 +27,25 @@ public abstract class ItemComputerBase extends ItemBlock implements IComputerItem, IMedia { - protected ItemComputerBase( Block block ) - { - super( block ); - } + private final ComputerFamily family; - public abstract ComputerFamily getFamily( int damage ); - - @Override - public final int getMetadata( int damage ) + public ItemComputerBase( BlockComputerBase block, Properties settings ) { - return damage; + super( block, settings ); + family = block.getFamily(); } @Override - public void addInformation( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, @Nonnull ITooltipFlag flag ) + public void addInformation( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, @Nonnull ITooltipFlag options ) { - if( flag.isAdvanced() ) + if( options.isAdvanced() ) { int id = getComputerID( stack ); - if( id >= 0 ) list.add( StringUtil.translateFormatted( "gui.computercraft.tooltip.computer_id", id ) ); + if( id >= 0 ) + { + list.add( new TextComponentTranslation( "gui.computercraft.tooltip.computer_id", id ) + .applyTextStyle( TextFormatting.GRAY ) ); + } } } @@ -54,9 +56,9 @@ public String getLabel( @Nonnull ItemStack stack ) } @Override - public final ComputerFamily getFamily( @Nonnull ItemStack stack ) + public final ComputerFamily getFamily() { - return getFamily( stack.getItemDamage() ); + return family; } // IMedia implementation @@ -66,7 +68,7 @@ public boolean setLabel( @Nonnull ItemStack stack, String label ) { if( label != null ) { - stack.setStackDisplayName( label ); + stack.setDisplayName( new TextComponentString( label ) ); } else { @@ -78,7 +80,7 @@ public boolean setLabel( @Nonnull ItemStack stack, String label ) @Override public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world ) { - ComputerFamily family = getFamily( stack ); + ComputerFamily family = getFamily(); if( family != ComputerFamily.Command ) { int id = getComputerID( stack ); diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java index dee45d203..e93f77260 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java @@ -7,29 +7,34 @@ package dan200.computercraft.shared.computer.recipe; import dan200.computercraft.shared.computer.items.IComputerItem; -import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.ShapedRecipes; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.item.crafting.ShapedRecipe; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; -import net.minecraftforge.common.crafting.CraftingHelper; import javax.annotation.Nonnull; /** * Represents a recipe which converts a computer from one form into another. */ -public abstract class ComputerConvertRecipe extends ShapedRecipes +public abstract class ComputerConvertRecipe extends ShapedRecipe { - public ComputerConvertRecipe( String group, @Nonnull CraftingHelper.ShapedPrimer primer, @Nonnull ItemStack result ) + private final String group; + + public ComputerConvertRecipe( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result ) { - super( group, primer.width, primer.height, primer.input, result ); + super( identifier, group, width, height, ingredients, result ); + this.group = group; } @Nonnull protected abstract ItemStack convert( @Nonnull IComputerItem item, @Nonnull ItemStack stack ); @Override - public boolean matches( @Nonnull InventoryCrafting inventory, @Nonnull World world ) + public boolean matches( @Nonnull IInventory inventory, @Nonnull World world ) { if( !super.matches( inventory, world ) ) return false; @@ -43,7 +48,7 @@ public boolean matches( @Nonnull InventoryCrafting inventory, @Nonnull World wor @Nonnull @Override - public ItemStack getCraftingResult( @Nonnull InventoryCrafting inventory ) + public ItemStack getCraftingResult( @Nonnull IInventory inventory ) { // Find our computer item and convert it. for( int i = 0; i < inventory.getSizeInventory(); i++ ) @@ -54,4 +59,11 @@ public ItemStack getCraftingResult( @Nonnull InventoryCrafting inventory ) return ItemStack.EMPTY; } + + @Nonnull + @Override + public String getGroup() + { + return group; + } } diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java index 0b3cd7475..3911c3534 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java @@ -8,46 +8,74 @@ import com.google.gson.JsonObject; import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.items.IComputerItem; import dan200.computercraft.shared.util.RecipeUtil; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.network.PacketBuffer; import net.minecraft.util.JsonUtils; -import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.common.crafting.IRecipeFactory; -import net.minecraftforge.common.crafting.JsonContext; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; import javax.annotation.Nonnull; -public class ComputerFamilyRecipe extends ComputerConvertRecipe +public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe { private final ComputerFamily family; - public ComputerFamilyRecipe( String group, @Nonnull CraftingHelper.ShapedPrimer primer, @Nonnull ItemStack result, ComputerFamily family ) + public ComputerFamilyRecipe( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family ) { - super( group, primer, result ); + super( identifier, group, width, height, ingredients, result ); this.family = family; } - @Nonnull - @Override - protected ItemStack convert( @Nonnull IComputerItem item, @Nonnull ItemStack stack ) + public ComputerFamily getFamily() { - return item.withFamily( stack, family ); + return family; } - public static class Factory implements IRecipeFactory + public abstract static class Serializer implements IRecipeSerializer { + protected abstract T create( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family ); + + @Nonnull @Override - public IRecipe parse( JsonContext context, JsonObject json ) + public T read( @Nonnull ResourceLocation identifier, @Nonnull JsonObject json ) { String group = JsonUtils.getString( json, "group", "" ); ComputerFamily family = RecipeUtil.getFamily( json, "family" ); - CraftingHelper.ShapedPrimer primer = RecipeUtil.getPrimer( context, json ); - ItemStack result = deserializeItem( JsonUtils.getJsonObject( json, "result" ), false ); + RecipeUtil.ShapedTemplate template = RecipeUtil.getTemplate( json ); + ItemStack result = deserializeItem( JsonUtils.getJsonObject( json, "result" ) ); - return new ComputerFamilyRecipe( group, primer, result, family ); + return create( identifier, group, template.width, template.height, template.ingredients, result, family ); + } + + @Nonnull + @Override + public T read( @Nonnull ResourceLocation identifier, @Nonnull PacketBuffer buf ) + { + int width = buf.readVarInt(); + int height = buf.readVarInt(); + String group = buf.readString( Short.MAX_VALUE ); + + NonNullList ingredients = NonNullList.withSize( width * height, Ingredient.EMPTY ); + for( int i = 0; i < ingredients.size(); i++ ) ingredients.set( i, Ingredient.read( buf ) ); + + ItemStack result = buf.readItemStack(); + ComputerFamily family = buf.readEnumValue( ComputerFamily.class ); + return create( identifier, group, width, height, ingredients, result, family ); + } + + @Override + public void write( @Nonnull PacketBuffer buf, @Nonnull T recipe ) + { + buf.writeVarInt( recipe.getWidth() ); + buf.writeVarInt( recipe.getHeight() ); + buf.writeString( recipe.getGroup() ); + for( Ingredient ingredient : recipe.getIngredients() ) ingredient.write( buf ); + buf.writeItemStack( recipe.getRecipeOutput() ); + buf.writeEnumValue( recipe.getFamily() ); } } } diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerIngredient.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerIngredient.java deleted file mode 100644 index 4ce036e1b..000000000 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerIngredient.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.shared.computer.recipe; - -import com.google.gson.JsonObject; -import com.google.gson.JsonSyntaxException; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.items.IComputerItem; -import dan200.computercraft.shared.util.RecipeUtil; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.Ingredient; -import net.minecraft.util.JsonUtils; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.common.crafting.IIngredientFactory; -import net.minecraftforge.common.crafting.JsonContext; -import net.minecraftforge.fml.common.registry.ForgeRegistries; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * Represents an ingredient which requires an item to have a specific - * computer family. This allows us to have operations which only work - * on normal or - */ -public class ComputerIngredient extends Ingredient -{ - private final IComputerItem item; - private final ComputerFamily family; - - public ComputerIngredient( T item, int data, ComputerFamily family ) - { - super( new ItemStack( item, 1, data ) ); - - this.item = item; - this.family = family; - } - - @Override - public boolean apply( @Nullable ItemStack stack ) - { - return stack != null && stack.getItem() == item && item.getFamily( stack ) == family; - } - - public static class Factory implements IIngredientFactory - { - @Nonnull - @Override - public Ingredient parse( JsonContext context, JsonObject json ) - { - String itemName = context.appendModId( JsonUtils.getString( json, "item" ) ); - int data = JsonUtils.getInt( json, "data", 0 ); - ComputerFamily family = RecipeUtil.getFamily( json, "family" ); - - Item item = ForgeRegistries.ITEMS.getValue( new ResourceLocation( itemName ) ); - - if( item == null ) throw new JsonSyntaxException( "Unknown item '" + itemName + "'" ); - if( !(item instanceof IComputerItem) ) - { - throw new JsonSyntaxException( "Item '" + itemName + "' is not a computer item" ); - } - - - return new ComputerIngredient( (Item & IComputerItem) item, data, family ); - } - } -} diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java new file mode 100644 index 000000000..e7604f2df --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java @@ -0,0 +1,57 @@ +/* + * 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.shared.computer.recipe; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.items.IComputerItem; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nonnull; + +public class ComputerUpgradeRecipe extends ComputerFamilyRecipe +{ + public ComputerUpgradeRecipe( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family ) + { + super( identifier, group, width, height, ingredients, result, family ); + } + + @Nonnull + @Override + protected ItemStack convert( @Nonnull IComputerItem item, @Nonnull ItemStack stack ) + { + return item.withFamily( stack, getFamily() ); + } + + @Nonnull + @Override + public IRecipeSerializer getSerializer() + { + return SERIALIZER; + } + + private static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "computer_upgrade" ); + public static final IRecipeSerializer SERIALIZER = new Serializer() + { + @Override + protected ComputerUpgradeRecipe create( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family ) + { + return new ComputerUpgradeRecipe( identifier, group, width, height, ingredients, result, family ); + } + + @Nonnull + @Override + public ResourceLocation getName() + { + return ID; + } + }; +} diff --git a/src/main/java/dan200/computercraft/shared/datafix/Fixes.java b/src/main/java/dan200/computercraft/shared/datafix/Fixes.java deleted file mode 100644 index 9b1d284da..000000000 --- a/src/main/java/dan200/computercraft/shared/datafix/Fixes.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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.shared.datafix; - -import dan200.computercraft.ComputerCraft; -import net.minecraft.util.datafix.FixTypes; -import net.minecraftforge.common.util.CompoundDataFixer; -import net.minecraftforge.common.util.ModFixs; - -public final class Fixes -{ - public static final int VERSION = 1; - - private Fixes() {} - - public static void register( CompoundDataFixer fixer ) - { - ModFixs fixes = fixer.init( ComputerCraft.MOD_ID, VERSION ); - fixes.registerFix( FixTypes.BLOCK_ENTITY, new TileEntityDataFixer() ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/datafix/TileEntityDataFixer.java b/src/main/java/dan200/computercraft/shared/datafix/TileEntityDataFixer.java deleted file mode 100644 index 9e343f070..000000000 --- a/src/main/java/dan200/computercraft/shared/datafix/TileEntityDataFixer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.shared.datafix; - -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.datafix.IFixableData; - -import javax.annotation.Nonnull; - -import static dan200.computercraft.ComputerCraft.MOD_ID; -import static dan200.computercraft.shared.datafix.Fixes.VERSION; - -/** - * Fixes up the botched tile entity IDs from the 1.11 port. - */ -public class TileEntityDataFixer implements IFixableData -{ - @Override - public int getFixVersion() - { - return VERSION; - } - - @Nonnull - @Override - public NBTTagCompound fixTagCompound( @Nonnull NBTTagCompound tag ) - { - String id = tag.getString( "id" ); - if( id.startsWith( MOD_ID + " : " ) ) - { - tag.setString( "id", id.replaceFirst( MOD_ID + " : ", MOD_ID + ":" ) ); - } - return tag; - } -} diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java index 6ec7aaddf..2ce9eb8e6 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java @@ -13,63 +13,65 @@ import dan200.computercraft.shared.PocketUpgrades; import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.media.items.ItemDiskLegacy; +import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory; import dan200.computercraft.shared.turtle.items.ITurtleItem; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; -import mezz.jei.api.*; -import mezz.jei.api.ISubtypeRegistry.ISubtypeInterpreter; -import mezz.jei.api.ingredients.IIngredientRegistry; -import mezz.jei.api.ingredients.VanillaTypes; -import mezz.jei.api.recipe.IRecipeCategory; -import mezz.jei.api.recipe.IRecipeWrapper; -import mezz.jei.api.recipe.VanillaRecipeCategoryUid; -import mezz.jei.api.recipe.wrapper.ICraftingRecipeWrapper; +import mezz.jei.api.IModPlugin; +import mezz.jei.api.JeiPlugin; +import mezz.jei.api.constants.VanillaRecipeCategoryUid; +import mezz.jei.api.constants.VanillaTypes; +import mezz.jei.api.ingredients.subtypes.ISubtypeInterpreter; +import mezz.jei.api.recipe.IRecipeManager; +import mezz.jei.api.recipe.category.IRecipeCategory; +import mezz.jei.api.registration.IAdvancedRegistration; +import mezz.jei.api.registration.ISubtypeRegistration; +import mezz.jei.api.runtime.IJeiRuntime; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.oredict.OreDictionary; +import javax.annotation.Nonnull; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static dan200.computercraft.shared.integration.jei.RecipeResolver.MAIN_FAMILIES; -@JEIPlugin +@JeiPlugin public class JEIComputerCraft implements IModPlugin { - private IIngredientRegistry ingredients; - + @Nonnull @Override - public void registerItemSubtypes( ISubtypeRegistry subtypeRegistry ) + public ResourceLocation getPluginUid() { - subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.turtle, turtleSubtype ); - subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.turtleExpanded, turtleSubtype ); - subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.turtleAdvanced, turtleSubtype ); - - subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.pocketComputer, pocketSubtype ); - - subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.disk, diskSubtype ); - subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.diskExpanded, diskSubtype ); + return new ResourceLocation( ComputerCraft.MOD_ID, "jei" ); } @Override - public void register( IModRegistry registry ) + public void registerItemSubtypes( ISubtypeRegistration subtypeRegistry ) { - ingredients = registry.getIngredientRegistry(); + subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.turtleNormal, turtleSubtype ); + subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.turtleAdvanced, turtleSubtype ); - // Hide treasure disks from the ingredient list - registry.getJeiHelpers().getIngredientBlacklist() - .addIngredientToBlacklist( new ItemStack( ComputerCraft.Items.treasureDisk, OreDictionary.WILDCARD_VALUE ) ); + subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.pocketComputerNormal, pocketSubtype ); + subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.pocketComputerAdvanced, pocketSubtype ); - registry.addRecipeRegistryPlugin( new RecipeResolver() ); + subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.disk, diskSubtype ); + } + + @Override + public void registerAdvanced( IAdvancedRegistration registry ) + { + registry.addRecipeManagerPlugin( new RecipeResolver() ); } @Override public void onRuntimeAvailable( IJeiRuntime runtime ) { - IRecipeRegistry registry = runtime.getRecipeRegistry(); + IRecipeManager registry = runtime.getRecipeManager(); // Register all turtles/pocket computers (not just vanilla upgrades) as upgrades on JEI. List upgradeItems = new ArrayList<>(); @@ -87,17 +89,22 @@ public void onRuntimeAvailable( IJeiRuntime runtime ) upgradeItems.add( PocketComputerItemFactory.create( -1, null, -1, family, upgrade ) ); } } - ingredients.addIngredientsAtRuntime( VanillaTypes.ITEM, upgradeItems ); + + runtime.getIngredientManager().addIngredientsAtRuntime( VanillaTypes.ITEM, upgradeItems ); + + // Hide treasure disks + runtime.getIngredientManager().removeIngredientsAtRuntime( VanillaTypes.ITEM, + Collections.singletonList( new ItemStack( ComputerCraft.Items.treasureDisk ) ) ); // Hide all upgrade recipes - IRecipeCategory category = (IRecipeCategory) registry.getRecipeCategory( VanillaRecipeCategoryUid.CRAFTING ); + IRecipeCategory category = (IRecipeCategory) registry.getRecipeCategory( VanillaRecipeCategoryUid.CRAFTING ); if( category != null ) { - for( IRecipeWrapper wrapper : registry.getRecipeWrappers( category ) ) + for( Object wrapper : registry.getRecipes( category ) ) { - if( !(wrapper instanceof ICraftingRecipeWrapper) ) continue; - ResourceLocation id = ((ICraftingRecipeWrapper) wrapper).getRegistryName(); - if( id != null && id.getNamespace().equals( ComputerCraft.MOD_ID ) + if( !(wrapper instanceof IRecipe) ) continue; + ResourceLocation id = ((IRecipe) wrapper).getId(); + if( id.getNamespace().equals( ComputerCraft.MOD_ID ) && (id.getPath().startsWith( "generated/turtle_" ) || id.getPath().startsWith( "generated/pocket_" )) ) { registry.hideRecipe( wrapper, VanillaRecipeCategoryUid.CRAFTING ); @@ -116,16 +123,12 @@ public void onRuntimeAvailable( IJeiRuntime runtime ) ITurtleItem turtle = (ITurtleItem) item; StringBuilder name = new StringBuilder(); - name.append( turtle.getFamily( stack ) ); - // Add left and right upgrades to the identifier ITurtleUpgrade left = turtle.getUpgrade( stack, TurtleSide.Left ); - name.append( '|' ); - if( left != null ) name.append( left.getUpgradeID() ); - ITurtleUpgrade right = turtle.getUpgrade( stack, TurtleSide.Right ); - name.append( '|' ); - if( right != null ) name.append( '|' ).append( right.getUpgradeID() ); + if( left != null ) name.append( left.getUpgradeID() ); + if( left != null && right != null ) name.append( '|' ); + if( right != null ) name.append( right.getUpgradeID() ); return name.toString(); }; @@ -137,14 +140,10 @@ public void onRuntimeAvailable( IJeiRuntime runtime ) Item item = stack.getItem(); if( !(item instanceof ItemPocketComputer) ) return ""; - ItemPocketComputer pocket = (ItemPocketComputer) item; StringBuilder name = new StringBuilder(); - name.append( pocket.getFamily( stack ) ); - // Add the upgrade to the identifier - IPocketUpgrade upgrade = pocket.getUpgrade( stack ); - name.append( '|' ); + IPocketUpgrade upgrade = ItemPocketComputer.getUpgrade( stack ); if( upgrade != null ) name.append( upgrade.getUpgradeID() ); return name.toString(); @@ -155,9 +154,9 @@ public void onRuntimeAvailable( IJeiRuntime runtime ) */ private static final ISubtypeInterpreter diskSubtype = stack -> { Item item = stack.getItem(); - if( !(item instanceof ItemDiskLegacy) ) return ""; + if( !(item instanceof ItemDisk) ) return ""; - ItemDiskLegacy disk = (ItemDiskLegacy) item; + ItemDisk disk = (ItemDisk) item; int colour = disk.getColour( stack ); return colour == -1 ? "" : String.format( "%06x", colour ); diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java index 59ecf9c64..e30417122 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java @@ -6,6 +6,7 @@ package dan200.computercraft.shared.integration.jei; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; @@ -17,19 +18,25 @@ import dan200.computercraft.shared.turtle.items.ITurtleItem; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; import dan200.computercraft.shared.util.InventoryUtil; -import mezz.jei.api.ingredients.IIngredients; -import mezz.jei.api.ingredients.VanillaTypes; -import mezz.jei.api.recipe.*; -import mezz.jei.api.recipe.wrapper.IShapedCraftingRecipeWrapper; +import mezz.jei.api.constants.VanillaRecipeCategoryUid; +import mezz.jei.api.recipe.IFocus; +import mezz.jei.api.recipe.advanced.IRecipeManagerPlugin; +import mezz.jei.api.recipe.category.IRecipeCategory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.item.crafting.ShapedRecipe; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; import javax.annotation.Nonnull; import java.util.*; -import static java.util.Arrays.asList; +import static net.minecraft.item.crafting.Ingredient.fromStacks; +import static net.minecraft.util.NonNullList.from; -class RecipeResolver implements IRecipeRegistryPlugin +class RecipeResolver implements IRecipeManagerPlugin { static final ComputerFamily[] MAIN_FAMILIES = new ComputerFamily[] { ComputerFamily.Normal, ComputerFamily.Advanced }; @@ -86,7 +93,7 @@ private boolean hasUpgrade( @Nonnull ItemStack stack ) @Nonnull @Override - public List getRecipeCategoryUids( @Nonnull IFocus focus ) + public List getRecipeCategoryUids( @Nonnull IFocus focus ) { V value = focus.getValue(); if( !(value instanceof ItemStack) ) return Collections.emptyList(); @@ -110,7 +117,7 @@ public List getRecipeCategoryUids( @Nonnull IFocus focus ) @Nonnull @Override - public List getRecipeWrappers( @Nonnull IRecipeCategory recipeCategory, @Nonnull IFocus focus ) + public List getRecipes( @Nonnull IRecipeCategory recipeCategory, @Nonnull IFocus focus ) { if( !(focus.getValue() instanceof ItemStack) || !recipeCategory.getUid().equals( VanillaRecipeCategoryUid.CRAFTING ) ) { @@ -131,7 +138,7 @@ public List getRecipeWrappers( @Nonnull IRecipe @Nonnull @Override - public List getRecipeWrappers( @Nonnull IRecipeCategory recipeCategory ) + public List getRecipes( @Nonnull IRecipeCategory recipeCategory ) { return Collections.emptyList(); } @@ -150,17 +157,18 @@ private List findRecipesWithInput( @Nonnull ItemStack stack ) if( left != null && right != null ) return Collections.emptyList(); List recipes = new ArrayList<>(); + Ingredient ingredient = fromStacks( stack ); for( UpgradeInfo upgrade : turtleUpgrades ) { // The turtle is facing towards us, so upgrades on the left are actually crafted on the right. if( left == null ) { - recipes.add( horizontal( asList( stack, upgrade.stack ), turtleWith( stack, upgrade.turtle, right ) ) ); + recipes.add( horizontal( from( Ingredient.EMPTY, ingredient, upgrade.ingredient ), turtleWith( stack, upgrade.turtle, right ) ) ); } if( right == null ) { - recipes.add( horizontal( asList( upgrade.stack, stack ), turtleWith( stack, left, upgrade.turtle ) ) ); + recipes.add( horizontal( from( Ingredient.EMPTY, upgrade.ingredient, ingredient ), turtleWith( stack, left, upgrade.turtle ) ) ); } } @@ -169,14 +177,14 @@ private List findRecipesWithInput( @Nonnull ItemStack stack ) else if( stack.getItem() instanceof ItemPocketComputer ) { // Suggest possible upgrades which can be applied to this turtle - ItemPocketComputer item = (ItemPocketComputer) stack.getItem(); - IPocketUpgrade back = item.getUpgrade( stack ); + IPocketUpgrade back = ItemPocketComputer.getUpgrade( stack ); if( back != null ) return Collections.emptyList(); List recipes = new ArrayList<>(); + Ingredient ingredient = fromStacks( stack ); for( UpgradeInfo upgrade : pocketUpgrades ) { - recipes.add( vertical( asList( stack, upgrade.stack ), pocketWith( stack, upgrade.pocket ) ) ); + recipes.add( vertical( from( Ingredient.EMPTY, ingredient, upgrade.ingredient ), pocketWith( stack, upgrade.pocket ) ) ); } return recipes; @@ -188,6 +196,7 @@ else if( stack.getItem() instanceof ItemPocketComputer ) List recipes = null; boolean multiple = false; + Ingredient ingredient = fromStacks( stack ); for( UpgradeInfo upgrade : upgrades ) { ItemStack craftingStack = upgrade.stack; @@ -222,7 +231,7 @@ private static List findRecipesWithOutput( @Nonnull ItemStack stack ) if( stack.getItem() instanceof ITurtleItem ) { ITurtleItem item = (ITurtleItem) stack.getItem(); - List recipes = new ArrayList<>( 0 ); + List recipes = new ArrayList<>( 0 ); ITurtleUpgrade left = item.getUpgrade( stack, TurtleSide.Left ); ITurtleUpgrade right = item.getUpgrade( stack, TurtleSide.Right ); @@ -230,25 +239,33 @@ private static List findRecipesWithOutput( @Nonnull ItemStack stack ) // The turtle is facing towards us, so upgrades on the left are actually crafted on the right. if( left != null ) { - recipes.add( horizontal( asList( turtleWith( stack, null, right ), left.getCraftingItem() ), stack ) ); + recipes.add( horizontal( + from( Ingredient.EMPTY, fromStacks( turtleWith( stack, null, right ) ), fromStacks( left.getCraftingItem() ) ), + stack + ) ); } if( right != null ) { - recipes.add( horizontal( asList( right.getCraftingItem(), turtleWith( stack, left, null ) ), stack ) ); + recipes.add( horizontal( + from( Ingredient.EMPTY, fromStacks( right.getCraftingItem() ), fromStacks( turtleWith( stack, left, null ) ) ), + stack + ) ); } return cast( recipes ); } else if( stack.getItem() instanceof ItemPocketComputer ) { - ItemPocketComputer item = (ItemPocketComputer) stack.getItem(); - List recipes = new ArrayList<>( 0 ); + List recipes = new ArrayList<>( 0 ); - IPocketUpgrade back = item.getUpgrade( stack ); + IPocketUpgrade back = ItemPocketComputer.getUpgrade( stack ); if( back != null ) { - recipes.add( vertical( asList( back.getCraftingItem(), pocketWith( stack, null ) ), stack ) ); + recipes.add( vertical( + from( Ingredient.EMPTY, fromStacks( back.getCraftingItem() ), fromStacks( pocketWith( stack, null ) ) ), + stack + ) ); } return cast( recipes ); @@ -260,7 +277,7 @@ else if( stack.getItem() instanceof ItemPocketComputer ) } @SuppressWarnings( { "unchecked", "rawtypes" } ) - private static List cast( List from ) + private static List cast( List from ) { return (List) from; } @@ -269,7 +286,7 @@ private static ItemStack turtleWith( ItemStack stack, ITurtleUpgrade left, ITurt { ITurtleItem item = (ITurtleItem) stack.getItem(); return TurtleItemFactory.create( - item.getComputerID( stack ), item.getLabel( stack ), item.getColour( stack ), item.getFamily( stack ), + item.getComputerID( stack ), item.getLabel( stack ), item.getColour( stack ), item.getFamily(), left, right, item.getFuelLevel( stack ), item.getOverlay( stack ) ); } @@ -278,59 +295,63 @@ private static ItemStack pocketWith( ItemStack stack, IPocketUpgrade back ) { ItemPocketComputer item = (ItemPocketComputer) stack.getItem(); return PocketComputerItemFactory.create( - item.getComputerID( stack ), item.getLabel( stack ), item.getColour( stack ), item.getFamily( stack ), + item.getComputerID( stack ), item.getLabel( stack ), item.getColour( stack ), item.getFamily(), back ); } - private static Shaped vertical( List input, ItemStack result ) + private static Shaped vertical( NonNullList input, ItemStack result ) { return new Shaped( 1, input.size(), input, result ); } - private static Shaped horizontal( List input, ItemStack result ) + private static Shaped horizontal( NonNullList input, ItemStack result ) { return new Shaped( input.size(), 1, input, result ); } - private static class Shaped implements IShapedCraftingRecipeWrapper + private static class Shaped extends ShapedRecipe { - private final int width; - private final int height; - private final List input; - private final ItemStack output; + private static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "impostor" ); - Shaped( int width, int height, List input, ItemStack output ) + Shaped( int width, int height, NonNullList input, ItemStack output ) { - this.width = width; - this.height = height; - this.input = input; - this.output = output; + super( ID, null, width, height, input, output ); } + @Nonnull @Override - public int getWidth() + public ResourceLocation getId() { - return width; + return null; } + @Nonnull @Override - public int getHeight() + public IRecipeSerializer getSerializer() { - return height; + throw new IllegalStateException( "Should not serialise the JEI recipe" ); } + } - @Override - public void getIngredients( @Nonnull IIngredients ingredients ) + private static final class Upgrade + { + final T upgrade; + final ItemStack stack; + final Ingredient ingredient; + + private Upgrade( T upgrade, ItemStack stack ) { - ingredients.setInputs( VanillaTypes.ITEM, input ); - ingredients.setOutput( VanillaTypes.ITEM, output ); + this.upgrade = upgrade; + this.stack = stack; + ingredient = fromStacks( stack ); } } private static class UpgradeInfo { final ItemStack stack; + final Ingredient ingredient; final ITurtleUpgrade turtle; final IPocketUpgrade pocket; ArrayList recipes; @@ -338,6 +359,7 @@ private static class UpgradeInfo UpgradeInfo( ItemStack stack, ITurtleUpgrade turtle ) { this.stack = stack; + ingredient = fromStacks( stack ); this.turtle = turtle; pocket = null; } @@ -345,6 +367,7 @@ private static class UpgradeInfo UpgradeInfo( ItemStack stack, IPocketUpgrade pocket ) { this.stack = stack; + ingredient = fromStacks( stack ); turtle = null; this.pocket = pocket; } @@ -360,7 +383,7 @@ List getRecipes() if( turtle != null && TurtleUpgrades.suitableForFamily( family, turtle ) ) { recipes.add( horizontal( - asList( stack, TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null ) ), + from( Ingredient.EMPTY, ingredient, fromStacks( TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null ) ) ), TurtleItemFactory.create( -1, null, -1, family, null, turtle, 0, null ) ) ); } @@ -368,7 +391,7 @@ List getRecipes() if( pocket != null ) { recipes.add( vertical( - asList( stack, PocketComputerItemFactory.create( -1, null, -1, family, null ) ), + from( Ingredient.EMPTY, ingredient, fromStacks( PocketComputerItemFactory.create( -1, null, -1, family, null ) ) ), PocketComputerItemFactory.create( -1, null, -1, family, pocket ) ) ); } diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java new file mode 100644 index 000000000..93ff17333 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java @@ -0,0 +1,132 @@ +/* + * 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.shared.media.items; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.filesystem.IMount; +import dan200.computercraft.api.media.IMedia; +import dan200.computercraft.shared.common.IColouredItem; +import dan200.computercraft.shared.util.Colour; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.NonNullList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.world.IWorldReader; +import net.minecraft.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; + +public class ItemDisk extends Item implements IMedia, IColouredItem +{ + private static final String NBT_ID = "DiskId"; + + public ItemDisk( Properties settings ) + { + super( settings ); + } + + @Nonnull + public static ItemStack createFromIDAndColour( int id, String label, int colour ) + { + ItemStack stack = new ItemStack( ComputerCraft.Items.disk ); + setDiskID( stack, id ); + ComputerCraft.Items.disk.setLabel( stack, label ); + IColouredItem.setColourBasic( stack, colour ); + return stack; + } + + @Override + public void fillItemGroup( @Nonnull ItemGroup tabs, @Nonnull NonNullList list ) + { + if( !isInGroup( tabs ) ) return; + for( int colour = 0; colour < 16; colour++ ) + { + list.add( createFromIDAndColour( -1, null, Colour.VALUES[colour].getHex() ) ); + } + } + + @Override + public void addInformation( ItemStack stack, @Nullable World world, List list, ITooltipFlag options ) + { + if( options.isAdvanced() ) + { + int id = getDiskID( stack ); + if( id >= 0 ) + { + list.add( new TextComponentTranslation( "gui.computercraft.tooltip.disk_id", id ) + .applyTextStyle( TextFormatting.GRAY ) ); + } + } + } + + @Override + public boolean doesSneakBypassUse( ItemStack stack, IWorldReader world, BlockPos pos, EntityPlayer player ) + { + return true; + } + + @Override + public String getLabel( @Nonnull ItemStack stack ) + { + return stack.hasDisplayName() ? stack.getDisplayName().getString() : null; + } + + @Override + public boolean setLabel( @Nonnull ItemStack stack, String label ) + { + if( label != null ) + { + stack.setDisplayName( new TextComponentString( label ) ); + } + else + { + stack.clearCustomName(); + } + return true; + } + + @Override + public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world ) + { + int diskID = getDiskID( stack ); + if( diskID < 0 ) + { + diskID = ComputerCraftAPI.createUniqueNumberedSaveDir( world, "disk" ); + setDiskID( stack, diskID ); + } + return ComputerCraftAPI.createSaveDirMount( world, "disk/" + diskID, ComputerCraft.floppySpaceLimit ); + } + + public static int getDiskID( @Nonnull ItemStack stack ) + { + NBTTagCompound nbt = stack.getTag(); + return nbt != null && nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; + } + + private static void setDiskID( @Nonnull ItemStack stack, int id ) + { + if( id >= 0 ) stack.getOrCreateTag().putInt( NBT_ID, id ); + } + + @Override + public int getColour( @Nonnull ItemStack stack ) + { + int colour = IColouredItem.getColourBasic( stack ); + return colour == -1 ? Colour.White.getHex() : colour; + } +} diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDiskExpanded.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDiskExpanded.java deleted file mode 100644 index fbca52659..000000000 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemDiskExpanded.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.shared.media.items; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.util.Colour; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; - -import javax.annotation.Nonnull; - -public class ItemDiskExpanded extends ItemDiskLegacy -{ - @Nonnull - public static ItemStack createFromIDAndColour( int id, String label, int colour ) - { - ItemStack stack = new ItemStack( ComputerCraft.Items.diskExpanded, 1, 0 ); - - NBTTagCompound nbt = stack.getTagCompound(); - if( nbt == null ) - { - nbt = new NBTTagCompound(); - stack.setTagCompound( nbt ); - } - nbt.setInteger( "color", colour ); - ComputerCraft.Items.diskExpanded.setDiskID( stack, id ); - ComputerCraft.Items.diskExpanded.setLabel( stack, label ); - return stack; - } - - @Override - public int getDiskID( @Nonnull ItemStack stack ) - { - NBTTagCompound nbt = stack.getTagCompound(); - if( nbt != null && nbt.hasKey( "diskID" ) ) - { - return nbt.getInteger( "diskID" ); - } - return -1; - } - - @Override - protected void setDiskID( @Nonnull ItemStack stack, int id ) - { - if( id >= 0 ) - { - NBTTagCompound nbt = stack.getTagCompound(); - if( nbt == null ) - { - nbt = new NBTTagCompound(); - stack.setTagCompound( nbt ); - } - nbt.setInteger( "diskID", id ); - } - } - - @Override - public int getColour( @Nonnull ItemStack stack ) - { - NBTTagCompound nbt = stack.getTagCompound(); - if( nbt != null && nbt.hasKey( "color" ) ) - { - return nbt.getInteger( "color" ); - } - else - { - return Colour.values()[Math.min( 15, stack.getItemDamage() )].getHex(); - } - } -} diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDiskLegacy.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDiskLegacy.java deleted file mode 100644 index 97b8d1355..000000000 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemDiskLegacy.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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.shared.media.items; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.ComputerCraftAPI; -import dan200.computercraft.api.filesystem.IMount; -import dan200.computercraft.api.media.IMedia; -import dan200.computercraft.shared.common.IColouredItem; -import dan200.computercraft.shared.util.Colour; -import dan200.computercraft.shared.util.StringUtil; -import net.minecraft.client.util.ITooltipFlag; -import net.minecraft.creativetab.CreativeTabs; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.NonNullList; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockAccess; -import net.minecraft.world.World; - -import javax.annotation.Nonnull; -import java.util.List; - -public class ItemDiskLegacy extends Item implements IMedia, IColouredItem -{ - public ItemDiskLegacy() - { - setMaxStackSize( 1 ); - setHasSubtypes( true ); - setTranslationKey( "computercraft:disk" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - } - - @Override - public void getSubItems( @Nonnull CreativeTabs tabs, @Nonnull NonNullList list ) - { - if( !isInCreativeTab( tabs ) ) return; - for( int colour = 0; colour < 16; colour++ ) - { - ItemStack stack = createFromIDAndColour( -1, null, Colour.values()[colour].getHex() ); - if( stack.getItem() == this ) - { - list.add( stack ); - } - } - } - - @Nonnull - public static ItemStack createFromIDAndColour( int id, String label, int colour ) - { - return ItemDiskExpanded.createFromIDAndColour( id, label, colour ); - } - - public int getDiskID( @Nonnull ItemStack stack ) - { - int damage = stack.getItemDamage(); - if( damage > 0 ) - { - return damage; - } - return -1; - } - - protected void setDiskID( @Nonnull ItemStack stack, int id ) - { - if( id > 0 ) - { - stack.setItemDamage( id ); - } - else - { - stack.setItemDamage( 0 ); - } - } - - @Override - public void addInformation( @Nonnull ItemStack stack, World world, List list, ITooltipFlag flag ) - { - if( flag.isAdvanced() ) - { - int id = getDiskID( stack ); - if( id >= 0 ) list.add( StringUtil.translateFormatted( "gui.computercraft.tooltip.disk_id", id ) ); - } - } - - // IMedia implementation - - @Override - public String getLabel( @Nonnull ItemStack stack ) - { - if( stack.hasDisplayName() ) - { - return stack.getDisplayName(); - } - return null; - } - - @Override - public boolean setLabel( @Nonnull ItemStack stack, String label ) - { - if( label != null ) - { - stack.setStackDisplayName( label ); - } - else - { - stack.clearCustomName(); - } - return true; - } - - @Override - public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world ) - { - int diskID = getDiskID( stack ); - if( diskID < 0 ) - { - diskID = ComputerCraftAPI.createUniqueNumberedSaveDir( world, "computer/disk" ); - setDiskID( stack, diskID ); - } - return ComputerCraftAPI.createSaveDirMount( world, "computer/disk/" + diskID, ComputerCraft.floppySpaceLimit ); - } - - @Override - public int getColour( @Nonnull ItemStack stack ) - { - return Colour.Blue.getHex(); - } - - @Override - public boolean doesSneakBypassUse( @Nonnull ItemStack stack, IBlockAccess world, BlockPos pos, EntityPlayer player ) - { - return true; - } - - @Override - public ItemStack withColour( ItemStack stack, int colour ) - { - return ItemDiskExpanded.createFromIDAndColour( getDiskID( stack ), getLabel( stack ), colour ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java index 6f9629d82..5c12e84d2 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java @@ -9,7 +9,6 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.network.Containers; import net.minecraft.client.util.ITooltipFlag; -import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -17,7 +16,8 @@ import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumHand; -import net.minecraft.util.NonNullList; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentString; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -25,10 +25,10 @@ public class ItemPrintout extends Item { - private static final String NBT_TITLE = "title"; - private static final String NBT_PAGES = "pages"; - private static final String NBT_LINE_TEXT = "line"; - private static final String NBT_LINE_COLOUR = "colour"; + private static final String NBT_TITLE = "Title"; + private static final String NBT_PAGES = "Pages"; + private static final String NBT_LINE_TEXT = "Text"; + private static final String NBT_LINE_COLOUR = "Color"; public static final int LINES_PER_PAGE = 21; public static final int LINE_MAX_LENGTH = 25; @@ -36,50 +36,24 @@ public class ItemPrintout extends Item public enum Type { - Single, - Multiple, - Book + PAGE, + PAGES, + BOOK } - public ItemPrintout() + private final Type type; + + public ItemPrintout( Properties settings, Type type ) { - setMaxStackSize( 1 ); - setHasSubtypes( true ); - setTranslationKey( "computercraft:page" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); + super( settings ); + this.type = type; } @Override - public void getSubItems( @Nonnull CreativeTabs tabs, @Nonnull NonNullList list ) + public void addInformation( @Nonnull ItemStack stack, World world, List list, ITooltipFlag options ) { - if( !isInCreativeTab( tabs ) ) return; - list.add( createSingleFromTitleAndText( null, new String[LINES_PER_PAGE], new String[LINES_PER_PAGE] ) ); - list.add( createMultipleFromTitleAndText( null, new String[2 * LINES_PER_PAGE], new String[2 * LINES_PER_PAGE] ) ); - list.add( createBookFromTitleAndText( null, new String[2 * LINES_PER_PAGE], new String[2 * LINES_PER_PAGE] ) ); - } - - @Override - public void addInformation( @Nonnull ItemStack itemstack, World world, List list, ITooltipFlag flag ) - { - String title = getTitle( itemstack ); - if( title != null && !title.isEmpty() ) list.add( title ); - } - - @Nonnull - @Override - public String getTranslationKey( @Nonnull ItemStack stack ) - { - Type type = getType( stack ); - switch( type ) - { - case Single: - default: - return "item.computercraft:page"; - case Multiple: - return "item.computercraft:pages"; - case Book: - return "item.computercraft:book"; - } + String title = getTitle( stack ); + if( title != null && !title.isEmpty() ) list.add( new TextComponentString( title ) ); } @Nonnull @@ -91,94 +65,67 @@ public ActionResult onItemRightClick( World world, EntityPlayer playe } @Nonnull - private static ItemStack createFromTitleAndText( Type type, String title, String[] text, String[] colours ) + private ItemStack createFromTitleAndText( String title, String[] text, String[] colours ) { - // Calculate damage - int damage; - switch( type ) - { - case Single: - default: - damage = 0; - break; - case Multiple: - damage = 1; - break; - case Book: - damage = 2; - break; - } - - // Create stack - ItemStack stack = new ItemStack( ComputerCraft.Items.printout, 1, damage ); + ItemStack stack = new ItemStack( this ); // Build NBT - NBTTagCompound nbt = new NBTTagCompound(); - if( title != null ) nbt.setString( NBT_TITLE, title ); + if( title != null ) stack.getOrCreateTag().putString( NBT_TITLE, title ); if( text != null ) { - nbt.setInteger( NBT_PAGES, text.length / LINES_PER_PAGE ); + NBTTagCompound tag = stack.getOrCreateTag(); + tag.putInt( NBT_PAGES, text.length / LINES_PER_PAGE ); for( int i = 0; i < text.length; i++ ) { - if( text[i] != null ) nbt.setString( NBT_LINE_TEXT + i, text[i] ); + if( text[i] != null ) tag.putString( NBT_LINE_TEXT + i, text[i] ); } } if( colours != null ) { + NBTTagCompound tag = stack.getOrCreateTag(); for( int i = 0; i < colours.length; i++ ) { - if( colours[i] != null ) nbt.setString( NBT_LINE_COLOUR + i, colours[i] ); + if( colours[i] != null ) tag.putString( NBT_LINE_COLOUR + i, colours[i] ); } } - stack.setTagCompound( nbt ); - // Return stack + return stack; } @Nonnull public static ItemStack createSingleFromTitleAndText( String title, String[] text, String[] colours ) { - return createFromTitleAndText( Type.Single, title, text, colours ); + return ComputerCraft.Items.printedPage.createFromTitleAndText( title, text, colours ); } @Nonnull public static ItemStack createMultipleFromTitleAndText( String title, String[] text, String[] colours ) { - return createFromTitleAndText( Type.Multiple, title, text, colours ); + return ComputerCraft.Items.printedPages.createFromTitleAndText( title, text, colours ); } @Nonnull public static ItemStack createBookFromTitleAndText( String title, String[] text, String[] colours ) { - return createFromTitleAndText( Type.Book, title, text, colours ); + return ComputerCraft.Items.printedBook.createFromTitleAndText( title, text, colours ); } - public static Type getType( @Nonnull ItemStack stack ) + public Type getType() { - int damage = stack.getItemDamage(); - switch( damage ) - { - case 0: - default: - return Type.Single; - case 1: - return Type.Multiple; - case 2: - return Type.Book; - } + return type; } public static String getTitle( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTagCompound(); - return nbt != null && nbt.hasKey( NBT_TITLE ) ? nbt.getString( NBT_TITLE ) : null; + NBTTagCompound nbt = stack.getTag(); + return nbt != null && nbt.contains( NBT_TITLE ) ? nbt.getString( NBT_TITLE ) : null; } public static int getPageCount( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTagCompound(); - return nbt != null && nbt.hasKey( NBT_PAGES ) ? nbt.getInteger( NBT_PAGES ) : 1; + NBTTagCompound nbt = stack.getTag(); + return nbt != null && nbt.contains( NBT_PAGES ) ? nbt.getInt( NBT_PAGES ) : 1; } public static String[] getText( @Nonnull ItemStack stack ) @@ -193,7 +140,7 @@ public static String[] getColours( @Nonnull ItemStack stack ) private static String[] getLines( @Nonnull ItemStack stack, String prefix ) { - NBTTagCompound nbt = stack.getTagCompound(); + NBTTagCompound nbt = stack.getTag(); int numLines = getPageCount( stack ) * LINES_PER_PAGE; String[] lines = new String[numLines]; for( int i = 0; i < lines.length; i++ ) diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java index d475ec54e..106d8968e 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java @@ -13,43 +13,48 @@ import dan200.computercraft.core.filesystem.SubMount; import dan200.computercraft.shared.util.Colour; import net.minecraft.client.util.ITooltipFlag; -import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; +import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockAccess; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.world.IWorldReader; import net.minecraft.world.World; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.IOException; import java.util.List; public class ItemTreasureDisk extends Item implements IMedia { - public ItemTreasureDisk() + private static final String NBT_TITLE = "Title"; + private static final String NBT_COLOUR = "Colour"; + private static final String NBT_SUB_PATH = "SubPath"; + + public ItemTreasureDisk( Properties settings ) { - setMaxStackSize( 1 ); - setHasSubtypes( true ); - setTranslationKey( "computercraft:treasure_disk" ); + super( settings ); } @Override - public void getSubItems( @Nonnull CreativeTabs tabs, @Nonnull NonNullList list ) + public void fillItemGroup( @Nonnull ItemGroup group, @Nonnull NonNullList stacks ) { } @Override - public void addInformation( @Nonnull ItemStack stack, World world, List list, ITooltipFlag flag ) + public void addInformation( ItemStack stack, @Nullable World world, List list, ITooltipFlag tooltipOptions ) { String label = getTitle( stack ); - if( !label.isEmpty() ) list.add( label ); + if( !label.isEmpty() ) list.add( new TextComponentString( label ) ); } @Override - public boolean doesSneakBypassUse( @Nonnull ItemStack stack, IBlockAccess world, BlockPos pos, EntityPlayer player ) + public boolean doesSneakBypassUse( @Nonnull ItemStack stack, IWorldReader world, BlockPos pos, EntityPlayer player ) { return true; } @@ -88,51 +93,48 @@ else if( rootTreasure.exists( "deprecated/" + subPath ) ) public static ItemStack create( String subPath, int colourIndex ) { - NBTTagCompound nbt = new NBTTagCompound(); - nbt.setString( "subPath", subPath ); + ItemStack result = new ItemStack( ComputerCraft.Items.treasureDisk ); + NBTTagCompound nbt = result.getOrCreateTag(); + nbt.putString( NBT_SUB_PATH, subPath ); int slash = subPath.indexOf( '/' ); if( slash >= 0 ) { String author = subPath.substring( 0, slash ); String title = subPath.substring( slash + 1 ); - nbt.setString( "title", "\"" + title + "\" by " + author ); + nbt.putString( NBT_TITLE, "\"" + title + "\" by " + author ); } else { - nbt.setString( "title", "untitled" ); + nbt.putString( NBT_TITLE, "untitled" ); } - nbt.setInteger( "colour", Colour.values()[colourIndex].getHex() ); + nbt.putInt( NBT_COLOUR, Colour.values()[colourIndex].getHex() ); - ItemStack result = new ItemStack( ComputerCraft.Items.treasureDisk, 1, 0 ); - result.setTagCompound( nbt ); return result; } private static IMount getTreasureMount() { - return ComputerCraftAPI.createResourceMount( ComputerCraft.class, "computercraft", "lua/treasure" ); + return ComputerCraftAPI.createResourceMount( "computercraft", "lua/treasure" ); } - // private stuff - @Nonnull private static String getTitle( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTagCompound(); - return nbt != null && nbt.hasKey( "title" ) ? nbt.getString( "title" ) : "'alongtimeago' by dan200"; + NBTTagCompound nbt = stack.getTag(); + return nbt != null && nbt.contains( NBT_TITLE ) ? nbt.getString( NBT_TITLE ) : "'alongtimeago' by dan200"; } @Nonnull private static String getSubPath( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTagCompound(); - return nbt != null && nbt.hasKey( "subPath" ) ? nbt.getString( "subPath" ) : "dan200/alongtimeago"; + NBTTagCompound nbt = stack.getTag(); + return nbt != null && nbt.contains( NBT_SUB_PATH ) ? nbt.getString( NBT_SUB_PATH ) : "dan200/alongtimeago"; } public static int getColour( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTagCompound(); - return nbt != null && nbt.hasKey( "colour" ) ? nbt.getInteger( "colour" ) : Colour.Blue.getHex(); + NBTTagCompound nbt = stack.getTag(); + return nbt != null && nbt.contains( NBT_COLOUR ) ? nbt.getInt( NBT_COLOUR ) : Colour.Blue.getHex(); } } diff --git a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java index 73fcc6e0d..c6341bc61 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java +++ b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java @@ -40,7 +40,6 @@ public String getAudioTitle( @Nonnull ItemStack stack ) @Override public SoundEvent getAudio( @Nonnull ItemStack stack ) { - ItemRecord itemRecord = (ItemRecord) stack.getItem(); - return itemRecord.sound; + return ((ItemRecord) stack.getItem()).getSound(); } } diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java index c7775080e..f28bb8f2f 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java @@ -6,30 +6,37 @@ package dan200.computercraft.shared.media.recipes; -import com.google.gson.JsonObject; -import dan200.computercraft.shared.media.items.ItemDiskLegacy; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.media.items.ItemDisk; +import dan200.computercraft.shared.util.AbstractRecipe; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.ColourTracker; import dan200.computercraft.shared.util.ColourUtils; -import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.init.Items; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.EnumDyeColor; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; +import net.minecraft.item.crafting.RecipeSerializers; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; -import net.minecraftforge.common.crafting.IRecipeFactory; -import net.minecraftforge.common.crafting.JsonContext; -import net.minecraftforge.oredict.OreIngredient; -import net.minecraftforge.registries.IForgeRegistryEntry; +import net.minecraftforge.common.Tags; import javax.annotation.Nonnull; -public class DiskRecipe extends IForgeRegistryEntry.Impl implements IRecipe +public class DiskRecipe extends AbstractRecipe { - private final Ingredient paper = new OreIngredient( "paper" ); - private final Ingredient redstone = new OreIngredient( "dustRedstone" ); + private final Ingredient paper = Ingredient.fromItems( Items.PAPER ); + private final Ingredient redstone = Ingredient.fromTag( Tags.Items.DUSTS_REDSTONE ); + + public DiskRecipe( ResourceLocation id ) + { + super( id ); + } @Override - public boolean matches( @Nonnull InventoryCrafting inv, @Nonnull World world ) + public boolean matches( @Nonnull IInventory inv, @Nonnull World world ) { boolean paperFound = false; boolean redstoneFound = false; @@ -40,17 +47,17 @@ public boolean matches( @Nonnull InventoryCrafting inv, @Nonnull World world ) if( !stack.isEmpty() ) { - if( paper.apply( stack ) ) + if( paper.test( stack ) ) { if( paperFound ) return false; paperFound = true; } - else if( redstone.apply( stack ) ) + else if( redstone.test( stack ) ) { if( redstoneFound ) return false; redstoneFound = true; } - else if( ColourUtils.getStackColour( stack ) < 0 ) + else if( ColourUtils.getStackColour( stack ) != null ) { return false; } @@ -62,7 +69,7 @@ else if( ColourUtils.getStackColour( stack ) < 0 ) @Nonnull @Override - public ItemStack getCraftingResult( @Nonnull InventoryCrafting inv ) + public ItemStack getCraftingResult( @Nonnull IInventory inv ) { ColourTracker tracker = new ColourTracker(); @@ -72,17 +79,17 @@ public ItemStack getCraftingResult( @Nonnull InventoryCrafting inv ) if( stack.isEmpty() ) continue; - if( !paper.apply( stack ) && !redstone.apply( stack ) ) + if( !paper.test( stack ) && !redstone.test( stack ) ) { - int index = ColourUtils.getStackColour( stack ); - if( index < 0 ) continue; + EnumDyeColor dye = ColourUtils.getStackColour( stack ); + if( dye == null ) continue; - Colour colour = Colour.values()[index]; + Colour colour = Colour.VALUES[dye.getId()]; tracker.addColour( colour.getR(), colour.getG(), colour.getB() ); } } - return ItemDiskLegacy.createFromIDAndColour( -1, null, tracker.hasColour() ? tracker.getColour() : Colour.Blue.getHex() ); + return ItemDisk.createFromIDAndColour( -1, null, tracker.hasColour() ? tracker.getColour() : Colour.Blue.getHex() ); } @Override @@ -91,25 +98,21 @@ public boolean canFit( int x, int y ) return x >= 2 && y >= 2; } - @Override - public boolean isDynamic() - { - return true; - } - @Nonnull @Override public ItemStack getRecipeOutput() { - return ItemDiskLegacy.createFromIDAndColour( -1, null, Colour.Blue.getHex() ); + return ItemDisk.createFromIDAndColour( -1, null, Colour.Blue.getHex() ); } - public static class Factory implements IRecipeFactory + @Nonnull + @Override + public IRecipeSerializer getSerializer() { - @Override - public IRecipe parse( JsonContext jsonContext, JsonObject jsonObject ) - { - return new DiskRecipe(); - } + return SERIALIZER; } + + public static final IRecipeSerializer SERIALIZER = new RecipeSerializers.SimpleSerializer<>( + ComputerCraft.MOD_ID + ":disk", DiskRecipe::new + ); } diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java index c0cdfb587..12c7c3a16 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java @@ -6,25 +6,30 @@ package dan200.computercraft.shared.media.recipes; -import com.google.gson.JsonObject; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.media.items.ItemPrintout; -import net.minecraft.inventory.InventoryCrafting; +import dan200.computercraft.shared.util.AbstractRecipe; +import net.minecraft.init.Items; +import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; +import net.minecraft.item.crafting.RecipeSerializers; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; -import net.minecraftforge.common.crafting.IRecipeFactory; -import net.minecraftforge.common.crafting.JsonContext; -import net.minecraftforge.oredict.OreIngredient; -import net.minecraftforge.registries.IForgeRegistryEntry; import javax.annotation.Nonnull; -public class PrintoutRecipe extends IForgeRegistryEntry.Impl implements IRecipe +public final class PrintoutRecipe extends AbstractRecipe { - private final Ingredient paper = new OreIngredient( "paper" ); - private final Ingredient leather = new OreIngredient( "leather" ); - private final Ingredient string = new OreIngredient( "string" ); + private final Ingredient paper = Ingredient.fromItems( Items.PAPER ); + private final Ingredient leather = Ingredient.fromItems( Items.LEATHER ); + private final Ingredient string = Ingredient.fromItems( Items.STRING ); + + private PrintoutRecipe( ResourceLocation id ) + { + super( id ); + } @Override public boolean canFit( int x, int y ) @@ -32,12 +37,6 @@ public boolean canFit( int x, int y ) return x >= 3 && y >= 3; } - @Override - public boolean isDynamic() - { - return true; - } - @Nonnull @Override public ItemStack getRecipeOutput() @@ -46,14 +45,14 @@ public ItemStack getRecipeOutput() } @Override - public boolean matches( @Nonnull InventoryCrafting inventory, @Nonnull World world ) + public boolean matches( @Nonnull IInventory inventory, @Nonnull World world ) { return !getCraftingResult( inventory ).isEmpty(); } @Nonnull @Override - public ItemStack getCraftingResult( @Nonnull InventoryCrafting inventory ) + public ItemStack getCraftingResult( @Nonnull IInventory inventory ) { // See if we match the recipe, and extract the input disk ID and dye colour int numPages = 0; @@ -66,10 +65,10 @@ public ItemStack getCraftingResult( @Nonnull InventoryCrafting inventory ) { for( int x = 0; x < inventory.getWidth(); x++ ) { - ItemStack stack = inventory.getStackInRowAndColumn( x, y ); + ItemStack stack = inventory.getStackInSlot( x + y * inventory.getWidth() ); if( !stack.isEmpty() ) { - if( stack.getItem() instanceof ItemPrintout && ItemPrintout.getType( stack ) != ItemPrintout.Type.Book ) + if( stack.getItem() instanceof ItemPrintout && ((ItemPrintout) stack.getItem()).getType() != ItemPrintout.Type.BOOK ) { if( printouts == null ) { @@ -80,7 +79,7 @@ public ItemStack getCraftingResult( @Nonnull InventoryCrafting inventory ) numPrintouts++; printoutFound = true; } - else if( paper.apply( stack ) ) + else if( paper.test( stack ) ) { if( printouts == null ) { @@ -90,11 +89,11 @@ else if( paper.apply( stack ) ) numPages++; numPrintouts++; } - else if( string.apply( stack ) && !stringFound ) + else if( string.test( stack ) && !stringFound ) { stringFound = true; } - else if( leather.apply( stack ) && !leatherFound ) + else if( leather.test( stack ) && !leatherFound ) { leatherFound = true; } @@ -159,12 +158,14 @@ else if( leather.apply( stack ) && !leatherFound ) return ItemStack.EMPTY; } - public static class Factory implements IRecipeFactory + @Nonnull + @Override + public IRecipeSerializer getSerializer() { - @Override - public IRecipe parse( JsonContext jsonContext, JsonObject jsonObject ) - { - return new PrintoutRecipe(); - } + return SERIALIZER; } + + public static final IRecipeSerializer SERIALIZER = new RecipeSerializers.SimpleSerializer<>( + ComputerCraft.MOD_ID + ":printout", PrintoutRecipe::new + ); } diff --git a/src/main/java/dan200/computercraft/shared/network/Containers.java b/src/main/java/dan200/computercraft/shared/network/Containers.java index 579f3d7bf..b59b45d16 100644 --- a/src/main/java/dan200/computercraft/shared/network/Containers.java +++ b/src/main/java/dan200/computercraft/shared/network/Containers.java @@ -7,16 +7,13 @@ package dan200.computercraft.shared.network; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.client.gui.*; -import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.computer.blocks.TileComputer; -import dan200.computercraft.shared.computer.core.ClientComputer; -import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputer; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; -import dan200.computercraft.shared.media.inventory.ContainerHeldItem; import dan200.computercraft.shared.media.items.ItemPrintout; +import dan200.computercraft.shared.network.container.*; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive; import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; @@ -26,208 +23,74 @@ import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.tileentity.TileEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -import net.minecraftforge.fml.common.network.IGuiHandler; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -public final class Containers implements IGuiHandler +public final class Containers { - public static final Containers INSTANCE = new Containers(); - - private static final int DISK_DRIVE = 100; - private static final int COMPUTER = 101; - private static final int PRINTER = 102; - private static final int TURTLE = 103; - private static final int PRINTOUT = 105; - private static final int POCKET_COMPUTER = 106; - private static final int VIEW_COMPUTER = 110; - private Containers() { } public static void openDiskDriveGUI( EntityPlayer player, TileDiskDrive drive ) { - BlockPos pos = drive.getPos(); - player.openGui( ComputerCraft.instance, DISK_DRIVE, player.getEntityWorld(), pos.getX(), pos.getY(), pos.getZ() ); + TileEntityContainerType.diskDrive( drive.getPos() ).open( player ); } public static void openComputerGUI( EntityPlayer player, TileComputer computer ) { - BlockPos pos = computer.getPos(); - player.openGui( ComputerCraft.instance, COMPUTER, player.getEntityWorld(), pos.getX(), pos.getY(), pos.getZ() ); + TileEntityContainerType.computer( computer.getPos() ).open( player ); } public static void openPrinterGUI( EntityPlayer player, TilePrinter printer ) { - BlockPos pos = printer.getPos(); - player.openGui( ComputerCraft.instance, PRINTER, player.getEntityWorld(), pos.getX(), pos.getY(), pos.getZ() ); + TileEntityContainerType.printer( printer.getPos() ).open( player ); } public static void openTurtleGUI( EntityPlayer player, TileTurtle turtle ) { - BlockPos pos = turtle.getPos(); - player.openGui( ComputerCraft.instance, TURTLE, player.getEntityWorld(), pos.getX(), pos.getY(), pos.getZ() ); + TileEntityContainerType.turtle( turtle.getPos() ).open( player ); } public static void openPrintoutGUI( EntityPlayer player, EnumHand hand ) { - player.openGui( ComputerCraft.instance, PRINTOUT, player.getEntityWorld(), hand.ordinal(), 0, 0 ); + ItemStack stack = player.getHeldItem( hand ); + Item item = stack.getItem(); + if( !(item instanceof ItemPrintout) ) return; + + new PrintoutContainerType( hand ).open( player ); } public static void openPocketComputerGUI( EntityPlayer player, EnumHand hand ) { - player.openGui( ComputerCraft.instance, POCKET_COMPUTER, player.getEntityWorld(), hand.ordinal(), 0, 0 ); + ItemStack stack = player.getHeldItem( hand ); + Item item = stack.getItem(); + if( !(item instanceof ItemPocketComputer) ) return; + + new PocketComputerContainerType( hand ).open( player ); } public static void openComputerGUI( EntityPlayer player, ServerComputer computer ) { - ComputerFamily family = computer.getFamily(); - int width = 0, height = 0; - Terminal terminal = computer.getTerminal(); - if( terminal != null ) - { - width = terminal.getWidth(); - height = terminal.getHeight(); - } - - // Pack useful terminal information into the various coordinate bits. - // These are extracted in ComputerCraftProxyCommon.getClientGuiElement - player.openGui( ComputerCraft.instance, VIEW_COMPUTER, player.getEntityWorld(), - computer.getInstanceID(), family.ordinal(), (width & 0xFFFF) << 16 | (height & 0xFFFF) - ); + new ViewComputerContainerType( computer ).open( player ); } - @Override - public Object getServerGuiElement( int id, EntityPlayer player, World world, int x, int y, int z ) + public static void setup() { - BlockPos pos = new BlockPos( x, y, z ); - switch( id ) - { - case DISK_DRIVE: - { - TileEntity tile = world.getTileEntity( pos ); - if( tile instanceof TileDiskDrive ) - { - TileDiskDrive drive = (TileDiskDrive) tile; - return new ContainerDiskDrive( player.inventory, drive ); - } - break; - } - case COMPUTER: - { - TileEntity tile = world.getTileEntity( pos ); - if( tile instanceof TileComputer ) - { - TileComputer computer = (TileComputer) tile; - return new ContainerComputer( computer ); - } - break; - } - case PRINTER: - { - TileEntity tile = world.getTileEntity( pos ); - if( tile instanceof TilePrinter ) - { - TilePrinter printer = (TilePrinter) tile; - return new ContainerPrinter( player.inventory, printer ); - } - break; - } - case TURTLE: - { - TileEntity tile = world.getTileEntity( pos ); - if( tile instanceof TileTurtle ) - { - TileTurtle turtle = (TileTurtle) tile; - return new ContainerTurtle( player.inventory, turtle.getAccess(), turtle.getServerComputer() ); - } - break; - } - case PRINTOUT: - return new ContainerHeldItem( player, x == 0 ? EnumHand.MAIN_HAND : EnumHand.OFF_HAND ); - case POCKET_COMPUTER: - return new ContainerPocketComputer( player, x == 0 ? EnumHand.MAIN_HAND : EnumHand.OFF_HAND ); - case VIEW_COMPUTER: - { - ServerComputer computer = ComputerCraft.serverComputerRegistry.get( x ); - return computer == null ? null : new ContainerViewComputer( computer ); - } - } - return null; - } + ContainerType.register( TileEntityContainerType::computer, ( packet, player ) -> + new ContainerComputer( (TileComputer) packet.getTileEntity( player ) ) ); + ContainerType.register( TileEntityContainerType::turtle, ( packet, player ) -> { + TileTurtle turtle = (TileTurtle) packet.getTileEntity( player ); + return new ContainerTurtle( player.inventory, turtle.getAccess(), turtle.getServerComputer() ); + } ); + ContainerType.register( TileEntityContainerType::diskDrive, ( packet, player ) -> + new ContainerDiskDrive( player.inventory, (TileDiskDrive) packet.getTileEntity( player ) ) ); + ContainerType.register( TileEntityContainerType::printer, ( packet, player ) -> + new ContainerPrinter( player.inventory, (TilePrinter) packet.getTileEntity( player ) ) ); - @Override - @SideOnly( Side.CLIENT ) - public Object getClientGuiElement( int id, EntityPlayer player, World world, int x, int y, int z ) - { - BlockPos pos = new BlockPos( x, y, z ); - switch( id ) - { - case DISK_DRIVE: - { - TileEntity tile = world.getTileEntity( pos ); - return tile instanceof TileDiskDrive ? new GuiDiskDrive( new ContainerDiskDrive( player.inventory, (TileDiskDrive) tile ) ) : null; - } - case COMPUTER: - { - TileEntity tile = world.getTileEntity( pos ); - return tile instanceof TileComputer ? new GuiComputer( (TileComputer) tile ) : null; - } - case PRINTER: - { - TileEntity tile = world.getTileEntity( pos ); - return tile instanceof TilePrinter ? new GuiPrinter( new ContainerPrinter( player.inventory, (TilePrinter) tile ) ) : null; - } - case TURTLE: - { - TileEntity tile = world.getTileEntity( pos ); - if( tile instanceof TileTurtle ) - { - TileTurtle turtle = (TileTurtle) tile; - return new GuiTurtle( turtle, new ContainerTurtle( player.inventory, turtle.getAccess() ) ); - } - return null; - } - case PRINTOUT: - { - ContainerHeldItem container = new ContainerHeldItem( player, x == 0 ? EnumHand.MAIN_HAND : EnumHand.OFF_HAND ); - return container.getStack().getItem() instanceof ItemPrintout ? new GuiPrintout( container ) : null; - } - case POCKET_COMPUTER: - { - ContainerPocketComputer container = new ContainerPocketComputer( player, x == 0 ? EnumHand.MAIN_HAND : EnumHand.OFF_HAND ); - return container.getStack().getItem() instanceof ItemPocketComputer ? new GuiPocketComputer( container ) : null; - } - case VIEW_COMPUTER: - { - ClientComputer computer = ComputerCraft.clientComputerRegistry.get( x ); - - // We extract some terminal information from the various coordinate flags. - // See ComputerCraft.openComputerGUI for how they are packed. - ComputerFamily family = ComputerFamily.values()[y]; - int width = (z >> 16) & 0xFFFF, height = z & 0xFF; - - if( computer == null ) - { - computer = new ClientComputer( x ); - ComputerCraft.clientComputerRegistry.add( x, computer ); - } - else if( computer.getTerminal() != null ) - { - width = computer.getTerminal().getWidth(); - height = computer.getTerminal().getHeight(); - } - - ContainerViewComputer container = new ContainerViewComputer( computer ); - return new GuiComputer( container, family, computer, width, height ); - } - default: - return null; - } + ContainerType.register( PocketComputerContainerType::new, ( packet, player ) -> new ContainerPocketComputer( player, packet.hand ) ); + ContainerType.register( PrintoutContainerType::new, ( packet, player ) -> new ContainerHeldItem( player, packet.hand ) ); + ContainerType.register( ViewComputerContainerType::new, ( packet, player ) -> new ContainerViewComputer( ComputerCraft.serverComputerRegistry.get( packet.instanceId ) ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java index 441738db0..4afe60ce5 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java @@ -9,21 +9,24 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.network.client.*; import dan200.computercraft.shared.network.server.*; -import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.util.IThreadListener; -import net.minecraftforge.fml.common.network.NetworkRegistry; -import net.minecraftforge.fml.common.network.simpleimpl.IMessage; -import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; -import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper; -import net.minecraftforge.fml.relauncher.Side; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.fml.network.NetworkDirection; +import net.minecraftforge.fml.network.NetworkEvent; +import net.minecraftforge.fml.network.NetworkRegistry; +import net.minecraftforge.fml.network.simple.SimpleChannel; +import net.minecraftforge.fml.server.ServerLifecycleHooks; +import java.util.function.Function; import java.util.function.Supplier; public final class NetworkHandler { - public static SimpleNetworkWrapper network; + public static SimpleChannel network; private NetworkHandler() { @@ -31,41 +34,56 @@ private NetworkHandler() public static void setup() { - network = NetworkRegistry.INSTANCE.newSimpleChannel( ComputerCraft.MOD_ID ); + String version = ComputerCraft.getVersion(); + network = NetworkRegistry.ChannelBuilder.named( new ResourceLocation( ComputerCraft.MOD_ID, "network" ) ) + .networkProtocolVersion( () -> version ) + .clientAcceptedVersions( version::equals ).serverAcceptedVersions( version::equals ) + .simpleChannel(); // Server messages - registerMainThread( 0, Side.SERVER, ComputerActionServerMessage::new ); - registerMainThread( 1, Side.SERVER, QueueEventServerMessage::new ); - registerMainThread( 2, Side.SERVER, RequestComputerMessage::new ); - registerMainThread( 3, Side.SERVER, KeyEventServerMessage::new ); - registerMainThread( 4, Side.SERVER, MouseEventServerMessage::new ); + registerMainThread( 0, ComputerActionServerMessage::new ); + registerMainThread( 1, QueueEventServerMessage::new ); + registerMainThread( 2, RequestComputerMessage::new ); + registerMainThread( 3, KeyEventServerMessage::new ); + registerMainThread( 4, MouseEventServerMessage::new ); // Client messages - registerMainThread( 10, Side.CLIENT, ChatTableClientMessage::new ); - registerMainThread( 11, Side.CLIENT, ComputerDataClientMessage::new ); - registerMainThread( 12, Side.CLIENT, ComputerDeletedClientMessage::new ); - registerMainThread( 13, Side.CLIENT, ComputerTerminalClientMessage::new ); - registerMainThread( 14, Side.CLIENT, PlayRecordClientMessage::new ); + registerMainThread( 10, ChatTableClientMessage::new ); + registerMainThread( 11, ComputerDataClientMessage::new ); + registerMainThread( 12, ComputerDeletedClientMessage::new ); + registerMainThread( 13, ComputerTerminalClientMessage::new ); + registerMainThread( 14, PlayRecordClientMessage.class, PlayRecordClientMessage::new ); } - public static void sendToPlayer( EntityPlayer player, IMessage packet ) + public static void sendToPlayer( EntityPlayer player, NetworkMessage packet ) { - network.sendTo( packet, (EntityPlayerMP) player ); + network.sendTo( packet, ((EntityPlayerMP) player).connection.netManager, NetworkDirection.PLAY_TO_CLIENT ); } - public static void sendToAllPlayers( IMessage packet ) + public static void sendToAllPlayers( NetworkMessage packet ) { - network.sendToAll( packet ); + for( EntityPlayerMP player : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers() ) + { + sendToPlayer( player, packet ); + } } - public static void sendToServer( IMessage packet ) + public static void sendToServer( NetworkMessage packet ) { network.sendToServer( packet ); } - public static void sendToAllAround( IMessage packet, NetworkRegistry.TargetPoint point ) + public static void sendToAllAround( NetworkMessage packet, World world, Vec3d pos, double range ) { - network.sendToAllAround( packet, point ); + for( EntityPlayerMP player : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers() ) + { + if( player.getEntityWorld() != world ) continue; + + double x = pos.x - player.posX; + double y = pos.y - player.posY; + double z = pos.z - player.posZ; + if( x * x + y * y + z * z < range * range ) sendToPlayer( player, packet ); + } } /** @@ -73,24 +91,40 @@ public static void sendToAllAround( IMessage packet, NetworkRegistry.TargetPoint * Register packet, and a thread-unsafe handler for it. * * @param id The identifier for this packet type - * @param side The side to register this packet handler under * @param factory The factory for this type of packet. */ - private static void registerMainThread( int id, Side side, Supplier factory ) + private static void registerMainThread( int id, Supplier factory ) { - network.registerMessage( MAIN_THREAD_HANDLER, factory.get().getClass(), id, side ); + registerMainThread( id, getType( factory ), buf -> { + T instance = factory.get(); + instance.fromBytes( buf ); + return instance; + } ); } - private static final IMessageHandler MAIN_THREAD_HANDLER = ( packet, context ) -> { - IThreadListener listener = context.side == Side.CLIENT ? Minecraft.getMinecraft() : context.getServerHandler().player.server; - if( listener.isCallingFromMinecraftThread() ) - { - packet.handle( context ); - } - else - { - listener.addScheduledTask( () -> packet.handle( context ) ); - } - return null; - }; + /** + * /** + * Register packet, and a thread-unsafe handler for it. + * + * @param id The identifier for this packet type + * @param decoder The factory for this type of packet. + */ + private static void registerMainThread( int id, Class type, Function decoder ) + { + network.messageBuilder( type, id ) + .encoder( NetworkMessage::toBytes ) + .decoder( decoder ) + .consumer( ( packet, contextSup ) -> { + NetworkEvent.Context context = contextSup.get(); + context.enqueueWork( () -> packet.handle( context ) ); + context.setPacketHandled( true ); + } ) + .add(); + } + + @SuppressWarnings( "unchecked" ) + private static Class getType( Supplier supplier ) + { + return (Class) supplier.get().getClass(); + } } diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java b/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java index d8680ec2d..e99b9ad73 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java @@ -6,10 +6,8 @@ package dan200.computercraft.shared.network; -import io.netty.buffer.ByteBuf; import net.minecraft.network.PacketBuffer; -import net.minecraftforge.fml.common.network.simpleimpl.IMessage; -import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import net.minecraftforge.fml.network.NetworkEvent; import javax.annotation.Nonnull; @@ -19,7 +17,7 @@ * @see dan200.computercraft.shared.network.client * @see dan200.computercraft.shared.network.server */ -public interface NetworkMessage extends IMessage +public interface NetworkMessage { /** * Write this packet to a buffer. @@ -37,24 +35,15 @@ public interface NetworkMessage extends IMessage * * @param buf The buffer to read data from. */ - void fromBytes( @Nonnull PacketBuffer buf ); + default void fromBytes( @Nonnull PacketBuffer buf ) + { + throw new IllegalStateException( "Should have been registered using a \"from bytes\" method" ); + } /** * Handle this {@link NetworkMessage}. * * @param context The context with which to handle this message */ - void handle( MessageContext context ); - - @Override - default void fromBytes( ByteBuf buf ) - { - fromBytes( new PacketBuffer( buf ) ); - } - - @Override - default void toBytes( ByteBuf buf ) - { - toBytes( new PacketBuffer( buf ) ); - } + void handle( NetworkEvent.Context context ); } diff --git a/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java index 9fb3f35a4..a3731c774 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java @@ -9,12 +9,11 @@ import dan200.computercraft.client.ClientTableFormatter; import dan200.computercraft.shared.command.text.TableBuilder; import dan200.computercraft.shared.network.NetworkMessage; -import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.network.PacketBuffer; import net.minecraft.util.text.ITextComponent; -import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.network.NetworkEvent; import javax.annotation.Nonnull; @@ -61,7 +60,7 @@ public void fromBytes( @Nonnull PacketBuffer buf ) if( buf.readBoolean() ) { ITextComponent[] headers = new ITextComponent[columns]; - for( int i = 0; i < columns; i++ ) headers[i] = NBTUtil.readTextComponent( buf ); + for( int i = 0; i < columns; i++ ) headers[i] = buf.readTextComponent(); table = new TableBuilder( id, headers ); } else @@ -73,7 +72,7 @@ public void fromBytes( @Nonnull PacketBuffer buf ) for( int i = 0; i < rows; i++ ) { ITextComponent[] row = new ITextComponent[columns]; - for( int j = 0; j < columns; j++ ) row[j] = NBTUtil.readTextComponent( buf ); + for( int j = 0; j < columns; j++ ) row[j] = buf.readTextComponent(); table.row( row ); } @@ -82,8 +81,8 @@ public void fromBytes( @Nonnull PacketBuffer buf ) } @Override - @SideOnly( Side.CLIENT ) - public void handle( MessageContext context ) + @OnlyIn( Dist.CLIENT ) + public void handle( NetworkEvent.Context context ) { ClientTableFormatter.INSTANCE.display( table ); } diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java index 1a0999f0b..77cf5605e 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java @@ -6,12 +6,11 @@ package dan200.computercraft.shared.network.client; -import dan200.computercraft.shared.computer.blocks.ComputerState; +import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; -import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import net.minecraftforge.fml.network.NetworkEvent; import javax.annotation.Nonnull; @@ -47,11 +46,11 @@ public void fromBytes( @Nonnull PacketBuffer buf ) { super.fromBytes( buf ); state = buf.readEnumValue( ComputerState.class ); - userData = NBTUtil.readCompoundTag( buf ); + userData = buf.readCompoundTag(); } @Override - public void handle( MessageContext context ) + public void handle( NetworkEvent.Context context ) { getComputer().setState( state, userData ); } diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java index daa9d4398..b2dcb4285 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java @@ -7,7 +7,7 @@ package dan200.computercraft.shared.network.client; import dan200.computercraft.ComputerCraft; -import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import net.minecraftforge.fml.network.NetworkEvent; public class ComputerDeletedClientMessage extends ComputerClientMessage { @@ -21,7 +21,7 @@ public ComputerDeletedClientMessage() } @Override - public void handle( MessageContext context ) + public void handle( NetworkEvent.Context context ) { ComputerCraft.clientComputerRegistry.remove( getInstanceId() ); } diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java index 5c7adf562..914101143 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java @@ -6,10 +6,9 @@ package dan200.computercraft.shared.network.client; -import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; -import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import net.minecraftforge.fml.network.NetworkEvent; import javax.annotation.Nonnull; @@ -38,11 +37,11 @@ public void toBytes( @Nonnull PacketBuffer buf ) public void fromBytes( @Nonnull PacketBuffer buf ) { super.fromBytes( buf ); - tag = NBTUtil.readCompoundTag( buf ); + tag = buf.readCompoundTag(); } @Override - public void handle( MessageContext context ) + public void handle( NetworkEvent.Context context ) { getComputer().readDescription( tag ); } diff --git a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java index 4458b5e7e..737468d09 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java @@ -11,11 +11,13 @@ import net.minecraft.network.PacketBuffer; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; -import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.network.NetworkEvent; +import net.minecraftforge.registries.ForgeRegistries; import javax.annotation.Nonnull; +import java.util.Objects; /** * Starts or stops a record on the client, depending on if {@link #soundEvent} is {@code null}. @@ -26,9 +28,9 @@ */ public class PlayRecordClientMessage implements NetworkMessage { - private BlockPos pos; - private String name; - private SoundEvent soundEvent; + private final BlockPos pos; + private final String name; + private final SoundEvent soundEvent; public PlayRecordClientMessage( BlockPos pos, SoundEvent event, String name ) { @@ -40,10 +42,23 @@ public PlayRecordClientMessage( BlockPos pos, SoundEvent event, String name ) public PlayRecordClientMessage( BlockPos pos ) { this.pos = pos; + name = null; + soundEvent = null; } - public PlayRecordClientMessage() + public PlayRecordClientMessage( PacketBuffer buf ) { + pos = buf.readBlockPos(); + if( buf.readBoolean() ) + { + name = buf.readString( Short.MAX_VALUE ); + soundEvent = ForgeRegistries.SOUND_EVENTS.getValue( buf.readResourceLocation() ); + } + else + { + name = null; + soundEvent = null; + } } @Override @@ -58,26 +73,15 @@ public void toBytes( @Nonnull PacketBuffer buf ) { buf.writeBoolean( true ); buf.writeString( name ); - buf.writeInt( SoundEvent.REGISTRY.getIDForObject( soundEvent ) ); + buf.writeResourceLocation( Objects.requireNonNull( soundEvent.getRegistryName(), "Sound is not registered" ) ); } } @Override - public void fromBytes( @Nonnull PacketBuffer buf ) + @OnlyIn( Dist.CLIENT ) + public void handle( NetworkEvent.Context context ) { - pos = buf.readBlockPos(); - if( buf.readBoolean() ) - { - name = buf.readString( Short.MAX_VALUE ); - soundEvent = SoundEvent.REGISTRY.getObjectById( buf.readInt() ); - } - } - - @Override - @SideOnly( Side.CLIENT ) - public void handle( MessageContext context ) - { - Minecraft mc = Minecraft.getMinecraft(); + Minecraft mc = Minecraft.getInstance(); mc.world.playRecord( pos, soundEvent ); if( name != null ) mc.ingameGUI.setRecordPlayingMessage( name ); } diff --git a/src/main/java/dan200/computercraft/shared/network/container/ContainerType.java b/src/main/java/dan200/computercraft/shared/network/container/ContainerType.java new file mode 100644 index 000000000..27ca78681 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/network/container/ContainerType.java @@ -0,0 +1,104 @@ +/* + * 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.shared.network.container; + +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.world.IInteractionObject; +import net.minecraftforge.fml.network.NetworkHooks; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * A horrible hack to allow opening GUIs until Forge adds a built-in system. + */ +public interface ContainerType extends IInteractionObject +{ + @Nonnull + ResourceLocation getId(); + + void toBytes( PacketBuffer buf ); + + void fromBytes( PacketBuffer buf ); + + @Nonnull + @Override + @SuppressWarnings( "unchecked" ) + default T createContainer( @Nonnull InventoryPlayer inventoryPlayer, @Nonnull EntityPlayer entityPlayer ) + { + return ((BiFunction, EntityPlayer, T>) containerFactories.get( getId() )).apply( this, entityPlayer ); + } + + @Nonnull + @Override + default String getGuiID() + { + return getId().toString(); + } + + @Nonnull + @Override + default ITextComponent getName() + { + return new TextComponentString( "" ); + } + + @Override + default boolean hasCustomName() + { + return false; + } + + @Nullable + @Override + default ITextComponent getCustomName() + { + return null; + } + + default void open( EntityPlayer player ) + { + NetworkHooks.openGui( (EntityPlayerMP) player, this, this::toBytes ); + } + + static > void register( Supplier containerType, BiFunction factory ) + { + factories.put( containerType.get().getId(), containerType ); + containerFactories.put( containerType.get().getId(), factory ); + } + + static > void registerGui( Supplier containerType, BiFunction factory ) + { + guiFactories.put( containerType.get().getId(), factory ); + } + + static > void registerGui( Supplier containerType, Function factory ) + { + registerGui( containerType, ( type, player ) -> { + @SuppressWarnings( "unchecked" ) + C container = ((BiFunction) containerFactories.get( type.getId() )).apply( type, player ); + return container == null ? null : factory.apply( container ); + } ); + } + + Map>> factories = new HashMap<>(); + Map, EntityPlayer, GuiContainer>> guiFactories = new HashMap<>(); + Map, EntityPlayer, ? extends Container>> containerFactories = new HashMap<>(); +} diff --git a/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerType.java b/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerType.java new file mode 100644 index 000000000..859b369aa --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerType.java @@ -0,0 +1,55 @@ +/* + * 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.shared.network.container; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nonnull; + +/** + * Opens a pocket computer GUI based on the held item + * + * @see dan200.computercraft.shared.pocket.items.ItemPocketComputer + */ +public class PocketComputerContainerType implements ContainerType +{ + public static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_gui" ); + + public EnumHand hand; + + public PocketComputerContainerType( EnumHand hand ) + { + this.hand = hand; + } + + public PocketComputerContainerType() + { + } + + @Nonnull + @Override + public ResourceLocation getId() + { + return ID; + } + + @Override + public void toBytes( @Nonnull PacketBuffer buf ) + { + buf.writeEnumValue( hand ); + } + + @Override + public void fromBytes( @Nonnull PacketBuffer buf ) + { + hand = buf.readEnumValue( EnumHand.class ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/network/container/PrintoutContainerType.java b/src/main/java/dan200/computercraft/shared/network/container/PrintoutContainerType.java new file mode 100644 index 000000000..b89244d75 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/network/container/PrintoutContainerType.java @@ -0,0 +1,55 @@ +/* + * 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.shared.network.container; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.common.ContainerHeldItem; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nonnull; + +/** + * Opens a printout GUI based on the currently held item + * + * @see dan200.computercraft.shared.media.items.ItemPrintout + */ +public class PrintoutContainerType implements ContainerType +{ + public static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "printout_gui" ); + + public EnumHand hand; + + public PrintoutContainerType( EnumHand hand ) + { + this.hand = hand; + } + + public PrintoutContainerType() + { + } + + @Nonnull + @Override + public ResourceLocation getId() + { + return ID; + } + + @Override + public void toBytes( @Nonnull PacketBuffer buf ) + { + buf.writeEnumValue( hand ); + } + + @Override + public void fromBytes( @Nonnull PacketBuffer buf ) + { + hand = buf.readEnumValue( EnumHand.class ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/network/container/TileEntityContainerType.java b/src/main/java/dan200/computercraft/shared/network/container/TileEntityContainerType.java new file mode 100644 index 000000000..48185e1b5 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/network/container/TileEntityContainerType.java @@ -0,0 +1,114 @@ +/* + * 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.shared.network.container; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.computer.inventory.ContainerComputer; +import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; +import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; +import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; + +import javax.annotation.Nonnull; + +/** + * Opens a GUI on a specific ComputerCraft TileEntity + * + * @see dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive + * @see dan200.computercraft.shared.peripheral.printer.TilePrinter + * @see dan200.computercraft.shared.computer.blocks.TileComputer + */ +public final class TileEntityContainerType implements ContainerType +{ + private static final ResourceLocation DISK_DRIVE = new ResourceLocation( ComputerCraft.MOD_ID, "disk_drive" ); + private static final ResourceLocation PRINTER = new ResourceLocation( ComputerCraft.MOD_ID, "printer" ); + private static final ResourceLocation COMPUTER = new ResourceLocation( ComputerCraft.MOD_ID, "computer" ); + private static final ResourceLocation TURTLE = new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ); + + public BlockPos pos; + private final ResourceLocation id; + + private TileEntityContainerType( ResourceLocation id, BlockPos pos ) + { + this.id = id; + this.pos = pos; + } + + private TileEntityContainerType( ResourceLocation id ) + { + this.id = id; + } + + @Nonnull + @Override + public ResourceLocation getId() + { + return id; + } + + @Override + public void toBytes( PacketBuffer buf ) + { + buf.writeBlockPos( pos ); + } + + @Override + public void fromBytes( PacketBuffer buf ) + { + pos = buf.readBlockPos(); + } + + public TileEntity getTileEntity( EntityPlayer entity ) + { + return entity.world.getTileEntity( pos ); + } + + public static TileEntityContainerType diskDrive() + { + return new TileEntityContainerType<>( DISK_DRIVE ); + } + + public static TileEntityContainerType diskDrive( BlockPos pos ) + { + return new TileEntityContainerType<>( DISK_DRIVE, pos ); + } + + public static TileEntityContainerType printer() + { + return new TileEntityContainerType<>( PRINTER ); + } + + public static TileEntityContainerType printer( BlockPos pos ) + { + return new TileEntityContainerType<>( PRINTER, pos ); + } + + public static TileEntityContainerType computer() + { + return new TileEntityContainerType<>( COMPUTER ); + } + + public static TileEntityContainerType computer( BlockPos pos ) + { + return new TileEntityContainerType<>( COMPUTER, pos ); + } + + public static TileEntityContainerType turtle() + { + return new TileEntityContainerType<>( TURTLE ); + } + + public static TileEntityContainerType turtle( BlockPos pos ) + { + return new TileEntityContainerType<>( TURTLE, pos ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerType.java b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerType.java new file mode 100644 index 000000000..ff541796a --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerType.java @@ -0,0 +1,73 @@ +/* + * 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.shared.network.container; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nonnull; + +/** + * View an arbitrary computer on the client. + * + * @see dan200.computercraft.shared.command.CommandComputerCraft + */ +public class ViewComputerContainerType implements ContainerType +{ + public static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "view_computer_gui" ); + + public int instanceId; + public int width; + public int height; + public ComputerFamily family; + + public ViewComputerContainerType( ServerComputer computer ) + { + instanceId = computer.getInstanceID(); + Terminal terminal = computer.getTerminal(); + if( terminal != null ) + { + width = terminal.getWidth(); + height = terminal.getHeight(); + } + family = computer.getFamily(); + } + + public ViewComputerContainerType() + { + } + + @Nonnull + @Override + public ResourceLocation getId() + { + return ID; + } + + @Override + public void toBytes( @Nonnull PacketBuffer buf ) + { + buf.writeVarInt( instanceId ); + buf.writeVarInt( width ); + buf.writeVarInt( height ); + buf.writeEnumValue( family ); + } + + @Override + public void fromBytes( @Nonnull PacketBuffer buf ) + { + instanceId = buf.readVarInt(); + width = buf.readVarInt(); + height = buf.readVarInt(); + family = buf.readEnumValue( ComputerFamily.class ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java index 2d4c6e07b..ab40f03b8 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java @@ -11,7 +11,7 @@ import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.NetworkMessage; import net.minecraft.network.PacketBuffer; -import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import net.minecraftforge.fml.network.NetworkEvent; import javax.annotation.Nonnull; @@ -47,12 +47,12 @@ public void fromBytes( @Nonnull PacketBuffer buf ) } @Override - public void handle( MessageContext context ) + public void handle( NetworkEvent.Context context ) { ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instanceId ); if( computer == null ) return; - IContainerComputer container = computer.getContainer( context.getServerHandler().player ); + IContainerComputer container = computer.getContainer( context.getSender() ); if( container == null ) return; handle( computer, container ); diff --git a/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java index c1467f3f9..c2b57055a 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java @@ -51,7 +51,7 @@ public void fromBytes( @Nonnull PacketBuffer buf ) super.fromBytes( buf ); event = buf.readString( Short.MAX_VALUE ); - NBTTagCompound args = NBTUtil.readCompoundTag( buf ); + NBTTagCompound args = buf.readCompoundTag(); this.args = args == null ? null : NBTUtil.decodeObjects( args ); } diff --git a/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java index 77b4aecb2..74282b7e8 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java @@ -10,7 +10,7 @@ import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.NetworkMessage; import net.minecraft.network.PacketBuffer; -import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import net.minecraftforge.fml.network.NetworkEvent; import javax.annotation.Nonnull; @@ -40,9 +40,9 @@ public void fromBytes( @Nonnull PacketBuffer buf ) } @Override - public void handle( MessageContext context ) + public void handle( NetworkEvent.Context context ) { ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instance ); - if( computer != null ) computer.sendComputerState( context.getServerHandler().player ); + if( computer != null ) computer.sendComputerState( context.getSender() ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/PeripheralType.java b/src/main/java/dan200/computercraft/shared/peripheral/PeripheralType.java deleted file mode 100644 index 3bb4dfa2b..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/PeripheralType.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.shared.peripheral; - -import net.minecraft.util.IStringSerializable; - -import javax.annotation.Nonnull; - -public enum PeripheralType implements IStringSerializable -{ - DiskDrive( "disk_drive" ), - Printer( "printer" ), - Monitor( "monitor" ), - AdvancedMonitor( "advanced_monitor" ), - WirelessModem( "wireless_modem" ), - WiredModem( "wired_modem" ), - Cable( "cable" ), - WiredModemWithCable( "wired_modem_with_cable" ), - AdvancedModem( "advanced_modem" ), - Speaker( "speaker" ), - WiredModemFull( "wired_modem_full" ); - - private final String name; - - PeripheralType( String name ) - { - this.name = name; - } - - @Nonnull - @Override - public String getName() - { - return name; - } - - @Override - public String toString() { return name; } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/BlockPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/common/BlockPeripheral.java deleted file mode 100644 index b7d5c46f1..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/BlockPeripheral.java +++ /dev/null @@ -1,573 +0,0 @@ -/* - * 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.shared.peripheral.common; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.common.BlockGeneric; -import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive; -import dan200.computercraft.shared.peripheral.modem.ModemBounds; -import dan200.computercraft.shared.peripheral.modem.wireless.TileWirelessModem; -import dan200.computercraft.shared.peripheral.monitor.TileMonitor; -import dan200.computercraft.shared.peripheral.printer.TilePrinter; -import dan200.computercraft.shared.peripheral.speaker.TileSpeaker; -import dan200.computercraft.shared.util.DirectionUtil; -import net.minecraft.block.BlockHorizontal; -import net.minecraft.block.material.Material; -import net.minecraft.block.properties.PropertyDirection; -import net.minecraft.block.properties.PropertyEnum; -import net.minecraft.block.state.BlockFaceShape; -import net.minecraft.block.state.BlockStateContainer; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemStack; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.BlockRenderLayer; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.NonNullList; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.world.IBlockAccess; -import net.minecraft.world.World; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - -import javax.annotation.Nonnull; - -public class BlockPeripheral extends BlockGeneric -{ - public static final PropertyDirection FACING = BlockHorizontal.FACING; - public static final PropertyEnum VARIANT = PropertyEnum.create( "variant", BlockPeripheralVariant.class ); - - public BlockPeripheral() - { - super( Material.ROCK ); - setHardness( 2.0f ); - setTranslationKey( "computercraft:peripheral" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - setDefaultState( blockState.getBaseState() - .withProperty( FACING, EnumFacing.NORTH ) - .withProperty( VARIANT, BlockPeripheralVariant.DiskDriveEmpty ) - ); - } - - @Override - @Nonnull - @SideOnly( Side.CLIENT ) - public BlockRenderLayer getRenderLayer() - { - return BlockRenderLayer.CUTOUT; - } - - @Nonnull - @Override - protected BlockStateContainer createBlockState() - { - return new BlockStateContainer( this, FACING, VARIANT ); - } - - @Nonnull - @Override - @Deprecated - public IBlockState getStateFromMeta( int meta ) - { - IBlockState state = getDefaultState(); - if( meta >= 2 && meta <= 5 ) - { - state = state.withProperty( VARIANT, BlockPeripheralVariant.DiskDriveEmpty ); - state = state.withProperty( FACING, EnumFacing.byIndex( meta ) ); - } - else if( meta <= 9 ) - { - if( meta == 0 ) - { - state = state.withProperty( VARIANT, BlockPeripheralVariant.WirelessModemDownOff ); - state = state.withProperty( FACING, EnumFacing.NORTH ); - } - else if( meta == 1 ) - { - state = state.withProperty( VARIANT, BlockPeripheralVariant.WirelessModemUpOff ); - state = state.withProperty( FACING, EnumFacing.NORTH ); - } - else - { - state = state.withProperty( VARIANT, BlockPeripheralVariant.WirelessModemOff ); - state = state.withProperty( FACING, EnumFacing.byIndex( meta - 4 ) ); - } - } - else if( meta == 10 ) - { - state = state.withProperty( VARIANT, BlockPeripheralVariant.Monitor ); - } - else if( meta == 11 ) - { - state = state.withProperty( VARIANT, BlockPeripheralVariant.PrinterEmpty ); - } - else if( meta == 12 ) - { - state = state.withProperty( VARIANT, BlockPeripheralVariant.AdvancedMonitor ); - } - else if( meta == 13 ) - { - state = state.withProperty( VARIANT, BlockPeripheralVariant.Speaker ); - } - return state; - } - - @Override - public int getMetaFromState( IBlockState state ) - { - int meta = 0; - BlockPeripheralVariant variant = state.getValue( VARIANT ); - switch( variant.getPeripheralType() ) - { - case DiskDrive: - { - EnumFacing dir = state.getValue( FACING ); - if( dir.getAxis() == EnumFacing.Axis.Y ) - { - dir = EnumFacing.NORTH; - } - meta = dir.getIndex(); - break; - } - case WirelessModem: - switch( variant ) - { - case WirelessModemDownOff: - case WirelessModemDownOn: - meta = 0; - break; - case WirelessModemUpOff: - case WirelessModemUpOn: - meta = 1; - break; - default: - { - EnumFacing dir = state.getValue( FACING ); - meta = dir.getIndex() + 4; - break; - } - } - break; - case Monitor: - meta = 10; - break; - case Printer: - meta = 11; - break; - case AdvancedMonitor: - meta = 12; - break; - case Speaker: - meta = 13; - break; - } - return meta; - } - - @Nonnull - @Override - @Deprecated - public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos ) - { - TileEntity tile = world.getTileEntity( pos ); - PeripheralType type = getPeripheralType( state ); - switch( type ) - { - case DiskDrive: - { - if( !(tile instanceof TileDiskDrive) ) return state; - - TileDiskDrive drive = (TileDiskDrive) tile; - state = state.withProperty( FACING, drive.getDirection() ); - switch( drive.getAnim() ) - { - default: - case 0: - return state.withProperty( VARIANT, BlockPeripheralVariant.DiskDriveEmpty ); - case 1: - return state.withProperty( VARIANT, BlockPeripheralVariant.DiskDriveInvalid ); - case 2: - return state.withProperty( VARIANT, BlockPeripheralVariant.DiskDriveFull ); - } - } - case Printer: - { - if( !(tile instanceof TilePrinter) ) return state; - - TilePrinter printer = (TilePrinter) tile; - state = state.withProperty( FACING, printer.getDirection() ); - switch( printer.getAnim() ) - { - default: - case 0: - return state.withProperty( VARIANT, BlockPeripheralVariant.PrinterEmpty ); - case 1: - return state.withProperty( VARIANT, BlockPeripheralVariant.PrinterTopFull ); - case 2: - return state.withProperty( VARIANT, BlockPeripheralVariant.PrinterBottomFull ); - case 3: - return state.withProperty( VARIANT, BlockPeripheralVariant.PrinterBothFull ); - } - } - case WirelessModem: - { - if( !(tile instanceof TileWirelessModem) ) return state; - - TileWirelessModem modem = (TileWirelessModem) tile; - EnumFacing direction = modem.getDirection(); - switch( direction ) - { - case UP: - return state - .withProperty( FACING, EnumFacing.NORTH ) - .withProperty( VARIANT, - modem.isOn() ? BlockPeripheralVariant.WirelessModemUpOn : BlockPeripheralVariant.WirelessModemUpOff ); - case DOWN: - return state - .withProperty( FACING, EnumFacing.NORTH ) - .withProperty( VARIANT, - modem.isOn() ? BlockPeripheralVariant.WirelessModemDownOn : BlockPeripheralVariant.WirelessModemDownOff ); - default: - { - return state - .withProperty( FACING, direction ) - .withProperty( VARIANT, - modem.isOn() ? BlockPeripheralVariant.WirelessModemOn : BlockPeripheralVariant.WirelessModemOff ); - } - } - } - case Speaker: - { - if( !(tile instanceof TileSpeaker) ) return state; - return state.withProperty( FACING, ((TileSpeaker) tile).getDirection() ); - } - case Monitor: - case AdvancedMonitor: - { - if( !(tile instanceof TileMonitor) ) return state; - - TileMonitor monitor = (TileMonitor) tile; - EnumFacing dir = monitor.getDirection(); - EnumFacing front = monitor.getFront(); - int xIndex = monitor.getXIndex(); - int yIndex = monitor.getYIndex(); - int width = monitor.getWidth(); - int height = monitor.getHeight(); - - BlockPeripheralVariant baseVariant; - if( front == EnumFacing.UP ) - { - baseVariant = type == PeripheralType.AdvancedMonitor ? - BlockPeripheralVariant.AdvancedMonitorUp : - BlockPeripheralVariant.MonitorUp; - } - else if( front == EnumFacing.DOWN ) - { - baseVariant = type == PeripheralType.AdvancedMonitor ? - BlockPeripheralVariant.AdvancedMonitorDown : - BlockPeripheralVariant.MonitorDown; - } - else - { - baseVariant = type == PeripheralType.AdvancedMonitor ? - BlockPeripheralVariant.AdvancedMonitor : - BlockPeripheralVariant.Monitor; - } - - int subType; - if( width == 1 && height == 1 ) - { - subType = 0; - } - else if( height == 1 ) - { - if( xIndex == 0 ) - { - subType = 1; - } - else if( xIndex == width - 1 ) - { - subType = 3; - } - else - { - subType = 2; - } - } - else if( width == 1 ) - { - if( yIndex == 0 ) - { - subType = 6; - } - else if( yIndex == height - 1 ) - { - subType = 4; - } - else - { - subType = 5; - } - } - else - { - if( xIndex == 0 ) - { - subType = 7; - } - else if( xIndex == width - 1 ) - { - subType = 9; - } - else - { - subType = 8; - } - if( yIndex == 0 ) - { - subType += 6; - } - else if( yIndex < height - 1 ) - { - subType += 3; - } - } - - return state - .withProperty( FACING, dir ) - .withProperty( VARIANT, BlockPeripheralVariant.values()[baseVariant.ordinal() + subType] ); - } - default: - return state; - } - } - - @Nonnull - @Override - @Deprecated - public final IBlockState getStateForPlacement( World world, BlockPos pos, EnumFacing placedSide, float hitX, float hitY, float hitZ, int damage, EntityLivingBase placer ) - { - switch( getPeripheralType( damage ) ) - { - case DiskDrive: - default: - return getDefaultState() - .withProperty( VARIANT, BlockPeripheralVariant.DiskDriveEmpty ) - .withProperty( FACING, placedSide.getAxis() == EnumFacing.Axis.Y ? EnumFacing.NORTH : placedSide ); - case WirelessModem: - { - EnumFacing dir = placedSide.getOpposite(); - if( dir == EnumFacing.DOWN ) - { - return getDefaultState() - .withProperty( VARIANT, BlockPeripheralVariant.WirelessModemDownOff ) - .withProperty( FACING, EnumFacing.NORTH ); - } - else if( dir == EnumFacing.UP ) - { - return getDefaultState() - .withProperty( VARIANT, BlockPeripheralVariant.WirelessModemUpOff ) - .withProperty( FACING, EnumFacing.NORTH ); - } - else - { - return getDefaultState() - .withProperty( VARIANT, BlockPeripheralVariant.WirelessModemOff ) - .withProperty( FACING, dir ); - } - } - case Monitor: - return getDefaultState().withProperty( VARIANT, BlockPeripheralVariant.Monitor ); - case Printer: - return getDefaultState().withProperty( VARIANT, BlockPeripheralVariant.PrinterEmpty ); - case AdvancedMonitor: - return getDefaultState().withProperty( VARIANT, BlockPeripheralVariant.AdvancedMonitor ); - case Speaker: - return getDefaultState().withProperty( VARIANT, BlockPeripheralVariant.Speaker ); - } - } - - public PeripheralType getPeripheralType( int damage ) - { - return ComputerCraft.Items.peripheral.getPeripheralType( damage ); - } - - public static PeripheralType getPeripheralType( IBlockState state ) - { - return state.getValue( VARIANT ).getPeripheralType(); - } - - private TileGeneric createTile( PeripheralType type ) - { - switch( type ) - { - case DiskDrive: - default: - return new TileDiskDrive(); - case WirelessModem: - return new TileWirelessModem(); - case Monitor: - case AdvancedMonitor: - return new TileMonitor(); - case Printer: - return new TilePrinter(); - case Speaker: - return new TileSpeaker(); - } - } - - @Override - public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, EntityLivingBase player, @Nonnull ItemStack stack ) - { - TileEntity tile = world.getTileEntity( pos ); - switch( getPeripheralType( state ) ) - { - case Speaker: - case DiskDrive: - case Printer: - if( tile instanceof TilePeripheralBase ) - { - TilePeripheralBase peripheral = (TilePeripheralBase) tile; - peripheral.setDirection( DirectionUtil.fromEntityRot( player ) ); - if( stack.hasDisplayName() ) peripheral.setLabel( stack.getDisplayName() ); - } - break; - case Monitor: - case AdvancedMonitor: - if( tile instanceof TileMonitor ) - { - int direction = DirectionUtil.fromEntityRot( player ).getIndex(); - if( player.rotationPitch > 66.5F ) - { - direction += 12; - } - else if( player.rotationPitch < -66.5F ) - { - direction += 6; - } - - TileMonitor monitor = (TileMonitor) tile; - if( world.isRemote ) - { - monitor.setDir( direction ); - } - else - { - monitor.contractNeighbours(); - monitor.setDir( direction ); - monitor.contract(); - monitor.expand(); - } - } - break; - } - } - - @Override - @Deprecated - public final boolean isOpaqueCube( IBlockState state ) - { - PeripheralType type = getPeripheralType( state ); - return type == PeripheralType.DiskDrive || type == PeripheralType.Printer - || type == PeripheralType.Monitor || type == PeripheralType.AdvancedMonitor - || type == PeripheralType.Speaker; - } - - @Override - @Deprecated - public final boolean isFullCube( IBlockState state ) - { - return isOpaqueCube( state ); - } - - @Override - @Deprecated - public boolean isFullBlock( IBlockState state ) - { - return isOpaqueCube( state ); - } - - @Nonnull - @Override - @Deprecated - public BlockFaceShape getBlockFaceShape( IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing side ) - { - return isOpaqueCube( state ) ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED; - } - - @Override - @Deprecated - public boolean causesSuffocation( IBlockState state ) - { - // This normally uses the default state - return material.blocksMovement() && state.isOpaqueCube(); - } - - @Override - @Deprecated - public int getLightOpacity( IBlockState state ) - { - // This normally uses the default state - return isOpaqueCube( state ) ? 255 : 0; - } - - @Override - @Deprecated - @Nonnull - public AxisAlignedBB getBoundingBox( IBlockState state, IBlockAccess world, BlockPos pos ) - { - if( getPeripheralType( state ) == PeripheralType.WirelessModem ) - { - TileEntity tile = world.getTileEntity( pos ); - if( tile instanceof TileWirelessModem ) - { - return ModemBounds.getBounds( ((TileWirelessModem) tile).getDirection() ); - } - } - - return super.getBoundingBox( state, world, pos ); - } - - @Override - public final boolean canPlaceBlockOnSide( @Nonnull World world, @Nonnull BlockPos pos, EnumFacing side ) - { - return true; // ItemPeripheralBase handles this - } - - @Override - public final TileGeneric createTile( IBlockState state ) - { - return createTile( getPeripheralType( state ) ); - } - - @Override - public final TileGeneric createTile( int damage ) - { - return createTile( getPeripheralType( damage ) ); - } - - @Nonnull - @Override - public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult target, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player ) - { - TileEntity tile = world.getTileEntity( pos ); - return tile instanceof ITilePeripheral - ? PeripheralItemFactory.create( (ITilePeripheral) tile ) - : super.getPickBlock( state, target, world, pos, player ); - } - - @Override - public void getDrops( @Nonnull NonNullList drops, IBlockAccess world, BlockPos pos, @Nonnull IBlockState state, int fortune ) - { - drops.add( PeripheralItemFactory.create( getPeripheralType( state ), null, 1 ) ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/BlockPeripheralVariant.java b/src/main/java/dan200/computercraft/shared/peripheral/common/BlockPeripheralVariant.java deleted file mode 100644 index a14c39bb4..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/BlockPeripheralVariant.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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.shared.peripheral.common; - -import dan200.computercraft.shared.peripheral.PeripheralType; -import net.minecraft.util.IStringSerializable; - -import javax.annotation.Nonnull; - -public enum BlockPeripheralVariant implements IStringSerializable -{ - DiskDriveEmpty( "disk_drive_empty", PeripheralType.DiskDrive ), - DiskDriveFull( "disk_drive_full", PeripheralType.DiskDrive ), - DiskDriveInvalid( "disk_drive_invalid", PeripheralType.DiskDrive ), - PrinterEmpty( "printer_empty", PeripheralType.Printer ), - PrinterTopFull( "printer_top_full", PeripheralType.Printer ), - PrinterBottomFull( "printer_bottom_full", PeripheralType.Printer ), - PrinterBothFull( "printer_both_full", PeripheralType.Printer ), - WirelessModemOff( "wireless_modem_off", PeripheralType.WirelessModem ), - WirelessModemOn( "wireless_modem_on", PeripheralType.WirelessModem ), - WirelessModemUpOff( "wireless_modem_up_off", PeripheralType.WirelessModem ), - WirelessModemUpOn( "wireless_modem_up_on", PeripheralType.WirelessModem ), - WirelessModemDownOff( "wireless_modem_down_off", PeripheralType.WirelessModem ), - WirelessModemDownOn( "wireless_modem_down_on", PeripheralType.WirelessModem ), - Monitor( "monitor", PeripheralType.Monitor ), - MonitorR( "monitor_r", PeripheralType.Monitor ), - MonitorLR( "monitor_lr", PeripheralType.Monitor ), - MonitorL( "monitor_l", PeripheralType.Monitor ), - MonitorD( "monitor_d", PeripheralType.Monitor ), - MonitorUD( "monitor_ud", PeripheralType.Monitor ), - MonitorU( "monitor_u", PeripheralType.Monitor ), - MonitorRD( "monitor_rd", PeripheralType.Monitor ), - MonitorLRD( "monitor_lrd", PeripheralType.Monitor ), - MonitorLD( "monitor_ld", PeripheralType.Monitor ), - MonitorRUD( "monitor_rud", PeripheralType.Monitor ), - MonitorLRUD( "monitor_lrud", PeripheralType.Monitor ), - MonitorLUD( "monitor_lud", PeripheralType.Monitor ), - MonitorRU( "monitor_ru", PeripheralType.Monitor ), - MonitorLRU( "monitor_lru", PeripheralType.Monitor ), - MonitorLU( "monitor_lu", PeripheralType.Monitor ), - MonitorUp( "monitor_up", PeripheralType.Monitor ), - MonitorUpR( "monitor_up_r", PeripheralType.Monitor ), - MonitorUpLR( "monitor_up_lr", PeripheralType.Monitor ), - MonitorUpL( "monitor_up_l", PeripheralType.Monitor ), - MonitorUpD( "monitor_up_d", PeripheralType.Monitor ), - MonitorUpUD( "monitor_up_ud", PeripheralType.Monitor ), - MonitorUpU( "monitor_up_u", PeripheralType.Monitor ), - MonitorUpRD( "monitor_up_rd", PeripheralType.Monitor ), - MonitorUpLRD( "monitor_up_lrd", PeripheralType.Monitor ), - MonitorUpLD( "monitor_up_ld", PeripheralType.Monitor ), - MonitorUpRUD( "monitor_up_rud", PeripheralType.Monitor ), - MonitorUpLRUD( "monitor_up_lrud", PeripheralType.Monitor ), - MonitorUpLUD( "monitor_up_lud", PeripheralType.Monitor ), - MonitorUpRU( "monitor_up_ru", PeripheralType.Monitor ), - MonitorUpLRU( "monitor_up_lru", PeripheralType.Monitor ), - MonitorUpLU( "monitor_up_lu", PeripheralType.Monitor ), - MonitorDown( "monitor_down", PeripheralType.Monitor ), - MonitorDownR( "monitor_down_r", PeripheralType.Monitor ), - MonitorDownLR( "monitor_down_lr", PeripheralType.Monitor ), - MonitorDownL( "monitor_down_l", PeripheralType.Monitor ), - MonitorDownD( "monitor_down_d", PeripheralType.Monitor ), - MonitorDownUD( "monitor_down_ud", PeripheralType.Monitor ), - MonitorDownU( "monitor_down_u", PeripheralType.Monitor ), - MonitorDownRD( "monitor_down_rd", PeripheralType.Monitor ), - MonitorDownLRD( "monitor_down_lrd", PeripheralType.Monitor ), - MonitorDownLD( "monitor_down_ld", PeripheralType.Monitor ), - MonitorDownRUD( "monitor_down_rud", PeripheralType.Monitor ), - MonitorDownLRUD( "monitor_down_lrud", PeripheralType.Monitor ), - MonitorDownLUD( "monitor_down_lud", PeripheralType.Monitor ), - MonitorDownRU( "monitor_down_ru", PeripheralType.Monitor ), - MonitorDownLRU( "monitor_down_lru", PeripheralType.Monitor ), - MonitorDownLU( "monitor_down_lu", PeripheralType.Monitor ), - AdvancedMonitor( "advanced_monitor", PeripheralType.AdvancedMonitor ), - AdvancedMonitorR( "advanced_monitor_r", PeripheralType.AdvancedMonitor ), - AdvancedMonitorLR( "advanced_monitor_lr", PeripheralType.AdvancedMonitor ), - AdvancedMonitorL( "advanced_monitor_l", PeripheralType.AdvancedMonitor ), - AdvancedMonitorD( "advanced_monitor_d", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUD( "advanced_monitor_ud", PeripheralType.AdvancedMonitor ), - AdvancedMonitorU( "advanced_monitor_u", PeripheralType.AdvancedMonitor ), - AdvancedMonitorRD( "advanced_monitor_rd", PeripheralType.AdvancedMonitor ), - AdvancedMonitorLRD( "advanced_monitor_lrd", PeripheralType.AdvancedMonitor ), - AdvancedMonitorLD( "advanced_monitor_ld", PeripheralType.AdvancedMonitor ), - AdvancedMonitorRUD( "advanced_monitor_rud", PeripheralType.AdvancedMonitor ), - AdvancedMonitorLRUD( "advanced_monitor_lrud", PeripheralType.AdvancedMonitor ), - AdvancedMonitorLUD( "advanced_monitor_lud", PeripheralType.AdvancedMonitor ), - AdvancedMonitorRU( "advanced_monitor_ru", PeripheralType.AdvancedMonitor ), - AdvancedMonitorLRU( "advanced_monitor_lru", PeripheralType.AdvancedMonitor ), - AdvancedMonitorLU( "advanced_monitor_lu", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUp( "advanced_monitor_up", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpR( "advanced_monitor_up_r", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpLR( "advanced_monitor_up_lr", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpL( "advanced_monitor_up_l", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpD( "advanced_monitor_up_d", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpUD( "advanced_monitor_up_ud", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpU( "advanced_monitor_up_u", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpRD( "advanced_monitor_up_rd", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpLRD( "advanced_monitor_up_lrd", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpLD( "advanced_monitor_up_ld", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpRUD( "advanced_monitor_up_rud", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpLRUD( "advanced_monitor_up_lrud", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpLUD( "advanced_monitor_up_lud", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpRU( "advanced_monitor_up_ru", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpLRU( "advanced_monitor_up_lru", PeripheralType.AdvancedMonitor ), - AdvancedMonitorUpLU( "advanced_monitor_up_lu", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDown( "advanced_monitor_down", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownR( "advanced_monitor_down_r", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownLR( "advanced_monitor_down_lr", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownL( "advanced_monitor_down_l", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownD( "advanced_monitor_down_d", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownUD( "advanced_monitor_down_ud", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownU( "advanced_monitor_down_u", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownRD( "advanced_monitor_down_rd", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownLRD( "advanced_monitor_down_lrd", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownLD( "advanced_monitor_down_ld", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownRUD( "advanced_monitor_down_rud", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownLRUD( "advanced_monitor_down_lrud", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownLUD( "advanced_monitor_down_lud", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownRU( "advanced_monitor_down_ru", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownLRU( "advanced_monitor_down_lru", PeripheralType.AdvancedMonitor ), - AdvancedMonitorDownLU( "advanced_monitor_down_lu", PeripheralType.AdvancedMonitor ), - Speaker( "speaker", PeripheralType.Speaker ); - - private final String name; - private final PeripheralType peripheralType; - - BlockPeripheralVariant( String name, PeripheralType peripheralType ) - { - this.name = name; - this.peripheralType = peripheralType; - } - - @Nonnull - @Override - public String getName() - { - return name; - } - - public PeripheralType getPeripheralType() - { - return peripheralType; - } - - @Override - public String toString() - { - return name; - } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/IPeripheralItem.java b/src/main/java/dan200/computercraft/shared/peripheral/common/IPeripheralItem.java deleted file mode 100644 index 9e53c865a..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/IPeripheralItem.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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.shared.peripheral.common; - -import dan200.computercraft.shared.peripheral.PeripheralType; -import net.minecraft.item.ItemStack; - -import javax.annotation.Nonnull; - -public interface IPeripheralItem -{ - PeripheralType getPeripheralType( @Nonnull ItemStack stack ); -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/IPeripheralTile.java b/src/main/java/dan200/computercraft/shared/peripheral/common/IPeripheralTile.java deleted file mode 100644 index 119dd171a..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/IPeripheralTile.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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.shared.peripheral.common; - -@Deprecated -public interface IPeripheralTile extends dan200.computercraft.api.peripheral.IPeripheralTile -{ -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/ITilePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/common/ITilePeripheral.java deleted file mode 100644 index e256eb06c..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/ITilePeripheral.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.shared.peripheral.common; - -import dan200.computercraft.shared.peripheral.PeripheralType; - -/** - * The tile for {@link BlockPeripheral}. - */ -public interface ITilePeripheral -{ - PeripheralType getPeripheralType(); - - default String getLabel() - { - return null; - } - - default void setLabel( String label ) - { - } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheral.java deleted file mode 100644 index 753c09ca3..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheral.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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.shared.peripheral.common; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.integration.mcmp.MCMPHooks; -import dan200.computercraft.shared.peripheral.PeripheralType; -import net.minecraft.block.Block; -import net.minecraft.creativetab.CreativeTabs; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumActionResult; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; -import net.minecraft.util.NonNullList; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -import javax.annotation.Nonnull; - -public class ItemPeripheral extends ItemPeripheralBase -{ - public ItemPeripheral( Block block ) - { - super( block ); - setTranslationKey( "computercraft:peripheral" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - setHasSubtypes( true ); - } - - @Nonnull - public ItemStack create( PeripheralType type, String label, int quantity ) - { - ItemStack stack; - switch( type ) - { - case DiskDrive: - stack = new ItemStack( this, quantity, 0 ); - break; - case WirelessModem: - stack = new ItemStack( this, quantity, 1 ); - break; - case Monitor: - stack = new ItemStack( this, quantity, 2 ); - break; - case Printer: - stack = new ItemStack( this, quantity, 3 ); - break; - case AdvancedMonitor: - stack = new ItemStack( this, quantity, 4 ); - break; - case Speaker: - stack = new ItemStack( this, quantity, 5 ); - break; - - default: - // Ignore types we can't handle - return ItemStack.EMPTY; - } - if( label != null ) - { - stack.setStackDisplayName( label ); - } - return stack; - } - - @Override - public void getSubItems( @Nonnull CreativeTabs tabs, @Nonnull NonNullList list ) - { - if( !isInCreativeTab( tabs ) ) return; - list.add( PeripheralItemFactory.create( PeripheralType.DiskDrive, null, 1 ) ); - list.add( PeripheralItemFactory.create( PeripheralType.Printer, null, 1 ) ); - list.add( PeripheralItemFactory.create( PeripheralType.Monitor, null, 1 ) ); - list.add( PeripheralItemFactory.create( PeripheralType.AdvancedMonitor, null, 1 ) ); - list.add( PeripheralItemFactory.create( PeripheralType.WirelessModem, null, 1 ) ); - list.add( PeripheralItemFactory.create( PeripheralType.Speaker, null, 1 ) ); - } - - @Override - public PeripheralType getPeripheralType( int damage ) - { - switch( damage ) - { - case 0: - default: - return PeripheralType.DiskDrive; - case 1: - return PeripheralType.WirelessModem; - case 2: - return PeripheralType.Monitor; - case 3: - return PeripheralType.Printer; - case 4: - return PeripheralType.AdvancedMonitor; - case 5: - return PeripheralType.Speaker; - } - } - - @Nonnull - @Override - public EnumActionResult onItemUse( EntityPlayer player, World world, @Nonnull BlockPos pos, @Nonnull EnumHand hand, @Nonnull EnumFacing facing, float hitX, float hitY, float hitZ ) - { - if( getPeripheralType( player.getHeldItem( hand ) ) == PeripheralType.WirelessModem ) - { - EnumActionResult result = MCMPHooks.onItemUse( this, player, world, pos, hand, facing, hitX, hitY, hitZ ); - if( result != EnumActionResult.PASS ) return result; - } - - return super.onItemUse( player, world, pos, hand, facing, hitX, hitY, hitZ ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheralBase.java b/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheralBase.java deleted file mode 100644 index 35b0fe8b0..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheralBase.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.shared.peripheral.common; - -import dan200.computercraft.shared.peripheral.PeripheralType; -import net.minecraft.block.Block; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemBlock; -import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -import javax.annotation.Nonnull; - -public abstract class ItemPeripheralBase extends ItemBlock implements IPeripheralItem -{ - protected ItemPeripheralBase( Block block ) - { - super( block ); - setMaxStackSize( 64 ); - } - - public abstract PeripheralType getPeripheralType( int damage ); - - @Override - public final int getMetadata( int damage ) - { - return damage; - } - - @Override - public boolean canPlaceBlockOnSide( World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side, EntityPlayer player, @Nonnull ItemStack stack ) // canPlaceItemBlockOnSide - { - PeripheralType type = getPeripheralType( stack ); - switch( type ) - { - case WirelessModem: - case WiredModem: - case AdvancedModem: - return world.isSideSolid( pos, side ); - case Cable: - return true; - default: - return super.canPlaceBlockOnSide( world, pos, side, player, stack ); - } - } - - @Nonnull - @Override - public String getTranslationKey( @Nonnull ItemStack stack ) - { - PeripheralType type = getPeripheralType( stack ); - switch( type ) - { - case DiskDrive: - default: - return "tile.computercraft:drive"; - case Printer: - return "tile.computercraft:printer"; - case Monitor: - return "tile.computercraft:monitor"; - case AdvancedMonitor: - return "tile.computercraft:advanced_monitor"; - case WirelessModem: - return "tile.computercraft:wireless_modem"; - case WiredModem: - case WiredModemWithCable: - return "tile.computercraft:wired_modem"; - case Cable: - return "tile.computercraft:cable"; - case AdvancedModem: - return "tile.computercraft:advanced_modem"; - case Speaker: - return "tile.computercraft:speaker"; - case WiredModemFull: - return "tile.computercraft:wired_modem"; - } - } - - @Override - public final PeripheralType getPeripheralType( @Nonnull ItemStack stack ) - { - return getPeripheralType( stack.getItemDamage() ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/PeripheralItemFactory.java b/src/main/java/dan200/computercraft/shared/peripheral/common/PeripheralItemFactory.java deleted file mode 100644 index aff6de8a4..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/PeripheralItemFactory.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.shared.peripheral.common; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.peripheral.PeripheralType; -import net.minecraft.item.ItemStack; - -import javax.annotation.Nonnull; - -public final class PeripheralItemFactory -{ - private PeripheralItemFactory() {} - - @Nonnull - public static ItemStack create( ITilePeripheral tile ) - { - return create( tile.getPeripheralType(), tile.getLabel(), 1 ); - } - - @Nonnull - public static ItemStack create( PeripheralType type, String label, int quantity ) - { - switch( type ) - { - case Speaker: - case DiskDrive: - case Printer: - case Monitor: - case AdvancedMonitor: - case WirelessModem: - return ComputerCraft.Items.peripheral.create( type, label, quantity ); - case WiredModem: - case Cable: - return ComputerCraft.Items.cable.create( type, quantity ); - case AdvancedModem: - return new ItemStack( ComputerCraft.Blocks.advancedModem, quantity ); - case WiredModemFull: - return new ItemStack( ComputerCraft.Blocks.wiredModemFull, quantity ); - } - return ItemStack.EMPTY; - } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/TilePeripheralBase.java b/src/main/java/dan200/computercraft/shared/peripheral/common/TilePeripheralBase.java deleted file mode 100644 index 35a6e1b2b..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/TilePeripheralBase.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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.shared.peripheral.common; - -import dan200.computercraft.api.peripheral.IPeripheralTile; -import dan200.computercraft.shared.common.IDirectionalTile; -import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.peripheral.PeripheralType; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.ITickable; - -import javax.annotation.Nonnull; - -public abstract class TilePeripheralBase extends TileGeneric implements IPeripheralTile, ITickable, IDirectionalTile, ITilePeripheral -{ - private EnumFacing m_dir; - private int m_anim; - private boolean m_changed; - - private String m_label; - - public TilePeripheralBase() - { - m_dir = EnumFacing.NORTH; - m_anim = 0; - m_changed = false; - - m_label = null; - } - - - @Override - public BlockPeripheral getBlock() - { - return (BlockPeripheral) super.getBlock(); - } - - @Override - public final PeripheralType getPeripheralType() - { - return BlockPeripheral.getPeripheralType( getBlockState() ); - } - - @Override - public String getLabel() - { - if( m_label != null && !m_label.isEmpty() ) - { - return m_label; - } - return null; - } - - @Override - public void setLabel( String label ) - { - m_label = label; - } - - // IDirectionalTile implementation - - @Override - public EnumFacing getDirection() - { - return m_dir; - } - - @Override - public void setDirection( EnumFacing dir ) - { - if( dir != m_dir ) - { - m_dir = dir; - m_changed = true; - } - } - - public int getAnim() - { - return m_anim; - } - - protected void setAnim( int anim ) - { - if( anim != m_anim ) - { - m_anim = anim; - m_changed = true; - } - } - - @Override - public void update() - { - if( m_changed ) - { - m_changed = false; - updateBlock(); - } - } - - @Override - public void readFromNBT( NBTTagCompound nbt ) - { - // Read properties - super.readFromNBT( nbt ); - if( nbt.hasKey( "dir" ) ) - { - m_dir = EnumFacing.byIndex( nbt.getInteger( "dir" ) ); - } - if( nbt.hasKey( "anim" ) ) - { - m_anim = nbt.getInteger( "anim" ); - } - if( nbt.hasKey( "label" ) ) - { - m_label = nbt.getString( "label" ); - } - } - - @Nonnull - @Override - public NBTTagCompound writeToNBT( NBTTagCompound nbt ) - { - // Write properties - nbt.setInteger( "dir", m_dir.getIndex() ); - nbt.setInteger( "anim", m_anim ); - if( m_label != null ) nbt.setString( "label", m_label ); - return super.writeToNBT( nbt ); - } - - @Override - protected void readDescription( @Nonnull NBTTagCompound nbt ) - { - super.readDescription( nbt ); - m_dir = EnumFacing.byIndex( nbt.getInteger( "dir" ) ); - m_anim = nbt.getInteger( "anim" ); - m_label = nbt.hasKey( "label" ) ? nbt.getString( "label" ) : null; - } - - @Override - protected void writeDescription( @Nonnull NBTTagCompound nbt ) - { - super.writeDescription( nbt ); - nbt.setInteger( "dir", m_dir.getIndex() ); - nbt.setInteger( "anim", m_anim ); - if( m_label != null ) nbt.setString( "label", m_label ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java new file mode 100644 index 000000000..98d893683 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java @@ -0,0 +1,84 @@ +/* + * 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.shared.peripheral.diskdrive; + +import dan200.computercraft.shared.common.BlockGeneric; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.item.ItemStack; +import net.minecraft.state.DirectionProperty; +import net.minecraft.state.EnumProperty; +import net.minecraft.state.StateContainer; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.stats.StatList; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.INameable; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class BlockDiskDrive extends BlockGeneric +{ + static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; + static final EnumProperty STATE = EnumProperty.create( "state", DiskDriveState.class ); + + public BlockDiskDrive( Properties settings ) + { + super( settings, TileDiskDrive.FACTORY ); + setDefaultState( getStateContainer().getBaseState() + .with( FACING, EnumFacing.NORTH ) + .with( STATE, DiskDriveState.EMPTY ) ); + } + + + @Override + protected void fillStateContainer( StateContainer.Builder properties ) + { + properties.add( FACING, STATE ); + } + + @Nullable + @Override + public IBlockState getStateForPlacement( BlockItemUseContext placement ) + { + return getDefaultState().with( FACING, placement.getPlacementHorizontalFacing().getOpposite() ); + } + + @Override + public void harvestBlock( @Nonnull World world, EntityPlayer player, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nullable TileEntity te, ItemStack stack ) + { + if( te instanceof INameable && ((INameable) te).hasCustomName() ) + { + player.addStat( StatList.BLOCK_MINED.get( this ) ); + player.addExhaustion( 0.005F ); + + ItemStack result = new ItemStack( this ); + result.setDisplayName( ((INameable) te).getCustomName() ); + spawnAsEntity( world, pos, result ); + } + else + { + super.harvestBlock( world, player, pos, state, te, stack ); + } + } + + @Override + public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack ) + { + if( stack.hasDisplayName() ) + { + TileEntity tileentity = world.getTileEntity( pos ); + if( tileentity instanceof TileDiskDrive ) ((TileDiskDrive) tileentity).customName = stack.getDisplayName(); + } + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java index 06930188a..bde384e18 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java @@ -21,19 +21,19 @@ public class ContainerDiskDrive extends Container public ContainerDiskDrive( IInventory playerInventory, TileDiskDrive diskDrive ) { m_diskDrive = diskDrive; - addSlotToContainer( new Slot( m_diskDrive, 0, 8 + 4 * 18, 35 ) ); + addSlot( new Slot( m_diskDrive, 0, 8 + 4 * 18, 35 ) ); for( int y = 0; y < 3; y++ ) { for( int x = 0; x < 9; x++ ) { - addSlotToContainer( new Slot( playerInventory, x + y * 9 + 9, 8 + x * 18, 84 + y * 18 ) ); + addSlot( new Slot( playerInventory, x + y * 9 + 9, 8 + x * 18, 84 + y * 18 ) ); } } for( int x = 0; x < 9; x++ ) { - addSlotToContainer( new Slot( playerInventory, x, 8 + x * 18, 142 ) ); + addSlot( new Slot( playerInventory, x, 8 + x * 18, 142 ) ); } } @@ -55,7 +55,7 @@ public ItemStack transferStackInSlot( EntityPlayer player, int slotIndex ) Slot slot = inventorySlots.get( slotIndex ); if( slot == null || !slot.getHasStack() ) return ItemStack.EMPTY; - ItemStack existing = slot.getStack().copy(); + ItemStack existing = slot.getStack(); ItemStack result = existing.copy(); if( slotIndex == 0 ) { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java index f15dcaf44..1623a1548 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java @@ -11,9 +11,8 @@ import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.shared.media.items.ItemDiskLegacy; +import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.util.StringUtil; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import javax.annotation.Nonnull; @@ -108,8 +107,7 @@ public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaCont case 10: // getDiskID { ItemStack disk = m_diskDrive.getDiskStack(); - Item item = disk.getItem(); - return item instanceof ItemDiskLegacy ? new Object[] { ((ItemDiskLegacy) item).getDiskID( disk ) } : null; + return disk.getItem() instanceof ItemDisk ? new Object[] { ItemDisk.getDiskID( disk ) } : null; } default: return null; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java new file mode 100644 index 000000000..d15dd010d --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java @@ -0,0 +1,32 @@ +/* + * 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.shared.peripheral.diskdrive; + +import net.minecraft.util.IStringSerializable; + +import javax.annotation.Nonnull; + +public enum DiskDriveState implements IStringSerializable +{ + EMPTY( "empty" ), + FULL( "full" ), + INVALID( "invalid" ); + + private final String name; + + DiskDriveState( String name ) + { + this.name = name; + } + + @Override + @Nonnull + public String getName() + { + return name; + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index 83c0b35a0..313a26d11 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -6,33 +6,30 @@ package dan200.computercraft.shared.peripheral.diskdrive; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.MediaProviders; +import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.network.Containers; -import dan200.computercraft.shared.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.common.BlockPeripheral; -import dan200.computercraft.shared.peripheral.common.TilePeripheralBase; import dan200.computercraft.shared.util.DefaultInventory; import dan200.computercraft.shared.util.InventoryUtil; +import dan200.computercraft.shared.util.NamedBlockEntityType; import dan200.computercraft.shared.util.RecordUtil; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; -import net.minecraft.util.SoundEvent; +import net.minecraft.util.*; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextComponentTranslation; -import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.InvWrapper; @@ -44,18 +41,28 @@ import static net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; -public class TileDiskDrive extends TilePeripheralBase implements DefaultInventory +public final class TileDiskDrive extends TileGeneric implements DefaultInventory, ITickable, IPeripheralTile { + private static final String NBT_NAME = "CustomName"; + private static final String NBT_ITEM = "Item"; + + public static final NamedBlockEntityType FACTORY = NamedBlockEntityType.create( + new ResourceLocation( ComputerCraft.MOD_ID, "disk_drive" ), + TileDiskDrive::new + ); + private static class MountInfo { String mountPath; } + ITextComponent customName; + private final Map m_computers = new HashMap<>(); @Nonnull private ItemStack m_diskStack = ItemStack.EMPTY; - private final IItemHandlerModifiable m_itemHandler = new InvWrapper( this ); + private final LazyOptional m_itemCap = LazyOptional.of( () -> new InvWrapper( this ) ); private IMount m_diskMount = null; private boolean m_recordQueued = false; @@ -63,14 +70,16 @@ private static class MountInfo private boolean m_restartRecord = false; private boolean m_ejectQueued; + private TileDiskDrive() + { + super( FACTORY ); + } + @Override public void destroy() { ejectContents( true ); - if( m_recordPlaying ) - { - stopRecord(); - } + if( m_recordPlaying ) stopRecord(); } @Override @@ -96,49 +105,42 @@ public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, } } - @Override public EnumFacing getDirection() { - return getBlockState().getValue( BlockPeripheral.FACING ); + return getBlockState().get( BlockDiskDrive.FACING ); } @Override - public void setDirection( EnumFacing dir ) + public void read( NBTTagCompound nbt ) { - if( dir.getAxis() == EnumFacing.Axis.Y ) dir = EnumFacing.NORTH; - setBlockState( getBlockState().withProperty( BlockPeripheral.FACING, dir ) ); - } - - @Override - public void readFromNBT( NBTTagCompound nbt ) - { - super.readFromNBT( nbt ); - if( nbt.hasKey( "item" ) ) + super.read( nbt ); + customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; + if( nbt.contains( NBT_ITEM ) ) { - NBTTagCompound item = nbt.getCompoundTag( "item" ); - m_diskStack = new ItemStack( item ); + NBTTagCompound item = nbt.getCompound( NBT_ITEM ); + m_diskStack = ItemStack.read( item ); m_diskMount = null; } } @Nonnull @Override - public NBTTagCompound writeToNBT( NBTTagCompound nbt ) + public NBTTagCompound write( NBTTagCompound nbt ) { + if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) ); + if( !m_diskStack.isEmpty() ) { NBTTagCompound item = new NBTTagCompound(); - m_diskStack.writeToNBT( item ); - nbt.setTag( "item", item ); + m_diskStack.write( item ); + nbt.put( NBT_ITEM, item ); } - return super.writeToNBT( nbt ); + return super.write( nbt ); } @Override - public void update() + public void tick() { - super.update(); - // Ejection if( m_ejectQueued ) { @@ -220,7 +222,7 @@ public ItemStack decrStackSize( int slot, int count ) return disk; } - ItemStack part = m_diskStack.splitStack( count ); + ItemStack part = m_diskStack.split( count ); setInventorySlotContents( slot, m_diskStack.isEmpty() ? ItemStack.EMPTY : m_diskStack ); return part; } @@ -247,6 +249,7 @@ public void setInventorySlotContents( int slot, @Nonnull ItemStack stack ) // Unmount old disk if( !m_diskStack.isEmpty() ) { + // TODO: Is this iteration thread safe? Set computers = m_computers.keySet(); for( IComputerAccess computer : computers ) unmountDisk( computer ); } @@ -264,9 +267,6 @@ public void setInventorySlotContents( int slot, @Nonnull ItemStack stack ) m_diskMount = null; markDirty(); - // Update contents - updateAnim(); - // Mount new disk if( !m_diskStack.isEmpty() ) { @@ -277,24 +277,10 @@ public void setInventorySlotContents( int slot, @Nonnull ItemStack stack ) } @Override - public boolean hasCustomName() + public void markDirty() { - return getLabel() != null; - } - - @Nonnull - @Override - public String getName() - { - String label = getLabel(); - return label != null ? label : "tile.computercraft:drive.name"; - } - - @Nonnull - @Override - public ITextComponent getDisplayName() - { - return hasCustomName() ? new TextComponentString( getName() ) : new TextComponentTranslation( getName() ); + if( !world.isRemote ) updateBlockState(); + super.markDirty(); } @Override @@ -309,8 +295,6 @@ public void clear() setInventorySlotContents( 0, ItemStack.EMPTY ); } - // IPeripheralTile implementation - @Override public IPeripheral getPeripheral( @Nonnull EnumFacing side ) { @@ -455,19 +439,29 @@ private synchronized void unmountDisk( IComputerAccess computer ) } } - private void updateAnim() + private void updateBlockState() { + if( removed ) return; + if( !m_diskStack.isEmpty() ) { IMedia contents = getDiskMedia(); - setAnim( contents != null ? 2 : 1 ); + updateBlockState( contents != null ? DiskDriveState.FULL : DiskDriveState.INVALID ); } else { - setAnim( 0 ); + updateBlockState( DiskDriveState.EMPTY ); } } + private void updateBlockState( DiskDriveState state ) + { + IBlockState blockState = getBlockState(); + if( blockState.get( BlockDiskDrive.STATE ) == state ) return; + + getWorld().setBlockState( getPos(), blockState.with( BlockDiskDrive.STATE, state ) ); + } + private synchronized void ejectContents( boolean destroyed ) { if( getWorld().isRemote || m_diskStack.isEmpty() ) return; @@ -500,10 +494,11 @@ private synchronized void ejectContents( boolean destroyed ) } @Override - protected final void readDescription( @Nonnull NBTTagCompound nbt ) + protected void readDescription( @Nonnull NBTTagCompound nbt ) { super.readDescription( nbt ); - m_diskStack = nbt.hasKey( "item" ) ? new ItemStack( nbt.getCompoundTag( "item" ) ) : ItemStack.EMPTY; + customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; + m_diskStack = nbt.contains( NBT_ITEM ) ? ItemStack.read( nbt.getCompound( NBT_ITEM ) ) : ItemStack.EMPTY; updateBlock(); } @@ -511,20 +506,15 @@ protected final void readDescription( @Nonnull NBTTagCompound nbt ) protected void writeDescription( @Nonnull NBTTagCompound nbt ) { super.writeDescription( nbt ); + if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) ); if( !m_diskStack.isEmpty() ) { NBTTagCompound item = new NBTTagCompound(); - m_diskStack.writeToNBT( item ); - nbt.setTag( "item", item ); + m_diskStack.write( item ); + nbt.put( NBT_ITEM, item ); } } - @Override - public boolean shouldRefresh( World world, BlockPos pos, @Nonnull IBlockState oldState, @Nonnull IBlockState newState ) - { - return super.shouldRefresh( world, pos, oldState, newState ) || BlockPeripheral.getPeripheralType( newState ) != PeripheralType.DiskDrive; - } - // Private methods private void playRecord() @@ -546,20 +536,31 @@ private void stopRecord() RecordUtil.playRecord( null, null, getWorld(), getPos() ); } + @Nonnull @Override - public boolean hasCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + public LazyOptional getCapability( @Nonnull Capability cap, @Nullable final EnumFacing side ) { - return capability == ITEM_HANDLER_CAPABILITY || super.hasCapability( capability, facing ); + if( cap == ITEM_HANDLER_CAPABILITY ) return m_itemCap.cast(); + return super.getCapability( cap, side ); + } + + @Override + public boolean hasCustomName() + { + return customName != null; } @Nullable @Override - public T getCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + public ITextComponent getCustomName() { - if( capability == ITEM_HANDLER_CAPABILITY ) - { - return ITEM_HANDLER_CAPABILITY.cast( m_itemHandler ); - } - return super.getCapability( capability, facing ); + return customName; + } + + @Nonnull + @Override + public ITextComponent getName() + { + return customName != null ? customName : getBlockState().getBlock().getNameTextComponent(); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemBounds.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemBounds.java deleted file mode 100644 index 4770d2f69..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemBounds.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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.shared.peripheral.modem; - -import net.minecraft.block.Block; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.AxisAlignedBB; - -import javax.annotation.Nonnull; - -public final class ModemBounds -{ - private static final AxisAlignedBB[] BOXES = new AxisAlignedBB[] { - new AxisAlignedBB( 0.125, 0.0, 0.125, 0.875, 0.1875, 0.875 ), // Down - new AxisAlignedBB( 0.125, 0.8125, 0.125, 0.875, 1.0, 0.875 ), // Up - new AxisAlignedBB( 0.125, 0.125, 0.0, 0.875, 0.875, 0.1875 ), // North - new AxisAlignedBB( 0.125, 0.125, 0.8125, 0.875, 0.875, 1.0 ), // South - new AxisAlignedBB( 0.0, 0.125, 0.125, 0.1875, 0.875, 0.875 ), // West - new AxisAlignedBB( 0.8125, 0.125, 0.125, 1.0, 0.875, 0.875 ), // East - }; - - private ModemBounds() {} - - @Nonnull - public static AxisAlignedBB getBounds( EnumFacing facing ) - { - int direction = facing.ordinal(); - return direction < BOXES.length ? BOXES[direction] : Block.FULL_BLOCK_AABB; - } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java index 1f920432c..0c9f6453a 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java @@ -39,20 +39,6 @@ public ModemState getModemState() return m_state; } - @Deprecated - public boolean pollChanged() - { - // Only for backwards compatibility - return m_state.pollChanged(); - } - - @Deprecated - public boolean isActive() - { - // Only for backwards compatibility - return m_state.isOpen(); - } - private synchronized void setNetwork( IPacketNetwork network ) { if( m_network == network ) return; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java new file mode 100644 index 000000000..697ab044c --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java @@ -0,0 +1,32 @@ +/* + * 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.shared.peripheral.modem; + +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.util.math.shapes.VoxelShapes; + +import javax.annotation.Nonnull; + +public final class ModemShapes +{ + private static final VoxelShape[] BOXES = new VoxelShape[] { + VoxelShapes.create( 0.125, 0.0, 0.125, 0.875, 0.1875, 0.875 ), // Down + VoxelShapes.create( 0.125, 0.8125, 0.125, 0.875, 1.0, 0.875 ), // Up + VoxelShapes.create( 0.125, 0.125, 0.0, 0.875, 0.875, 0.1875 ), // North + VoxelShapes.create( 0.125, 0.125, 0.8125, 0.875, 0.875, 1.0 ), // South + VoxelShapes.create( 0.0, 0.125, 0.125, 0.1875, 0.875, 0.875 ), // West + VoxelShapes.create( 0.8125, 0.125, 0.125, 1.0, 0.875, 0.875 ), // East + }; + + @Nonnull + public static VoxelShape getBounds( EnumFacing facing ) + { + int direction = facing.ordinal(); + return direction < BOXES.length ? BOXES[direction] : VoxelShapes.fullCube(); + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java deleted file mode 100644 index 6ec0ada76..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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.shared.peripheral.modem; - -/** - * This only exists for backwards compatibility - */ -public abstract class WirelessModemPeripheral extends dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral -{ - @Deprecated - public WirelessModemPeripheral( boolean advanced ) - { - super( new ModemState(), advanced ); - } -} 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 8c4ad3fd4..e39c96167 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 @@ -10,287 +10,99 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.shared.common.BlockGeneric; -import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory; +import dan200.computercraft.shared.util.WaterloggableBlock; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.block.Block; -import net.minecraft.block.material.Material; -import net.minecraft.block.properties.PropertyBool; -import net.minecraft.block.properties.PropertyEnum; import net.minecraft.block.state.BlockFaceShape; -import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.fluid.IFluidState; +import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; +import net.minecraft.state.BooleanProperty; +import net.minecraft.state.EnumProperty; +import net.minecraft.state.StateContainer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.NonNullList; -import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.IBlockAccess; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorld; +import net.minecraft.world.IWorldReaderBase; import net.minecraft.world.World; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.ArrayList; import java.util.EnumMap; -import java.util.List; -public class BlockCable extends BlockGeneric +public class BlockCable extends BlockGeneric implements WaterloggableBlock { - public static final PropertyEnum MODEM = PropertyEnum.create( "modem", BlockCableModemVariant.class ); - static final PropertyBool CABLE = PropertyBool.create( "cable" ); - static final PropertyBool NORTH = PropertyBool.create( "north" ); - static final PropertyBool SOUTH = PropertyBool.create( "south" ); - static final PropertyBool EAST = PropertyBool.create( "east" ); - static final PropertyBool WEST = PropertyBool.create( "west" ); - static final PropertyBool UP = PropertyBool.create( "up" ); - static final PropertyBool DOWN = PropertyBool.create( "down" ); - static final EnumMap CONNECTIONS = - new EnumMap<>( new ImmutableMap.Builder() + public static final EnumProperty MODEM = EnumProperty.create( "modem", CableModemVariant.class ); + public static final BooleanProperty CABLE = BooleanProperty.create( "cable" ); + + private static final BooleanProperty NORTH = BooleanProperty.create( "north" ); + private static final BooleanProperty SOUTH = BooleanProperty.create( "south" ); + private static final BooleanProperty EAST = BooleanProperty.create( "east" ); + private static final BooleanProperty WEST = BooleanProperty.create( "west" ); + private static final BooleanProperty UP = BooleanProperty.create( "up" ); + private static final BooleanProperty DOWN = BooleanProperty.create( "down" ); + + static final EnumMap CONNECTIONS = + new EnumMap<>( new ImmutableMap.Builder() .put( EnumFacing.DOWN, DOWN ).put( EnumFacing.UP, UP ) .put( EnumFacing.NORTH, NORTH ).put( EnumFacing.SOUTH, SOUTH ) .put( EnumFacing.WEST, WEST ).put( EnumFacing.EAST, EAST ) .build() ); - public BlockCable() + public BlockCable( Properties settings ) { - super( Material.ROCK ); - setHardness( 1.5f ); - setTranslationKey( "computercraft:cable" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - setDefaultState( blockState.getBaseState() - .withProperty( MODEM, BlockCableModemVariant.None ) - .withProperty( CABLE, false ) - .withProperty( NORTH, false ) - .withProperty( SOUTH, false ) - .withProperty( EAST, false ) - .withProperty( WEST, false ) - .withProperty( UP, false ) - .withProperty( DOWN, false ) + super( settings, TileCable.FACTORY ); + + setDefaultState( getStateContainer().getBaseState() + .with( MODEM, CableModemVariant.None ) + .with( CABLE, false ) + .with( NORTH, false ).with( SOUTH, false ) + .with( EAST, false ).with( WEST, false ) + .with( UP, false ).with( DOWN, false ) + .with( WATERLOGGED, false ) ); } - @Nonnull @Override - protected BlockStateContainer createBlockState() + protected void fillStateContainer( StateContainer.Builder builder ) { - return new BlockStateContainer( this, - MODEM, - CABLE, - NORTH, - SOUTH, - EAST, - WEST, - UP, - DOWN - ); - } - - @Nonnull - @Override - @Deprecated - public IBlockState getStateFromMeta( int meta ) - { - IBlockState state = getDefaultState(); - if( meta < 6 ) - { - state = state.withProperty( CABLE, false ); - state = state.withProperty( MODEM, BlockCableModemVariant.from( EnumFacing.byIndex( meta ) ) ); - } - else if( meta < 12 ) - { - state = state.withProperty( CABLE, true ); - state = state.withProperty( MODEM, BlockCableModemVariant.from( EnumFacing.byIndex( meta - 6 ) ) ); - } - else if( meta == 13 ) - { - state = state.withProperty( CABLE, true ); - state = state.withProperty( MODEM, BlockCableModemVariant.None ); - } - return state; - } - - @Override - public int getMetaFromState( IBlockState state ) - { - int meta = 0; - boolean cable = state.getValue( CABLE ); - BlockCableModemVariant modem = state.getValue( MODEM ); - if( cable && modem != BlockCableModemVariant.None ) - { - meta = 6 + modem.getFacing().getIndex(); - } - else if( modem != BlockCableModemVariant.None ) - { - meta = modem.getFacing().getIndex(); - } - else if( cable ) - { - meta = 13; - } - return meta; - } - - - @Override - @Deprecated - public final IBlockState getStateForPlacement( World world, BlockPos pos, EnumFacing placedSide, float hitX, float hitY, float hitZ, int damage, EntityLivingBase placer ) - { - switch( ComputerCraft.Items.cable.getPeripheralType( damage ) ) - { - case Cable: - return getDefaultState() - .withProperty( CABLE, true ) - .withProperty( MODEM, BlockCableModemVariant.None ); - default: - case WiredModem: - return getDefaultState() - .withProperty( CABLE, false ) - .withProperty( MODEM, BlockCableModemVariant.from( placedSide.getOpposite() ) ); - case WiredModemWithCable: - return getDefaultState() - .withProperty( CABLE, true ) - .withProperty( MODEM, BlockCableModemVariant.from( placedSide.getOpposite() ) ); - } + builder.add( MODEM, CABLE, NORTH, SOUTH, EAST, WEST, UP, DOWN, WATERLOGGED ); } public static boolean canConnectIn( IBlockState state, EnumFacing direction ) { - return state.getValue( CABLE ) - && state.getValue( MODEM ).getFacing() != direction; + return state.get( BlockCable.CABLE ) && state.get( BlockCable.MODEM ).getFacing() != direction; } - public static boolean doesConnectVisually( IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing direction ) + public static boolean doesConnectVisually( IBlockState state, IBlockReader world, BlockPos pos, EnumFacing direction ) { - if( !state.getValue( CABLE ) ) return false; - if( state.getValue( MODEM ).getFacing() == direction ) return true; + if( !state.get( CABLE ) ) return false; + if( state.get( MODEM ).getFacing() == direction ) return true; return ComputerCraftAPI.getWiredElementAt( world, pos.offset( direction ), direction.getOpposite() ) != null; } @Nonnull @Override @Deprecated - public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos ) + public VoxelShape getShape( IBlockState state, IBlockReader world, BlockPos pos ) { - state = state - .withProperty( NORTH, doesConnectVisually( state, world, pos, EnumFacing.NORTH ) ) - .withProperty( SOUTH, doesConnectVisually( state, world, pos, EnumFacing.SOUTH ) ) - .withProperty( EAST, doesConnectVisually( state, world, pos, EnumFacing.EAST ) ) - .withProperty( WEST, doesConnectVisually( state, world, pos, EnumFacing.WEST ) ) - .withProperty( UP, doesConnectVisually( state, world, pos, EnumFacing.UP ) ) - .withProperty( DOWN, doesConnectVisually( state, world, pos, EnumFacing.DOWN ) ); - - TileEntity tile = world.getTileEntity( pos ); - int anim = tile instanceof TileCable ? ((TileCable) tile).getState() : 0; - - BlockCableModemVariant modem = state.getValue( MODEM ); - if( modem != BlockCableModemVariant.None ) modem = BlockCableModemVariant.from( modem.getFacing(), anim ); - state = state.withProperty( MODEM, modem ); - - return state; + return CableShapes.getShape( state ); } @Override - @Deprecated - public boolean shouldSideBeRendered( IBlockState state, @Nonnull IBlockAccess world, @Nonnull BlockPos pos, EnumFacing side ) + public boolean removedByPlayer( IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest, IFluidState fluid ) { - return true; - } - - public static PeripheralType getPeripheralType( IBlockState state ) - { - boolean cable = state.getValue( CABLE ); - BlockCableModemVariant modem = state.getValue( MODEM ); - if( cable && modem != BlockCableModemVariant.None ) + if( state.get( CABLE ) && state.get( MODEM ).getFacing() != null ) { - return PeripheralType.WiredModemWithCable; - } - else if( modem != BlockCableModemVariant.None ) - { - return PeripheralType.WiredModem; - } - else - { - return PeripheralType.Cable; - } - } - - @Override - protected TileGeneric createTile( IBlockState state ) - { - return new TileCable(); - } - - @Override - protected TileGeneric createTile( int damage ) - { - return new TileCable(); - } - - @Nonnull - @Override - @Deprecated - public AxisAlignedBB getBoundingBox( IBlockState state, IBlockAccess source, BlockPos pos ) - { - return CableBounds.getBounds( state.getActualState( source, pos ) ); - } - - @Override - @Deprecated - public void addCollisionBoxToList( IBlockState state, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull AxisAlignedBB bigBox, @Nonnull List list, Entity entity, boolean isActualState ) - { - if( !isActualState ) state = state.getActualState( world, pos ); - - // Get collision bounds - List collision = new ArrayList<>( 1 ); - CableBounds.getBounds( state, collision ); - for( AxisAlignedBB localBounds : collision ) addCollisionBoxToList( pos, bigBox, list, localBounds ); - } - - @Nullable - @Override - @Deprecated - public RayTraceResult collisionRayTrace( IBlockState state, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Vec3d start, @Nonnull Vec3d end ) - { - double distance = Double.POSITIVE_INFINITY; - RayTraceResult result = null; - - List bounds = new ArrayList<>( 7 ); - CableBounds.getBounds( state.getActualState( world, pos ), bounds ); - - Vec3d startOff = start.subtract( pos.getX(), pos.getY(), pos.getZ() ); - Vec3d endOff = end.subtract( pos.getX(), pos.getY(), pos.getZ() ); - - for( AxisAlignedBB bb : bounds ) - { - RayTraceResult hit = bb.calculateIntercept( startOff, endOff ); - if( hit != null ) - { - double newDistance = hit.hitVec.squareDistanceTo( startOff ); - if( newDistance <= distance ) - { - distance = newDistance; - result = hit; - } - } - } - - return result == null ? null : new RayTraceResult( result.hitVec.add( pos.getX(), pos.getY(), pos.getZ() ), result.sideHit, pos ); - } - - @Override - public boolean removedByPlayer( @Nonnull IBlockState state, World world, @Nonnull BlockPos pos, @Nonnull EntityPlayer player, boolean willHarvest ) - { - PeripheralType type = getPeripheralType( state ); - if( type == PeripheralType.WiredModemWithCable ) - { - RayTraceResult hit = state.collisionRayTrace( world, pos, WorldUtil.getRayStart( player ), WorldUtil.getRayEnd( player ) ); + RayTraceResult hit = Block.collisionRayTrace( state, world, pos, WorldUtil.getRayStart( player ), WorldUtil.getRayEnd( player ) ); if( hit != null ) { TileEntity tile = world.getTileEntity( pos ); @@ -301,23 +113,23 @@ public boolean removedByPlayer( @Nonnull IBlockState state, World world, @Nonnul ItemStack item; IBlockState newState; - AxisAlignedBB bb = CableBounds.getModemBounds( state ); - if( WorldUtil.isVecInsideInclusive( bb, hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ) + VoxelShape bb = CableShapes.getModemShape( state ); + if( WorldUtil.isVecInside( bb, hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ) { - newState = state.withProperty( MODEM, BlockCableModemVariant.None ); - item = PeripheralItemFactory.create( PeripheralType.WiredModem, null, 1 ); + newState = state.with( MODEM, CableModemVariant.None ); + item = new ItemStack( ComputerCraft.Items.wiredModem ); } else { - newState = state.withProperty( CABLE, false ); - item = PeripheralItemFactory.create( PeripheralType.Cable, null, 1 ); + newState = state.with( CABLE, false ); + item = new ItemStack( ComputerCraft.Items.cable ); } - world.setBlockState( pos, newState, 3 ); + world.setBlockState( pos, correctConnections( world, pos, newState ), 3 ); cable.modemChanged(); cable.connectionsChanged(); - if( !world.isRemote && !player.capabilities.isCreativeMode ) + if( !world.isRemote && !player.abilities.isCreativeMode ) { Block.spawnAsEntity( world, pos, item ); } @@ -327,38 +139,34 @@ public boolean removedByPlayer( @Nonnull IBlockState state, World world, @Nonnul } } - return super.removedByPlayer( state, world, pos, player, willHarvest ); + return super.removedByPlayer( state, world, pos, player, willHarvest, fluid ); } @Override - public void getDrops( @Nonnull NonNullList drops, IBlockAccess world, BlockPos pos, @Nonnull IBlockState state, int fortune ) + public void getDrops( IBlockState state, NonNullList drops, World world, BlockPos pos, int fortune ) { - PeripheralType type = getPeripheralType( state ); - switch( type ) - { - case Cable: - case WiredModem: - drops.add( PeripheralItemFactory.create( type, null, 1 ) ); - break; - case WiredModemWithCable: - drops.add( PeripheralItemFactory.create( PeripheralType.WiredModem, null, 1 ) ); - drops.add( PeripheralItemFactory.create( PeripheralType.Cable, null, 1 ) ); - break; - } + if( state.get( CABLE ) ) drops.add( new ItemStack( ComputerCraft.Items.cable ) ); + if( state.get( MODEM ) != CableModemVariant.None ) drops.add( new ItemStack( ComputerCraft.Items.cable ) ); } @Nonnull @Override - public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult hit, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player ) + public ItemStack getPickBlock( IBlockState state, RayTraceResult hit, IBlockReader world, BlockPos pos, EntityPlayer player ) { - PeripheralType type = getPeripheralType( state ); - if( type == PeripheralType.WiredModemWithCable ) - { - type = hit == null || WorldUtil.isVecInsideInclusive( CableBounds.getModemBounds( state ), hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) - ? PeripheralType.WiredModem : PeripheralType.Cable; - } + EnumFacing modem = state.get( MODEM ).getFacing(); + boolean cable = state.get( CABLE ); + + // If we've only got one, just use that. + if( !cable ) return new ItemStack( ComputerCraft.Items.wiredModem ); + 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 + TileEntity tile = world.getTileEntity( pos ); + return tile instanceof TileCable && hit != null && + CableShapes.getModemShape( state ).getBoundingBox().contains( hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) + ? new ItemStack( ComputerCraft.Items.wiredModem ) + : new ItemStack( ComputerCraft.Items.cable ); - return PeripheralItemFactory.create( type, null, 1 ); } @Override @@ -368,20 +176,99 @@ public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, Entit if( tile instanceof TileCable ) { TileCable cable = (TileCable) tile; - if( cable.getPeripheralType() != PeripheralType.WiredModem ) - { - cable.connectionsChanged(); - } + if( cable.hasCable() ) cable.connectionsChanged(); } super.onBlockPlacedBy( world, pos, state, placer, stack ); } + @Nonnull @Override @Deprecated - public final boolean isOpaqueCube( IBlockState state ) + public IFluidState getFluidState( IBlockState state ) { - return false; + return getWaterloggedFluidState( state ); + } + + @Nonnull + @Override + @Deprecated + public IBlockState updatePostPlacement( @Nonnull IBlockState state, EnumFacing side, IBlockState otherState, IWorld world, BlockPos pos, BlockPos otherPos ) + { + updateWaterloggedPostPlacement( state, world, pos ); + // Should never happen, but handle the case where we've no modem or cable. + if( !state.get( CABLE ) && state.get( MODEM ) == CableModemVariant.None ) + { + return getFluidState( state ).getBlockState(); + } + + if( side == state.get( MODEM ).getFacing() && !state.isValidPosition( world, pos ) ) + { + if( !state.get( CABLE ) ) return getFluidState( state ).getBlockState(); + + /* TODO: + TileEntity entity = world.getTileEntity( pos ); + if( entity instanceof TileCable ) + { + entity.modemChanged(); + entity.connectionsChanged(); + } + */ + state = state.with( MODEM, CableModemVariant.None ); + } + + return state.with( CONNECTIONS.get( side ), doesConnectVisually( state, world, pos, side ) ); + } + + @Override + @Deprecated + public boolean isValidPosition( IBlockState state, IWorldReaderBase world, BlockPos pos ) + { + EnumFacing facing = state.get( MODEM ).getFacing(); + if( facing == null ) return true; + + BlockPos offsetPos = pos.offset( facing ); + IBlockState offsetState = world.getBlockState( offsetPos ); + return offsetState.getBlockFaceShape( world, offsetPos, facing.getOpposite() ) == BlockFaceShape.SOLID; + } + + @Nullable + @Override + public IBlockState getStateForPlacement( BlockItemUseContext context ) + { + IBlockState state = getDefaultState() + .with( WATERLOGGED, getWaterloggedStateForPlacement( context ) ); + + if( context.getItem().getItem() instanceof ItemBlockCable.Cable ) + { + World world = context.getWorld(); + BlockPos pos = context.getPos(); + return correctConnections( world, pos, state.with( CABLE, true ) ); + } + else + { + return state.with( MODEM, CableModemVariant.from( context.getFace().getOpposite() ) ); + } + } + + public static IBlockState correctConnections( World world, BlockPos pos, IBlockState state ) + { + if( state.get( CABLE ) ) + { + return state + .with( NORTH, doesConnectVisually( state, world, pos, EnumFacing.NORTH ) ) + .with( SOUTH, doesConnectVisually( state, world, pos, EnumFacing.SOUTH ) ) + .with( EAST, doesConnectVisually( state, world, pos, EnumFacing.EAST ) ) + .with( WEST, doesConnectVisually( state, world, pos, EnumFacing.WEST ) ) + .with( UP, doesConnectVisually( state, world, pos, EnumFacing.UP ) ) + .with( DOWN, doesConnectVisually( state, world, pos, EnumFacing.DOWN ) ); + } + else + { + return state + .with( NORTH, false ).with( SOUTH, false ).with( EAST, false ) + .with( WEST, false ).with( UP, false ).with( DOWN, false ); + } } @Override @@ -391,10 +278,11 @@ public final boolean isFullCube( IBlockState state ) return false; } + @Nonnull @Override @Deprecated - public BlockFaceShape getBlockFaceShape( IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing side ) + public BlockFaceShape getBlockFaceShape( IBlockReader worldIn, IBlockState state, BlockPos pos, EnumFacing face ) { return BlockFaceShape.UNDEFINED; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java index 157094455..3cfc9e5b2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java @@ -6,79 +6,29 @@ package dan200.computercraft.shared.peripheral.modem.wired; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.common.BlockGeneric; -import dan200.computercraft.shared.common.TileGeneric; -import net.minecraft.block.material.Material; -import net.minecraft.block.properties.PropertyBool; -import net.minecraft.block.state.BlockStateContainer; +import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockAccess; - -import javax.annotation.Nonnull; +import net.minecraft.state.BooleanProperty; +import net.minecraft.state.StateContainer; public class BlockWiredModemFull extends BlockGeneric { - private static final PropertyBool MODEM_ON = PropertyBool.create( "modem" ); - private static final PropertyBool PERIPHERAL_ON = PropertyBool.create( "peripheral" ); + public static final BooleanProperty MODEM_ON = BooleanProperty.create( "modem" ); + public static final BooleanProperty PERIPHERAL_ON = BooleanProperty.create( "peripheral" ); - public BlockWiredModemFull() + public BlockWiredModemFull( Properties settings ) { - super( Material.ROCK ); - setHardness( 1.5f ); - setTranslationKey( "computercraft:wired_modem_full" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - setDefaultState( blockState.getBaseState() - .withProperty( MODEM_ON, false ) - .withProperty( PERIPHERAL_ON, false ) - ); - } - - @Nonnull - @Override - protected BlockStateContainer createBlockState() - { - return new BlockStateContainer( this, - MODEM_ON, - PERIPHERAL_ON + super( settings, TileWiredModemFull.FACTORY ); + setDefaultState( getStateContainer().getBaseState() + .with( MODEM_ON, false ) + .with( PERIPHERAL_ON, false ) ); } @Override - public int getMetaFromState( IBlockState state ) + protected void fillStateContainer( StateContainer.Builder builder ) { - return 0; - } - - @Nonnull - @Override - @Deprecated - public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos ) - { - TileEntity te = world.getTileEntity( pos ); - if( te instanceof TileWiredModemFull ) - { - TileWiredModemFull modem = (TileWiredModemFull) te; - int anim = modem.getState(); - state = state - .withProperty( MODEM_ON, (anim & 1) != 0 ) - .withProperty( PERIPHERAL_ON, (anim & 2) != 0 ); - } - - return state; - } - - @Override - protected TileGeneric createTile( IBlockState state ) - { - return new TileWiredModemFull(); - } - - @Override - protected TileGeneric createTile( int damage ) - { - return new TileWiredModemFull(); + builder.add( MODEM_ON, PERIPHERAL_ON ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBounds.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBounds.java deleted file mode 100644 index 4af2cff12..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBounds.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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.shared.peripheral.modem.wired; - -import com.google.common.collect.ImmutableMap; -import dan200.computercraft.shared.peripheral.modem.ModemBounds; -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.AxisAlignedBB; - -import java.util.EnumMap; -import java.util.List; - -public final class CableBounds -{ - public static final double MIN = 0.375; - public static final double MAX = 1 - MIN; - - private static final AxisAlignedBB SHAPE_CABLE_CORE = new AxisAlignedBB( MIN, MIN, MIN, MAX, MAX, MAX ); - private static final EnumMap SHAPE_CABLE_ARM = - new EnumMap<>( new ImmutableMap.Builder() - .put( EnumFacing.DOWN, new AxisAlignedBB( MIN, 0, MIN, MAX, MIN, MAX ) ) - .put( EnumFacing.UP, new AxisAlignedBB( MIN, MAX, MIN, MAX, 1, MAX ) ) - .put( EnumFacing.NORTH, new AxisAlignedBB( MIN, MIN, 0, MAX, MAX, MIN ) ) - .put( EnumFacing.SOUTH, new AxisAlignedBB( MIN, MIN, MAX, MAX, MAX, 1 ) ) - .put( EnumFacing.WEST, new AxisAlignedBB( 0, MIN, MIN, MIN, MAX, MAX ) ) - .put( EnumFacing.EAST, new AxisAlignedBB( MAX, MIN, MIN, 1, MAX, MAX ) ) - .build() - ); - - private static final AxisAlignedBB[] SHAPES = new AxisAlignedBB[(1 << 6) * 7]; - private static final AxisAlignedBB[] CABLE_SHAPES = new AxisAlignedBB[1 << 6]; - - private CableBounds() - { - } - - private static int getCableIndex( IBlockState state ) - { - int index = 0; - for( EnumFacing facing : EnumFacing.VALUES ) - { - if( state.getValue( BlockCable.CONNECTIONS.get( facing ) ) ) index |= 1 << facing.ordinal(); - } - - return index; - } - - private static AxisAlignedBB getCableBounds( int index ) - { - AxisAlignedBB bounds = CABLE_SHAPES[index]; - if( bounds != null ) return bounds; - - bounds = SHAPE_CABLE_CORE; - for( EnumFacing facing : EnumFacing.VALUES ) - { - if( (index & (1 << facing.ordinal())) != 0 ) - { - bounds = bounds.union( SHAPE_CABLE_ARM.get( facing ) ); - } - } - - return CABLE_SHAPES[index] = bounds; - } - - public static AxisAlignedBB getCableBounds( IBlockState state ) - { - if( !state.getValue( BlockCable.CABLE ) ) return BlockCable.NULL_AABB; - return getCableBounds( getCableIndex( state ) ); - } - - public static void getCableBounds( IBlockState state, List bounds ) - { - if( !state.getValue( BlockCable.CABLE ) ) return; - - bounds.add( SHAPE_CABLE_CORE ); - for( EnumFacing facing : EnumFacing.VALUES ) - { - if( state.getValue( BlockCable.CONNECTIONS.get( facing ) ) ) bounds.add( SHAPE_CABLE_ARM.get( facing ) ); - } - } - - public static AxisAlignedBB getModemBounds( IBlockState state ) - { - EnumFacing facing = state.getValue( BlockCable.MODEM ).getFacing(); - return facing == null ? Block.NULL_AABB : ModemBounds.getBounds( facing ); - } - - public static AxisAlignedBB getBounds( IBlockState state ) - { - if( !state.getValue( BlockCable.CABLE ) ) return getModemBounds( state ); - - EnumFacing facing = state.getValue( BlockCable.MODEM ).getFacing(); - int cableIndex = getCableIndex( state ); - int index = cableIndex + ((facing == null ? 0 : facing.ordinal() + 1) << 6); - - AxisAlignedBB shape = SHAPES[index]; - if( shape != null ) return shape; - - shape = getCableBounds( cableIndex ); - if( facing != null ) shape = shape.union( ModemBounds.getBounds( facing ) ); - return SHAPES[index] = shape; - } - - public static void getBounds( IBlockState state, List bounds ) - { - EnumFacing facing = state.getValue( BlockCable.MODEM ).getFacing(); - if( facing != null ) bounds.add( getModemBounds( state ) ); - getCableBounds( state, bounds ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCableModemVariant.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java similarity index 84% rename from src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCableModemVariant.java rename to src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java index 711492f4c..de2ff52e7 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCableModemVariant.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java @@ -10,9 +10,8 @@ import net.minecraft.util.IStringSerializable; import javax.annotation.Nonnull; -import javax.annotation.Nullable; -public enum BlockCableModemVariant implements IStringSerializable +public enum CableModemVariant implements IStringSerializable { None( "none", null ), DownOff( "down_off", EnumFacing.DOWN ), @@ -40,28 +39,28 @@ public enum BlockCableModemVariant implements IStringSerializable WestOnPeripheral( "west_on_peripheral", EnumFacing.WEST ), EastOnPeripheral( "east_on_peripheral", EnumFacing.EAST ); - private static final BlockCableModemVariant[] VALUES = values(); + private static final CableModemVariant[] VALUES = values(); private final String name; private final EnumFacing facing; - BlockCableModemVariant( String name, EnumFacing facing ) + CableModemVariant( String name, EnumFacing facing ) { this.name = name; this.facing = facing; } - @Nonnull - public static BlockCableModemVariant from( @Nullable EnumFacing facing ) + public static CableModemVariant from( EnumFacing facing ) { return facing == null ? None : VALUES[1 + facing.getIndex()]; } @Nonnull - public static BlockCableModemVariant from( @Nullable EnumFacing facing, int state ) + public static CableModemVariant from( EnumFacing facing, boolean modem, boolean peripheral ) { - return facing == null ? None : VALUES[1 + 6 * state + facing.ordinal()]; + int state = (modem ? 2 : 0) + (peripheral ? 1 : 0); + return facing == null ? None : VALUES[1 + 6 * state + facing.getIndex()]; } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java new file mode 100644 index 000000000..4f9810f44 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java @@ -0,0 +1,100 @@ +/* + * 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.shared.peripheral.modem.wired; + +import com.google.common.collect.ImmutableMap; +import dan200.computercraft.shared.peripheral.modem.ModemShapes; +import dan200.computercraft.shared.util.DirectionUtil; +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.util.math.shapes.VoxelShapes; + +import java.util.EnumMap; + +import static dan200.computercraft.shared.peripheral.modem.wired.BlockCable.*; + +public final class CableShapes +{ + private static final double MIN = 0.375; + private static final double MAX = 1 - MIN; + + private static final VoxelShape SHAPE_CABLE_CORE = VoxelShapes.create( MIN, MIN, MIN, MAX, MAX, MAX ); + private static final EnumMap SHAPE_CABLE_ARM = + new EnumMap<>( new ImmutableMap.Builder() + .put( EnumFacing.DOWN, VoxelShapes.create( MIN, 0, MIN, MAX, MIN, MAX ) ) + .put( EnumFacing.UP, VoxelShapes.create( MIN, MAX, MIN, MAX, 1, MAX ) ) + .put( EnumFacing.NORTH, VoxelShapes.create( MIN, MIN, 0, MAX, MAX, MIN ) ) + .put( EnumFacing.SOUTH, VoxelShapes.create( MIN, MIN, MAX, MAX, MAX, 1 ) ) + .put( EnumFacing.WEST, VoxelShapes.create( 0, MIN, MIN, MIN, MAX, MAX ) ) + .put( EnumFacing.EAST, VoxelShapes.create( MAX, MIN, MIN, 1, MAX, MAX ) ) + .build() + ); + + private static final VoxelShape[] SHAPES = new VoxelShape[(1 << 6) * 7]; + private static final VoxelShape[] CABLE_SHAPES = new VoxelShape[1 << 6]; + + private CableShapes() + { + } + + private static int getCableIndex( IBlockState state ) + { + int index = 0; + for( EnumFacing facing : DirectionUtil.FACINGS ) + { + if( state.get( CONNECTIONS.get( facing ) ) ) index |= 1 << facing.ordinal(); + } + + return index; + } + + private static VoxelShape getCableShape( int index ) + { + VoxelShape shape = CABLE_SHAPES[index]; + if( shape != null ) return shape; + + shape = SHAPE_CABLE_CORE; + for( EnumFacing facing : DirectionUtil.FACINGS ) + { + if( (index & (1 << facing.ordinal())) != 0 ) + { + shape = VoxelShapes.or( shape, SHAPE_CABLE_ARM.get( facing ) ); + } + } + + return CABLE_SHAPES[index] = shape; + } + + public static VoxelShape getCableShape( IBlockState state ) + { + if( !state.get( CABLE ) ) return VoxelShapes.empty(); + return getCableShape( getCableIndex( state ) ); + } + + public static VoxelShape getModemShape( IBlockState state ) + { + EnumFacing facing = state.get( MODEM ).getFacing(); + return facing == null ? VoxelShapes.empty() : ModemShapes.getBounds( facing ); + } + + public static VoxelShape getShape( IBlockState state ) + { + EnumFacing facing = state.get( MODEM ).getFacing(); + if( !state.get( CABLE ) ) return getModemShape( state ); + + int cableIndex = getCableIndex( state ); + int index = cableIndex + ((facing == null ? 0 : facing.ordinal() + 1) << 6); + + VoxelShape shape = SHAPES[index]; + if( shape != null ) return shape; + + shape = getCableShape( cableIndex ); + if( facing != null ) shape = VoxelShapes.or( shape, ModemShapes.getBounds( facing ) ); + return SHAPES[index] = shape; + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java new file mode 100644 index 000000000..d65ca60f0 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java @@ -0,0 +1,153 @@ +/* + * 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.shared.peripheral.modem.wired; + +import dan200.computercraft.ComputerCraft; +import net.minecraft.block.SoundType; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.*; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.registries.ForgeRegistries; + +import javax.annotation.Nonnull; + +import static dan200.computercraft.shared.peripheral.modem.wired.BlockCable.*; + +public abstract class ItemBlockCable extends ItemBlock +{ + private String translationKey; + + public ItemBlockCable( BlockCable block, Properties settings ) + { + super( block, settings ); + } + + boolean placeAt( World world, BlockPos pos, IBlockState state, EntityPlayer player ) + { + // TODO: Check entity collision. + if( !state.isValidPosition( world, pos ) ) return false; + + world.setBlockState( pos, state, 3 ); + SoundType soundType = state.getBlock().getSoundType( state, world, pos, player ); + world.playSound( null, pos, soundType.getPlaceSound(), SoundCategory.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F ); + + TileEntity tile = world.getTileEntity( pos ); + if( tile instanceof TileCable ) + { + TileCable cable = (TileCable) tile; + cable.modemChanged(); + cable.connectionsChanged(); + } + + return true; + } + + boolean placeAtCorrected( World world, BlockPos pos, IBlockState state ) + { + return placeAt( world, pos, correctConnections( world, pos, state ), null ); + } + + @Override + public void fillItemGroup( @Nonnull ItemGroup group, @Nonnull NonNullList list ) + { + if( isInGroup( group ) ) list.add( new ItemStack( this ) ); + } + + @Nonnull + @Override + public String getTranslationKey() + { + if( translationKey == null ) + { + translationKey = Util.makeTranslationKey( "block", ForgeRegistries.ITEMS.getKey( this ) ); + } + return translationKey; + } + + public static class WiredModem extends ItemBlockCable + { + public WiredModem( BlockCable block, Properties settings ) + { + super( block, settings ); + } + + @Nonnull + @Override + public EnumActionResult tryPlace( BlockItemUseContext context ) + { + ItemStack stack = context.getItem(); + if( stack.isEmpty() ) return EnumActionResult.FAIL; + + World world = context.getWorld(); + BlockPos pos = context.getPos(); + IBlockState existingState = world.getBlockState( pos ); + + // Try to add a modem to a cable + if( existingState.getBlock() == ComputerCraft.Blocks.cable && existingState.get( MODEM ) == CableModemVariant.None ) + { + EnumFacing side = context.getFace().getOpposite(); + IBlockState newState = existingState + .with( MODEM, CableModemVariant.from( side ) ) + .with( CONNECTIONS.get( side ), existingState.get( CABLE ) ); + if( placeAt( world, pos, newState, context.getPlayer() ) ) + { + stack.shrink( 1 ); + return EnumActionResult.SUCCESS; + } + } + + return super.tryPlace( context ); + } + } + + public static class Cable extends ItemBlockCable + { + public Cable( BlockCable block, Properties settings ) + { + super( block, settings ); + } + + @Nonnull + @Override + public EnumActionResult tryPlace( BlockItemUseContext context ) + { + ItemStack stack = context.getItem(); + if( stack.isEmpty() ) return EnumActionResult.FAIL; + + World world = context.getWorld(); + BlockPos pos = context.getPos(); + + // Try to add a cable to a modem inside the block we're clicking on. + BlockPos insidePos = pos.offset( context.getFace().getOpposite() ); + IBlockState insideState = world.getBlockState( insidePos ); + if( insideState.getBlock() == ComputerCraft.Blocks.cable && !insideState.get( BlockCable.CABLE ) + && placeAtCorrected( world, insidePos, insideState.with( BlockCable.CABLE, true ) ) ) + { + stack.shrink( 1 ); + return EnumActionResult.SUCCESS; + } + + // Try to add a cable to a modem adjacent to this block + IBlockState existingState = world.getBlockState( pos ); + if( existingState.getBlock() == ComputerCraft.Blocks.cable && !existingState.get( BlockCable.CABLE ) + && placeAtCorrected( world, pos, existingState.with( BlockCable.CABLE, true ) ) ) + { + stack.shrink( 1 ); + return EnumActionResult.SUCCESS; + } + + return super.tryPlace( context ); + } + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemCable.java deleted file mode 100644 index bb928190a..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemCable.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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.shared.peripheral.modem.wired; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.common.ItemPeripheralBase; -import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory; -import net.minecraft.block.Block; -import net.minecraft.block.SoundType; -import net.minecraft.block.state.IBlockState; -import net.minecraft.creativetab.CreativeTabs; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemStack; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.*; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public class ItemCable extends ItemPeripheralBase -{ - public ItemCable( Block block ) - { - super( block ); - setTranslationKey( "computercraft:cable" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - setHasSubtypes( true ); - } - - @Nonnull - public ItemStack create( PeripheralType type, int quantity ) - { - switch( type ) - { - case Cable: - return new ItemStack( this, quantity, 0 ); - case WiredModem: - return new ItemStack( this, quantity, 1 ); - default: - return ItemStack.EMPTY; - } - } - - @Override - public void getSubItems( @Nullable CreativeTabs tabs, @Nonnull NonNullList list ) - { - if( !isInCreativeTab( tabs ) ) return; - list.add( PeripheralItemFactory.create( PeripheralType.WiredModem, null, 1 ) ); - list.add( PeripheralItemFactory.create( PeripheralType.Cable, null, 1 ) ); - } - - @Nonnull - @Override - public EnumActionResult onItemUse( @Nonnull EntityPlayer player, World world, @Nonnull BlockPos pos, @Nonnull EnumHand hand, @Nonnull EnumFacing side, float fx, float fy, float fz ) - { - ItemStack stack = player.getHeldItem( hand ); - if( !canPlaceBlockOnSide( world, pos, side, player, stack ) ) return EnumActionResult.FAIL; - - // Try to add a cable to a modem - PeripheralType type = getPeripheralType( stack ); - IBlockState existingState = world.getBlockState( pos ); - Block existing = existingState.getBlock(); - if( existing == ComputerCraft.Blocks.cable ) - { - PeripheralType existingType = BlockCable.getPeripheralType( existingState ); - if( existingType == PeripheralType.WiredModem && type == PeripheralType.Cable ) - { - if( !stack.isEmpty() ) - { - IBlockState newState = existingState.withProperty( BlockCable.CABLE, true ); - world.setBlockState( pos, newState, 3 ); - SoundType soundType = newState.getBlock().getSoundType( newState, world, pos, player ); - world.playSound( null, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, soundType.getPlaceSound(), SoundCategory.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F ); - stack.shrink( 1 ); - - TileEntity tile = world.getTileEntity( pos ); - if( tile instanceof TileCable ) - { - TileCable cable = (TileCable) tile; - cable.connectionsChanged(); - } - return EnumActionResult.SUCCESS; - } - return EnumActionResult.FAIL; - } - } - - // Try to add on the side of something - if( !existing.isAir( existingState, world, pos ) && (type == PeripheralType.Cable || existingState.isSideSolid( world, pos, side )) ) - { - BlockPos offset = pos.offset( side ); - IBlockState offsetExistingState = world.getBlockState( offset ); - Block offsetExisting = offsetExistingState.getBlock(); - if( offsetExisting == ComputerCraft.Blocks.cable ) - { - // Try to add a modem to a cable - PeripheralType offsetExistingType = BlockCable.getPeripheralType( offsetExistingState ); - if( offsetExistingType == PeripheralType.Cable && type == PeripheralType.WiredModem ) - { - if( !stack.isEmpty() ) - { - IBlockState newState = offsetExistingState.withProperty( BlockCable.MODEM, BlockCableModemVariant.from( side.getOpposite() ) ); - world.setBlockState( offset, newState, 3 ); - SoundType soundType = newState.getBlock().getSoundType( newState, world, offset, player ); - world.playSound( null, offset.getX() + 0.5, offset.getY() + 0.5, offset.getZ() + 0.5, soundType.getPlaceSound(), SoundCategory.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F ); - stack.shrink( 1 ); - - TileEntity tile = world.getTileEntity( offset ); - if( tile instanceof TileCable ) - { - TileCable cable = (TileCable) tile; - cable.modemChanged(); - cable.connectionsChanged(); - } - return EnumActionResult.SUCCESS; - } - return EnumActionResult.FAIL; - } - - // Try to add a cable to a modem - if( offsetExistingType == PeripheralType.WiredModem && type == PeripheralType.Cable ) - { - if( !stack.isEmpty() ) - { - IBlockState newState = offsetExistingState.withProperty( BlockCable.CABLE, true ); - world.setBlockState( offset, newState, 3 ); - SoundType soundType = newState.getBlock().getSoundType( newState, world, offset, player ); - world.playSound( null, offset.getX() + 0.5, offset.getY() + 0.5, offset.getZ() + 0.5, soundType.getPlaceSound(), SoundCategory.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F ); - stack.shrink( 1 ); - - TileEntity tile = world.getTileEntity( offset ); - if( tile instanceof TileCable ) - { - TileCable cable = (TileCable) tile; - cable.modemChanged(); - cable.connectionsChanged(); - } - return EnumActionResult.SUCCESS; - } - return EnumActionResult.FAIL; - } - } - } - - return super.onItemUse( player, world, pos, hand, side, fx, fy, fz ); - } - - @Override - public PeripheralType getPeripheralType( int damage ) - { - return damage == 1 ? PeripheralType.WiredModem : PeripheralType.Cable; - } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemWiredModemFull.java deleted file mode 100644 index e437f2dbb..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemWiredModemFull.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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.shared.peripheral.modem.wired; - -import dan200.computercraft.shared.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.common.ItemPeripheralBase; -import net.minecraft.block.Block; - -public class ItemWiredModemFull extends ItemPeripheralBase -{ - public ItemWiredModemFull( Block block ) - { - super( block ); - } - - @Override - public PeripheralType getPeripheralType( int damage ) - { - return PeripheralType.WiredModemFull; - } -} 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 0cd0d4da4..0ac5b5e7a 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 @@ -7,6 +7,7 @@ package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.base.Objects; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.network.wired.IWiredElement; import dan200.computercraft.api.network.wired.IWiredNode; @@ -14,22 +15,26 @@ import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.command.CommandCopy; import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory; import dan200.computercraft.shared.peripheral.modem.ModemState; +import dan200.computercraft.shared.util.DirectionUtil; +import dan200.computercraft.shared.util.NamedBlockEntityType; import dan200.computercraft.shared.util.TickScheduler; import dan200.computercraft.shared.wired.CapabilityWiredElement; import net.minecraft.block.Block; +import net.minecraft.block.state.BlockFaceShape; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -38,6 +43,13 @@ public class TileCable extends TileGeneric implements IPeripheralTile { + public static final NamedBlockEntityType FACTORY = NamedBlockEntityType.create( + new ResourceLocation( ComputerCraft.MOD_ID, "cable" ), + TileCable::new + ); + + private static final String NBT_PERIPHERAL_ENABLED = "PeirpheralAccess"; + private class CableElement extends WiredModemElement { @Nonnull @@ -68,19 +80,17 @@ protected void detachPeripheral( String name ) } } - // Members - private boolean m_peripheralAccessAllowed; private WiredModemLocalPeripheral m_peripheral = new WiredModemLocalPeripheral(); private boolean m_destroyed = false; - private EnumFacing modemDirection; + private EnumFacing modemDirection = EnumFacing.NORTH; private boolean hasModemDirection = false; - private boolean m_connectionsFormed = false; private final WiredModemElement m_cable = new CableElement(); + private LazyOptional m_cableCapability = LazyOptional.of( () -> m_cable ); private final IWiredNode m_node = m_cable.getNode(); private final WiredModemPeripheral m_modem = new WiredModemPeripheral( new ModemState( () -> TickScheduler.schedule( this ) ), @@ -103,9 +113,12 @@ public Vec3d getPosition() } }; - private int m_state = 0; + public TileCable() + { + super( FACTORY ); + } - private void remove() + private void onRemove() { if( world == null || !world.isRemote ) { @@ -121,22 +134,22 @@ public void destroy() { m_destroyed = true; m_modem.destroy(); - remove(); + onRemove(); } } @Override - public void onChunkUnload() + public void onChunkUnloaded() { - super.onChunkUnload(); - remove(); + super.onChunkUnloaded(); + onRemove(); } @Override - public void invalidate() + public void remove() { - super.invalidate(); - remove(); + super.remove(); + onRemove(); } @Override @@ -146,7 +159,7 @@ public void onLoad() if( !world.isRemote ) { updateDirection(); - world.scheduleUpdate( pos, getBlockType(), 0 ); + world.getPendingBlockTicks().scheduleTick( pos, getBlockState().getBlock(), 0 ); } } @@ -155,7 +168,7 @@ public void updateContainingBlockInfo() { super.updateContainingBlockInfo(); hasModemDirection = false; - if( !world.isRemote ) world.scheduleUpdate( pos, getBlockType(), 0 ); + if( !world.isRemote ) world.getPendingBlockTicks().scheduleTick( pos, getBlockState().getBlock(), 0 ); } private void updateDirection() @@ -170,7 +183,7 @@ private void updateDirection() private EnumFacing getDirection() { IBlockState state = getBlockState(); - EnumFacing facing = state.getValue( BlockCable.MODEM ).getFacing(); + EnumFacing facing = state.get( BlockCable.MODEM ).getFacing(); return facing != null ? facing : EnumFacing.NORTH; } @@ -178,32 +191,30 @@ private EnumFacing getDirection() public void onNeighbourChange( @Nonnull BlockPos neighbour ) { EnumFacing dir = getDirection(); - if( neighbour.equals( getPos().offset( dir ) ) && !getWorld().isSideSolid( neighbour, dir.getOpposite() ) ) + if( neighbour.equals( getPos().offset( dir ) ) && hasModem() + && getWorld().getBlockState( neighbour ).getBlockFaceShape( world, neighbour, dir.getOpposite() ) != BlockFaceShape.SOLID + ) { - switch( getPeripheralType() ) + if( hasCable() ) { - case WiredModem: - // Drop everything and remove block - getBlockType().dropBlockAsItem( getWorld(), getPos(), getBlockState(), 0 ); - getWorld().setBlockToAir( getPos() ); - - // This'll call #destroy(), so we don't need to reset the network here. - return; - case WiredModemWithCable: - // Drop the modem and convert to cable - Block.spawnAsEntity( getWorld(), getPos(), PeripheralItemFactory.create( PeripheralType.WiredModem, null, 1 ) ); - setBlockState( getBlockState().withProperty( BlockCable.MODEM, BlockCableModemVariant.None ) ); - modemChanged(); - connectionsChanged(); - - return; + // Drop the modem and convert to cable + Block.spawnAsEntity( getWorld(), getPos(), new ItemStack( ComputerCraft.Items.wiredModem ) ); + getWorld().setBlockState( getPos(), getBlockState().with( BlockCable.MODEM, CableModemVariant.None ) ); + modemChanged(); + connectionsChanged(); } + else + { + // Drop everything and remove block + Block.spawnAsEntity( getWorld(), getPos(), new ItemStack( ComputerCraft.Items.wiredModem ) ); + getWorld().removeBlock( getPos() ); + // This'll call #destroy(), so we don't need to reset the network here. + } + + return; } - if( !world.isRemote && m_peripheralAccessAllowed ) - { - if( m_peripheral.attach( world, getPos(), dir ) ) updateConnectedPeripherals(); - } + onNeighbourTileEntityChange( neighbour ); } @Override @@ -223,30 +234,24 @@ public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour ) @Override public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ ) { - if( getPeripheralType() != PeripheralType.WiredModemWithCable || player.isSneaking() ) return false; + if( !canAttachPeripheral() || player.isSneaking() ) return false; - if( !getWorld().isRemote ) + if( getWorld().isRemote ) return true; + + String oldName = m_peripheral.getConnectedName(); + togglePeripheralAccess(); + String newName = m_peripheral.getConnectedName(); + if( !Objects.equal( newName, oldName ) ) { - String oldName = m_peripheral.getConnectedName(); - togglePeripheralAccess(); - String newName = m_peripheral.getConnectedName(); - - if( !Objects.equal( newName, oldName ) ) + if( oldName != null ) { - if( oldName != null ) - { - player.sendMessage( - new TextComponentTranslation( "chat.computercraft.wired_modem.peripheral_disconnected", - CommandCopy.createCopyText( oldName ) ) - ); - } - if( newName != null ) - { - player.sendMessage( - new TextComponentTranslation( "chat.computercraft.wired_modem.peripheral_connected", - CommandCopy.createCopyText( newName ) ) - ); - } + player.sendStatusMessage( new TextComponentTranslation( "chat.computercraft.wired_modem.peripheral_disconnected", + CommandCopy.createCopyText( oldName ) ), false ); + } + if( newName != null ) + { + player.sendStatusMessage( new TextComponentTranslation( "chat.computercraft.wired_modem.peripheral_connected", + CommandCopy.createCopyText( newName ) ), false ); } } @@ -254,64 +259,43 @@ public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, } @Override - public void readFromNBT( NBTTagCompound nbt ) + public void read( NBTTagCompound nbt ) { - // Read properties - super.readFromNBT( nbt ); - m_peripheralAccessAllowed = nbt.getBoolean( "peripheralAccess" ); - m_peripheral.readNBT( nbt, "" ); + super.read( nbt ); + m_peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED ); + m_peripheral.read( nbt, "" ); } @Nonnull @Override - public NBTTagCompound writeToNBT( NBTTagCompound nbt ) + public NBTTagCompound write( NBTTagCompound nbt ) { - // Write properties - nbt.setBoolean( "peripheralAccess", m_peripheralAccessAllowed ); - m_peripheral.writeNBT( nbt, "" ); - return super.writeToNBT( nbt ); + nbt.putBoolean( NBT_PERIPHERAL_ENABLED, m_peripheralAccessAllowed ); + m_peripheral.write( nbt, "" ); + return super.write( nbt ); } - @Override - protected void writeDescription( @Nonnull NBTTagCompound nbt ) + private void updateBlockState() { - super.writeDescription( nbt ); - nbt.setInteger( "state", m_state ); - } + IBlockState state = getBlockState(); + CableModemVariant oldVariant = state.get( BlockCable.MODEM ); + CableModemVariant newVariant = CableModemVariant + .from( oldVariant.getFacing(), m_modem.getModemState().isOpen(), m_peripheralAccessAllowed ); - @Override - public final void readDescription( @Nonnull NBTTagCompound nbt ) - { - super.readDescription( nbt ); - m_state = nbt.getInteger( "state" ); - updateBlock(); - } - - public int getState() - { - return m_state; - } - - private void updateState() - { - int state = 0; - if( m_modem.getModemState().isOpen() ) state |= 1; - if( m_peripheralAccessAllowed ) state |= 2; - if( state != m_state ) + if( oldVariant != newVariant ) { - m_state = state; - updateBlock(); + world.setBlockState( getPos(), state.with( BlockCable.MODEM, newVariant ) ); } } @Override - protected void updateTick() + public void blockTick() { if( getWorld().isRemote ) return; updateDirection(); - if( m_modem.getModemState().pollChanged() ) updateState(); + if( m_modem.getModemState().pollChanged() ) updateBlockState(); if( !m_connectionsFormed ) { @@ -333,7 +317,7 @@ void connectionsChanged() IBlockState state = getBlockState(); World world = getWorld(); BlockPos current = getPos(); - for( EnumFacing facing : EnumFacing.VALUES ) + for( EnumFacing facing : DirectionUtil.FACINGS ) { BlockPos offset = current.offset( facing ); if( !world.isBlockLoaded( offset ) ) continue; @@ -356,16 +340,22 @@ else if( m_node.getNetwork() == element.getNode().getNetwork() ) void modemChanged() { + // Tell anyone who cares that the connection state has changed + // TODO: Be more restrictive about this. + m_cableCapability.invalidate(); + m_cableCapability = LazyOptional.of( () -> m_cable ); + if( getWorld().isRemote ) return; - PeripheralType type = getPeripheralType(); - if( type != PeripheralType.WiredModemWithCable && m_peripheralAccessAllowed ) + // If we can no longer attach peripherals, then detach any + // which may have existed + if( !canAttachPeripheral() && m_peripheralAccessAllowed ) { m_peripheralAccessAllowed = false; m_peripheral.detach(); m_node.updatePeripherals( Collections.emptyMap() ); markDirty(); - updateState(); + updateBlockState(); } } @@ -387,7 +377,7 @@ private void togglePeripheralAccess() m_node.updatePeripherals( Collections.emptyMap() ); } - updateState(); + updateBlockState(); } private void updateConnectedPeripherals() @@ -397,7 +387,7 @@ private void updateConnectedPeripherals() { // If there are no peripherals then disable access and update the display state. m_peripheralAccessAllowed = false; - updateState(); + updateBlockState(); } m_node.updatePeripherals( peripherals ); @@ -409,26 +399,14 @@ public boolean canRenderBreaking() return true; } + @Nonnull @Override - public boolean hasCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) - { - if( capability == CapabilityWiredElement.CAPABILITY ) - { - return !m_destroyed && BlockCable.canConnectIn( getBlockState(), facing ); - } - - return super.hasCapability( capability, facing ); - } - - @Nullable - @Override - public T getCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + public LazyOptional getCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) { if( capability == CapabilityWiredElement.CAPABILITY ) { return !m_destroyed && BlockCable.canConnectIn( getBlockState(), facing ) - ? CapabilityWiredElement.CAPABILITY.cast( m_cable ) - : null; + ? m_cableCapability.cast() : LazyOptional.empty(); } return super.getCapability( capability, facing ); @@ -437,12 +415,21 @@ public T getCapability( @Nonnull Capability capability, @Nullable EnumFac @Override public IPeripheral getPeripheral( @Nonnull EnumFacing side ) { - return !m_destroyed && getPeripheralType() != PeripheralType.Cable && side == getDirection() ? m_modem : null; + return !m_destroyed && hasModem() && side == getDirection() ? m_modem : null; } - public PeripheralType getPeripheralType() + public boolean hasCable() { - IBlockState state = getBlockState(); - return BlockCable.getPeripheralType( state ); + return getBlockState().get( BlockCable.CABLE ); + } + + public boolean hasModem() + { + return getBlockState().get( BlockCable.MODEM ) != CableModemVariant.None; + } + + 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 02f63caff..56a1ff3ef 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 @@ -7,7 +7,8 @@ package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.base.Objects; -import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.ComputerCraftAPIImpl; import dan200.computercraft.api.network.wired.IWiredElement; import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.peripheral.IPeripheral; @@ -15,25 +16,40 @@ import dan200.computercraft.shared.command.CommandCopy; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemState; +import dan200.computercraft.shared.util.DirectionUtil; +import dan200.computercraft.shared.util.NamedBlockEntityType; import dan200.computercraft.shared.util.TickScheduler; import dan200.computercraft.shared.wired.CapabilityWiredElement; +import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; +import static dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull.MODEM_ON; +import static dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull.PERIPHERAL_ON; + public class TileWiredModemFull extends TileGeneric implements IPeripheralTile { + public static final NamedBlockEntityType FACTORY = NamedBlockEntityType.create( + new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full" ), + TileWiredModemFull::new + ); + + private static final String NBT_PERIPHERAL_ENABLED = "PeripheralAccess"; + private static final class FullElement extends WiredModemElement { private final TileWiredModemFull m_entity; @@ -89,16 +105,18 @@ public Vec3d getPosition() private final ModemState m_modemState = new ModemState( () -> TickScheduler.schedule( this ) ); private final WiredModemElement m_element = new FullElement( this ); + private final LazyOptional m_elementCap = LazyOptional.of( () -> m_element ); private final IWiredNode m_node = m_element.getNode(); private int m_state = 0; public TileWiredModemFull() { + super( FACTORY ); for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i] = new WiredModemLocalPeripheral(); } - private void remove() + private void doRemove() { if( world == null || !world.isRemote ) { @@ -113,23 +131,23 @@ public void destroy() if( !m_destroyed ) { m_destroyed = true; - remove(); + doRemove(); } super.destroy(); } @Override - public void onChunkUnload() + public void onChunkUnloaded() { - super.onChunkUnload(); - remove(); + super.onChunkUnloaded(); + doRemove(); } @Override - public void invalidate() + public void remove() { - super.invalidate(); - remove(); + super.remove(); + doRemove(); } @Override @@ -143,7 +161,7 @@ public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour ) { if( !world.isRemote && m_peripheralAccessAllowed ) { - for( EnumFacing facing : EnumFacing.VALUES ) + for( EnumFacing facing : DirectionUtil.FACINGS ) { if( getPos().offset( facing ).equals( neighbour ) ) { @@ -157,27 +175,20 @@ public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour ) @Override public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ ) { - if( !getWorld().isRemote ) - { - // On server, we interacted if a peripheral was found - Set oldPeriphNames = getConnectedPeripheralNames(); - togglePeripheralAccess(); - Set periphNames = getConnectedPeripheralNames(); + if( getWorld().isRemote ) return true; - if( !Objects.equal( periphNames, oldPeriphNames ) ) - { - sendPeripheralChanges( player, "chat.computercraft.wired_modem.peripheral_disconnected", oldPeriphNames ); - sendPeripheralChanges( player, "chat.computercraft.wired_modem.peripheral_connected", periphNames ); - } + // On server, we interacted if a peripheral was found + Set oldPeriphNames = getConnectedPeripheralNames(); + togglePeripheralAccess(); + Set periphNames = getConnectedPeripheralNames(); - return true; - } - else + if( !Objects.equal( periphNames, oldPeriphNames ) ) { - // On client, we can't know this, so we assume so to be safe - // The server will correct us if we're wrong - return true; + sendPeripheralChanges( player, "chat.computercraft.wired_modem.peripheral_disconnected", oldPeriphNames ); + sendPeripheralChanges( player, "chat.computercraft.wired_modem.peripheral_connected", periphNames ); } + + return true; } private static void sendPeripheralChanges( EntityPlayer player, String kind, Collection peripherals ) @@ -194,71 +205,48 @@ private static void sendPeripheralChanges( EntityPlayer player, String kind, Col base.appendSibling( CommandCopy.createCopyText( names.get( i ) ) ); } - player.sendMessage( new TextComponentTranslation( kind, base ) ); + player.sendStatusMessage( new TextComponentTranslation( kind, base ), false ); } @Override - public void readFromNBT( NBTTagCompound nbt ) + public void read( NBTTagCompound nbt ) { - super.readFromNBT( nbt ); - m_peripheralAccessAllowed = nbt.getBoolean( "peripheralAccess" ); - for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i].readNBT( nbt, "_" + i ); + super.read( nbt ); + m_peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED ); + for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i].read( nbt, Integer.toString( i ) ); } @Nonnull @Override - public NBTTagCompound writeToNBT( NBTTagCompound nbt ) + public NBTTagCompound write( NBTTagCompound nbt ) { - nbt.setBoolean( "peripheralAccess", m_peripheralAccessAllowed ); - for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i].writeNBT( nbt, "_" + i ); - return super.writeToNBT( nbt ); + nbt.putBoolean( NBT_PERIPHERAL_ENABLED, m_peripheralAccessAllowed ); + for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i].write( nbt, Integer.toString( i ) ); + return super.write( nbt ); } - public int getState() + private void updateBlockState() { - return m_state; - } + IBlockState state = getBlockState(); + boolean modemOn = m_modemState.isOpen(), peripheralOn = m_peripheralAccessAllowed; + if( state.get( MODEM_ON ) == modemOn && state.get( PERIPHERAL_ON ) == peripheralOn ) return; - private void updateState() - { - int state = 0; - if( m_modemState.isOpen() ) state |= 1; - if( m_peripheralAccessAllowed ) state |= 2; - if( state != m_state ) - { - m_state = state; - updateBlock(); - } - } - - @Override - protected void writeDescription( @Nonnull NBTTagCompound nbt ) - { - super.writeDescription( nbt ); - nbt.setInteger( "state", m_state ); - } - - @Override - public final void readDescription( @Nonnull NBTTagCompound nbt ) - { - super.readDescription( nbt ); - m_state = nbt.getInteger( "state" ); - updateBlock(); + getWorld().setBlockState( getPos(), state.with( MODEM_ON, modemOn ).with( PERIPHERAL_ON, peripheralOn ) ); } @Override public void onLoad() { super.onLoad(); - if( !world.isRemote ) world.scheduleUpdate( pos, getBlockType(), 0 ); + if( !world.isRemote ) world.getPendingBlockTicks().scheduleTick( pos, getBlockState().getBlock(), 0 ); } @Override - protected void updateTick() + public void blockTick() { if( getWorld().isRemote ) return; - if( m_modemState.pollChanged() ) updateState(); + if( m_modemState.pollChanged() ) updateBlockState(); if( !m_connectionsFormed ) { @@ -267,7 +255,7 @@ protected void updateTick() connectionsChanged(); if( m_peripheralAccessAllowed ) { - for( EnumFacing facing : EnumFacing.VALUES ) + for( EnumFacing facing : DirectionUtil.FACINGS ) { m_peripherals[facing.ordinal()].attach( world, getPos(), facing ); } @@ -282,12 +270,12 @@ private void connectionsChanged() World world = getWorld(); BlockPos current = getPos(); - for( EnumFacing facing : EnumFacing.VALUES ) + for( EnumFacing facing : DirectionUtil.FACINGS ) { BlockPos offset = current.offset( facing ); if( !world.isBlockLoaded( offset ) ) continue; - IWiredElement element = ComputerCraftAPI.getWiredElementAt( world, offset, facing.getOpposite() ); + IWiredElement element = ComputerCraftAPIImpl.INSTANCE.getWiredElementAt( world, offset, facing.getOpposite() ); if( element == null ) continue; // If we can connect to it then do so @@ -300,7 +288,7 @@ private void togglePeripheralAccess() if( !m_peripheralAccessAllowed ) { boolean hasAny = false; - for( EnumFacing facing : EnumFacing.VALUES ) + for( EnumFacing facing : DirectionUtil.FACINGS ) { WiredModemLocalPeripheral peripheral = m_peripherals[facing.ordinal()]; peripheral.attach( world, getPos(), facing ); @@ -320,7 +308,7 @@ private void togglePeripheralAccess() m_node.updatePeripherals( Collections.emptyMap() ); } - updateState(); + updateBlockState(); } private Set getConnectedPeripheralNames() @@ -352,34 +340,27 @@ private void updateConnectedPeripherals() { // If there are no peripherals then disable access and update the display state. m_peripheralAccessAllowed = false; - updateState(); + updateBlockState(); } m_node.updatePeripherals( peripherals ); } - // IWiredElementTile - + @Nonnull @Override - public boolean hasCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + public LazyOptional getCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) { - if( capability == CapabilityWiredElement.CAPABILITY ) return !m_destroyed; - return super.hasCapability( capability, facing ); - } - - @Nullable - @Override - public T getCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) - { - if( capability == CapabilityWiredElement.CAPABILITY ) - { - if( m_destroyed ) return null; - return CapabilityWiredElement.CAPABILITY.cast( m_element ); - } - + if( capability == CapabilityWiredElement.CAPABILITY ) return m_elementCap.cast(); return super.getCapability( capability, facing ); } + public IWiredElement getElement() + { + return m_element; + } + + // IPeripheralTile + @Override public IPeripheral getPeripheral( @Nonnull EnumFacing side ) { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java index 1d90f0200..7159aa5d8 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java @@ -30,8 +30,8 @@ */ public final class WiredModemLocalPeripheral { - private static final String NBT_PERIPHERAL_TYPE = "peripheralType"; - private static final String NBT_PERIPHERAL_ID = "peripheralID"; + private static final String NBT_PERIPHERAL_TYPE = "PeripheralType"; + private static final String NBT_PERIPHERAL_ID = "PeripheralId"; private int id; private String type; @@ -68,7 +68,7 @@ public boolean attach( @Nonnull World world, @Nonnull BlockPos origin, @Nonnull else if( id < 0 || !type.equals( this.type ) ) { this.type = type; - this.id = IDAssigner.getNextIDFromFile( "computer/lastid_" + type + ".txt" ); + this.id = IDAssigner.getNextId( "peripheral." + type ); } return oldPeripheral == null || !oldPeripheral.equals( peripheral ); @@ -116,18 +116,18 @@ public Map toMap() : Collections.singletonMap( type + "_" + id, peripheral ); } - public void writeNBT( @Nonnull NBTTagCompound tag, @Nonnull String suffix ) + public void write( @Nonnull NBTTagCompound tag, @Nonnull String suffix ) { - if( id >= 0 ) tag.setInteger( NBT_PERIPHERAL_TYPE + suffix, id ); - if( type != null ) tag.setString( NBT_PERIPHERAL_TYPE + suffix, type ); + if( id >= 0 ) tag.putInt( NBT_PERIPHERAL_ID + suffix, id ); + if( type != null ) tag.putString( NBT_PERIPHERAL_TYPE + suffix, type ); } - public void readNBT( @Nonnull NBTTagCompound tag, @Nonnull String suffix ) + public void read( @Nonnull NBTTagCompound tag, @Nonnull String suffix ) { - id = tag.hasKey( NBT_PERIPHERAL_ID + suffix, Constants.NBT.TAG_ANY_NUMERIC ) - ? tag.getInteger( NBT_PERIPHERAL_ID + suffix ) : -1; + id = tag.contains( NBT_PERIPHERAL_ID + suffix, Constants.NBT.TAG_ANY_NUMERIC ) + ? tag.getInt( NBT_PERIPHERAL_ID + suffix ) : -1; - type = tag.hasKey( NBT_PERIPHERAL_TYPE + suffix, Constants.NBT.TAG_STRING ) + type = tag.contains( NBT_PERIPHERAL_TYPE + suffix, Constants.NBT.TAG_STRING ) ? tag.getString( NBT_PERIPHERAL_TYPE + suffix ) : null; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockAdvancedModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockAdvancedModem.java deleted file mode 100644 index 1300869a4..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockAdvancedModem.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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.shared.peripheral.modem.wireless; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.common.BlockGeneric; -import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.peripheral.modem.ModemBounds; -import net.minecraft.block.BlockDirectional; -import net.minecraft.block.material.Material; -import net.minecraft.block.properties.PropertyBool; -import net.minecraft.block.properties.PropertyDirection; -import net.minecraft.block.state.BlockFaceShape; -import net.minecraft.block.state.BlockStateContainer; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockAccess; -import net.minecraft.world.World; - -import javax.annotation.Nonnull; - -public class BlockAdvancedModem extends BlockGeneric -{ - public static final PropertyDirection FACING = BlockDirectional.FACING; - private static final PropertyBool ON = PropertyBool.create( "on" ); - - public BlockAdvancedModem() - { - super( Material.ROCK ); - setHardness( 2.0f ); - setTranslationKey( "computercraft:advanced_modem" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - setDefaultState( blockState.getBaseState() - .withProperty( FACING, EnumFacing.NORTH ) - .withProperty( ON, false ) - ); - } - - @Nonnull - @Override - protected BlockStateContainer createBlockState() - { - return new BlockStateContainer( this, FACING, ON ); - } - - @Nonnull - @Override - @Deprecated - public IBlockState getStateFromMeta( int meta ) - { - return getDefaultState().withProperty( FACING, EnumFacing.byIndex( meta ) ); - } - - @Override - public int getMetaFromState( IBlockState state ) - { - return state.getValue( FACING ).getIndex(); - } - - @Nonnull - @Override - @Deprecated - public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos ) - { - TileEntity tile = world.getTileEntity( pos ); - return state.withProperty( ON, tile instanceof TileAdvancedModem && ((TileAdvancedModem) tile).isOn() ); - } - - @Nonnull - @Override - @Deprecated - public IBlockState getStateForPlacement( World worldIn, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer ) - { - return getDefaultState().withProperty( FACING, facing.getOpposite() ); - } - - @Override - protected TileGeneric createTile( IBlockState state ) - { - return new TileAdvancedModem(); - } - - @Override - protected TileGeneric createTile( int damage ) - { - return new TileAdvancedModem(); - } - - @Override - @Deprecated - public final boolean isOpaqueCube( IBlockState state ) - { - return false; - } - - @Override - @Deprecated - public final boolean isFullCube( IBlockState state ) - { - return false; - } - - @Nonnull - @Override - @Deprecated - public BlockFaceShape getBlockFaceShape( IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing side ) - { - return BlockFaceShape.UNDEFINED; - } - - @Nonnull - @Override - @Deprecated - public AxisAlignedBB getBoundingBox( IBlockState state, IBlockAccess source, BlockPos pos ) - { - return ModemBounds.getBounds( state.getValue( FACING ) ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java new file mode 100644 index 000000000..208df3b0e --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java @@ -0,0 +1,112 @@ +/* + * 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.shared.peripheral.modem.wireless; + +import dan200.computercraft.shared.common.BlockGeneric; +import dan200.computercraft.shared.peripheral.modem.ModemShapes; +import dan200.computercraft.shared.util.WaterloggableBlock; +import net.minecraft.block.Block; +import net.minecraft.block.state.BlockFaceShape; +import net.minecraft.block.state.IBlockState; +import net.minecraft.fluid.IFluidState; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.state.BooleanProperty; +import net.minecraft.state.DirectionProperty; +import net.minecraft.state.StateContainer; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorld; +import net.minecraft.world.IWorldReaderBase; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class BlockWirelessModem extends BlockGeneric implements WaterloggableBlock +{ + public static final DirectionProperty FACING = BlockStateProperties.FACING; + public static final BooleanProperty ON = BooleanProperty.create( "on" ); + + public BlockWirelessModem( Properties settings, TileEntityType type ) + { + super( settings, type ); + setDefaultState( getStateContainer().getBaseState() + .with( FACING, EnumFacing.NORTH ) + .with( ON, false ) + .with( WATERLOGGED, false ) ); + } + + @Override + protected void fillStateContainer( StateContainer.Builder builder ) + { + builder.add( FACING, ON, WATERLOGGED ); + } + + @Nonnull + @Override + @Deprecated + public VoxelShape getShape( IBlockState blockState, IBlockReader blockView, BlockPos blockPos ) + { + return ModemShapes.getBounds( blockState.get( FACING ) ); + } + + @Nonnull + @Override + @Deprecated + public IFluidState getFluidState( IBlockState state ) + { + return getWaterloggedFluidState( state ); + } + + @Nonnull + @Override + @Deprecated + public IBlockState updatePostPlacement( @Nonnull IBlockState state, EnumFacing side, IBlockState otherState, IWorld world, BlockPos pos, BlockPos otherPos ) + { + updateWaterloggedPostPlacement( state, world, pos ); + return side == state.get( FACING ) && !state.isValidPosition( world, pos ) + ? state.getFluidState().getBlockState() + : state; + } + + @Override + @Deprecated + public boolean isValidPosition( IBlockState state, IWorldReaderBase world, BlockPos pos ) + { + EnumFacing facing = state.get( FACING ); + BlockPos offsetPos = pos.offset( facing ); + IBlockState offsetState = world.getBlockState( offsetPos ); + return offsetState.getBlockFaceShape( world, offsetPos, facing.getOpposite() ) == BlockFaceShape.SOLID; + } + + @Nullable + @Override + public IBlockState getStateForPlacement( BlockItemUseContext placement ) + { + return getDefaultState() + .with( FACING, placement.getFace().getOpposite() ) + .with( WATERLOGGED, getWaterloggedStateForPlacement( placement ) ); + } + + @Override + @Deprecated + public final boolean isFullCube( IBlockState state ) + { + return false; + } + + @Nonnull + @Override + @Deprecated + public BlockFaceShape getBlockFaceShape( IBlockReader worldIn, IBlockState state, BlockPos pos, EnumFacing face ) + { + return BlockFaceShape.UNDEFINED; + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/ItemAdvancedModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/ItemAdvancedModem.java deleted file mode 100644 index 5e494257e..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/ItemAdvancedModem.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.shared.peripheral.modem.wireless; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.integration.mcmp.MCMPHooks; -import dan200.computercraft.shared.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.common.ItemPeripheralBase; -import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory; -import net.minecraft.block.Block; -import net.minecraft.creativetab.CreativeTabs; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumActionResult; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; -import net.minecraft.util.NonNullList; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public class ItemAdvancedModem extends ItemPeripheralBase -{ - public ItemAdvancedModem( Block block ) - { - super( block ); - setTranslationKey( "computercraft:advanced_modem" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - } - - @Override - public void getSubItems( @Nullable CreativeTabs tabs, @Nonnull NonNullList list ) - { - if( !isInCreativeTab( tabs ) ) return; - list.add( PeripheralItemFactory.create( PeripheralType.AdvancedModem, null, 1 ) ); - } - - @Override - public PeripheralType getPeripheralType( int damage ) - { - return PeripheralType.AdvancedModem; - } - - @Nonnull - @Override - public EnumActionResult onItemUse( EntityPlayer player, World worldIn, @Nonnull BlockPos pos, @Nonnull EnumHand hand, @Nonnull EnumFacing facing, float hitX, float hitY, float hitZ ) - { - EnumActionResult result = MCMPHooks.onItemUse( this, player, worldIn, pos, hand, facing, hitX, hitY, hitZ ); - if( result != EnumActionResult.PASS ) return result; - - return super.onItemUse( player, worldIn, pos, hand, facing, hitX, hitY, hitZ ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileAdvancedModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileAdvancedModem.java deleted file mode 100644 index 374f939b9..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileAdvancedModem.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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.shared.peripheral.modem.wireless; - -import net.minecraft.util.EnumFacing; - -public class TileAdvancedModem extends TileWirelessModemBase -{ - public TileAdvancedModem() - { - super( true ); - } - - @Override - protected EnumFacing getDirection() - { - return getBlockState().getValue( BlockAdvancedModem.FACING ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index f3595013c..9637a225a 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -6,79 +6,144 @@ package dan200.computercraft.shared.peripheral.modem.wireless; -import dan200.computercraft.shared.common.IDirectionalTile; -import dan200.computercraft.shared.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.common.BlockPeripheral; -import dan200.computercraft.shared.peripheral.common.BlockPeripheralVariant; -import dan200.computercraft.shared.peripheral.common.ITilePeripheral; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.shared.common.TileGeneric; +import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; +import dan200.computercraft.shared.peripheral.modem.ModemState; +import dan200.computercraft.shared.util.NamedBlockEntityType; +import dan200.computercraft.shared.util.TickScheduler; import net.minecraft.block.state.IBlockState; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import javax.annotation.Nonnull; -public class TileWirelessModem extends TileWirelessModemBase implements IDirectionalTile, ITilePeripheral +public class TileWirelessModem extends TileGeneric { - public TileWirelessModem() + public static final NamedBlockEntityType FACTORY_NORMAL = NamedBlockEntityType.create( + new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ), + f -> new TileWirelessModem( f, false ) + ); + + public static final NamedBlockEntityType FACTORY_ADVANCED = NamedBlockEntityType.create( + new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ), + f -> new TileWirelessModem( f, true ) + ); + + private static class Peripheral extends WirelessModemPeripheral { - super( false ); + private final TileWirelessModem entity; + + Peripheral( TileWirelessModem entity ) + { + super( new ModemState( () -> TickScheduler.schedule( entity ) ), entity.advanced ); + this.entity = entity; + } + + @Nonnull + @Override + public World getWorld() + { + return entity.getWorld(); + } + + @Nonnull + @Override + public Vec3d getPosition() + { + BlockPos pos = entity.getPos().offset( entity.modemDirection ); + return new Vec3d( pos.getX(), pos.getY(), pos.getZ() ); + } + + @Override + public boolean equals( IPeripheral other ) + { + return this == other || (other instanceof Peripheral && entity == ((Peripheral) other).entity); + } + } + + private final boolean advanced; + + private boolean hasModemDirection = false; + private EnumFacing modemDirection = EnumFacing.DOWN; + private final ModemPeripheral modem; + private boolean destroyed = false; + + public TileWirelessModem( TileEntityType type, boolean advanced ) + { + super( type ); + this.advanced = advanced; + modem = new Peripheral( this ); } @Override - public EnumFacing getDirection() + public void onLoad() { - // Wireless Modem - IBlockState state = getBlockState(); - switch( state.getValue( BlockPeripheral.VARIANT ) ) + super.onLoad(); + updateDirection(); + world.getPendingBlockTicks().scheduleTick( getPos(), getBlockState().getBlock(), 0 ); + } + + @Override + public void destroy() + { + if( !destroyed ) { - case WirelessModemDownOff: - case WirelessModemDownOn: - return EnumFacing.DOWN; - case WirelessModemUpOff: - case WirelessModemUpOn: - return EnumFacing.UP; - default: - return state.getValue( BlockPeripheral.FACING ); + modem.destroy(); + destroyed = true; } } @Override - public void setDirection( EnumFacing dir ) + public void markDirty() { - // Wireless Modem - if( dir == EnumFacing.UP ) + super.markDirty(); + if( world != null ) { - setBlockState( getBlockState() - .withProperty( BlockPeripheral.VARIANT, BlockPeripheralVariant.WirelessModemUpOff ) - .withProperty( BlockPeripheral.FACING, EnumFacing.NORTH ) - ); - } - else if( dir == EnumFacing.DOWN ) - { - setBlockState( getBlockState() - .withProperty( BlockPeripheral.VARIANT, BlockPeripheralVariant.WirelessModemDownOff ) - .withProperty( BlockPeripheral.FACING, EnumFacing.NORTH ) - ); + updateDirection(); } else { - setBlockState( getBlockState() - .withProperty( BlockPeripheral.VARIANT, BlockPeripheralVariant.WirelessModemOff ) - .withProperty( BlockPeripheral.FACING, dir ) - ); + hasModemDirection = false; } } @Override - public boolean shouldRefresh( World world, BlockPos pos, @Nonnull IBlockState oldState, @Nonnull IBlockState newState ) + public void updateContainingBlockInfo() { - return super.shouldRefresh( world, pos, oldState, newState ) || BlockPeripheral.getPeripheralType( newState ) != PeripheralType.WirelessModem; + super.updateContainingBlockInfo(); + hasModemDirection = false; + world.getPendingBlockTicks().scheduleTick( getPos(), getBlockState().getBlock(), 0 ); } @Override - public PeripheralType getPeripheralType() + public void blockTick() { - return PeripheralType.WirelessModem; + updateDirection(); + + if( modem.getModemState().pollChanged() ) updateBlockState(); + } + + private void updateDirection() + { + if( hasModemDirection ) return; + + hasModemDirection = true; + modemDirection = getBlockState().get( BlockWirelessModem.FACING ); + } + + private void updateBlockState() + { + boolean on = modem.getModemState().isOpen(); + IBlockState state = getBlockState(); + if( state.get( BlockWirelessModem.ON ) != on ) + { + getWorld().setBlockState( getPos(), state.with( BlockWirelessModem.ON, on ) ); + } } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModemBase.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModemBase.java deleted file mode 100644 index 108401705..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModemBase.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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.shared.peripheral.modem.wireless; - -import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.api.peripheral.IPeripheralTile; -import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; -import dan200.computercraft.shared.peripheral.modem.ModemState; -import dan200.computercraft.shared.util.TickScheduler; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - -import javax.annotation.Nonnull; - -public abstract class TileWirelessModemBase extends TileGeneric implements IPeripheralTile -{ - protected TileWirelessModemBase( boolean advanced ) - { - this.advanced = advanced; - modem = new Peripheral( this ); // Needs to be initialised after advanced - } - - private static class Peripheral extends WirelessModemPeripheral - { - private final TileWirelessModemBase entity; - - Peripheral( TileWirelessModemBase entity ) - { - super( new ModemState( () -> TickScheduler.schedule( entity ) ), entity.advanced ); - this.entity = entity; - } - - @Nonnull - @Override - public World getWorld() - { - return entity.getWorld(); - } - - @Nonnull - @Override - public Vec3d getPosition() - { - BlockPos pos = entity.getPos().offset( entity.modemDirection ); - return new Vec3d( pos.getX(), pos.getY(), pos.getZ() ); - } - - @Override - public boolean equals( IPeripheral other ) - { - return this == other; - } - } - - private final boolean advanced; - private boolean hasModemDirection = false; - private EnumFacing modemDirection = EnumFacing.DOWN; - private final ModemPeripheral modem; - private boolean destroyed = false; - - private boolean on = false; - - @Override - public void onLoad() - { - super.onLoad(); - updateDirection(); - world.scheduleUpdate( getPos(), getBlockType(), 0 ); - } - - @Override - public void destroy() - { - if( !destroyed ) - { - modem.destroy(); - destroyed = true; - } - } - - @Override - public void updateContainingBlockInfo() - { - hasModemDirection = false; - super.updateContainingBlockInfo(); - world.scheduleUpdate( getPos(), getBlockType(), 0 ); - } - - @Override - public void updateTick() - { - updateDirection(); - - if( modem.getModemState().pollChanged() ) - { - boolean newOn = modem.getModemState().isOpen(); - if( newOn != on ) - { - on = newOn; - updateBlock(); - } - } - } - - private void updateDirection() - { - if( !hasModemDirection ) - { - hasModemDirection = true; - modemDirection = getDirection(); - } - } - - protected abstract EnumFacing getDirection(); - - @Override - public void onNeighbourChange( @Nonnull BlockPos neighbour ) - { - EnumFacing dir = getDirection(); - if( neighbour.equals( getPos().offset( dir ) ) && !getWorld().isSideSolid( neighbour, dir.getOpposite() ) ) - { - // Drop everything and remove block - getBlock().dropBlockAsItem( getWorld(), getPos(), getBlockState(), 0 ); - getWorld().setBlockToAir( getPos() ); - } - } - - @Override - protected void writeDescription( @Nonnull NBTTagCompound nbt ) - { - super.writeDescription( nbt ); - nbt.setBoolean( "on", on ); - } - - @Override - public final void readDescription( @Nonnull NBTTagCompound nbt ) - { - super.readDescription( nbt ); - on = nbt.getBoolean( "on" ); - updateBlock(); - } - - public boolean isOn() - { - return on; - } - - @Override - public IPeripheral getPeripheral( @Nonnull EnumFacing side ) - { - return !destroyed && side == getDirection() ? modem : null; - } -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java new file mode 100644 index 000000000..40e389323 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java @@ -0,0 +1,101 @@ +/* + * 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.shared.peripheral.monitor; + +import dan200.computercraft.shared.common.BlockGeneric; +import dan200.computercraft.shared.common.TileGeneric; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.item.ItemStack; +import net.minecraft.state.DirectionProperty; +import net.minecraft.state.EnumProperty; +import net.minecraft.state.StateContainer; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class BlockMonitor extends BlockGeneric +{ + public static final DirectionProperty ORIENTATION = DirectionProperty.create( "orientation", + EnumFacing.UP, EnumFacing.DOWN, EnumFacing.NORTH ); + + public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; + + static final EnumProperty STATE = EnumProperty.create( "state", MonitorEdgeState.class ); + + public BlockMonitor( Properties settings, TileEntityType type ) + { + super( settings, type ); + setDefaultState( getStateContainer().getBaseState() + .with( ORIENTATION, EnumFacing.NORTH ) + .with( FACING, EnumFacing.NORTH ) + .with( STATE, MonitorEdgeState.NONE ) ); + } + + @Nonnull + @Override + public BlockRenderLayer getRenderLayer() + { + return BlockRenderLayer.CUTOUT; + } + + @Override + protected void fillStateContainer( StateContainer.Builder builder ) + { + builder.add( ORIENTATION, FACING, STATE ); + } + + @Override + @Nullable + public IBlockState getStateForPlacement( BlockItemUseContext context ) + { + float pitch = context.getPlayer() == null ? 0 : context.getPlayer().rotationPitch; + EnumFacing orientation; + if( pitch > 66.5f ) + { + // If the player is looking down, place it facing upwards + orientation = EnumFacing.UP; + } + else if( pitch < -66.5f ) + { + // If they're looking up, place it down. + orientation = EnumFacing.DOWN; + } + else + { + orientation = EnumFacing.NORTH; + } + + return getDefaultState() + .with( FACING, context.getPlacementHorizontalFacing().getOpposite() ) + .with( ORIENTATION, orientation ); + } + + @Override + public void onBlockPlacedBy( World world, BlockPos pos, IBlockState blockState, @Nullable EntityLivingBase livingEntity, ItemStack itemStack ) + { + super.onBlockPlacedBy( world, pos, blockState, livingEntity, itemStack ); + + TileEntity entity = world.getTileEntity( pos ); + if( entity instanceof TileMonitor && !world.isRemote ) + { + TileMonitor monitor = (TileMonitor) entity; + monitor.contractNeighbours(); + monitor.contract(); + monitor.expand(); + } + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java index 0d64cbf58..d2fb79675 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java @@ -9,8 +9,8 @@ import dan200.computercraft.shared.common.ClientTerminal; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.math.BlockPos; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import java.util.HashSet; import java.util.Iterator; @@ -37,7 +37,7 @@ public TileMonitor getOrigin() return origin; } - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) public void createLists() { if( renderDisplayLists == null ) @@ -46,7 +46,7 @@ public void createLists() for( int i = 0; i < renderDisplayLists.length; i++ ) { - renderDisplayLists[i] = GlStateManager.glGenLists( 1 ); + renderDisplayLists[i] = GlStateManager.genLists( 1 ); } synchronized( allMonitors ) @@ -56,7 +56,7 @@ public void createLists() } } - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) public void destroy() { if( renderDisplayLists != null ) @@ -68,14 +68,14 @@ public void destroy() for( int list : renderDisplayLists ) { - GlStateManager.glDeleteLists( list, 1 ); + GlStateManager.deleteLists( list, 1 ); } renderDisplayLists = null; } } - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) public static void destroyAll() { synchronized( allMonitors ) @@ -87,7 +87,7 @@ public static void destroyAll() { for( int list : monitor.renderDisplayLists ) { - GlStateManager.glDeleteLists( list, 1 ); + GlStateManager.deleteLists( list, 1 ); } monitor.renderDisplayLists = null; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java new file mode 100644 index 000000000..00b60f65c --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java @@ -0,0 +1,75 @@ +/* + * 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.shared.peripheral.monitor; + +import net.minecraft.util.IStringSerializable; + +import javax.annotation.Nonnull; + +import static dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState.Flags.*; + +public enum MonitorEdgeState implements IStringSerializable +{ + NONE( "none", 0 ), + + L( "l", LEFT ), + R( "r", RIGHT ), + LR( "lr", LEFT | RIGHT ), + U( "u", UP ), + D( "d", DOWN ), + + UD( "ud", UP | DOWN ), + RD( "rd", RIGHT | DOWN ), + LD( "ld", LEFT | DOWN ), + RU( "ru", RIGHT | UP ), + LU( "lu", LEFT | UP ), + + LRD( "lrd", LEFT | RIGHT | DOWN ), + RUD( "rud", RIGHT | UP | DOWN ), + LUD( "lud", LEFT | UP | DOWN ), + LRU( "lru", LEFT | RIGHT | UP ), + LRUD( "lrud", LEFT | RIGHT | UP | DOWN ); + + private final String name; + private final int flags; + + MonitorEdgeState( String name, int flags ) + { + this.name = name; + this.flags = flags; + } + + private static final MonitorEdgeState[] BY_FLAG = new MonitorEdgeState[16]; + + static + { + for( MonitorEdgeState state : values() ) + { + BY_FLAG[state.flags] = state; + } + } + + public static MonitorEdgeState fromConnections( boolean up, boolean down, boolean left, boolean right ) + { + return BY_FLAG[(up ? UP : 0) | (down ? DOWN : 0) | (left ? LEFT : 0) | (right ? RIGHT : 0)]; + } + + @Nonnull + @Override + public String getName() + { + return name; + } + + static final class Flags + { + static final int UP = 1 << 0; + static final int DOWN = 1 << 1; + static final int LEFT = 1 << 2; + static final int RIGHT = 1 << 3; + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 88b48e9f4..47b748f41 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -6,32 +6,40 @@ package dan200.computercraft.shared.peripheral.monitor; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.common.ServerTerminal; import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.common.BlockPeripheral; -import dan200.computercraft.shared.peripheral.common.ITilePeripheral; -import net.minecraft.block.state.IBlockState; +import dan200.computercraft.shared.util.NamedBlockEntityType; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; -import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import javax.annotation.Nonnull; -import java.util.Collections; +import java.util.HashSet; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeripheralTile +public class TileMonitor extends TileGeneric implements IPeripheralTile { + public static final NamedBlockEntityType FACTORY_NORMAL = NamedBlockEntityType.create( + new ResourceLocation( ComputerCraft.MOD_ID, "monitor_normal" ), + f -> new TileMonitor( f, false ) + ); + + public static final NamedBlockEntityType FACTORY_ADVANCED = NamedBlockEntityType.create( + new ResourceLocation( ComputerCraft.MOD_ID, "monitor_advanced" ), + f -> new TileMonitor( f, true ) + ); + public static final double RENDER_BORDER = 2.0 / 16.0; public static final double RENDER_MARGIN = 0.5 / 16.0; public static final double RENDER_PIXEL_SCALE = 1.0 / 64.0; @@ -39,10 +47,17 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph private static final int MAX_WIDTH = 8; private static final int MAX_HEIGHT = 6; + private static final String NBT_X = "XIndex"; + private static final String NBT_Y = "YIndex"; + private static final String NBT_WIDTH = "Width"; + private static final String NBT_HEIGHT = "Height"; + + private final boolean advanced; + private ServerMonitor m_serverMonitor; private ClientMonitor m_clientMonitor; private MonitorPeripheral m_peripheral; - private final Set m_computers = Collections.newSetFromMap( new ConcurrentHashMap<>() ); + private final Set m_computers = new HashSet<>(); private boolean m_destroyed = false; private boolean visiting = false; @@ -52,39 +67,39 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph private int m_xIndex = 0; private int m_yIndex = 0; - private int m_dir = 2; - - private boolean m_advanced; + public TileMonitor( TileEntityType type, boolean advanced ) + { + super( type ); + this.advanced = advanced; + } @Override public void onLoad() { super.onLoad(); - m_advanced = getBlockState().getValue( BlockPeripheral.VARIANT ) - .getPeripheralType() == PeripheralType.AdvancedMonitor; - world.scheduleUpdate( getPos(), getBlockType(), 0 ); + world.getPendingBlockTicks().scheduleTick( getPos(), getBlockState().getBlock(), 0 ); } @Override public void destroy() { + // TODO: Call this before using the block if( m_destroyed ) return; - m_destroyed = true; if( !getWorld().isRemote ) contractNeighbours(); } @Override - public void invalidate() + public void remove() { - super.invalidate(); + super.remove(); if( m_clientMonitor != null && m_xIndex == 0 && m_yIndex == 0 ) m_clientMonitor.destroy(); } @Override - public void onChunkUnload() + public void onChunkUnloaded() { - super.onChunkUnload(); + super.onChunkUnloaded(); if( m_clientMonitor != null && m_xIndex == 0 && m_yIndex == 0 ) m_clientMonitor.destroy(); } @@ -102,29 +117,27 @@ public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, @Nonnull @Override - public NBTTagCompound writeToNBT( NBTTagCompound nbt ) + public NBTTagCompound write( NBTTagCompound tag ) { - nbt.setInteger( "xIndex", m_xIndex ); - nbt.setInteger( "yIndex", m_yIndex ); - nbt.setInteger( "width", m_width ); - nbt.setInteger( "height", m_height ); - nbt.setInteger( "dir", m_dir ); - return super.writeToNBT( nbt ); + tag.putInt( NBT_X, m_xIndex ); + tag.putInt( NBT_Y, m_yIndex ); + tag.putInt( NBT_WIDTH, m_width ); + tag.putInt( NBT_HEIGHT, m_height ); + return super.write( tag ); } @Override - public void readFromNBT( NBTTagCompound nbt ) + public void read( NBTTagCompound tag ) { - super.readFromNBT( nbt ); - m_xIndex = nbt.getInteger( "xIndex" ); - m_yIndex = nbt.getInteger( "yIndex" ); - m_width = nbt.getInteger( "width" ); - m_height = nbt.getInteger( "height" ); - m_dir = nbt.getInteger( "dir" ); + super.read( tag ); + m_xIndex = tag.getInt( NBT_X ); + m_yIndex = tag.getInt( NBT_Y ); + m_width = tag.getInt( NBT_WIDTH ); + m_height = tag.getInt( NBT_HEIGHT ); } @Override - public void updateTick() + public void blockTick() { if( m_xIndex != 0 || m_yIndex != 0 || m_serverMonitor == null ) return; @@ -158,17 +171,10 @@ public void updateTick() public IPeripheral getPeripheral( @Nonnull EnumFacing side ) { createServerMonitor(); // Ensure the monitor is created before doing anything else. - if( m_peripheral == null ) m_peripheral = new MonitorPeripheral( this ); return m_peripheral; } - @Override - public PeripheralType getPeripheralType() - { - return m_advanced ? PeripheralType.AdvancedMonitor : PeripheralType.Monitor; - } - public ServerMonitor getCachedServerMonitor() { return m_serverMonitor; @@ -191,7 +197,7 @@ private ServerMonitor createServerMonitor() if( m_xIndex == 0 && m_yIndex == 0 ) { // If we're the origin, set up the new monitor - m_serverMonitor = new ServerMonitor( m_advanced, this ); + m_serverMonitor = new ServerMonitor( advanced, this ); m_serverMonitor.rebuild(); // And propagate it to child monitors @@ -235,11 +241,11 @@ public ClientMonitor getClientMonitor() protected void writeDescription( @Nonnull NBTTagCompound nbt ) { super.writeDescription( nbt ); - nbt.setInteger( "xIndex", m_xIndex ); - nbt.setInteger( "yIndex", m_yIndex ); - nbt.setInteger( "width", m_width ); - nbt.setInteger( "height", m_height ); - nbt.setInteger( "monitorDir", m_dir ); + + nbt.putInt( NBT_X, m_xIndex ); + nbt.putInt( NBT_Y, m_yIndex ); + nbt.putInt( NBT_WIDTH, m_width ); + nbt.putInt( NBT_HEIGHT, m_height ); if( m_xIndex == 0 && m_yIndex == 0 && m_serverMonitor != null ) { @@ -256,13 +262,11 @@ protected final void readDescription( @Nonnull NBTTagCompound nbt ) int oldYIndex = m_yIndex; int oldWidth = m_width; int oldHeight = m_height; - int oldDir = m_dir; - m_xIndex = nbt.getInteger( "xIndex" ); - m_yIndex = nbt.getInteger( "yIndex" ); - m_width = nbt.getInteger( "width" ); - m_height = nbt.getInteger( "height" ); - m_dir = nbt.getInteger( "monitorDir" ); + m_xIndex = nbt.getInt( NBT_X ); + m_yIndex = nbt.getInt( NBT_Y ); + m_width = nbt.getInt( NBT_WIDTH ); + m_height = nbt.getInt( NBT_HEIGHT ); if( oldXIndex != m_xIndex || oldYIndex != m_yIndex ) { @@ -275,97 +279,53 @@ protected final void readDescription( @Nonnull NBTTagCompound nbt ) if( m_xIndex == 0 && m_yIndex == 0 ) { // If we're the origin terminal then read the description - if( m_clientMonitor == null ) m_clientMonitor = new ClientMonitor( m_advanced, this ); + if( m_clientMonitor == null ) m_clientMonitor = new ClientMonitor( advanced, this ); m_clientMonitor.readDescription( nbt ); } if( oldXIndex != m_xIndex || oldYIndex != m_yIndex || - oldWidth != m_width || oldHeight != m_height || - oldDir != m_dir ) + oldWidth != m_width || oldHeight != m_height ) { // One of our properties has changed, so ensure we redraw the block updateBlock(); } } - // Sizing and placement stuff + private void updateBlockState() + { + getWorld().setBlockState( getPos(), getBlockState() + .with( BlockMonitor.STATE, MonitorEdgeState.fromConnections( + m_yIndex < m_height - 1, m_yIndex > 0, + m_xIndex > 0, m_xIndex < m_width - 1 ) ), 2 ); + } + + // region Sizing and placement stuff public EnumFacing getDirection() { - int dir = getDir() % 6; - switch( dir ) - { - case 2: - return EnumFacing.NORTH; - case 3: - return EnumFacing.SOUTH; - case 4: - return EnumFacing.WEST; - case 5: - return EnumFacing.EAST; - } - return EnumFacing.NORTH; + return getBlockState().get( BlockMonitor.FACING ); } - public int getDir() + public EnumFacing getOrientation() { - return m_dir; - } - - public void setDir( int dir ) - { - m_dir = dir; - markDirty(); + return getBlockState().get( BlockMonitor.ORIENTATION ); } public EnumFacing getFront() { - return m_dir <= 5 ? EnumFacing.byIndex( m_dir ) : m_dir <= 11 ? EnumFacing.DOWN : EnumFacing.UP; + EnumFacing orientation = getOrientation(); + return orientation == EnumFacing.NORTH ? getDirection() : orientation; } public EnumFacing getRight() { - int dir = getDir() % 6; - switch( dir ) - { - case 2: - return EnumFacing.WEST; - case 3: - return EnumFacing.EAST; - case 4: - return EnumFacing.SOUTH; - case 5: - return EnumFacing.NORTH; - } - return EnumFacing.WEST; + return getDirection().rotateYCCW(); } private EnumFacing getDown() { - int dir = getDir(); - if( dir <= 5 ) return EnumFacing.UP; - - switch( dir ) - { - // up facing - case 8: - return EnumFacing.NORTH; - case 9: - return EnumFacing.SOUTH; - case 10: - return EnumFacing.WEST; - case 11: - return EnumFacing.EAST; - // down facing - case 14: - return EnumFacing.SOUTH; - case 15: - return EnumFacing.NORTH; - case 16: - return EnumFacing.EAST; - case 17: - return EnumFacing.WEST; - } - return EnumFacing.NORTH; + EnumFacing orientation = getOrientation(); + if( orientation == EnumFacing.NORTH ) return EnumFacing.UP; + return orientation == EnumFacing.DOWN ? getDirection() : getDirection().getOpposite(); } public int getWidth() @@ -392,6 +352,7 @@ private TileMonitor getSimilarMonitorAt( BlockPos pos ) { if( pos.equals( getPos() ) ) return this; + int y = pos.getY(); World world = getWorld(); if( world == null || !world.isBlockLoaded( pos ) ) return null; @@ -399,8 +360,9 @@ private TileMonitor getSimilarMonitorAt( BlockPos pos ) if( !(tile instanceof TileMonitor) ) return null; TileMonitor monitor = (TileMonitor) tile; - return !monitor.visiting && monitor.getDir() == getDir() && monitor.m_advanced == m_advanced && - !monitor.m_destroyed ? monitor : null; + return !monitor.visiting && !monitor.m_destroyed && advanced == monitor.advanced + && getDirection() == monitor.getDirection() && getOrientation() == monitor.getOrientation() + ? monitor : null; } private TileMonitor getNeighbour( int x, int y ) @@ -449,7 +411,7 @@ private void resize( int width, int height ) // Either delete the current monitor or sync a new one. if( needsTerminal ) { - if( m_serverMonitor == null ) m_serverMonitor = new ServerMonitor( m_advanced, this ); + if( m_serverMonitor == null ) m_serverMonitor = new ServerMonitor( advanced, this ); } else { @@ -473,6 +435,7 @@ private void resize( int width, int height ) monitor.m_width = width; monitor.m_height = height; monitor.m_serverMonitor = m_serverMonitor; + monitor.updateBlockState(); monitor.updateBlock(); } } @@ -534,12 +497,13 @@ private boolean mergeDown() return true; } - public void expand() + @SuppressWarnings( "StatementWithEmptyBody" ) + void expand() { while( mergeLeft() || mergeRight() || mergeUp() || mergeDown() ) ; } - public void contractNeighbours() + void contractNeighbours() { visiting = true; if( m_xIndex > 0 ) @@ -565,7 +529,7 @@ public void contractNeighbours() visiting = false; } - public void contract() + void contract() { int height = m_height; int width = m_width; @@ -580,6 +544,7 @@ public void contract() if( below != null ) below.resize( width, height - 1 ); if( right != null ) right.expand(); if( below != null ) below.expand(); + return; } @@ -627,11 +592,11 @@ public void contract() } } - public void monitorTouched( float xPos, float yPos, float zPos ) + private void monitorTouched( float xPos, float yPos, float zPos ) { - int side = getDir(); - XYPair pair = XYPair.of( xPos, yPos, zPos, side ); - pair = new XYPair( pair.x + m_xIndex, pair.y + m_height - m_yIndex - 1 ); + XYPair pair = XYPair + .of( xPos, yPos, zPos, getDirection(), getOrientation() ) + .add( m_xIndex, m_height - m_yIndex - 1 ); if( pair.x > m_width - RENDER_BORDER || pair.y > m_height - RENDER_BORDER || pair.x < RENDER_BORDER || pair.y < RENDER_BORDER ) { @@ -666,6 +631,7 @@ public void monitorTouched( float xPos, float yPos, float zPos ) } } } + // endregion void addComputer( IComputerAccess computer ) { @@ -677,12 +643,13 @@ void removeComputer( IComputerAccess computer ) m_computers.remove( computer ); } + /* @Nonnull @Override public AxisAlignedBB getRenderBoundingBox() { TileMonitor start = getNeighbour( 0, 0 ); - TileMonitor end = getNeighbour( m_width - 1, m_height - 1 ); + TileMonitor end = getNeighbour( width - 1, height - 1 ); if( start != null && end != null ) { BlockPos startPos = start.getPos(); @@ -701,24 +668,5 @@ public AxisAlignedBB getRenderBoundingBox() return new AxisAlignedBB( pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1 ); } } - - @Override - public boolean shouldRefresh( World world, BlockPos pos, @Nonnull IBlockState oldState, @Nonnull IBlockState newState ) - { - if( super.shouldRefresh( world, pos, oldState, newState ) ) - { - return true; - } - else - { - switch( BlockPeripheral.getPeripheralType( newState ) ) - { - case Monitor: - case AdvancedMonitor: - return false; - default: - return true; - } - } - } + */ } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java index 30096d5ad..2fd92b142 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java @@ -6,6 +6,8 @@ package dan200.computercraft.shared.peripheral.monitor; +import net.minecraft.util.EnumFacing; + public class XYPair { public final float x; @@ -22,36 +24,51 @@ public XYPair add( float x, float y ) return new XYPair( this.x + x, this.y + y ); } - public static XYPair of( float xPos, float yPos, float zPos, int side ) + public static XYPair of( float xPos, float yPos, float zPos, EnumFacing facing, EnumFacing orientation ) { - switch( side ) + switch( orientation ) { - case 2: - return new XYPair( 1 - xPos, 1 - yPos ); - case 3: - return new XYPair( xPos, 1 - yPos ); - case 4: - return new XYPair( zPos, 1 - yPos ); - case 5: - return new XYPair( 1 - zPos, 1 - yPos ); - case 8: - return new XYPair( 1 - xPos, zPos ); - case 9: - return new XYPair( xPos, 1 - zPos ); - case 10: - return new XYPair( zPos, xPos ); - case 11: - return new XYPair( 1 - zPos, 1 - xPos ); - case 14: - return new XYPair( 1 - xPos, 1 - zPos ); - case 15: - return new XYPair( xPos, zPos ); - case 16: - return new XYPair( zPos, 1 - xPos ); - case 17: - return new XYPair( 1 - zPos, xPos ); - default: - return new XYPair( xPos, zPos ); + case NORTH: + switch( facing ) + { + case NORTH: + return new XYPair( 1 - xPos, 1 - yPos ); + case SOUTH: + return new XYPair( xPos, 1 - yPos ); + case WEST: + return new XYPair( zPos, 1 - yPos ); + case EAST: + return new XYPair( 1 - zPos, 1 - yPos ); + } + break; + case DOWN: + switch( facing ) + { + case NORTH: + return new XYPair( 1 - xPos, zPos ); + case SOUTH: + return new XYPair( xPos, 1 - zPos ); + case WEST: + return new XYPair( zPos, xPos ); + case EAST: + return new XYPair( 1 - zPos, 1 - xPos ); + } + break; + case UP: + switch( facing ) + { + case NORTH: + return new XYPair( 1 - xPos, 1 - zPos ); + case SOUTH: + return new XYPair( xPos, zPos ); + case WEST: + return new XYPair( zPos, 1 - xPos ); + case EAST: + return new XYPair( 1 - zPos, xPos ); + } + break; } + + return new XYPair( xPos, zPos ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java new file mode 100644 index 000000000..47d538c97 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java @@ -0,0 +1,85 @@ +/* + * 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.shared.peripheral.printer; + +import dan200.computercraft.shared.common.BlockGeneric; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.item.ItemStack; +import net.minecraft.state.BooleanProperty; +import net.minecraft.state.DirectionProperty; +import net.minecraft.state.StateContainer; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.stats.StatList; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.INameable; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class BlockPrinter extends BlockGeneric +{ + private static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; + static final BooleanProperty TOP = BooleanProperty.create( "top" ); + static final BooleanProperty BOTTOM = BooleanProperty.create( "bottom" ); + + public BlockPrinter( Properties settings ) + { + super( settings, TilePrinter.FACTORY ); + setDefaultState( getStateContainer().getBaseState() + .with( FACING, EnumFacing.NORTH ) + .with( TOP, false ) + .with( BOTTOM, false ) ); + } + + @Override + protected void fillStateContainer( StateContainer.Builder properties ) + { + properties.add( FACING, TOP, BOTTOM ); + } + + @Nullable + @Override + public IBlockState getStateForPlacement( BlockItemUseContext placement ) + { + return getDefaultState().with( FACING, placement.getPlacementHorizontalFacing().getOpposite() ); + } + + @Override + public void harvestBlock( @Nonnull World world, EntityPlayer player, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nullable TileEntity te, ItemStack stack ) + { + if( te instanceof INameable && ((INameable) te).hasCustomName() ) + { + player.addStat( StatList.BLOCK_MINED.get( this ) ); + player.addExhaustion( 0.005F ); + + ItemStack result = new ItemStack( this ); + result.setDisplayName( ((INameable) te).getCustomName() ); + spawnAsEntity( world, pos, result ); + } + else + { + super.harvestBlock( world, player, pos, state, te, stack ); + } + } + + @Override + public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack ) + { + if( stack.hasDisplayName() ) + { + TileEntity tileentity = world.getTileEntity( pos ); + if( tileentity instanceof TilePrinter ) ((TilePrinter) tileentity).customName = stack.getDisplayName(); + } + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java index a1a7af401..7d6eae516 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java @@ -7,11 +7,11 @@ package dan200.computercraft.shared.peripheral.printer; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.Items; import net.minecraft.inventory.Container; import net.minecraft.inventory.IContainerListener; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemDye; import net.minecraft.item.ItemStack; import javax.annotation.Nonnull; @@ -29,25 +29,25 @@ public ContainerPrinter( IInventory playerInventory, TilePrinter printer ) m_lastPrinting = false; // Ink slot - addSlotToContainer( new Slot( m_printer, 0, 13, 35 ) ); + addSlot( new Slot( printer, 0, 13, 35 ) ); // In-tray - for( int x = 0; x < 6; x++ ) addSlotToContainer( new Slot( m_printer, x + 1, 61 + x * 18, 22 ) ); + for( int x = 0; x < 6; x++ ) addSlot( new Slot( printer, x + 1, 61 + x * 18, 22 ) ); // Out-tray - for( int x = 0; x < 6; x++ ) addSlotToContainer( new Slot( m_printer, x + 7, 61 + x * 18, 49 ) ); + for( int x = 0; x < 6; x++ ) addSlot( new Slot( printer, x + 7, 61 + x * 18, 49 ) ); // Player inv for( int y = 0; y < 3; y++ ) { for( int x = 0; x < 9; x++ ) { - addSlotToContainer( new Slot( playerInventory, x + y * 9 + 9, 8 + x * 18, 84 + y * 18 ) ); + addSlot( new Slot( playerInventory, x + y * 9 + 9, 8 + x * 18, 84 + y * 18 ) ); } } // Player hotbar - for( int x = 0; x < 9; x++ ) addSlotToContainer( new Slot( playerInventory, x, 8 + x * 18, 142 ) ); + for( int x = 0; x < 9; x++ ) addSlot( new Slot( playerInventory, x, 8 + x * 18, 142 ) ); } public boolean isPrinting() @@ -74,6 +74,7 @@ public void detectAndSendChanges() if( !m_printer.getWorld().isRemote ) { + // Push the printing state to the client if needed. boolean printing = m_printer.isPrinting(); if( printing != m_lastPrinting ) { @@ -117,7 +118,7 @@ public ItemStack transferStackInSlot( EntityPlayer player, int index ) else { // Transfer from inventory to printer - if( stack.getItem() == Items.DYE ) + if( stack.getItem() instanceof ItemDye ) { if( !mergeItemStack( stack, 0, 1, false ) ) return ItemStack.EMPTY; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index 2afbe1a2c..6f32d3bef 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -6,32 +6,34 @@ package dan200.computercraft.shared.peripheral.printer; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.network.Containers; -import dan200.computercraft.shared.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.common.BlockPeripheral; -import dan200.computercraft.shared.peripheral.common.TilePeripheralBase; +import dan200.computercraft.shared.util.ColourUtils; import dan200.computercraft.shared.util.DefaultSidedInventory; +import dan200.computercraft.shared.util.NamedBlockEntityType; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; +import net.minecraft.inventory.ItemStackHelper; +import net.minecraft.item.EnumDyeColor; import net.minecraft.item.Item; +import net.minecraft.item.ItemDye; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextComponentTranslation; -import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.Constants; +import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.InvWrapper; import net.minecraftforge.items.wrapper.SidedInvWrapper; @@ -41,24 +43,36 @@ import static net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; -public class TilePrinter extends TilePeripheralBase implements DefaultSidedInventory +public final class TilePrinter extends TileGeneric implements DefaultSidedInventory, IPeripheralTile { - // Statics + public static final NamedBlockEntityType FACTORY = NamedBlockEntityType.create( + new ResourceLocation( ComputerCraft.MOD_ID, "printer" ), + TilePrinter::new + ); - private static final int[] bottomSlots = new int[] { 7, 8, 9, 10, 11, 12 }; - private static final int[] topSlots = new int[] { 1, 2, 3, 4, 5, 6 }; - private static final int[] sideSlots = new int[] { 0 }; + private static final String NBT_NAME = "CustomName"; + private static final String NBT_PRINTING = "Printing"; + private static final String NBT_PAGE_TITLE = "PageTitle"; - // Members + private static final int[] BOTTOM_SLOTS = new int[] { 7, 8, 9, 10, 11, 12 }; + private static final int[] TOP_SLOTS = new int[] { 1, 2, 3, 4, 5, 6 }; + private static final int[] SIDE_SLOTS = new int[] { 0 }; + + ITextComponent customName; private final NonNullList m_inventory = NonNullList.withSize( 13, ItemStack.EMPTY ); - private final IItemHandlerModifiable m_itemHandlerAll = new InvWrapper( this ); - private IItemHandlerModifiable[] m_itemHandlerSides; + private IItemHandlerModifiable m_itemHandlerAll = new InvWrapper( this ); + private LazyOptional[] m_itemHandlerSides; private final Terminal m_page = new Terminal( ItemPrintout.LINE_MAX_LENGTH, ItemPrintout.LINES_PER_PAGE ); private String m_pageTitle = ""; private boolean m_printing = false; + private TilePrinter() + { + super( FACTORY ); + } + @Override public void destroy() { @@ -75,86 +89,71 @@ public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, } @Override - public void readFromNBT( NBTTagCompound nbt ) + public void read( NBTTagCompound nbt ) { - super.readFromNBT( nbt ); + super.read( nbt ); + + customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; // Read page synchronized( m_page ) { - m_printing = nbt.getBoolean( "printing" ); - m_pageTitle = nbt.getString( "pageTitle" ); + m_printing = nbt.getBoolean( NBT_PRINTING ); + m_pageTitle = nbt.getString( NBT_PAGE_TITLE ); m_page.readFromNBT( nbt ); } // Read inventory synchronized( m_inventory ) { - NBTTagList nbttaglist = nbt.getTagList( "Items", Constants.NBT.TAG_COMPOUND ); - for( int i = 0; i < nbttaglist.tagCount(); i++ ) - { - NBTTagCompound itemTag = nbttaglist.getCompoundTagAt( i ); - int j = itemTag.getByte( "Slot" ) & 0xff; - if( j < m_inventory.size() ) - { - m_inventory.set( j, new ItemStack( itemTag ) ); - } - } + ItemStackHelper.loadAllItems( nbt, m_inventory ); } } @Nonnull @Override - public NBTTagCompound writeToNBT( NBTTagCompound nbt ) + public NBTTagCompound write( NBTTagCompound nbt ) { + if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) ); + // Write page synchronized( m_page ) { - nbt.setBoolean( "printing", m_printing ); - nbt.setString( "pageTitle", m_pageTitle ); + nbt.putBoolean( NBT_PRINTING, m_printing ); + nbt.putString( NBT_PAGE_TITLE, m_pageTitle ); m_page.writeToNBT( nbt ); } // Write inventory synchronized( m_inventory ) { - NBTTagList nbttaglist = new NBTTagList(); - for( int i = 0; i < m_inventory.size(); i++ ) - { - if( !m_inventory.get( i ).isEmpty() ) - { - NBTTagCompound tag = new NBTTagCompound(); - tag.setByte( "Slot", (byte) i ); - m_inventory.get( i ).writeToNBT( tag ); - nbttaglist.appendTag( tag ); - } - } - nbt.setTag( "Items", nbttaglist ); + ItemStackHelper.saveAllItems( nbt, m_inventory ); } - return super.writeToNBT( nbt ); + return super.write( nbt ); } @Override - public final void readDescription( @Nonnull NBTTagCompound nbt ) + protected void writeDescription( @Nonnull NBTTagCompound nbt ) + { + super.writeDescription( nbt ); + if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) ); + } + + @Override + public void readDescription( @Nonnull NBTTagCompound nbt ) { super.readDescription( nbt ); + customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; updateBlock(); } - @Override - public boolean shouldRefresh( World world, BlockPos pos, @Nonnull IBlockState oldState, @Nonnull IBlockState newState ) - { - return super.shouldRefresh( world, pos, oldState, newState ) || BlockPeripheral.getPeripheralType( newState ) != PeripheralType.Printer; - } - public boolean isPrinting() { return m_printing; } // IInventory implementation - @Override public int getSizeInventory() { @@ -187,7 +186,7 @@ public ItemStack removeStackFromSlot( int i ) ItemStack result = m_inventory.get( i ); m_inventory.set( i, ItemStack.EMPTY ); markDirty(); - updateAnim(); + updateBlockState(); return result; } } @@ -205,15 +204,15 @@ public ItemStack decrStackSize( int i, int j ) ItemStack itemstack = m_inventory.get( i ); m_inventory.set( i, ItemStack.EMPTY ); markDirty(); - updateAnim(); + updateBlockState(); return itemstack; } - ItemStack part = m_inventory.get( i ).splitStack( j ); + ItemStack part = m_inventory.get( i ).split( j ); if( m_inventory.get( i ).isEmpty() ) { m_inventory.set( i, ItemStack.EMPTY ); - updateAnim(); + updateBlockState(); } markDirty(); return part; @@ -227,7 +226,7 @@ public void setInventorySlotContents( int i, @Nonnull ItemStack stack ) { m_inventory.set( i, stack ); markDirty(); - updateAnim(); + updateBlockState(); } } @@ -238,7 +237,7 @@ public void clear() { for( int i = 0; i < m_inventory.size(); i++ ) m_inventory.set( i, ItemStack.EMPTY ); markDirty(); - updateAnim(); + updateBlockState(); } } @@ -249,7 +248,7 @@ public boolean isItemValidForSlot( int slot, @Nonnull ItemStack stack ) { return isInk( stack ); } - else if( slot >= topSlots[0] && slot <= topSlots[topSlots.length - 1] ) + else if( slot >= TOP_SLOTS[0] && slot <= TOP_SLOTS[TOP_SLOTS.length - 1] ) { return isPaper( stack ); } @@ -260,30 +259,9 @@ else if( slot >= topSlots[0] && slot <= topSlots[topSlots.length - 1] ) } @Override - public boolean hasCustomName() + public boolean isUsableByPlayer( @Nonnull EntityPlayer playerEntity ) { - return getLabel() != null; - } - - @Nonnull - @Override - public String getName() - { - String label = getLabel(); - return label != null ? label : "tile.computercraft:printer.name"; - } - - @Nonnull - @Override - public ITextComponent getDisplayName() - { - return hasCustomName() ? new TextComponentString( getName() ) : new TextComponentTranslation( getName() ); - } - - @Override - public boolean isUsableByPlayer( @Nonnull EntityPlayer player ) - { - return isUsable( player, false ); + return isUsable( playerEntity, false ); } // ISidedInventory implementation @@ -295,11 +273,11 @@ public int[] getSlotsForFace( @Nonnull EnumFacing side ) switch( side ) { case DOWN: // Bottom (Out tray) - return bottomSlots; + return BOTTOM_SLOTS; case UP: // Top (In tray) - return topSlots; + return TOP_SLOTS; default: // Sides (Ink) - return sideSlots; + return SIDE_SLOTS; } } @@ -374,13 +352,14 @@ public void setPageTitle( String title ) private static boolean isInk( @Nonnull ItemStack stack ) { - return stack.getItem() == Items.DYE; + return stack.getItem() instanceof ItemDye; } private static boolean isPaper( @Nonnull ItemStack stack ) { Item item = stack.getItem(); - return item == Items.PAPER || item instanceof ItemPrintout && ItemPrintout.getType( stack ) == ItemPrintout.Type.Single; + return item == Items.PAPER + || (item instanceof ItemPrintout && ((ItemPrintout) item).getType() == ItemPrintout.Type.PAGE); } private boolean canInputPage() @@ -405,8 +384,8 @@ private boolean inputPage() if( !paperStack.isEmpty() && isPaper( paperStack ) ) { // Setup the new page - int colour = inkStack.getItemDamage(); - m_page.setTextColour( colour >= 0 && colour < 16 ? 15 - colour : 15 ); + EnumDyeColor dye = ColourUtils.getStackColour( inkStack ); + m_page.setTextColour( dye != null ? dye.getId() : 15 ); m_page.clear(); if( paperStack.getItem() instanceof ItemPrintout ) @@ -434,7 +413,7 @@ private boolean inputPage() if( paperStack.isEmpty() ) { m_inventory.set( i, ItemStack.EMPTY ); - updateAnim(); + updateBlockState(); } markDirty(); @@ -462,7 +441,7 @@ private boolean outputPage() ItemStack stack = ItemPrintout.createSingleFromTitleAndText( m_pageTitle, lines, colours ); synchronized( m_inventory ) { - for( int slot : bottomSlots ) + for( int slot : BOTTOM_SLOTS ) { if( m_inventory.get( slot ).isEmpty() ) { @@ -499,17 +478,17 @@ private void ejectContents() } } - private void updateAnim() + private void updateBlockState() { + boolean top = false, bottom = false; synchronized( m_inventory ) { - int anim = 0; for( int i = 1; i < 7; i++ ) { ItemStack stack = m_inventory.get( i ); if( !stack.isEmpty() && isPaper( stack ) ) { - anim += 1; + top = true; break; } } @@ -518,42 +497,80 @@ private void updateAnim() ItemStack stack = m_inventory.get( i ); if( !stack.isEmpty() && isPaper( stack ) ) { - anim += 2; + bottom = true; break; } } - setAnim( anim ); } + + updateBlockState( top, bottom ); + } + + private void updateBlockState( boolean top, boolean bottom ) + { + if( removed ) return; + + IBlockState state = getBlockState(); + if( state.get( BlockPrinter.TOP ) == top & state.get( BlockPrinter.BOTTOM ) == bottom ) return; + + getWorld().setBlockState( getPos(), state.with( BlockPrinter.TOP, top ).with( BlockPrinter.BOTTOM, bottom ) ); + } + + + @SuppressWarnings( { "unchecked", "rawtypes" } ) + @Nonnull + @Override + public LazyOptional getCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + { + if( capability == ITEM_HANDLER_CAPABILITY ) + { + LazyOptional[] handlers = m_itemHandlerSides; + if( handlers == null ) handlers = m_itemHandlerSides = new LazyOptional[6]; + + LazyOptional handler; + if( facing == null ) + { + int i = 6; + handler = handlers[i]; + if( handler == null ) + { + handler = handlers[i] = LazyOptional.of( () -> m_itemHandlerAll ); + } + } + else + { + + int i = facing.ordinal(); + handler = handlers[i]; + if( handler == null ) + { + handler = handlers[i] = LazyOptional.of( () -> new SidedInvWrapper( this, facing ) ); + } + } + + return handler.cast(); + } + + return super.getCapability( capability, facing ); } @Override - public boolean hasCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + public boolean hasCustomName() { - return capability == ITEM_HANDLER_CAPABILITY || super.hasCapability( capability, facing ); + return customName != null; } @Nullable @Override - public T getCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + public ITextComponent getCustomName() { - if( capability == ITEM_HANDLER_CAPABILITY ) - { - if( facing == null ) - { - return ITEM_HANDLER_CAPABILITY.cast( m_itemHandlerAll ); - } - else - { - IItemHandlerModifiable[] handlers = m_itemHandlerSides; - if( handlers == null ) handlers = m_itemHandlerSides = new IItemHandlerModifiable[6]; + return customName; + } - int i = facing.ordinal(); - IItemHandlerModifiable handler = handlers[i]; - if( handler == null ) handler = handlers[i] = new SidedInvWrapper( this, facing ); - - return ITEM_HANDLER_CAPABILITY.cast( handler ); - } - } - return super.getCapability( capability, facing ); + @Nonnull + @Override + public ITextComponent getName() + { + return customName != null ? customName : getBlockState().getBlock().getNameTextComponent(); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java new file mode 100644 index 000000000..d31169fab --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java @@ -0,0 +1,43 @@ +/* + * 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.shared.peripheral.speaker; + +import dan200.computercraft.shared.common.BlockGeneric; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.state.DirectionProperty; +import net.minecraft.state.StateContainer; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.EnumFacing; + +import javax.annotation.Nullable; + +public class BlockSpeaker extends BlockGeneric +{ + private static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; + + public BlockSpeaker( Properties settings ) + { + super( settings, TileSpeaker.FACTORY ); + setDefaultState( getStateContainer().getBaseState() + .with( FACING, EnumFacing.NORTH ) ); + } + + @Override + protected void fillStateContainer( StateContainer.Builder properties ) + { + properties.add( FACING ); + } + + @Nullable + @Override + public IBlockState getStateForPlacement( BlockItemUseContext placement ) + { + return getDefaultState().with( FACING, placement.getPlacementHorizontalFacing().getOpposite() ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index dcc19ccd9..5cc4da1a4 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -13,10 +13,10 @@ import dan200.computercraft.api.peripheral.IPeripheral; import net.minecraft.network.play.server.SPacketCustomSound; import net.minecraft.server.MinecraftServer; +import net.minecraft.state.properties.NoteBlockInstrument; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.ResourceLocationException; import net.minecraft.util.SoundCategory; -import net.minecraft.util.SoundEvent; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; @@ -40,19 +40,7 @@ public void update() public abstract World getWorld(); - public Vec3d getPosition() - { - // FIXME: Should be abstract, but we need this for Plethora compat. We'll - // be able to change this in a few versions as we implement both there. - @SuppressWarnings( "deprecation" ) BlockPos pos = getPos(); - return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); - } - - @Deprecated - public BlockPos getPos() - { - return new BlockPos( getPosition() ); - } + public abstract Vec3d getPosition(); public boolean madeSound( long ticks ) { @@ -87,7 +75,17 @@ public Object[] callMethod( @Nonnull IComputerAccess computerAccess, @Nonnull IL float volume = (float) optReal( args, 1, 1.0 ); float pitch = (float) optReal( args, 2, 1.0 ); - return new Object[] { playSound( context, name, volume, pitch, false ) }; + ResourceLocation identifier; + try + { + identifier = new ResourceLocation( name ); + } + catch( ResourceLocationException e ) + { + throw new LuaException( "Malformed sound name '" + name + "' " ); + } + + return new Object[] { playSound( context, identifier, volume, pitch, false ) }; } case 1: // playNote @@ -105,22 +103,30 @@ private synchronized Object[] playNote( Object[] arguments, ILuaContext context float volume = (float) optReal( arguments, 1, 1.0 ); float pitch = (float) optReal( arguments, 2, 1.0 ); - String noteName = "block.note." + name; + NoteBlockInstrument instrument = null; + for( NoteBlockInstrument testInstrument : NoteBlockInstrument.values() ) + { + if( testInstrument.getName().equalsIgnoreCase( name ) ) + { + instrument = testInstrument; + break; + } + } // Check if the note exists - if( !SoundEvent.REGISTRY.containsKey( new ResourceLocation( noteName ) ) ) + if( instrument == null ) { throw new LuaException( "Invalid instrument, \"" + name + "\"!" ); } // If the resource location for note block notes changes, this method call will need to be updated - boolean success = playSound( context, noteName, volume, (float) Math.pow( 2.0, (pitch - 12.0) / 12.0 ), true ); + boolean success = playSound( context, instrument.getSound().getName(), volume, (float) Math.pow( 2.0, (pitch - 12.0) / 12.0 ), true ); if( success ) m_notesThisTick.incrementAndGet(); return new Object[] { success }; } - private synchronized boolean playSound( ILuaContext context, String name, float volume, float pitch, boolean isNote ) throws LuaException + private synchronized boolean playSound( ILuaContext context, ResourceLocation name, float volume, float pitch, boolean isNote ) throws LuaException { if( m_clock - m_lastPlayTime < TileSpeaker.MIN_TICKS_BETWEEN_SOUNDS && (!isNote || m_clock - m_lastPlayTime != 0 || m_notesThisTick.get() >= ComputerCraft.maxNotesPerTick) ) @@ -134,13 +140,13 @@ private synchronized boolean playSound( ILuaContext context, String name, float Vec3d pos = getPosition(); context.issueMainThreadTask( () -> { - MinecraftServer server = world.getMinecraftServer(); + MinecraftServer server = world.getServer(); if( server == null ) return null; float adjVolume = Math.min( volume, 3.0f ); server.getPlayerList().sendToAllNearExcept( - null, pos.x, pos.y, pos.z, adjVolume > 1.0f ? 16 * adjVolume : 16.0, world.provider.getDimension(), - new SPacketCustomSound( name, SoundCategory.RECORDS, pos.x, pos.y, pos.z, adjVolume, pitch ) + null, pos.x, pos.y, pos.z, adjVolume > 1.0f ? 16 * adjVolume : 16.0, world.dimension.getType(), + new SPacketCustomSound( name, SoundCategory.RECORDS, pos, adjVolume, pitch ) ); return null; } ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java index caaeeccbe..667af245d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java @@ -6,9 +6,14 @@ package dan200.computercraft.shared.peripheral.speaker; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.shared.peripheral.common.TilePeripheralBase; +import dan200.computercraft.api.peripheral.IPeripheralTile; +import dan200.computercraft.shared.common.TileGeneric; +import dan200.computercraft.shared.util.NamedBlockEntityType; import net.minecraft.util.EnumFacing; +import net.minecraft.util.ITickable; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; @@ -16,27 +21,29 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class TileSpeaker extends TilePeripheralBase +public class TileSpeaker extends TileGeneric implements ITickable, IPeripheralTile { - // Statics public static final int MIN_TICKS_BETWEEN_SOUNDS = 1; - // Members + public static final NamedBlockEntityType FACTORY = NamedBlockEntityType.create( + new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ), + TileSpeaker::new + ); + private final SpeakerPeripheral m_peripheral; public TileSpeaker() { + super( FACTORY ); m_peripheral = new Peripheral( this ); } @Override - public void update() + public void tick() { m_peripheral.update(); } - // IPeripheralTile implementation - @Override public IPeripheral getPeripheral( @Nonnull EnumFacing side ) { @@ -72,3 +79,4 @@ public boolean equals( @Nullable IPeripheral other ) } } } + diff --git a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java index 906890b49..078a6ac8c 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java +++ b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java @@ -59,7 +59,7 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O // equipBack return context.executeMainThreadTask( () -> { - Entity entity = m_computer.getValidEntity(); + Entity entity = m_computer.getEntity(); if( !(entity instanceof EntityPlayer) ) return new Object[] { false, "Cannot find player" }; EntityPlayer player = (EntityPlayer) entity; InventoryPlayer inventory = player.inventory; @@ -98,7 +98,7 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O // unequipBack return context.executeMainThreadTask( () -> { - Entity entity = m_computer.getValidEntity(); + Entity entity = m_computer.getEntity(); if( !(entity instanceof EntityPlayer) ) return new Object[] { false, "Cannot find player" }; EntityPlayer player = (EntityPlayer) entity; InventoryPlayer inventory = player.inventory; 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 491bdaca1..8008f8714 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -31,6 +31,8 @@ import java.util.Collections; import java.util.Map; +import static dan200.computercraft.shared.pocket.items.ItemPocketComputer.NBT_LIGHT; + public class PocketServerComputer extends ServerComputer implements IPocketAccess { private IPocketUpgrade m_upgrade; @@ -46,25 +48,18 @@ public PocketServerComputer( World world, int computerID, String label, int inst @Override @Deprecated public Entity getEntity() - { - return m_entity; - } - - @Nullable - @Override - public Entity getValidEntity() { Entity entity = m_entity; - if( entity == null || m_stack == null || entity.isDead ) return null; + if( entity == null || m_stack == null || entity.removed ) return null; - if( m_entity instanceof EntityPlayer ) + if( entity instanceof EntityPlayer ) { - InventoryPlayer inventory = ((EntityPlayer) m_entity).inventory; + InventoryPlayer inventory = ((EntityPlayer) entity).inventory; return inventory.mainInventory.contains( m_stack ) || inventory.offHandInventory.contains( m_stack ) ? entity : null; } - else if( m_entity instanceof EntityLivingBase ) + else if( entity instanceof EntityLivingBase ) { - EntityLivingBase living = (EntityLivingBase) m_entity; + EntityLivingBase living = (EntityLivingBase) entity; return living.getHeldItemMainhand() == m_stack || living.getHeldItemOffhand() == m_stack ? entity : null; } else @@ -76,7 +71,7 @@ else if( m_entity instanceof EntityLivingBase ) @Override public int getColour() { - return ComputerCraft.Items.pocketComputer.getColour( m_stack ); + return IColouredItem.getColourBasic( m_stack ); } @Override @@ -90,8 +85,7 @@ public void setColour( int colour ) public int getLight() { NBTTagCompound tag = getUserData(); - return tag.hasKey( ItemPocketComputer.NBT_LIGHT, Constants.NBT.TAG_ANY_NUMERIC ) - ? tag.getInteger( ItemPocketComputer.NBT_LIGHT ) : -1; + return tag.contains( NBT_LIGHT, Constants.NBT.TAG_ANY_NUMERIC ) ? tag.getInt( NBT_LIGHT ) : -1; } @Override @@ -100,15 +94,15 @@ public void setLight( int colour ) NBTTagCompound tag = getUserData(); if( colour >= 0 && colour <= 0xFFFFFF ) { - if( !tag.hasKey( ItemPocketComputer.NBT_LIGHT, Constants.NBT.TAG_ANY_NUMERIC ) || tag.getInteger( ItemPocketComputer.NBT_LIGHT ) != colour ) + if( !tag.contains( NBT_LIGHT, Constants.NBT.TAG_ANY_NUMERIC ) || tag.getInt( NBT_LIGHT ) != colour ) { - tag.setInteger( ItemPocketComputer.NBT_LIGHT, colour ); + tag.putInt( NBT_LIGHT, colour ); updateUserData(); } } - else if( tag.hasKey( ItemPocketComputer.NBT_LIGHT, Constants.NBT.TAG_ANY_NUMERIC ) ) + else if( tag.contains( NBT_LIGHT, Constants.NBT.TAG_ANY_NUMERIC ) ) { - tag.removeTag( ItemPocketComputer.NBT_LIGHT ); + tag.remove( NBT_LIGHT ); updateUserData(); } } @@ -160,7 +154,6 @@ public void setUpgrade( IPocketUpgrade upgrade ) { ItemPocketComputer.setUpgrade( m_stack, upgrade ); updateUpgradeNBTData(); - m_upgrade = upgrade; invalidatePeripheral(); } diff --git a/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java index fa79ec289..9619ba9e3 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java @@ -6,10 +6,10 @@ package dan200.computercraft.shared.pocket.inventory; +import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.InputState; -import dan200.computercraft.shared.media.inventory.ContainerHeldItem; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; 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 16680acc5..6cbf405f5 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -14,29 +14,31 @@ import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.shared.PocketUpgrades; import dan200.computercraft.shared.common.IColouredItem; -import dan200.computercraft.shared.computer.blocks.ComputerState; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.items.IComputerItem; import dan200.computercraft.shared.network.Containers; import dan200.computercraft.shared.pocket.apis.PocketAPI; import dan200.computercraft.shared.pocket.core.PocketServerComputer; -import dan200.computercraft.shared.util.StringUtil; import net.minecraft.client.util.ITooltipFlag; -import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.IItemPropertyGetter; import net.minecraft.item.Item; +import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.*; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; -import net.minecraftforge.common.util.Constants; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -44,64 +46,46 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, IColouredItem { - private static final String NBT_UPGRADE = "upgrade"; - private static final String NBT_UPGRADE_INFO = "upgrade_info"; - public static final String NBT_LIGHT = "modemLight"; + private static final String NBT_UPGRADE = "Upgrade"; + private static final String NBT_UPGRADE_INFO = "UpgradeInfo"; + public static final String NBT_LIGHT = "Light"; - private static final String NBT_INSTANCE = "instanceID"; - private static final String NBT_SESSION = "sessionID"; + private static final String NBT_INSTANCE = "Instanceid"; + private static final String NBT_SESSION = "SessionId"; - public ItemPocketComputer() + private final ComputerFamily family; + + public ItemPocketComputer( Properties settings, ComputerFamily family ) { - setMaxStackSize( 1 ); - setHasSubtypes( true ); - setTranslationKey( "computercraft:pocket_computer" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); + super( settings ); + this.family = family; addPropertyOverride( new ResourceLocation( ComputerCraft.MOD_ID, "state" ), COMPUTER_STATE ); addPropertyOverride( new ResourceLocation( ComputerCraft.MOD_ID, "coloured" ), COMPUTER_COLOURED ); } - public ItemStack create( int id, String label, int colour, ComputerFamily family, IPocketUpgrade upgrade ) + public ItemStack create( int id, String label, int colour, IPocketUpgrade upgrade ) { - // Ignore types we can't handle - if( family != ComputerFamily.Normal && family != ComputerFamily.Advanced ) return null; - - // Build the stack - int damage = family == ComputerFamily.Advanced ? 1 : 0; - ItemStack result = new ItemStack( this, 1, damage ); - if( id >= 0 || upgrade != null ) - { - NBTTagCompound compound = new NBTTagCompound(); - if( id >= 0 ) compound.setInteger( NBT_ID, id ); - if( upgrade != null ) compound.setString( NBT_UPGRADE, upgrade.getUpgradeID().toString() ); - result.setTagCompound( compound ); - } - - if( label != null ) result.setStackDisplayName( label ); - if( colour != -1 ) IColouredItem.setColourBasic( result, colour ); - + ItemStack result = new ItemStack( this ); + if( id >= 0 ) result.getOrCreateTag().putInt( NBT_ID, id ); + if( label != null ) result.setDisplayName( new TextComponentString( label ) ); + if( upgrade != null ) result.getOrCreateTag().putString( NBT_UPGRADE, upgrade.getUpgradeID().toString() ); + if( colour != -1 ) result.getOrCreateTag().putInt( NBT_COLOUR, colour ); return result; } @Override - public void getSubItems( @Nonnull CreativeTabs tabs, @Nonnull NonNullList list ) + public void fillItemGroup( @Nonnull ItemGroup group, @Nonnull NonNullList stacks ) { - if( !isInCreativeTab( tabs ) ) return; - getSubItems( list, ComputerFamily.Normal ); - getSubItems( list, ComputerFamily.Advanced ); - } - - private static void getSubItems( NonNullList list, ComputerFamily family ) - { - list.add( PocketComputerItemFactory.create( -1, null, -1, family, null ) ); + if( !isInGroup( group ) ) return; + stacks.add( create( -1, null, -1, null ) ); for( IPocketUpgrade upgrade : PocketUpgrades.getVanillaUpgrades() ) { - list.add( PocketComputerItemFactory.create( -1, null, -1, family, upgrade ) ); + stacks.add( create( -1, null, -1, upgrade ) ); } } @Override - public void onUpdate( ItemStack stack, World world, Entity entity, int slotNum, boolean selected ) + public void inventoryTick( ItemStack stack, World world, Entity entity, int slotNum, boolean selected ) { if( !world.isRemote ) { @@ -176,45 +160,34 @@ public ActionResult onItemRightClick( World world, EntityPlayer playe @Nonnull @Override - public String getTranslationKey( @Nonnull ItemStack stack ) - { - switch( getFamily( stack ) ) - { - case Normal: - default: - return "item.computercraft:pocket_computer"; - case Advanced: - return "item.computercraft:advanced_pocket_computer"; - } - } - - @Nonnull - @Override - public String getItemStackDisplayName( @Nonnull ItemStack stack ) + public ITextComponent getDisplayName( @Nonnull ItemStack stack ) { String baseString = getTranslationKey( stack ); IPocketUpgrade upgrade = getUpgrade( stack ); if( upgrade != null ) { - return StringUtil.translateFormatted( - baseString + ".upgraded.name", - StringUtil.translate( upgrade.getUnlocalisedAdjective() ) + return new TextComponentTranslation( baseString + ".upgraded", + new TextComponentTranslation( upgrade.getUnlocalisedAdjective() ) ); } else { - return StringUtil.translate( baseString + ".name" ); + return super.getDisplayName( stack ); } } @Override - public void addInformation( @Nonnull ItemStack stack, World world, List list, ITooltipFlag flag ) + public void addInformation( @Nonnull ItemStack stack, @Nullable World world, List list, ITooltipFlag flag ) { if( flag.isAdvanced() ) { int id = getComputerID( stack ); - if( id >= 0 ) list.add( StringUtil.translateFormatted( "gui.computercraft.tooltip.computer_id", id ) ); + if( id >= 0 ) + { + list.add( new TextComponentTranslation( "gui.computercraft.tooltip.computer_id", id ) + .applyTextStyle( TextFormatting.GRAY ) ); + } } } @@ -267,7 +240,7 @@ private PocketServerComputer createServerComputer( final World world, IInventory computerID, getLabel( stack ), instanceID, - getFamily( stack ) + getFamily() ); computer.updateValues( entity, stack, getUpgrade( stack ) ); computer.addAPI( new PocketAPI( computer ) ); @@ -308,8 +281,7 @@ private static ClientComputer getClientComputer( @Nonnull ItemStack stack ) private static void setComputerID( @Nonnull ItemStack stack, int computerID ) { - if( !stack.hasTagCompound() ) stack.setTagCompound( new NBTTagCompound() ); - stack.getTagCompound().setInteger( NBT_ID, computerID ); + stack.getOrCreateTag().putInt( NBT_ID, computerID ); } @Override @@ -319,17 +291,9 @@ public String getLabel( @Nonnull ItemStack stack ) } @Override - public ComputerFamily getFamily( @Nonnull ItemStack stack ) + public ComputerFamily getFamily() { - int damage = stack.getItemDamage(); - switch( damage ) - { - case 0: - default: - return ComputerFamily.Normal; - case 1: - return ComputerFamily.Advanced; - } + return family; } @Override @@ -348,7 +312,7 @@ public boolean setLabel( @Nonnull ItemStack stack, String label ) { if( label != null ) { - stack.setStackDisplayName( label ); + stack.setDisplayName( new TextComponentString( label ) ); } else { @@ -370,110 +334,77 @@ public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world ) private static int getInstanceID( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTagCompound(); - return nbt != null && nbt.hasKey( NBT_INSTANCE ) ? nbt.getInteger( NBT_INSTANCE ) : -1; + NBTTagCompound nbt = stack.getTag(); + return nbt != null && nbt.contains( NBT_INSTANCE ) ? nbt.getInt( NBT_INSTANCE ) : -1; } private static void setInstanceID( @Nonnull ItemStack stack, int instanceID ) { - if( !stack.hasTagCompound() ) stack.setTagCompound( new NBTTagCompound() ); - stack.getTagCompound().setInteger( NBT_INSTANCE, instanceID ); + stack.getOrCreateTag().putInt( NBT_INSTANCE, instanceID ); } private static int getSessionID( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTagCompound(); - return nbt != null && nbt.hasKey( NBT_SESSION ) ? nbt.getInteger( NBT_SESSION ) : -1; + NBTTagCompound nbt = stack.getTag(); + return nbt != null && nbt.contains( NBT_SESSION ) ? nbt.getInt( NBT_SESSION ) : -1; } private static void setSessionID( @Nonnull ItemStack stack, int sessionID ) { - if( !stack.hasTagCompound() ) stack.setTagCompound( new NBTTagCompound() ); - stack.getTagCompound().setInteger( NBT_SESSION, sessionID ); + stack.getOrCreateTag().putInt( NBT_SESSION, sessionID ); } - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) public static ComputerState getState( @Nonnull ItemStack stack ) { ClientComputer computer = getClientComputer( stack ); - return computer == null ? ComputerState.Off : computer.getState(); + return computer == null ? ComputerState.OFF : computer.getState(); } - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) public static int getLightState( @Nonnull ItemStack stack ) { ClientComputer computer = getClientComputer( stack ); if( computer != null && computer.isOn() ) { NBTTagCompound computerNBT = computer.getUserData(); - if( computerNBT != null && computerNBT.hasKey( NBT_LIGHT, Constants.NBT.TAG_ANY_NUMERIC ) ) + if( computerNBT != null && computerNBT.contains( NBT_LIGHT ) ) { - return computerNBT.getInteger( NBT_LIGHT ); + return computerNBT.getInt( NBT_LIGHT ); } } return -1; } - public IPocketUpgrade getUpgrade( @Nonnull ItemStack stack ) + public static IPocketUpgrade getUpgrade( @Nonnull ItemStack stack ) { - NBTTagCompound compound = stack.getTagCompound(); - if( compound != null ) - { - if( compound.hasKey( NBT_UPGRADE, Constants.NBT.TAG_STRING ) ) - { - String name = compound.getString( NBT_UPGRADE ); - return PocketUpgrades.get( name ); - } - else if( compound.hasKey( NBT_UPGRADE, Constants.NBT.TAG_ANY_NUMERIC ) ) - { - int id = compound.getInteger( NBT_UPGRADE ); - if( id == 1 ) return ComputerCraft.PocketUpgrades.wirelessModem; - } - } + NBTTagCompound compound = stack.getTag(); + return compound != null && compound.contains( NBT_UPGRADE ) + ? PocketUpgrades.get( compound.getString( NBT_UPGRADE ) ) : null; - return null; } public static void setUpgrade( @Nonnull ItemStack stack, IPocketUpgrade upgrade ) { - NBTTagCompound compound = stack.getTagCompound(); - if( compound == null ) stack.setTagCompound( compound = new NBTTagCompound() ); + NBTTagCompound compound = stack.getOrCreateTag(); if( upgrade == null ) { - compound.removeTag( NBT_UPGRADE ); + compound.remove( NBT_UPGRADE ); } else { - compound.setString( NBT_UPGRADE, upgrade.getUpgradeID().toString() ); + compound.putString( NBT_UPGRADE, upgrade.getUpgradeID().toString() ); } - compound.removeTag( NBT_UPGRADE_INFO ); + compound.remove( NBT_UPGRADE_INFO ); } public static NBTTagCompound getUpgradeInfo( @Nonnull ItemStack stack ) { - NBTTagCompound tag = stack.getTagCompound(); - if( tag == null ) - { - tag = new NBTTagCompound(); - stack.setTagCompound( tag ); - } - - if( tag.hasKey( NBT_UPGRADE_INFO, Constants.NBT.TAG_COMPOUND ) ) - { - return tag.getCompoundTag( NBT_UPGRADE_INFO ); - } - else - { - NBTTagCompound sub = new NBTTagCompound(); - tag.setTag( NBT_UPGRADE_INFO, sub ); - return sub; - } + return stack.getOrCreateChildTag( NBT_UPGRADE_INFO ); } private static final IItemPropertyGetter COMPUTER_STATE = ( stack, world, player ) -> getState( stack ).ordinal(); - - private static final IItemPropertyGetter COMPUTER_COLOURED = ( stack, world, player ) -> - IColouredItem.getColourBasic( stack ) != -1 ? 1 : 0; + private static final IItemPropertyGetter COMPUTER_COLOURED = ( stack, world, player ) -> IColouredItem.getColourBasic( stack ) != -1 ? 1 : 0; } diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java index edc432189..6b64cf578 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java @@ -23,8 +23,9 @@ public static ItemStack create( int id, String label, int colour, ComputerFamily switch( family ) { case Normal: + return ComputerCraft.Items.pocketComputerNormal.create( id, label, colour, upgrade ); case Advanced: - return ComputerCraft.Items.pocketComputer.create( id, label, colour, family, upgrade ); + return ComputerCraft.Items.pocketComputerAdvanced.create( id, label, colour, upgrade ); default: return ItemStack.EMPTY; } diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java index d8c10327f..6fdd707cb 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java @@ -6,11 +6,10 @@ package dan200.computercraft.shared.pocket.peripherals; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.pocket.AbstractPocketUpgrade; import dan200.computercraft.api.pocket.IPocketAccess; -import dan200.computercraft.shared.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory; import dan200.computercraft.shared.peripheral.modem.ModemState; import net.minecraft.entity.Entity; import net.minecraft.util.ResourceLocation; @@ -25,13 +24,10 @@ public class PocketModem extends AbstractPocketUpgrade public PocketModem( boolean advanced ) { super( + new ResourceLocation( "computercraft", advanced ? "wireless_modem_advanced" : "wireless_modem_normal" ), advanced - ? new ResourceLocation( "computercraft", "advanced_modem" ) - : new ResourceLocation( "computercraft", "wireless_modem" ), - PeripheralItemFactory.create( - advanced ? PeripheralType.AdvancedModem : PeripheralType.WirelessModem, - null, 1 - ) + ? ComputerCraft.Blocks.wirelessModemAdvanced + : ComputerCraft.Blocks.wirelessModemNormal ); this.advanced = advanced; } @@ -48,11 +44,11 @@ public void update( @Nonnull IPocketAccess access, @Nullable IPeripheral periphe { if( !(peripheral instanceof PocketModemPeripheral) ) return; - Entity entity = access.getValidEntity(); + Entity entity = access.getEntity(); PocketModemPeripheral modem = (PocketModemPeripheral) peripheral; - if( entity != null ) modem.setLocation( entity.getEntityWorld(), entity.getPositionEyes( 1 ) ); + if( entity != null ) modem.setLocation( entity.getEntityWorld(), entity.getEyePosition( 1 ) ); ModemState state = modem.getModemState(); if( state.pollChanged() ) access.setLight( state.isOpen() ? 0xBA0000 : -1 ); diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java index e025d6d02..65a4e07fd 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java @@ -6,11 +6,10 @@ package dan200.computercraft.shared.pocket.peripherals; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.pocket.AbstractPocketUpgrade; import dan200.computercraft.api.pocket.IPocketAccess; -import dan200.computercraft.shared.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory; import net.minecraft.entity.Entity; import net.minecraft.util.ResourceLocation; @@ -21,10 +20,7 @@ public class PocketSpeaker extends AbstractPocketUpgrade { public PocketSpeaker() { - super( - new ResourceLocation( "computercraft", "speaker" ), - PeripheralItemFactory.create( PeripheralType.Speaker, null, 1 ) - ); + super( new ResourceLocation( "computercraft", "speaker" ), ComputerCraft.Blocks.speaker ); } @Nullable @@ -41,10 +37,10 @@ public void update( @Nonnull IPocketAccess access, @Nullable IPeripheral periphe PocketSpeakerPeripheral speaker = (PocketSpeakerPeripheral) peripheral; - Entity entity = access.getValidEntity(); + Entity entity = access.getEntity(); if( entity != null ) { - speaker.setLocation( entity.getEntityWorld(), entity.getPositionEyes( 1.0f ) ); + speaker.setLocation( entity.getEntityWorld(), entity.getEyePosition( 1 ) ); } speaker.update(); diff --git a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java index 78186299c..76fbac517 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java @@ -6,36 +6,35 @@ package dan200.computercraft.shared.pocket.recipes; -import com.google.gson.JsonObject; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.shared.PocketUpgrades; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory; -import net.minecraft.inventory.InventoryCrafting; +import dan200.computercraft.shared.util.AbstractRecipe; +import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.item.crafting.RecipeSerializers; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; -import net.minecraftforge.common.crafting.IRecipeFactory; -import net.minecraftforge.common.crafting.JsonContext; -import net.minecraftforge.registries.IForgeRegistryEntry; import javax.annotation.Nonnull; -public class PocketComputerUpgradeRecipe extends IForgeRegistryEntry.Impl implements IRecipe +public final class PocketComputerUpgradeRecipe extends AbstractRecipe { + private PocketComputerUpgradeRecipe( ResourceLocation identifier ) + { + super( identifier ); + } + @Override public boolean canFit( int x, int y ) { return x >= 2 && y >= 2; } - @Override - public boolean isDynamic() - { - return true; - } - @Nonnull @Override public ItemStack getRecipeOutput() @@ -44,26 +43,25 @@ public ItemStack getRecipeOutput() } @Override - public boolean matches( @Nonnull InventoryCrafting inventory, @Nonnull World world ) + public boolean matches( @Nonnull IInventory inventory, @Nonnull World world ) { return !getCraftingResult( inventory ).isEmpty(); } @Nonnull @Override - public ItemStack getCraftingResult( @Nonnull InventoryCrafting inventory ) + public ItemStack getCraftingResult( @Nonnull IInventory inventory ) { // Scan the grid for a pocket computer ItemStack computer = ItemStack.EMPTY; int computerX = -1; int computerY = -1; - computer: for( int y = 0; y < inventory.getHeight(); y++ ) { for( int x = 0; x < inventory.getWidth(); x++ ) { - ItemStack item = inventory.getStackInRowAndColumn( x, y ); + ItemStack item = inventory.getStackInSlot( x + y * inventory.getWidth() ); if( !item.isEmpty() && item.getItem() instanceof ItemPocketComputer ) { computer = item; @@ -77,7 +75,7 @@ public ItemStack getCraftingResult( @Nonnull InventoryCrafting inventory ) if( computer.isEmpty() ) return ItemStack.EMPTY; ItemPocketComputer itemComputer = (ItemPocketComputer) computer.getItem(); - if( itemComputer.getUpgrade( computer ) != null ) return ItemStack.EMPTY; + if( ItemPocketComputer.getUpgrade( computer ) != null ) return ItemStack.EMPTY; // Check for upgrades around the item IPocketUpgrade upgrade = null; @@ -85,7 +83,7 @@ public ItemStack getCraftingResult( @Nonnull InventoryCrafting inventory ) { for( int x = 0; x < inventory.getWidth(); x++ ) { - ItemStack item = inventory.getStackInRowAndColumn( x, y ); + ItemStack item = inventory.getStackInSlot( x + y * inventory.getWidth() ); if( x == computerX && y == computerY ) continue; if( x == computerX && y == computerY - 1 ) @@ -103,19 +101,22 @@ else if( !item.isEmpty() ) if( upgrade == null ) return ItemStack.EMPTY; // Construct the new stack - ComputerFamily family = itemComputer.getFamily( computer ); + ComputerFamily family = itemComputer.getFamily(); int computerID = itemComputer.getComputerID( computer ); String label = itemComputer.getLabel( computer ); int colour = itemComputer.getColour( computer ); return PocketComputerItemFactory.create( computerID, label, colour, family, upgrade ); } - public static class Factory implements IRecipeFactory + @Nonnull + @Override + public IRecipeSerializer getSerializer() { - @Override - public IRecipe parse( JsonContext jsonContext, JsonObject jsonObject ) - { - return new PocketComputerUpgradeRecipe(); - } + return SERIALIZER; } + + public static final IRecipeSerializer SERIALIZER = new RecipeSerializers.SimpleSerializer<>( + ComputerCraft.MOD_ID + ":pocket_computer_upgrade", + PocketComputerUpgradeRecipe::new + ); } diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 92703eb2c..66e749df6 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -11,69 +11,69 @@ import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.core.computer.MainThread; +import dan200.computercraft.core.tracking.Tracking; import dan200.computercraft.shared.Config; import dan200.computercraft.shared.command.CommandComputerCraft; +import dan200.computercraft.shared.command.arguments.ArgumentSerializers; +import dan200.computercraft.shared.common.ColourableRecipe; import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.datafix.Fixes; -import dan200.computercraft.shared.integration.charset.IntegrationCharset; +import dan200.computercraft.shared.computer.recipe.ComputerUpgradeRecipe; import dan200.computercraft.shared.media.items.RecordMedia; +import dan200.computercraft.shared.media.recipes.DiskRecipe; +import dan200.computercraft.shared.media.recipes.PrintoutRecipe; import dan200.computercraft.shared.network.Containers; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral; -import dan200.computercraft.shared.turtle.core.TurtlePlayer; -import dan200.computercraft.shared.util.CreativeTabMain; +import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; +import dan200.computercraft.shared.pocket.recipes.PocketComputerUpgradeRecipe; +import dan200.computercraft.shared.turtle.recipes.TurtleRecipe; +import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe; +import dan200.computercraft.shared.util.ImpostorRecipe; +import dan200.computercraft.shared.util.ImpostorShapelessRecipe; import dan200.computercraft.shared.wired.CapabilityWiredElement; -import net.minecraft.command.CommandHandler; -import net.minecraft.creativetab.CreativeTabs; import net.minecraft.inventory.Container; import net.minecraft.item.Item; import net.minecraft.item.ItemRecord; -import net.minecraft.server.MinecraftServer; +import net.minecraft.item.crafting.RecipeSerializers; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityCommandBlock; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.event.entity.player.PlayerContainerEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.client.event.ConfigChangedEvent; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; -import net.minecraftforge.fml.common.network.FMLNetworkEvent; -import net.minecraftforge.fml.common.network.NetworkRegistry; -import net.minecraftforge.fml.common.registry.EntityRegistry; -import pl.asie.charset.ModCharset; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.event.server.FMLServerStartedEvent; +import net.minecraftforge.fml.event.server.FMLServerStartingEvent; +import net.minecraftforge.fml.event.server.FMLServerStoppedEvent; -public class ComputerCraftProxyCommon +@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD ) +public final class ComputerCraftProxyCommon { - public void preInit() + @SubscribeEvent + public static void init( FMLCommonSetupEvent event ) { NetworkHandler.setup(); + Containers.setup(); - ComputerCraft.mainCreativeTab = new CreativeTabMain( CreativeTabs.getNextID() ); - - EntityRegistry.registerModEntity( - new ResourceLocation( ComputerCraft.MOD_ID, "turtle_player" ), TurtlePlayer.class, "turtle_player", - 0, ComputerCraft.instance, Integer.MAX_VALUE, Integer.MAX_VALUE, false - ); - } - - public void init() - { registerProviders(); - NetworkRegistry.INSTANCE.registerGuiHandler( ComputerCraft.instance, Containers.INSTANCE ); - Fixes.register( FMLCommonHandler.instance().getDataFixer() ); - if( Loader.isModLoaded( ModCharset.MODID ) ) IntegrationCharset.register(); - } + RecipeSerializers.register( ColourableRecipe.SERIALIZER ); + RecipeSerializers.register( ComputerUpgradeRecipe.SERIALIZER ); + RecipeSerializers.register( PocketComputerUpgradeRecipe.SERIALIZER ); + RecipeSerializers.register( DiskRecipe.SERIALIZER ); + RecipeSerializers.register( PrintoutRecipe.SERIALIZER ); + RecipeSerializers.register( TurtleRecipe.SERIALIZER ); + RecipeSerializers.register( TurtleUpgradeRecipe.SERIALIZER ); + RecipeSerializers.register( ImpostorShapelessRecipe.SERIALIZER ); + RecipeSerializers.register( ImpostorRecipe.SERIALIZER ); - public static void initServer( MinecraftServer server ) - { - CommandHandler handler = (CommandHandler) server.getCommandManager(); - handler.registerCommand( new CommandComputerCraft() ); + ArgumentSerializers.register(); + + // if( Loader.isModLoaded( ModCharset.MODID ) ) IntegrationCharset.register(); } private static void registerProviders() @@ -111,6 +111,7 @@ private ForgeHandlers() { } + /* @SubscribeEvent public static void onConnectionOpened( FMLNetworkEvent.ClientConnectedToServerEvent event ) { @@ -122,6 +123,7 @@ public static void onConnectionClosed( FMLNetworkEvent.ClientDisconnectionFromSe { ComputerCraft.clientComputerRegistry.reset(); } + */ @SubscribeEvent public static void onClientTick( TickEvent.ClientTickEvent event ) @@ -162,5 +164,27 @@ public static void onContainerOpen( PlayerContainerEvent.Open event ) } } } + + @SubscribeEvent + public static void onServerStarting( FMLServerStartingEvent event ) + { + CommandComputerCraft.register( event.getCommandDispatcher() ); + } + + @SubscribeEvent + public static void onServerStarted( FMLServerStartedEvent event ) + { + ComputerCraft.serverComputerRegistry.reset(); + WirelessNetwork.resetNetworks(); + Tracking.reset(); + } + + @SubscribeEvent + public static void onServerStopped( FMLServerStoppedEvent event ) + { + ComputerCraft.serverComputerRegistry.reset(); + WirelessNetwork.resetNetworks(); + Tracking.reset(); + } } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java index af987204b..1e99819b1 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java +++ b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java @@ -13,8 +13,9 @@ import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntityFurnace; +import net.minecraftforge.event.ForgeEventFactory; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import javax.annotation.Nonnull; @@ -50,7 +51,12 @@ public int refuel( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack currentStac private static int getFuelPerItem( @Nonnull ItemStack stack ) { - return TileEntityFurnace.getItemBurnTime( stack ) * 5 / 100; + int basicBurnTime = stack.getBurnTime(); + int burnTime = ForgeEventFactory.getItemBurnTime( + stack, + basicBurnTime == -1 ? TileEntityFurnace.getBurnTimes().getOrDefault( stack.getItem(), 0 ) : basicBurnTime + ); + return (burnTime * 5) / 100; } @SubscribeEvent diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index bb82977bf..9b9927909 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -21,6 +21,7 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.registries.ForgeRegistries; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -343,13 +344,11 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O if( stack.isEmpty() ) return new Object[] { null }; Item item = stack.getItem(); - String name = Item.REGISTRY.getNameForObject( item ).toString(); - int damage = stack.getItemDamage(); + String name = ForgeRegistries.ITEMS.getKey( item ).toString(); int count = stack.getCount(); Map table = new HashMap<>(); table.put( "name", name ); - table.put( "damage", damage ); table.put( "count", count ); TurtleActionEvent event = new TurtleInspectItemEvent( m_turtle, stack, table ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java index 20a7de977..d16515e3b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.turtle.blocks; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.computer.blocks.BlockComputerBase; import dan200.computercraft.shared.computer.blocks.TileComputerBase; @@ -14,45 +13,58 @@ import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.turtle.items.ITurtleItem; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; -import dan200.computercraft.shared.util.DirectionUtil; -import net.minecraft.block.BlockHorizontal; -import net.minecraft.block.material.Material; -import net.minecraft.block.properties.PropertyDirection; +import dan200.computercraft.shared.util.WaterloggableBlock; +import net.minecraft.block.Block; import net.minecraft.block.state.BlockFaceShape; -import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.projectile.EntityFireball; +import net.minecraft.fluid.IFluidState; +import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; +import net.minecraft.state.DirectionProperty; +import net.minecraft.state.StateContainer; +import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.EnumBlockRenderType; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; -import net.minecraft.world.IBlockAccess; -import net.minecraft.world.World; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.util.math.shapes.VoxelShapes; +import net.minecraft.world.*; import javax.annotation.Nonnull; +import javax.annotation.Nullable; -public class BlockTurtle extends BlockComputerBase +public class BlockTurtle extends BlockComputerBase implements WaterloggableBlock { - public static final PropertyDirection FACING = BlockHorizontal.FACING; + public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; - public BlockTurtle() + private static final VoxelShape DEFAULT_SHAPE = VoxelShapes.create( + 0.125, 0.125, 0.125, + 0.875, 0.875, 0.875 + ); + + public BlockTurtle( Properties settings, ComputerFamily family, TileEntityType type ) { - super( Material.IRON ); - setHardness( 2.5f ); - setTranslationKey( "computercraft:turtle" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - setDefaultState( blockState.getBaseState() - .withProperty( FACING, EnumFacing.NORTH ) + super( settings, family, type ); + setDefaultState( getStateContainer().getBaseState() + .with( FACING, EnumFacing.NORTH ) + .with( WATERLOGGED, false ) ); } + @Override + protected void fillStateContainer( StateContainer.Builder builder ) + { + builder.add( FACING, WATERLOGGED ); + } + @Nonnull @Override @Deprecated @@ -61,13 +73,6 @@ public EnumBlockRenderType getRenderType( IBlockState state ) return EnumBlockRenderType.INVISIBLE; } - @Override - @Deprecated - public boolean isOpaqueCube( IBlockState state ) - { - return false; - } - @Override @Deprecated public boolean isFullCube( IBlockState state ) @@ -78,102 +83,49 @@ public boolean isFullCube( IBlockState state ) @Nonnull @Override @Deprecated - public BlockFaceShape getBlockFaceShape( IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing side ) + public BlockFaceShape getBlockFaceShape( IBlockReader world, IBlockState state, BlockPos pos, EnumFacing side ) { return BlockFaceShape.UNDEFINED; } - @Nonnull - @Override - protected BlockStateContainer createBlockState() - { - return new BlockStateContainer( this, FACING ); - } - @Nonnull @Override @Deprecated - public IBlockState getStateFromMeta( int meta ) - { - return getDefaultState(); - } - - @Override - public int getMetaFromState( IBlockState state ) - { - return 0; - } - - @Nonnull - @Override - @Deprecated - public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos ) - { - return state.withProperty( FACING, getDirection( world, pos ) ); - } - - @Override - protected IBlockState getDefaultBlockState( ComputerFamily family, EnumFacing placedSide ) - { - return getDefaultState(); - } - - @Nonnull - @Override - @Deprecated - public AxisAlignedBB getBoundingBox( IBlockState state, IBlockAccess world, BlockPos pos ) + public VoxelShape getShape( IBlockState state, IBlockReader world, BlockPos pos ) { TileEntity tile = world.getTileEntity( pos ); Vec3d offset = tile instanceof TileTurtle ? ((TileTurtle) tile).getRenderOffset( 1.0f ) : Vec3d.ZERO; - return new AxisAlignedBB( - offset.x + 0.125, offset.y + 0.125, offset.z + 0.125, - offset.x + 0.875, offset.y + 0.875, offset.z + 0.875 - ); + return offset.equals( Vec3d.ZERO ) ? DEFAULT_SHAPE : DEFAULT_SHAPE.withOffset( offset.x, offset.y, offset.z ); } - private ComputerFamily getFamily() + @Nullable + @Override + public IBlockState getStateForPlacement( BlockItemUseContext placement ) { - if( this == ComputerCraft.Blocks.turtleAdvanced ) - { - return ComputerFamily.Advanced; - } - else - { - return ComputerFamily.Normal; - } + return getDefaultState() + .with( FACING, placement.getPlacementHorizontalFacing() ) + .with( WATERLOGGED, getWaterloggedStateForPlacement( placement ) ); + } + + @Nonnull + @Override + @Deprecated + public IFluidState getFluidState( IBlockState state ) + { + return getWaterloggedFluidState( state ); + } + + @Nonnull + @Override + @Deprecated + public IBlockState updatePostPlacement( @Nonnull IBlockState state, EnumFacing side, IBlockState otherState, IWorld world, BlockPos pos, BlockPos otherPos ) + { + updateWaterloggedPostPlacement( state, world, pos ); + return state; } @Override - public ComputerFamily getFamily( int damage ) - { - return getFamily(); - } - - @Override - public ComputerFamily getFamily( IBlockState state ) - { - return getFamily(); - } - - @Override - protected TileComputerBase createTile( ComputerFamily family ) - { - if( this == ComputerCraft.Blocks.turtleAdvanced ) - { - return new TileTurtleAdvanced(); - } - else if( this == ComputerCraft.Blocks.turtleExpanded ) - { - return new TileTurtleExpanded(); - } - else - { - return new TileTurtle(); - } - } - - @Override - public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, EntityLivingBase player, @Nonnull ItemStack stack ) + public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, @Nullable EntityLivingBase player, @Nonnull ItemStack stack ) { super.onBlockPlacedBy( world, pos, state, player, stack ); @@ -208,22 +160,17 @@ public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, Entit if( overlay != null ) ((TurtleBrain) turtle.getAccess()).setOverlay( overlay ); } } - - // Set direction - EnumFacing dir = DirectionUtil.fromEntityRot( player ); - setDirection( world, pos, dir.getOpposite() ); } @Override - @Deprecated - public float getExplosionResistance( Entity exploder ) + public float getExplosionResistance( IBlockState state, IWorldReader world, BlockPos pos, @Nullable Entity exploder, Explosion explosion ) { if( getFamily() == ComputerFamily.Advanced && (exploder instanceof EntityLivingBase || exploder instanceof EntityFireball) ) { return 2000; } - return super.getExplosionResistance( exploder ); + return super.getExplosionResistance( state, world, pos, exploder, explosion ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java index 4eba4378e..9bb93086b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java @@ -9,12 +9,11 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; -import dan200.computercraft.shared.common.IDirectionalTile; import dan200.computercraft.shared.computer.blocks.IComputerTile; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.Vec3d; -public interface ITurtleTile extends IComputerTile, IDirectionalTile +public interface ITurtleTile extends IComputerTile { int getColour(); 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 fc1482612..50569ee1e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -12,23 +12,25 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; +import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.computer.blocks.ComputerPeripheral; import dan200.computercraft.shared.computer.blocks.ComputerProxy; import dan200.computercraft.shared.computer.blocks.TileComputerBase; import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.Containers; import dan200.computercraft.shared.turtle.apis.TurtleAPI; import dan200.computercraft.shared.turtle.core.TurtleBrain; -import dan200.computercraft.shared.util.DefaultInventory; -import dan200.computercraft.shared.util.InventoryUtil; -import dan200.computercraft.shared.util.RedstoneUtil; -import dan200.computercraft.shared.util.WorldUtil; +import dan200.computercraft.shared.util.*; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; +import net.minecraft.item.EnumDyeColor; +import net.minecraft.item.ItemDye; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.NonNullList; @@ -37,6 +39,7 @@ import net.minecraft.util.math.Vec3d; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.Constants; +import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.InvWrapper; @@ -53,6 +56,16 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default public static final int INVENTORY_WIDTH = 4; public static final int INVENTORY_HEIGHT = 4; + public static final NamedBlockEntityType FACTORY_NORMAL = NamedBlockEntityType.create( + new ResourceLocation( ComputerCraft.MOD_ID, "turtle_normal" ), + type -> new TileTurtle( type, ComputerFamily.Normal ) + ); + + public static final NamedBlockEntityType FACTORY_ADVANCED = NamedBlockEntityType.create( + new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ), + type -> new TileTurtle( type, ComputerFamily.Advanced ) + ); + // Members enum MoveState @@ -65,24 +78,19 @@ enum MoveState private NonNullList m_inventory; private NonNullList m_previousInventory; private final IItemHandlerModifiable m_itemHandler = new InvWrapper( this ); + private final LazyOptional m_itemHandlerCap = LazyOptional.of( () -> m_itemHandler ); private boolean m_inventoryChanged; private TurtleBrain m_brain; private MoveState m_moveState; - private ComputerFamily m_family; - public TileTurtle() - { - this( ComputerFamily.Normal ); - } - - public TileTurtle( ComputerFamily family ) + public TileTurtle( TileEntityType type, ComputerFamily family ) { + super( type, family ); m_inventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); m_previousInventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); m_inventoryChanged = false; m_brain = new TurtleBrain( this ); m_moveState = MoveState.NOT_MOVED; - m_family = family; } public boolean hasMoved() @@ -134,7 +142,7 @@ public void destroy() else { // Just turn off any redstone we had on - for( EnumFacing dir : EnumFacing.VALUES ) + for( EnumFacing dir : DirectionUtil.FACINGS ) { RedstoneUtil.propagateRedstoneOutput( getWorld(), getPos(), dir ); } @@ -160,16 +168,16 @@ public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, ItemStack currentItem = player.getHeldItem( hand ); if( !currentItem.isEmpty() ) { - if( currentItem.getItem() == Items.DYE ) + if( currentItem.getItem() instanceof ItemDye ) { // Dye to change turtle colour if( !getWorld().isRemote ) { - int dye = currentItem.getItemDamage() & 0xf; + EnumDyeColor dye = ((ItemDye) currentItem.getItem()).getDyeColor(); if( m_brain.getDyeColour() != dye ) { m_brain.setDyeColour( dye ); - if( !player.capabilities.isCreativeMode ) + if( !player.isCreative() ) { currentItem.shrink( 1 ); } @@ -185,7 +193,7 @@ else if( currentItem.getItem() == Items.WATER_BUCKET && m_brain.getColour() != - if( m_brain.getColour() != -1 ) { m_brain.setColour( -1 ); - if( !player.capabilities.isCreativeMode ) + if( !player.isCreative() ) { player.setHeldItem( hand, new ItemStack( Items.BUCKET ) ); player.inventory.markDirty(); @@ -219,9 +227,9 @@ protected double getInteractRange( EntityPlayer player ) } @Override - public void update() + public void tick() { - super.update(); + super.tick(); m_brain.update(); synchronized( m_inventory ) { @@ -239,6 +247,11 @@ public void update() } } + @Override + protected void updateBlockState( ComputerState newState ) + { + } + @Override public void onNeighbourChange( @Nonnull BlockPos neighbour ) { @@ -263,21 +276,21 @@ public void notifyMoveEnd() } @Override - public void readFromNBT( NBTTagCompound nbt ) + public void read( NBTTagCompound nbt ) { - super.readFromNBT( nbt ); + super.read( nbt ); // Read inventory - NBTTagList nbttaglist = nbt.getTagList( "Items", Constants.NBT.TAG_COMPOUND ); + NBTTagList nbttaglist = nbt.getList( "Items", Constants.NBT.TAG_COMPOUND ); m_inventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); m_previousInventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); - for( int i = 0; i < nbttaglist.tagCount(); i++ ) + for( int i = 0; i < nbttaglist.size(); i++ ) { - NBTTagCompound tag = nbttaglist.getCompoundTagAt( i ); + NBTTagCompound tag = nbttaglist.getCompound( i ); int slot = tag.getByte( "Slot" ) & 0xff; if( slot < getSizeInventory() ) { - m_inventory.set( slot, new ItemStack( tag ) ); + m_inventory.set( slot, ItemStack.read( tag ) ); m_previousInventory.set( slot, InventoryUtil.copyItem( m_inventory.get( slot ) ) ); } } @@ -288,7 +301,7 @@ public void readFromNBT( NBTTagCompound nbt ) @Nonnull @Override - public NBTTagCompound writeToNBT( NBTTagCompound nbt ) + public NBTTagCompound write( NBTTagCompound nbt ) { // Write inventory NBTTagList nbttaglist = new NBTTagList(); @@ -297,27 +310,27 @@ public NBTTagCompound writeToNBT( NBTTagCompound nbt ) if( !m_inventory.get( i ).isEmpty() ) { NBTTagCompound tag = new NBTTagCompound(); - tag.setByte( "Slot", (byte) i ); - m_inventory.get( i ).writeToNBT( tag ); - nbttaglist.appendTag( tag ); + tag.putByte( "Slot", (byte) i ); + m_inventory.get( i ).write( tag ); + nbttaglist.add( tag ); } } - nbt.setTag( "Items", nbttaglist ); + nbt.put( "Items", nbttaglist ); // Write brain nbt = m_brain.writeToNBT( nbt ); - return super.writeToNBT( nbt ); + return super.write( nbt ); } @Override - protected boolean isPeripheralBlockedOnSide( int localSide ) + protected boolean isPeripheralBlockedOnSide( EnumFacing localSide ) { return hasPeripheralUpgradeOnSide( localSide ); } @Override - protected boolean isRedstoneBlockedOnSide( int localSide ) + protected boolean isRedstoneBlockedOnSide( EnumFacing localSide ) { return false; } @@ -327,13 +340,16 @@ protected boolean isRedstoneBlockedOnSide( int localSide ) @Override public EnumFacing getDirection() { - return m_brain.getDirection(); + return getBlockState().get( BlockTurtle.FACING ); } - @Override public void setDirection( EnumFacing dir ) { - m_brain.setDirection( dir ); + if( dir.getAxis() == EnumFacing.Axis.Y ) dir = EnumFacing.NORTH; + world.setBlockState( pos, getBlockState().with( BlockTurtle.FACING, dir ) ); + updateOutput(); + updateInput(); + onTileEntityChange(); } // ITurtleTile @@ -380,13 +396,6 @@ public float getToolRenderAngle( TurtleSide side, float f ) return m_brain.getToolRenderAngle( side, f ); } - // IComputerTile - @Override - public ComputerFamily getFamily() - { - return m_family; - } - public void setOwningPlayer( GameProfile player ) { m_brain.setOwningPlayer( player ); @@ -460,7 +469,7 @@ public ItemStack decrStackSize( int slot, int count ) return stack; } - ItemStack part = stack.splitStack( count ); + ItemStack part = stack.split( count ); onInventoryDefinitelyChanged(); return part; } @@ -559,15 +568,15 @@ protected void readDescription( @Nonnull NBTTagCompound nbt ) // Privates - private boolean hasPeripheralUpgradeOnSide( int side ) + private boolean hasPeripheralUpgradeOnSide( EnumFacing side ) { ITurtleUpgrade upgrade; switch( side ) { - case 4: + case WEST: upgrade = getUpgrade( TurtleSide.Right ); break; - case 5: + case EAST: upgrade = getUpgrade( TurtleSide.Left ); break; default: @@ -599,20 +608,11 @@ public IItemHandlerModifiable getItemHandler() return m_itemHandler; } + @Nonnull @Override - public boolean hasCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + public LazyOptional getCapability( @Nonnull Capability cap, @Nullable EnumFacing side ) { - return capability == ITEM_HANDLER_CAPABILITY || super.hasCapability( capability, facing ); - } - - @Nullable - @Override - public T getCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) - { - if( capability == ITEM_HANDLER_CAPABILITY ) - { - return ITEM_HANDLER_CAPABILITY.cast( m_itemHandler ); - } - return super.getCapability( capability, facing ); + if( cap == ITEM_HANDLER_CAPABILITY ) return m_itemHandlerCap.cast(); + return super.getCapability( cap, side ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtleAdvanced.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtleAdvanced.java deleted file mode 100644 index 02db45df9..000000000 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtleAdvanced.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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.shared.turtle.blocks; - -import dan200.computercraft.shared.computer.core.ComputerFamily; - -public class TileTurtleAdvanced extends TileTurtle -{ - public TileTurtleAdvanced() - { - super( ComputerFamily.Advanced ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtleExpanded.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtleExpanded.java deleted file mode 100644 index beb8ebe7d..000000000 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtleExpanded.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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.shared.turtle.blocks; - -import dan200.computercraft.shared.computer.core.ComputerFamily; - -public class TileTurtleExpanded extends TileTurtle -{ - public TileTurtleExpanded() - { - super( ComputerFamily.Normal ); - } -} 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 ba28c46eb..b590838ae 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -20,18 +20,21 @@ import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.util.Colour; -import dan200.computercraft.shared.util.ColourUtils; import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.HolidayUtil; import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.MoverType; +import net.minecraft.fluid.IFluidState; +import net.minecraft.init.Particles; import net.minecraft.inventory.IInventory; +import net.minecraft.item.EnumDyeColor; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tags.FluidTags; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EntitySelectors; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; @@ -44,8 +47,20 @@ import java.util.*; import java.util.concurrent.TimeUnit; +import static dan200.computercraft.shared.common.IColouredItem.NBT_COLOUR; +import static dan200.computercraft.shared.util.WaterloggableBlock.WATERLOGGED; + public class TurtleBrain implements ITurtleAccess { + public static final String NBT_RIGHT_UPGRADE = "RightUpgrade"; + public static final String NBT_RIGHT_UPGRADE_DATA = "RightUpgradeNbt"; + public static final String NBT_LEFT_UPGRADE = "LeftUpgrade"; + public static final String NBT_LEFT_UPGRADE_DATA = "LeftUpgradeNbt"; + public static final String NBT_FUEL = "Fuel"; + public static final String NBT_OVERLAY = "Overlay"; + + private static final String NBT_SLOT = "Slot"; + private static final int ANIM_DURATION = 8; private TileTurtle m_owner; @@ -64,7 +79,6 @@ public class TurtleBrain implements ITurtleAccess private int m_colourHex = -1; private ResourceLocation m_overlay = null; - private EnumFacing m_direction = EnumFacing.NORTH; private TurtleAnimation m_animation = TurtleAnimation.None; private int m_animationProgress = 0; private int m_lastAnimationProgress = 0; @@ -134,232 +148,126 @@ public void update() } } + /** + * Read common data for saving and client synchronisation + * + * @param nbt The tag to read from + */ + private void readCommon( NBTTagCompound nbt ) + { + // Read fields + m_colourHex = nbt.contains( NBT_COLOUR ) ? nbt.getInt( NBT_COLOUR ) : -1; + m_fuelLevel = nbt.contains( NBT_FUEL ) ? nbt.getInt( NBT_FUEL ) : 0; + m_overlay = nbt.contains( NBT_OVERLAY ) ? new ResourceLocation( nbt.getString( NBT_OVERLAY ) ) : null; + + // Read upgrades + setUpgrade( TurtleSide.Left, nbt.contains( NBT_LEFT_UPGRADE ) ? TurtleUpgrades.get( nbt.getString( NBT_LEFT_UPGRADE ) ) : null ); + setUpgrade( TurtleSide.Right, nbt.contains( NBT_RIGHT_UPGRADE ) ? TurtleUpgrades.get( nbt.getString( NBT_RIGHT_UPGRADE ) ) : null ); + + // NBT + m_upgradeNBTData.clear(); + if( nbt.contains( NBT_LEFT_UPGRADE_DATA ) ) + { + m_upgradeNBTData.put( TurtleSide.Left, nbt.getCompound( NBT_LEFT_UPGRADE_DATA ).copy() ); + } + if( nbt.contains( NBT_RIGHT_UPGRADE_DATA ) ) + { + m_upgradeNBTData.put( TurtleSide.Right, nbt.getCompound( NBT_RIGHT_UPGRADE_DATA ).copy() ); + } + } + + private void writeCommon( NBTTagCompound nbt ) + { + nbt.putInt( NBT_FUEL, m_fuelLevel ); + if( m_colourHex != -1 ) nbt.putInt( NBT_COLOUR, m_colourHex ); + if( m_overlay != null ) nbt.putString( NBT_OVERLAY, m_overlay.toString() ); + + // Write upgrades + String leftUpgradeId = getUpgradeId( getUpgrade( TurtleSide.Left ) ); + if( leftUpgradeId != null ) nbt.putString( NBT_LEFT_UPGRADE, leftUpgradeId ); + String rightUpgradeId = getUpgradeId( getUpgrade( TurtleSide.Right ) ); + if( rightUpgradeId != null ) nbt.putString( NBT_RIGHT_UPGRADE, rightUpgradeId ); + + // Write upgrade NBT + if( m_upgradeNBTData.containsKey( TurtleSide.Left ) ) + { + nbt.put( NBT_LEFT_UPGRADE_DATA, getUpgradeNBTData( TurtleSide.Left ).copy() ); + } + if( m_upgradeNBTData.containsKey( TurtleSide.Right ) ) + { + nbt.put( NBT_RIGHT_UPGRADE_DATA, getUpgradeNBTData( TurtleSide.Right ).copy() ); + } + } + public void readFromNBT( NBTTagCompound nbt ) { + readCommon( nbt ); + // Read state - m_direction = EnumFacing.byIndex( nbt.getInteger( "dir" ) ); - m_selectedSlot = nbt.getInteger( "selectedSlot" ); - m_fuelLevel = nbt.hasKey( "fuelLevel" ) ? nbt.getInteger( "fuelLevel" ) : 0; + m_selectedSlot = nbt.getInt( NBT_SLOT ); // Read owner - if( nbt.hasKey( "owner", Constants.NBT.TAG_COMPOUND ) ) + if( nbt.contains( "Owner", Constants.NBT.TAG_COMPOUND ) ) { - NBTTagCompound owner = nbt.getCompoundTag( "owner" ); + NBTTagCompound owner = nbt.getCompound( "Owner" ); m_owningPlayer = new GameProfile( - new UUID( owner.getLong( "upper_id" ), owner.getLong( "lower_id" ) ), - owner.getString( "name" ) + new UUID( owner.getLong( "UpperId" ), owner.getLong( "LowerId" ) ), + owner.getString( "Name" ) ); } else { m_owningPlayer = null; } - - // Read colour - m_colourHex = ColourUtils.getHexColour( nbt ); - - // Read overlay - if( nbt.hasKey( "overlay_mod" ) ) - { - String overlayMod = nbt.getString( "overlay_mod" ); - if( nbt.hasKey( "overlay_path" ) ) - { - String overlayPath = nbt.getString( "overlay_path" ); - m_overlay = new ResourceLocation( overlayMod, overlayPath ); - } - else - { - m_overlay = null; - } - } - else - { - m_overlay = null; - } - - // Read upgrades - // (pre-1.4 turtles will have a "subType" variable, newer things will have "leftUpgrade" and "rightUpgrade") - ITurtleUpgrade leftUpgrade = null; - ITurtleUpgrade rightUpgrade = null; - if( nbt.hasKey( "subType" ) ) - { - // Loading a pre-1.4 world - int subType = nbt.getInteger( "subType" ); - if( (subType & 0x1) > 0 ) - { - leftUpgrade = ComputerCraft.TurtleUpgrades.diamondPickaxe; - } - if( (subType & 0x2) > 0 ) - { - rightUpgrade = ComputerCraft.TurtleUpgrades.wirelessModem; - } - } - else - { - // Loading a post-1.4 world - if( nbt.hasKey( "leftUpgrade" ) ) - { - leftUpgrade = nbt.getTagId( "leftUpgrade" ) == Constants.NBT.TAG_STRING - ? TurtleUpgrades.get( nbt.getString( "leftUpgrade" ) ) - : TurtleUpgrades.get( nbt.getShort( "leftUpgrade" ) ); - } - if( nbt.hasKey( "rightUpgrade" ) ) - { - rightUpgrade = nbt.getTagId( "rightUpgrade" ) == Constants.NBT.TAG_STRING - ? TurtleUpgrades.get( nbt.getString( "rightUpgrade" ) ) - : TurtleUpgrades.get( nbt.getShort( "rightUpgrade" ) ); - } - } - setUpgrade( TurtleSide.Left, leftUpgrade ); - setUpgrade( TurtleSide.Right, rightUpgrade ); - - // NBT - m_upgradeNBTData.clear(); - if( nbt.hasKey( "leftUpgradeNBT" ) ) - { - m_upgradeNBTData.put( TurtleSide.Left, nbt.getCompoundTag( "leftUpgradeNBT" ).copy() ); - } - if( nbt.hasKey( "rightUpgradeNBT" ) ) - { - m_upgradeNBTData.put( TurtleSide.Right, nbt.getCompoundTag( "rightUpgradeNBT" ).copy() ); - } } public NBTTagCompound writeToNBT( NBTTagCompound nbt ) { + writeCommon( nbt ); + // Write state - nbt.setInteger( "dir", m_direction.getIndex() ); - nbt.setInteger( "selectedSlot", m_selectedSlot ); - nbt.setInteger( "fuelLevel", m_fuelLevel ); + nbt.putInt( NBT_SLOT, m_selectedSlot ); // Write owner if( m_owningPlayer != null ) { NBTTagCompound owner = new NBTTagCompound(); - nbt.setTag( "owner", owner ); + nbt.put( "Owner", owner ); - owner.setLong( "upper_id", m_owningPlayer.getId().getMostSignificantBits() ); - owner.setLong( "lower_id", m_owningPlayer.getId().getLeastSignificantBits() ); - owner.setString( "name", m_owningPlayer.getName() ); - } - - // Write upgrades - String leftUpgradeID = getUpgradeID( getUpgrade( TurtleSide.Left ) ); - if( leftUpgradeID != null ) nbt.setString( "leftUpgrade", leftUpgradeID ); - String rightUpgradeID = getUpgradeID( getUpgrade( TurtleSide.Right ) ); - if( rightUpgradeID != null ) nbt.setString( "rightUpgrade", rightUpgradeID ); - - // Write colour - if( m_colourHex != -1 ) nbt.setInteger( "colour", m_colourHex ); - - // Write overlay - if( m_overlay != null ) - { - nbt.setString( "overlay_mod", m_overlay.getNamespace() ); - nbt.setString( "overlay_path", m_overlay.getPath() ); - } - - // Write NBT - if( m_upgradeNBTData.containsKey( TurtleSide.Left ) ) - { - nbt.setTag( "leftUpgradeNBT", getUpgradeNBTData( TurtleSide.Left ).copy() ); - } - if( m_upgradeNBTData.containsKey( TurtleSide.Right ) ) - { - nbt.setTag( "rightUpgradeNBT", getUpgradeNBTData( TurtleSide.Right ).copy() ); + owner.putLong( "UpperId", m_owningPlayer.getId().getMostSignificantBits() ); + owner.putLong( "LowerId", m_owningPlayer.getId().getLeastSignificantBits() ); + owner.putString( "Name", m_owningPlayer.getName() ); } return nbt; } - private static String getUpgradeID( ITurtleUpgrade upgrade ) + private static String getUpgradeId( ITurtleUpgrade upgrade ) { return upgrade != null ? upgrade.getUpgradeID().toString() : null; } - public void writeDescription( NBTTagCompound nbt ) - { - // Upgrades - String leftUpgradeID = getUpgradeID( getUpgrade( TurtleSide.Left ) ); - if( leftUpgradeID != null ) nbt.setString( "leftUpgrade", leftUpgradeID ); - String rightUpgradeID = getUpgradeID( getUpgrade( TurtleSide.Right ) ); - if( rightUpgradeID != null ) nbt.setString( "rightUpgrade", rightUpgradeID ); - - // NBT - if( m_upgradeNBTData.containsKey( TurtleSide.Left ) ) - { - nbt.setTag( "leftUpgradeNBT", getUpgradeNBTData( TurtleSide.Left ).copy() ); - } - if( m_upgradeNBTData.containsKey( TurtleSide.Right ) ) - { - nbt.setTag( "rightUpgradeNBT", getUpgradeNBTData( TurtleSide.Right ).copy() ); - } - - // Colour - if( m_colourHex != -1 ) - { - nbt.setInteger( "colour", m_colourHex ); - } - - // Overlay - if( m_overlay != null ) - { - nbt.setString( "overlay_mod", m_overlay.getNamespace() ); - nbt.setString( "overlay_path", m_overlay.getPath() ); - } - - // Animation - nbt.setInteger( "animation", m_animation.ordinal() ); - nbt.setInteger( "direction", m_direction.getIndex() ); - nbt.setInteger( "fuelLevel", m_fuelLevel ); - } - public void readDescription( NBTTagCompound nbt ) { - // Upgrades - setUpgrade( TurtleSide.Left, nbt.hasKey( "leftUpgrade" ) ? TurtleUpgrades.get( nbt.getString( "leftUpgrade" ) ) : null ); - setUpgrade( TurtleSide.Right, nbt.hasKey( "rightUpgrade" ) ? TurtleUpgrades.get( nbt.getString( "rightUpgrade" ) ) : null ); - - // NBT - m_upgradeNBTData.clear(); - if( nbt.hasKey( "leftUpgradeNBT" ) ) - { - m_upgradeNBTData.put( TurtleSide.Left, nbt.getCompoundTag( "leftUpgradeNBT" ).copy() ); - } - if( nbt.hasKey( "rightUpgradeNBT" ) ) - { - m_upgradeNBTData.put( TurtleSide.Right, nbt.getCompoundTag( "rightUpgradeNBT" ).copy() ); - } - - // Colour - m_colourHex = ColourUtils.getHexColour( nbt ); - - // Overlay - if( nbt.hasKey( "overlay_mod" ) && nbt.hasKey( "overlay_path" ) ) - { - String overlayMod = nbt.getString( "overlay_mod" ); - String overlayPath = nbt.getString( "overlay_path" ); - m_overlay = new ResourceLocation( overlayMod, overlayPath ); - } - else - { - m_overlay = null; - } + readCommon( nbt ); // Animation - TurtleAnimation anim = TurtleAnimation.values()[nbt.getInteger( "animation" )]; + TurtleAnimation anim = TurtleAnimation.values()[nbt.getInt( "Animation" )]; if( anim != m_animation && anim != TurtleAnimation.Wait && anim != TurtleAnimation.ShortWait && anim != TurtleAnimation.None ) { - m_animation = TurtleAnimation.values()[nbt.getInteger( "animation" )]; + m_animation = anim; m_animationProgress = 0; m_lastAnimationProgress = 0; } + } - m_direction = EnumFacing.byIndex( nbt.getInteger( "direction" ) ); - m_fuelLevel = nbt.getInteger( "fuelLevel" ); + public void writeDescription( NBTTagCompound nbt ) + { + writeCommon( nbt ); + nbt.putInt( "Animation", m_animation.ordinal() ); } @Nonnull @@ -388,7 +296,7 @@ public boolean teleportTo( @Nonnull World world, @Nonnull BlockPos pos ) World oldWorld = getWorld(); TileTurtle oldOwner = m_owner; BlockPos oldPos = m_owner.getPos(); - Block oldBlock = m_owner.getBlock(); + IBlockState oldBlock = m_owner.getBlockState(); if( oldWorld == world && oldPos.equals( pos ) ) { @@ -402,15 +310,22 @@ public boolean teleportTo( @Nonnull World world, @Nonnull BlockPos pos ) // Ensure we're inside the world border if( !world.getWorldBorder().contains( pos ) ) return false; + IFluidState existingFluid = world.getBlockState( pos ).getFluidState(); + IBlockState newState = oldBlock + // We only mark this as waterlogged when travelling into a source block. This prevents us from spreading + // fluid by creating a new source when moving into a block, causing the next block to be almost full and + // then moving into that. + .with( WATERLOGGED, existingFluid.isTagged( FluidTags.WATER ) && existingFluid.isSource() ); + oldOwner.notifyMoveStart(); try { // Create a new turtle - if( world.setBlockState( pos, oldBlock.getDefaultState(), 0 ) ) + if( world.setBlockState( pos, newState, 0 ) ) { Block block = world.getBlockState( pos ).getBlock(); - if( block == oldBlock ) + if( block == oldBlock.getBlock() ) { TileEntity newTile = world.getTileEntity( pos ); if( newTile instanceof TileTurtle ) @@ -424,7 +339,7 @@ public boolean teleportTo( @Nonnull World world, @Nonnull BlockPos pos ) newTurtle.createServerComputer().setPosition( pos ); // Remove the old turtle - oldWorld.setBlockToAir( oldPos ); + oldWorld.removeBlock( oldPos ); // Make sure everybody knows about it newTurtle.updateBlock(); @@ -435,7 +350,7 @@ public boolean teleportTo( @Nonnull World world, @Nonnull BlockPos pos ) } // Something went wrong, remove the newly created turtle - world.setBlockToAir( pos ); + world.removeBlock( pos ); } } finally @@ -492,20 +407,13 @@ public float getVisualYaw( float f ) @Override public EnumFacing getDirection() { - return m_direction; + return m_owner.getDirection(); } @Override public void setDirection( @Nonnull EnumFacing dir ) { - if( dir.getAxis() == EnumFacing.Axis.Y ) - { - dir = EnumFacing.NORTH; - } - m_direction = dir; - m_owner.updateOutput(); - m_owner.updateInput(); - m_owner.onTileEntityChange(); + m_owner.setDirection( dir ); } @Override @@ -661,19 +569,19 @@ public void setOverlay( ResourceLocation overlay ) } } - public int getDyeColour() + public EnumDyeColor getDyeColour() { - if( m_colourHex == -1 ) return -1; + if( m_colourHex == -1 ) return null; Colour colour = Colour.fromHex( m_colourHex ); - return colour == null ? -1 : colour.ordinal(); + return colour == null ? null : EnumDyeColor.byId( 15 - colour.ordinal() ); } - public void setDyeColour( int dyeColour ) + public void setDyeColour( EnumDyeColor dyeColour ) { int newColour = -1; - if( dyeColour >= 0 && dyeColour < 16 ) + if( dyeColour != null ) { - newColour = Colour.values()[dyeColour].getHex(); + newColour = Colour.values()[15 - dyeColour.getId()].getHex(); } if( m_colourHex != newColour ) { @@ -721,11 +629,7 @@ public GameProfile getOwningPlayer() @Override public ITurtleUpgrade getUpgrade( @Nonnull TurtleSide side ) { - if( m_upgrades.containsKey( side ) ) - { - return m_upgrades.get( side ); - } - return null; + return m_upgrades.get( side ); } @Override @@ -741,6 +645,7 @@ public void setUpgrade( @Nonnull TurtleSide side, ITurtleUpgrade upgrade ) { if( upgrade == null ) return; } + m_upgradeNBTData.remove( side ); // Set new upgrade @@ -764,11 +669,9 @@ public IPeripheral getPeripheral( @Nonnull TurtleSide side ) @Override public NBTTagCompound getUpgradeNBTData( TurtleSide side ) { - if( !m_upgradeNBTData.containsKey( side ) ) - { - m_upgradeNBTData.put( side, new NBTTagCompound() ); - } - return m_upgradeNBTData.get( side ); + NBTTagCompound nbt = m_upgradeNBTData.get( side ); + if( nbt == null ) m_upgradeNBTData.put( side, nbt = new NBTTagCompound() ); + return nbt; } @Override @@ -939,10 +842,10 @@ private void updateAnimation() { case MoveForward: default: - moveDir = m_direction; + moveDir = getDirection(); break; case MoveBack: - moveDir = m_direction.getOpposite(); + moveDir = getDirection().getOpposite(); break; case MoveUp: moveDir = EnumFacing.UP; @@ -1017,8 +920,8 @@ private void updateAnimation() double x = position.x + world.rand.nextGaussian() * 0.1; double y = position.y + 0.5 + world.rand.nextGaussian() * 0.1; double z = position.z + world.rand.nextGaussian() * 0.1; - world.spawnParticle( - EnumParticleTypes.HEART, x, y, z, + world.addParticle( + Particles.HEART, x, y, z, world.rand.nextGaussian() * 0.02, world.rand.nextGaussian() * 0.02, world.rand.nextGaussian() * 0.02 diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java index a7c069a8f..5b5be1263 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java @@ -11,16 +11,13 @@ import dan200.computercraft.api.turtle.TurtleCommandResult; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -import net.minecraftforge.fml.relauncher.ReflectionHelper; import javax.annotation.Nonnull; -import java.lang.reflect.Method; public class TurtleCompareCommand implements ITurtleCommand { @@ -54,6 +51,7 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) if( !lookAtBlock.isAir( lookAtState, world, newPosition ) ) { // Try createStackedBlock first + /* if( !lookAtBlock.hasTileEntity( lookAtState ) ) { try @@ -69,18 +67,19 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { } } + */ // See if the block drops anything with the same ID as itself // (try 5 times to try and beat random number generators) for( int i = 0; i < 5 && lookAtStack.isEmpty(); i++ ) { NonNullList drops = NonNullList.create(); - lookAtBlock.getDrops( drops, world, newPosition, lookAtState, 0 ); + lookAtState.getDrops( drops, world, newPosition, 0 ); if( !drops.isEmpty() ) { for( ItemStack drop : drops ) { - if( drop.getItem() == Item.getItemFromBlock( lookAtBlock ) ) + if( drop.getItem() == lookAtBlock.asItem() ) { lookAtStack = drop; break; @@ -92,36 +91,13 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) // Last resort: roll our own (which will probably be wrong) if( lookAtStack.isEmpty() ) { - Item item = Item.getItemFromBlock( lookAtBlock ); - if( item != null && item.getHasSubtypes() ) - { - lookAtStack = new ItemStack( item, 1, lookAtBlock.getMetaFromState( lookAtState ) ); - } - else - { - lookAtStack = new ItemStack( item, 1, 0 ); - } + lookAtStack = new ItemStack( lookAtBlock ); } } } - // If they're both empty, obviously the same - if( selectedStack.isEmpty() && lookAtStack.isEmpty() ) return TurtleCommandResult.success(); - - // If the items don't match, obviously different. - if( selectedStack.isEmpty() || lookAtStack == null || selectedStack.getItem() != lookAtStack.getItem() ) - { - return TurtleCommandResult.failure(); - } - - // If the damage matches, or the damage doesn't matter, then the same. - if( !selectedStack.getHasSubtypes() || selectedStack.getItemDamage() == lookAtStack.getItemDamage() ) - { - return TurtleCommandResult.success(); - } - - // Otherwise just double check the translation is the same. It's a pretty good guess. - return selectedStack.getTranslationKey().equals( lookAtStack.getTranslationKey() ) + // Compare them + return selectedStack.getItem() == lookAtStack.getItem() ? TurtleCommandResult.success() : TurtleCommandResult.failure(); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java index 1778af0a7..d1f75e761 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java @@ -12,12 +12,13 @@ import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.api.turtle.event.TurtleBlockEvent; import net.minecraft.block.Block; -import net.minecraft.block.properties.IProperty; import net.minecraft.block.state.IBlockState; +import net.minecraft.state.IProperty; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.registries.ForgeRegistries; import javax.annotation.Nonnull; import java.util.HashMap; @@ -51,13 +52,13 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) } Block block = state.getBlock(); + String name = ForgeRegistries.BLOCKS.getKey( block ).toString(); - Map table = new HashMap<>( 3 ); - table.put( "name", Block.REGISTRY.getNameForObject( block ).toString() ); - table.put( "metadata", block.getMetaFromState( state ) ); + Map table = new HashMap<>(); + table.put( "name", name ); Map stateTable = new HashMap<>(); - for( ImmutableMap.Entry, ? extends Comparable> entry : state.getActualState( world, newPosition ).getProperties().entrySet() ) + for( ImmutableMap.Entry, ? extends Comparable> entry : state.getValues().entrySet() ) { IProperty property = entry.getKey(); stateTable.put( property.getName(), getPropertyValue( property, entry.getValue() ) ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java index 839fe0ae6..dfe3dd5c1 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java @@ -14,12 +14,12 @@ import dan200.computercraft.api.turtle.event.TurtleBlockEvent; import dan200.computercraft.shared.TurtlePermissions; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; @@ -56,23 +56,22 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) // Check existing block is air or replaceable IBlockState state = oldWorld.getBlockState( newPosition ); - Block block = state.getBlock(); if( !oldWorld.isAirBlock( newPosition ) && !WorldUtil.isLiquidBlock( oldWorld, newPosition ) && - !block.isReplaceable( oldWorld, newPosition ) ) + !state.getMaterial().isReplaceable() ) { return TurtleCommandResult.failure( "Movement obstructed" ); } // Check there isn't anything in the way - AxisAlignedBB aabb = state.getBoundingBox( oldWorld, oldPosition ); + AxisAlignedBB aabb = getBox( state.getCollisionShape( oldWorld, oldPosition ) ); aabb = aabb.offset( newPosition.getX(), newPosition.getY(), newPosition.getZ() ); - if( !oldWorld.checkNoEntityCollision( aabb ) ) + if( !oldWorld.checkNoEntityCollision( null, aabb ) ) { if( !ComputerCraft.turtlesCanPush || m_direction == MoveDirection.Up || m_direction == MoveDirection.Down ) { @@ -80,10 +79,10 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) } // Check there is space for all the pushable entities to be pushed - List list = oldWorld.getEntitiesWithinAABB( Entity.class, aabb, x -> x != null && !x.isDead && x.preventEntitySpawning ); + List list = oldWorld.getEntitiesWithinAABB( Entity.class, aabb, x -> x != null && x.isAlive() && x.preventEntitySpawning ); for( Entity entity : list ) { - AxisAlignedBB entityBB = entity.getEntityBoundingBox(); + AxisAlignedBB entityBB = entity.getBoundingBox(); if( entityBB == null ) entityBB = entity.getCollisionBoundingBox(); if( entityBB == null ) continue; @@ -92,7 +91,7 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) direction.getYOffset(), direction.getZOffset() ); - if( !oldWorld.getCollisionBoxes( null, pushedBB ).isEmpty() ) + if( !oldWorld.checkNoEntityCollision( null, pushedBB ) ) { return TurtleCommandResult.failure( "Movement obstructed" ); } @@ -139,11 +138,11 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) private static TurtleCommandResult canEnter( TurtlePlayer turtlePlayer, World world, BlockPos position ) { - if( world.isOutsideBuildHeight( position ) ) + if( World.isOutsideBuildHeight( position ) ) { return TurtleCommandResult.failure( position.getY() < 0 ? "Too low to move" : "Too high to move" ); } - if( !world.isValid( position ) ) return TurtleCommandResult.failure( "Cannot leave the world" ); + if( !World.isValid( position ) ) return TurtleCommandResult.failure( "Cannot leave the world" ); // Check spawn protection if( ComputerCraft.turtlesObeyBlockProtection && !TurtlePermissions.isBlockEnterable( world, position, turtlePlayer ) ) @@ -159,4 +158,11 @@ private static TurtleCommandResult canEnter( TurtlePlayer turtlePlayer, World wo return TurtleCommandResult.success(); } + + private static AxisAlignedBB getBox( VoxelShape shape ) + { + return shape.isEmpty() ? EMPTY_BOX : shape.getBoundingBox(); + } + + private static final AxisAlignedBB EMPTY_BOX = new AxisAlignedBB( 0, 0, 0, 0, 0, 0 ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index 16fd6e508..463f385d8 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -35,7 +35,7 @@ import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.player.PlayerInteractEvent; -import net.minecraftforge.fml.common.eventhandler.Event; +import net.minecraftforge.eventbus.api.Event; import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; @@ -288,19 +288,20 @@ else if( !remainder.isEmpty() ) } } - private static boolean canDeployOnBlock( @Nonnull ItemStack stack, ITurtleAccess turtle, TurtlePlayer player, BlockPos position, EnumFacing side, boolean allowReplaceable, String[] outErrorMessage ) + private static boolean canDeployOnBlock( @Nonnull BlockItemUseContext context, ITurtleAccess turtle, TurtlePlayer player, BlockPos position, EnumFacing side, boolean allowReplaceable, String[] outErrorMessage ) { World world = turtle.getWorld(); - if( !world.isValid( position ) || world.isAirBlock( position ) || - (stack.getItem() instanceof ItemBlock && WorldUtil.isLiquidBlock( world, position )) ) + if( World.isValid( position ) && + !world.isAirBlock( position ) && + !(context.getItem().getItem() instanceof ItemBlock && WorldUtil.isLiquidBlock( world, position )) ) { return false; } - Block block = world.getBlockState( position ).getBlock(); IBlockState state = world.getBlockState( position ); + Block block = state.getBlock(); - boolean replaceable = block.isReplaceable( world, position ); + boolean replaceable = state.isReplaceable( context ); if( !allowReplaceable && replaceable ) return false; if( ComputerCraft.turtlesObeyBlockProtection ) @@ -317,7 +318,7 @@ private static boolean canDeployOnBlock( @Nonnull ItemStack stack, ITurtleAccess } // Check the block is solid or liquid - return block.canCollideCheck( state, true ); + return block.isCollidable( state ); } @Nonnull @@ -328,11 +329,8 @@ private static ItemStack deployOnBlock( @Nonnull ItemStack stack, ITurtleAccess BlockPos playerPosition = position.offset( side ); orientPlayer( turtle, turtlePlayer, playerPosition, playerDir ); - // Check if there's something suitable to place onto - if( !canDeployOnBlock( stack, turtle, turtlePlayer, position, side, allowReplace, outErrorMessage ) ) - { - return stack; - } + ItemStack stackCopy = stack.copy(); + turtlePlayer.loadInventory( stackCopy ); // Calculate where the turtle would hit the block float hitX = 0.5f + side.getXOffset() * 0.5f; @@ -343,26 +341,32 @@ private static ItemStack deployOnBlock( @Nonnull ItemStack stack, ITurtleAccess hitY = 0.45f; } + // Check if there's something suitable to place onto + ItemUseContext context = new ItemUseContext( turtlePlayer, stackCopy, position, side, hitX, hitY, hitZ ); + if( !canDeployOnBlock( new BlockItemUseContext( context ), turtle, turtlePlayer, position, side, allowReplace, outErrorMessage ) ) + { + return stack; + } + // Load up the turtle's inventory Item item = stack.getItem(); - ItemStack stackCopy = stack.copy(); - turtlePlayer.loadInventory( stackCopy ); // Do the deploying (put everything in the players inventory) boolean placed = false; TileEntity existingTile = turtle.getWorld().getTileEntity( position ); // See PlayerInteractionManager.processRightClickBlock + // TODO: ^ Check we're still consistent. PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock( turtlePlayer, EnumHand.MAIN_HAND, position, side, new Vec3d( hitX, hitY, hitZ ) ); if( !event.isCanceled() ) { - if( item.onItemUseFirst( turtlePlayer, turtle.getWorld(), position, side, hitX, hitY, hitZ, EnumHand.MAIN_HAND ) == EnumActionResult.SUCCESS ) + if( item.onItemUseFirst( stack, context ) == EnumActionResult.SUCCESS ) { placed = true; turtlePlayer.loadInventory( stackCopy ); } else if( event.getUseItem() != Event.Result.DENY && - stackCopy.onItemUse( turtlePlayer, turtle.getWorld(), position, EnumHand.MAIN_HAND, side, hitX, hitY, hitZ ) == EnumActionResult.SUCCESS ) + stackCopy.onItemUse( context ) == EnumActionResult.SUCCESS ) { placed = true; turtlePlayer.loadInventory( stackCopy ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 209eb4503..564033055 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -7,10 +7,12 @@ package dan200.computercraft.shared.turtle.core; import com.mojang.authlib.GameProfile; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; import net.minecraft.entity.IMerchant; import net.minecraft.entity.passive.AbstractHorse; import net.minecraft.inventory.IInventory; @@ -29,21 +31,19 @@ import javax.annotation.Nullable; import java.util.UUID; -public class TurtlePlayer extends FakePlayer +public final class TurtlePlayer extends FakePlayer { public static final GameProfile DEFAULT_PROFILE = new GameProfile( UUID.fromString( "0d0c4ca0-4ff1-11e4-916c-0800200c9a66" ), "[ComputerCraft]" ); - /** - * Construct a TurtlePlayer which exists in the world - * - * @param world The world the player exists in - * @deprecated This is required by {@link Entity}. - */ - @Deprecated - public TurtlePlayer( World world ) + public static final EntityType TYPE = EntityType.Builder.create( TurtlePlayer.class, TurtlePlayer::new ) + .disableSerialization() + .disableSummoning() + .build( ComputerCraft.MOD_ID + ":turtle_player" ); + + private TurtlePlayer( World world ) { super( (WorldServer) world, DEFAULT_PROFILE ); } @@ -159,8 +159,10 @@ public SleepResult trySleep( @Nonnull BlockPos bedLocation ) return SleepResult.OTHER_PROBLEM; } + // TODO: Flesh this out. Or just stub out the connection, like plethora? + @Override - public void openEditSign( TileEntitySign signTile ) + public void openSignEditor( TileEntitySign signTile ) { } @@ -180,7 +182,7 @@ public void displayVillagerTradeGui( IMerchant villager ) } @Override - public void openGuiHorseInventory( AbstractHorse horse, IInventory inventoryIn ) + public void openHorseInventory( AbstractHorse horse, IInventory inventoryIn ) { } @@ -199,10 +201,12 @@ protected void onItemUseFinish() { } + /* @Override public void mountEntityAndWakeUp() { } + */ @Override public void dismountEntity( @Nonnull Entity entity ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java index 4eab4550b..7fd9b598d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java @@ -110,7 +110,7 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) ItemStack leaveStack; if( stack.getCount() > m_quantity ) { - storeStack = stack.splitStack( m_quantity ); + storeStack = stack.split( m_quantity ); leaveStack = stack; } else @@ -125,7 +125,7 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { if( remainder.isEmpty() && leaveStack.isEmpty() ) { - entity.setDead(); + entity.remove(); } else if( remainder.isEmpty() ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java index 3982e7770..66a4fefc6 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java @@ -47,7 +47,7 @@ protected ContainerTurtle( IInventory playerInventory, ITurtleAccess turtle, int { for( int x = 0; x < 4; x++ ) { - addSlotToContainer( new Slot( m_turtle.getInventory(), x + y * 4, turtleInvStartX + 1 + x * 18, playerInvStartY + 1 + y * 18 ) ); + addSlot( new Slot( m_turtle.getInventory(), x + y * 4, turtleInvStartX + 1 + x * 18, playerInvStartY + 1 + y * 18 ) ); } } @@ -56,14 +56,14 @@ protected ContainerTurtle( IInventory playerInventory, ITurtleAccess turtle, int { for( int x = 0; x < 9; x++ ) { - addSlotToContainer( new Slot( playerInventory, x + y * 9 + 9, 8 + x * 18, playerInvStartY + 1 + y * 18 ) ); + addSlot( new Slot( playerInventory, x + y * 9 + 9, 8 + x * 18, playerInvStartY + 1 + y * 18 ) ); } } // Player hotbar for( int x = 0; x < 9; x++ ) { - addSlotToContainer( new Slot( playerInventory, x, 8 + x * 18, playerInvStartY + 3 * 18 + 5 ) ); + addSlot( new Slot( playerInventory, x, 8 + x * 18, playerInvStartY + 3 * 18 + 5 ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java new file mode 100644 index 000000000..33519d2d6 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java @@ -0,0 +1,167 @@ +/* + * 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.shared.turtle.items; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.turtle.ITurtleUpgrade; +import dan200.computercraft.api.turtle.TurtleSide; +import dan200.computercraft.shared.TurtleUpgrades; +import dan200.computercraft.shared.common.IColouredItem; +import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.items.ItemComputerBase; +import dan200.computercraft.shared.turtle.blocks.BlockTurtle; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.TextComponentTranslation; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import static dan200.computercraft.shared.turtle.core.TurtleBrain.*; + +public class ItemTurtle extends ItemComputerBase implements ITurtleItem +{ + public ItemTurtle( BlockTurtle block, Properties settings ) + { + super( block, settings ); + } + + public ItemStack create( int id, String label, int colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, int fuelLevel, ResourceLocation overlay ) + { + // Build the stack + ItemStack stack = new ItemStack( this ); + if( label != null ) stack.setDisplayName( new TextComponentString( label ) ); + if( id >= 0 ) stack.getOrCreateTag().putInt( NBT_ID, id ); + IColouredItem.setColourBasic( stack, colour ); + if( fuelLevel > 0 ) stack.getOrCreateTag().putInt( NBT_FUEL, fuelLevel ); + if( overlay != null ) stack.getOrCreateTag().putString( NBT_OVERLAY, overlay.toString() ); + + if( leftUpgrade != null ) + { + stack.getOrCreateTag().putString( NBT_LEFT_UPGRADE, leftUpgrade.getUpgradeID().toString() ); + } + + if( rightUpgrade != null ) + { + stack.getOrCreateTag().putString( NBT_RIGHT_UPGRADE, rightUpgrade.getUpgradeID().toString() ); + } + + return stack; + } + + @Override + public void fillItemGroup( @Nonnull ItemGroup group, @Nonnull NonNullList list ) + { + if( !isInGroup( group ) ) return; + + ComputerFamily family = getFamily(); + + list.add( create( -1, null, -1, null, null, 0, null ) ); + for( ITurtleUpgrade upgrade : TurtleUpgrades.getVanillaUpgrades() ) + { + if( !TurtleUpgrades.suitableForFamily( family, upgrade ) ) continue; + + list.add( create( -1, null, -1, null, upgrade, 0, null ) ); + } + } + + @Nonnull + @Override + public ITextComponent getDisplayName( @Nonnull ItemStack stack ) + { + String baseString = getTranslationKey( stack ); + ITurtleUpgrade left = getUpgrade( stack, TurtleSide.Left ); + ITurtleUpgrade right = getUpgrade( stack, TurtleSide.Right ); + if( left != null && right != null ) + { + return new TextComponentTranslation( baseString + ".upgraded_twice", + new TextComponentTranslation( right.getUnlocalisedAdjective() ), + new TextComponentTranslation( left.getUnlocalisedAdjective() ) + ); + } + else if( left != null ) + { + return new TextComponentTranslation( baseString + ".upgraded", + new TextComponentTranslation( left.getUnlocalisedAdjective() ) + ); + } + else if( right != null ) + { + return new TextComponentTranslation( baseString + ".upgraded", + new TextComponentTranslation( right.getUnlocalisedAdjective() ) + ); + } + else + { + return new TextComponentTranslation( baseString ); + } + } + + @Nullable + @Override + public String getCreatorModId( ItemStack stack ) + { + // Determine our "creator mod" from the upgrades. We attempt to find the first non-vanilla/non-CC + // upgrade (starting from the left). + + ITurtleUpgrade left = getUpgrade( stack, TurtleSide.Left ); + if( left != null ) + { + String mod = TurtleUpgrades.getOwner( left ); + if( mod != null && !mod.equals( ComputerCraft.MOD_ID ) ) return mod; + } + + ITurtleUpgrade right = getUpgrade( stack, TurtleSide.Right ); + if( right != null ) + { + String mod = TurtleUpgrades.getOwner( right ); + if( mod != null && !mod.equals( ComputerCraft.MOD_ID ) ) return mod; + } + + return super.getCreatorModId( stack ); + } + + @Override + public ItemStack withFamily( @Nonnull ItemStack stack, @Nonnull ComputerFamily family ) + { + return TurtleItemFactory.create( + getComputerID( stack ), getLabel( stack ), + getColour( stack ), family, + getUpgrade( stack, TurtleSide.Left ), getUpgrade( stack, TurtleSide.Right ), + getFuelLevel( stack ), getOverlay( stack ) + ); + } + + @Override + public ITurtleUpgrade getUpgrade( @Nonnull ItemStack stack, @Nonnull TurtleSide side ) + { + NBTTagCompound tag = stack.getTag(); + if( tag == null ) return null; + + String key = side == TurtleSide.Left ? NBT_LEFT_UPGRADE : NBT_RIGHT_UPGRADE; + return tag.contains( key ) ? TurtleUpgrades.get( tag.getString( key ) ) : null; + } + + @Override + public ResourceLocation getOverlay( @Nonnull ItemStack stack ) + { + NBTTagCompound tag = stack.getTag(); + return tag != null && tag.contains( NBT_OVERLAY ) ? new ResourceLocation( tag.getString( NBT_OVERLAY ) ) : null; + } + + @Override + public int getFuelLevel( @Nonnull ItemStack stack ) + { + NBTTagCompound tag = stack.getTag(); + return tag != null && tag.contains( NBT_FUEL ) ? tag.getInt( NBT_FUEL ) : 0; + } +} diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleAdvanced.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleAdvanced.java deleted file mode 100644 index ba4a61f38..000000000 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleAdvanced.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.shared.turtle.items; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import net.minecraft.block.Block; - -public class ItemTurtleAdvanced extends ItemTurtleNormal -{ - public ItemTurtleAdvanced( Block block ) - { - super( block ); - setTranslationKey( "computercraft:advanced_turtle" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - } - - // IComputerItem implementation - - @Override - public ComputerFamily getFamily() - { - return ComputerFamily.Advanced; - } -} diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleBase.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleBase.java deleted file mode 100644 index 6234d0b62..000000000 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleBase.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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.shared.turtle.items; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.turtle.ITurtleUpgrade; -import dan200.computercraft.api.turtle.TurtleSide; -import dan200.computercraft.shared.TurtleUpgrades; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.items.ItemComputerBase; -import dan200.computercraft.shared.util.StringUtil; -import net.minecraft.block.Block; -import net.minecraft.creativetab.CreativeTabs; -import net.minecraft.item.ItemStack; -import net.minecraft.util.NonNullList; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public abstract class ItemTurtleBase extends ItemComputerBase implements ITurtleItem -{ - protected ItemTurtleBase( Block block ) - { - super( block ); - setMaxStackSize( 64 ); - setHasSubtypes( true ); - } - - public abstract ComputerFamily getFamily(); - - @Override - public ComputerFamily getFamily( int damage ) - { - return getFamily(); - } - - @Override - public void getSubItems( @Nullable CreativeTabs tabs, @Nonnull NonNullList list ) - { - if( !isInCreativeTab( tabs ) ) return; - - ComputerFamily family = getFamily(); - - ItemStack normalStack = TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null ); - if( !normalStack.isEmpty() && normalStack.getItem() == this ) list.add( normalStack ); - - for( ITurtleUpgrade upgrade : TurtleUpgrades.getVanillaUpgrades() ) - { - if( !TurtleUpgrades.suitableForFamily( family, upgrade ) ) continue; - - ItemStack stack = TurtleItemFactory.create( -1, null, -1, family, null, upgrade, 0, null ); - if( !stack.isEmpty() && stack.getItem() == this ) list.add( stack ); - } - } - - @Nonnull - @Override - public String getTranslationKey( @Nonnull ItemStack stack ) - { - ComputerFamily family = getFamily( stack ); - switch( family ) - { - case Normal: - default: - return "tile.computercraft:turtle"; - case Advanced: - return "tile.computercraft:advanced_turtle"; - } - } - - @Nonnull - @Override - public String getItemStackDisplayName( @Nonnull ItemStack stack ) - { - String baseString = getTranslationKey( stack ); - ITurtleUpgrade left = getUpgrade( stack, TurtleSide.Left ); - ITurtleUpgrade right = getUpgrade( stack, TurtleSide.Right ); - if( left != null && right != null ) - { - return StringUtil.translateFormatted( - baseString + ".upgraded_twice.name", - StringUtil.translate( right.getUnlocalisedAdjective() ), - StringUtil.translate( left.getUnlocalisedAdjective() ) - ); - } - else if( left != null ) - { - return StringUtil.translateFormatted( - baseString + ".upgraded.name", - StringUtil.translate( left.getUnlocalisedAdjective() ) - ); - } - else if( right != null ) - { - return StringUtil.translateFormatted( - baseString + ".upgraded.name", - StringUtil.translate( right.getUnlocalisedAdjective() ) - ); - } - else - { - return StringUtil.translate( baseString + ".name" ); - } - } - - @Nullable - @Override - public String getCreatorModId( ItemStack stack ) - { - // Determine our "creator mod" from the upgrades. We attempt to find the first non-vanilla/non-CC - // upgrade (starting from the left). - - ITurtleUpgrade left = getUpgrade( stack, TurtleSide.Left ); - if( left != null ) - { - String mod = TurtleUpgrades.getOwner( left ); - if( mod != null && !mod.equals( ComputerCraft.MOD_ID ) ) return mod; - } - - ITurtleUpgrade right = getUpgrade( stack, TurtleSide.Right ); - if( right != null ) - { - String mod = TurtleUpgrades.getOwner( right ); - if( mod != null && !mod.equals( ComputerCraft.MOD_ID ) ) return mod; - } - - return super.getCreatorModId( stack ); - } - - @Override - public ItemStack withFamily( @Nonnull ItemStack stack, @Nonnull ComputerFamily family ) - { - return TurtleItemFactory.create( - getComputerID( stack ), getLabel( stack ), - getColour( stack ), family, - getUpgrade( stack, TurtleSide.Left ), getUpgrade( stack, TurtleSide.Right ), - getFuelLevel( stack ), getOverlay( stack ) - ); - } - - @Override - public ItemStack withColour( ItemStack stack, int colour ) - { - return TurtleItemFactory.create( - getComputerID( stack ), getLabel( stack ), colour, getFamily( stack ), - getUpgrade( stack, TurtleSide.Left ), getUpgrade( stack, TurtleSide.Right ), - getFuelLevel( stack ), getOverlay( stack ) - ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java deleted file mode 100644 index 75a31ac71..000000000 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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.shared.turtle.items; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.turtle.ITurtleUpgrade; -import dan200.computercraft.api.turtle.TurtleSide; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import net.minecraft.block.Block; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.ResourceLocation; - -import javax.annotation.Nonnull; - -public class ItemTurtleLegacy extends ItemTurtleBase -{ - public ItemTurtleLegacy( Block block ) - { - super( block ); - setTranslationKey( "computercraft:turtle" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - } - - // IComputerItem implementation - - @Override - public int getComputerID( @Nonnull ItemStack stack ) - { - if( stack.hasTagCompound() && stack.getTagCompound().hasKey( "computerID" ) ) - { - return stack.getTagCompound().getInteger( "computerID" ); - } - else - { - int damage = stack.getItemDamage(); - return ((damage & 0xfffc) >> 2) - 1; - } - } - - @Override - public ComputerFamily getFamily() - { - return ComputerFamily.Normal; - } - - // ITurtleItem implementation - - @Override - public ITurtleUpgrade getUpgrade( @Nonnull ItemStack stack, @Nonnull TurtleSide side ) - { - int damage = stack.getItemDamage(); - switch( side ) - { - case Left: - if( (damage & 0x1) > 0 ) return ComputerCraft.TurtleUpgrades.diamondPickaxe; - break; - case Right: - if( (damage & 0x2) > 0 ) return ComputerCraft.TurtleUpgrades.wirelessModem; - break; - } - return null; - } - - @Override - public int getColour( @Nonnull ItemStack stack ) - { - return -1; - } - - @Override - public ResourceLocation getOverlay( @Nonnull ItemStack stack ) { return null; } - - @Override - public int getFuelLevel( @Nonnull ItemStack stack ) - { - if( stack.hasTagCompound() ) - { - NBTTagCompound nbt = stack.getTagCompound(); - return nbt.getInteger( "fuelLevel" ); - } - return 0; - } -} - diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleNormal.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleNormal.java deleted file mode 100644 index 4d21726cd..000000000 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleNormal.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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.shared.turtle.items; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.turtle.ITurtleUpgrade; -import dan200.computercraft.api.turtle.TurtleSide; -import dan200.computercraft.shared.TurtleUpgrades; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.util.ColourUtils; -import net.minecraft.block.Block; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.common.util.Constants; - -import javax.annotation.Nonnull; - -public class ItemTurtleNormal extends ItemTurtleBase -{ - public ItemTurtleNormal( Block block ) - { - super( block ); - setTranslationKey( "computercraft:turtle" ); - setCreativeTab( ComputerCraft.mainCreativeTab ); - } - - public ItemStack create( int id, String label, int colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, int fuelLevel, ResourceLocation overlay ) - { - ItemStack stack = new ItemStack( this, 1, 0 ); - NBTTagCompound nbt = new NBTTagCompound(); - if( leftUpgrade != null ) nbt.setString( "leftUpgrade", leftUpgrade.getUpgradeID().toString() ); - if( rightUpgrade != null ) nbt.setString( "rightUpgrade", rightUpgrade.getUpgradeID().toString() ); - if( id >= 0 ) nbt.setInteger( "computerID", id ); - if( fuelLevel > 0 ) nbt.setInteger( "fuelLevel", fuelLevel ); - if( colour != -1 ) nbt.setInteger( "colour", colour ); - if( overlay != null ) - { - nbt.setString( "overlay_mod", overlay.getNamespace() ); - nbt.setString( "overlay_path", overlay.getPath() ); - } - stack.setTagCompound( nbt ); - - if( label != null ) stack.setStackDisplayName( label ); - - return stack; - } - - // IComputerItem implementation - - @Override - public int getComputerID( @Nonnull ItemStack stack ) - { - NBTTagCompound nbt = stack.getTagCompound(); - return nbt != null && nbt.hasKey( "computerID" ) ? nbt.getInteger( "computerID" ) : -1; - } - - @Override - public ComputerFamily getFamily() - { - return ComputerFamily.Normal; - } - - // ITurtleItem implementation - - @Override - public ITurtleUpgrade getUpgrade( @Nonnull ItemStack stack, @Nonnull TurtleSide side ) - { - NBTTagCompound nbt = stack.getTagCompound(); - if( nbt == null ) return null; - switch( side ) - { - case Left: - if( nbt.hasKey( "leftUpgrade" ) ) - { - return nbt.getTagId( "leftUpgrade" ) == Constants.NBT.TAG_STRING - ? TurtleUpgrades.get( nbt.getString( "leftUpgrade" ) ) - : TurtleUpgrades.get( nbt.getShort( "leftUpgrade" ) ); - } - break; - case Right: - if( nbt.hasKey( "rightUpgrade" ) ) - { - return nbt.getTagId( "rightUpgrade" ) == Constants.NBT.TAG_STRING - ? TurtleUpgrades.get( nbt.getString( "rightUpgrade" ) ) - : TurtleUpgrades.get( nbt.getShort( "rightUpgrade" ) ); - } - break; - } - return null; - } - - @Override - public int getColour( @Nonnull ItemStack stack ) - { - NBTTagCompound tag = stack.getTagCompound(); - return tag == null ? -1 : ColourUtils.getHexColour( tag ); - } - - @Override - public ResourceLocation getOverlay( @Nonnull ItemStack stack ) - { - NBTTagCompound nbt = stack.getTagCompound(); - if( nbt != null && nbt.hasKey( "overlay_mod" ) && nbt.hasKey( "overlay_path" ) ) - { - String overlayMod = nbt.getString( "overlay_mod" ); - String overlayPath = nbt.getString( "overlay_path" ); - return new ResourceLocation( overlayMod, overlayPath ); - } - return null; - } - - @Override - public int getFuelLevel( @Nonnull ItemStack stack ) - { - NBTTagCompound nbt = stack.getTagCompound(); - return nbt != null && nbt.hasKey( "fuelLevel" ) ? nbt.getInteger( "fuelLevel" ) : 0; - } -} diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java index b335d2b62..2ff09685f 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java @@ -43,7 +43,7 @@ public static ItemStack create( int id, String label, int colour, ComputerFamily switch( family ) { case Normal: - return ComputerCraft.Items.turtleExpanded.create( id, label, colour, leftUpgrade, rightUpgrade, fuelLevel, overlay ); + return ComputerCraft.Items.turtleNormal.create( id, label, colour, leftUpgrade, rightUpgrade, fuelLevel, overlay ); case Advanced: return ComputerCraft.Items.turtleAdvanced.create( id, label, colour, leftUpgrade, rightUpgrade, fuelLevel, overlay ); default: diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java index 6757d6239..ff48d31da 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java @@ -6,29 +6,31 @@ package dan200.computercraft.shared.turtle.recipes; -import com.google.gson.JsonObject; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.items.IComputerItem; -import dan200.computercraft.shared.computer.recipe.ComputerConvertRecipe; +import dan200.computercraft.shared.computer.recipe.ComputerFamilyRecipe; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; -import dan200.computercraft.shared.util.RecipeUtil; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; -import net.minecraft.util.JsonUtils; -import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.common.crafting.IRecipeFactory; -import net.minecraftforge.common.crafting.JsonContext; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; import javax.annotation.Nonnull; -public class TurtleRecipe extends ComputerConvertRecipe +public final class TurtleRecipe extends ComputerFamilyRecipe { - private final ComputerFamily family; - - public TurtleRecipe( String group, @Nonnull CraftingHelper.ShapedPrimer primer, ComputerFamily family ) + private TurtleRecipe( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family ) { - super( group, primer, TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null ) ); - this.family = family; + super( identifier, group, width, height, ingredients, result, family ); + } + + @Nonnull + @Override + public IRecipeSerializer getSerializer() + { + return SERIALIZER; } @Nonnull @@ -38,19 +40,23 @@ protected ItemStack convert( @Nonnull IComputerItem item, @Nonnull ItemStack sta int computerID = item.getComputerID( stack ); String label = item.getLabel( stack ); - return TurtleItemFactory.create( computerID, label, -1, family, null, null, 0, null ); + return TurtleItemFactory.create( computerID, label, -1, getFamily(), null, null, 0, null ); } - public static class Factory implements IRecipeFactory + private static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ); + public static final IRecipeSerializer SERIALIZER = new Serializer() { @Override - public IRecipe parse( JsonContext context, JsonObject json ) + protected TurtleRecipe create( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family ) { - String group = JsonUtils.getString( json, "group", "" ); - ComputerFamily family = RecipeUtil.getFamily( json, "family" ); - CraftingHelper.ShapedPrimer primer = RecipeUtil.getPrimer( context, json ); - - return new TurtleRecipe( group, primer, family ); + return new TurtleRecipe( identifier, group, width, height, ingredients, result, family ); } - } + + @Nonnull + @Override + public ResourceLocation getName() + { + return ID; + } + }; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java index 11c394855..c896666f6 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java @@ -6,38 +6,36 @@ package dan200.computercraft.shared.turtle.recipes; -import com.google.gson.JsonObject; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.items.ITurtleItem; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; -import net.minecraft.inventory.InventoryCrafting; +import dan200.computercraft.shared.util.AbstractRecipe; +import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.item.crafting.RecipeSerializers; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; -import net.minecraftforge.common.crafting.IRecipeFactory; -import net.minecraftforge.common.crafting.JsonContext; -import net.minecraftforge.registries.IForgeRegistryEntry; import javax.annotation.Nonnull; -public class TurtleUpgradeRecipe extends IForgeRegistryEntry.Impl implements IRecipe +public final class TurtleUpgradeRecipe extends AbstractRecipe { + private TurtleUpgradeRecipe( ResourceLocation id ) + { + super( id ); + } + @Override public boolean canFit( int x, int y ) { return x >= 3 && y >= 1; } - @Override - public boolean isDynamic() - { - return true; - } - @Nonnull @Override public ItemStack getRecipeOutput() @@ -46,14 +44,14 @@ public ItemStack getRecipeOutput() } @Override - public boolean matches( @Nonnull InventoryCrafting inventory, @Nonnull World world ) + public boolean matches( @Nonnull IInventory inventory, @Nonnull World world ) { return !getCraftingResult( inventory ).isEmpty(); } @Nonnull @Override - public ItemStack getCraftingResult( @Nonnull InventoryCrafting inventory ) + public ItemStack getCraftingResult( @Nonnull IInventory inventory ) { // Scan the grid for a row containing a turtle and 1 or 2 items ItemStack leftItem = ItemStack.EMPTY; @@ -68,7 +66,7 @@ public ItemStack getCraftingResult( @Nonnull InventoryCrafting inventory ) boolean finishedRow = false; for( int x = 0; x < inventory.getWidth(); x++ ) { - ItemStack item = inventory.getStackInRowAndColumn( x, y ); + ItemStack item = inventory.getStackInSlot( x + y * inventory.getWidth() ); if( !item.isEmpty() ) { if( finishedRow ) @@ -126,7 +124,7 @@ else if( !turtle.isEmpty() && rightItem.isEmpty() ) // Turtle is already found, just check this row is empty for( int x = 0; x < inventory.getWidth(); x++ ) { - ItemStack item = inventory.getStackInRowAndColumn( x, y ); + ItemStack item = inventory.getStackInSlot( x + y * inventory.getWidth() ); if( !item.isEmpty() ) { return ItemStack.EMPTY; @@ -144,7 +142,7 @@ else if( !turtle.isEmpty() && rightItem.isEmpty() ) // At this point we have a turtle + 1 or 2 items // Get the turtle we already have ITurtleItem itemTurtle = (ITurtleItem) turtle.getItem(); - ComputerFamily family = itemTurtle.getFamily( turtle ); + ComputerFamily family = itemTurtle.getFamily(); ITurtleUpgrade[] upgrades = new ITurtleUpgrade[] { itemTurtle.getUpgrade( turtle, TurtleSide.Left ), itemTurtle.getUpgrade( turtle, TurtleSide.Right ), @@ -182,12 +180,14 @@ else if( !turtle.isEmpty() && rightItem.isEmpty() ) return TurtleItemFactory.create( computerID, label, colour, family, upgrades[0], upgrades[1], fuelLevel, overlay ); } - public static class Factory implements IRecipeFactory + @Nonnull + @Override + public IRecipeSerializer getSerializer() { - @Override - public IRecipe parse( JsonContext jsonContext, JsonObject jsonObject ) - { - return new TurtleUpgradeRecipe(); - } + return SERIALIZER; } + + public static final IRecipeSerializer SERIALIZER = new RecipeSerializers.SimpleSerializer<>( + ComputerCraft.MOD_ID + ":turtle_upgrade", TurtleUpgradeRecipe::new + ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java index c623a2066..ff03200a6 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java @@ -11,14 +11,14 @@ public class TurtleAxe extends TurtleTool { - public TurtleAxe( ResourceLocation id, int legacyId, String adjective, Item item ) + public TurtleAxe( ResourceLocation id, String adjective, Item item ) { - super( id, legacyId, adjective, item ); + super( id, adjective, item ); } - public TurtleAxe( ResourceLocation id, int legacyId, Item item ) + public TurtleAxe( ResourceLocation id, Item item ) { - super( id, legacyId, item ); + super( id, item ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java index 6dd6f3aaf..884781afc 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java @@ -12,13 +12,13 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleUpgradeType; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.model.IBakedModel; -import net.minecraft.client.renderer.block.model.ModelManager; -import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.model.ModelManager; +import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.init.Blocks; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; @@ -26,15 +26,15 @@ public class TurtleCraftingTable extends AbstractTurtleUpgrade { - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) private ModelResourceLocation m_leftModel; - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) private ModelResourceLocation m_rightModel; - public TurtleCraftingTable( ResourceLocation id, int legacyId ) + public TurtleCraftingTable( ResourceLocation id ) { - super( id, legacyId, TurtleUpgradeType.Peripheral, Blocks.CRAFTING_TABLE ); + super( id, TurtleUpgradeType.Peripheral, Blocks.CRAFTING_TABLE ); } @Override @@ -43,7 +43,7 @@ public IPeripheral createPeripheral( @Nonnull ITurtleAccess turtle, @Nonnull Tur return new CraftingTablePeripheral( turtle ); } - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) private void loadModelLocations() { if( m_leftModel == null ) @@ -55,14 +55,13 @@ private void loadModelLocations() @Nonnull @Override - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) public Pair getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { loadModelLocations(); Matrix4f transform = null; - Minecraft mc = Minecraft.getMinecraft(); - ModelManager modelManager = mc.getRenderItem().getItemModelMesher().getModelManager(); + ModelManager modelManager = Minecraft.getInstance().getItemRenderer().getItemModelMesher().getModelManager(); if( side == TurtleSide.Left ) { return Pair.of( modelManager.getModel( m_leftModel ), transform ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java index be57b1995..0a0797541 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java @@ -25,14 +25,14 @@ public class TurtleHoe extends TurtleTool { - public TurtleHoe( ResourceLocation id, int legacyId, String adjective, Item item ) + public TurtleHoe( ResourceLocation id, String adjective, Item item ) { - super( id, legacyId, adjective, item ); + super( id, adjective, item ); } - public TurtleHoe( ResourceLocation id, int legacyId, Item item ) + public TurtleHoe( ResourceLocation id, Item item ) { - super( id, legacyId, item ); + super( id, item ); } @Override @@ -45,6 +45,7 @@ protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, T material == Material.CACTUS || material == Material.GOURD || material == Material.LEAVES || + material == Material.OCEAN_PLANT || material == Material.VINE; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java index 40fc88fb2..169dd98cc 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java @@ -12,7 +12,6 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.InventoryCrafting; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.CraftingManager; import net.minecraft.item.crafting.IRecipe; import net.minecraft.util.NonNullList; import net.minecraft.util.text.ITextComponent; @@ -20,7 +19,8 @@ import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.ForgeHooks; -import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.common.crafting.VanillaRecipeTypes; +import net.minecraftforge.fml.hooks.BasicEventHooks; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -68,7 +68,7 @@ private IRecipe tryCrafting( int xStart, int yStart ) } // Check the actual crafting - return CraftingManager.findMatchingRecipe( this, m_turtle.getWorld() ); + return m_turtle.getWorld().getRecipeManager().getRecipe( this, m_turtle.getWorld(), VanillaRecipeTypes.CRAFTING ); } @Nullable @@ -96,7 +96,7 @@ public List doCrafting( World world, int maxCount ) results.add( result ); result.onCrafting( world, player, result.getCount() ); - FMLCommonHandler.instance().firePlayerCraftingEvent( player, result, this ); + BasicEventHooks.firePlayerCraftingEvent( player, result, this ); ForgeHooks.setCraftingPlayer( player ); NonNullList remainders = recipe.getRemainingItems( this ); @@ -136,15 +136,6 @@ else if( ItemStack.areItemsEqual( existing, remainder ) && ItemStack.areItemStac return results; } - @Nonnull - @Override - public ItemStack getStackInRowAndColumn( int x, int y ) - { - return x >= 0 && x < getWidth() && y >= 0 && y < getHeight() - ? getStackInSlot( x + y * getWidth() ) - : ItemStack.EMPTY; - } - @Override public int getWidth() { @@ -184,9 +175,9 @@ public ItemStack getStackInSlot( int i ) @Nonnull @Override - public String getName() + public ITextComponent getName() { - return ""; + return new TextComponentString( "" ); } @Override @@ -195,13 +186,6 @@ public boolean hasCustomName() return false; } - @Nonnull - @Override - public ITextComponent getDisplayName() - { - return new TextComponentString( "" ); - } - @Nonnull @Override public ItemStack removeStackFromSlot( int i ) @@ -243,16 +227,6 @@ public boolean isUsableByPlayer( EntityPlayer player ) return true; } - @Override - public void openInventory( EntityPlayer player ) - { - } - - @Override - public void closeInventory( EntityPlayer player ) - { - } - @Override public boolean isItemValidForSlot( int i, @Nonnull ItemStack stack ) { @@ -260,23 +234,6 @@ public boolean isItemValidForSlot( int i, @Nonnull ItemStack stack ) return m_turtle.getInventory().isItemValidForSlot( i, stack ); } - @Override - public int getField( int id ) - { - return 0; - } - - @Override - public void setField( int id, int value ) - { - } - - @Override - public int getFieldCount() - { - return 0; - } - @Override public void clear() { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index 039b632eb..4fa8e9a62 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -6,25 +6,24 @@ package dan200.computercraft.shared.turtle.upgrades; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.AbstractTurtleUpgrade; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.*; -import dan200.computercraft.shared.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.model.IBakedModel; -import net.minecraft.client.renderer.block.model.ModelManager; -import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.model.ModelManager; +import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; @@ -70,23 +69,25 @@ public boolean equals( IPeripheral other ) private boolean advanced; - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) private ModelResourceLocation m_leftOffModel; - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) private ModelResourceLocation m_rightOffModel; - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) private ModelResourceLocation m_leftOnModel; - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) private ModelResourceLocation m_rightOnModel; - public TurtleModem( boolean advanced, ResourceLocation id, int legacyId ) + public TurtleModem( boolean advanced, ResourceLocation id ) { super( - id, legacyId, TurtleUpgradeType.Peripheral, - advanced ? PeripheralItemFactory.create( PeripheralType.AdvancedModem, null, 1 ) : PeripheralItemFactory.create( PeripheralType.WirelessModem, null, 1 ) + id, TurtleUpgradeType.Peripheral, + advanced + ? ComputerCraft.Blocks.wirelessModemAdvanced + : ComputerCraft.Blocks.wirelessModemNormal ); this.advanced = advanced; } @@ -104,31 +105,31 @@ public TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull Turt return TurtleCommandResult.failure(); } - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) private void loadModelLocations() { if( m_leftOffModel == null ) { if( advanced ) { - m_leftOffModel = new ModelResourceLocation( "computercraft:advanced_turtle_modem_off_left", "inventory" ); - m_rightOffModel = new ModelResourceLocation( "computercraft:advanced_turtle_modem_off_right", "inventory" ); - m_leftOnModel = new ModelResourceLocation( "computercraft:advanced_turtle_modem_on_left", "inventory" ); - m_rightOnModel = new ModelResourceLocation( "computercraft:advanced_turtle_modem_on_right", "inventory" ); + m_leftOffModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_off_left", "inventory" ); + m_rightOffModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_off_right", "inventory" ); + m_leftOnModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_on_left", "inventory" ); + m_rightOnModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_on_right", "inventory" ); } else { - m_leftOffModel = new ModelResourceLocation( "computercraft:turtle_modem_off_left", "inventory" ); - m_rightOffModel = new ModelResourceLocation( "computercraft:turtle_modem_off_right", "inventory" ); - m_leftOnModel = new ModelResourceLocation( "computercraft:turtle_modem_on_left", "inventory" ); - m_rightOnModel = new ModelResourceLocation( "computercraft:turtle_modem_on_right", "inventory" ); + m_leftOffModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_off_left", "inventory" ); + m_rightOffModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_off_right", "inventory" ); + m_leftOnModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_on_left", "inventory" ); + m_rightOnModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_on_right", "inventory" ); } } } @Nonnull @Override - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) public Pair getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { loadModelLocations(); @@ -137,15 +138,14 @@ public Pair getModel( ITurtleAccess turtle, @Nonnull Turt if( turtle != null ) { NBTTagCompound turtleNBT = turtle.getUpgradeNBTData( side ); - if( turtleNBT.hasKey( "active" ) ) + if( turtleNBT.contains( "active" ) ) { active = turtleNBT.getBoolean( "active" ); } } Matrix4f transform = null; - Minecraft mc = Minecraft.getMinecraft(); - ModelManager modelManager = mc.getRenderItem().getItemModelMesher().getModelManager(); + ModelManager modelManager = Minecraft.getInstance().getItemRenderer().getItemModelMesher().getModelManager(); if( side == TurtleSide.Left ) { return Pair.of( @@ -174,7 +174,7 @@ public void update( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side ) ModemState state = ((Peripheral) peripheral).getModemState(); if( state.pollChanged() ) { - turtle.getUpgradeNBTData( side ).setBoolean( "active", state.isOpen() ); + turtle.getUpgradeNBTData( side ).putBoolean( "active", state.isOpen() ); turtle.updateUpgradeNBTData( side ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java index a8f287c23..cb5f66cd6 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java @@ -25,14 +25,14 @@ public class TurtleShovel extends TurtleTool { - public TurtleShovel( ResourceLocation id, int legacyId, String adjective, Item item ) + public TurtleShovel( ResourceLocation id, String adjective, Item item ) { - super( id, legacyId, adjective, item ); + super( id, adjective, item ); } - public TurtleShovel( ResourceLocation id, int legacyId, Item item ) + public TurtleShovel( ResourceLocation id, Item item ) { - super( id, legacyId, item ); + super( id, item ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java index 712bfb531..c82a0663d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -7,24 +7,23 @@ package dan200.computercraft.shared.turtle.upgrades; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.AbstractTurtleUpgrade; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleUpgradeType; -import dan200.computercraft.shared.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory; import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.model.IBakedModel; -import net.minecraft.client.renderer.block.model.ModelManager; -import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.model.ModelManager; +import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; @@ -61,18 +60,15 @@ public boolean equals( IPeripheral other ) } } - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) private ModelResourceLocation m_leftModel; - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) private ModelResourceLocation m_rightModel; - public TurtleSpeaker( ResourceLocation id, int legacyId ) + public TurtleSpeaker( ResourceLocation id ) { - super( - id, legacyId, TurtleUpgradeType.Peripheral, - PeripheralItemFactory.create( PeripheralType.Speaker, null, 1 ) - ); + super( id, TurtleUpgradeType.Peripheral, ComputerCraft.Blocks.speaker ); } @Override @@ -81,7 +77,7 @@ public IPeripheral createPeripheral( @Nonnull ITurtleAccess turtle, @Nonnull Tur return new TurtleSpeaker.Peripheral( turtle ); } - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) private void loadModelLocations() { if( m_leftModel == null ) @@ -93,11 +89,11 @@ private void loadModelLocations() @Nonnull @Override - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) public Pair getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { loadModelLocations(); - ModelManager modelManager = Minecraft.getMinecraft().getRenderItem().getItemModelMesher().getModelManager(); + ModelManager modelManager = Minecraft.getInstance().getItemRenderer().getItemModelMesher().getModelManager(); if( side == TurtleSide.Left ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java index 8f5f13619..31b445081 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java @@ -16,14 +16,14 @@ public class TurtleSword extends TurtleTool { - public TurtleSword( ResourceLocation id, int legacyId, String adjective, Item item ) + public TurtleSword( ResourceLocation id, String adjective, Item item ) { - super( id, legacyId, adjective, item ); + super( id, adjective, item ); } - public TurtleSword( ResourceLocation id, int legacyId, Item item ) + public TurtleSword( ResourceLocation id, Item item ) { - super( id, legacyId, item ); + super( id, item ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index ce61cd1cb..c27278777 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -20,10 +20,11 @@ import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.entity.Entity; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.item.EntityArmorStand; +import net.minecraft.fluid.IFluidState; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -34,11 +35,11 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.player.AttackEntityEvent; import net.minecraftforge.event.world.BlockEvent; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; @@ -50,21 +51,21 @@ public class TurtleTool extends AbstractTurtleUpgrade { protected ItemStack m_item; - public TurtleTool( ResourceLocation id, int legacyID, String adjective, Item item ) + public TurtleTool( ResourceLocation id, String adjective, Item item ) { - super( id, legacyID, TurtleUpgradeType.Tool, adjective, item ); - m_item = new ItemStack( item, 1, 0 ); + super( id, TurtleUpgradeType.Tool, adjective, item ); + m_item = new ItemStack( item ); } - public TurtleTool( ResourceLocation id, int legacyID, Item item ) + public TurtleTool( ResourceLocation id, Item item ) { - super( id, legacyID, TurtleUpgradeType.Tool, item ); - m_item = new ItemStack( item, 1, 0 ); + super( id, TurtleUpgradeType.Tool, item ); + m_item = new ItemStack( item ); } @Nonnull @Override - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) public Pair getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { float xOffset = side == TurtleSide.Left ? -0.40625f : 0.40625f; @@ -74,9 +75,9 @@ public Pair getModel( ITurtleAccess turtle, @Nonnull Turt 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f ); - Minecraft mc = Minecraft.getMinecraft(); + Minecraft mc = Minecraft.getInstance(); return Pair.of( - mc.getRenderItem().getItemModelMesher().getItemModel( m_item ), + mc.getItemRenderer().getItemModelMesher().getItemModel( m_item ), transform ); } @@ -99,7 +100,7 @@ public TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull Turt protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player ) { Block block = state.getBlock(); - return !block.isAir( state, world, pos ) + return !state.isAir( world, pos ) && block != Blocks.BEDROCK && state.getPlayerRelativeBlockHardness( player, world, pos ) > 0 && block.canEntityDestroy( state, world, pos, player ); @@ -148,7 +149,7 @@ private TurtleCommandResult attack( final ITurtleAccess turtle, EnumFacing direc boolean attacked = false; if( !hitEntity.hitByEntity( turtlePlayer ) ) { - float damage = (float) turtlePlayer.getEntityAttribute( SharedMonsterAttributes.ATTACK_DAMAGE ).getAttributeValue(); + float damage = (float) turtlePlayer.getAttribute( SharedMonsterAttributes.ATTACK_DAMAGE ).getValue(); damage *= getDamageMultiplier(); if( damage > 0.0f ) { @@ -157,7 +158,7 @@ private TurtleCommandResult attack( final ITurtleAccess turtle, EnumFacing direc { // Special case for armor stands: attack twice to guarantee destroy hitEntity.attackEntityFrom( source, damage ); - if( !hitEntity.isDead ) + if( hitEntity.isAlive() ) { hitEntity.attackEntityFrom( source, damage ); } @@ -200,6 +201,7 @@ private TurtleCommandResult dig( ITurtleAccess turtle, EnumFacing direction, Tur } IBlockState state = world.getBlockState( blockPosition ); + IFluidState fluidState = world.getFluidState( blockPosition ); TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, turtlePosition, direction ); turtlePlayer.loadInventory( m_item.copy() ); @@ -239,12 +241,12 @@ private TurtleCommandResult dig( ITurtleAccess turtle, EnumFacing direction, Tur // Much of this logic comes from PlayerInteractionManager#tryHarvestBlock, so it's a good idea // to consult there before making any changes. - // Play the destruction sound + // Play the destruction sound and particles world.playEvent( 2001, blockPosition, Block.getStateId( state ) ); // Destroy the block - boolean canHarvest = state.getBlock().canHarvestBlock( world, blockPosition, turtlePlayer ); - boolean canBreak = state.getBlock().removedByPlayer( state, world, blockPosition, turtlePlayer, canHarvest ); + boolean canHarvest = state.canHarvestBlock( world, blockPosition, turtlePlayer ); + boolean canBreak = state.removedByPlayer( world, blockPosition, turtlePlayer, canHarvest, fluidState ); if( canBreak ) state.getBlock().onPlayerDestroy( world, blockPosition, state ); if( canHarvest ) { diff --git a/src/main/java/dan200/computercraft/shared/util/AbstractRecipe.java b/src/main/java/dan200/computercraft/shared/util/AbstractRecipe.java new file mode 100644 index 000000000..a6908bbee --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/AbstractRecipe.java @@ -0,0 +1,43 @@ +/* + * 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.shared.util; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nonnull; + +public abstract class AbstractRecipe implements IRecipe +{ + private final ResourceLocation id; + + public AbstractRecipe( ResourceLocation id ) + { + this.id = id; + } + + @Nonnull + @Override + public ItemStack getRecipeOutput() + { + return ItemStack.EMPTY; + } + + @Nonnull + @Override + public ResourceLocation getId() + { + return id; + } + + @Override + public boolean isDynamic() + { + return true; + } +} diff --git a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java index 08c4ec6b1..22d47f827 100644 --- a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java +++ b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java @@ -6,77 +6,47 @@ package dan200.computercraft.shared.util; +import net.minecraft.item.EnumDyeColor; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraftforge.common.util.Constants; -import net.minecraftforge.oredict.OreDictionary; -import org.apache.commons.lang3.ArrayUtils; +import net.minecraft.tags.Tag; +import net.minecraftforge.common.Tags; -import javax.annotation.Nonnull; +import javax.annotation.Nullable; public final class ColourUtils { - private static final String[] DYES = new String[] { - "dyeBlack", "dyeRed", "dyeGreen", "dyeBrown", - "dyeBlue", "dyePurple", "dyeCyan", "dyeLightGray", - "dyeGray", "dyePink", "dyeLime", "dyeYellow", - "dyeLightBlue", "dyeMagenta", "dyeOrange", "dyeWhite" + @SuppressWarnings( { "unchecked", "rawtypes" } ) + private static final Tag[] DYES = new Tag[] { + Tags.Items.DYES_WHITE, + Tags.Items.DYES_ORANGE, + Tags.Items.DYES_MAGENTA, + Tags.Items.DYES_LIGHT_BLUE, + Tags.Items.DYES_YELLOW, + Tags.Items.DYES_LIME, + Tags.Items.DYES_PINK, + Tags.Items.DYES_GRAY, + Tags.Items.DYES_LIGHT_GRAY, + Tags.Items.DYES_CYAN, + Tags.Items.DYES_PURPLE, + Tags.Items.DYES_BLUE, + Tags.Items.DYES_BROWN, + Tags.Items.DYES_GREEN, + Tags.Items.DYES_RED, + Tags.Items.DYES_BLACK, }; - private static int[] ids; - + @Nullable private ColourUtils() {} - public static int getStackColour( ItemStack stack ) + public static EnumDyeColor getStackColour( ItemStack stack ) { - if( ids == null ) + for( int i = 0; i < DYES.length; i++ ) { - int[] ids = ColourUtils.ids = new int[DYES.length]; - for( int i = 0; i < DYES.length; i++ ) - { - ids[i] = OreDictionary.getOreID( DYES[i] ); - } + Tag dye = DYES[i]; + if( dye.contains( stack.getItem() ) ) return EnumDyeColor.byId( i ); } - for( int id : OreDictionary.getOreIDs( stack ) ) - { - int index = ArrayUtils.indexOf( ids, id ); - if( index >= 0 ) return index; - } - - return -1; + return null; } - - public static int getHexColour( @Nonnull NBTTagCompound tag ) - { - if( tag.hasKey( "colourIndex", Constants.NBT.TAG_ANY_NUMERIC ) ) - { - return Colour.VALUES[tag.getInteger( "colourIndex" ) & 0xF].getHex(); - } - else if( tag.hasKey( "colour", Constants.NBT.TAG_ANY_NUMERIC ) ) - { - return tag.getInteger( "colour" ); - } - else if( tag.hasKey( "color", Constants.NBT.TAG_ANY_NUMERIC ) ) - { - return tag.getInteger( "color" ); - } - else - { - return -1; - } - } - - public static Colour getColour( @Nonnull NBTTagCompound tag ) - { - if( tag.hasKey( "colourIndex", Constants.NBT.TAG_ANY_NUMERIC ) ) - { - return Colour.fromInt( tag.getInteger( "colourIndex" ) & 0xF ); - } - else - { - return null; - } - } - } diff --git a/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java b/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java index 10023b740..28905442f 100644 --- a/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java +++ b/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java @@ -7,25 +7,25 @@ package dan200.computercraft.shared.util; import dan200.computercraft.ComputerCraft; -import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import javax.annotation.Nonnull; -public class CreativeTabMain extends CreativeTabs +public class CreativeTabMain extends ItemGroup { - public CreativeTabMain( int i ) + public CreativeTabMain() { - super( i, ComputerCraft.MOD_ID ); + super( ComputerCraft.MOD_ID ); } @Nonnull @Override - @SideOnly( Side.CLIENT ) + @OnlyIn( Dist.CLIENT ) public ItemStack createIcon() { - return new ItemStack( ComputerCraft.Blocks.computer ); + return new ItemStack( ComputerCraft.Blocks.computerNormal ); } } diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultInteractionObject.java b/src/main/java/dan200/computercraft/shared/util/DefaultInteractionObject.java new file mode 100644 index 000000000..878f2951a --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/DefaultInteractionObject.java @@ -0,0 +1,32 @@ +/* + * 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.shared.util; + +import dan200.computercraft.shared.network.container.ContainerType; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.world.IInteractionObject; + +import javax.annotation.Nonnull; + +public interface DefaultInteractionObject extends IInteractionObject +{ + @Nonnull + @Override + T createContainer( @Nonnull InventoryPlayer inventory, @Nonnull EntityPlayer player ); + + @Nonnull + ContainerType getContainerType(); + + @Nonnull + @Override + default String getGuiID() + { + return getContainerType().getId().toString(); + } +} diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java index 7c4aeb6e3..dbaf26825 100644 --- a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java +++ b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java @@ -9,8 +9,10 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public interface DefaultInventory extends IInventory { @@ -52,4 +54,17 @@ default int getFieldCount() { return 0; } + + @Override + default boolean hasCustomName() + { + return getCustomName() != null; + } + + @Nullable + @Override + default ITextComponent getCustomName() + { + return null; + } } diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java index b1ca2333c..2c1f0bc24 100644 --- a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java +++ b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java @@ -11,11 +11,12 @@ import net.minecraft.util.EnumFacing; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public interface DefaultSidedInventory extends DefaultInventory, ISidedInventory { @Override - default boolean canInsertItem( int slot, @Nonnull ItemStack stack, @Nonnull EnumFacing side ) + default boolean canInsertItem( int slot, @Nonnull ItemStack stack, @Nullable EnumFacing side ) { return isItemValidForSlot( slot, stack ); } diff --git a/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java b/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java index 778882044..a4d654fb4 100644 --- a/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java @@ -6,53 +6,38 @@ package dan200.computercraft.shared.util; -import dan200.computercraft.shared.common.IDirectionalTile; -import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.EnumFacing; public final class DirectionUtil { private DirectionUtil() {} - public static int toLocal( IDirectionalTile directional, EnumFacing dir ) + public static final EnumFacing[] FACINGS = EnumFacing.values(); + + public static EnumFacing toLocal( EnumFacing front, EnumFacing relative ) { - EnumFacing front = directional.getDirection(); + if( relative.getAxis() == EnumFacing.Axis.Y ) return relative; + if( front.getAxis() == EnumFacing.Axis.Y ) front = EnumFacing.NORTH; - EnumFacing back = front.getOpposite(); - EnumFacing left = front.rotateYCCW(); - EnumFacing right = front.rotateY(); - if( dir == front ) + if( relative == front ) { - return 3; + return EnumFacing.SOUTH; } - else if( dir == back ) + else if( relative == front.getOpposite() ) { - return 2; + return EnumFacing.NORTH; } - else if( dir == left ) + else if( relative == front.rotateYCCW() ) { - return 5; - } - else if( dir == right ) - { - return 4; - } - else if( dir == EnumFacing.UP ) - { - return 1; + return EnumFacing.EAST; } else { - return 0; + return EnumFacing.WEST; } } - public static EnumFacing fromEntityRot( EntityLivingBase player ) - { - return EnumFacing.fromAngle( player.rotationYaw ).getOpposite(); - } - public static float toPitchAngle( EnumFacing dir ) { switch( dir ) @@ -65,10 +50,4 @@ public static float toPitchAngle( EnumFacing dir ) return 0.0f; } } - - @Deprecated - public static float toYawAngle( EnumFacing dir ) - { - return dir.getHorizontalAngle(); - } } diff --git a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java index 94a053aa9..701dc8dbd 100644 --- a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java +++ b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java @@ -16,12 +16,13 @@ import net.minecraftforge.event.entity.EntityJoinWorldEvent; import net.minecraftforge.event.entity.living.LivingDropsEvent; import net.minecraftforge.event.world.BlockEvent; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.EventPriority; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.function.Function; @@ -48,7 +49,7 @@ public static void set( Entity entity, Function consumer ) dropPos = null; dropBounds = new AxisAlignedBB( entity.getPosition() ).grow( 2, 2, 2 ); - entity.captureDrops = true; + entity.captureDrops( new ArrayList<>() ); } public static void set( World world, BlockPos pos, Function consumer ) @@ -68,11 +69,10 @@ public static List clear() Entity entity = dropEntity.get(); if( entity != null ) { - entity.captureDrops = false; - if( entity.capturedDrops != null ) + Collection dropped = entity.captureDrops( null ); + if( dropped != null ) { - for( EntityItem entityItem : entity.capturedDrops ) handleDrops( entityItem.getItem() ); - entity.capturedDrops.clear(); + for( EntityItem entityItem : dropped ) handleDrops( entityItem.getItem() ); } } } @@ -101,7 +101,7 @@ public static void onEntityLivingDrops( LivingDropsEvent event ) // Capture any mob drops for the current entity if( dropEntity != null && event.getEntity() == dropEntity.get() ) { - List drops = event.getDrops(); + Collection drops = event.getDrops(); for( EntityItem entityItem : drops ) handleDrops( entityItem.getItem() ); drops.clear(); } @@ -116,7 +116,7 @@ public static void onHarvestDrops( BlockEvent.HarvestDropsEvent event ) { for( ItemStack item : event.getDrops() ) { - if( event.getWorld().rand.nextFloat() < event.getDropChance() ) handleDrops( item ); + if( event.getWorld().getRandom().nextFloat() < event.getDropChance() ) handleDrops( item ); } event.getDrops().clear(); } diff --git a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java index 34f72c35a..68d6c361f 100644 --- a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java +++ b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java @@ -6,118 +6,101 @@ package dan200.computercraft.shared.util; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; import dan200.computercraft.ComputerCraft; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.dimension.DimensionType; +import net.minecraftforge.fml.server.ServerLifecycleHooks; -import java.io.*; +import java.io.File; +import java.io.Reader; +import java.io.Writer; +import java.lang.ref.WeakReference; +import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; public final class IDAssigner { + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + private static final Type ID_TOKEN = new TypeToken>() {}.getType(); + private IDAssigner() { } - public static int getNextIDFromDirectory( String path ) + private static Map ids; + private static WeakReference server; + private static Path idFile; + + public static File getDir() { - return getNextIDFromDirectory( new File( ComputerCraft.getWorldDir(), path ) ); + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + File worldDirectory = server.getWorld( DimensionType.OVERWORLD ).getSaveHandler().getWorldDirectory(); + return new File( worldDirectory, ComputerCraft.MOD_ID ); } - public static int getNextIDFromFile( String path ) + private static MinecraftServer getCachedServer() { - return getNextIDFromFile( new File( ComputerCraft.getWorldDir(), path ) ); + if( server == null ) return null; + + MinecraftServer currentServer = server.get(); + if( currentServer == null ) return null; + + if( currentServer != ServerLifecycleHooks.getCurrentServer() ) return null; + return currentServer; } - public static int getNextIDFromDirectory( File dir ) + public static synchronized int getNextId( String kind ) { - return getNextID( dir, true ); - } - - public static int getNextIDFromFile( File file ) - { - return getNextID( file, false ); - } - - private static int getNextID( File location, boolean directory ) - { - // Determine where to locate ID file - File lastIdFile; - if( directory ) + MinecraftServer currentServer = getCachedServer(); + if( currentServer == null ) { - location.mkdirs(); - lastIdFile = new File( location, "lastid.txt" ); - } - else - { - location.getParentFile().mkdirs(); - lastIdFile = location; - } + // The server has changed, refetch our ID map + server = new WeakReference<>( ServerLifecycleHooks.getCurrentServer() ); - // Try to determine the id - int id = 0; - if( !lastIdFile.exists() ) - { - // If an ID file doesn't exist, determine it from the file structure - if( directory && location.exists() && location.isDirectory() ) + File dir = getDir(); + dir.mkdirs(); + + // Load our ID file from disk + idFile = new File( dir, "ids.json" ).toPath(); + if( Files.isRegularFile( idFile ) ) { - String[] contents = location.list(); - for( String content : contents ) + try( Reader reader = Files.newBufferedReader( idFile, StandardCharsets.UTF_8 ) ) { - try - { - int number = Integer.parseInt( content ); - id = Math.max( number + 1, id ); - } - catch( NumberFormatException e ) - { - ComputerCraft.log.error( "Unexpected file '" + content + "' in '" + location.getAbsolutePath() + "'", e ); - } + ids = GSON.fromJson( reader, ID_TOKEN ); + } + catch( Exception e ) + { + ComputerCraft.log.error( "Cannot load id file '" + idFile + "'", e ); + ids = new HashMap<>(); } } - } - else - { - // If an ID file does exist, parse the file to get the ID string - String idString; - try + else { - FileInputStream in = new FileInputStream( lastIdFile ); - InputStreamReader isr = new InputStreamReader( in, StandardCharsets.UTF_8 ); - try( BufferedReader br = new BufferedReader( isr ) ) - { - idString = br.readLine(); - } - } - catch( IOException e ) - { - ComputerCraft.log.error( "Cannot open ID file '" + lastIdFile + "'", e ); - return 0; - } - - try - { - id = Integer.parseInt( idString ) + 1; - } - catch( NumberFormatException e ) - { - ComputerCraft.log.error( "Cannot parse ID file '" + lastIdFile + "', perhaps it is corrupt?", e ); - return 0; + ids = new HashMap<>(); } } - // Write the lastID file out with the new value - try + Integer existing = ids.get( kind ); + int next = existing == null ? 0 : existing + 1; + ids.put( kind, next ); + + // We've changed the ID file, so save it back again. + try( Writer writer = Files.newBufferedWriter( idFile, StandardCharsets.UTF_8 ) ) { - try( BufferedWriter out = new BufferedWriter( new FileWriter( lastIdFile, false ) ) ) - { - out.write( Integer.toString( id ) ); - out.newLine(); - } + GSON.toJson( ids, writer ); } - catch( IOException e ) + catch( Exception e ) { - ComputerCraft.log.error( "An error occurred while trying to create the computer folder. Please check you have relevant permissions.", e ); + ComputerCraft.log.error( "Cannot update ID file '" + idFile + "'", e ); } - return id; + return next; } } diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java index 5227cd2d2..dd4d0d86e 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java @@ -7,61 +7,98 @@ package dan200.computercraft.shared.util; import com.google.gson.JsonObject; -import net.minecraft.inventory.InventoryCrafting; +import dan200.computercraft.ComputerCraft; +import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; -import net.minecraft.item.crafting.ShapedRecipes; +import net.minecraft.item.crafting.RecipeSerializers; +import net.minecraft.item.crafting.ShapedRecipe; +import net.minecraft.network.PacketBuffer; import net.minecraft.util.JsonUtils; import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.common.crafting.IRecipeFactory; -import net.minecraftforge.common.crafting.JsonContext; import javax.annotation.Nonnull; -public class ImpostorRecipe extends ShapedRecipes +public final class ImpostorRecipe extends ShapedRecipe { - public ImpostorRecipe( @Nonnull String group, int width, int height, NonNullList ingredients, @Nonnull ItemStack result ) + private final String group; + + private ImpostorRecipe( @Nonnull ResourceLocation id, @Nonnull String group, int width, int height, NonNullList ingredients, @Nonnull ItemStack result ) { - super( group, width, height, ingredients, result ); + super( id, group, width, height, ingredients, result ); + this.group = group; } - public ImpostorRecipe( @Nonnull String group, int width, int height, ItemStack[] ingredients, @Nonnull ItemStack result ) + @Nonnull + @Override + public String getGroup() { - super( group, width, height, convert( ingredients ), result ); - } - - private static NonNullList convert( ItemStack[] items ) - { - NonNullList ingredients = NonNullList.withSize( items.length, Ingredient.EMPTY ); - for( int i = 0; i < items.length; i++ ) ingredients.set( i, Ingredient.fromStacks( items[i] ) ); - return ingredients; + return group; } @Override - public boolean matches( @Nonnull InventoryCrafting inv, World world ) + public boolean matches( @Nonnull IInventory inv, World world ) { return false; } @Nonnull @Override - public ItemStack getCraftingResult( @Nonnull InventoryCrafting inventory ) + public ItemStack getCraftingResult( @Nonnull IInventory inventory ) { return ItemStack.EMPTY; } - public static class Factory implements IRecipeFactory + @Nonnull + @Override + public IRecipeSerializer getSerializer() + { + return SERIALIZER; + } + + private static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shaped" ); + public static final IRecipeSerializer SERIALIZER = new IRecipeSerializer() { @Override - public IRecipe parse( JsonContext ctx, JsonObject json ) + public ImpostorRecipe read( @Nonnull ResourceLocation identifier, @Nonnull JsonObject json ) { String group = JsonUtils.getString( json, "group", "" ); - CraftingHelper.ShapedPrimer primer = RecipeUtil.getPrimer( ctx, json ); - ItemStack result = CraftingHelper.getItemStack( JsonUtils.getJsonObject( json, "result" ), ctx ); - return new ImpostorRecipe( group, primer.width, primer.height, primer.input, result ); + ShapedRecipe recipe = RecipeSerializers.CRAFTING_SHAPED.read( identifier, json ); + ItemStack result = CraftingHelper.getItemStack( JsonUtils.getJsonObject( json, "result" ), true ); + return new ImpostorRecipe( identifier, group, recipe.getWidth(), recipe.getHeight(), recipe.getIngredients(), result ); } - } + + @Override + public ImpostorRecipe read( @Nonnull ResourceLocation identifier, @Nonnull PacketBuffer buf ) + { + int width = buf.readVarInt(); + int height = buf.readVarInt(); + String group = buf.readString( Short.MAX_VALUE ); + NonNullList items = NonNullList.withSize( width * height, Ingredient.EMPTY ); + for( int k = 0; k < items.size(); ++k ) items.set( k, Ingredient.read( buf ) ); + ItemStack result = buf.readItemStack(); + return new ImpostorRecipe( identifier, group, width, height, items, result ); + } + + @Override + public void write( @Nonnull PacketBuffer buf, @Nonnull ImpostorRecipe recipe ) + { + buf.writeVarInt( recipe.getRecipeWidth() ); + buf.writeVarInt( recipe.getRecipeHeight() ); + buf.writeString( recipe.getGroup() ); + for( Ingredient ingredient : recipe.getIngredients() ) ingredient.write( buf ); + buf.writeItemStack( recipe.getRecipeOutput() ); + } + + @Nonnull + @Override + public ResourceLocation getName() + { + return ID; + } + }; } diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java index 12c56caf0..889ed2869 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java @@ -6,62 +6,121 @@ package dan200.computercraft.shared.util; +import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import net.minecraft.inventory.InventoryCrafting; +import com.google.gson.JsonParseException; +import dan200.computercraft.ComputerCraft; +import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; -import net.minecraft.item.crafting.ShapelessRecipes; +import net.minecraft.item.crafting.ShapelessRecipe; +import net.minecraft.network.PacketBuffer; import net.minecraft.util.JsonUtils; import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.common.crafting.IRecipeFactory; -import net.minecraftforge.common.crafting.JsonContext; import javax.annotation.Nonnull; -public class ImpostorShapelessRecipe extends ShapelessRecipes +public final class ImpostorShapelessRecipe extends ShapelessRecipe { - public ImpostorShapelessRecipe( @Nonnull String group, @Nonnull ItemStack result, NonNullList ingredients ) + private final String group; + + private ImpostorShapelessRecipe( @Nonnull ResourceLocation id, @Nonnull String group, @Nonnull ItemStack result, NonNullList ingredients ) { - super( group, result, ingredients ); + super( id, group, result, ingredients ); + this.group = group; } - public ImpostorShapelessRecipe( @Nonnull String group, @Nonnull ItemStack result, ItemStack[] ingredients ) + @Nonnull + @Override + public String getGroup() { - super( group, result, convert( ingredients ) ); - } - - private static NonNullList convert( ItemStack[] items ) - { - NonNullList ingredients = NonNullList.withSize( items.length, Ingredient.EMPTY ); - for( int i = 0; i < items.length; i++ ) ingredients.set( i, Ingredient.fromStacks( items[i] ) ); - return ingredients; + return group; } @Override - public boolean matches( InventoryCrafting inv, World world ) + public boolean matches( IInventory inv, World world ) { return false; } @Nonnull @Override - public ItemStack getCraftingResult( InventoryCrafting inventory ) + public ItemStack getCraftingResult( IInventory inventory ) { return ItemStack.EMPTY; } - public static class Factory implements IRecipeFactory + @Nonnull + @Override + public IRecipeSerializer getSerializer() + { + return SERIALIZER; + } + + private static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shapeless" ); + + public static final IRecipeSerializer SERIALIZER = new IRecipeSerializer() { @Override - public IRecipe parse( JsonContext context, JsonObject json ) + public ImpostorShapelessRecipe read( @Nonnull ResourceLocation id, @Nonnull JsonObject json ) { - String group = JsonUtils.getString( json, "group", "" ); - NonNullList ingredients = RecipeUtil.getIngredients( context, json ); - ItemStack itemstack = CraftingHelper.getItemStack( JsonUtils.getJsonObject( json, "result" ), context ); - return new ImpostorShapelessRecipe( group, itemstack, ingredients ); + String s = JsonUtils.getString( json, "group", "" ); + NonNullList ingredients = readIngredients( JsonUtils.getJsonArray( json, "ingredients" ) ); + + if( ingredients.isEmpty() ) throw new JsonParseException( "No ingredients for shapeless recipe" ); + if( ingredients.size() > 9 ) + { + throw new JsonParseException( "Too many ingredients for shapeless recipe the max is 9" ); + } + + ItemStack itemstack = CraftingHelper.getItemStack( JsonUtils.getJsonObject( json, "result" ), true ); + return new ImpostorShapelessRecipe( id, s, itemstack, ingredients ); } - } + + private NonNullList readIngredients( JsonArray arrays ) + { + NonNullList items = NonNullList.create(); + for( int i = 0; i < arrays.size(); ++i ) + { + Ingredient ingredient = Ingredient.deserialize( arrays.get( i ) ); + if( !ingredient.hasNoMatchingItems() ) items.add( ingredient ); + } + + return items; + } + + @Override + public ImpostorShapelessRecipe read( @Nonnull ResourceLocation id, PacketBuffer buffer ) + { + String s = buffer.readString( 32767 ); + int i = buffer.readVarInt(); + NonNullList items = NonNullList.withSize( i, Ingredient.EMPTY ); + + for( int j = 0; j < items.size(); j++ ) items.set( j, Ingredient.read( buffer ) ); + ItemStack result = buffer.readItemStack(); + + return new ImpostorShapelessRecipe( id, s, result, items ); + } + + @Override + public void write( @Nonnull PacketBuffer buffer, @Nonnull ImpostorShapelessRecipe recipe ) + { + buffer.writeString( recipe.getGroup() ); + buffer.writeVarInt( recipe.getIngredients().size() ); + + for( Ingredient ingredient : recipe.getIngredients() ) ingredient.write( buffer ); + buffer.writeItemStack( recipe.getRecipeOutput() ); + } + + @Nonnull + @Override + public ResourceLocation getName() + { + return ID; + } + }; } diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java index 46a878f49..d67223e24 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java @@ -16,6 +16,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.ItemHandlerHelper; @@ -44,7 +45,7 @@ public static boolean areItemsStackable( @Nonnull ItemStack a, @Nonnull ItemStac * Determines if two items are "mostly" equivalent. Namely, they have the same item and damage, and identical * share stacks. * - * This is largely based on {@link net.minecraftforge.common.crafting.IngredientNBT#apply(ItemStack)}. It is + * This is largely based on {@link net.minecraftforge.common.crafting.IngredientNBT#test(ItemStack)}. It is * sufficient to ensure basic information (such as enchantments) are the same, while not having to worry about * capabilities. * @@ -57,12 +58,12 @@ public static boolean areItemsSimilar( @Nonnull ItemStack a, @Nonnull ItemStack if( a == b ) return true; if( a.isEmpty() ) return !b.isEmpty(); - if( a.getItem() != b.getItem() || a.getItemDamage() != b.getItemDamage() ) return false; + if( a.getItem() != b.getItem() ) return false; - // A more expanded form of ItemStack.areItemStackShareTagsEqual, but allowing an empty tag to be equal to a + // A more expanded form of ItemStack.areShareTagsEqual, but allowing an empty tag to be equal to a // null one. - NBTTagCompound shareTagA = a.getItem().getNBTShareTag( a ); - NBTTagCompound shareTagB = b.getItem().getNBTShareTag( b ); + NBTTagCompound shareTagA = a.getItem().getShareTag( a ); + NBTTagCompound shareTagB = b.getItem().getShareTag( b ); if( shareTagA == shareTagB ) return true; if( shareTagA == null ) return shareTagB.isEmpty(); if( shareTagB == null ) return shareTagA.isEmpty(); @@ -83,10 +84,10 @@ public static IItemHandler getInventory( World world, BlockPos pos, EnumFacing s TileEntity tileEntity = world.getTileEntity( pos ); if( tileEntity != null ) { - IItemHandler itemHandler = tileEntity.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side ); - if( itemHandler != null ) + LazyOptional itemHandler = tileEntity.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side ); + if( itemHandler.isPresent() ) { - return itemHandler; + return itemHandler.orElseThrow( NullPointerException::new ); } else if( side != null && tileEntity instanceof ISidedInventory ) { @@ -173,8 +174,10 @@ public static ItemStack takeItems( int count, IItemHandler inventory, int start, { int slot = start + (i + begin - start) % range; + // If we've extracted all items, return if( count <= 0 ) break; + // If this doesn't slot, abort. ItemStack stack = inventory.getStackInSlot( slot ); if( !stack.isEmpty() && (partialStack.isEmpty() || areItemsStackable( stack, partialStack )) ) { @@ -195,6 +198,7 @@ public static ItemStack takeItems( int count, IItemHandler inventory, int start, count -= extracted.getCount(); } } + } return partialStack; diff --git a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java index f83dbf1e9..9a115002b 100644 --- a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java @@ -7,20 +7,18 @@ package dan200.computercraft.shared.util; import net.minecraft.nbt.*; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.text.ITextComponent; import net.minecraftforge.common.util.Constants; -import java.io.IOException; -import java.io.UncheckedIOException; import java.util.HashMap; import java.util.Map; +import static net.minecraftforge.common.util.Constants.NBT.*; + public final class NBTUtil { private NBTUtil() {} - private static NBTBase toNBTTag( Object object ) + private static INBTBase toNBTTag( Object object ) { if( object == null ) return null; if( object instanceof Boolean ) return new NBTTagByte( (byte) ((boolean) (Boolean) object ? 1 : 0) ); @@ -33,16 +31,16 @@ private static NBTBase toNBTTag( Object object ) int i = 0; for( Map.Entry entry : m.entrySet() ) { - NBTBase key = toNBTTag( entry.getKey() ); - NBTBase value = toNBTTag( entry.getKey() ); + INBTBase key = toNBTTag( entry.getKey() ); + INBTBase value = toNBTTag( entry.getKey() ); if( key != null && value != null ) { - nbt.setTag( "k" + i, key ); - nbt.setTag( "v" + i, value ); + nbt.put( "k" + i, key ); + nbt.put( "v" + i, value ); i++; } } - nbt.setInteger( "len", m.size() ); + nbt.putInt( "len", m.size() ); return nbt; } @@ -54,48 +52,44 @@ public static NBTTagCompound encodeObjects( Object[] objects ) if( objects == null || objects.length <= 0 ) return null; NBTTagCompound nbt = new NBTTagCompound(); - nbt.setInteger( "len", objects.length ); + nbt.putInt( "len", objects.length ); for( int i = 0; i < objects.length; i++ ) { - Object object = objects[i]; - NBTBase tag = toNBTTag( object ); - if( tag != null ) nbt.setTag( Integer.toString( i ), tag ); + INBTBase child = toNBTTag( objects[i] ); + if( child != null ) nbt.put( Integer.toString( i ), child ); } return nbt; } - private static Object fromNBTTag( NBTBase tag ) + private static Object fromNBTTag( INBTBase tag ) { if( tag == null ) return null; - - byte typeID = tag.getId(); - switch( typeID ) + switch( tag.getId() ) { - case Constants.NBT.TAG_BYTE: // byte + case TAG_BYTE: return ((NBTTagByte) tag).getByte() > 0; - case Constants.NBT.TAG_DOUBLE: // Double + case TAG_DOUBLE: return ((NBTTagDouble) tag).getDouble(); - case Constants.NBT.TAG_STRING: // String - return ((NBTTagString) tag).getString(); - case Constants.NBT.TAG_COMPOUND: // Compound + default: + case TAG_STRING: + return tag.getString(); + case TAG_COMPOUND: { NBTTagCompound c = (NBTTagCompound) tag; - int len = c.getInteger( "len" ); + int len = c.getInt( "len" ); Map map = new HashMap<>( len ); for( int i = 0; i < len; i++ ) { - Object key = fromNBTTag( c.getTag( "k" + i ) ); - Object value = fromNBTTag( c.getTag( "v" + i ) ); + Object key = fromNBTTag( c.get( "k" + i ) ); + Object value = fromNBTTag( c.get( "v" + i ) ); if( key != null && value != null ) map.put( key, value ); } return map; } - default: - return null; } } - public static Object toLua( NBTBase tag ) + public static Object toLua( INBTBase tag ) { if( tag == null ) return null; @@ -111,14 +105,14 @@ public static Object toLua( NBTBase tag ) case Constants.NBT.TAG_DOUBLE: return ((NBTPrimitive) tag).getDouble(); case Constants.NBT.TAG_STRING: // String - return ((NBTTagString) tag).getString(); + return tag.getString(); case Constants.NBT.TAG_COMPOUND: // Compound { NBTTagCompound compound = (NBTTagCompound) tag; - Map map = new HashMap<>( compound.getSize() ); - for( String key : compound.getKeySet() ) + Map map = new HashMap<>( compound.size() ); + for( String key : compound.keySet() ) { - Object value = toLua( compound.getTag( key ) ); + Object value = toLua( compound.get( key ) ); if( value != null ) map.put( key, value ); } return map; @@ -126,8 +120,8 @@ public static Object toLua( NBTBase tag ) case Constants.NBT.TAG_LIST: { NBTTagList list = (NBTTagList) tag; - Map map = new HashMap<>( list.tagCount() ); - for( int i = 0; i < list.tagCount(); i++ ) map.put( i, toLua( list.get( i ) ) ); + Map map = new HashMap<>( list.size() ); + for( int i = 0; i < list.size(); i++ ) map.put( i, toLua( list.get( i ) ) ); return map; } case Constants.NBT.TAG_BYTE_ARRAY: @@ -150,41 +144,20 @@ public static Object toLua( NBTBase tag ) } } - public static Object[] decodeObjects( NBTTagCompound tagCompound ) + public static Object[] decodeObjects( NBTTagCompound tag ) { - int len = tagCompound.getInteger( "len" ); + int len = tag.getInt( "len" ); if( len <= 0 ) return null; Object[] objects = new Object[len]; for( int i = 0; i < len; i++ ) { String key = Integer.toString( i ); - if( tagCompound.hasKey( key ) ) objects[i] = fromNBTTag( tagCompound.getTag( key ) ); + if( tag.contains( key ) ) + { + objects[i] = fromNBTTag( tag.get( key ) ); + } } return objects; } - - public static NBTTagCompound readCompoundTag( PacketBuffer buf ) - { - try - { - return buf.readCompoundTag(); - } - catch( IOException e ) - { - throw new UncheckedIOException( e ); - } - } - - public static ITextComponent readTextComponent( PacketBuffer buf ) - { - try - { - return buf.readTextComponent(); - } - catch( IOException e ) - { - throw new UncheckedIOException( e ); - } - } } diff --git a/src/main/java/dan200/computercraft/shared/util/NamedBlockEntityType.java b/src/main/java/dan200/computercraft/shared/util/NamedBlockEntityType.java new file mode 100644 index 000000000..db4c0caad --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/NamedBlockEntityType.java @@ -0,0 +1,81 @@ +/* + * 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.shared.util; + +import com.mojang.datafixers.DataFixUtils; +import com.mojang.datafixers.types.Type; +import dan200.computercraft.ComputerCraft; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SharedConstants; +import net.minecraft.util.datafix.DataFixesManager; +import net.minecraft.util.datafix.TypeReferences; + +import java.util.function.Function; +import java.util.function.Supplier; + +public final class NamedBlockEntityType extends TileEntityType +{ + private final ResourceLocation identifier; + + private NamedBlockEntityType( ResourceLocation identifier, Supplier supplier ) + { + super( supplier, getDatafixer( identifier ) ); + this.identifier = identifier; + setRegistryName( identifier ); + } + + public static NamedBlockEntityType create( ResourceLocation identifier, Supplier supplier ) + { + return new NamedBlockEntityType<>( identifier, supplier ); + } + + public static NamedBlockEntityType create( ResourceLocation identifier, Function, ? extends T> builder ) + { + return new FixedPointSupplier<>( identifier, builder ).factory; + } + + public ResourceLocation getId() + { + return identifier; + } + + public static Type getDatafixer( ResourceLocation id ) + { + try + { + return DataFixesManager.getDataFixer() + .getSchema( DataFixUtils.makeKey( ComputerCraft.DATAFIXER_VERSION ) ) + .getChoiceType( TypeReferences.BLOCK_ENTITY, id.toString() ); + } + catch( IllegalArgumentException e ) + { + if( SharedConstants.developmentMode ) throw e; + ComputerCraft.log.warn( "No data fixer registered for block entity " + id ); + return null; + } + } + + private static final class FixedPointSupplier implements Supplier + { + final NamedBlockEntityType factory; + private final Function, ? extends T> builder; + + private FixedPointSupplier( ResourceLocation identifier, Function, ? extends T> builder ) + { + factory = create( identifier, this ); + this.builder = builder; + } + + @Override + public T get() + { + return builder.apply( factory ); + } + } +} diff --git a/src/main/java/dan200/computercraft/shared/util/Palette.java b/src/main/java/dan200/computercraft/shared/util/Palette.java index b332e8b5f..81d47f50b 100644 --- a/src/main/java/dan200/computercraft/shared/util/Palette.java +++ b/src/main/java/dan200/computercraft/shared/util/Palette.java @@ -89,13 +89,13 @@ public NBTTagCompound writeToNBT( NBTTagCompound nbt ) rgb8[i] = encodeRGB8( colours[i] ); } - nbt.setIntArray( "term_palette", rgb8 ); + nbt.putIntArray( "term_palette", rgb8 ); return nbt; } public void readFromNBT( NBTTagCompound nbt ) { - if( !nbt.hasKey( "term_palette" ) ) return; + if( !nbt.contains( "term_palette" ) ) return; int[] rgb8 = nbt.getIntArray( "term_palette" ); if( rgb8.length != colours.length ) return; diff --git a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java index d2fd270c3..332c9e161 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java @@ -13,17 +13,31 @@ import net.minecraft.item.crafting.Ingredient; import net.minecraft.util.JsonUtils; import net.minecraft.util.NonNullList; -import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.common.crafting.JsonContext; import java.util.Map; import java.util.Set; +// TODO: Replace some things with Forge?? + public final class RecipeUtil { private RecipeUtil() {} - public static CraftingHelper.ShapedPrimer getPrimer( JsonContext context, JsonObject json ) + public static class ShapedTemplate + { + public final int width; + public final int height; + public final NonNullList ingredients; + + public ShapedTemplate( int width, int height, NonNullList ingredients ) + { + this.width = width; + this.height = height; + this.ingredients = ingredients; + } + } + + public static ShapedTemplate getTemplate( JsonObject json ) { Map ingMap = Maps.newHashMap(); for( Map.Entry entry : JsonUtils.getJsonObject( json, "key" ).entrySet() ) @@ -37,7 +51,7 @@ public static CraftingHelper.ShapedPrimer getPrimer( JsonContext context, JsonOb throw new JsonSyntaxException( "Invalid key entry: ' ' is a reserved symbol." ); } - ingMap.put( entry.getKey().charAt( 0 ), CraftingHelper.getIngredient( entry.getValue(), context ) ); + ingMap.put( entry.getKey().charAt( 0 ), Ingredient.deserialize( entry.getValue() ) ); } ingMap.put( ' ', Ingredient.EMPTY ); @@ -60,16 +74,14 @@ public static CraftingHelper.ShapedPrimer getPrimer( JsonContext context, JsonOb pattern[x] = line; } - CraftingHelper.ShapedPrimer primer = new CraftingHelper.ShapedPrimer(); - primer.width = pattern[0].length(); - primer.height = pattern.length; - primer.mirrored = false; - primer.input = NonNullList.withSize( primer.width * primer.height, Ingredient.EMPTY ); + int width = pattern[0].length(); + int height = pattern.length; + NonNullList ingredients = NonNullList.withSize( width * height, Ingredient.EMPTY ); - Set keys = Sets.newHashSet( ingMap.keySet() ); - keys.remove( ' ' ); + Set missingKeys = Sets.newHashSet( ingMap.keySet() ); + missingKeys.remove( ' ' ); - int x = 0; + int i = 0; for( String line : pattern ) { for( char chr : line.toCharArray() ) @@ -79,25 +91,25 @@ public static CraftingHelper.ShapedPrimer getPrimer( JsonContext context, JsonOb { throw new JsonSyntaxException( "Pattern references symbol '" + chr + "' but it's not defined in the key" ); } - primer.input.set( x++, ing ); - keys.remove( chr ); + ingredients.set( i++, ing ); + missingKeys.remove( chr ); } } - if( !keys.isEmpty() ) + if( !missingKeys.isEmpty() ) { - throw new JsonSyntaxException( "Key defines symbols that aren't used in pattern: " + keys ); + throw new JsonSyntaxException( "Key defines symbols that aren't used in pattern: " + missingKeys ); } - return primer; + return new ShapedTemplate( width, height, ingredients ); } - public static NonNullList getIngredients( JsonContext context, JsonObject json ) + public static NonNullList getIngredients( JsonObject json ) { NonNullList ingredients = NonNullList.create(); for( JsonElement ele : JsonUtils.getJsonArray( json, "ingredients" ) ) { - ingredients.add( CraftingHelper.getIngredient( ele, context ) ); + ingredients.add( Ingredient.deserialize( ele ) ); } if( ingredients.isEmpty() ) throw new JsonParseException( "No ingredients for recipe" ); diff --git a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java index 0977775dc..f5ff089e9 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java @@ -7,15 +7,16 @@ package dan200.computercraft.shared.util; import dan200.computercraft.shared.network.NetworkHandler; +import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.client.PlayRecordClientMessage; import net.minecraft.item.Item; import net.minecraft.item.ItemRecord; import net.minecraft.item.ItemStack; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -import net.minecraftforge.fml.common.network.NetworkRegistry; -import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import javax.annotation.Nonnull; @@ -25,10 +26,8 @@ private RecordUtil() {} public static void playRecord( SoundEvent record, String recordInfo, World world, BlockPos pos ) { - IMessage packet = record != null ? new PlayRecordClientMessage( pos, record, recordInfo ) : new PlayRecordClientMessage( pos ); - - NetworkRegistry.TargetPoint point = new NetworkRegistry.TargetPoint( world.provider.getDimension(), pos.getX(), pos.getY(), pos.getZ(), 64 ); - NetworkHandler.sendToAllAround( packet, point ); + NetworkMessage packet = record != null ? new PlayRecordClientMessage( pos, record, recordInfo ) : new PlayRecordClientMessage( pos ); + NetworkHandler.sendToAllAround( packet, world, new Vec3d( pos ), 64 ); } public static String getRecordInfo( @Nonnull ItemStack recordStack ) @@ -36,7 +35,6 @@ public static String getRecordInfo( @Nonnull ItemStack recordStack ) Item item = recordStack.getItem(); if( !(item instanceof ItemRecord) ) return null; - ItemRecord record = (ItemRecord) item; - return StringUtil.translate( record.displayName ); + return new TextComponentTranslation( item.getTranslationKey() + ".desc" ).getString(); } } diff --git a/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java b/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java index 85e5c6717..90ea40e91 100644 --- a/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.util; -import dan200.computercraft.shared.BundledRedstone; import net.minecraft.block.state.IBlockState; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; @@ -14,27 +13,13 @@ public final class RedstoneUtil { - private RedstoneUtil() {} - - @Deprecated - public static int getRedstoneOutput( World world, BlockPos pos, EnumFacing side ) - { - return world.getRedstonePower( pos, side.getOpposite() ); - } - - @Deprecated - public static int getBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side ) - { - return BundledRedstone.getOutput( world, pos, side ); - } - public static void propagateRedstoneOutput( World world, BlockPos pos, EnumFacing side ) { // Propagate ordinary output IBlockState block = world.getBlockState( pos ); BlockPos neighbourPos = pos.offset( side ); IBlockState neighbour = world.getBlockState( neighbourPos ); - if( neighbour.getBlock().isAir( neighbour, world, neighbourPos ) ) + if( !neighbour.isAir( world, pos ) ) { world.neighborChanged( neighbourPos, block.getBlock(), pos ); if( neighbour.getBlock().isNormalCube( neighbour, world, neighbourPos ) ) diff --git a/src/main/java/dan200/computercraft/shared/util/StringUtil.java b/src/main/java/dan200/computercraft/shared/util/StringUtil.java index 8c92a25a4..d8ebcd0e3 100644 --- a/src/main/java/dan200/computercraft/shared/util/StringUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/StringUtil.java @@ -32,24 +32,6 @@ public static String normaliseLabel( String label ) return builder.toString(); } - /** - * Translates a Stat name - */ - @SuppressWarnings( "deprecation" ) - public static String translate( String key ) - { - return net.minecraft.util.text.translation.I18n.translateToLocal( key ); - } - - /** - * Translates a Stat name with format args - */ - @SuppressWarnings( "deprecation" ) - public static String translateFormatted( String key, Object... format ) - { - return net.minecraft.util.text.translation.I18n.translateToLocalFormatted( key, format ); - } - public static byte[] encodeString( String string ) { byte[] chars = new byte[string.length()]; diff --git a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java index 62ac366cc..6a367da98 100644 --- a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java +++ b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java @@ -9,12 +9,12 @@ import com.google.common.collect.MapMaker; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.common.TileGeneric; -import net.minecraft.block.Block; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.ITickList; import net.minecraft.world.World; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; import java.util.Collections; @@ -22,7 +22,7 @@ import java.util.Set; /** - * A thread-safe version of {@link World#scheduleUpdate(BlockPos, Block, int)}. + * A thread-safe version of {@link ITickList#scheduleTick(BlockPos, Object, int)}. * * We use this when modems and other peripherals change a block in a different thread. */ @@ -61,7 +61,7 @@ public static void tick( TickEvent.ServerTickEvent event ) if( world != null && pos != null && world.isBlockLoaded( pos ) && world.getTileEntity( pos ) == tile ) { - world.scheduleUpdate( pos, tile.getBlockType(), 0 ); + world.getPendingBlockTicks().scheduleTick( pos, tile.getBlockState().getBlock(), 0 ); } } } diff --git a/src/main/java/dan200/computercraft/shared/util/WaterloggableBlock.java b/src/main/java/dan200/computercraft/shared/util/WaterloggableBlock.java new file mode 100644 index 000000000..4c0f593c5 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/WaterloggableBlock.java @@ -0,0 +1,99 @@ +/* + * 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.shared.util; + +import net.minecraft.block.IBucketPickupHandler; +import net.minecraft.block.ILiquidContainer; +import net.minecraft.block.state.IBlockState; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.IFluidState; +import net.minecraft.init.Fluids; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.state.BooleanProperty; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorld; + +import javax.annotation.Nonnull; + +/** + * Represents a block which can be filled with water + * + * I'm fairly sure this exists on 1.14, but it's a useful convenience wrapper to have on 1.13. + */ +public interface WaterloggableBlock extends IBucketPickupHandler, ILiquidContainer +{ + BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; + + /** + * Call from {@link net.minecraft.block.Block#getFluidState(IBlockState)} + * + * @param state The current state + * @return This waterlogged block's current fluid + */ + default IFluidState getWaterloggedFluidState( IBlockState state ) + { + return state.get( WATERLOGGED ) ? Fluids.WATER.getStillFluidState( false ) : Fluids.EMPTY.getDefaultState(); + } + + @Nonnull + @Override + default Fluid pickupFluid( @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull IBlockState state ) + { + if( state.get( WATERLOGGED ) ) + { + world.setBlockState( pos, state.with( WATERLOGGED, false ), 3 ); + return Fluids.WATER; + } + else + { + return Fluids.EMPTY; + } + } + + @Override + default boolean canContainFluid( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nonnull Fluid fluid ) + { + return !state.get( WATERLOGGED ) && fluid == Fluids.WATER; + } + + @Override + default boolean receiveFluid( @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nonnull IFluidState fluid ) + { + if( !canContainFluid( world, pos, state, fluid.getFluid() ) ) return false; + + if( !world.isRemote() ) + { + world.setBlockState( pos, state.with( WATERLOGGED, true ), 3 ); + world.getPendingFluidTicks().scheduleTick( pos, fluid.getFluid(), fluid.getFluid().getTickRate( world ) ); + } + + return true; + } + + /** + * Call from {@link net.minecraft.block.Block#updatePostPlacement(IBlockState, EnumFacing, IBlockState, IWorld, BlockPos, BlockPos)} + * + * @param state The current state + * @param world The position of this block + * @param pos The world this block exists in + */ + default void updateWaterloggedPostPlacement( IBlockState state, IWorld world, BlockPos pos ) + { + if( state.get( WATERLOGGED ) ) + { + world.getPendingFluidTicks().scheduleTick( pos, Fluids.WATER, Fluids.WATER.getTickRate( world ) ); + } + } + + default boolean getWaterloggedStateForPlacement( BlockItemUseContext context ) + { + return context.getWorld().getFluidState( context.getPos() ).getFluid() == Fluids.WATER; + } +} diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index d6a76dbfa..ecf7da47e 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -7,6 +7,7 @@ package dan200.computercraft.shared.util; import com.google.common.base.Predicate; +import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; @@ -17,6 +18,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.World; import org.apache.commons.lang3.tuple.Pair; @@ -26,19 +28,21 @@ public final class WorldUtil { @SuppressWarnings( "Guava" ) - private static final Predicate CAN_COLLIDE = x -> x != null && !x.isDead && x.canBeCollidedWith(); - - private WorldUtil() {} - - @Deprecated - public static boolean isBlockInWorld( World world, BlockPos pos ) - { - return world.isValid( pos ); - } + private static final Predicate CAN_COLLIDE = x -> x != null && x.isAlive() && x.canBeCollidedWith(); public static boolean isLiquidBlock( World world, BlockPos pos ) { - return world.getBlockState( pos ).getMaterial().isLiquid(); + if( !World.isValid( pos ) ) return false; + IBlockState state = world.getBlockState( pos ); + return !state.getFluidState().isEmpty(); + } + + public static boolean isVecInside( VoxelShape shape, Vec3d vec ) + { + if( shape.isEmpty() ) return false; + // return shape.contains( pos.x, pos.y, pos.z ); + AxisAlignedBB 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; } public static Pair rayTraceEntities( World world, Vec3d vecStart, Vec3d vecDir, double distance ) @@ -47,7 +51,7 @@ public static Pair rayTraceEntities( World world, Vec3d vecStart, // Raycast for blocks RayTraceResult result = world.rayTraceBlocks( vecStart, vecEnd ); - if( result != null && result.typeOfHit == RayTraceResult.Type.BLOCK ) + if( result != null && result.type == RayTraceResult.Type.BLOCK ) { distance = vecStart.distanceTo( result.hitVec ); vecEnd = vecStart.add( vecDir.x * distance, vecDir.y * distance, vecDir.z * distance ); @@ -71,7 +75,7 @@ public static Pair rayTraceEntities( World world, Vec3d vecStart, List list = world.getEntitiesWithinAABB( Entity.class, bigBox, CAN_COLLIDE ); for( Entity entity : list ) { - AxisAlignedBB littleBox = entity.getEntityBoundingBox(); + AxisAlignedBB littleBox = entity.getBoundingBox(); if( littleBox == null ) { littleBox = entity.getCollisionBoundingBox(); @@ -117,21 +121,16 @@ else if( littleBox.intersects( bigBox ) ) public static Vec3d getRayStart( EntityLivingBase entity ) { - return new Vec3d( entity.posX, entity.posY + entity.getEyeHeight(), entity.posZ ); + return entity.getEyePosition( 1 ); } public static Vec3d getRayEnd( EntityPlayer player ) { - double reach = player.getEntityAttribute( EntityPlayer.REACH_DISTANCE ).getAttributeValue(); + double reach = player.getAttribute( EntityPlayer.REACH_DISTANCE ).getValue(); Vec3d look = player.getLookVec(); return getRayStart( player ).add( look.x * reach, look.y * reach, look.z * reach ); } - public static boolean isVecInsideInclusive( AxisAlignedBB bb, Vec3d vec ) - { - 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; - } - public static void dropItemStack( @Nonnull ItemStack stack, World world, BlockPos pos ) { dropItemStack( stack, world, pos, null ); @@ -168,11 +167,11 @@ public static void dropItemStack( @Nonnull ItemStack stack, World world, double public static void dropItemStack( @Nonnull ItemStack stack, World world, double xPos, double yPos, double zPos, double xDir, double yDir, double zDir ) { - EntityItem entityItem = new EntityItem( world, xPos, yPos, zPos, stack.copy() ); - entityItem.motionX = xDir * 0.7 + world.rand.nextFloat() * 0.2 - 0.1; - entityItem.motionY = yDir * 0.7 + world.rand.nextFloat() * 0.2 - 0.1; - entityItem.motionZ = zDir * 0.7 + world.rand.nextFloat() * 0.2 - 0.1; - entityItem.setDefaultPickupDelay(); - world.spawnEntity( entityItem ); + EntityItem item = new EntityItem( world, xPos, yPos, zPos, stack.copy() ); + item.motionX = xDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1; + item.motionY = yDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1; + item.motionZ = zDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1; + item.setDefaultPickupDelay(); + world.spawnEntity( item ); } } diff --git a/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java b/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java index 12b626aaa..d484f94bb 100644 --- a/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java +++ b/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java @@ -8,15 +8,17 @@ import dan200.computercraft.api.network.wired.IWiredElement; import dan200.computercraft.api.network.wired.IWiredNode; -import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.INBTBase; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.CapabilityInject; import net.minecraftforge.common.capabilities.CapabilityManager; +import net.minecraftforge.common.util.LazyOptional; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public final class CapabilityWiredElement { @@ -64,14 +66,23 @@ public String getSenderID() private static class NullStorage implements Capability.IStorage { @Override - public NBTBase writeNBT( Capability capability, IWiredElement instance, EnumFacing side ) + public INBTBase writeNBT( Capability capability, IWiredElement instance, EnumFacing side ) { return null; } @Override - public void readNBT( Capability capability, IWiredElement instance, EnumFacing side, NBTBase base ) + public void readNBT( Capability capability, IWiredElement instance, EnumFacing side, INBTBase base ) { } } + + private static final IWiredElement NULL_ELEMENT = new NullElement(); + + @Nullable + public static IWiredElement unwrap( LazyOptional capability ) + { + IWiredElement element = capability.orElse( NULL_ELEMENT ); + return element == NULL_ELEMENT ? null : element; + } } diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index 5b6828a3e..6273708c6 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -73,7 +73,6 @@ public class ComputerTestDelegate public void before() { ComputerCraft.logPeripheralErrors = true; - ComputerCraft.log = LogManager.getLogger( ComputerCraft.MOD_ID ); Terminal term = new Terminal( 78, 20 ); IWritableMount mount = new MemoryMount() diff --git a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java index dbd3ccf35..e9dc940c4 100644 --- a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java +++ b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java @@ -12,7 +12,6 @@ import dan200.computercraft.core.filesystem.FileMount; import dan200.computercraft.core.filesystem.JarMount; import dan200.computercraft.core.filesystem.MemoryMount; -import net.minecraftforge.fml.common.Loader; import java.io.File; import java.io.IOException; @@ -78,19 +77,19 @@ public long getComputerSpaceLimit() @Override public String getHostString() { - return "ComputerCraft ${version} (Minecraft " + Loader.MC_VERSION + ")"; + return "ComputerCraft ${version} (Test environment)"; } @Override public IMount createResourceMount( String domain, String subPath ) { - return createMount( ComputerCraft.class, "assets/" + domain + "/" + subPath, "main" ); + return createMount( ComputerCraft.class, "data/" + domain + "/" + subPath, "main" ); } @Override public InputStream createResourceFile( String domain, String subPath ) { - return ComputerCraft.class.getClassLoader().getResourceAsStream( "assets/" + domain + "/" + subPath ); + return ComputerCraft.class.getClassLoader().getResourceAsStream( "data/" + domain + "/" + subPath ); } diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java index 2a7c9e551..55a74a0b1 100644 --- a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java +++ b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java @@ -15,7 +15,6 @@ import dan200.computercraft.core.apis.ArgumentHelper; import dan200.computercraft.core.filesystem.MemoryMount; import dan200.computercraft.core.terminal.Terminal; -import org.apache.logging.log4j.LogManager; import org.junit.jupiter.api.Assertions; import javax.annotation.Nonnull; @@ -30,11 +29,6 @@ public class ComputerBootstrap private static final int TPS = 20; private static final int MAX_TIME = 10; - public static void run( IMount mount, Consumer setup ) - { - - } - public static void run( String program ) { MemoryMount mount = new MemoryMount() @@ -47,7 +41,6 @@ public static void run( String program ) public static void run( IWritableMount mount, Consumer setup ) { ComputerCraft.logPeripheralErrors = true; - ComputerCraft.log = LogManager.getLogger( ComputerCraft.MOD_ID ); Terminal term = new Terminal( ComputerCraft.terminalWidth_computer, ComputerCraft.terminalHeight_computer ); final Computer computer = new Computer( new BasicEnvironment( mount ), term, 0 ); diff --git a/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java new file mode 100644 index 000000000..30cc449be --- /dev/null +++ b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java @@ -0,0 +1,79 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.filesystem; + +import dan200.computercraft.api.filesystem.IMount; +import net.minecraft.resources.FolderPack; +import net.minecraft.resources.ResourcePackType; +import net.minecraft.resources.SimpleReloadableResourceManager; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class ResourceMountTest +{ + private IMount mount; + + @BeforeEach + public void before() + { + SimpleReloadableResourceManager manager = new SimpleReloadableResourceManager( ResourcePackType.SERVER_DATA ); + manager.addResourcePack( new FolderPack( new File( "src/main/resources" ) ) ); + + mount = new ResourceMount( "computercraft", "lua/rom", manager ); + } + + @Test + public void testList() throws IOException + { + List files = new ArrayList<>(); + mount.list( "", files ); + files.sort( Comparator.naturalOrder() ); + + assertEquals( + Arrays.asList( "apis", "autorun", "help", "modules", "programs", "startup.lua" ), + files + ); + } + + @Test + public void testExists() throws IOException + { + assertTrue( mount.exists( "" ) ); + assertTrue( mount.exists( "startup.lua" ) ); + assertTrue( mount.exists( "programs/fun/advanced/paint.lua" ) ); + + assertFalse( mount.exists( "programs/fun/advance/paint.lua" ) ); + assertFalse( mount.exists( "programs/fun/advanced/paint.lu" ) ); + } + + @Test + public void testIsDir() throws IOException + { + assertTrue( mount.isDirectory( "" ) ); + } + + @Test + public void testIsFile() throws IOException + { + assertFalse( mount.isDirectory( "startup.lua" ) ); + } + + @Test + public void testSize() throws IOException + { + assertNotEquals( mount.getSize( "startup.lua" ), 0 ); + } +} diff --git a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java index 6a44ccba4..6d5329b69 100644 --- a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java +++ b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java @@ -8,7 +8,6 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; @@ -18,14 +17,12 @@ import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.shared.util.DirectionUtil; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -import org.apache.logging.log4j.LogManager; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import javax.annotation.Nonnull; @@ -39,12 +36,6 @@ public class NetworkTest { - @BeforeEach - public void setup() - { - ComputerCraft.log = LogManager.getLogger(); - } - @Test public void testConnect() { @@ -270,7 +261,7 @@ public void testLarge() long start = System.nanoTime(); grid.forEach( ( existing, pos ) -> { - for( EnumFacing facing : EnumFacing.VALUES ) + for( EnumFacing facing : DirectionUtil.FACINGS ) { BlockPos offset = pos.offset( facing ); if( offset.getX() > BRUTE_SIZE / 2 == pos.getX() > BRUTE_SIZE / 2 )