commit db2ad29b52d667eb463ef43c3399b045bd42d6f0 Author: GlodBlock <1356392126@qq.com> Date: Tue May 10 17:57:38 2022 +0800 begin work diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..6effbc91 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# This is the universal Text Editor Configuration +# for all GTNewHorizons projects +# See: https://editorconfig.org/ + +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{bat,ini}] +end_of_line = crlf + +[*.{dtd,json,info,mcmeta,md,sh,svg,xml,xsd,xsl,yaml,yml}] +indent_size = 2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..7e4570ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.bat +.gradle/ +.idea/ +out/ +*.iml +*.ipr +*.iws +run/ diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000..a6b5f68c --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,3 @@ +# Any Github changes require admin approval +/.github/** @GTNewHorizons/admin + diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..c8cf37cd --- /dev/null +++ b/build.gradle @@ -0,0 +1,738 @@ +//version: 1644894948 +/* +DO NOT CHANGE THIS FILE! + +Also, you may replace this file at any time if there is an update available. +Please check https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/build.gradle for updates. +*/ + +import org.gradle.internal.logging.text.StyledTextOutput +import org.gradle.internal.logging.text.StyledTextOutputFactory +import org.gradle.internal.logging.text.StyledTextOutput.Style + +import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +import java.util.concurrent.TimeUnit + +buildscript { + repositories { + maven { + name 'forge' + url 'https://maven.minecraftforge.net' + } + maven { + name 'sonatype' + url 'https://oss.sonatype.org/content/repositories/snapshots/' + } + maven { + name 'Scala CI dependencies' + url 'https://repo1.maven.org/maven2/' + } + maven { + name 'jitpack' + url 'https://jitpack.io' + } + } + dependencies { + classpath 'com.github.GTNewHorizons:ForgeGradle:1.2.7' + } +} + +plugins { + id 'java-library' + id 'idea' + id 'eclipse' + id 'scala' + id 'maven-publish' + id 'org.jetbrains.kotlin.jvm' version '1.5.30' apply false + id 'org.jetbrains.kotlin.kapt' version '1.5.30' apply false + id 'org.ajoberstar.grgit' version '4.1.1' + id 'com.github.johnrengelman.shadow' version '4.0.4' + id 'com.palantir.git-version' version '0.13.0' apply false + id 'de.undercouch.download' version '5.0.1' + id 'com.github.gmazzo.buildconfig' version '3.0.3' apply false +} + +if (project.file('.git/HEAD').isFile()) { + apply plugin: 'com.palantir.git-version' +} + +def out = services.get(StyledTextOutputFactory).create('an-output') + +apply plugin: 'forge' + +def projectJavaVersion = JavaLanguageVersion.of(8) + +java { + toolchain { + languageVersion.set(projectJavaVersion) + } +} + +idea { + module { + inheritOutputDirs = true + downloadJavadoc = true + downloadSources = true + } +} + +if(JavaVersion.current() != JavaVersion.VERSION_1_8) { + throw new GradleException("This project requires Java 8, but it's running on " + JavaVersion.current()) +} + +checkPropertyExists("modName") +checkPropertyExists("modId") +checkPropertyExists("modGroup") +checkPropertyExists("autoUpdateBuildScript") +checkPropertyExists("minecraftVersion") +checkPropertyExists("forgeVersion") +checkPropertyExists("replaceGradleTokenInFile") +checkPropertyExists("gradleTokenModId") +checkPropertyExists("gradleTokenModName") +checkPropertyExists("gradleTokenVersion") +checkPropertyExists("gradleTokenGroupName") +checkPropertyExists("apiPackage") +checkPropertyExists("accessTransformersFile") +checkPropertyExists("usesMixins") +checkPropertyExists("mixinPlugin") +checkPropertyExists("mixinsPackage") +checkPropertyExists("coreModClass") +checkPropertyExists("containsMixinsAndOrCoreModOnly") +checkPropertyExists("usesShadowedDependencies") +checkPropertyExists("developmentEnvironmentUserName") + +boolean noPublishedSources = project.findProperty("noPublishedSources") ? project.noPublishedSources.toBoolean() : false + +String javaSourceDir = "src/main/java/" +String scalaSourceDir = "src/main/scala/" +String kotlinSourceDir = "src/main/kotlin/" + +String targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") +String targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") +String targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") +if(!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) { + throw new GradleException("Could not resolve \"modGroup\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin) +} + +if(apiPackage) { + targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + if(!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) { + throw new GradleException("Could not resolve \"apiPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin) + } +} + +if(accessTransformersFile) { + String targetFile = "src/main/resources/META-INF/" + accessTransformersFile + if(!getFile(targetFile).exists()) { + throw new GradleException("Could not resolve \"accessTransformersFile\"! Could not find " + targetFile) + } +} + +if(usesMixins.toBoolean()) { + if(mixinsPackage.isEmpty() || mixinPlugin.isEmpty()) { + throw new GradleException("\"mixinPlugin\" requires \"mixinsPackage\" and \"mixinPlugin\" to be set!") + } + + targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/") + targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/") + targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/") + if(!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) { + throw new GradleException("Could not resolve \"mixinsPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin) + } + + String targetFileJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".java" + String targetFileScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".scala" + String targetFileScalaJava = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".java" + String targetFileKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".kt" + if(!(getFile(targetFileJava).exists() || getFile(targetFileScala).exists() || getFile(targetFileScalaJava).exists() || getFile(targetFileKotlin).exists())) { + throw new GradleException("Could not resolve \"mixinPlugin\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava + " or " + targetFileKotlin) + } +} + +if(coreModClass) { + String targetFileJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".java" + String targetFileScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".scala" + String targetFileScalaJava = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".java" + String targetFileKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".kt" + if(!(getFile(targetFileJava).exists() || getFile(targetFileScala).exists() || getFile(targetFileScalaJava).exists() || getFile(targetFileKotlin).exists())) { + throw new GradleException("Could not resolve \"coreModClass\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava + " or " + targetFileKotlin) + } +} + +configurations.all { + resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS) + + // Make sure GregTech build won't time out + System.setProperty("org.gradle.internal.http.connectionTimeout", 120000 as String) + System.setProperty("org.gradle.internal.http.socketTimeout", 120000 as String) +} + +// Fix Jenkins' Git: chmod a file should not be detected as a change and append a '.dirty' to the version +try { + 'git config core.fileMode false'.execute() +} +catch (Exception ignored) { + out.style(Style.Failure).println("git isn't installed at all") +} + +// Pulls version first from the VERSION env and then git tag +String identifiedVersion +String versionOverride = System.getenv("VERSION") ?: null +try { + identifiedVersion = versionOverride == null ? gitVersion() : versionOverride +} +catch (Exception ignored) { + out.style(Style.Failure).text( + 'This mod must be version controlled by Git AND the repository must provide at least one tag,\n' + + 'or the VERSION override must be set! ').style(Style.SuccessHeader).text('(Do NOT download from GitHub using the ZIP option, instead\n' + + 'clone the repository, see ').style(Style.Info).text('https://gtnh.miraheze.org/wiki/Development').style(Style.SuccessHeader).println(' for details.)' + ) + versionOverride = 'NO-GIT-TAG-SET' + identifiedVersion = versionOverride +} +version = minecraftVersion + '-' + identifiedVersion +ext { + modVersion = identifiedVersion +} + +if(identifiedVersion == versionOverride) { + out.style(Style.Failure).text('Override version to ').style(Style.Identifier).text(modVersion).style(Style.Failure).println('!\7') +} + +group = modGroup +if(project.hasProperty("customArchiveBaseName") && customArchiveBaseName) { + archivesBaseName = customArchiveBaseName +} +else { + archivesBaseName = modId +} + +def arguments = [] +def jvmArguments = [] + +if(usesMixins.toBoolean()) { + arguments += [ + "--tweakClass org.spongepowered.asm.launch.MixinTweaker" + ] + jvmArguments += [ + "-Dmixin.debug.countInjections=true", "-Dmixin.debug.verbose=true", "-Dmixin.debug.export=true" + ] +} + +minecraft { + version = minecraftVersion + '-' + forgeVersion + '-' + minecraftVersion + runDir = 'run' + + if (replaceGradleTokenInFile) { + replaceIn replaceGradleTokenInFile + if(gradleTokenModId) { + replace gradleTokenModId, modId + } + if(gradleTokenModName) { + replace gradleTokenModName, modName + } + if(gradleTokenVersion) { + replace gradleTokenVersion, modVersion + } + if(gradleTokenGroupName) { + replace gradleTokenGroupName, modGroup + } + } + + clientIntellijRun { + args(arguments) + jvmArgs(jvmArguments) + + if(developmentEnvironmentUserName) { + args("--username", developmentEnvironmentUserName) + } + } + + serverIntellijRun { + args(arguments) + jvmArgs(jvmArguments) + } +} + +if(file('addon.gradle').exists()) { + apply from: 'addon.gradle' +} + +apply from: 'repositories.gradle' + +configurations { + implementation.extendsFrom(shadowImplementation) // TODO: remove after all uses are refactored + implementation.extendsFrom(shadowCompile) + implementation.extendsFrom(shadeCompile) +} + +repositories { + maven { + name 'Overmind forge repo mirror' + url 'https://gregtech.overminddl1.com/' + } + if(usesMixins.toBoolean()) { + maven { + name 'sponge' + url 'https://repo.spongepowered.org/repository/maven-public' + } + maven { + url 'https://jitpack.io' + } + } +} + +dependencies { + if(usesMixins.toBoolean()) { + annotationProcessor('org.ow2.asm:asm-debug-all:5.0.3') + annotationProcessor('com.google.guava:guava:24.1.1-jre') + annotationProcessor('com.google.code.gson:gson:2.8.6') + annotationProcessor('org.spongepowered:mixin:0.8-SNAPSHOT') + // using 0.8 to workaround a issue in 0.7 which fails mixin application + compile('com.github.GTNewHorizons:SpongePoweredMixin:0.7.12-GTNH') { + // Mixin includes a lot of dependencies that are too up-to-date + exclude module: 'launchwrapper' + exclude module: 'guava' + exclude module: 'gson' + exclude module: 'commons-io' + exclude module: 'log4j-core' + } + compile('com.github.GTNewHorizons:SpongeMixins:1.5.0') + } +} + +apply from: 'dependencies.gradle' + +def mixingConfigRefMap = 'mixins.' + modId + '.refmap.json' +def refMap = "${tasks.compileJava.temporaryDir}" + File.separator + mixingConfigRefMap +def mixinSrg = "${tasks.reobf.temporaryDir}" + File.separator + "mixins.srg" + +task generateAssets { + if(usesMixins.toBoolean()) { + getFile("/src/main/resources/mixins." + modId + ".json").text = """{ + "required": true, + "minVersion": "0.7.11", + "package": "${modGroup}.${mixinsPackage}", + "plugin": "${modGroup}.${mixinPlugin}", + "refmap": "${mixingConfigRefMap}", + "target": "@env(DEFAULT)", + "compatibilityLevel": "JAVA_8" +} + +""" + } +} + +task relocateShadowJar(type: ConfigureShadowRelocation) { + target = tasks.shadowJar + prefix = modGroup + ".shadow" +} + +shadowJar { + project.configurations.shadeCompile.each { dep -> + from(project.zipTree(dep)) { + exclude 'META-INF', 'META-INF/**' + } + } + + manifest { + attributes(getManifestAttributes()) + } + + minimize() // This will only allow shading for actually used classes + configurations = [project.configurations.shadowImplementation, project.configurations.shadowCompile] + dependsOn(relocateShadowJar) +} + +jar { + project.configurations.shadeCompile.each { dep -> + from(project.zipTree(dep)) { + exclude 'META-INF', 'META-INF/**' + } + } + + manifest { + attributes(getManifestAttributes()) + } + + if(usesShadowedDependencies.toBoolean()) { + dependsOn(shadowJar) + enabled = false + } +} + +reobf { + if(usesMixins.toBoolean()) { + addExtraSrgFile mixinSrg + } +} + +afterEvaluate { + if(usesMixins.toBoolean()) { + tasks.compileJava { + options.compilerArgs += [ + "-AreobfSrgFile=${tasks.reobf.srg}", + "-AoutSrgFile=${mixinSrg}", + "-AoutRefMapFile=${refMap}", + // Elan: from what I understand they are just some linter configs so you get some warning on how to properly code + "-XDenableSunApiLintControl", + "-XDignore.symbol.file" + ] + } + } +} + +runClient { + if(developmentEnvironmentUserName) { + arguments += [ + "--username", + developmentEnvironmentUserName + ] + } + + args(arguments) + jvmArgs(jvmArguments) +} + +runServer { + args(arguments) + jvmArgs(jvmArguments) +} + +tasks.withType(JavaExec).configureEach { + javaLauncher.set( + javaToolchains.launcherFor { + languageVersion = projectJavaVersion + } + ) +} + +processResources { + // this will ensure that this task is redone when the versions change. + inputs.property "version", project.version + inputs.property "mcversion", project.minecraft.version + + // replace stuff in mcmod.info, nothing else + from(sourceSets.main.resources.srcDirs) { + include 'mcmod.info' + + // replace modVersion and minecraftVersion + expand "minecraftVersion": project.minecraft.version, + "modVersion": modVersion, + "modId": modId, + "modName": modName + } + + if(usesMixins.toBoolean()) { + from refMap + } + + // copy everything else that's not the mcmod.info + from(sourceSets.main.resources.srcDirs) { + exclude 'mcmod.info' + } +} + +def getManifestAttributes() { + def manifestAttributes = [:] + if(!containsMixinsAndOrCoreModOnly.toBoolean() && (usesMixins.toBoolean() || coreModClass)) { + manifestAttributes += ["FMLCorePluginContainsFMLMod": true] + } + + if(accessTransformersFile) { + manifestAttributes += ["FMLAT" : accessTransformersFile.toString()] + } + + if(coreModClass) { + manifestAttributes += ["FMLCorePlugin": modGroup + "." + coreModClass] + } + + if(usesMixins.toBoolean()) { + manifestAttributes += [ + "TweakClass" : "org.spongepowered.asm.launch.MixinTweaker", + "MixinConfigs" : "mixins." + modId + ".json", + "ForceLoadAsMod" : !containsMixinsAndOrCoreModOnly.toBoolean() + ] + } + return manifestAttributes +} + +task sourcesJar(type: Jar) { + from (sourceSets.main.allJava) + from (file("$projectDir/LICENSE")) + getArchiveClassifier().set('sources') +} + +task shadowDevJar(type: ShadowJar) { + project.configurations.shadeCompile.each { dep -> + from(project.zipTree(dep)) { + exclude 'META-INF', 'META-INF/**' + } + } + + from sourceSets.main.output + getArchiveClassifier().set("dev") + + manifest { + attributes(getManifestAttributes()) + } + + minimize() // This will only allow shading for actually used classes + configurations = [project.configurations.shadowImplementation, project.configurations.shadowCompile] +} + +task relocateShadowDevJar(type: ConfigureShadowRelocation) { + target = tasks.shadowDevJar + prefix = modGroup + ".shadow" +} + +task circularResolverJar(type: Jar) { + dependsOn(relocateShadowDevJar) + dependsOn(shadowDevJar) + enabled = false +} + +task devJar(type: Jar) { + project.configurations.shadeCompile.each { dep -> + from(project.zipTree(dep)) { + exclude 'META-INF', 'META-INF/**' + } + } + + from sourceSets.main.output + getArchiveClassifier().set("dev") + + manifest { + attributes(getManifestAttributes()) + } + + if(usesShadowedDependencies.toBoolean()) { + dependsOn(circularResolverJar) + enabled = false + } +} + +task apiJar(type: Jar) { + from (sourceSets.main.allJava) { + include modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + '/**' + } + + from (sourceSets.main.output) { + include modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + '/**' + } + + from (sourceSets.main.resources.srcDirs) { + include("LICENSE") + } + + getArchiveClassifier().set('api') +} + +artifacts { + if(!noPublishedSources) { + archives sourcesJar + } + archives devJar + if(apiPackage) { + archives apiJar + } +} + +// The gradle metadata includes all of the additional deps that we disabled from POM generation (including forgeBin with no groupID), +// and isn't strictly needed with the POM so just disable it. +tasks.withType(GenerateModuleMetadata) { + enabled = false +} + +// workaround variable hiding in pom processing +def projectConfigs = project.configurations + +publishing { + publications { + maven(MavenPublication) { + from components.java + if(usesShadowedDependencies.toBoolean()) { + artifact source: shadowJar, classifier: "" + } + if(!noPublishedSources) { + artifact source: sourcesJar, classifier: "src" + } + artifact source: usesShadowedDependencies.toBoolean() ? shadowDevJar : devJar, classifier: "dev" + if (apiPackage) { + artifact source: apiJar, classifier: "api" + } + + groupId = System.getenv("ARTIFACT_GROUP_ID") ?: "com.github.GTNewHorizons" + artifactId = System.getenv("ARTIFACT_ID") ?: project.name + // Using the identified version, not project.version as it has the prepended 1.7.10 + version = System.getenv("RELEASE_VERSION") ?: identifiedVersion + + // remove extra garbage from minecraft and minecraftDeps configuration + pom.withXml { + def badArtifacts = [:].withDefault {[] as Set} + for (configuration in [projectConfigs.minecraft, projectConfigs.minecraftDeps]) { + for (dependency in configuration.allDependencies) { + badArtifacts[dependency.group == null ? "" : dependency.group] += dependency.name + } + } + // example for specifying extra stuff to ignore + // badArtifacts["org.example.group"] += "artifactName" + + Node pomNode = asNode() + pomNode.dependencies.'*'.findAll() { + badArtifacts[it.groupId.text()].contains(it.artifactId.text()) + }.each() { + it.parent().remove(it) + } + } + } + } + + repositories { + maven { + url = "http://jenkins.usrv.eu:8081/nexus/content/repositories/releases" + credentials { + username = System.getenv("MAVEN_USER") ?: "NONE" + password = System.getenv("MAVEN_PASSWORD") ?: "NONE" + } + } + } +} + +// Updating +task updateBuildScript { + doLast { + if (performBuildScriptUpdate(projectDir.toString())) return + + print("Build script already up-to-date!") + } +} + +if (isNewBuildScriptVersionAvailable(projectDir.toString())) { + if (autoUpdateBuildScript.toBoolean()) { + performBuildScriptUpdate(projectDir.toString()) + } else { + out.style(Style.SuccessHeader).println("Build script update available! Run 'gradle updateBuildScript'") + } +} + +static URL availableBuildScriptUrl() { + new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/main/build.gradle") +} + +boolean performBuildScriptUpdate(String projectDir) { + if (isNewBuildScriptVersionAvailable(projectDir)) { + def buildscriptFile = getFile("build.gradle") + availableBuildScriptUrl().withInputStream { i -> buildscriptFile.withOutputStream { it << i } } + out.style(Style.Success).print("Build script updated. Please REIMPORT the project or RESTART your IDE!") + return true + } + return false +} + +boolean isNewBuildScriptVersionAvailable(String projectDir) { + Map parameters = ["connectTimeout": 2000, "readTimeout": 2000] + + String currentBuildScript = getFile("build.gradle").getText() + String currentBuildScriptHash = getVersionHash(currentBuildScript) + String availableBuildScript = availableBuildScriptUrl().newInputStream(parameters).getText() + String availableBuildScriptHash = getVersionHash(availableBuildScript) + + boolean isUpToDate = currentBuildScriptHash.empty || availableBuildScriptHash.empty || currentBuildScriptHash == availableBuildScriptHash + return !isUpToDate +} + +static String getVersionHash(String buildScriptContent) { + String versionLine = buildScriptContent.find("^//version: [a-z0-9]*") + if(versionLine != null) { + return versionLine.split(": ").last() + } + return "" +} + +configure(updateBuildScript) { + group = 'forgegradle' + description = 'Updates the build script to the latest version' +} + +// Deobfuscation + +def deobf(String sourceURL) { + try { + URL url = new URL(sourceURL) + String fileName = url.getFile() + + //get rid of directories: + int lastSlash = fileName.lastIndexOf("/") + if(lastSlash > 0) { + fileName = fileName.substring(lastSlash + 1) + } + //get rid of extension: + if(fileName.endsWith(".jar")) { + fileName = fileName.substring(0, fileName.lastIndexOf(".")) + } + + String hostName = url.getHost() + if(hostName.startsWith("www.")) { + hostName = hostName.substring(4) + } + List parts = Arrays.asList(hostName.split("\\.")) + Collections.reverse(parts) + hostName = String.join(".", parts) + + return deobf(sourceURL, hostName + "/" + fileName) + } catch(Exception e) { + return deobf(sourceURL, "deobf/" + String.valueOf(sourceURL.hashCode())) + } +} + +// The method above is to be preferred. Use this method if the filename is not at the end of the URL. +def deobf(String sourceURL, String fileName) { + String cacheDir = System.getProperty("user.home") + "/.gradle/caches/" + String bon2Dir = cacheDir + "forge_gradle/deobf" + String bon2File = bon2Dir + "/BON2-2.5.0.jar" + String obfFile = cacheDir + "modules-2/files-2.1/" + fileName + ".jar" + String deobfFile = cacheDir + "modules-2/files-2.1/" + fileName + "-deobf.jar" + + if(file(deobfFile).exists()) { + return files(deobfFile) + } + + download.run { + src 'https://github.com/GTNewHorizons/BON2/releases/download/2.5.0/BON2-2.5.0.CUSTOM-all.jar' + dest bon2File + quiet true + overwrite false + } + + download.run { + src sourceURL + dest obfFile + quiet true + overwrite false + } + + exec { + commandLine 'java', '-jar', bon2File, '--inputJar', obfFile, '--outputJar', deobfFile, '--mcVer', '1.7.10', '--mappingsVer', 'stable_12', '--notch' + workingDir bon2Dir + standardOutput = new ByteArrayOutputStream() + } + + return files(deobfFile) +} + +// Helper methods + +def checkPropertyExists(String propertyName) { + if (!project.hasProperty(propertyName)) { + throw new GradleException("This project requires a property \"" + propertyName + "\"! Please add it your \"gradle.properties\". You can find all properties and their description here: https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/gradle.properties") + } +} + +def getFile(String relativePath) { + return new File(projectDir, relativePath) +} diff --git a/dependencies.gradle b/dependencies.gradle new file mode 100644 index 00000000..ecfd8cbc --- /dev/null +++ b/dependencies.gradle @@ -0,0 +1,14 @@ +// Add your dependencies here + +dependencies { + compile('com.github.GTNewHorizons:GT5-Unofficial:5.09.40.41:dev') + compile('com.github.GTNewHorizons:StructureLib:1.0.15:dev') + compile('com.github.GTNewHorizons:NotEnoughItems:2.2.12-GTNH:dev') + compile('net.industrial-craft:industrialcraft-2:2.2.828-experimental:dev') + compile('com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta-75-GTNH:dev') + compile('curse.maven:cofh-core-69162:2388751') + compile('com.github.GTNewHorizons:ExtraCells2:2.5.9:dev') {transitive = false} + + compileOnly('com.github.GTNewHorizons:AppleCore:3.1.9:dev') {transitive = false} + compileOnly('com.github.GTNewHorizons:BuildCraft:7.1.27:dev') {transitive = false} +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..e3f5c6c9 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,71 @@ +modName = FluidCraftForAE2 + +# This is a case-sensitive string to identify your mod. Convention is to use lower case. +modId = ae2fc + +modGroup = com.glodblock.github + +# WHY is there no version field? +# The build script relies on git to provide a version via tags. It is super easy and will enable you to always know the +# code base or your binary. Check out this tutorial: https://blog.mattclemente.com/2017/10/13/versioning-with-git-tags/ + +# Will update your build.gradle automatically whenever an update is available +autoUpdateBuildScript = false + +minecraftVersion = 1.7.10 +forgeVersion = 10.13.4.1614 + +# Select a username for testing your mod with breakpoints. You may leave this empty for a random user name each time you +# restart Minecraft in development. Choose this dependent on your mod: +# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name +# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty +developmentEnvironmentUserName = Developer + +# Define a source file of your project with: +# public static final String VERSION = "GRADLETOKEN_VERSION"; +# The string's content will be replaced with your mods version when compiled. You should use this to specify your mod's +# version in @Mod([...], version = VERSION, [...]) +# Leave these properties empty to skip individual token replacements +replaceGradleTokenInFile = FluidCraft.java +gradleTokenModId = GRADLETOKEN_MODID +gradleTokenModName = GRADLETOKEN_MODNAME +gradleTokenVersion = GRADLETOKEN_VERSION +gradleTokenGroupName = GRADLETOKEN_GROUPNAME + +# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can +# leave this property empty. +# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api +apiPackage = + +# Specify the configuration file for Forge's access transformers here. I must be placed into /src/main/resources/META-INF/ +# Example value: mymodid_at.cfg +accessTransformersFile = + +# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled! +usesMixins = false +# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise. +mixinPlugin = +# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail! +mixinsPackage = +# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin! +# This parameter is for legacy compatibility only +# Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin +coreModClass = coremod.FluidCraftCore +# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class +# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false! +containsMixinsAndOrCoreModOnly = false + +# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated in your jar. It is your +# responsibility check the licence and request permission for distribution, if required. +usesShadowedDependencies = false + +# Optional parameter to customize the produced artifacts. Use this to preserver artifact naming when migrating older +# projects. New projects should not use this parameter. +#customArchiveBaseName = + +# Optional parameter to prevent the source code from being published +# noPublishedSources = +systemProp.http.proxyHost=127.0.0.1 +systemProp.http.proxyPort=7890 +systemProp.https.proxyHost=127.0.0.1 +systemProp.https.proxyPort=7890 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..5c2d1cf0 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..3ab0b725 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 00000000..91a7e269 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/repositories.gradle b/repositories.gradle new file mode 100644 index 00000000..a4ff7a25 --- /dev/null +++ b/repositories.gradle @@ -0,0 +1,31 @@ +// Add any additional repositories for your dependencies here + +repositories { + maven { + name 'GTNH Maven' + url 'http://jenkins.usrv.eu:8081/nexus/content/groups/public/' + allowInsecureProtocol + } + maven { + name 'ic2' + url 'https://maven.ic2.player.to/' + metadataSources { + mavenPom() + artifact() + } + + } + maven { + name 'gt' + url 'https://gregtech.overminddl1.com/' + } + maven { + url 'https://cursemaven.com' + content { + includeGroup 'curse.maven' + } + } + maven { + url 'https://jitpack.io' + } +} diff --git a/src/main/java/com/glodblock/github/FluidCraft.java b/src/main/java/com/glodblock/github/FluidCraft.java new file mode 100644 index 00000000..589a7a2a --- /dev/null +++ b/src/main/java/com/glodblock/github/FluidCraft.java @@ -0,0 +1,62 @@ +package com.glodblock.github; + +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.loader.ChannelLoader; +import com.glodblock.github.loader.ListenerLoader; +import com.glodblock.github.loader.RenderLoader; +import com.glodblock.github.nei.recipes.DefaultExtractorLoader; +import com.glodblock.github.proxy.CommonProxy; +import com.glodblock.github.util.ModAndClassUtil; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLLoadCompleteEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.network.NetworkRegistry; +import net.minecraft.util.ResourceLocation; + +@Mod(modid = FluidCraft.MODID, version = FluidCraft.VERSION) +public class FluidCraft { + + public static final String MODID = "GRADLETOKEN_MODID"; + public static final String VERSION = "GRADLETOKEN_VERSION"; + public static final String MODNAME = "GRADLETOKEN_MODNAME"; + + @Mod.Instance(MODID) + public static FluidCraft INSTANCE; + + @SidedProxy(clientSide = "com.glodblock.github.proxy.ClientProxy", serverSide = "com.glodblock.github.proxy.CommonProxy") + public static CommonProxy proxy; + + @Mod.EventHandler + public static void preInit(FMLPreInitializationEvent event) { + (new ChannelLoader()).run(); + proxy.preInit(event); + } + + @Mod.EventHandler + public static void init(FMLInitializationEvent event) { + (new RenderLoader()).run(); + (new ListenerLoader()).run(); + ModAndClassUtil.init(); + proxy.init(event); + } + + @Mod.EventHandler + public static void postInit(FMLPostInitializationEvent event) { + NetworkRegistry.INSTANCE.registerGuiHandler(FluidCraft.INSTANCE, new InventoryHandler()); + (new DefaultExtractorLoader()).run(); + proxy.postInit(event); + } + + @Mod.EventHandler + public void onLoadComplete(FMLLoadCompleteEvent event) { + + } + + public static ResourceLocation resource(String path) { + return new ResourceLocation(MODID, path); + } + +} diff --git a/src/main/java/com/glodblock/github/client/ClientHelper.java b/src/main/java/com/glodblock/github/client/ClientHelper.java new file mode 100644 index 00000000..41d19560 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/ClientHelper.java @@ -0,0 +1,29 @@ +package com.glodblock.github.client; + +import com.glodblock.github.client.textures.FCPartsTexture; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.common.MinecraftForge; + +public class ClientHelper { + + @SubscribeEvent + public void updateTextureSheet( final TextureStitchEvent.Pre ev ) + { + if( ev.map.getTextureType() == 0 ) + { + for( final FCPartsTexture cb : FCPartsTexture.values() ) + { + cb.registerIcon( ev.map ); + } + } + } + + public static void register() { + ClientHelper handler = new ClientHelper(); + MinecraftForge.EVENT_BUS.register(handler); + FMLCommonHandler.instance().bus().register(handler); + } + +} diff --git a/src/main/java/com/glodblock/github/client/gui/GuiBaseFluidPatternTerminal.java b/src/main/java/com/glodblock/github/client/gui/GuiBaseFluidPatternTerminal.java new file mode 100644 index 00000000..bae893e3 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/GuiBaseFluidPatternTerminal.java @@ -0,0 +1,163 @@ +package com.glodblock.github.client.gui; + +import appeng.api.config.ActionItems; +import appeng.api.config.ItemSubstitution; +import appeng.api.config.Settings; +import appeng.api.storage.ITerminalHost; +import appeng.client.gui.widgets.GuiImgButton; +import appeng.client.gui.widgets.GuiTabButton; +import appeng.container.slot.AppEngSlot; +import appeng.core.localization.GuiText; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.gui.container.FCBasePartContainer; +import com.glodblock.github.network.CPacketFluidPatternTermBtns; +import com.glodblock.github.util.Ae2Reflect; +import com.glodblock.github.util.ModAndClassUtil; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import org.lwjgl.input.Keyboard; + +public class GuiBaseFluidPatternTerminal extends GuiFCBaseMonitor { + + private static final String SUBSITUTION_DISABLE = "0"; + private static final String SUBSITUTION_ENABLE = "1"; + + private static final String CRAFTMODE_CRFTING = "1"; + private static final String CRAFTMODE_PROCESSING = "0"; + + public final FCBasePartContainer container; + + private GuiTabButton tabCraftButton; + private GuiTabButton tabProcessButton; + private GuiImgButton substitutionsEnabledBtn; + private GuiImgButton substitutionsDisabledBtn; + private GuiImgButton encodeBtn; + private GuiImgButton clearBtn; + private GuiImgButton doubleBtn; + + public GuiBaseFluidPatternTerminal(final InventoryPlayer inventoryPlayer, final ITerminalHost te ) + { + super( inventoryPlayer, te, new FCBasePartContainer( inventoryPlayer, te ) ); + this.container = (FCBasePartContainer) this.inventorySlots; + Ae2Reflect.setReservedSpace(this, 81); + } + + @Override + protected void actionPerformed( final GuiButton btn ) + { + super.actionPerformed( btn ); + + if( this.tabCraftButton == btn || this.tabProcessButton == btn ) + { + FluidCraft.proxy.netHandler.sendToServer( new CPacketFluidPatternTermBtns( "PatternTerminal.CraftMode", this.tabProcessButton == btn ? CRAFTMODE_CRFTING : CRAFTMODE_PROCESSING ) ); + } + else if( this.encodeBtn == btn ) + { + FluidCraft.proxy.netHandler.sendToServer( new CPacketFluidPatternTermBtns( "PatternTerminal.Encode", isShiftKeyDown() ? "2" : "1" ) ); + } + else if( this.clearBtn == btn ) + { + FluidCraft.proxy.netHandler.sendToServer( new CPacketFluidPatternTermBtns( "PatternTerminal.Clear", "1" ) ); + } + else if( this.substitutionsEnabledBtn == btn || this.substitutionsDisabledBtn == btn ) + { + FluidCraft.proxy.netHandler.sendToServer( new CPacketFluidPatternTermBtns( "PatternTerminal.Substitute", this.substitutionsEnabledBtn == btn ? SUBSITUTION_DISABLE : SUBSITUTION_ENABLE ) ); + } + else if (ModAndClassUtil.isDoubleButton && doubleBtn == btn) + { + FluidCraft.proxy.netHandler.sendToServer( new CPacketFluidPatternTermBtns( "PatternTerminal.Double", Keyboard.isKeyDown( Keyboard.KEY_LSHIFT ) ? "1": "0") ); + } + } + + @Override + @SuppressWarnings("unchecked") + public void initGui() + { + super.initGui(); + this.tabCraftButton = new GuiTabButton( this.guiLeft + 173, this.guiTop + this.ySize - 177, new ItemStack( Blocks.crafting_table ), GuiText.CraftingPattern.getLocal(), itemRender ); + this.buttonList.add( this.tabCraftButton ); + + this.tabProcessButton = new GuiTabButton( this.guiLeft + 173, this.guiTop + this.ySize - 177, new ItemStack( Blocks.furnace ), GuiText.ProcessingPattern.getLocal(), itemRender ); + this.buttonList.add( this.tabProcessButton ); + + this.substitutionsEnabledBtn = new GuiImgButton( this.guiLeft + 84, this.guiTop + this.ySize - 163, Settings.ACTIONS, ItemSubstitution.ENABLED ); + this.substitutionsEnabledBtn.setHalfSize( true ); + this.buttonList.add( this.substitutionsEnabledBtn ); + + this.substitutionsDisabledBtn = new GuiImgButton( this.guiLeft + 84, this.guiTop + this.ySize - 163, Settings.ACTIONS, ItemSubstitution.DISABLED ); + this.substitutionsDisabledBtn.setHalfSize( true ); + this.buttonList.add( this.substitutionsDisabledBtn ); + + this.clearBtn = new GuiImgButton( this.guiLeft + 74, this.guiTop + this.ySize - 163, Settings.ACTIONS, ActionItems.CLOSE ); + this.clearBtn.setHalfSize( true ); + this.buttonList.add( this.clearBtn ); + + this.encodeBtn = new GuiImgButton( this.guiLeft + 147, this.guiTop + this.ySize - 142, Settings.ACTIONS, ActionItems.ENCODE ); + this.buttonList.add( this.encodeBtn ); + + if (ModAndClassUtil.isDoubleButton) { + this.doubleBtn = new GuiImgButton( this.guiLeft + 74, this.guiTop + this.ySize - 153, Settings.ACTIONS, ActionItems.DOUBLE ); + this.doubleBtn.setHalfSize( true ); + this.buttonList.add( this.doubleBtn ); + } + } + + @Override + public void drawFG( final int offsetX, final int offsetY, final int mouseX, final int mouseY ) + { + if( !this.container.isCraftingMode() ) + { + this.tabCraftButton.visible = false; + this.tabProcessButton.visible = true; + if (ModAndClassUtil.isDoubleButton) + this.doubleBtn.visible = true; + } + else + { + this.tabCraftButton.visible = true; + this.tabProcessButton.visible = false; + if (ModAndClassUtil.isDoubleButton) + this.doubleBtn.visible = false; + } + + if( this.container.substitute ) + { + this.substitutionsEnabledBtn.visible = true; + this.substitutionsDisabledBtn.visible = false; + } + else + { + this.substitutionsEnabledBtn.visible = false; + this.substitutionsDisabledBtn.visible = true; + } + + super.drawFG( offsetX, offsetY, mouseX, mouseY ); + this.fontRendererObj.drawString( GuiText.PatternTerminal.getLocal(), 8, this.ySize - 96 + 2 - Ae2Reflect.getReservedSpace(this), 4210752 ); + } + + @Override + protected String getBackground() + { + if( this.container.isCraftingMode() ) + { + return "guis/pattern.png"; + } + return "guis/pattern2.png"; + } + + @Override + protected void repositionSlot( final AppEngSlot s ) + { + if( s.isPlayerSide() ) + { + s.yDisplayPosition = s.getY() + this.ySize - 78 - 5; + } + else + { + s.yDisplayPosition = s.getY() + this.ySize - 78 - 3; + } + } + +} diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFCBaseMonitor.java b/src/main/java/com/glodblock/github/client/gui/GuiFCBaseMonitor.java new file mode 100644 index 00000000..38dd7564 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/GuiFCBaseMonitor.java @@ -0,0 +1,750 @@ +package com.glodblock.github.client.gui; + +import appeng.api.config.*; +import appeng.api.implementations.tiles.IViewCellStorage; +import appeng.api.storage.ITerminalHost; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.util.IConfigManager; +import appeng.api.util.IConfigurableObject; +import appeng.client.gui.AEBaseMEGui; +import appeng.client.gui.widgets.*; +import appeng.client.me.InternalSlotME; +import appeng.client.me.ItemRepo; +import appeng.client.me.SlotDisconnected; +import appeng.client.me.SlotME; +import appeng.container.AEBaseContainer; +import appeng.container.slot.*; +import appeng.core.AEConfig; +import appeng.core.AELog; +import appeng.core.localization.ButtonToolTips; +import appeng.core.localization.GuiText; +import appeng.core.sync.GuiBridge; +import appeng.core.sync.network.NetworkHandler; +import appeng.core.sync.packets.PacketInventoryAction; +import appeng.core.sync.packets.PacketSwitchGuis; +import appeng.core.sync.packets.PacketValueConfig; +import appeng.helpers.InventoryAction; +import appeng.integration.IntegrationRegistry; +import appeng.integration.IntegrationType; +import appeng.util.IConfigManagerHost; +import appeng.util.Platform; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.gui.container.FCBaseMonitorContain; +import com.glodblock.github.client.gui.container.FCBasePartContainer; +import com.glodblock.github.common.parts.PartFluidPatternTerminal; +import com.glodblock.github.network.CPacketInventoryAction; +import com.glodblock.github.network.CPacketSetTargetItem; +import com.glodblock.github.util.Ae2Reflect; +import com.glodblock.github.util.NameConst; +import com.google.common.base.Stopwatch; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class GuiFCBaseMonitor extends AEBaseMEGui implements ISortSource, IConfigManagerHost +{ + + public static int craftingGridOffsetX; + public static int craftingGridOffsetY; + + private static String memoryText = ""; + private final ItemRepo repo; + private final int offsetX = 9; + private final int lowerTextureOffset = 0; + private final IConfigManager configSrc; + private final boolean viewCell; + private final ItemStack[] myCurrentViewCells = new ItemStack[5]; + private final FCBaseMonitorContain monitorableContainer; + private GuiTabButton craftingStatusBtn; + private GuiImgButton craftingStatusImgBtn; + private MEGuiTextField searchField; + private String myName; + private int perRow = 9; + private int reservedSpace = 0; + private boolean customSortOrder = true; + private int rows = 0; + private int maxRows = Integer.MAX_VALUE; + private int standardSize; + private GuiImgButton ViewBox; + private GuiImgButton SortByBox; + private GuiImgButton SortDirBox; + private GuiImgButton searchBoxSettings; + private GuiImgButton terminalStyleBox; + private GuiImgButton searchStringSave; + + public GuiFCBaseMonitor(final InventoryPlayer inventoryPlayer, final ITerminalHost te ) + { + this( inventoryPlayer, te, new FCBasePartContainer( inventoryPlayer, te ) ); + } + + public GuiFCBaseMonitor( final InventoryPlayer inventoryPlayer, final ITerminalHost te, final FCBasePartContainer c ) + { + + super( c ); + + final GuiScrollbar scrollbar = new GuiScrollbar(); + this.setScrollBar( scrollbar ); + this.repo = new ItemRepo( scrollbar, this ); + + this.xSize = 185; + this.ySize = 204; + + if( te instanceof IViewCellStorage) + { + this.xSize += 33; + } + + this.standardSize = this.xSize; + + this.configSrc = ( (IConfigurableObject) this.inventorySlots ).getConfigManager(); + ( this.monitorableContainer = (FCBaseMonitorContain) this.inventorySlots ).setGui( this ); + + this.viewCell = te instanceof IViewCellStorage; + + if( te instanceof PartFluidPatternTerminal) + { + this.myName = NameConst.GUI_FLUID_PATTERN_TERMINAL; + } + } + + public void postUpdate( final List list ) + { + for( final IAEItemStack is : list ) + { + this.repo.postUpdate( is ); + } + + this.repo.updateView(); + this.setScrollBar(); + } + + private void setScrollBar() + { + this.getScrollBar().setTop( 18 ).setLeft( 175 ).setHeight( this.rows * 18 - 2 ); + this.getScrollBar().setRange( 0, ( this.repo.size() + this.perRow - 1 ) / this.perRow - this.rows, Math.max( 1, this.rows / 6 ) ); + } + + @Override + protected void actionPerformed( final GuiButton btn ) + { + + if( btn == this.craftingStatusBtn || btn == this.craftingStatusImgBtn ) + { + NetworkHandler.instance.sendToServer( new PacketSwitchGuis( GuiBridge.GUI_CRAFTING_STATUS ) ); + } + + if( btn instanceof GuiImgButton ) + { + final boolean backwards = Mouse.isButtonDown( 1 ); + + final GuiImgButton iBtn = (GuiImgButton) btn; + if( iBtn.getSetting() != Settings.ACTIONS ) + { + final Enum cv = iBtn.getCurrentValue(); + final Enum next = Platform.rotateEnum( cv, backwards, iBtn.getSetting().getPossibleValues() ); + + if( btn == this.terminalStyleBox ) + { + AEConfig.instance.settings.putSetting( iBtn.getSetting(), next ); + } + else if( btn == this.searchBoxSettings ) + { + AEConfig.instance.settings.putSetting( iBtn.getSetting(), next ); + } + else if( btn == this.searchStringSave ) + { + AEConfig.instance.preserveSearchBar = next == YesNo.YES; + } + else + { + try + { + NetworkHandler.instance.sendToServer( new PacketValueConfig( iBtn.getSetting().name(), next.name() ) ); + } + catch( final IOException e ) + { + AELog.debug( e ); + } + } + + iBtn.set( next ); + + if( next.getClass() == SearchBoxMode.class || next.getClass() == TerminalStyle.class ) + { + this.reinitalize(); + } + } + } + } + + private void reinitalize() + { + this.buttonList.clear(); + this.initGui(); + } + + @Override + public void initGui() + { + Keyboard.enableRepeatEvents( true ); + + this.maxRows = this.getMaxRows(); + this.perRow = AEConfig.instance.getConfigManager().getSetting( Settings.TERMINAL_STYLE ) != TerminalStyle.FULL ? 9 : 9 + ( ( this.width - this.standardSize ) / 18 ); + + final boolean hasNEI = IntegrationRegistry.INSTANCE.isEnabled( IntegrationType.NEI ); + + final int NEI = hasNEI ? 0 : 0; + int top = hasNEI ? 22 : 0; + + final int magicNumber = 114 + 1; + final int extraSpace = this.height - magicNumber - NEI - top - this.reservedSpace; + + this.rows = (int) Math.floor( extraSpace / 18 ); + if( this.rows > this.maxRows ) + { + top += ( this.rows - this.maxRows ) * 18 / 2; + this.rows = this.maxRows; + } + + if( hasNEI ) + { + this.rows--; + } + + if( this.rows < 3 ) + { + this.rows = 3; + } + + this.getMeSlots().clear(); + for( int y = 0; y < this.rows; y++ ) + { + for( int x = 0; x < this.perRow; x++ ) + { + this.getMeSlots().add( new InternalSlotME( this.repo, x + y * this.perRow, this.offsetX + x * 18, 18 + y * 18 ) ); + } + } + + if( AEConfig.instance.getConfigManager().getSetting( Settings.TERMINAL_STYLE ) != TerminalStyle.FULL ) + { + this.xSize = this.standardSize + ( ( this.perRow - 9 ) * 18 ); + } + else + { + this.xSize = this.standardSize; + } + + super.initGui(); + // full size : 204 + // extra slots : 72 + // slot 18 + + this.ySize = magicNumber + this.rows * 18 + this.reservedSpace; + // this.guiTop = top; + final int unusedSpace = this.height - this.ySize; + this.guiTop = (int) Math.floor( unusedSpace / ( unusedSpace < 0 ? 3.8f : 2.0f ) ); + + int offset = this.guiTop + 8; + + if( this.customSortOrder ) + { + this.buttonList.add( this.SortByBox = new GuiImgButton( this.guiLeft - 18, offset, Settings.SORT_BY, this.configSrc.getSetting( Settings.SORT_BY ) ) ); + offset += 20; + } + + this.buttonList.add( this.ViewBox = new GuiImgButton( this.guiLeft - 18, offset, Settings.VIEW_MODE, this.configSrc.getSetting( Settings.VIEW_MODE ) ) ); + offset += 20; + + this.buttonList.add( this.SortDirBox = new GuiImgButton( this.guiLeft - 18, offset, Settings.SORT_DIRECTION, this.configSrc.getSetting( Settings.SORT_DIRECTION ) ) ); + offset += 20; + + this.buttonList.add( this.searchBoxSettings = new GuiImgButton( this.guiLeft - 18, offset, Settings.SEARCH_MODE, AEConfig.instance.settings.getSetting( Settings.SEARCH_MODE ) ) ); + offset += 20; + + this.buttonList.add( this.searchStringSave = new GuiImgButton( this.guiLeft - 18, offset, Settings.SAVE_SEARCH, AEConfig.instance.preserveSearchBar ? YesNo.YES : YesNo.NO ) ); + offset += 20; + + this.buttonList.add( this.terminalStyleBox = new GuiImgButton( this.guiLeft - 18, offset, Settings.TERMINAL_STYLE, AEConfig.instance.settings.getSetting( Settings.TERMINAL_STYLE ) ) ); + offset += 20; + + this.searchField = new MEGuiTextField( this.fontRendererObj, this.guiLeft + Math.max( 80, this.offsetX ), this.guiTop + 4, 90, 12 ); + this.searchField.setEnableBackgroundDrawing( false ); + this.searchField.setMaxStringLength( 25 ); + this.searchField.setTextColor( 0xFFFFFF ); + this.searchField.setVisible( true ); + searchField.setMessage(ButtonToolTips.SearchStringTooltip.getLocal()); + + if( this.viewCell) + { + if (AEConfig.instance.getConfigManager().getSetting(Settings.CRAFTING_STATUS).equals(CraftingStatus.BUTTON)) { + this.buttonList.add(this.craftingStatusImgBtn = new GuiImgButton(this.guiLeft - 18, offset, Settings.CRAFTING_STATUS, AEConfig.instance.settings.getSetting(Settings.CRAFTING_STATUS))); + } else { + this.buttonList.add(this.craftingStatusBtn = new GuiTabButton(this.guiLeft + 170, this.guiTop - 4, 2 + 11 * 16, GuiText.CraftingStatus.getLocal(), itemRender)); + this.craftingStatusBtn.setHideEdge( 13 ); // GuiTabButton implementation // + } + } + + // Enum setting = AEConfig.INSTANCE.getSetting( "Terminal", SearchBoxMode.class, SearchBoxMode.AUTOSEARCH ); + final Enum setting = AEConfig.instance.settings.getSetting( Settings.SEARCH_MODE ); + this.searchField.setFocused( SearchBoxMode.AUTOSEARCH == setting || SearchBoxMode.NEI_AUTOSEARCH == setting ); + + if (AEConfig.instance.preserveSearchBar || this.isSubGui()) + { + setSearchString(memoryText, false); + } + if( this.isSubGui() ) + { + this.repo.updateView(); + this.setScrollBar(); + } + + craftingGridOffsetX = Integer.MAX_VALUE; + craftingGridOffsetY = Integer.MAX_VALUE; + + for( final Object s : this.inventorySlots.inventorySlots ) + { + if( s instanceof AppEngSlot) + { + if( ( (Slot) s ).xDisplayPosition < 197 ) + { + this.repositionSlot( (AppEngSlot) s ); + } + } + + if( s instanceof SlotCraftingMatrix || s instanceof SlotFakeCraftingMatrix) + { + final Slot g = (Slot) s; + if( g.xDisplayPosition > 0 && g.yDisplayPosition > 0 ) + { + craftingGridOffsetX = Math.min( craftingGridOffsetX, g.xDisplayPosition ); + craftingGridOffsetY = Math.min( craftingGridOffsetY, g.yDisplayPosition ); + } + } + } + + craftingGridOffsetX -= 25; + craftingGridOffsetY -= 6; + } + + public void setSearchString(String memoryText, boolean updateView) + { + this.searchField.setText(memoryText); + this.repo.setSearchString(memoryText); + if (updateView) + { + this.repo.updateView(); + this.setScrollBar(); + } + } + + @Override + public void drawFG( final int offsetX, final int offsetY, final int mouseX, final int mouseY ) + { + this.fontRendererObj.drawString( this.getGuiDisplayName( GuiText.Terminal.getLocal() ), 8, 6, 4210752 ); + this.fontRendererObj.drawString( GuiText.inventory.getLocal(), 8, this.ySize - 96 + 3, 4210752 ); + } + + @Override + protected void mouseClicked( final int xCoord, final int yCoord, final int btn ) + { + final Enum searchMode = AEConfig.instance.settings.getSetting( Settings.SEARCH_MODE ); + + if( searchMode != SearchBoxMode.AUTOSEARCH && searchMode != SearchBoxMode.NEI_AUTOSEARCH ) + { + this.searchField.mouseClicked( xCoord, yCoord, btn ); + } + + if( btn == 1 && this.searchField.isMouseIn( xCoord, yCoord ) ) + { + setSearchString("", true); + } + + super.mouseClicked( xCoord, yCoord, btn ); + } + + @Override + protected void handleMouseClick( final Slot slot, final int slotIdx, final int ctrlDown, final int mouseButton ) + { + final EntityPlayer player = Minecraft.getMinecraft().thePlayer; + + if( slot instanceof SlotFake) + { + final InventoryAction action = ctrlDown == 1 ? InventoryAction.SPLIT_OR_PLACE_SINGLE : InventoryAction.PICKUP_OR_SET_DOWN; + + if( Ae2Reflect.getDragClick(this).size() > 1 ) + { + return; + } + + final PacketInventoryAction p = new PacketInventoryAction( action, slotIdx, 0 ); + NetworkHandler.instance.sendToServer( p ); + + return; + } + + if( slot instanceof SlotPatternTerm) + { + if( mouseButton == 6 ) + { + return; // prevent weird double clicks.. + } + + try + { + NetworkHandler.instance.sendToServer( ( (SlotPatternTerm) slot ).getRequest( isShiftKeyDown() ) ); + } + catch( final IOException e ) + { + AELog.debug( e ); + } + } + else if( slot instanceof SlotCraftingTerm ) + { + if( mouseButton == 6 ) + { + return; // prevent weird double clicks.. + } + + InventoryAction action = null; + if( isShiftKeyDown() ) + { + action = InventoryAction.CRAFT_SHIFT; + } + else + { + // Craft stack on right-click, craft single on left-click + action = ( mouseButton == 1 ) ? InventoryAction.CRAFT_STACK : InventoryAction.CRAFT_ITEM; + } + + final PacketInventoryAction p = new PacketInventoryAction( action, slotIdx, 0 ); + NetworkHandler.instance.sendToServer( p ); + + return; + } + + if( Keyboard.isKeyDown( Keyboard.KEY_SPACE ) ) + { + if( this.enableSpaceClicking() && !( slot instanceof SlotPatternTerm ) ) + { + IAEItemStack stack = null; + if( slot instanceof SlotME ) + { + stack = ( (SlotME) slot ).getAEStack(); + } + + int slotNum = Ae2Reflect.getInventorySlots(this).size(); + + if( !( slot instanceof SlotME ) && slot != null ) + { + slotNum = slot.slotNumber; + } + + ( (AEBaseContainer) this.inventorySlots ).setTargetStack( stack ); + final PacketInventoryAction p = new PacketInventoryAction( InventoryAction.MOVE_REGION, slotNum, 0 ); + NetworkHandler.instance.sendToServer( p ); + return; + } + } + + if( slot instanceof SlotDisconnected) + { + if( Ae2Reflect.getDragClick(this).size() > 1 ) + { + return; + } + + InventoryAction action = null; + + switch( mouseButton ) + { + case 0: // pickup / set-down. + { + ItemStack heldStack = player.inventory.getItemStack(); + if (slot.getStack() == null && heldStack != null) + action = InventoryAction.SPLIT_OR_PLACE_SINGLE; + else if (slot.getStack() != null && (heldStack == null || heldStack.stackSize <= 1)) + action = InventoryAction.PICKUP_OR_SET_DOWN; + } + break; + case 1: + action = ctrlDown == 1 ? InventoryAction.PICKUP_SINGLE : InventoryAction.SHIFT_CLICK; + break; + + case 3: // creative dupe: + + if( player.capabilities.isCreativeMode ) + { + action = InventoryAction.CREATIVE_DUPLICATE; + } + + break; + + default: + case 4: // drop item: + case 6: + } + + if( action != null ) + { + final PacketInventoryAction p = new PacketInventoryAction( action, slot.getSlotIndex(), ( (SlotDisconnected) slot ).getSlot().getId() ); + NetworkHandler.instance.sendToServer( p ); + } + + return; + } + + if( slot instanceof SlotME ) + { + InventoryAction action = null; + IAEItemStack stack = null; + + switch( mouseButton ) + { + case 0: // pickup / set-down. + action = ctrlDown == 1 ? InventoryAction.SPLIT_OR_PLACE_SINGLE : InventoryAction.PICKUP_OR_SET_DOWN; + stack = ( (SlotME) slot ).getAEStack(); + + if( stack != null && action == InventoryAction.PICKUP_OR_SET_DOWN && stack.getStackSize() == 0 && player.inventory.getItemStack() == null ) + { + action = InventoryAction.AUTO_CRAFT; + } + + break; + case 1: + action = ctrlDown == 1 ? InventoryAction.PICKUP_SINGLE : InventoryAction.SHIFT_CLICK; + stack = ( (SlotME) slot ).getAEStack(); + break; + + case 3: // creative dupe: + + stack = ( (SlotME) slot ).getAEStack(); + if( stack != null && stack.isCraftable() ) + { + action = InventoryAction.AUTO_CRAFT; + } + else if( player.capabilities.isCreativeMode ) + { + final IAEItemStack slotItem = ( (SlotME) slot ).getAEStack(); + if( slotItem != null ) + { + action = InventoryAction.CREATIVE_DUPLICATE; + } + } + break; + + default: + case 4: // drop item: + case 6: + } + + if (action == InventoryAction.AUTO_CRAFT) { + ((AEBaseContainer) this.inventorySlots).setTargetStack( stack ); + FluidCraft.proxy.netHandler.sendToServer(new CPacketInventoryAction(action, Ae2Reflect.getInventorySlots(this).size(), 0, stack)); + } + else if( action != null ) + { + ( (AEBaseContainer) this.inventorySlots ).setTargetStack( stack ); + final PacketInventoryAction p = new PacketInventoryAction( action, Ae2Reflect.getInventorySlots(this).size(), 0 ); + NetworkHandler.instance.sendToServer( p ); + } + + return; + } + + super.handleMouseClick( slot, slotIdx, ctrlDown, mouseButton ); + } + + @Override + public void onGuiClosed() + { + super.onGuiClosed(); + Keyboard.enableRepeatEvents( false ); + memoryText = this.searchField.getText(); + } + + @Override + public void drawBG( final int offsetX, final int offsetY, final int mouseX, final int mouseY ) + { + + this.bindTexture( this.getBackground() ); + final int x_width = 197; + this.drawTexturedModalRect( offsetX, offsetY, 0, 0, x_width, 18 ); + + if( this.viewCell ) + { + this.drawTexturedModalRect( offsetX + x_width, offsetY, x_width, 0, 46, 128 ); + } + + for( int x = 0; x < this.rows; x++ ) + { + this.drawTexturedModalRect( offsetX, offsetY + 18 + x * 18, 0, 18, x_width, 18 ); + } + + this.drawTexturedModalRect( offsetX, offsetY + 16 + this.rows * 18 + this.lowerTextureOffset, 0, 106 - 18 - 18, x_width, 99 + this.reservedSpace - this.lowerTextureOffset ); + + if( this.viewCell ) + { + boolean update = false; + + for( int i = 0; i < 5; i++ ) + { + if( this.myCurrentViewCells[i] != this.monitorableContainer.getCellViewSlot( i ).getStack() ) + { + update = true; + this.myCurrentViewCells[i] = this.monitorableContainer.getCellViewSlot( i ).getStack(); + } + } + + if( update ) + { + this.repo.setViewCell( this.myCurrentViewCells ); + } + } + + if( this.searchField != null ) + { + this.searchField.drawTextBox(); + } + } + + protected String getBackground() + { + return "guis/terminal.png"; + } + + @Override + protected boolean isPowered() + { + return this.repo.hasPower(); + } + + int getMaxRows() + { + return AEConfig.instance.getConfigManager().getSetting( Settings.TERMINAL_STYLE ) == TerminalStyle.SMALL ? 6 : Integer.MAX_VALUE; + } + + protected void repositionSlot( final AppEngSlot s ) + { + s.yDisplayPosition = s.getY() + this.ySize - 78 - 5; + } + + @Override + protected void keyTyped( final char character, final int key ) + { + if( !this.checkHotbarKeys( key ) ) + { + if( character == ' ' && this.searchField.getText().isEmpty() ) + { + return; + } + + if( this.searchField.textboxKeyTyped( character, key ) ) + { + this.repo.setSearchString( this.searchField.getText() ); + this.repo.updateView(); + this.setScrollBar(); + } + else + { + super.keyTyped( character, key ); + } + } + } + + @Override + public void updateScreen() + { + this.repo.setPower( this.monitorableContainer.isPowered() ); + super.updateScreen(); + } + + @Override + public Enum getSortBy() + { + return this.configSrc.getSetting( Settings.SORT_BY ); + } + + @Override + public Enum getSortDir() + { + return this.configSrc.getSetting( Settings.SORT_DIRECTION ); + } + + @Override + public Enum getSortDisplay() + { + return this.configSrc.getSetting( Settings.VIEW_MODE ); + } + + @Override + public void updateSetting( final IConfigManager manager, final Enum settingName, final Enum newValue ) + { + if( this.SortByBox != null ) + { + this.SortByBox.set( this.configSrc.getSetting( Settings.SORT_BY ) ); + } + + if( this.SortDirBox != null ) + { + this.SortDirBox.set( this.configSrc.getSetting( Settings.SORT_DIRECTION ) ); + } + + if( this.ViewBox != null ) + { + this.ViewBox.set( this.configSrc.getSetting( Settings.VIEW_MODE ) ); + } + + this.repo.updateView(); + } + + int getReservedSpace() + { + return this.reservedSpace; + } + + void setReservedSpace( final int reservedSpace ) + { + this.reservedSpace = reservedSpace; + } + + public boolean isCustomSortOrder() + { + return this.customSortOrder; + } + + void setCustomSortOrder( final boolean customSortOrder ) + { + this.customSortOrder = customSortOrder; + } + + public int getStandardSize() + { + return this.standardSize; + } + + void setStandardSize( final int standardSize ) + { + this.standardSize = standardSize; + } + + @Override + public void drawScreen( final int mouseX, final int mouseY, final float btn ) { + super.drawScreen(mouseX, mouseY, btn); + if (AEConfig.instance.preserveSearchBar && searchField != null) + handleTooltip(mouseX, mouseY, searchField.new TooltipProvider()); + } + public boolean isOverSearchField(int x, int y) + { + return searchField.isMouseIn(x,y); + } +} diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFluidCraftAmount.java b/src/main/java/com/glodblock/github/client/gui/GuiFluidCraftAmount.java new file mode 100644 index 00000000..f854df83 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/GuiFluidCraftAmount.java @@ -0,0 +1,257 @@ +package com.glodblock.github.client.gui; + +import appeng.api.AEApi; +import appeng.api.definitions.IDefinitions; +import appeng.api.definitions.IParts; +import appeng.api.storage.ITerminalHost; +import appeng.client.gui.AEBaseGui; +import appeng.client.gui.widgets.GuiNumberBox; +import appeng.client.gui.widgets.GuiTabButton; +import appeng.container.AEBaseContainer; +import appeng.container.implementations.ContainerCraftAmount; +import appeng.core.AEConfig; +import appeng.core.localization.GuiText; +import appeng.helpers.Reflected; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.common.parts.PartFluidPatternTerminal; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.loader.ItemAndBlockHolder; +import com.glodblock.github.network.CPacketCraftRequest; +import com.glodblock.github.network.CPacketSwitchGuis; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; + +public class GuiFluidCraftAmount extends AEBaseGui +{ + private GuiNumberBox amountToCraft; + private GuiTabButton originalGuiBtn; + + private GuiButton next; + + private GuiButton plus1; + private GuiButton plus10; + private GuiButton plus100; + private GuiButton plus1000; + private GuiButton minus1; + private GuiButton minus10; + private GuiButton minus100; + private GuiButton minus1000; + + private GuiType originalGui; + + @Reflected + public GuiFluidCraftAmount(final InventoryPlayer inventoryPlayer, final ITerminalHost te ) + { + super( new ContainerCraftAmount( inventoryPlayer, te ) ); + } + + @Override + public void initGui() + { + super.initGui(); + + final int a = AEConfig.instance.craftItemsByStackAmounts( 0 ); + final int b = AEConfig.instance.craftItemsByStackAmounts( 1 ); + final int c = AEConfig.instance.craftItemsByStackAmounts( 2 ); + final int d = AEConfig.instance.craftItemsByStackAmounts( 3 ); + + this.buttonList.add( this.plus1 = new GuiButton( 0, this.guiLeft + 20, this.guiTop + 26, 22, 20, "+" + a ) ); + this.buttonList.add( this.plus10 = new GuiButton( 0, this.guiLeft + 48, this.guiTop + 26, 28, 20, "+" + b ) ); + this.buttonList.add( this.plus100 = new GuiButton( 0, this.guiLeft + 82, this.guiTop + 26, 32, 20, "+" + c ) ); + this.buttonList.add( this.plus1000 = new GuiButton( 0, this.guiLeft + 120, this.guiTop + 26, 38, 20, "+" + d ) ); + + this.buttonList.add( this.minus1 = new GuiButton( 0, this.guiLeft + 20, this.guiTop + 75, 22, 20, "-" + a ) ); + this.buttonList.add( this.minus10 = new GuiButton( 0, this.guiLeft + 48, this.guiTop + 75, 28, 20, "-" + b ) ); + this.buttonList.add( this.minus100 = new GuiButton( 0, this.guiLeft + 82, this.guiTop + 75, 32, 20, "-" + c ) ); + this.buttonList.add( this.minus1000 = new GuiButton( 0, this.guiLeft + 120, this.guiTop + 75, 38, 20, "-" + d ) ); + + this.buttonList.add( this.next = new GuiButton( 0, this.guiLeft + 128, this.guiTop + 51, 38, 20, GuiText.Next.getLocal() ) ); + + ItemStack myIcon = null; + final Object target = ( (AEBaseContainer) this.inventorySlots ).getTarget(); + final IDefinitions definitions = AEApi.instance().definitions(); + final IParts parts = definitions.parts(); + + if( target instanceof PartFluidPatternTerminal) + { + myIcon = new ItemStack(ItemAndBlockHolder.FLUID_TERMINAL, 1); + this.originalGui = GuiType.FLUID_PATTERN_TERMINAL; + } + + if( this.originalGui != null && myIcon != null ) + { + this.buttonList.add( this.originalGuiBtn = new GuiTabButton( this.guiLeft + 154, this.guiTop, myIcon, myIcon.getDisplayName(), itemRender ) ); + } + + this.amountToCraft = new GuiNumberBox( this.fontRendererObj, this.guiLeft + 62, this.guiTop + 57, 59, this.fontRendererObj.FONT_HEIGHT, Integer.class ); + this.amountToCraft.setEnableBackgroundDrawing( false ); + this.amountToCraft.setMaxStringLength( 16 ); + this.amountToCraft.setTextColor( 0xFFFFFF ); + this.amountToCraft.setVisible( true ); + this.amountToCraft.setFocused( true ); + this.amountToCraft.setText( "1" ); + this.amountToCraft.setSelectionPos(0); + } + + @Override + public void drawFG( final int offsetX, final int offsetY, final int mouseX, final int mouseY ) + { + this.fontRendererObj.drawString( GuiText.SelectAmount.getLocal(), 8, 6, 4210752 ); + } + + @Override + public void drawBG( final int offsetX, final int offsetY, final int mouseX, final int mouseY ) + { + this.next.displayString = isShiftKeyDown() ? GuiText.Start.getLocal() : GuiText.Next.getLocal(); + + this.bindTexture( "guis/craftAmt.png" ); + this.drawTexturedModalRect( offsetX, offsetY, 0, 0, this.xSize, this.ySize ); + + try + { + Long.parseLong( this.amountToCraft.getText() ); + this.next.enabled = this.amountToCraft.getText().length() > 0; + } + catch( final NumberFormatException e ) + { + this.next.enabled = false; + } + + this.amountToCraft.drawTextBox(); + } + + @Override + protected void keyTyped( final char character, final int key ) + { + if( !this.checkHotbarKeys( key ) ) + { + if( key == 28 ) + { + this.actionPerformed( this.next ); + } + if( ( key == 211 || key == 205 || key == 203 || key == 14 || character == '-' || Character.isDigit( character ) ) && this.amountToCraft.textboxKeyTyped( character, key ) ) + { + try + { + String out = this.amountToCraft.getText(); + + boolean fixed = false; + while( out.startsWith( "0" ) && out.length() > 1 ) + { + out = out.substring( 1 ); + fixed = true; + } + + if( fixed ) + { + this.amountToCraft.setText( out ); + } + + if( out.isEmpty() ) + { + out = "0"; + } + + final long result = Long.parseLong( out ); + if( result < 0 ) + { + this.amountToCraft.setText( "1" ); + } + } + catch( final NumberFormatException e ) + { + // :P + } + } + else + { + super.keyTyped( character, key ); + } + } + } + + @Override + protected void actionPerformed( final GuiButton btn ) + { + super.actionPerformed( btn ); + + try + { + + if( btn == this.originalGuiBtn ) + { + FluidCraft.proxy.netHandler.sendToServer( new CPacketSwitchGuis( this.originalGui ) ); + } + + if( btn == this.next ) + { + FluidCraft.proxy.netHandler.sendToServer( new CPacketCraftRequest( Integer.parseInt( this.amountToCraft.getText() ), isShiftKeyDown() ) ); + } + } + catch( final NumberFormatException e ) + { + // nope.. + this.amountToCraft.setText( "1" ); + } + + final boolean isPlus = btn == this.plus1 || btn == this.plus10 || btn == this.plus100 || btn == this.plus1000; + final boolean isMinus = btn == this.minus1 || btn == this.minus10 || btn == this.minus100 || btn == this.minus1000; + + if( isPlus || isMinus ) + { + this.addQty( this.getQty( btn ) ); + } + } + + private void addQty( final int i ) + { + try + { + String out = this.amountToCraft.getText(); + + boolean fixed = false; + while( out.startsWith( "0" ) && out.length() > 1 ) + { + out = out.substring( 1 ); + fixed = true; + } + + if( fixed ) + { + this.amountToCraft.setText( out ); + } + + if( out.isEmpty() ) + { + out = "0"; + } + + long result = Integer.parseInt( out ); + + if( result == 1 && i > 1 ) + { + result = 0; + } + + result += i; + if( result < 1 ) + { + result = 1; + } + + out = Long.toString( result ); + Integer.parseInt( out ); + this.amountToCraft.setText( out ); + } + catch( final NumberFormatException e ) + { + // :P + } + } + + protected String getBackground() + { + return "guis/craftAmt.png"; + } +} diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFluidCraftConfirm.java b/src/main/java/com/glodblock/github/client/gui/GuiFluidCraftConfirm.java new file mode 100644 index 00000000..f650d5d1 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/GuiFluidCraftConfirm.java @@ -0,0 +1,531 @@ +package com.glodblock.github.client.gui; + +import appeng.api.AEApi; +import appeng.api.storage.ITerminalHost; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; +import appeng.client.gui.AEBaseGui; +import appeng.client.gui.widgets.GuiScrollbar; +import appeng.core.AELog; +import appeng.core.localization.GuiText; +import appeng.util.Platform; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.gui.container.ContainerFluidCraftConfirm; +import com.glodblock.github.common.parts.PartFluidPatternTerminal; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.network.CPacketFluidPatternTermBtns; +import com.glodblock.github.network.CPacketSwitchGuis; +import com.google.common.base.Joiner; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class GuiFluidCraftConfirm extends AEBaseGui { + + private final ContainerFluidCraftConfirm ccc; + + private final int rows = 5; + + private final IItemList storage = AEApi.instance().storage().createItemList(); + private final IItemList pending = AEApi.instance().storage().createItemList(); + private final IItemList missing = AEApi.instance().storage().createItemList(); + + private final List visual = new ArrayList(); + + private GuiType OriginalGui; + private GuiButton cancel; + private GuiButton start; + private GuiButton selectCPU; + private int tooltip = -1; + + public GuiFluidCraftConfirm(final InventoryPlayer inventoryPlayer, final ITerminalHost te ) + { + super( new ContainerFluidCraftConfirm( inventoryPlayer, te ) ); + this.xSize = 238; + this.ySize = 206; + + final GuiScrollbar scrollbar = new GuiScrollbar(); + this.setScrollBar( scrollbar ); + + this.ccc = (ContainerFluidCraftConfirm) this.inventorySlots; + + if( te instanceof PartFluidPatternTerminal) + { + this.OriginalGui = GuiType.FLUID_PATTERN_TERMINAL; + } + } + + boolean isAutoStart() + { + return ( (ContainerFluidCraftConfirm) this.inventorySlots ).isAutoStart(); + } + + @Override + public void initGui() + { + super.initGui(); + + this.start = new GuiButton( 0, this.guiLeft + 162, this.guiTop + this.ySize - 25, 50, 20, GuiText.Start.getLocal() ); + this.start.enabled = false; + this.buttonList.add( this.start ); + + this.selectCPU = new GuiButton( 0, this.guiLeft + ( 219 - 180 ) / 2, this.guiTop + this.ySize - 68, 180, 20, GuiText.CraftingCPU.getLocal() + ": " + GuiText.Automatic ); + this.selectCPU.enabled = false; + this.buttonList.add( this.selectCPU ); + + if( this.OriginalGui != null ) + { + this.cancel = new GuiButton( 0, this.guiLeft + 6, this.guiTop + this.ySize - 25, 50, 20, GuiText.Cancel.getLocal() ); + } + + this.buttonList.add( this.cancel ); + } + + @Override + public void drawScreen( final int mouseX, final int mouseY, final float btn ) + { + this.updateCPUButtonText(); + + this.start.enabled = !( this.ccc.hasNoCPU() || this.isSimulation() ); + this.selectCPU.enabled = !this.isSimulation(); + + final int gx = ( this.width - this.xSize ) / 2; + final int gy = ( this.height - this.ySize ) / 2; + + this.tooltip = -1; + + final int offY = 23; + int y = 0; + int x = 0; + for( int z = 0; z <= 4 * 5; z++ ) + { + final int minX = gx + 9 + x * 67; + final int minY = gy + 22 + y * offY; + + if( minX < mouseX && minX + 67 > mouseX ) + { + if( minY < mouseY && minY + offY - 2 > mouseY ) + { + this.tooltip = z; + break; + } + } + + x++; + + if( x > 2 ) + { + y++; + x = 0; + } + } + + super.drawScreen( mouseX, mouseY, btn ); + } + + private void updateCPUButtonText() + { + String btnTextText = GuiText.CraftingCPU.getLocal() + ": " + GuiText.Automatic.getLocal(); + if( this.ccc.getSelectedCpu() >= 0 )// && status.selectedCpu < status.cpus.size() ) + { + if( this.ccc.getName().length() > 0 ) + { + final String name = this.ccc.getName().substring( 0, Math.min( 20, this.ccc.getName().length() ) ); + btnTextText = GuiText.CraftingCPU.getLocal() + ": " + name; + } + else + { + btnTextText = GuiText.CraftingCPU.getLocal() + ": #" + this.ccc.getSelectedCpu(); + } + } + + if( this.ccc.hasNoCPU() ) + { + btnTextText = GuiText.NoCraftingCPUs.getLocal(); + } + + this.selectCPU.displayString = btnTextText; + } + + private boolean isSimulation() + { + return ( (ContainerFluidCraftConfirm) this.inventorySlots ).isSimulation(); + } + + @Override + public void drawFG( final int offsetX, final int offsetY, final int mouseX, final int mouseY ) + { + final long BytesUsed = this.ccc.getUsedBytes(); + final String byteUsed = NumberFormat.getInstance().format( BytesUsed ); + final String Add = BytesUsed > 0 ? ( byteUsed + ' ' + GuiText.BytesUsed.getLocal() ) : GuiText.CalculatingWait.getLocal(); + this.fontRendererObj.drawString( GuiText.CraftingPlan.getLocal() + " - " + Add, 8, 7, 4210752 ); + + String dsp = null; + + if( this.isSimulation() ) + { + dsp = GuiText.Simulation.getLocal(); + } + else + { + dsp = this.ccc.getCpuAvailableBytes() > 0 ? ( GuiText.Bytes.getLocal() + ": " + this.ccc.getCpuAvailableBytes() + " : " + GuiText.CoProcessors.getLocal() + ": " + this.ccc.getCpuCoProcessors() ) : GuiText.Bytes.getLocal() + ": N/A : " + GuiText.CoProcessors.getLocal() + ": N/A"; + } + + final int offset = ( 219 - this.fontRendererObj.getStringWidth( dsp ) ) / 2; + this.fontRendererObj.drawString( dsp, offset, 165, 4210752 ); + + final int sectionLength = 67; + + int x = 0; + int y = 0; + final int xo = 9; + final int yo = 22; + final int viewStart = this.getScrollBar().getCurrentScroll() * 3; + final int viewEnd = viewStart + 3 * this.rows; + + String dspToolTip = ""; + final List lineList = new LinkedList(); + int toolPosX = 0; + int toolPosY = 0; + + final int offY = 23; + + for( int z = viewStart; z < Math.min( viewEnd, this.visual.size() ); z++ ) + { + final IAEItemStack refStack = this.visual.get( z );// repo.getReferenceItem( z ); + if( refStack != null ) + { + GL11.glPushMatrix(); + GL11.glScaled( 0.5, 0.5, 0.5 ); + + final IAEItemStack stored = this.storage.findPrecise( refStack ); + final IAEItemStack pendingStack = this.pending.findPrecise( refStack ); + final IAEItemStack missingStack = this.missing.findPrecise( refStack ); + + int lines = 0; + + if( stored != null && stored.getStackSize() > 0 ) + { + lines++; + } + if( pendingStack != null && pendingStack.getStackSize() > 0 ) + { + lines++; + } + if( pendingStack != null && pendingStack.getStackSize() > 0 ) + { + lines++; + } + + final int negY = ( ( lines - 1 ) * 5 ) / 2; + int downY = 0; + + if( stored != null && stored.getStackSize() > 0 ) + { + String str = Long.toString( stored.getStackSize() ); + if( stored.getStackSize() >= 10000 ) + { + str = Long.toString( stored.getStackSize() / 1000 ) + 'k'; + } + if( stored.getStackSize() >= 10000000 ) + { + str = Long.toString( stored.getStackSize() / 1000000 ) + 'm'; + } + + str = GuiText.FromStorage.getLocal() + ": " + str; + final int w = 4 + this.fontRendererObj.getStringWidth( str ); + this.fontRendererObj.drawString( str, (int) ( ( x * ( 1 + sectionLength ) + xo + sectionLength - 19 - ( w * 0.5 ) ) * 2 ), ( y * offY + yo + 6 - negY + downY ) * 2, 4210752 ); + + if( this.tooltip == z - viewStart ) + { + lineList.add( GuiText.FromStorage.getLocal() + ": " + Long.toString( stored.getStackSize() ) ); + } + + downY += 5; + } + + boolean red = false; + if( missingStack != null && missingStack.getStackSize() > 0 ) + { + String str = Long.toString( missingStack.getStackSize() ); + if( missingStack.getStackSize() >= 10000 ) + { + str = Long.toString( missingStack.getStackSize() / 1000 ) + 'k'; + } + if( missingStack.getStackSize() >= 10000000 ) + { + str = Long.toString( missingStack.getStackSize() / 1000000 ) + 'm'; + } + + str = GuiText.Missing.getLocal() + ": " + str; + final int w = 4 + this.fontRendererObj.getStringWidth( str ); + this.fontRendererObj.drawString( str, (int) ( ( x * ( 1 + sectionLength ) + xo + sectionLength - 19 - ( w * 0.5 ) ) * 2 ), ( y * offY + yo + 6 - negY + downY ) * 2, 4210752 ); + + if( this.tooltip == z - viewStart ) + { + lineList.add( GuiText.Missing.getLocal() + ": " + Long.toString( missingStack.getStackSize() ) ); + } + + red = true; + downY += 5; + } + + if( pendingStack != null && pendingStack.getStackSize() > 0 ) + { + String str = Long.toString( pendingStack.getStackSize() ); + if( pendingStack.getStackSize() >= 10000 ) + { + str = Long.toString( pendingStack.getStackSize() / 1000 ) + 'k'; + } + if( pendingStack.getStackSize() >= 10000000 ) + { + str = Long.toString( pendingStack.getStackSize() / 1000000 ) + 'm'; + } + + str = GuiText.ToCraft.getLocal() + ": " + str; + final int w = 4 + this.fontRendererObj.getStringWidth( str ); + this.fontRendererObj.drawString( str, (int) ( ( x * ( 1 + sectionLength ) + xo + sectionLength - 19 - ( w * 0.5 ) ) * 2 ), ( y * offY + yo + 6 - negY + downY ) * 2, 4210752 ); + + if( this.tooltip == z - viewStart ) + { + lineList.add( GuiText.ToCraft.getLocal() + ": " + Long.toString( pendingStack.getStackSize() ) ); + } + } + + GL11.glPopMatrix(); + final int posX = x * ( 1 + sectionLength ) + xo + sectionLength - 19; + final int posY = y * offY + yo; + + final ItemStack is = refStack.copy().getItemStack(); + + if( this.tooltip == z - viewStart ) + { + dspToolTip = Platform.getItemDisplayName( is ); + if( lineList.size() > 0 ) + { + addItemTooltip(is, lineList); + dspToolTip = dspToolTip + '\n' + Joiner.on( "\n" ).join( lineList ); + } + + toolPosX = x * ( 1 + sectionLength ) + xo + sectionLength - 8; + toolPosY = y * offY + yo; + } + + this.drawItem( posX, posY, is ); + + if( red ) + { + final int startX = x * ( 1 + sectionLength ) + xo; + final int startY = posY - 4; + drawRect( startX, startY, startX + sectionLength, startY + offY, 0x1AFF0000 ); + } + + x++; + + if( x > 2 ) + { + y++; + x = 0; + } + } + } + + if( this.tooltip >= 0 && dspToolTip.length() > 0 ) + { + this.drawTooltip( toolPosX, toolPosY + 10, 0, dspToolTip ); + } + } + + @Override + public void drawBG( final int offsetX, final int offsetY, final int mouseX, final int mouseY ) + { + this.setScrollBar(); + this.bindTexture( "guis/craftingreport.png" ); + this.drawTexturedModalRect( offsetX, offsetY, 0, 0, this.xSize, this.ySize ); + } + + private void setScrollBar() + { + final int size = this.visual.size(); + + this.getScrollBar().setTop( 19 ).setLeft( 218 ).setHeight( 114 ); + this.getScrollBar().setRange( 0, ( size + 2 ) / 3 - this.rows, 1 ); + } + + public void postUpdate( final List list, final byte ref ) + { + switch( ref ) + { + case 0: + for( final IAEItemStack l : list ) + { + this.handleInput( this.storage, l ); + } + break; + + case 1: + for( final IAEItemStack l : list ) + { + this.handleInput( this.pending, l ); + } + break; + + case 2: + for( final IAEItemStack l : list ) + { + this.handleInput( this.missing, l ); + } + break; + } + + for( final IAEItemStack l : list ) + { + final long amt = this.getTotal( l ); + + if( amt <= 0 ) + { + this.deleteVisualStack( l ); + } + else + { + final IAEItemStack is = this.findVisualStack( l ); + is.setStackSize( amt ); + } + } + + this.setScrollBar(); + } + + private void handleInput( final IItemList s, final IAEItemStack l ) + { + IAEItemStack a = s.findPrecise( l ); + + if( l.getStackSize() <= 0 ) + { + if( a != null ) + { + a.reset(); + } + } + else + { + if( a == null ) + { + s.add( l.copy() ); + a = s.findPrecise( l ); + } + + if( a != null ) + { + a.setStackSize( l.getStackSize() ); + } + } + } + + private long getTotal( final IAEItemStack is ) + { + final IAEItemStack a = this.storage.findPrecise( is ); + final IAEItemStack c = this.pending.findPrecise( is ); + final IAEItemStack m = this.missing.findPrecise( is ); + + long total = 0; + + if( a != null ) + { + total += a.getStackSize(); + } + + if( c != null ) + { + total += c.getStackSize(); + } + + if( m != null ) + { + total += m.getStackSize(); + } + + return total; + } + + private void deleteVisualStack( final IAEItemStack l ) + { + final Iterator i = this.visual.iterator(); + while( i.hasNext() ) + { + final IAEItemStack o = i.next(); + if( o.equals( l ) ) + { + i.remove(); + return; + } + } + } + + private IAEItemStack findVisualStack( final IAEItemStack l ) + { + for( final IAEItemStack o : this.visual ) + { + if( o.equals( l ) ) + { + return o; + } + } + + final IAEItemStack stack = l.copy(); + this.visual.add( stack ); + return stack; + } + + @Override + protected void keyTyped( final char character, final int key ) + { + if( !this.checkHotbarKeys( key ) ) + { + if( key == 28 ) + { + this.actionPerformed( this.start ); + } + super.keyTyped( character, key ); + } + } + + @Override + protected void actionPerformed( final GuiButton btn ) + { + super.actionPerformed( btn ); + + final boolean backwards = Mouse.isButtonDown( 1 ); + + if( btn == this.selectCPU ) + { + FluidCraft.proxy.netHandler.sendToServer( new CPacketFluidPatternTermBtns( "Terminal.Cpu", backwards ? "Prev" : "Next" ) ); + } + + if( btn == this.cancel ) + { + FluidCraft.proxy.netHandler.sendToServer( new CPacketSwitchGuis( this.OriginalGui ) ); + } + + if( btn == this.start ) + { + try + { + FluidCraft.proxy.netHandler.sendToServer( new CPacketFluidPatternTermBtns( "Terminal.Start", "Start" ) ); + } + catch( final Throwable e ) + { + AELog.debug( e ); + } + } + } + +} diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFluidPacketDecoder.java b/src/main/java/com/glodblock/github/client/gui/GuiFluidPacketDecoder.java new file mode 100644 index 00000000..989a439d --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/GuiFluidPacketDecoder.java @@ -0,0 +1,33 @@ +package com.glodblock.github.client.gui; + +import appeng.client.gui.AEBaseGui; +import appeng.core.localization.GuiText; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.gui.container.ContainerFluidPacketDecoder; +import com.glodblock.github.common.tile.TileFluidPacketDecoder; +import com.glodblock.github.util.NameConst; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.util.ResourceLocation; + +public class GuiFluidPacketDecoder extends AEBaseGui { + + private static final ResourceLocation TEX_BG = FluidCraft.resource("textures/gui/fluid_packet_decoder.png"); + + public GuiFluidPacketDecoder(InventoryPlayer ipl, TileFluidPacketDecoder tile) { + super(new ContainerFluidPacketDecoder(ipl, tile)); + } + + @Override + public void drawBG(int offsetX, int offsetY, int mouseX, int mouseY) { + mc.getTextureManager().bindTexture(TEX_BG); + drawTexturedModalRect(offsetX, offsetY, 0, 0, 176, ySize); + } + + @Override + public void drawFG(int offsetX, int offsetY, int mouseX, int mouseY) { + fontRendererObj.drawString(getGuiDisplayName(I18n.format(NameConst.GUI_FLUID_PACKET_DECODER)), 8, 6, 0x404040); + fontRendererObj.drawString(GuiText.inventory.getLocal(), 8, ySize - 94, 0x404040); + } + +} diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternEncoder.java b/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternEncoder.java new file mode 100644 index 00000000..45f71284 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternEncoder.java @@ -0,0 +1,136 @@ +package com.glodblock.github.client.gui; + +import appeng.api.storage.data.IAEItemStack; +import appeng.client.gui.AEBaseGui; +import appeng.client.render.AppEngRenderItem; +import appeng.core.localization.GuiText; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.gui.container.ContainerFluidPatternEncoder; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.common.tile.TileFluidPatternEncoder; +import com.glodblock.github.inventory.gui.MouseRegionManager; +import com.glodblock.github.inventory.slot.SlotFluid; +import com.glodblock.github.inventory.slot.SlotSingleItem; +import com.glodblock.github.network.CPacketEncodePattern; +import com.glodblock.github.util.Ae2Reflect; +import com.glodblock.github.util.NameConst; +import com.glodblock.github.util.Util; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fluids.FluidStack; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class GuiFluidPatternEncoder extends AEBaseGui { + + private static final ResourceLocation TEX_BG = FluidCraft.resource("textures/gui/fluid_pattern_encoder.png"); + + private final ContainerFluidPatternEncoder cont; + private final MouseRegionManager mouseRegions = new MouseRegionManager(this, fontRendererObj); + private final AppEngRenderItem stackSizeRenderer = Ae2Reflect.getStackSizeRenderer(this); + + public GuiFluidPatternEncoder(InventoryPlayer ipl, TileFluidPatternEncoder tile) { + super(new ContainerFluidPatternEncoder(ipl, tile)); + this.cont = (ContainerFluidPatternEncoder)inventorySlots; + mouseRegions.addRegion(141, 38, 10, 10, new MouseRegionManager.Handler() { + @Override + public List getTooltip() { + return Collections.singletonList(I18n.format(NameConst.TT_ENCODE_PATTERN)); + } + + @Override + public boolean onClick(int button) { + if (button == 0) { + if (cont.canEncodePattern()) { + FluidCraft.proxy.netHandler.sendToServer(new CPacketEncodePattern()); + } + return true; + } + return false; + } + }); + } + + @Override + protected void mouseClicked(int xCoord, int yCoord, int btn) { + if (mouseRegions.onClick(xCoord, yCoord, btn)) { + super.mouseClicked(xCoord, yCoord, btn); + } + } + + @Override + public void drawBG(int offsetX, int offsetY, int mouseX, int mouseY) { + mc.getTextureManager().bindTexture(TEX_BG); + drawTexturedModalRect(offsetX, offsetY, 0, 0, 176, ySize); + } + + @Override + public void drawFG(int offsetX, int offsetY, int mouseX, int mouseY) { + fontRendererObj.drawString(getGuiDisplayName(I18n.format(NameConst.GUI_FLUID_PATTERN_ENCODER)), 8, 6, 0x404040); + fontRendererObj.drawString(GuiText.inventory.getLocal(), 8, ySize - 94, 0x404040); + mouseRegions.render(mouseX, mouseY); + } + + @Override + public void func_146977_a( final Slot s ) + { + this.drawSlot0( s ); + } + + public void drawSlot0(Slot slot) { + if (slot instanceof SlotFluid) { + IAEItemStack stack = ((SlotFluid)slot).getAeStack(); + super.func_146977_a(new SlotSingleItem(slot)); + if (stack == null) return; + IAEItemStack fake = stack.copy(); + if (fake.getItemStack().getItem() instanceof ItemFluidPacket) { + if (ItemFluidPacket.getFluidStack(stack) != null && ItemFluidPacket.getFluidStack(stack).amount > 0) + fake.setStackSize(ItemFluidPacket.getFluidStack(stack).amount); + } + stackSizeRenderer.setAeStack(fake); + stackSizeRenderer.renderItemOverlayIntoGUI(fontRendererObj, mc.getTextureManager(), stack.getItemStack(), slot.xDisplayPosition, slot.yDisplayPosition); + } else { + super.func_146977_a(slot); + } + } + + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + protected void renderToolTip(ItemStack stack, int x, int y) { + List list; + if (stack.getItem() instanceof ItemFluidPacket) { + FluidStack fluid = ItemFluidPacket.getFluidStack(stack); + if (fluid != null) { + list = Arrays.asList(fluid.getLocalizedName(), String.format(EnumChatFormatting.GRAY + "%,d mB", fluid.amount)); + } + else { + list = stack.getTooltip(this.mc.thePlayer, this.mc.gameSettings.advancedItemTooltips); + } + } + else { + list = stack.getTooltip(this.mc.thePlayer, this.mc.gameSettings.advancedItemTooltips); + } + + for (int k = 0; k < list.size(); ++k) + { + if (k == 0) + { + list.set(k, stack.getRarity().rarityColor + (String)list.get(k)); + } + else + { + list.set(k, EnumChatFormatting.GRAY + (String)list.get(k)); + } + } + FontRenderer font = stack.getItem().getFontRenderer(stack); + drawHoveringText(list, x, y, (font == null ? fontRendererObj : font)); + } + +} diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternTerminal.java b/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternTerminal.java new file mode 100644 index 00000000..7a372bb4 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternTerminal.java @@ -0,0 +1,73 @@ +package com.glodblock.github.client.gui; + +import appeng.api.storage.ITerminalHost; +import appeng.api.storage.data.IAEItemStack; +import appeng.client.gui.widgets.GuiTabButton; +import appeng.client.render.AppEngRenderItem; +import appeng.container.slot.SlotFake; +import appeng.util.item.AEItemStack; +import com.glodblock.github.client.gui.container.ContainerFluidPatternTerminal; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.inventory.slot.SlotSingleItem; +import com.glodblock.github.util.Ae2Reflect; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; + +public class GuiFluidPatternTerminal extends GuiBaseFluidPatternTerminal { + + private GuiTabButton craftingStatusBtn; + private final AppEngRenderItem stackSizeRenderer = Ae2Reflect.getStackSizeRenderer(this); + + public GuiFluidPatternTerminal(InventoryPlayer inventoryPlayer, ITerminalHost te) { + super(inventoryPlayer, te); + ContainerFluidPatternTerminal container = new ContainerFluidPatternTerminal(inventoryPlayer, te); + container.setGui(this); + this.inventorySlots = container; + Ae2Reflect.setGuiContainer(this, container); + } + + @Override + public void initGui() { + super.initGui(); + craftingStatusBtn = Ae2Reflect.getCraftingStatusButton(this); + } + + @Override + public void func_146977_a( final Slot s ) + { + if (drawSlot0(s)) + super.func_146977_a( s ); + } + + public boolean drawSlot0(Slot slot) { + if (slot instanceof SlotFake && !this.container.isCraftingMode()) { + AEItemStack stack = AEItemStack.create(slot.getStack()); + super.func_146977_a(new SlotSingleItem(slot)); + if (stack == null) return true; + IAEItemStack fake = stack.copy(); + if (fake.getItemStack().getItem() instanceof ItemFluidPacket) { + if (ItemFluidPacket.getFluidStack(stack) != null && ItemFluidPacket.getFluidStack(stack).amount > 0) + fake.setStackSize(ItemFluidPacket.getFluidStack(stack).amount); + } + else + return true; + stackSizeRenderer.setAeStack(fake); + stackSizeRenderer.renderItemOverlayIntoGUI(fontRendererObj, mc.getTextureManager(), stack.getItemStack(), slot.xDisplayPosition, slot.yDisplayPosition); + return false; + } + return true; + } + + @Override + protected void actionPerformed(final GuiButton btn) { + if (btn == craftingStatusBtn) { + InventoryHandler.switchGui(GuiType.FLUID_PAT_TERM_CRAFTING_STATUS); + } else { + super.actionPerformed(btn); + } + } + +} diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternTerminalCraftingStatus.java b/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternTerminalCraftingStatus.java new file mode 100644 index 00000000..3e6e44fb --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternTerminalCraftingStatus.java @@ -0,0 +1,38 @@ +package com.glodblock.github.client.gui; + +import appeng.api.storage.ITerminalHost; +import appeng.client.gui.implementations.GuiCraftingStatus; +import appeng.client.gui.widgets.GuiTabButton; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.loader.ItemAndBlockHolder; +import com.glodblock.github.util.Ae2Reflect; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; + +public class GuiFluidPatternTerminalCraftingStatus extends GuiCraftingStatus { + + private GuiTabButton originalGuiBtn; + + public GuiFluidPatternTerminalCraftingStatus(InventoryPlayer inventoryPlayer, ITerminalHost te) { + super(inventoryPlayer, te); + } + + @Override + public void initGui() { + Ae2Reflect.rewriteIcon(this, new ItemStack(ItemAndBlockHolder.FLUID_TERMINAL, 1)); + super.initGui(); + originalGuiBtn = Ae2Reflect.getOriginalGuiButton(this); + } + + @Override + protected void actionPerformed(final GuiButton btn) { + if (btn == originalGuiBtn) { + InventoryHandler.switchGui(GuiType.FLUID_PATTERN_TERMINAL); + } else { + super.actionPerformed(btn); + } + } + +} diff --git a/src/main/java/com/glodblock/github/client/gui/IFluidSyncContainer.java b/src/main/java/com/glodblock/github/client/gui/IFluidSyncContainer.java new file mode 100644 index 00000000..469d66b7 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/IFluidSyncContainer.java @@ -0,0 +1,9 @@ +package com.glodblock.github.client.gui; + +import appeng.api.storage.data.IAEFluidStack; + +import java.util.Map; + +public interface IFluidSyncContainer { + void receiveFluidSlots( final Map fluids ); +} diff --git a/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidConfigurable.java b/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidConfigurable.java new file mode 100644 index 00000000..209572fa --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidConfigurable.java @@ -0,0 +1,382 @@ +package com.glodblock.github.client.gui.container; + +import appeng.api.config.Upgrades; +import appeng.api.implementations.IUpgradeableHost; +import appeng.api.storage.data.IAEFluidStack; +import appeng.client.me.InternalSlotME; +import appeng.client.me.SlotME; +import appeng.container.implementations.ContainerUpgradeable; +import appeng.container.slot.*; +import appeng.util.Platform; +import appeng.util.item.AEFluidStack; +import com.glodblock.github.client.gui.IFluidSyncContainer; +import com.glodblock.github.inventory.IAEFluidTank; +import com.glodblock.github.util.Ae2Reflect; +import com.glodblock.github.util.FluidSyncHelper; +import com.glodblock.github.util.Util; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public abstract class ContainerFluidConfigurable extends ContainerUpgradeable implements IFluidSyncContainer +{ + private FluidSyncHelper sync = null; + + public ContainerFluidConfigurable(InventoryPlayer ip, IUpgradeableHost te ) + { + super( ip, te ); + } + + public abstract IAEFluidTank getFluidConfigInventory(); + + private FluidSyncHelper getSynchHelper() + { + if( this.sync == null ) + { + this.sync = new FluidSyncHelper( this.getFluidConfigInventory(), 0 ); + } + return this.sync; + } + + @Override + public ItemStack transferStackInSlot(final EntityPlayer p, final int idx ) + { + if( Platform.isClient() ) + { + return null; + } + + boolean hasMETiles = false; + for( final Object is : this.inventorySlots ) + { + if( is instanceof InternalSlotME) + { + hasMETiles = true; + break; + } + } + + if( hasMETiles && Platform.isClient() ) + { + return null; + } + + final AppEngSlot clickSlot = (AppEngSlot) this.inventorySlots.get( idx ); // require AE SLots! + + if( clickSlot instanceof SlotDisabled || clickSlot instanceof SlotInaccessible) + { + return null; + } + if( clickSlot != null && clickSlot.getHasStack() ) + { + ItemStack tis = clickSlot.getStack(); + + if( tis == null ) + { + return null; + } + + final List selectedSlots = new ArrayList(); + + /** + * Gather a list of valid destinations. + */ + if( clickSlot.isPlayerSide() ) + { + tis = this.transferStackToContainer( tis ); + + // target slots in the container... + for( final Object inventorySlot : this.inventorySlots ) + { + final AppEngSlot cs = (AppEngSlot) inventorySlot; + + if( !( cs.isPlayerSide() ) && !( cs instanceof SlotFake) && !( cs instanceof SlotCraftingMatrix) ) + { + if( cs.isItemValid( tis ) ) + { + selectedSlots.add( cs ); + } + } + } + } + else + { + // target slots in the container... + for( final Object inventorySlot : this.inventorySlots ) + { + final AppEngSlot cs = (AppEngSlot) inventorySlot; + + if( ( cs.isPlayerSide() ) && !( cs instanceof SlotFake ) && !( cs instanceof SlotCraftingMatrix ) ) + { + if( cs.isItemValid( tis ) ) + { + selectedSlots.add( cs ); + } + } + } + } + + /** + * Handle Fake Slot Shift clicking. + */ + if( selectedSlots.isEmpty() && clickSlot.isPlayerSide() ) + { + if( tis != null ) + { + // target slots in the container... + for( final Object inventorySlot : this.inventorySlots ) + { + final AppEngSlot cs = (AppEngSlot) inventorySlot; + final ItemStack destination = cs.getStack(); + + if( !( cs.isPlayerSide() ) && cs instanceof SlotFake ) + { + if( Platform.isSameItemPrecise( destination, tis ) ) + { + break; + } + else if( destination == null ) + { + cs.putStack( tis.copy() ); + cs.onSlotChanged(); + this.detectAndSendChanges(); + break; + } + } + } + } + } + + if( tis != null ) + { + // find partials.. + for( final Slot d : selectedSlots ) + { + if( d instanceof SlotDisabled || d instanceof SlotME) + { + continue; + } + + if( d.isItemValid( tis ) ) + { + if( d.getHasStack() ) + { + final ItemStack t = d.getStack(); + + if( Platform.isSameItemPrecise( tis, t ) ) // t.isItemEqual(tis)) + { + int maxSize = t.getMaxStackSize(); + if( maxSize > d.getSlotStackLimit() ) + { + maxSize = d.getSlotStackLimit(); + } + + int placeAble = maxSize - t.stackSize; + + if( tis.stackSize < placeAble ) + { + placeAble = tis.stackSize; + } + + t.stackSize += placeAble; + tis.stackSize -= placeAble; + + if( tis.stackSize <= 0 ) + { + clickSlot.putStack( null ); + d.onSlotChanged(); + + // if ( hasMETiles ) updateClient(); + + this.detectAndSendChanges(); + this.detectAndSendChanges(); + return null; + } + else + { + this.detectAndSendChanges(); + } + } + } + } + } + + // any match.. + for( final Slot d : selectedSlots ) + { + if( d instanceof SlotDisabled || d instanceof SlotME ) + { + continue; + } + + if( d.isItemValid( tis ) ) + { + if( d.getHasStack() ) + { + final ItemStack t = d.getStack(); + + if( Platform.isSameItemPrecise( t, tis ) ) + { + int maxSize = t.getMaxStackSize(); + if( d.getSlotStackLimit() < maxSize ) + { + maxSize = d.getSlotStackLimit(); + } + + int placeAble = maxSize - t.stackSize; + + if( tis.stackSize < placeAble ) + { + placeAble = tis.stackSize; + } + + t.stackSize += placeAble; + tis.stackSize -= placeAble; + + if( tis.stackSize <= 0 ) + { + clickSlot.putStack( null ); + d.onSlotChanged(); + + // if ( worldEntity != null ) + // worldEntity.markDirty(); + // if ( hasMETiles ) updateClient(); + + this.detectAndSendChanges(); + this.detectAndSendChanges(); + return null; + } + else + { + this.detectAndSendChanges(); + } + } + } + else + { + int maxSize = tis.getMaxStackSize(); + if( maxSize > d.getSlotStackLimit() ) + { + maxSize = d.getSlotStackLimit(); + } + + final ItemStack tmp = tis.copy(); + if( tmp.stackSize > maxSize ) + { + tmp.stackSize = maxSize; + } + + tis.stackSize -= tmp.stackSize; + d.putStack( tmp ); + + if( tis.stackSize <= 0 ) + { + clickSlot.putStack( null ); + d.onSlotChanged(); + + // if ( worldEntity != null ) + // worldEntity.markDirty(); + // if ( hasMETiles ) updateClient(); + + this.detectAndSendChanges(); + this.detectAndSendChanges(); + return null; + } + else + { + this.detectAndSendChanges(); + } + } + } + } + } + + clickSlot.putStack( tis != null ? tis.copy() : null ); + } + + this.detectAndSendChanges(); + return null; + } + + protected ItemStack transferStackToContainer(ItemStack input ) + { + FluidStack fs = Util.getFluidFromItem( input ); + if( fs != null ) + { + final IAEFluidTank t = this.getFluidConfigInventory(); + final IAEFluidStack stack = AEFluidStack.create( fs ); + for( int i = 0; i < t.getSlots(); ++i ) + { + if( t.getFluidInSlot( i ) == null && this.isValidForConfig( i, stack ) ) + { + t.setFluidInSlot( i, stack ); + break; + } + } + } + return input; + } + + protected boolean isValidForConfig( int slot, IAEFluidStack fs ) + { + if( this.supportCapacity() ) + { + // assumes 4 slots per upgrade + final int upgrades = Ae2Reflect.getUpgrade(this).getInstalledUpgrades( Upgrades.CAPACITY ); + + if( slot > 0 && upgrades < 1 ) + { + return false; + } + if( slot > 4 && upgrades < 2 ) + { + return false; + } + } + + return true; + } + + @Override + @SuppressWarnings("unchecked") + protected void standardDetectAndSendChanges() + { + if( Platform.isServer() ) + { + this.getSynchHelper().sendDiff( this.crafters ); + + // clear out config items that are no longer valid (eg capacity upgrade removed) + final IAEFluidTank t = this.getFluidConfigInventory(); + for( int i = 0; i < t.getSlots(); ++i ) + { + if( t.getFluidInSlot( i ) != null && !this.isValidForConfig( i, t.getFluidInSlot( i ) ) ) + { + t.setFluidInSlot( i, null ); + } + } + } + super.standardDetectAndSendChanges(); + } + + @Override + public void addCraftingToCrafters( ICrafting listener ) + { + super.addCraftingToCrafters( listener ); + this.getSynchHelper().sendFull( Collections.singleton( listener ) ); + } + + @Override + public void receiveFluidSlots( Map fluids ) + { + this.getSynchHelper().readPacket( fluids ); + } + +} diff --git a/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidCraftConfirm.java b/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidCraftConfirm.java new file mode 100644 index 00000000..3f26ac62 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidCraftConfirm.java @@ -0,0 +1,436 @@ +package com.glodblock.github.client.gui.container; + +import appeng.api.AEApi; +import appeng.api.config.Actionable; +import appeng.api.config.SecurityPermissions; +import appeng.api.networking.IGrid; +import appeng.api.networking.crafting.ICraftingCPU; +import appeng.api.networking.crafting.ICraftingGrid; +import appeng.api.networking.crafting.ICraftingJob; +import appeng.api.networking.crafting.ICraftingLink; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.security.IActionHost; +import appeng.api.networking.security.PlayerSource; +import appeng.api.networking.storage.IStorageGrid; +import appeng.api.storage.IMEInventory; +import appeng.api.storage.ITerminalHost; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; +import appeng.container.AEBaseContainer; +import appeng.container.guisync.GuiSync; +import appeng.container.implementations.CraftingCPURecord; +import appeng.core.AELog; +import appeng.util.Platform; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.common.parts.PartFluidPatternTerminal; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.network.SPacketMEInventoryUpdate; +import com.glodblock.github.util.Ae2Reflect; +import com.google.common.collect.ImmutableSet; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.util.ChatComponentText; +import net.minecraft.world.World; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Collections; +import java.util.concurrent.Future; + +public class ContainerFluidCraftConfirm extends AEBaseContainer { + + private final ArrayList cpus = new ArrayList(); + private Future job; + private ICraftingJob result; + @GuiSync( 0 ) + public long bytesUsed; + @GuiSync( 1 ) + public long cpuBytesAvail; + @GuiSync( 2 ) + public int cpuCoProcessors; + @GuiSync( 3 ) + public boolean autoStart = false; + @GuiSync( 4 ) + public boolean simulation = true; + @GuiSync( 5 ) + public int selectedCpu = -1; + @GuiSync( 6 ) + public boolean noCPU = true; + @GuiSync( 7 ) + public String myName = ""; + + public ContainerFluidCraftConfirm(final InventoryPlayer ip, final ITerminalHost te ) + { + super( ip, te ); + } + + public void cycleCpu( final boolean next ) + { + if( next ) + { + this.setSelectedCpu( this.getSelectedCpu() + 1 ); + } + else + { + this.setSelectedCpu( this.getSelectedCpu() - 1 ); + } + + if( this.getSelectedCpu() < -1 ) + { + this.setSelectedCpu( this.cpus.size() - 1 ); + } + else if( this.getSelectedCpu() >= this.cpus.size() ) + { + this.setSelectedCpu( -1 ); + } + + if( this.getSelectedCpu() == -1 ) + { + this.setCpuAvailableBytes( 0 ); + this.setCpuCoProcessors( 0 ); + this.setName( "" ); + } + else + { + this.setName(Ae2Reflect.getName(this.cpus.get(this.getSelectedCpu()))); + this.setCpuAvailableBytes(Ae2Reflect.getSize(this.cpus.get(this.getSelectedCpu()))); + this.setCpuCoProcessors(Ae2Reflect.getProcessors(this.cpus.get(this.getSelectedCpu()))); + } + } + + @Override + public void detectAndSendChanges() + { + if( Platform.isClient() ) + { + return; + } + if (getGrid() == null) + return; + + final ICraftingGrid cc = this.getGrid().getCache( ICraftingGrid.class ); + final ImmutableSet cpuSet = cc.getCpus(); + + int matches = 0; + boolean changed = false; + for( final ICraftingCPU c : cpuSet ) + { + boolean found = false; + for( final CraftingCPURecord ccr : this.cpus ) + { + if( Ae2Reflect.getCPU(ccr) == c ) + { + found = true; + } + } + + final boolean matched = this.cpuMatches( c ); + + if( matched ) + { + matches++; + } + + if( found == !matched ) + { + changed = true; + } + } + + if( changed || this.cpus.size() != matches ) + { + this.cpus.clear(); + for( final ICraftingCPU c : cpuSet ) + { + if( this.cpuMatches( c ) ) + { + this.cpus.add( new CraftingCPURecord( c.getAvailableStorage(), c.getCoProcessors(), c ) ); + } + } + + this.sendCPUs(); + } + + this.setNoCPU( this.cpus.isEmpty() ); + + super.detectAndSendChanges(); + + if( this.getJob() != null && this.getJob().isDone() ) + { + try + { + this.result = this.getJob().get(); + + if( !this.result.isSimulation() ) + { + this.setSimulation( false ); + if( this.isAutoStart() ) + { + this.startJob(); + return; + } + } + else + { + this.setSimulation( true ); + } + + final SPacketMEInventoryUpdate a = new SPacketMEInventoryUpdate( (byte) 0 ); + final SPacketMEInventoryUpdate b = new SPacketMEInventoryUpdate( (byte) 1 ); + final SPacketMEInventoryUpdate c = this.result.isSimulation() ? new SPacketMEInventoryUpdate( (byte) 2 ) : null; + + final IItemList plan = AEApi.instance().storage().createItemList(); + this.result.populatePlan( plan ); + + this.setUsedBytes( this.result.getByteTotal() ); + + for( final IAEItemStack out : plan ) + { + + IAEItemStack o = out.copy(); + o.reset(); + o.setStackSize( out.getStackSize() ); + + final IAEItemStack p = out.copy(); + p.reset(); + p.setStackSize( out.getCountRequestable() ); + + final IStorageGrid sg = this.getGrid().getCache( IStorageGrid.class ); + final IMEInventory items = sg.getItemInventory(); + + IAEItemStack m = null; + if( c != null && this.result.isSimulation() ) + { + m = o.copy(); + o = items.extractItems( o, Actionable.SIMULATE, this.getActionSource() ); + + if( o == null ) + { + o = m.copy(); + o.setStackSize( 0 ); + } + + m.setStackSize( m.getStackSize() - o.getStackSize() ); + } + + if( o.getStackSize() > 0 ) + { + a.appendItem( o ); + } + + if( p.getStackSize() > 0 ) + { + b.appendItem( p ); + } + + if( c != null && m != null && m.getStackSize() > 0 ) + { + c.appendItem( m ); + } + } + + for( final Object g : this.crafters ) + { + if( g instanceof EntityPlayer) + { + FluidCraft.proxy.netHandler.sendTo( a, (EntityPlayerMP) g ); + FluidCraft.proxy.netHandler.sendTo( b, (EntityPlayerMP) g ); + if( c != null ) + { + FluidCraft.proxy.netHandler.sendTo( c, (EntityPlayerMP) g ); + } + } + } + } + catch( final Throwable e ) + { + this.getPlayerInv().player.addChatMessage( new ChatComponentText( "Error: " + e.toString() ) ); + AELog.debug( e ); + this.setValidContainer( false ); + this.result = null; + } + + this.setJob( null ); + } + this.verifyPermissions( SecurityPermissions.CRAFT, false ); + } + + private IGrid getGrid() + { + final IActionHost h = ( (IActionHost) this.getTarget() ); + if (h == null || h.getActionableNode() == null) + return null; + return h.getActionableNode().getGrid(); + } + + private boolean cpuMatches( final ICraftingCPU c ) + { + return c.getAvailableStorage() >= this.getUsedBytes() && !c.isBusy(); + } + + private void sendCPUs() + { + Collections.sort( this.cpus ); + + if( this.getSelectedCpu() >= this.cpus.size() ) + { + this.setSelectedCpu( -1 ); + this.setCpuAvailableBytes( 0 ); + this.setCpuCoProcessors( 0 ); + this.setName( "" ); + } + else if( this.getSelectedCpu() != -1 ) + { + this.setName(Ae2Reflect.getName(this.cpus.get(this.getSelectedCpu()))); + this.setCpuAvailableBytes(Ae2Reflect.getSize(this.cpus.get(this.getSelectedCpu()))); + this.setCpuCoProcessors(Ae2Reflect.getProcessors(this.cpus.get(this.getSelectedCpu()))); + } + } + + public void startJob() + { + GuiType originalGui = null; + + final IActionHost ah = this.getActionHost(); + if( ah instanceof PartFluidPatternTerminal) + { + originalGui = GuiType.FLUID_PATTERN_TERMINAL; + } + + if( this.result != null && !this.isSimulation() && getGrid() != null) + { + final ICraftingGrid cc = this.getGrid().getCache( ICraftingGrid.class ); + final ICraftingLink g = cc.submitJob( this.result, null, this.getSelectedCpu() == -1 ? null : Ae2Reflect.getCPU(this.cpus.get(this.getSelectedCpu())), true, this.getActionSrc() ); + this.setAutoStart( false ); + if( g != null && originalGui != null && this.getOpenContext() != null ) + { + InventoryHandler.switchGui(originalGui); + } + } + } + + private BaseActionSource getActionSrc() + { + return new PlayerSource( this.getPlayerInv().player, (IActionHost) this.getTarget() ); + } + + @Override + public void removeCraftingFromCrafters( final ICrafting c ) + { + super.removeCraftingFromCrafters( c ); + if( this.getJob() != null ) + { + this.getJob().cancel( true ); + this.setJob( null ); + } + } + + @Override + public void onContainerClosed( final EntityPlayer par1EntityPlayer ) + { + super.onContainerClosed( par1EntityPlayer ); + if( this.getJob() != null ) + { + this.getJob().cancel( true ); + this.setJob( null ); + } + } + + public World getWorld() + { + return this.getPlayerInv().player.worldObj; + } + + public boolean isAutoStart() + { + return this.autoStart; + } + + public void setAutoStart( final boolean autoStart ) + { + this.autoStart = autoStart; + } + + public long getUsedBytes() + { + return this.bytesUsed; + } + + private void setUsedBytes( final long bytesUsed ) + { + this.bytesUsed = bytesUsed; + } + + public long getCpuAvailableBytes() + { + return this.cpuBytesAvail; + } + + private void setCpuAvailableBytes( final long cpuBytesAvail ) + { + this.cpuBytesAvail = cpuBytesAvail; + } + + public int getCpuCoProcessors() + { + return this.cpuCoProcessors; + } + + private void setCpuCoProcessors( final int cpuCoProcessors ) + { + this.cpuCoProcessors = cpuCoProcessors; + } + + public int getSelectedCpu() + { + return this.selectedCpu; + } + + private void setSelectedCpu( final int selectedCpu ) + { + this.selectedCpu = selectedCpu; + } + + public String getName() + { + return this.myName; + } + + private void setName( @Nonnull final String myName ) + { + this.myName = myName; + } + + public boolean hasNoCPU() + { + return this.noCPU; + } + + private void setNoCPU( final boolean noCPU ) + { + this.noCPU = noCPU; + } + + public boolean isSimulation() + { + return this.simulation; + } + + private void setSimulation( final boolean simulation ) + { + this.simulation = simulation; + } + + private Future getJob() + { + return this.job; + } + + public void setJob( final Future job ) + { + this.job = job; + } +} diff --git a/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidPacketDecoder.java b/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidPacketDecoder.java new file mode 100644 index 00000000..94adedee --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidPacketDecoder.java @@ -0,0 +1,16 @@ +package com.glodblock.github.client.gui.container; + +import appeng.container.AEBaseContainer; +import appeng.container.slot.SlotNormal; +import com.glodblock.github.common.tile.TileFluidPacketDecoder; +import net.minecraft.entity.player.InventoryPlayer; + +public class ContainerFluidPacketDecoder extends AEBaseContainer { + + public ContainerFluidPacketDecoder(InventoryPlayer ipl, TileFluidPacketDecoder tile) { + super(ipl, tile); + addSlotToContainer(new SlotNormal(tile.getInventory(), 0, 80, 35)); + bindPlayerInventory(ipl, 0, 84); + } + +} diff --git a/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidPatternEncoder.java b/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidPatternEncoder.java new file mode 100644 index 00000000..fe2d6dcf --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidPatternEncoder.java @@ -0,0 +1,226 @@ +package com.glodblock.github.client.gui.container; + +import appeng.api.AEApi; +import appeng.api.storage.data.IAEItemStack; +import appeng.container.AEBaseContainer; +import appeng.container.slot.SlotFake; +import appeng.container.slot.SlotRestrictedInput; +import appeng.helpers.InventoryAction; +import appeng.util.item.AEItemStack; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidEncodedPattern; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.common.tile.TileFluidPatternEncoder; +import com.glodblock.github.inventory.AeItemStackHandler; +import com.glodblock.github.inventory.AeStackInventory; +import com.glodblock.github.inventory.PatternConsumer; +import com.glodblock.github.inventory.slot.SlotFluid; +import com.glodblock.github.loader.ItemAndBlockHolder; +import com.glodblock.github.util.FluidPatternDetails; +import com.glodblock.github.util.Util; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidContainerRegistry; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidContainerItem; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class ContainerFluidPatternEncoder extends AEBaseContainer implements PatternConsumer { + + private final TileFluidPatternEncoder tile; + + public ContainerFluidPatternEncoder(InventoryPlayer ipl, TileFluidPatternEncoder tile) { + super(ipl, tile); + this.tile = tile; + AeItemStackHandler crafting = new AeItemStackHandler(tile.getCraftingSlots()); + AeItemStackHandler output = new AeItemStackHandler(tile.getOutputSlots()); + for (int y = 0; y < 3; y++) { + for (int x = 0; x < 3; x++) { + addSlotToContainer(new SlotFluidConvertingFake(crafting, y * 3 + x, 23 + x * 18, 17 + y * 18)); + } + addSlotToContainer(new SlotFluidConvertingFake(output, y, 113, 17 + y * 18)); + } + addSlotToContainer(new SlotRestrictedInput( + SlotRestrictedInput.PlacableItemType.BLANK_PATTERN, tile.getInventory(), 0, 138, 20, ipl)); + addSlotToContainer(new SlotRestrictedInput( + SlotRestrictedInput.PlacableItemType.ENCODED_PATTERN, tile.getInventory(), 1, 138, 50, ipl)); + bindPlayerInventory(ipl, 0, 84); + } + + public TileFluidPatternEncoder getTile() { + return tile; + } + + public boolean canEncodePattern() { + if (isNotPattern(tile.getInventory().getStackInSlot(0)) && isNotPattern(tile.getInventory().getStackInSlot(1))) { + return false; + } + find_input: + { + for (IAEItemStack stack : tile.getCraftingSlots()) { + if (stack != null && stack.getStackSize() > 0) { + break find_input; + } + } + return false; + } + for (IAEItemStack stack : tile.getOutputSlots()) { + if (stack != null && stack.getStackSize() > 0) { + return true; + } + } + return false; + } + + private static boolean isNotPattern(ItemStack stack) { + return stack == null || !(AEApi.instance().definitions().materials().blankPattern().isSameAs(stack) + || (stack.getItem() instanceof ItemFluidEncodedPattern)); + } + + public void encodePattern() { + if (canEncodePattern()) { + // if there is an encoded pattern, overwrite it; otherwise, consume a blank + if (tile.getInventory().getStackInSlot(1) == null) { + tile.getInventory().decrStackSize(0, 1); // this better work + } + ItemStack patternStack = new ItemStack(ItemAndBlockHolder.PATTERN); + FluidPatternDetails pattern = new FluidPatternDetails(patternStack); + pattern.setInputs(collectAeInventory(tile.getCraftingSlots())); + pattern.setOutputs(collectAeInventory(tile.getOutputSlots())); + tile.getInventory().setInventorySlotContents(1, pattern.writeToStack()); + } + } + + private static IAEItemStack[] collectAeInventory(AeStackInventory inv) { + // see note at top of DensePatternDetails + List acc = new ArrayList<>(); + for (IAEItemStack stack : inv) { + if (stack != null) { + if (stack.getItem() instanceof ItemFluidPacket) { + IAEItemStack dropStack = ItemFluidDrop.newAeStack(ItemFluidPacket.getFluidStack(stack)); + if (dropStack != null) { + acc.add(dropStack); + continue; + } + } + acc.add(stack); + } + } + return acc.toArray(new IAEItemStack[0]); + } + + // adapted from ae2's AEBaseContainer#doAction + @Override + public void doAction(EntityPlayerMP player, InventoryAction action, int slotId, long id) { + Slot slot = getSlot(slotId); + if (slot instanceof SlotFluidConvertingFake) { + final ItemStack stack = player.inventory.getItemStack(); + switch (action) { + case PICKUP_OR_SET_DOWN: + if (stack == null) { + slot.putStack(null); + } else { + ((SlotFluidConvertingFake)slot).putConvertedStack(stack.copy()); + } + break; + case PLACE_SINGLE: + if (stack != null) { + ((SlotFluidConvertingFake)slot).putConvertedStack(Objects.requireNonNull(Util.copyStackWithSize(stack, 1))); + } + break; + case SPLIT_OR_PLACE_SINGLE: + ItemStack inSlot = slot.getStack(); + if (inSlot != null) { + if (stack == null) { + slot.putStack(Util.copyStackWithSize(inSlot, Math.max(1, inSlot.stackSize - 1))); + } else if (stack.isItemEqual(inSlot)) { + slot.putStack(Util.copyStackWithSize(inSlot, + Math.min(inSlot.getMaxStackSize(), inSlot.stackSize + 1))); + } else { + ((SlotFluidConvertingFake)slot).putConvertedStack(Objects.requireNonNull(Util.copyStackWithSize(stack, 1))); + } + } else if (stack != null) { + ((SlotFluidConvertingFake)slot).putConvertedStack(Objects.requireNonNull(Util.copyStackWithSize(stack, 1))); + } + break; + } + } else { + super.doAction(player, action, slotId, id); + } + } + + @Override + public void acceptPattern(IAEItemStack[] inputs, IAEItemStack[] outputs) { + copyStacks(inputs, tile.getCraftingSlots()); + copyStacks(outputs, tile.getOutputSlots()); + } + + private static void copyStacks(IAEItemStack[] src, AeStackInventory dest) { + int bound = Math.min(src.length, dest.getSlotCount()); + for (int i = 0; i < bound; i++) { + dest.setStack(i, src[i]); + } + } + + private static class SlotFluidConvertingFake extends SlotFake implements SlotFluid { + + private final AeStackInventory inv; + + public SlotFluidConvertingFake(AeItemStackHandler inv, int idx, int x, int y) { + super(inv, idx, x, y); + this.inv = inv.getAeInventory(); + } + + @Override + public void putStack(ItemStack stack) { + inv.setStack(getSlotIndex(), AEItemStack.create(stack)); + } + + @Override + public void setAeStack(@Nullable IAEItemStack stack, boolean sync) { + inv.setStack(getSlotIndex(), stack); + } + + public void putConvertedStack(ItemStack stack) { + if (stack == null) { + setAeStack(null, false); + return; + } else if (stack.getItem() instanceof IFluidContainerItem) { + FluidStack fluid = ((IFluidContainerItem) stack.getItem()).getFluid(stack); + if (fluid != null) { + fluid.amount *= stack.stackSize; + IAEItemStack aeStack = ItemFluidPacket.newAeStack(fluid); + if (aeStack != null) { + setAeStack(aeStack, false); + return; + } + } + } else if (FluidContainerRegistry.isContainer(stack)) { + FluidStack fluid = FluidContainerRegistry.getFluidForFilledItem(stack); + if (fluid != null) { + fluid.amount *= stack.stackSize; + IAEItemStack aeStack = ItemFluidPacket.newAeStack(fluid); + if (aeStack != null) { + setAeStack(aeStack, false); + return; + } + } + } + putStack(stack); + } + + @Nullable + @Override + public IAEItemStack getAeStack() { + return inv.getStack(getSlotIndex()); + } + + } + +} diff --git a/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidPatternTerminal.java b/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidPatternTerminal.java new file mode 100644 index 00000000..936c8309 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidPatternTerminal.java @@ -0,0 +1,185 @@ +package com.glodblock.github.client.gui.container; + +import appeng.api.AEApi; +import appeng.api.definitions.IDefinitions; +import appeng.api.storage.ITerminalHost; +import appeng.api.storage.data.IAEItemStack; +import appeng.container.slot.SlotFakeCraftingMatrix; +import appeng.container.slot.SlotPatternOutputs; +import appeng.helpers.InventoryAction; +import appeng.util.item.AEItemStack; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidEncodedPattern; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.inventory.PatternConsumer; +import com.glodblock.github.loader.ItemAndBlockHolder; +import com.glodblock.github.util.FluidPatternDetails; +import com.glodblock.github.util.Util; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidContainerRegistry; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidContainerItem; + +import java.util.ArrayList; +import java.util.List; + +public class ContainerFluidPatternTerminal extends FCBasePartContainer implements PatternConsumer { + + public ContainerFluidPatternTerminal(InventoryPlayer ip, ITerminalHost monitorable) { + super(ip, monitorable); + } + + @Override + public void encode() { + if (!checkHasFluidPattern()) { + super.encode(); + return; + } + ItemStack stack = this.patternSlotOUT.getStack(); + if (stack == null) { + stack = this.patternSlotIN.getStack(); + if (!isPattern(stack)) { + return; + } + if (stack.stackSize == 1) { + this.patternSlotIN.putStack(null); + } else { + stack.stackSize --; + } + encodeFluidPattern(); + } else if (isPattern(stack)) { + encodeFluidPattern(); + } + } + + private static boolean isPattern(final ItemStack output) { + if (output == null) { + return false; + } + if (output.getItem() instanceof ItemFluidEncodedPattern) { + return true; + } + final IDefinitions defs = AEApi.instance().definitions(); + return defs.items().encodedPattern().isSameAs(output) || defs.materials().blankPattern().isSameAs(output); + } + + private boolean checkHasFluidPattern() { + if (this.craftingMode) { + return false; + } + boolean hasFluid = false, search = false; + for (Slot craftingSlot : this.craftingSlots) { + final ItemStack crafting = craftingSlot.getStack(); + if (crafting == null) { + continue; + } + search = true; + if (crafting.getItem() instanceof ItemFluidPacket) { + hasFluid = true; + break; + } + } + if (!search) { // search=false -> inputs were empty + return false; + } + // `search` should be true at this point + for (Slot outputSlot : this.outputSlots) { + final ItemStack out = outputSlot.getStack(); + if (out == null) { + continue; + } + search = false; + if (hasFluid) { + break; + } else if (out.getItem() instanceof ItemFluidPacket) { + hasFluid = true; + break; + } + } + return hasFluid && !search; // search=true -> outputs were empty + } + + private void encodeFluidPattern() { + ItemStack patternStack = new ItemStack(ItemAndBlockHolder.PATTERN); + FluidPatternDetails pattern = new FluidPatternDetails(patternStack); + pattern.setInputs(collectInventory(craftingSlots)); + pattern.setOutputs(collectInventory(outputSlots)); + patternSlotOUT.putStack(pattern.writeToStack()); + } + + private static IAEItemStack[] collectInventory(Slot[] slots) { + // see note at top of FluidPatternDetails + List acc = new ArrayList<>(); + for (Slot slot : slots) { + ItemStack stack = slot.getStack(); + if (stack == null) { + continue; + } + if (stack.getItem() instanceof ItemFluidPacket) { + IAEItemStack dropStack = ItemFluidDrop.newAeStack(ItemFluidPacket.getFluidStack(stack)); + if (dropStack != null) { + acc.add(dropStack); + continue; + } + } + IAEItemStack aeStack = AEItemStack.create(stack); + acc.add(aeStack); + } + return acc.toArray(new IAEItemStack[0]); + } + + @Override + public void acceptPattern(IAEItemStack[] inputs, IAEItemStack[] outputs) { + if (getPatternTerminal() != null) { + getPatternTerminal().onChangeCrafting(inputs, outputs); + } + } + + @Override + public void doAction(EntityPlayerMP player, InventoryAction action, int slotId, long id) { + if (this.isCraftingMode()) { + super.doAction(player, action, slotId, id); + return; + } + if (slotId < 0 || slotId >= this.inventorySlots.size()) { + super.doAction(player, action, slotId, id); + return; + } + Slot slot = getSlot(slotId); + ItemStack stack = player.inventory.getItemStack(); + if ((slot instanceof SlotFakeCraftingMatrix || slot instanceof SlotPatternOutputs) && stack != null + && (stack.getItem() instanceof IFluidContainerItem || FluidContainerRegistry.isContainer(stack))) { + FluidStack fluid = null; + switch (action) { + case PICKUP_OR_SET_DOWN: + fluid = Util.getFluidFromItem(stack); + slot.putStack(ItemFluidPacket.newStack(fluid)); + break; + case SPLIT_OR_PLACE_SINGLE: + fluid = Util.getFluidFromItem(Util.copyStackWithSize(stack, 1)); + FluidStack origin = ItemFluidPacket.getFluidStack(slot.getStack()); + if (fluid != null && fluid.equals(origin)) { + fluid.amount += origin.amount; + if (fluid.amount <= 0) fluid = null; + } + slot.putStack(ItemFluidPacket.newStack(fluid)); + break; + } + if (fluid == null) { + super.doAction(player, action, slotId, id); + return; + } + return; + } + if (action == InventoryAction.SPLIT_OR_PLACE_SINGLE) { + if (stack == null && slot.getStack() != null && slot.getStack().getItem() instanceof ItemFluidPacket) { + return; + } + } + super.doAction(player, action, slotId, id); + } + +} diff --git a/src/main/java/com/glodblock/github/client/gui/container/FCBaseMonitorContain.java b/src/main/java/com/glodblock/github/client/gui/container/FCBaseMonitorContain.java new file mode 100644 index 00000000..27212654 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/container/FCBaseMonitorContain.java @@ -0,0 +1,408 @@ +package com.glodblock.github.client.gui.container; + +import appeng.api.AEApi; +import appeng.api.config.*; +import appeng.api.implementations.guiobjects.IPortableCell; +import appeng.api.implementations.tiles.IMEChest; +import appeng.api.implementations.tiles.IViewCellStorage; +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridHost; +import appeng.api.networking.IGridNode; +import appeng.api.networking.energy.IEnergyGrid; +import appeng.api.networking.energy.IEnergySource; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.storage.IBaseMonitor; +import appeng.api.parts.IPart; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.IMEMonitorHandlerReceiver; +import appeng.api.storage.ITerminalHost; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; +import appeng.api.util.IConfigManager; +import appeng.api.util.IConfigurableObject; +import appeng.container.AEBaseContainer; +import appeng.container.guisync.GuiSync; +import appeng.container.slot.SlotRestrictedInput; +import appeng.core.AELog; +import appeng.core.sync.network.NetworkHandler; +import appeng.core.sync.packets.PacketValueConfig; +import appeng.helpers.WirelessTerminalGuiObject; +import appeng.me.helpers.ChannelPowerSrc; +import appeng.util.ConfigManager; +import appeng.util.IConfigManagerHost; +import appeng.util.Platform; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.network.SPacketMEInventoryUpdate; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.nio.BufferOverflowException; + +public class FCBaseMonitorContain extends AEBaseContainer implements IConfigManagerHost, IConfigurableObject, IMEMonitorHandlerReceiver +{ + + private final SlotRestrictedInput[] cellView = new SlotRestrictedInput[5]; + private final IMEMonitor monitor; + private final IItemList items = AEApi.instance().storage().createItemList(); + private final IConfigManager clientCM; + private final ITerminalHost host; + @GuiSync( 99 ) + public boolean canAccessViewCells = false; + @GuiSync( 98 ) + public boolean hasPower = false; + private IConfigManagerHost gui; + private IConfigManager serverCM; + private IGridNode networkNode; + + public FCBaseMonitorContain(final InventoryPlayer ip, final ITerminalHost monitorable ) + { + this( ip, monitorable, true ); + } + + protected FCBaseMonitorContain( final InventoryPlayer ip, final ITerminalHost monitorable, final boolean bindInventory ) + { + super( ip, monitorable instanceof TileEntity ? (TileEntity) monitorable : null, monitorable instanceof IPart ? (IPart) monitorable : null ); + + this.host = monitorable; + this.clientCM = new ConfigManager( this ); + + this.clientCM.registerSetting( Settings.SORT_BY, SortOrder.NAME ); + this.clientCM.registerSetting( Settings.VIEW_MODE, ViewItems.ALL ); + this.clientCM.registerSetting( Settings.SORT_DIRECTION, SortDir.ASCENDING ); + + if( Platform.isServer() ) + { + this.serverCM = monitorable.getConfigManager(); + + this.monitor = monitorable.getItemInventory(); + if( this.monitor != null ) + { + this.monitor.addListener( this, null ); + + this.setCellInventory( this.monitor ); + + if( monitorable instanceof IPortableCell) + { + this.setPowerSource( (IEnergySource) monitorable ); + } + else if( monitorable instanceof IMEChest) + { + this.setPowerSource( (IEnergySource) monitorable ); + } + else if( monitorable instanceof IGridHost) + { + final IGridNode node = ( (IGridHost) monitorable ).getGridNode( ForgeDirection.UNKNOWN ); + if( node != null ) + { + this.networkNode = node; + final IGrid g = node.getGrid(); + if( g != null ) + { + this.setPowerSource( new ChannelPowerSrc( this.networkNode, (IEnergySource) g.getCache( IEnergyGrid.class ) ) ); + } + } + } + } + else + { + this.setValidContainer( false ); + } + } + else + { + this.monitor = null; + } + + this.canAccessViewCells = false; + if( monitorable instanceof IViewCellStorage) + { + for( int y = 0; y < 5; y++ ) + { + this.cellView[y] = new SlotRestrictedInput( SlotRestrictedInput.PlacableItemType.VIEW_CELL, ( (IViewCellStorage) monitorable ).getViewCellStorage(), y, 206, y * 18 + 8, this.getInventoryPlayer() ); + this.cellView[y].setAllowEdit( this.canAccessViewCells ); + this.addSlotToContainer( this.cellView[y] ); + } + } + + if( bindInventory ) + { + this.bindPlayerInventory( ip, 0, 0 ); + } + } + + public IGridNode getNetworkNode() + { + return this.networkNode; + } + + @Override + public void detectAndSendChanges() + { + if( Platform.isServer() ) + { + if( this.monitor != this.host.getItemInventory() ) + { + this.setValidContainer( false ); + } + + for( final Settings set : this.serverCM.getSettings() ) + { + final Enum sideLocal = this.serverCM.getSetting( set ); + final Enum sideRemote = this.clientCM.getSetting( set ); + + if( sideLocal != sideRemote ) + { + this.clientCM.putSetting( set, sideLocal ); + for( final Object crafter : this.crafters ) + { + try + { + NetworkHandler.instance.sendTo( new PacketValueConfig( set.name(), sideLocal.name() ), (EntityPlayerMP) crafter ); + } + catch( final IOException e ) + { + AELog.debug( e ); + } + } + } + } + + if( !this.items.isEmpty() ) + { + final IItemList monitorCache = this.monitor.getStorageList(); + + final SPacketMEInventoryUpdate piu = new SPacketMEInventoryUpdate(); + + for( final IAEItemStack is : this.items ) + { + final IAEItemStack send = monitorCache.findPrecise( is ); + if( send == null ) + { + is.setStackSize( 0 ); + piu.appendItem( is ); + } + else + { + piu.appendItem( send ); + } + } + + if( !piu.isEmpty() ) + { + this.items.resetStatus(); + + for( final Object c : this.crafters ) + { + if( c instanceof EntityPlayer) + { + FluidCraft.proxy.netHandler.sendTo(piu, (EntityPlayerMP) c); + } + } + } + } + + this.updatePowerStatus(); + + final boolean oldAccessible = this.canAccessViewCells; + this.canAccessViewCells = + this.host instanceof WirelessTerminalGuiObject + || this.hasAccess( SecurityPermissions.BUILD, false ); + if( this.canAccessViewCells != oldAccessible ) + { + for( int y = 0; y < 5; y++ ) + { + if( this.cellView[y] != null ) + { + this.cellView[y].setAllowEdit( this.canAccessViewCells ); + } + } + } + + super.detectAndSendChanges(); + } + } + + protected void updatePowerStatus() + { + try + { + if( this.networkNode != null ) + { + this.setPowered( this.networkNode.isActive() ); + } + else if( this.getPowerSource() instanceof IEnergyGrid ) + { + this.setPowered( ( (IEnergyGrid) this.getPowerSource() ).isNetworkPowered() ); + } + else + { + this.setPowered( this.getPowerSource().extractAEPower( 1, Actionable.SIMULATE, PowerMultiplier.CONFIG ) > 0.8 ); + } + } + catch( final Throwable t ) + { + // :P + } + } + + @Override + public void onUpdate( final String field, final Object oldValue, final Object newValue ) + { + if( field.equals( "canAccessViewCells" ) ) + { + for( int y = 0; y < 5; y++ ) + { + if( this.cellView[y] != null ) + { + this.cellView[y].setAllowEdit( this.canAccessViewCells ); + } + } + } + + super.onUpdate( field, oldValue, newValue ); + } + + @Override + public void addCraftingToCrafters( final ICrafting c ) + { + super.addCraftingToCrafters( c ); + this.queueInventory( c ); + } + + private void queueInventory( final ICrafting c ) + { + if( Platform.isServer() && c instanceof EntityPlayer && this.monitor != null ) + { + SPacketMEInventoryUpdate piu = new SPacketMEInventoryUpdate(); + final IItemList monitorCache = this.monitor.getStorageList(); + + for( final IAEItemStack send : monitorCache ) + { + try + { + piu.appendItem( send ); + } + catch( final BufferOverflowException boe ) + { + FluidCraft.proxy.netHandler.sendTo( piu, (EntityPlayerMP) c ); + + piu = new SPacketMEInventoryUpdate(); + piu.appendItem( send ); + } + } + FluidCraft.proxy.netHandler.sendTo( piu, (EntityPlayerMP) c ); + } + } + + @Override + public void removeCraftingFromCrafters( final ICrafting c ) + { + super.removeCraftingFromCrafters( c ); + + if( this.crafters.isEmpty() && this.monitor != null ) + { + this.monitor.removeListener( this ); + } + } + + @Override + public void onContainerClosed( final EntityPlayer player ) + { + super.onContainerClosed( player ); + if( this.monitor != null ) + { + this.monitor.removeListener( this ); + } + } + + @Override + public boolean isValid( final Object verificationToken ) + { + return true; + } + + @Override + public void postChange(final IBaseMonitor monitor, final Iterable change, final BaseActionSource source ) + { + for( final IAEItemStack is : change ) + { + this.items.add( is ); + } + } + + @Override + public void onListUpdate() + { + for( final Object c : this.crafters ) + { + if( c instanceof ICrafting ) + { + final ICrafting cr = (ICrafting) c; + this.queueInventory( cr ); + } + } + } + + @Override + public void updateSetting( final IConfigManager manager, final Enum settingName, final Enum newValue ) + { + if( this.getGui() != null ) + { + this.getGui().updateSetting( manager, settingName, newValue ); + } + } + + @Override + public IConfigManager getConfigManager() + { + if( Platform.isServer() ) + { + return this.serverCM; + } + return this.clientCM; + } + + public ItemStack[] getViewCells() + { + final ItemStack[] list = new ItemStack[this.cellView.length]; + + for( int x = 0; x < this.cellView.length; x++ ) + { + list[x] = this.cellView[x].getStack(); + } + + return list; + } + + public SlotRestrictedInput getCellViewSlot( final int index ) + { + return this.cellView[index]; + } + + public boolean isPowered() + { + return this.hasPower; + } + + private void setPowered( final boolean isPowered ) + { + this.hasPower = isPowered; + } + + private IConfigManagerHost getGui() + { + return this.gui; + } + + public void setGui( @Nonnull final IConfigManagerHost gui ) + { + this.gui = gui; + } +} diff --git a/src/main/java/com/glodblock/github/client/gui/container/FCBasePartContainer.java b/src/main/java/com/glodblock/github/client/gui/container/FCBasePartContainer.java new file mode 100644 index 00000000..320088fd --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/container/FCBasePartContainer.java @@ -0,0 +1,625 @@ +package com.glodblock.github.client.gui.container; + +import appeng.api.AEApi; +import appeng.api.config.Actionable; +import appeng.api.definitions.IDefinitions; +import appeng.api.networking.security.MachineSource; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.ITerminalHost; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; +import appeng.container.ContainerNull; +import appeng.container.guisync.GuiSync; +import appeng.container.slot.*; +import appeng.core.sync.packets.PacketPatternSlot; +import appeng.helpers.IContainerCraftingPacket; +import appeng.items.storage.ItemViewCell; +import appeng.tile.inventory.AppEngInternalInventory; +import appeng.tile.inventory.IAEAppEngInventory; +import appeng.tile.inventory.InvOperation; +import appeng.util.InventoryAdaptor; +import appeng.util.Platform; +import appeng.util.inv.AdaptorPlayerHand; +import appeng.util.item.AEItemStack; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.common.parts.PartFluidPatternTerminal; +import com.glodblock.github.util.Util; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.*; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +public class FCBasePartContainer extends FCBaseMonitorContain implements IAEAppEngInventory, IOptionalSlotHost, IContainerCraftingPacket { + + private final PartFluidPatternTerminal patternTerminal; + private final AppEngInternalInventory cOut = new AppEngInternalInventory( null, 1 ); + private final IInventory crafting; + protected final SlotFakeCraftingMatrix[] craftingSlots = new SlotFakeCraftingMatrix[9]; + protected final OptionalSlotFake[] outputSlots = new OptionalSlotFake[3]; + protected final SlotPatternTerm craftSlot; + protected final SlotRestrictedInput patternSlotIN; + protected final SlotRestrictedInput patternSlotOUT; + @GuiSync( 97 ) + public boolean craftingMode = true; + @GuiSync( 96 ) + public boolean substitute = false; + + public FCBasePartContainer(final InventoryPlayer ip, final ITerminalHost monitorable ) + { + super( ip, monitorable, false ); + this.patternTerminal = (PartFluidPatternTerminal) monitorable; + + final IInventory patternInv = this.getPatternTerminal().getInventoryByName( "pattern" ); + final IInventory output = this.getPatternTerminal().getInventoryByName( "output" ); + + this.crafting = this.getPatternTerminal().getInventoryByName( "crafting" ); + + for( int y = 0; y < 3; y++ ) + { + for( int x = 0; x < 3; x++ ) + { + this.addSlotToContainer( this.craftingSlots[x + y * 3] = new SlotFakeCraftingMatrix( this.crafting, x + y * 3, 18 + x * 18, -76 + y * 18 ) ); + } + } + + this.addSlotToContainer( this.craftSlot = new SlotPatternTerm( ip.player, this.getActionSource(), this.getPowerSource(), monitorable, this.crafting, patternInv, this.cOut, 110, -76 + 18, this, 2, this ) ); + this.craftSlot.setIIcon( -1 ); + + for( int y = 0; y < 3; y++ ) + { + this.addSlotToContainer( this.outputSlots[y] = new SlotPatternOutputs( output, this, y, 110, -76 + y * 18, 0, 0, 1 ) ); + this.outputSlots[y].setRenderDisabled( false ); + } + + this.addSlotToContainer( this.patternSlotIN = new SlotRestrictedInput( SlotRestrictedInput.PlacableItemType.BLANK_PATTERN, patternInv, 0, 147, -72 - 9, this.getInventoryPlayer() ) ); + this.addSlotToContainer( this.patternSlotOUT = new SlotRestrictedInput( SlotRestrictedInput.PlacableItemType.ENCODED_PATTERN, patternInv, 1, 147, -72 + 34, this.getInventoryPlayer() ) ); + + this.patternSlotOUT.setStackLimit( 1 ); + + this.bindPlayerInventory( ip, 0, 0 ); + this.updateOrderOfOutputSlots(); + } + + private void updateOrderOfOutputSlots() + { + if( !this.isCraftingMode() ) + { + this.craftSlot.xDisplayPosition = -9000; + + for( int y = 0; y < 3; y++ ) + { + this.outputSlots[y].xDisplayPosition = this.outputSlots[y].getX(); + } + } + else + { + this.craftSlot.xDisplayPosition = this.craftSlot.getX(); + + for( int y = 0; y < 3; y++ ) + { + this.outputSlots[y].xDisplayPosition = -9000; + } + } + } + + @Override + public void putStackInSlot( final int par1, final ItemStack par2ItemStack ) + { + super.putStackInSlot( par1, par2ItemStack ); + this.getAndUpdateOutput(); + } + + @Override + public void putStacksInSlots( final ItemStack[] par1ArrayOfItemStack ) + { + super.putStacksInSlots( par1ArrayOfItemStack ); + this.getAndUpdateOutput(); + } + + private ItemStack getAndUpdateOutput() + { + final InventoryCrafting ic = new InventoryCrafting( this, 3, 3 ); + + for( int x = 0; x < ic.getSizeInventory(); x++ ) + { + ic.setInventorySlotContents( x, this.crafting.getStackInSlot( x ) ); + } + + final ItemStack is = CraftingManager.getInstance().findMatchingRecipe( ic, this.getPlayerInv().player.worldObj ); + this.cOut.setInventorySlotContents( 0, is ); + return is; + } + + @Override + public void saveChanges() + { + + } + + @Override + public void onChangeInventory(final IInventory inv, final int slot, final InvOperation mc, final ItemStack removedStack, final ItemStack newStack ) + { + + } + + public void encodeAndMoveToInventory() + { + encode(); + ItemStack output = this.patternSlotOUT.getStack(); + if ( output != null ) + { + if (!getPlayerInv().addItemStackToInventory( output )){ + getPlayerInv().player.entityDropItem(output, 0); + } + this.patternSlotOUT.putStack( null ); + } + } + + public void encode() + { + ItemStack output = this.patternSlotOUT.getStack(); + + final ItemStack[] in = this.getInputs(); + final ItemStack[] out = this.getOutputs(); + + // if there is no input, this would be silly. + if( in == null || out == null ) + { + return; + } + + // first check the output slots, should either be null, or a pattern + if( output != null && !this.isPattern( output ) ) + { + return; + }// if nothing is there we should snag a new pattern. + else if( output == null ) + { + output = this.patternSlotIN.getStack(); + if (!this.isPattern( output )) + { + return; // no blanks. + } + + // remove one, and clear the input slot. + output.stackSize--; + if( output.stackSize == 0 ) + { + this.patternSlotIN.putStack( null ); + } + + // add a new encoded pattern. + for( final ItemStack encodedPatternStack : AEApi.instance().definitions().items().encodedPattern().maybeStack( 1 ).asSet() ) + { + output = encodedPatternStack; + this.patternSlotOUT.putStack( output ); + } + } + + // encode the slot. + final NBTTagCompound encodedValue = new NBTTagCompound(); + + final NBTTagList tagIn = new NBTTagList(); + final NBTTagList tagOut = new NBTTagList(); + + for( final ItemStack i : in ) + { + tagIn.appendTag( this.createItemTag( i ) ); + } + + for( final ItemStack i : out ) + { + tagOut.appendTag( this.createItemTag( i ) ); + } + + encodedValue.setTag( "in", tagIn ); + encodedValue.setTag( "out", tagOut ); + encodedValue.setBoolean( "crafting", this.isCraftingMode() ); + encodedValue.setBoolean( "substitute", this.isSubstitute() ); + + output.setTagCompound( encodedValue ); + } + + private ItemStack[] getInputs() + { + final ItemStack[] input = new ItemStack[9]; + boolean hasValue = false; + + for( int x = 0; x < this.craftingSlots.length; x++ ) + { + input[x] = this.craftingSlots[x].getStack(); + if( input[x] != null ) + { + hasValue = true; + } + } + + if( hasValue ) + { + return input; + } + + return null; + } + + private ItemStack[] getOutputs() + { + if( this.isCraftingMode() ) + { + final ItemStack out = this.getAndUpdateOutput(); + + if( out != null && out.stackSize > 0 ) + { + return new ItemStack[] { out }; + } + } + else + { + final List list = new ArrayList<>( 3 ); + boolean hasValue = false; + + for( final OptionalSlotFake outputSlot : this.outputSlots ) + { + final ItemStack out = outputSlot.getStack(); + + if( out != null && out.stackSize > 0 ) + { + list.add( out ); + hasValue = true; + } + } + + if( hasValue ) + { + return list.toArray( new ItemStack[list.size()] ); + } + } + + return null; + } + + private boolean isPattern( final ItemStack output ) + { + if( output == null ) + { + return false; + } + + final IDefinitions definitions = AEApi.instance().definitions(); + + boolean isPattern = definitions.items().encodedPattern().isSameAs( output ); + isPattern |= definitions.materials().blankPattern().isSameAs( output ); + + return isPattern; + } + + private NBTBase createItemTag(final ItemStack i ) + { + final NBTTagCompound c = new NBTTagCompound(); + + if( i != null ) + { + i.writeToNBT( c ); + } + + return c; + } + + @Override + public boolean isSlotEnabled( final int idx ) + { + if( idx == 1 ) + { + return Platform.isServer() ? !this.getPatternTerminal().isCraftingRecipe() : !this.isCraftingMode(); + } + else if( idx == 2 ) + { + return Platform.isServer() ? this.getPatternTerminal().isCraftingRecipe() : this.isCraftingMode(); + } + else + { + return false; + } + } + + public void craftOrGetItem( final PacketPatternSlot packetPatternSlot ) + { + if( packetPatternSlot.slotItem != null && this.getCellInventory() != null ) + { + final IAEItemStack out = packetPatternSlot.slotItem.copy(); + InventoryAdaptor inv = new AdaptorPlayerHand( this.getPlayerInv().player ); + final InventoryAdaptor playerInv = InventoryAdaptor.getAdaptor( this.getPlayerInv().player, ForgeDirection.UNKNOWN ); + + if( packetPatternSlot.shift ) + { + inv = playerInv; + } + + if( inv.simulateAdd( out.getItemStack() ) != null ) + { + return; + } + + final IAEItemStack extracted = Platform.poweredExtraction( this.getPowerSource(), this.getCellInventory(), out, this.getActionSource() ); + final EntityPlayer p = this.getPlayerInv().player; + + if( extracted != null ) + { + inv.addItems( extracted.getItemStack() ); + if( p instanceof EntityPlayerMP) + { + this.updateHeld( (EntityPlayerMP) p ); + } + this.detectAndSendChanges(); + return; + } + + final InventoryCrafting ic = new InventoryCrafting( new ContainerNull(), 3, 3 ); + final InventoryCrafting real = new InventoryCrafting( new ContainerNull(), 3, 3 ); + + for( int x = 0; x < 9; x++ ) + { + ic.setInventorySlotContents( x, packetPatternSlot.pattern[x] == null ? null : packetPatternSlot.pattern[x].getItemStack() ); + } + + final IRecipe r = Platform.findMatchingRecipe( ic, p.worldObj ); + + if( r == null ) + { + return; + } + + final IMEMonitor storage = this.getPatternTerminal().getItemInventory(); + final IItemList all = storage.getStorageList(); + + final ItemStack is = r.getCraftingResult( ic ); + + for( int x = 0; x < ic.getSizeInventory(); x++ ) + { + if( ic.getStackInSlot( x ) != null ) + { + final ItemStack pulled = Platform.extractItemsByRecipe( this.getPowerSource(), this.getActionSource(), storage, p.worldObj, r, is, ic, ic.getStackInSlot( x ), x, all, Actionable.MODULATE, ItemViewCell.createFilter( this.getViewCells() ) ); + real.setInventorySlotContents( x, pulled ); + } + } + + final IRecipe rr = Platform.findMatchingRecipe( real, p.worldObj ); + + if( rr == r && Platform.isSameItemPrecise( rr.getCraftingResult( real ), is ) ) + { + final SlotCrafting sc = new SlotCrafting( p, real, this.cOut, 0, 0, 0 ); + sc.onPickupFromSlot( p, is ); + + for( int x = 0; x < real.getSizeInventory(); x++ ) + { + final ItemStack failed = playerInv.addItems( real.getStackInSlot( x ) ); + + if( failed != null ) + { + p.dropPlayerItemWithRandomChoice( failed, false ); + } + } + + inv.addItems( is ); + if( p instanceof EntityPlayerMP ) + { + this.updateHeld( (EntityPlayerMP) p ); + } + this.detectAndSendChanges(); + } + else + { + for( int x = 0; x < real.getSizeInventory(); x++ ) + { + final ItemStack failed = real.getStackInSlot( x ); + if( failed != null ) + { + this.getCellInventory().injectItems( AEItemStack.create( failed ), Actionable.MODULATE, new MachineSource( this.getPatternTerminal() ) ); + } + } + } + } + } + + @Override + public void detectAndSendChanges() + { + super.detectAndSendChanges(); + if( Platform.isServer() ) + { + if( this.isCraftingMode() != this.getPatternTerminal().isCraftingRecipe() ) + { + this.setCraftingMode( this.getPatternTerminal().isCraftingRecipe() ); + this.updateOrderOfOutputSlots(); + } + + this.substitute = this.patternTerminal.isSubstitution(); + } + } + + @Override + public void onUpdate( final String field, final Object oldValue, final Object newValue ) + { + super.onUpdate( field, oldValue, newValue ); + + if( field.equals( "craftingMode" ) ) + { + this.getAndUpdateOutput(); + this.updateOrderOfOutputSlots(); + } + } + + @Override + public void onSlotChange( final Slot s ) + { + if( s == this.patternSlotOUT && Platform.isServer() ) + { + for( final Object crafter : this.crafters ) + { + final ICrafting icrafting = (ICrafting) crafter; + + for( final Object g : this.inventorySlots ) + { + if( g instanceof OptionalSlotFake || g instanceof SlotFakeCraftingMatrix ) + { + final Slot sri = (Slot) g; + icrafting.sendSlotContents( this, sri.slotNumber, sri.getStack() ); + } + } + ( (EntityPlayerMP) icrafting ).isChangingQuantityOnly = false; + } + this.detectAndSendChanges(); + } + } + + public void clear() + { + for( final Slot s : this.craftingSlots ) + { + s.putStack( null ); + } + + for( final Slot s : this.outputSlots ) + { + s.putStack( null ); + } + + this.detectAndSendChanges(); + this.getAndUpdateOutput(); + } + + @Override + public IInventory getInventoryByName( final String name ) + { + if( name.equals( "player" ) ) + { + return this.getInventoryPlayer(); + } + return this.getPatternTerminal().getInventoryByName( name ); + } + + @Override + public boolean useRealItems() + { + return false; + } + + public void toggleSubstitute() + { + this.substitute = !this.substitute; + + this.detectAndSendChanges(); + this.getAndUpdateOutput(); + } + + public boolean isCraftingMode() + { + return this.craftingMode; + } + + private void setCraftingMode( final boolean craftingMode ) + { + this.craftingMode = craftingMode; + } + + public PartFluidPatternTerminal getPatternTerminal() + { + return this.patternTerminal; + } + + private boolean isSubstitute() + { + return this.substitute; + } + + public void setSubstitute( final boolean substitute ) + { + this.substitute = substitute; + } + + static boolean canDoubleStacks(SlotFake[] slots) + { + List enabledSlots = Arrays.stream(slots).filter(SlotFake::isEnabled).collect(Collectors.toList()); + long emptyStots = enabledSlots.stream().filter(s -> s.getStack() == null).count(); + long fullSlots = enabledSlots.stream().filter(s-> s.getStack() != null && s.getStack().stackSize * 2 > 127).count(); + return fullSlots <= emptyStots; + } + + static void doubleStacksInternal(SlotFake[] slots) + { + List overFlowStacks = new ArrayList<>(); + List enabledSlots = Arrays.stream(slots).filter(SlotFake::isEnabled).collect(Collectors.toList()); + for (final Slot s : enabledSlots) + { + ItemStack st = s.getStack(); + if (st == null) + continue; + if (Util.isFluidPacket(st)) { + FluidStack fluidStack = ItemFluidPacket.getFluidStack(st); + if (fluidStack != null) { + fluidStack = ItemFluidPacket.getFluidStack(st).copy(); + if (fluidStack.amount < Integer.MAX_VALUE / 2) + fluidStack.amount *= 2; + } + s.putStack(ItemFluidPacket.newStack(fluidStack)); + } + else if (st.stackSize * 2 > 127) + { + overFlowStacks.add(st.copy()); + } + else + { + st.stackSize *= 2; + s.putStack(st); + } + } + Iterator ow = overFlowStacks.iterator(); + for (final Slot s : enabledSlots) { + if (!ow.hasNext()) + break; + if (s.getStack() != null) + continue; + s.putStack(ow.next()); + } + assert !ow.hasNext(); + } + + public void doubleStacks(boolean isShift) + { + if (!isCraftingMode() && canDoubleStacks(craftingSlots) && canDoubleStacks(outputSlots)) + { + doubleStacksInternal(this.craftingSlots); + doubleStacksInternal(this.outputSlots); + if (isShift && !containsFluid(outputSlots) && !containsFluid(craftingSlots)) + { + while (canDoubleStacks(craftingSlots) && canDoubleStacks(outputSlots)) + { + doubleStacksInternal(this.craftingSlots); + doubleStacksInternal(this.outputSlots); + } + } + this.detectAndSendChanges(); + } + } + + static boolean containsFluid(SlotFake[] slots) { + List enabledSlots = Arrays.stream(slots).filter(SlotFake::isEnabled).collect(Collectors.toList()); + long fluid = enabledSlots.stream().filter(s -> Util.isFluidPacket(s.getStack())).count(); + return fluid > 0; + } + +} diff --git a/src/main/java/com/glodblock/github/client/render/ItemDropRender.java b/src/main/java/com/glodblock/github/client/render/ItemDropRender.java new file mode 100644 index 00000000..fe4173f4 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/render/ItemDropRender.java @@ -0,0 +1,109 @@ +package com.glodblock.github.client.render; + +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.loader.ItemAndBlockHolder; +import com.glodblock.github.util.RenderUtil; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraftforge.client.IItemRenderer; +import net.minecraftforge.client.MinecraftForgeClient; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import org.lwjgl.opengl.GL11; + +import java.util.HashMap; +import java.util.Map; + +@SideOnly(Side.CLIENT) +public class ItemDropRender implements IItemRenderer { + + private final Map colourCache = new HashMap<>(); + + public ItemDropRender() { + MinecraftForgeClient.registerItemRenderer(ItemAndBlockHolder.DROP, this); + } + + @Override + public boolean handleRenderType(ItemStack item, ItemRenderType type) { + return type != ItemRenderType.FIRST_PERSON_MAP; + } + + @Override + public boolean shouldUseRenderHelper(ItemRenderType type, ItemStack item, ItemRendererHelper helper) { + return type == ItemRenderType.ENTITY; + } + + @Override + public void renderItem(ItemRenderType type, ItemStack item, Object... data) { + IIcon shape = ItemAndBlockHolder.DROP.shape; + GL11.glEnable(GL11.GL_BLEND); + GL11.glEnable(GL11.GL_ALPHA_TEST); + if (type.equals(ItemRenderType.ENTITY)) { + GL11.glRotated(90.0D, 0.0D, 1.0D, 0.0D); + GL11.glTranslated(-0.5D, -0.6D, 0.0D); + } + + Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.locationItemsTexture); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + FluidStack fluid = ItemFluidDrop.getFluidStack(item); + if (fluid != null) { + int RGB = getColour(fluid); + GL11.glColor3f((RGB >> 16 & 0xFF) / 255.0F, (RGB >> 8 & 0xFF) / 255.0F, (RGB & 0xFF) / 255.0F); + } + + if (type.equals(ItemRenderType.INVENTORY)) { + RenderUtil.renderItemIcon(shape, 16.0D, 0.001D, 0.0F, 0.0F, -1.0F); + } else { + ItemRenderer.renderItemIn2D(Tessellator.instance, shape.getMaxU(), shape.getMinV(), shape.getMinU(), shape.getMaxV(), shape.getIconWidth(), shape.getIconHeight(), 0.0625F); + } + + GL11.glDisable(GL11.GL_ALPHA_TEST); + GL11.glDisable(GL11.GL_BLEND); + } + + public int getColour(FluidStack fluidStack) { + Fluid fluid = fluidStack.getFluid(); + int colour = fluid.getColor(fluidStack); + return colour != 0xFFFFFF ? colour : getColour(fluid); + } + + public int getColour(Fluid fluid) { + Integer cached = colourCache.get(fluid.getName()); + if (cached != null) { + return cached; + } + int colour = fluid.getColor(); + if (colour == 0xFFFFFF) { + TextureAtlasSprite sprite = Minecraft.getMinecraft().getTextureMapBlocks() + .getTextureExtry(fluid.getStillIcon().getIconName()); + if (sprite != null && sprite.getFrameCount() > 0) { + int[][] image = sprite.getFrameTextureData(0); + int r = 0, g = 0, b = 0, count = 0; + for (int[] row : image) { + for (int pixel : row) { + if (((pixel >> 24) & 0xFF) > 127) { // is alpha above 50%? + r += (pixel >> 16) & 0xFF; + g += (pixel >> 8) & 0xFF; + b += pixel & 0xFF; + ++count; + } + } + } + if (count > 0) { + // probably shouldn't need to mask each component by 0xFF + colour = ((r / count) << 16) | ((g / count) << 8) | (b / count); + } + } + } + colourCache.put(fluid.getName(), colour); + return colour; + } +} diff --git a/src/main/java/com/glodblock/github/client/render/ItemPacketRender.java b/src/main/java/com/glodblock/github/client/render/ItemPacketRender.java new file mode 100644 index 00000000..fbec4a86 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/render/ItemPacketRender.java @@ -0,0 +1,75 @@ +package com.glodblock.github.client.render; + +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.loader.ItemAndBlockHolder; +import com.glodblock.github.util.RenderUtil; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraftforge.client.IItemRenderer; +import net.minecraftforge.client.MinecraftForgeClient; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; +import org.lwjgl.opengl.GL11; + +@SideOnly(Side.CLIENT) +public class ItemPacketRender implements IItemRenderer { + + public ItemPacketRender() { + MinecraftForgeClient.registerItemRenderer(ItemAndBlockHolder.PACKET, this); + } + + @Override + public boolean handleRenderType(ItemStack item, ItemRenderType type) { + return type == ItemRenderType.INVENTORY; + } + + @Override + public boolean shouldUseRenderHelper(ItemRenderType type, ItemStack item, ItemRendererHelper helper) { + return false; + } + + @Override + public void renderItem(ItemRenderType type, ItemStack item, Object... data) { + if (item == null || item.getItem() == null || !(item.getItem() instanceof ItemFluidPacket)) + return; + + GL11.glEnable(GL11.GL_BLEND); + GL11.glEnable(GL11.GL_ALPHA_TEST); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + FluidStack fluid = ItemFluidPacket.getFluidStack(item); + int RGB = 0xFFFFFF; + if (fluid != null) { + RGB = fluid.getFluid().getColor(fluid); + } + IIcon icon = fluid == null ? FluidRegistry.WATER.getStillIcon() : fluid.getFluid().getStillIcon(); + + if (RGB != 0xFFFFFF) { + GL11.glColor3f((RGB >> 16 & 0xFF) / 255.0F, (RGB >> 8 & 0xFF) / 255.0F, (RGB & 0xFF) / 255.0F); + } + + Tessellator tess = Tessellator.instance; + tess.startDrawingQuads(); + // draw a simple rectangle for the inventory icon + final float x_min = icon.getMinU(); + final float x_max = icon.getMaxU(); + final float y_min = icon.getMinV(); + final float y_max = icon.getMaxV(); + tess.addVertexWithUV( 0, 16, 0, x_min, y_max); + tess.addVertexWithUV(16, 16, 0, x_max, y_max); + tess.addVertexWithUV(16, 0, 0, x_max, y_min); + tess.addVertexWithUV( 0, 0, 0, x_min, y_min); + tess.draw(); + + GL11.glDisable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_ALPHA_TEST); + } + +} diff --git a/src/main/java/com/glodblock/github/client/render/RenderBlockFluidInterface.java b/src/main/java/com/glodblock/github/client/render/RenderBlockFluidInterface.java new file mode 100644 index 00000000..d99d1020 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/render/RenderBlockFluidInterface.java @@ -0,0 +1,41 @@ +package com.glodblock.github.client.render; + +import appeng.client.render.BaseBlockRender; +import appeng.client.render.BlockRenderInfo; +import appeng.client.texture.ExtraBlockTextures; +import appeng.tile.misc.TileInterface; +import com.glodblock.github.client.textures.FCPartsTexture; +import com.glodblock.github.common.block.BlockFluidInterface; +import com.glodblock.github.common.tile.TileFluidInterface; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.common.util.ForgeDirection; + +public class RenderBlockFluidInterface extends BaseBlockRender +{ + + public RenderBlockFluidInterface() + { + super( false, 20 ); + } + + @Override + public boolean renderInWorld(final BlockFluidInterface block, final IBlockAccess world, final int x, final int y, final int z, final RenderBlocks renderer ) + { + final TileInterface ti = block.getTileEntity( world, x, y, z ); + final BlockRenderInfo info = block.getRendererInstance(); + + if( ti != null && ti.getForward() != ForgeDirection.UNKNOWN ) + { + final IIcon side = FCPartsTexture.BlockFluidInterfaceAlternate_Arrow.getIcon(); + info.setTemporaryRenderIcons( FCPartsTexture.BlockInterfaceAlternate.getIcon(), block.getIcon( 0, 0 ), side, side, side, side ); + } + + final boolean fz = super.renderInWorld( block, world, x, y, z, renderer ); + + info.setTemporaryRenderIcon( null ); + + return fz; + } +} diff --git a/src/main/java/com/glodblock/github/client/textures/FCPartsTexture.java b/src/main/java/com/glodblock/github/client/textures/FCPartsTexture.java new file mode 100644 index 00000000..b65c06d1 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/textures/FCPartsTexture.java @@ -0,0 +1,50 @@ +package com.glodblock.github.client.textures; + +import com.glodblock.github.util.NameConst; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.util.IIcon; +import net.minecraft.util.ResourceLocation; + +public enum FCPartsTexture { + + PartFluidPatternTerminal_Bright("pattern_terminal_bright"), PartFluidPatternTerminal_Dark("pattern_terminal_dark"), + PartFluidPatternTerminal_Colored("pattern_terminal_medium"), PartTerminalBroad("terminal_broad"), + BlockFluidInterfaceAlternate_Arrow("fluid_interface_arrow"), BlockInterfaceAlternate("fluid_interface_a"); + + private final String name; + public net.minecraft.util.IIcon IIcon; + + FCPartsTexture( final String name ) + { + this.name = name; + } + + public static ResourceLocation GuiTexture(final String string) + { + return null; + } + + @SideOnly( Side.CLIENT ) + public static IIcon getMissing() + { + return ( (TextureMap) Minecraft.getMinecraft().getTextureManager().getTexture( TextureMap.locationBlocksTexture ) ).getAtlasSprite( "missingno" ); + } + + public String getName() + { + return this.name; + } + + public IIcon getIcon() + { + return this.IIcon; + } + + public void registerIcon( final TextureMap map ) + { + this.IIcon = map.registerIcon( NameConst.RES_KEY + this.name ); + } +} diff --git a/src/main/java/com/glodblock/github/common/block/BlockFluidDiscretizer.java b/src/main/java/com/glodblock/github/common/block/BlockFluidDiscretizer.java new file mode 100644 index 00000000..d20deb7e --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/BlockFluidDiscretizer.java @@ -0,0 +1,24 @@ +package com.glodblock.github.common.block; + +import appeng.block.AEBaseItemBlock; +import com.glodblock.github.common.tile.TileFluidDiscretizer; +import com.glodblock.github.util.NameConst; +import cpw.mods.fml.common.registry.GameRegistry; +import net.minecraft.block.material.Material; + +public class BlockFluidDiscretizer extends FCBaseBlock { + + public BlockFluidDiscretizer() { + super(Material.iron, NameConst.BLOCK_FLUID_DISCRETIZER); + setFullBlock(true); + setOpaque(true); + setTileEntity(TileFluidDiscretizer.class); + } + + public BlockFluidDiscretizer register() { + GameRegistry.registerBlock(this, AEBaseItemBlock.class, NameConst.BLOCK_FLUID_DISCRETIZER); + GameRegistry.registerTileEntity(TileFluidDiscretizer.class, NameConst.BLOCK_FLUID_DISCRETIZER); + return this; + } + +} diff --git a/src/main/java/com/glodblock/github/common/block/BlockFluidInterface.java b/src/main/java/com/glodblock/github/common/block/BlockFluidInterface.java new file mode 100644 index 00000000..e342b966 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/BlockFluidInterface.java @@ -0,0 +1,81 @@ +package com.glodblock.github.common.block; + +import appeng.api.util.IOrientable; +import appeng.block.AEBaseItemBlock; +import appeng.core.features.AEFeature; +import appeng.core.sync.GuiBridge; +import appeng.tile.misc.TileInterface; +import appeng.util.Platform; +import com.glodblock.github.client.render.RenderBlockFluidInterface; +import com.glodblock.github.common.tile.TileFluidInterface; +import com.glodblock.github.util.NameConst; +import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.block.material.Material; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import java.util.EnumSet; + +public class BlockFluidInterface extends FCBaseBlock { + + public BlockFluidInterface() { + super(Material.iron, NameConst.BLOCK_FLUID_INTERFACE); + setFullBlock(true); + setOpaque(true); + setTileEntity(TileFluidInterface.class); + setFeature( EnumSet.of( AEFeature.Core ) ); + } + + @Override + @SideOnly( Side.CLIENT ) + protected RenderBlockFluidInterface getRenderer() + { + return new RenderBlockFluidInterface(); + } + + @Override + public boolean onActivated(final World w, final int x, final int y, final int z, final EntityPlayer p, final int side, final float hitX, final float hitY, final float hitZ ) + { + if( p.isSneaking() ) + { + return false; + } + + final TileInterface tg = this.getTileEntity( w, x, y, z ); + if( tg != null ) + { + if( Platform.isServer() ) + { + Platform.openGUI( p, tg, ForgeDirection.getOrientation( side ), GuiBridge.GUI_INTERFACE ); + } + return true; + } + return false; + } + + @Override + protected boolean hasCustomRotation() + { + return true; + } + + @Override + protected void customRotateBlock(final IOrientable rotatable, final ForgeDirection axis ) + { + if( rotatable instanceof TileInterface ) + { + ( (TileInterface) rotatable ).setSide( axis ); + } + } + + public BlockFluidInterface register() { + GameRegistry.registerBlock(this, AEBaseItemBlock.class, NameConst.BLOCK_FLUID_INTERFACE); + GameRegistry.registerTileEntity(TileFluidInterface.class, NameConst.BLOCK_FLUID_INTERFACE); + return this; + } + + +} diff --git a/src/main/java/com/glodblock/github/common/block/BlockFluidPacketDecoder.java b/src/main/java/com/glodblock/github/common/block/BlockFluidPacketDecoder.java new file mode 100644 index 00000000..bea0ee3a --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/BlockFluidPacketDecoder.java @@ -0,0 +1,45 @@ +package com.glodblock.github.common.block; + +import appeng.block.AEBaseItemBlock; +import com.glodblock.github.common.tile.TileFluidPacketDecoder; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.util.BlockPos; +import com.glodblock.github.util.NameConst; +import cpw.mods.fml.common.registry.GameRegistry; +import net.minecraft.block.material.Material; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; + +public class BlockFluidPacketDecoder extends FCBaseBlock { + + public BlockFluidPacketDecoder() { + super(Material.iron, NameConst.BLOCK_FLUID_PACKET_DECODER); + setFullBlock(true); + setOpaque(true); + setTileEntity(TileFluidPacketDecoder.class); + } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int facing, float hitX, float hitY, float hitZ) { + if (player.isSneaking()) { + return false; + } + TileFluidPacketDecoder tile = getTileEntity(world, x, y, z); + if (tile != null) { + if (!world.isRemote) { + InventoryHandler.openGui(player, world, new BlockPos(x, y, z), EnumFacing.getFront(facing), GuiType.FLUID_PACKET_DECODER); + } + return true; + } + return false; + } + + public BlockFluidPacketDecoder register() { + GameRegistry.registerBlock(this, AEBaseItemBlock.class, NameConst.BLOCK_FLUID_PACKET_DECODER); + GameRegistry.registerTileEntity(TileFluidPacketDecoder.class, NameConst.BLOCK_FLUID_PACKET_DECODER); + return this; + } + +} diff --git a/src/main/java/com/glodblock/github/common/block/BlockFluidPatternEncoder.java b/src/main/java/com/glodblock/github/common/block/BlockFluidPatternEncoder.java new file mode 100644 index 00000000..2790b504 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/BlockFluidPatternEncoder.java @@ -0,0 +1,46 @@ +package com.glodblock.github.common.block; + +import appeng.block.AEBaseItemBlock; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.common.tile.TileFluidPatternEncoder; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.util.BlockPos; +import com.glodblock.github.util.NameConst; +import cpw.mods.fml.common.registry.GameRegistry; +import net.minecraft.block.material.Material; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; + +public class BlockFluidPatternEncoder extends FCBaseBlock { + + public BlockFluidPatternEncoder() { + super(Material.iron, NameConst.BLOCK_FLUID_PATTERN_ENCODER); + setFullBlock(true); + setOpaque(true); + setTileEntity(TileFluidPatternEncoder.class); + } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int facing, float hitX, float hitY, float hitZ) { + if (player.isSneaking()) { + return false; + } + TileFluidPatternEncoder tile = getTileEntity(world, x, y, z); + if (tile != null) { + if (!world.isRemote) { + InventoryHandler.openGui(player, world, new BlockPos(x, y, z), EnumFacing.getFront(facing), GuiType.FLUID_PATTERN_ENCODER); + } + return true; + } + return false; + } + + public BlockFluidPatternEncoder register() { + GameRegistry.registerBlock(this, AEBaseItemBlock.class, NameConst.BLOCK_FLUID_PATTERN_ENCODER); + GameRegistry.registerTileEntity(TileFluidPatternEncoder.class, NameConst.BLOCK_FLUID_PATTERN_ENCODER); + return this; + } + +} diff --git a/src/main/java/com/glodblock/github/common/block/FCBaseBlock.java b/src/main/java/com/glodblock/github/common/block/FCBaseBlock.java new file mode 100644 index 00000000..01805e37 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/FCBaseBlock.java @@ -0,0 +1,37 @@ +package com.glodblock.github.common.block; + +import appeng.block.AEBaseTileBlock; +import appeng.core.features.AEFeature; +import com.glodblock.github.FluidCraft; +import net.minecraft.block.material.Material; +import net.minecraft.tileentity.TileEntity; + +import java.util.EnumSet; + +public class FCBaseBlock extends AEBaseTileBlock { + + public FCBaseBlock(Material mat, String name) { + super(mat); + this.setBlockName(name); + this.setBlockTextureName(FluidCraft.MODID + ":" + name); + } + + @Override + public void setTileEntity( final Class clazz ) { + super.setTileEntity(clazz); + } + + public void setOpaque(boolean opaque) { + this.isOpaque = opaque; + } + + public void setFullBlock(boolean full) { + this.isFullSize = full; + } + + @Override + public void setFeature( final EnumSet f ) { + super.setFeature(f); + } + +} diff --git a/src/main/java/com/glodblock/github/common/item/ItemFluidDrop.java b/src/main/java/com/glodblock/github/common/item/ItemFluidDrop.java new file mode 100644 index 00000000..4661224f --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemFluidDrop.java @@ -0,0 +1,142 @@ +package com.glodblock.github.common.item; + +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IAEItemStack; +import appeng.util.item.AEFluidStack; +import appeng.util.item.AEItemStack; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.loader.ItemAndBlockHolder; +import com.glodblock.github.util.NameConst; +import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.client.resources.I18n; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.IIcon; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; + +public class ItemFluidDrop extends Item { + + @SideOnly(Side.CLIENT) + public IIcon shape; + + @Override + @SuppressWarnings("unchecked") + @SideOnly(Side.CLIENT) + public void getSubItems(Item item, CreativeTabs tab, List list) { + if (CreativeTabs.tabMisc.equals(tab)) { + list.add(newStack(new FluidStack(FluidRegistry.WATER, 1))); + list.add(newStack(new FluidStack(FluidRegistry.LAVA, 1))); + } + } + + @Override + public String getItemStackDisplayName(ItemStack stack) { + FluidStack fluid = getFluidStack(stack); + return I18n.format("item.fluid_drop.name", fluid == null ? "???" : fluid.getLocalizedName()); + } + + @Override + @SuppressWarnings("unchecked") + @SideOnly(Side.CLIENT) + public void addInformation(ItemStack stack, EntityPlayer player, List tooltip, boolean flag) { + FluidStack fluid = getFluidStack(stack); + if (fluid != null) { + tooltip.add(String.format(EnumChatFormatting.GRAY + "%s, 1 mB", fluid.getLocalizedName())); + } else { + tooltip.add(EnumChatFormatting.RED + I18n.format(NameConst.TT_INVALID_FLUID)); + } + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister aIconRegister) { + super.registerIcons(aIconRegister); + shape = aIconRegister.registerIcon(NameConst.RES_KEY + NameConst.ITEM_FLUID_DROP); + } + + public static ItemStack newStack(@Nullable FluidStack fluid) { + if (fluid == null || fluid.amount <= 0) { + return null; + } + ItemStack stack = new ItemStack(ItemAndBlockHolder.DROP, fluid.amount); + NBTTagCompound tag = new NBTTagCompound(); + tag.setString("Fluid", fluid.getFluid().getName()); + stack.setTagCompound(tag); + return stack; + } + + public static FluidStack getFluidStack(ItemStack stack) { + if (stack == null|| stack.getItem() != ItemAndBlockHolder.DROP || !stack.hasTagCompound()) { + return null; + } + NBTTagCompound tag = Objects.requireNonNull(stack.getTagCompound()); + if (!tag.hasKey("Fluid", Constants.NBT.TAG_STRING)) { + return null; + } + Fluid fluid = FluidRegistry.getFluid(tag.getString("Fluid").toLowerCase()); + if (fluid == null) { + return null; + } + FluidStack fluidStack = new FluidStack(fluid, stack.stackSize); + if (tag.hasKey("FluidTag", Constants.NBT.TAG_COMPOUND)) { + fluidStack.tag = tag.getCompoundTag("FluidTag"); + } + return fluidStack; + } + + public static IAEFluidStack getAeFluidStack(@Nullable IAEItemStack stack) { + if (stack == null) { + return null; + } + IAEFluidStack fluidStack = AEFluidStack.create(getFluidStack(stack.getItemStack())); + if (fluidStack == null) { + return null; + } + fluidStack.setStackSize(stack.getStackSize()); + return fluidStack; + } + + public static IAEItemStack newAeStack(@Nullable FluidStack fluid) { + if (fluid == null || fluid.amount <= 0) { + return null; + } + IAEItemStack stack = AEItemStack.create(newStack(fluid)); + if (stack == null) { + return null; + } + stack.setStackSize(fluid.amount); + return stack; + } + + public static IAEItemStack newAeStack(@Nullable IAEFluidStack fluid) { + if (fluid == null || fluid.getStackSize() <= 0) { + return null; + } + IAEItemStack stack = AEItemStack.create(newStack(fluid.getFluidStack())); + if (stack == null) { + return null; + } + stack.setStackSize(fluid.getStackSize()); + return stack; + } + + public ItemFluidDrop register() { + GameRegistry.registerItem(this, NameConst.ITEM_FLUID_DROP, FluidCraft.MODID); + return this; + } + +} diff --git a/src/main/java/com/glodblock/github/common/item/ItemFluidEncodedPattern.java b/src/main/java/com/glodblock/github/common/item/ItemFluidEncodedPattern.java new file mode 100644 index 00000000..0e777d2e --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemFluidEncodedPattern.java @@ -0,0 +1,31 @@ +package com.glodblock.github.common.item; + +import appeng.api.networking.crafting.ICraftingPatternDetails; +import appeng.items.misc.ItemEncodedPattern; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.util.FluidPatternDetails; +import com.glodblock.github.util.NameConst; +import cpw.mods.fml.common.registry.GameRegistry; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public class ItemFluidEncodedPattern extends ItemEncodedPattern { + + public ItemFluidEncodedPattern() { + super(); + this.setUnlocalizedName(NameConst.ITEM_FLUID_ENCODED_PATTERN); + this.setTextureName(FluidCraft.MODID + ":" + NameConst.ITEM_FLUID_ENCODED_PATTERN); + } + + @Override + public ICraftingPatternDetails getPatternForItem(ItemStack is, World w) { + FluidPatternDetails pattern = new FluidPatternDetails(is); + return pattern.readFromStack() ? pattern : null; + } + + public ItemFluidEncodedPattern register() { + GameRegistry.registerItem(this, NameConst.ITEM_FLUID_ENCODED_PATTERN, FluidCraft.MODID); + return this; + } + +} diff --git a/src/main/java/com/glodblock/github/common/item/ItemFluidPacket.java b/src/main/java/com/glodblock/github/common/item/ItemFluidPacket.java new file mode 100644 index 00000000..4f24bd5e --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemFluidPacket.java @@ -0,0 +1,110 @@ +package com.glodblock.github.common.item; + +import appeng.api.storage.data.IAEItemStack; +import appeng.util.item.AEItemStack; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.loader.ItemAndBlockHolder; +import com.glodblock.github.util.NameConst; +import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.IIcon; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; + +public class ItemFluidPacket extends Item { + + public ItemFluidPacket() { + setUnlocalizedName(NameConst.ITEM_FLUID_PACKET); + setMaxStackSize(1); + } + + @Override + public String getItemStackDisplayName(ItemStack stack) { + FluidStack fluid = getFluidStack(stack); + return fluid != null ? String.format("%s, %,d mB", fluid.getLocalizedName(), fluid.amount) + : super.getItemStackDisplayName(stack); + } + + @Override + @SuppressWarnings("unchecked") + public void addInformation(ItemStack stack, EntityPlayer player, List tooltip, boolean flags) { + FluidStack fluid = getFluidStack(stack); + if (fluid != null) { + for (String line : I18n.format(NameConst.TT_FLUID_PACKET).split("\\\\n")) { + tooltip.add(EnumChatFormatting.GRAY + line); + } + } else { + tooltip.add(EnumChatFormatting.RED + I18n.format(NameConst.TT_INVALID_FLUID)); + } + } + + public static FluidStack getFluidStack(ItemStack stack) { + if (stack == null || !stack.hasTagCompound()) { + return null; + } + FluidStack fluid = FluidStack.loadFluidStackFromNBT(Objects.requireNonNull(stack.getTagCompound()).getCompoundTag("FluidStack")); + return (fluid != null && fluid.amount > 0) ? fluid : null; + } + + public static FluidStack getFluidStack(@Nullable IAEItemStack stack) { + return stack != null ? getFluidStack(stack.getItemStack()) : null; + } + + public static ItemStack newStack(@Nullable FluidStack fluid) { + if (fluid == null || fluid.amount == 0) { + return null; + } + ItemStack stack = new ItemStack(ItemAndBlockHolder.PACKET); + NBTTagCompound tag = new NBTTagCompound(); + NBTTagCompound fluidTag = new NBTTagCompound(); + fluid.writeToNBT(fluidTag); + tag.setTag("FluidStack", fluidTag); + stack.setTagCompound(tag); + return stack; + } + + @Nullable + public static IAEItemStack newAeStack(@Nullable FluidStack fluid) { + return AEItemStack.create(newStack(fluid)); + } + + @Override + public int getSpriteNumber() { + return 0; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister aIconRegister) { + } + + @SideOnly(Side.CLIENT) + public IIcon getIconFromDamage(int p_77617_1_) { + return FluidRegistry.WATER.getStillIcon(); + } + + @Override + @SideOnly(Side.CLIENT) + public int getColorFromItemStack(ItemStack aStack, int aRenderPass) { + Fluid tFluid = FluidRegistry.getFluid(aStack.getItemDamage()); + return tFluid == null ? 16777215 : tFluid.getColor(); + } + + public ItemFluidPacket register() { + GameRegistry.registerItem(this, NameConst.ITEM_FLUID_PACKET, FluidCraft.MODID); + return this; + } +} diff --git a/src/main/java/com/glodblock/github/common/item/ItemPartFluidPatternTerminal.java b/src/main/java/com/glodblock/github/common/item/ItemPartFluidPatternTerminal.java new file mode 100644 index 00000000..0ddbbf18 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemPartFluidPatternTerminal.java @@ -0,0 +1,53 @@ +package com.glodblock.github.common.item; + +import appeng.api.AEApi; +import appeng.api.parts.IPartItem; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.common.parts.PartFluidPatternTerminal; +import com.glodblock.github.util.NameConst; +import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import javax.annotation.Nullable; + +public class ItemPartFluidPatternTerminal extends Item implements IPartItem { + + public ItemPartFluidPatternTerminal() { + this.setMaxStackSize(64); + this.setUnlocalizedName(NameConst.ITEM_PART_FLUID_PATTERN_TERMINAL); + AEApi.instance().partHelper().setItemBusRenderer(this); + } + + @Nullable + @Override + public PartFluidPatternTerminal createPartFromItemStack(ItemStack is) { + return new PartFluidPatternTerminal(is); + } + + @Override + public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float xOffset, float yOffset, float zOffset) { + return AEApi.instance().partHelper().placeBus(player.getHeldItem(), x, y, z, side, player, world); + } + + public ItemPartFluidPatternTerminal register() { + GameRegistry.registerItem(this, NameConst.ITEM_PART_FLUID_PATTERN_TERMINAL, FluidCraft.MODID); + return this; + } + + @Override + public void registerIcons(IIconRegister _iconRegister) { + } + + @Override + @SideOnly(Side.CLIENT) + public int getSpriteNumber() { + return 0; + } + +} diff --git a/src/main/java/com/glodblock/github/common/parts/FCBasePart.java b/src/main/java/com/glodblock/github/common/parts/FCBasePart.java new file mode 100644 index 00000000..671412d2 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/parts/FCBasePart.java @@ -0,0 +1,507 @@ +package com.glodblock.github.common.parts; + +import appeng.api.config.Settings; +import appeng.api.config.SortDir; +import appeng.api.config.SortOrder; +import appeng.api.config.ViewItems; +import appeng.api.implementations.IPowerChannelState; +import appeng.api.implementations.tiles.IViewCellStorage; +import appeng.api.networking.GridFlags; +import appeng.api.networking.events.MENetworkBootingStatusChange; +import appeng.api.networking.events.MENetworkEventSubscribe; +import appeng.api.networking.events.MENetworkPowerStatusChange; +import appeng.api.parts.IPartCollisionHelper; +import appeng.api.parts.IPartRenderHelper; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.ITerminalHost; +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.util.IConfigManager; +import appeng.client.texture.CableBusTextures; +import appeng.core.sync.GuiBridge; +import appeng.me.GridAccessException; +import appeng.parts.AEBasePart; +import appeng.tile.inventory.AppEngInternalInventory; +import appeng.tile.inventory.IAEAppEngInventory; +import appeng.tile.inventory.InvOperation; +import appeng.util.ConfigManager; +import appeng.util.IConfigManagerHost; +import appeng.util.Platform; +import com.glodblock.github.client.textures.FCPartsTexture; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import io.netty.buffer.ByteBuf; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.util.MathHelper; +import net.minecraft.util.Vec3; +import net.minecraftforge.common.util.ForgeDirection; + +import java.io.IOException; +import java.util.List; + +public abstract class FCBasePart extends AEBasePart implements IPowerChannelState, ITerminalHost, IConfigManagerHost, IViewCellStorage, IAEAppEngInventory { + + protected static final int POWERED_FLAG = 4; + protected static final int CHANNEL_FLAG = 16; + private static final int BOOTING_FLAG = 8; + + private byte spin = 0; // 0-3 + private int clientFlags = 0; // sent as byte. + private float opacity = -1; + + private final IConfigManager cm = new ConfigManager( this ); + private final AppEngInternalInventory viewCell = new AppEngInternalInventory( this, 5 ); + + public FCBasePart( final ItemStack is ) + { + this( is, false ); + } + + protected FCBasePart( final ItemStack is, final boolean requireChannel ) + { + super( is ); + + if( requireChannel ) + { + this.getProxy().setFlags( GridFlags.REQUIRE_CHANNEL ); + this.getProxy().setIdlePowerUsage( 1.0 / 2.0 ); + } + else + { + this.getProxy().setIdlePowerUsage( 1.0 / 16.0 ); // lights drain a little bit. + } + this.cm.registerSetting( Settings.SORT_BY, SortOrder.NAME ); + this.cm.registerSetting( Settings.VIEW_MODE, ViewItems.ALL ); + this.cm.registerSetting( Settings.SORT_DIRECTION, SortDir.ASCENDING ); + } + + @MENetworkEventSubscribe + public final void bootingRender( final MENetworkBootingStatusChange c ) + { + if( !this.isLightSource() ) + { + this.getHost().markForUpdate(); + } + } + + @MENetworkEventSubscribe + public final void powerRender( final MENetworkPowerStatusChange c ) + { + this.getHost().markForUpdate(); + } + + @Override + public final void getBoxes( final IPartCollisionHelper bch ) + { + bch.addBox( 2, 2, 14, 14, 14, 16 ); + bch.addBox( 4, 4, 13, 12, 12, 14 ); + } + + @Override + public void onNeighborChanged() + { + this.opacity = -1; + this.getHost().markForUpdate(); + } + + @Override + public void getDrops(final List drops, final boolean wrenched ) + { + super.getDrops( drops, wrenched ); + + for( final ItemStack is : this.viewCell ) + { + if( is != null ) + { + drops.add( is ); + } + } + } + + @Override + public IConfigManager getConfigManager() + { + return this.cm; + } + + @Override + public void readFromNBT( final NBTTagCompound data ) + { + super.readFromNBT( data ); + if( data.hasKey( "opacity" ) ) + { + this.opacity = data.getFloat( "opacity" ); + } + this.spin = data.getByte( "spin" ); + this.cm.readFromNBT( data ); + this.viewCell.readFromNBT( data, "viewCell" ); + } + + @Override + public void writeToNBT( final NBTTagCompound data ) + { + super.writeToNBT( data ); + data.setFloat( "opacity", this.opacity ); + data.setByte( "spin", this.getSpin() ); + this.cm.writeToNBT( data ); + this.viewCell.writeToNBT( data, "viewCell" ); + } + + public GuiBridge getGui(final EntityPlayer player ) + { + return GuiBridge.GUI_ME; + } + + + @Override + public void writeToStream( final ByteBuf data ) throws IOException + { + super.writeToStream( data ); + this.clientFlags = this.getSpin() & 3; + + try + { + if( this.getProxy().getEnergy().isNetworkPowered() ) + { + this.clientFlags = this.getClientFlags() | FCBasePart.POWERED_FLAG; + } + + if( this.getProxy().getPath().isNetworkBooting() ) + { + this.clientFlags = this.getClientFlags() | FCBasePart.BOOTING_FLAG; + } + + if( this.getProxy().getNode().meetsChannelRequirements() ) + { + this.clientFlags = this.getClientFlags() | FCBasePart.CHANNEL_FLAG; + } + } + catch( final GridAccessException e ) + { + // um.. nothing. + } + + data.writeByte( (byte) this.getClientFlags() ); + } + + @Override + public boolean readFromStream( final ByteBuf data ) throws IOException + { + super.readFromStream( data ); + final int oldFlags = this.getClientFlags(); + this.clientFlags = data.readByte(); + this.spin = (byte) ( this.getClientFlags() & 3 ); + return this.getClientFlags() != oldFlags; + } + + @Override + public final int getLightLevel() + { + return this.blockLight( this.isPowered() ? ( this.isLightSource() ? 15 : 9 ) : 0 ); + } + + public boolean onPartActivate0(final EntityPlayer player, final Vec3 pos ) + { + final TileEntity te = this.getTile(); + + if( !player.isSneaking() && Platform.isWrench( player, player.inventory.getCurrentItem(), te.xCoord, te.yCoord, te.zCoord ) ) + { + if( Platform.isServer() ) + { + if( this.getSpin() > 3 ) + { + this.spin = 0; + } + + switch( this.getSpin() ) + { + case 0: + this.spin = 1; + break; + case 1: + this.spin = 3; + break; + case 2: + this.spin = 0; + break; + case 3: + this.spin = 2; + break; + } + + this.getHost().markForUpdate(); + this.saveChanges(); + } + return true; + } + else + { + return super.onPartActivate( player, pos ); + } + } + + @Override + public boolean onPartActivate( final EntityPlayer player, final Vec3 pos ) + { + if( !onPartActivate0( player, pos ) ) + { + if( !player.isSneaking() ) + { + if( Platform.isClient() ) + { + return true; + } + + Platform.openGUI( player, this.getHost().getTile(), this.getSide(), this.getGui( player ) ); + + return true; + } + } + return false; + } + + @Override + public final void onPlacement( final EntityPlayer player, final ItemStack held, final ForgeDirection side ) + { + super.onPlacement( player, held, side ); + + final byte rotation = (byte) ( MathHelper.floor_double( ( player.rotationYaw * 4F ) / 360F + 2.5D ) & 3 ); + if( side == ForgeDirection.UP ) + { + this.spin = rotation; + } + else if( side == ForgeDirection.DOWN ) + { + this.spin = rotation; + } + } + + private int blockLight(final int emit ) + { + if( this.opacity < 0 ) + { + final TileEntity te = this.getTile(); + this.opacity = 255 - te.getWorldObj().getBlockLightOpacity( te.xCoord + this.getSide().offsetX, te.yCoord + this.getSide().offsetY, te.zCoord + this.getSide().offsetZ ); + } + + return (int) ( emit * ( this.opacity / 255.0f ) ); + } + + @Override + public final boolean isPowered() + { + try + { + if( Platform.isServer() ) + { + return this.getProxy().getEnergy().isNetworkPowered(); + } + else + { + return ( ( this.getClientFlags() & FCBasePart.POWERED_FLAG ) == FCBasePart.POWERED_FLAG ); + } + } + catch( final GridAccessException e ) + { + return false; + } + } + + @Override + public IMEMonitor getItemInventory() + { + try + { + return this.getProxy().getStorage().getItemInventory(); + } + catch( final GridAccessException e ) + { + // err nope? + } + return null; + } + + @Override + public IMEMonitor getFluidInventory() + { + try + { + return this.getProxy().getStorage().getFluidInventory(); + } + catch( final GridAccessException e ) + { + // err nope? + } + return null; + } + + @Override + public void updateSetting( final IConfigManager manager, final Enum settingName, final Enum newValue ) + { + + } + + @Override + public IInventory getViewCellStorage() + { + return this.viewCell; + } + + @Override + public void onChangeInventory(final IInventory inv, final int slot, final InvOperation mc, final ItemStack removedStack, final ItemStack newStack ) + { + this.getHost().markForSave(); + } + + @Override + public final boolean isActive() + { + if( !this.isLightSource() ) + { + return ( ( this.getClientFlags() & ( FCBasePart.CHANNEL_FLAG | FCBasePart.POWERED_FLAG ) ) == ( FCBasePart.CHANNEL_FLAG | FCBasePart.POWERED_FLAG ) ); + } + else + { + return this.isPowered(); + } + } + + public final int getClientFlags() + { + return this.clientFlags; + } + + public final byte getSpin() + { + return this.spin; + } + + @Override + @SideOnly( Side.CLIENT ) + public void renderInventory(final IPartRenderHelper rh, final RenderBlocks renderer ) + { + rh.setBounds( 2, 2, 14, 14, 14, 16 ); + + final IIcon sideTexture = CableBusTextures.PartMonitorSides.getIcon(); + final IIcon backTexture = CableBusTextures.PartMonitorBack.getIcon(); + + rh.setTexture( sideTexture, sideTexture, backTexture, FCPartsTexture.PartTerminalBroad.getIcon(), sideTexture, sideTexture ); + rh.renderInventoryBox( renderer ); + + rh.setInvColor( this.getColor().whiteVariant ); + rh.renderInventoryFace( this.getFrontBright().getIcon(), ForgeDirection.SOUTH, renderer ); + + rh.setInvColor( this.getColor().mediumVariant ); + rh.renderInventoryFace( this.getFrontDark().getIcon(), ForgeDirection.SOUTH, renderer ); + + rh.setInvColor( this.getColor().blackVariant ); + rh.renderInventoryFace( this.getFrontColored().getIcon(), ForgeDirection.SOUTH, renderer ); + + rh.setBounds( 4, 4, 13, 12, 12, 14 ); + rh.renderInventoryBox( renderer ); + } + + @Override + @SideOnly( Side.CLIENT ) + public void renderStatic( final int x, final int y, final int z, final IPartRenderHelper rh, final RenderBlocks renderer ) + { + this.setRenderCache( rh.useSimplifiedRendering( x, y, z, this, this.getRenderCache() ) ); + + final IIcon sideTexture = CableBusTextures.PartMonitorSides.getIcon(); + final IIcon backTexture = CableBusTextures.PartMonitorBack.getIcon(); + + rh.setTexture( sideTexture, sideTexture, backTexture, FCPartsTexture.PartTerminalBroad.getIcon(), sideTexture, sideTexture ); + + rh.setBounds( 2, 2, 14, 14, 14, 16 ); + rh.renderBlock( x, y, z, renderer ); + + if( this.getLightLevel() > 0 ) + { + final int l = 13; + Tessellator.instance.setBrightness( l << 20 | l << 4 ); + } + + renderer.uvRotateBottom = renderer.uvRotateEast = renderer.uvRotateNorth = renderer.uvRotateSouth = renderer.uvRotateTop = renderer.uvRotateWest = this.getSpin(); + + Tessellator.instance.setColorOpaque_I( this.getColor().whiteVariant ); + rh.renderFace( x, y, z, this.getFrontBright().getIcon(), ForgeDirection.SOUTH, renderer ); + + Tessellator.instance.setColorOpaque_I( this.getColor().mediumVariant ); + rh.renderFace( x, y, z, this.getFrontDark().getIcon(), ForgeDirection.SOUTH, renderer ); + + Tessellator.instance.setColorOpaque_I( this.getColor().blackVariant ); + rh.renderFace( x, y, z, this.getFrontColored().getIcon(), ForgeDirection.SOUTH, renderer ); + + renderer.uvRotateBottom = renderer.uvRotateEast = renderer.uvRotateNorth = renderer.uvRotateSouth = renderer.uvRotateTop = renderer.uvRotateWest = 0; + + final IIcon sideStatusTexture = CableBusTextures.PartMonitorSidesStatus.getIcon(); + + rh.setTexture( sideStatusTexture, sideStatusTexture, backTexture, this.getItemStack().getIconIndex(), sideStatusTexture, sideStatusTexture ); + + rh.setBounds( 4, 4, 13, 12, 12, 14 ); + rh.renderBlock( x, y, z, renderer ); + + final boolean hasChan = ( this.getClientFlags() & ( FCBasePart.POWERED_FLAG | FCBasePart.CHANNEL_FLAG ) ) == ( FCBasePart.POWERED_FLAG | FCBasePart.CHANNEL_FLAG ); + final boolean hasPower = ( this.getClientFlags() & FCBasePart.POWERED_FLAG ) == FCBasePart.POWERED_FLAG; + + if( hasChan ) + { + final int l = 14; + Tessellator.instance.setBrightness( l << 20 | l << 4 ); + Tessellator.instance.setColorOpaque_I( this.getColor().blackVariant ); + } + else if( hasPower ) + { + final int l = 9; + Tessellator.instance.setBrightness( l << 20 | l << 4 ); + Tessellator.instance.setColorOpaque_I( this.getColor().whiteVariant ); + } + else + { + Tessellator.instance.setBrightness( 0 ); + Tessellator.instance.setColorOpaque_I( 0x000000 ); + } + + final IIcon sideStatusLightTexture = CableBusTextures.PartMonitorSidesStatusLights.getIcon(); + + rh.renderFace( x, y, z, sideStatusLightTexture, ForgeDirection.EAST, renderer ); + rh.renderFace( x, y, z, sideStatusLightTexture, ForgeDirection.WEST, renderer ); + rh.renderFace( x, y, z, sideStatusLightTexture, ForgeDirection.UP, renderer ); + rh.renderFace( x, y, z, sideStatusLightTexture, ForgeDirection.DOWN, renderer ); + } + + /** + * The texture used for the bright front layer. + *

+ * The final texture can overlap any of the the texture in no particular order. + */ + public abstract FCPartsTexture getFrontBright(); + + /** + * The texture used for the colored (medium) front layer. + *

+ * The final texture can overlap any of the the texture in no particular order. + */ + public abstract FCPartsTexture getFrontColored(); + + /** + * The texture used for the dark front layer. + *

+ * The final texture can overlap any of the the texture in no particular order. + */ + public abstract FCPartsTexture getFrontDark(); + + /** + * Should the part emit light. This actually only affects the light level, light source use a level of 15 and non + * light source 9. + */ + public abstract boolean isLightSource(); + +} diff --git a/src/main/java/com/glodblock/github/common/parts/PartFluidPatternTerminal.java b/src/main/java/com/glodblock/github/common/parts/PartFluidPatternTerminal.java new file mode 100644 index 00000000..2602187e --- /dev/null +++ b/src/main/java/com/glodblock/github/common/parts/PartFluidPatternTerminal.java @@ -0,0 +1,288 @@ +package com.glodblock.github.common.parts; + +import appeng.api.config.SecurityPermissions; +import appeng.api.implementations.ICraftingPatternItem; +import appeng.api.networking.IGridHost; +import appeng.api.networking.crafting.ICraftingPatternDetails; +import appeng.api.storage.data.IAEItemStack; +import appeng.core.sync.GuiBridge; +import appeng.tile.inventory.AppEngInternalInventory; +import appeng.tile.inventory.InvOperation; +import appeng.util.Platform; +import com.glodblock.github.client.textures.FCPartsTexture; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidEncodedPattern; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.util.BlockPos; +import com.glodblock.github.util.FluidPatternDetails; +import com.glodblock.github.util.Util; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.Vec3; + +import java.util.List; +import java.util.Objects; + +public class PartFluidPatternTerminal extends FCBasePart { + + private static final FCPartsTexture FRONT_BRIGHT_ICON = FCPartsTexture.PartFluidPatternTerminal_Bright; + private static final FCPartsTexture FRONT_DARK_ICON = FCPartsTexture.PartFluidPatternTerminal_Colored; + private static final FCPartsTexture FRONT_COLORED_ICON = FCPartsTexture.PartFluidPatternTerminal_Dark; + + private final AppEngInternalInventory crafting = new AppEngInternalInventory( this, 9 ); + private final AppEngInternalInventory output = new AppEngInternalInventory( this, 3 ); + private final AppEngInternalInventory pattern = new AppEngInternalInventory( this, 2 ); + + private boolean craftingMode = true; + private boolean substitute = false; + + public PartFluidPatternTerminal(ItemStack is) { + super(is, true); + } + + @Override + public void getDrops(final List drops, final boolean wrenched ) + { + for( final ItemStack is : this.pattern ) + { + if( is != null ) + { + drops.add( is ); + } + } + } + + @Override + public boolean onPartActivate( final EntityPlayer player, final Vec3 pos ) { + TileEntity te = this.getTile(); + BlockPos tePos = new BlockPos(te); + if (Platform.isWrench(player, player.inventory.getCurrentItem(), tePos.getX(), tePos.getY(), tePos.getZ())) { + return super.onPartActivate(player, pos); + } + if (Platform.isServer()) { + if (Util.hasPermission(player, SecurityPermissions.INJECT, (IGridHost) this) || Util.hasPermission(player, SecurityPermissions.EXTRACT, (IGridHost) this)) { + InventoryHandler.openGui(player, te.getWorldObj(), tePos, Objects.requireNonNull(Util.from(getSide())), GuiType.FLUID_PATTERN_TERMINAL); + } + else { + player.addChatComponentMessage(new ChatComponentText("You don't have permission to view.")); + } + } + return true; + } + + @Override + public void readFromNBT( final NBTTagCompound data ) + { + super.readFromNBT( data ); + this.setCraftingRecipe( data.getBoolean( "craftingMode" ) ); + this.setSubstitution( data.getBoolean( "substitute" ) ); + this.pattern.readFromNBT( data, "pattern" ); + this.output.readFromNBT( data, "outputList" ); + this.crafting.readFromNBT( data, "craftingGrid" ); + } + + @Override + public void writeToNBT( final NBTTagCompound data ) + { + super.writeToNBT( data ); + data.setBoolean( "craftingMode", this.craftingMode ); + data.setBoolean( "substitute", this.substitute ); + this.pattern.writeToNBT( data, "pattern" ); + this.output.writeToNBT( data, "outputList" ); + this.crafting.writeToNBT( data, "craftingGrid" ); + } + + @Override + public GuiBridge getGui(final EntityPlayer p ) + { + int x = (int) p.posX; + int y = (int) p.posY; + int z = (int) p.posZ; + if( this.getHost().getTile() != null ) + { + x = this.getTile().xCoord; + y = this.getTile().yCoord; + z = this.getTile().zCoord; + } + + if( GuiBridge.GUI_PATTERN_TERMINAL.hasPermissions( this.getHost().getTile(), x, y, z, this.getSide(), p ) ) + { + return GuiBridge.GUI_PATTERN_TERMINAL; + } + return GuiBridge.GUI_ME; + } + + public void onChangeInventory0(final IInventory inv, final int slot, final InvOperation mc, final ItemStack removedStack, final ItemStack newStack ) + { + if( inv == this.pattern && slot == 1 ) + { + final ItemStack is = this.pattern.getStackInSlot( 1 ); + if( is != null && is.getItem() instanceof ICraftingPatternItem) + { + final ICraftingPatternItem pattern = (ICraftingPatternItem) is.getItem(); + final ICraftingPatternDetails details = pattern.getPatternForItem( is, this.getHost().getTile().getWorldObj() ); + if( details != null ) + { + this.setCraftingRecipe( details.isCraftable() ); + this.setSubstitution( details.canSubstitute() ); + + for( int x = 0; x < this.crafting.getSizeInventory() && x < details.getInputs().length; x++ ) + { + final IAEItemStack item = details.getInputs()[x]; + this.crafting.setInventorySlotContents( x, item == null ? null : item.getItemStack() ); + } + + for( int x = 0; x < this.output.getSizeInventory() && x < details.getOutputs().length; x++ ) + { + final IAEItemStack item = details.getOutputs()[x]; + this.output.setInventorySlotContents( x, item == null ? null : item.getItemStack() ); + } + } + } + } + else if( inv == this.crafting ) + { + this.fixCraftingRecipes(); + } + + this.getHost().markForSave(); + } + + @Override + public void onChangeInventory(final IInventory inv, final int slot, final InvOperation mc, final ItemStack removedStack, final ItemStack newStack ) + { + if (inv == this.pattern && slot == 1) { + final ItemStack is = inv.getStackInSlot(1); + if (is != null && is.getItem() instanceof ItemFluidEncodedPattern) { + final ItemFluidEncodedPattern pattern = (ItemFluidEncodedPattern) is.getItem(); + final ICraftingPatternDetails details = pattern.getPatternForItem( is, this.getHost().getTile().getWorldObj() ); + if( details != null ) + { + this.setCraftingRecipe( details.isCraftable() ); + this.setSubstitution( details.canSubstitute() ); + + for( int x = 0; x < this.crafting.getSizeInventory() && x < details.getInputs().length; x++ ) + { + final IAEItemStack item = details.getInputs()[x]; + if (item != null && item.getItem() instanceof ItemFluidDrop) { + ItemStack packet = ItemFluidPacket.newStack(ItemFluidDrop.getFluidStack(item.getItemStack())); + this.crafting.setInventorySlotContents(x, packet); + } + else this.crafting.setInventorySlotContents( x, item == null ? null : item.getItemStack() ); + } + + for( int x = 0; x < this.output.getSizeInventory() && x < details.getOutputs().length; x++ ) + { + final IAEItemStack item = details.getOutputs()[x]; + if (item != null && item.getItem() instanceof ItemFluidDrop) { + ItemStack packet = ItemFluidPacket.newStack(ItemFluidDrop.getFluidStack(item.getItemStack())); + this.output.setInventorySlotContents(x, packet); + } + else this.output.setInventorySlotContents( x, item == null ? null : item.getItemStack() ); + } + } + this.getHost().markForSave(); + return; + } + } + onChangeInventory0(inv, slot, mc, removedStack, newStack); + } + + private void fixCraftingRecipes() + { + if( this.craftingMode ) + { + for( int x = 0; x < this.crafting.getSizeInventory(); x++ ) + { + final ItemStack is = this.crafting.getStackInSlot( x ); + if( is != null ) + { + is.stackSize = 1; + } + } + } + } + + public boolean isCraftingRecipe() + { + return this.craftingMode; + } + + public void setCraftingRecipe( final boolean craftingMode ) + { + this.craftingMode = craftingMode; + this.fixCraftingRecipes(); + } + + public boolean isSubstitution() + { + return this.substitute; + } + + public void setSubstitution( boolean canSubstitute ) + { + this.substitute = canSubstitute; + } + + public void onChangeCrafting(IAEItemStack[] newCrafting, IAEItemStack[] newOutput) { + IInventory crafting = this.getInventoryByName("crafting"); + IInventory output = this.getInventoryByName("output"); + if (crafting instanceof AppEngInternalInventory && output instanceof AppEngInternalInventory) { + for (int x = 0; x < crafting.getSizeInventory() && x < newCrafting.length; x++) { + final IAEItemStack item = newCrafting[x]; + crafting.setInventorySlotContents(x, item == null ? null: item.getItemStack()); + } + for (int x = 0; x < output.getSizeInventory() && x < newOutput.length; x++) { + final IAEItemStack item = newOutput[x]; + output.setInventorySlotContents(x, item == null ? null : item.getItemStack()); + } + } + } + + @Override + public IInventory getInventoryByName( final String name ) + { + if( name.equals( "crafting" ) ) + { + return this.crafting; + } + + if( name.equals( "output" ) ) + { + return this.output; + } + + if( name.equals( "pattern" ) ) + { + return this.pattern; + } + + return super.getInventoryByName( name ); + } + + @Override + public FCPartsTexture getFrontBright() { + return FRONT_BRIGHT_ICON; + } + + @Override + public FCPartsTexture getFrontColored() { + return FRONT_COLORED_ICON; + } + + @Override + public FCPartsTexture getFrontDark() { + return FRONT_DARK_ICON; + } + + @Override + public boolean isLightSource() { + return false; + } +} diff --git a/src/main/java/com/glodblock/github/common/tile/TileFluidDiscretizer.java b/src/main/java/com/glodblock/github/common/tile/TileFluidDiscretizer.java new file mode 100644 index 00000000..68f3aab9 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/tile/TileFluidDiscretizer.java @@ -0,0 +1,295 @@ +package com.glodblock.github.common.tile; + +import appeng.api.config.Actionable; +import appeng.api.networking.GridFlags; +import appeng.api.networking.crafting.ICraftingGrid; +import appeng.api.networking.energy.IEnergyGrid; +import appeng.api.networking.events.*; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.security.MachineSource; +import appeng.api.networking.storage.IBaseMonitor; +import appeng.api.networking.storage.IStorageGrid; +import appeng.api.storage.*; +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IAEStack; +import appeng.api.storage.data.IItemList; +import appeng.helpers.IPriorityHost; +import appeng.me.GridAccessException; +import appeng.me.cache.CraftingGridCache; +import appeng.me.storage.MEInventoryHandler; +import appeng.tile.grid.AENetworkTile; +import appeng.util.Platform; +import com.glodblock.github.common.item.ItemFluidDrop; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class TileFluidDiscretizer extends AENetworkTile implements IPriorityHost, ICellContainer { + + private final BaseActionSource ownActionSource = new MachineSource(this); + private final FluidDiscretizingInventory fluidDropInv = new FluidDiscretizingInventory(); + private final FluidCraftingInventory fluidCraftInv = new FluidCraftingInventory(); + private boolean prevActiveState = false; + + public TileFluidDiscretizer() { + super(); + getProxy().setIdlePowerUsage(3D); + getProxy().setFlags(GridFlags.REQUIRE_CHANNEL); + } + + @Override + public boolean canBeRotated() { + return false; + //based + } + + @Override + @SuppressWarnings("rawtypes") + public List getCellArray(StorageChannel channel) { + /*conflict = !checkDiscreatizer(); + if (conflict) return Collections.emptyList();*/ + if (getProxy().isActive()) { + if (channel == StorageChannel.ITEMS) { + return Collections.singletonList(fluidDropInv.invHandler); + } else if (channel == StorageChannel.FLUIDS) { + return Collections.singletonList(fluidCraftInv.invHandler); + } + } + return Collections.emptyList(); + } + + @Override + public int getPriority() { + return Integer.MAX_VALUE; + } + + @Override + public void setPriority(int newValue) { + //do nothing + } + + @Override + public void blinkCell(int slot) { + //do nothing + } + + @Override + public void gridChanged() { + IMEMonitor fluidGrid = getFluidGrid(); + if (fluidGrid != null) { + fluidGrid.addListener(fluidDropInv, fluidGrid); + } + } + + @Override + public void saveChanges(IMEInventory cellInventory) { + markDirty(); + } + + private IMEMonitor getFluidGrid() { + try { + return getProxy().getGrid().getCache(IStorageGrid.class).getFluidInventory(); + } catch (GridAccessException e) { + return null; + } + } + + private IEnergyGrid getEnergyGrid() { + try { + return getProxy().getGrid().getCache(IEnergyGrid.class); + } catch (GridAccessException e) { + return null; + } + } + + private void updateState() { + boolean isActive = getProxy().isActive(); + if (isActive != prevActiveState) { + prevActiveState = isActive; + try { + getProxy().getGrid().postEvent(new MENetworkCellArrayUpdate()); + } catch (GridAccessException e) { + // NO-OP + } + } + } + + @MENetworkEventSubscribe + public void onPowerUpdate(MENetworkPowerStatusChange event) { + updateState(); + } + + @MENetworkEventSubscribe + public void onChannelUpdate(MENetworkChannelsChanged event) { + updateState(); + } + + @MENetworkEventSubscribe + public void onStorageUpdate(MENetworkStorageEvent event) { + updateState(); + } + + private boolean checkDiscreatizer() { + int amount = getProxy().getNode().getGrid().getMachines(this.getClass()).size(); + return amount <= 1; + } + + private class FluidDiscretizingInventory implements IMEInventory, IMEMonitorHandlerReceiver { + + private final MEInventoryHandler invHandler = new MEInventoryHandler<>(this, getChannel()); + private List itemCache = null; + + FluidDiscretizingInventory() { + invHandler.setPriority(Integer.MAX_VALUE); + } + + @Override + public IAEItemStack injectItems(IAEItemStack request, Actionable type, BaseActionSource src) { + /*if (conflict) return request;*/ + IAEFluidStack fluidStack = ItemFluidDrop.getAeFluidStack(request); + if (fluidStack == null) { + return request; + } + IMEMonitor fluidGrid = getFluidGrid(); + if (fluidGrid == null) { + return request; + } + IEnergyGrid energyGrid = getEnergyGrid(); + if (energyGrid == null) { + return request; + } + if (type == Actionable.SIMULATE) { + return ItemFluidDrop.newAeStack(fluidGrid.injectItems(fluidStack.copy(), Actionable.SIMULATE, src)); + } + else { + return ItemFluidDrop.newAeStack(Platform.poweredInsert(energyGrid, fluidGrid, fluidStack, ownActionSource)); + } + } + + @Override + public IAEItemStack extractItems(IAEItemStack request, Actionable mode, BaseActionSource src) { + /*if (conflict) return null;*/ + IAEFluidStack fluidStack = ItemFluidDrop.getAeFluidStack(request); + if (fluidStack == null) { + return null; + } + IMEMonitor fluidGrid = getFluidGrid(); + if (fluidGrid == null) { + return null; + } + IEnergyGrid energyGrid = getEnergyGrid(); + if (energyGrid == null) { + return null; + } + if (mode == Actionable.SIMULATE) { + return ItemFluidDrop.newAeStack(fluidGrid.extractItems(fluidStack.copy(), Actionable.SIMULATE, src)); + } + else { + return ItemFluidDrop.newAeStack(Platform.poweredExtraction(energyGrid, fluidGrid, fluidStack, ownActionSource)); + } + } + + @Override + public IItemList getAvailableItems(IItemList out) { + /*if (conflict) return out;*/ + if (itemCache == null) { + itemCache = new ArrayList<>(); + IMEMonitor fluidGrid = getFluidGrid(); + if (fluidGrid != null) { + for (IAEFluidStack fluid : fluidGrid.getStorageList()) { + IAEItemStack stack = ItemFluidDrop.newAeStack(fluid); + if (stack != null) { + itemCache.add(stack); + } + } + } + } + for (IAEItemStack stack : itemCache) { + out.addStorage(stack); + } + return out; + } + + @Override + public StorageChannel getChannel() { + return StorageChannel.ITEMS; + } + + @Override + public boolean isValid(Object verificationToken) { + IMEMonitor fluidGrid = getFluidGrid(); + return fluidGrid != null && fluidGrid == verificationToken /*&& !conflict*/; + } + + @Override + public void postChange(IBaseMonitor monitor, Iterable change, BaseActionSource actionSource) { + itemCache = null; + try { + List mappedChanges = new ArrayList<>(); + for (IAEFluidStack fluidStack : change) { + IAEItemStack itemStack = ItemFluidDrop.newAeStack(fluidStack); + if (itemStack != null) { + mappedChanges.add(itemStack); + } + } + getProxy().getGrid().getCache(IStorageGrid.class) + .postAlterationOfStoredItems(getChannel(), mappedChanges, ownActionSource); + } catch (GridAccessException e) { + // NO-OP + } + } + + @Override + public void onListUpdate() { + // NO-OP + } + } + + private class FluidCraftingInventory implements IMEInventory { + + private final MEInventoryHandler invHandler = new MEInventoryHandler<>(this, getChannel()); + + FluidCraftingInventory() { + invHandler.setPriority(Integer.MAX_VALUE); + } + + @Override + @SuppressWarnings("rawtypes") + public IAEFluidStack injectItems(IAEFluidStack input, Actionable type, BaseActionSource src) { + /*if (conflict) return null;*/ + ICraftingGrid craftingGrid; + try { + craftingGrid = getProxy().getGrid().getCache(ICraftingGrid.class); + } catch (GridAccessException e) { + return null; + } + if (craftingGrid instanceof CraftingGridCache) { + IAEStack remaining = ((CraftingGridCache)craftingGrid).injectItems( + ItemFluidDrop.newAeStack(input), type, ownActionSource); + if (remaining instanceof IAEItemStack) { + return ItemFluidDrop.getAeFluidStack((IAEItemStack) remaining); + } + } + return null; + } + + @Override + public IAEFluidStack extractItems(IAEFluidStack request, Actionable mode, BaseActionSource src) { + return null; + } + + @Override + public IItemList getAvailableItems(IItemList out) { + return out; + } + + @Override + public StorageChannel getChannel() { + return StorageChannel.FLUIDS; + } + + } + +} diff --git a/src/main/java/com/glodblock/github/common/tile/TileFluidInterface.java b/src/main/java/com/glodblock/github/common/tile/TileFluidInterface.java new file mode 100644 index 00000000..200cf645 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/tile/TileFluidInterface.java @@ -0,0 +1,81 @@ +package com.glodblock.github.common.tile; + +import appeng.api.config.Actionable; +import appeng.api.networking.energy.IEnergyGrid; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.security.MachineSource; +import appeng.api.networking.storage.IStorageGrid; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.data.IAEFluidStack; +import appeng.me.GridAccessException; +import appeng.tile.misc.TileInterface; +import appeng.util.Platform; +import appeng.util.item.AEFluidStack; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; +import net.minecraftforge.fluids.IFluidHandler; + +public class TileFluidInterface extends TileInterface implements IFluidHandler +{ + + private final BaseActionSource ownActionSource = new MachineSource(this); + + private IMEMonitor getFluidGrid() { + try { + return getProxy().getGrid().getCache(IStorageGrid.class).getFluidInventory(); + } catch (GridAccessException e) { + return null; + } + } + + private IEnergyGrid getEnergyGrid() { + try { + return getProxy().getGrid().getCache(IEnergyGrid.class); + } catch (GridAccessException e) { + return null; + } + } + + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + IMEMonitor fluidGrid = getFluidGrid(); + IEnergyGrid energyGrid = getEnergyGrid(); + if (energyGrid == null || fluidGrid == null || resource == null) + return 0; + int ori = resource.amount; + IAEFluidStack remove; + if (doFill) { + remove = Platform.poweredInsert(energyGrid, fluidGrid, AEFluidStack.create(resource), ownActionSource); + } else { + remove = fluidGrid.injectItems(AEFluidStack.create(resource), Actionable.SIMULATE, ownActionSource); + } + return remove == null ? ori : (int) (ori - remove.getStackSize()); + } + + @Override + public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) { + return null; + } + + @Override + public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) { + return null; + } + + @Override + public boolean canFill(ForgeDirection from, Fluid fluid) { + return true; + } + + @Override + public boolean canDrain(ForgeDirection from, Fluid fluid) { + return false; + } + + @Override + public FluidTankInfo[] getTankInfo(ForgeDirection from) { + return new FluidTankInfo[]{new FluidTankInfo(null, 0)}; + } +} diff --git a/src/main/java/com/glodblock/github/common/tile/TileFluidPacketDecoder.java b/src/main/java/com/glodblock/github/common/tile/TileFluidPacketDecoder.java new file mode 100644 index 00000000..0aea4e25 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/tile/TileFluidPacketDecoder.java @@ -0,0 +1,102 @@ +package com.glodblock.github.common.tile; + +import appeng.api.networking.GridFlags; +import appeng.api.networking.IGridNode; +import appeng.api.networking.energy.IEnergyGrid; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.security.MachineSource; +import appeng.api.networking.storage.IStorageGrid; +import appeng.api.networking.ticking.IGridTickable; +import appeng.api.networking.ticking.TickRateModulation; +import appeng.api.networking.ticking.TickingRequest; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.data.IAEFluidStack; +import appeng.helpers.Reflected; +import appeng.me.GridAccessException; +import appeng.tile.TileEvent; +import appeng.tile.events.TileEventType; +import appeng.tile.grid.AENetworkTile; +import appeng.tile.inventory.AppEngInternalInventory; +import appeng.tile.inventory.IAEAppEngInventory; +import appeng.tile.inventory.InvOperation; +import appeng.util.Platform; +import appeng.util.item.AEFluidStack; +import com.glodblock.github.common.item.ItemFluidPacket; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.fluids.FluidStack; + +public class TileFluidPacketDecoder extends AENetworkTile implements IGridTickable, IAEAppEngInventory { + + private final AppEngInternalInventory inventory = new AppEngInternalInventory(this, 1); + private final BaseActionSource ownActionSource = new MachineSource(this); + + @Reflected + public TileFluidPacketDecoder() { + getProxy().setIdlePowerUsage(1D); + getProxy().setFlags(GridFlags.REQUIRE_CHANNEL); + } + + public IInventory getInventory() { + return inventory; + } + + @Override + public boolean canBeRotated() { + return false; + } + + @Override + public TickingRequest getTickingRequest(IGridNode node) { + return new TickingRequest(5, 120, false, true); + } + + @Override + public TickRateModulation tickingRequest(IGridNode node, int ticksSinceLastCall) { + ItemStack stack = inventory.getStackInSlot(0); + if (stack == null || !(stack.getItem() instanceof ItemFluidPacket)) { + return TickRateModulation.SLEEP; + } + FluidStack fluid = ItemFluidPacket.getFluidStack(stack); + if (fluid == null || fluid.amount <= 0) { + inventory.setInventorySlotContents(0, null); + return TickRateModulation.SLEEP; + } + IAEFluidStack aeFluid = AEFluidStack.create(fluid); + IEnergyGrid energyGrid = node.getGrid().getCache(IEnergyGrid.class); + IMEMonitor fluidGrid = node.getGrid().getCache(IStorageGrid.class).getFluidInventory(); + IAEFluidStack remaining = Platform.poweredInsert(energyGrid, fluidGrid, aeFluid, ownActionSource); + if (remaining != null) { + if (remaining.getStackSize() == aeFluid.getStackSize()) { + return TickRateModulation.SLOWER; + } + inventory.setInventorySlotContents(0, ItemFluidPacket.newStack(remaining.getFluidStack())); + return TickRateModulation.FASTER; + } else { + inventory.setInventorySlotContents(0, null); + return TickRateModulation.SLEEP; + } + } + + @Override + public void onChangeInventory(IInventory inv, int slot, InvOperation mc, ItemStack removedStack, ItemStack newStack) { + try { + getProxy().getTick().alertDevice(getProxy().getNode()); + } catch (GridAccessException e) { + // NO-OP + } + } + + @TileEvent( TileEventType.WORLD_NBT_WRITE ) + public NBTTagCompound writeToNBTEvent(NBTTagCompound data) { + inventory.writeToNBT(data, "Inventory"); + return data; + } + + @TileEvent( TileEventType.WORLD_NBT_READ ) + public void readFromNBTEvent(NBTTagCompound data) { + inventory.readFromNBT(data, "Inventory"); + } + +} diff --git a/src/main/java/com/glodblock/github/common/tile/TileFluidPatternEncoder.java b/src/main/java/com/glodblock/github/common/tile/TileFluidPatternEncoder.java new file mode 100644 index 00000000..a0f1cac5 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/tile/TileFluidPatternEncoder.java @@ -0,0 +1,77 @@ +package com.glodblock.github.common.tile; + +import appeng.api.storage.StorageChannel; +import appeng.api.storage.data.IAEItemStack; +import appeng.tile.AEBaseTile; +import appeng.tile.TileEvent; +import appeng.tile.events.TileEventType; +import appeng.tile.inventory.AppEngInternalInventory; +import appeng.tile.inventory.IAEAppEngInventory; +import appeng.tile.inventory.InvOperation; +import com.glodblock.github.inventory.AeStackInventory; +import com.glodblock.github.inventory.AeStackInventoryImpl; +import com.glodblock.github.util.BlockPos; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import java.util.List; + +public class TileFluidPatternEncoder extends AEBaseTile implements IAEAppEngInventory { + + private final AppEngInternalInventory patternInv = new AppEngInternalInventory(this, 2); + private final AeStackInventoryImpl crafting = new AeStackInventoryImpl<>(StorageChannel.ITEMS, 9, this); + private final AeStackInventoryImpl output = new AeStackInventoryImpl<>(StorageChannel.ITEMS, 3, this); + + public IInventory getInventory() { + return patternInv; + } + + public AeStackInventory getCraftingSlots() { + return crafting; + } + + public AeStackInventory getOutputSlots() { + return output; + } + + @Override + public boolean canBeRotated() { + return false; + } + + @Override + public void getDrops(final World w, final int x, final int y, final int z, final List drops ) { + getDrops(w, new BlockPos(x, y, z), drops); + } + + public void getDrops(World world, BlockPos pos, List drops) { + for (ItemStack stack : patternInv) { + if (stack != null) { + drops.add(stack); + } + } + } + + @TileEvent( TileEventType.WORLD_NBT_READ ) + public void readFromNBTEvent(NBTTagCompound data) { + patternInv.readFromNBT(data, "Inventory"); + crafting.readFromNbt(data, "CraftingSlots"); + output.readFromNbt(data, "OutputSlots"); + } + + @TileEvent( TileEventType.WORLD_NBT_WRITE ) + public NBTTagCompound writeToNBTEvent(NBTTagCompound data) { + patternInv.writeToNBT(data, "Inventory"); + crafting.writeToNbt(data, "CraftingSlots"); + output.writeToNbt(data, "OutputSlots"); + return data; + } + + @Override + public void onChangeInventory(IInventory inv, int slot, InvOperation mc, ItemStack removedStack, ItemStack newStack) { + + } + +} diff --git a/src/main/java/com/glodblock/github/coremod/FCClassTransformer.java b/src/main/java/com/glodblock/github/coremod/FCClassTransformer.java new file mode 100644 index 00000000..cd20951c --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/FCClassTransformer.java @@ -0,0 +1,59 @@ +package com.glodblock.github.coremod; + +import com.glodblock.github.coremod.transform.CraftingCpuTransformer; +import com.glodblock.github.coremod.transform.CraftingTreeNodeTransformer; +import com.glodblock.github.coremod.transform.DualityInterfaceTransformer; +import net.minecraft.launchwrapper.IClassTransformer; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; + +public class FCClassTransformer implements IClassTransformer { + + @Override + public byte[] transform(String name, String transformedName, byte[] code) { + Transform tform; + switch (transformedName) { + case "appeng.crafting.CraftingTreeNode": + tform = CraftingTreeNodeTransformer.INSTANCE; + break; + case "appeng.me.cluster.implementations.CraftingCPUCluster": + tform = CraftingCpuTransformer.INSTANCE; + break; + case "appeng.helpers.DualityInterface": + tform = DualityInterfaceTransformer.INSTANCE; + break; + /*case "appeng.container.implementations.ContainerInterfaceTerminal": + tform = ContainerInterfaceTerminalTransformer.INSTANCE; + break;*/ //unfinished + default: + return code; + } + System.out.println("[FCAE2] Transforming class: " + transformedName); + return tform.transformClass(code); + } + + public interface Transform { + + byte[] transformClass(byte[] code); + + } + + public static abstract class ClassMapper implements Transform { + + @Override + public byte[] transformClass(byte[] code) { + ClassReader reader = new ClassReader(code); + ClassWriter writer = new ClassWriter(reader, getWriteFlags()); + reader.accept(getClassMapper(writer), 0); + return writer.toByteArray(); + } + + protected int getWriteFlags() { + return 0; + } + + protected abstract ClassVisitor getClassMapper(ClassVisitor downstream); + + } +} diff --git a/src/main/java/com/glodblock/github/coremod/FluidCraftCore.java b/src/main/java/com/glodblock/github/coremod/FluidCraftCore.java new file mode 100644 index 00000000..b79dd40d --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/FluidCraftCore.java @@ -0,0 +1,40 @@ +package com.glodblock.github.coremod; + +import cpw.mods.fml.relauncher.IFMLLoadingPlugin; + +import javax.annotation.Nullable; +import java.util.Map; + +@IFMLLoadingPlugin.MCVersion("1.7.10") +@IFMLLoadingPlugin.TransformerExclusions("com.glodblock.github.coremod") +public class FluidCraftCore implements IFMLLoadingPlugin { + + @Override + public String[] getASMTransformerClass() { + return new String[] { FluidCraftCore.class.getPackage().getName() + ".FCClassTransformer" }; + } + + @Nullable + @Override + public String getModContainerClass() { + return null; + } + + @Nullable + @Override + public String getSetupClass() { + return null; + } + + @Override + public void injectData(Map data) { + // NO-OP + } + + @Nullable + @Override + public String getAccessTransformerClass() { + return null; + } + +} diff --git a/src/main/java/com/glodblock/github/coremod/hooker/CoreModHooks.java b/src/main/java/com/glodblock/github/coremod/hooker/CoreModHooks.java new file mode 100644 index 00000000..b66158d1 --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/hooker/CoreModHooks.java @@ -0,0 +1,87 @@ +package com.glodblock.github.coremod.hooker; + +import appeng.api.networking.IGridNode; +import appeng.api.networking.IMachineSet; +import appeng.api.storage.data.IAEItemStack; +import appeng.me.MachineSet; +import appeng.tile.misc.TileInterface; +import appeng.util.InventoryAdaptor; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.inventory.FluidConvertingInventoryAdaptor; +import com.glodblock.github.inventory.FluidConvertingInventoryCrafting; +import com.glodblock.github.loader.ItemAndBlockHolder; +import com.glodblock.github.util.Ae2Reflect; +import com.glodblock.github.util.SetBackedMachineSet; +import com.glodblock.github.util.Util; +import com.google.common.collect.Sets; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.util.ForgeDirection; + +import javax.annotation.Nullable; +import java.util.HashSet; +import java.util.Set; + +public class CoreModHooks { + + public static InventoryCrafting wrapCraftingBuffer(InventoryCrafting inv) { + return new FluidConvertingInventoryCrafting(Ae2Reflect.getCraftContainer(inv), Ae2Reflect.getCraftWidth(inv), inv.getSizeInventory()/Ae2Reflect.getCraftWidth(inv)); + } + + public static IAEItemStack wrapFluidPacketStack(IAEItemStack stack) { + if (stack.getItem() == ItemAndBlockHolder.PACKET) { + IAEItemStack dropStack = ItemFluidDrop.newAeStack(ItemFluidPacket.getFluidStack(stack.getItemStack())); + if (dropStack != null) { + return dropStack; + } + } + return stack; + } + + @Nullable + public static InventoryAdaptor wrapInventory(@Nullable TileEntity tile, ForgeDirection face) { + return tile != null ? FluidConvertingInventoryAdaptor.wrap(tile, Util.from(face)) : null; + } + + public static long getCraftingByteCost(IAEItemStack stack) { + return stack.getItem() instanceof ItemFluidDrop + ? (long)Math.ceil(stack.getStackSize() / 1000D) : stack.getStackSize(); + } + + public static IAEItemStack[] flattenFluidPackets(IAEItemStack[] stacks) { + for (int i = 0; i < stacks.length; i++) { + if (stacks[i].getItem() instanceof ItemFluidPacket) { + stacks[i] = ItemFluidDrop.newAeStack(ItemFluidPacket.getFluidStack(stacks[i])); + } + } + return stacks; + } + + /*public static IMachineSet getMachines(IGrid grid, Class c) { + if (c == TileInterface.class) { + return unionMachineSets(grid.getMachines(c), grid.getMachines(TileDualInterface.class)); + } else if (c == PartInterface.class) { + return unionMachineSets(grid.getMachines(c), grid.getMachines(PartDualInterface.class)); + } else { + return grid.getMachines(c); + } + }*/ //unfinished + + private static IMachineSet unionMachineSets(IMachineSet a, IMachineSet b) { + if (a.isEmpty()) { + return b; + } else if (b.isEmpty()) { + return a; + } else if (a instanceof MachineSet && b instanceof MachineSet) { + return new SetBackedMachineSet(TileInterface.class, Sets.union((MachineSet)a, (MachineSet)b)); + } else { + Set union = new HashSet<>(); + a.forEach(union::add); + b.forEach(union::add); + return new SetBackedMachineSet(TileInterface.class, union); + } + } + +} diff --git a/src/main/java/com/glodblock/github/coremod/transform/ContainerInterfaceTerminalTransformer.java b/src/main/java/com/glodblock/github/coremod/transform/ContainerInterfaceTerminalTransformer.java new file mode 100644 index 00000000..a2cfd941 --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/transform/ContainerInterfaceTerminalTransformer.java @@ -0,0 +1,58 @@ +package com.glodblock.github.coremod.transform; + +import com.glodblock.github.coremod.FCClassTransformer; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class ContainerInterfaceTerminalTransformer extends FCClassTransformer.ClassMapper { + + public static final ContainerInterfaceTerminalTransformer INSTANCE = new ContainerInterfaceTerminalTransformer(); + + private ContainerInterfaceTerminalTransformer() { + // NO-OP + } + + @Override + protected ClassVisitor getClassMapper(ClassVisitor downstream) { + return new TransformContainerInterfaceTerminal(Opcodes.ASM5, downstream); + } + + private static class TransformContainerInterfaceTerminal extends ClassVisitor { + + TransformContainerInterfaceTerminal(int api, ClassVisitor cv) { + super(api, cv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if (name.equals("detectAndSendChanges") || name.equals("func_75142_b") || name.equals("regenList")) { + return new TransformDetectAndSendChanges(api, super.visitMethod(access, name, desc, signature, exceptions)); + } + return super.visitMethod(access, name, desc, signature, exceptions); + } + + } + + private static class TransformDetectAndSendChanges extends MethodVisitor { + + TransformDetectAndSendChanges(int api, MethodVisitor mv) { + super(api, mv); + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (opcode == Opcodes.INVOKEINTERFACE + && owner.equals("appeng/api/networking/IGrid") && name.equals("getMachines")) { + super.visitMethodInsn(Opcodes.INVOKESTATIC, + "com/glodblock/github/coremod/hooker/CoreModHooks", + "getMachines", + "(Lappeng/api/networking/IGrid;Ljava/lang/Class;)Lappeng/api/networking/IMachineSet;", + false); + } else { + super.visitMethodInsn(opcode, owner, name, desc, itf); + } + } + + } +} diff --git a/src/main/java/com/glodblock/github/coremod/transform/CraftingCpuTransformer.java b/src/main/java/com/glodblock/github/coremod/transform/CraftingCpuTransformer.java new file mode 100644 index 00000000..f65a9e61 --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/transform/CraftingCpuTransformer.java @@ -0,0 +1,86 @@ +package com.glodblock.github.coremod.transform; + +import com.glodblock.github.coremod.FCClassTransformer; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class CraftingCpuTransformer extends FCClassTransformer.ClassMapper { + + public static final CraftingCpuTransformer INSTANCE = new CraftingCpuTransformer(); + + private CraftingCpuTransformer() { + // NO-OP + } + + @Override + protected ClassVisitor getClassMapper(ClassVisitor downstream) { + return new TransformCraftingCPUCluster(Opcodes.ASM5, downstream); + } + + private static class TransformCraftingCPUCluster extends ClassVisitor { + + TransformCraftingCPUCluster(int api, ClassVisitor cv) { + super(api, cv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if (name.equals("executeCrafting")) { + return new TransformExecuteCrafting(api, super.visitMethod(access, name, desc, signature, exceptions)); + } + return super.visitMethod(access, name, desc, signature, exceptions); + } + + } + + private static class TransformExecuteCrafting extends MethodVisitor { + + private boolean gotInventory = false; + + TransformExecuteCrafting(int api, MethodVisitor mv) { + super(api, mv); + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, String desc) { + if (opcode == Opcodes.GETFIELD + && owner.equals("appeng/me/cluster/implementations/CraftingCPUCluster") && name.equals("inventory")) { + gotInventory = true; + } + super.visitFieldInsn(opcode, owner, name, desc); + } + + @Override + public void visitLineNumber(int line, Label start) { + gotInventory = false; + super.visitLineNumber(line, start); + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + if (gotInventory) { + if (opcode == Opcodes.INVOKESTATIC + && owner.equals("appeng/util/item/AEItemStack") && name.equals("create")) { + gotInventory = false; + super.visitMethodInsn(Opcodes.INVOKESTATIC, + "com/glodblock/github/coremod/hooker/CoreModHooks", + "wrapFluidPacketStack", + "(Lappeng/api/storage/data/IAEItemStack;)Lappeng/api/storage/data/IAEItemStack;", + false); + } + } else if (opcode == Opcodes.INVOKESPECIAL + && owner.equals("net/minecraft/inventory/InventoryCrafting") && name.equals("")) { + super.visitMethodInsn(Opcodes.INVOKESTATIC, + "com/glodblock/github/coremod/hooker/CoreModHooks", + "wrapCraftingBuffer", + "(Lnet/minecraft/inventory/InventoryCrafting;)Lnet/minecraft/inventory/InventoryCrafting;", + false); + } + } + + } + +} diff --git a/src/main/java/com/glodblock/github/coremod/transform/CraftingTreeNodeTransformer.java b/src/main/java/com/glodblock/github/coremod/transform/CraftingTreeNodeTransformer.java new file mode 100644 index 00000000..901423af --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/transform/CraftingTreeNodeTransformer.java @@ -0,0 +1,77 @@ +package com.glodblock.github.coremod.transform; + +import com.glodblock.github.coremod.FCClassTransformer; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class CraftingTreeNodeTransformer extends FCClassTransformer.ClassMapper { + + public static final CraftingTreeNodeTransformer INSTANCE = new CraftingTreeNodeTransformer(); + + private CraftingTreeNodeTransformer() { + // NO-OP + } + + @Override + protected ClassVisitor getClassMapper(ClassVisitor downstream) { + return new TransformCraftingTreeNode(Opcodes.ASM5, downstream); + } + + private static class TransformCraftingTreeNode extends ClassVisitor { + + TransformCraftingTreeNode(int api, ClassVisitor cv) { + super(api, cv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if (name.equals("request")) { + return new TransformRequest(api, super.visitMethod(access, name, desc, signature, exceptions)); + } + return super.visitMethod(access, name, desc, signature, exceptions); + } + + } + + private static class TransformRequest extends MethodVisitor { + + private boolean writingBytes = false; + + TransformRequest(int api, MethodVisitor mv) { + super(api, mv); + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, String desc) { + if (opcode == Opcodes.GETFIELD && owner.equals("appeng/crafting/CraftingTreeNode") && name.equals("bytes")) { + writingBytes = true; + } + super.visitFieldInsn(opcode, owner, name, desc); + } + + @Override + public void visitLineNumber(int line, Label start) { + writingBytes = false; // no write here + super.visitLineNumber(line, start); + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (writingBytes && opcode == Opcodes.INVOKEINTERFACE + && owner.equals("appeng/api/storage/data/IAEItemStack") && name.equals("getStackSize")) { + writingBytes = false; + super.visitMethodInsn(Opcodes.INVOKESTATIC, + "com/glodblock/github/coremod/hooker/CoreModHooks", + "getCraftingByteCost", + "(Lappeng/api/storage/data/IAEItemStack;)J", + false); + } else { + super.visitMethodInsn(opcode, owner, name, desc, itf); + } + } + + } + +} diff --git a/src/main/java/com/glodblock/github/coremod/transform/DualityInterfaceTransformer.java b/src/main/java/com/glodblock/github/coremod/transform/DualityInterfaceTransformer.java new file mode 100644 index 00000000..00cf5131 --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/transform/DualityInterfaceTransformer.java @@ -0,0 +1,62 @@ +package com.glodblock.github.coremod.transform; + +import com.glodblock.github.coremod.FCClassTransformer; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class DualityInterfaceTransformer extends FCClassTransformer.ClassMapper { + + public static final DualityInterfaceTransformer INSTANCE = new DualityInterfaceTransformer(); + + private DualityInterfaceTransformer() { + // NO-OP + } + + @Override + protected ClassVisitor getClassMapper(ClassVisitor downstream) { + return new TransformDualityInterface(Opcodes.ASM5, downstream); + } + + private static class TransformDualityInterface extends ClassVisitor { + + TransformDualityInterface(int api, ClassVisitor cv) { + super(api, cv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + switch (name) { + case "pushItemsOut": + case "pushPattern": + case "isBusy": + return new TransformInvAdaptorCalls(api, super.visitMethod(access, name, desc, signature, exceptions)); + default: + return super.visitMethod(access, name, desc, signature, exceptions); + } + } + + } + + private static class TransformInvAdaptorCalls extends MethodVisitor { + + TransformInvAdaptorCalls(int api, MethodVisitor mv) { + super(api, mv); + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (opcode == Opcodes.INVOKESTATIC && owner.equals("appeng/util/InventoryAdaptor") && name.equals("getAdaptor")) { + super.visitMethodInsn(Opcodes.INVOKESTATIC, + "com/glodblock/github/coremod/hooker/CoreModHooks", + "wrapInventory", + "(Lnet/minecraft/tileentity/TileEntity;Lnet/minecraftforge/common/util/ForgeDirection;)Lappeng/util/InventoryAdaptor;", + false); + } else { + super.visitMethodInsn(opcode, owner, name, desc, itf); + } + } + + } + +} diff --git a/src/main/java/com/glodblock/github/inventory/AEFluidInventory.java b/src/main/java/com/glodblock/github/inventory/AEFluidInventory.java new file mode 100644 index 00000000..b029b0b3 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/AEFluidInventory.java @@ -0,0 +1,411 @@ +package com.glodblock.github.inventory; + +import appeng.api.storage.data.IAEFluidStack; +import appeng.core.AELog; +import appeng.util.Platform; +import appeng.util.item.AEFluidStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; +import net.minecraftforge.fluids.IFluidTank; + +import java.util.Objects; + +public class AEFluidInventory implements IAEFluidTank +{ + private final IAEFluidStack[] fluids; + private final IAEFluidInventory handler; + private final int capacity; + private FluidTankInfo[] props = null; + + public AEFluidInventory( final IAEFluidInventory handler, final int slots, final int capcity ) + { + this.fluids = new IAEFluidStack[slots]; + this.handler = handler; + this.capacity = capcity; + } + + public AEFluidInventory( final IAEFluidInventory handler, final int slots ) + { + this( handler, slots, Integer.MAX_VALUE ); + } + + @Override + public void setFluidInSlot( final int slot, final IAEFluidStack fluid ) + { + if( slot >= 0 && slot < this.getSlots() ) + { + if( Objects.equals( this.fluids[slot], fluid ) ) + { + if( fluid != null && fluid.getStackSize() != this.fluids[slot].getStackSize() ) + { + this.fluids[slot].setStackSize( Math.min( fluid.getStackSize(), this.capacity ) ); + this.onContentChanged( slot ); + } + } + else + { + if( fluid == null ) + { + this.fluids[slot] = null; + } + else + { + this.fluids[slot] = fluid.copy(); + this.fluids[slot].setStackSize( Math.min( fluid.getStackSize(), this.capacity ) ); + } + + this.onContentChanged( slot ); + } + } + } + + private void onContentChanged( final int slot ) + { + if( this.handler != null && Platform.isServer() ) + { + this.handler.onFluidInventoryChanged( this, slot ); + } + } + + @Override + public IAEFluidStack getFluidInSlot( final int slot ) + { + if( slot >= 0 && slot < this.getSlots() ) + { + return this.fluids[slot]; + } + return null; + } + + @Override + public int getSlots() + { + return this.fluids.length; + } + + @Override + public FluidTankInfo[] getTankInfo(ForgeDirection from) + { + if( this.props == null ) + { + this.props = new FluidTankInfo[this.getSlots()]; + for( int i = 0; i < this.getSlots(); ++i ) + { + this.props[i] = new FluidTankInfo(new FluidTankPropertiesWrapper( i )); + } + + } + return this.props; + } + + public int fill( final int slot, final FluidStack resource, final boolean doFill ) + { + if( resource == null || resource.amount <= 0 ) + { + return 0; + } + + final IAEFluidStack fluid = this.fluids[slot]; + + if( fluid != null && !fluid.getFluidStack().isFluidEqual( resource ) ) + { + return 0; + } + + int amountToStore = this.capacity; + + if( fluid != null ) + { + amountToStore -= fluid.getStackSize(); + } + + amountToStore = Math.min( amountToStore, resource.amount ); + + if( doFill ) + { + if( fluid == null ) + { + this.setFluidInSlot( slot, AEFluidStack.create( resource ) ); + } + else + { + fluid.setStackSize( fluid.getStackSize() + amountToStore ); + this.onContentChanged( slot ); + } + } + + return amountToStore; + } + + public FluidStack drain( final int slot, final FluidStack resource, final boolean doDrain ) + { + final IAEFluidStack fluid = this.fluids[slot]; + if(fluid == null || !fluid.getFluidStack().equals(resource)) + { + return null; + } + return this.drain( slot, resource.amount, doDrain ); + } + + public FluidStack drain( final int slot, final int maxDrain, boolean doDrain ) + { + final IAEFluidStack fluid = this.fluids[slot]; + if( fluid == null || maxDrain <= 0 ) + { + return null; + } + + int drained = maxDrain; + if( fluid.getStackSize() < drained ) + { + drained = (int) fluid.getStackSize(); + } + + FluidStack stack = new FluidStack( fluid.getFluid(), drained ); + if( doDrain ) + { + fluid.setStackSize( fluid.getStackSize() - drained ); + if( fluid.getStackSize() <= 0 ) + { + this.fluids[slot] = null; + } + this.onContentChanged( slot ); + } + return stack; + } + + @Override + public int fill(ForgeDirection from, final FluidStack fluid, final boolean doFill ) + { + if( fluid == null || fluid.amount <= 0 ) + { + return 0; + } + + final FluidStack insert = fluid.copy(); + + int totalFillAmount = 0; + for( int slot = 0; slot < this.getSlots(); ++slot ) + { + int fillAmount = this.fill( slot, insert, doFill ); + totalFillAmount += fillAmount; + insert.amount -= fillAmount; + if( insert.amount <= 0 ) + { + break; + } + } + return totalFillAmount; + } + + @Override + public FluidStack drain(ForgeDirection from, final FluidStack fluid, final boolean doDrain ) + { + if( fluid == null || fluid.amount <= 0 ) + { + return null; + } + + final FluidStack resource = fluid.copy(); + + FluidStack totalDrained = null; + for( int slot = 0; slot < this.getSlots(); ++slot ) + { + FluidStack drain = this.drain( slot, resource, doDrain ); + if( drain != null ) + { + if( totalDrained == null ) + { + totalDrained = drain; + } + else + { + totalDrained.amount += drain.amount; + } + + resource.amount -= drain.amount; + if( resource.amount <= 0 ) + { + break; + } + } + } + return totalDrained; + } + + @Override + public FluidStack drain( ForgeDirection from, final int maxDrain, final boolean doDrain ) + { + if( maxDrain == 0 ) + { + return null; + } + + FluidStack totalDrained = null; + int toDrain = maxDrain; + + for( int slot = 0; slot < this.getSlots(); ++slot ) + { + if( totalDrained == null ) + { + totalDrained = this.drain( slot, toDrain, doDrain ); + if( totalDrained != null ) + { + toDrain -= totalDrained.amount; + } + } + else + { + FluidStack copy = totalDrained.copy(); + copy.amount = toDrain; + FluidStack drain = this.drain( slot, copy, doDrain ); + if( drain != null ) + { + totalDrained.amount += drain.amount; + toDrain -= drain.amount; + } + } + + if( toDrain <= 0 ) + { + break; + } + } + return totalDrained; + } + + @Override + public boolean canFill(ForgeDirection from, Fluid fluid) { + return fill(from, new FluidStack(fluid, 1), false) == 1; + } + + @Override + public boolean canDrain(ForgeDirection from, Fluid fluid) { + return drain(from, new FluidStack(fluid, 1), false) != null; + } + + public void writeToNBT( final NBTTagCompound data, final String name ) + { + final NBTTagCompound c = new NBTTagCompound(); + this.writeToNBT( c ); + data.setTag( name, c ); + } + + private void writeToNBT( final NBTTagCompound target ) + { + for( int x = 0; x < this.fluids.length; x++ ) + { + try + { + final NBTTagCompound c = new NBTTagCompound(); + + if( this.fluids[x] != null ) + { + this.fluids[x].writeToNBT( c ); + } + + target.setTag( "#" + x, c ); + } + catch( final Exception ignored ) + { + } + } + } + + public void readFromNBT( final NBTTagCompound data, final String name ) + { + final NBTTagCompound c = data.getCompoundTag( name ); + if( c != null ) + { + this.readFromNBT( c ); + } + } + + private void readFromNBT( final NBTTagCompound target ) + { + for( int x = 0; x < this.fluids.length; x++ ) + { + try + { + final NBTTagCompound c = target.getCompoundTag( "#" + x ); + + if( c != null ) + { + this.fluids[x] = AEFluidStack.loadFluidStackFromNBT( c ); + } + } + catch( final Exception e ) + { + AELog.debug( e ); + } + } + } + + private class FluidTankPropertiesWrapper implements IFluidTank + { + private final int slot; + + public FluidTankPropertiesWrapper( final int slot ) + { + this.slot = slot; + } + + @Override + public FluidStack getFluid() + { + return AEFluidInventory.this.fluids[this.slot] == null ? null : AEFluidInventory.this.fluids[this.slot].getFluidStack(); + } + + @Override + public int getFluidAmount() { + return getFluid() == null ? 0 : getFluid().amount; + } + + @Override + public int getCapacity() + { + return Math.min( AEFluidInventory.this.capacity, Integer.MAX_VALUE ); + } + + @Override + public FluidTankInfo getInfo() { + return null; + } + + @Override + public int fill(FluidStack resource, boolean doFill) { + if (resource == null || (getFluid() != null && !resource.equals(getFluid()))) return 0; + int acc = 0; + if (getFluid() == null) { + acc = Math.min(resource.amount, getCapacity()); + } + if (getFluid() != null) { + acc = Math.max(resource.amount, getCapacity() - getFluid().amount); + } + if (doFill) { + if (getFluid() == null) + AEFluidInventory.this.setFluidInSlot(this.slot, AEFluidStack.create(new FluidStack(resource.getFluid(), acc))); + else getFluid().amount += acc; + } + return acc; + } + + @Override + public FluidStack drain(int maxDrain, boolean doDrain) { + if (getFluid() == null) return null; + FluidStack remove = new FluidStack(getFluid().getFluid(), 1); + int amt = Math.min(maxDrain, getFluid().amount); + remove.amount = amt; + if (doDrain) { + if (amt == getFluid().amount) { + AEFluidInventory.this.setFluidInSlot(this.slot, null); + } + else getFluid().amount -= amt; + } + return remove; + } + } +} diff --git a/src/main/java/com/glodblock/github/inventory/AEFluidTank.java b/src/main/java/com/glodblock/github/inventory/AEFluidTank.java new file mode 100644 index 00000000..a2d2ea41 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/AEFluidTank.java @@ -0,0 +1,90 @@ +package com.glodblock.github.inventory; + +import appeng.api.storage.data.IAEFluidStack; +import appeng.util.Platform; +import appeng.util.item.AEFluidStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTank; +import net.minecraftforge.fluids.FluidTankInfo; + +public class AEFluidTank extends FluidTank implements IAEFluidTank +{ + private final IAEFluidInventory host; + + public AEFluidTank( IAEFluidInventory host, int capacity ) + { + super( capacity ); + this.host = host; + if( host instanceof TileEntity) { + this.tile = (TileEntity) host; + } + } + + protected void onContentsChanged() + { + if( this.host != null && Platform.isServer() ) + { + this.host.onFluidInventoryChanged( this, 0 ); + } + } + + @Override + public void setFluidInSlot( int slot, IAEFluidStack fluid ) + { + if( slot == 0 ) + { + this.setFluid( fluid == null ? null : fluid.getFluidStack() ); + this.onContentsChanged(); + } + } + + @Override + public IAEFluidStack getFluidInSlot(int slot ) + { + if( slot == 0 ) + { + return AEFluidStack.create( this.getFluid() ); + } + return null; + } + + @Override + public int getSlots() + { + return 1; + } + + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + return super.fill(resource, doFill); + } + + @Override + public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) { + if (resource == null || !resource.equals(this.getFluid())) return null; + return super.drain(resource.amount, doDrain); + } + + @Override + public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) { + return super.drain(maxDrain, doDrain); + } + + @Override + public boolean canFill(ForgeDirection from, Fluid fluid) { + return super.fill(new FluidStack(fluid, 1), false) == 1; + } + + @Override + public boolean canDrain(ForgeDirection from, Fluid fluid) { + return drain(ForgeDirection.UNKNOWN, new FluidStack(fluid, 1), false) != null; + } + + @Override + public FluidTankInfo[] getTankInfo(ForgeDirection from) { + return new FluidTankInfo[]{super.getInfo()}; + } +} diff --git a/src/main/java/com/glodblock/github/inventory/AeItemStackHandler.java b/src/main/java/com/glodblock/github/inventory/AeItemStackHandler.java new file mode 100644 index 00000000..01305c0f --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/AeItemStackHandler.java @@ -0,0 +1,84 @@ +package com.glodblock.github.inventory; + +import appeng.api.storage.data.IAEItemStack; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +public class AeItemStackHandler implements IInventory { + + private final AeStackInventory inv; + + public AeItemStackHandler(AeStackInventory inv) { + this.inv = inv; + } + + public AeStackInventory getAeInventory() { + return inv; + } + + @Override + public int getSizeInventory() { + return inv.getSlotCount(); + } + + public ItemStack getStackInSlot(int slot) { + IAEItemStack stack = inv.getStack(slot); + return stack != null ? stack.getItemStack() : null; + } + + @Override + public ItemStack decrStackSize(int p_70298_1_, int p_70298_2_) { + return null; + } + + @Override + public ItemStack getStackInSlotOnClosing(int p_70304_1_) { + return null; + } + + @Override + public void setInventorySlotContents(int p_70299_1_, ItemStack p_70299_2_) { + + } + + @Override + public String getInventoryName() { + return "AeItemStackHandler"; + } + + @Override + public boolean hasCustomInventoryName() { + return false; + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + @Override + public void markDirty() { + } + + @Override + public boolean isUseableByPlayer(EntityPlayer p_70300_1_) { + return false; + } + + @Override + public void openInventory() { + + } + + @Override + public void closeInventory() { + + } + + @Override + public boolean isItemValidForSlot(int p_94041_1_, ItemStack p_94041_2_) { + return false; + } + +} diff --git a/src/main/java/com/glodblock/github/inventory/AeStackInventory.java b/src/main/java/com/glodblock/github/inventory/AeStackInventory.java new file mode 100644 index 00000000..2dba2d2c --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/AeStackInventory.java @@ -0,0 +1,19 @@ +package com.glodblock.github.inventory; + +import appeng.api.storage.data.IAEStack; + +import javax.annotation.Nullable; +import java.util.stream.Stream; + +public interface AeStackInventory> extends Iterable { + + int getSlotCount(); + + @Nullable + T getStack(int slot); + + void setStack(int slot, @Nullable T stack); + + Stream stream(); + +} diff --git a/src/main/java/com/glodblock/github/inventory/AeStackInventoryImpl.java b/src/main/java/com/glodblock/github/inventory/AeStackInventoryImpl.java new file mode 100644 index 00000000..53bc590d --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/AeStackInventoryImpl.java @@ -0,0 +1,102 @@ +package com.glodblock.github.inventory; + +import appeng.api.storage.StorageChannel; +import appeng.api.storage.data.IAEStack; +import appeng.tile.inventory.IAEAppEngInventory; +import appeng.util.item.AEFluidStack; +import appeng.util.item.AEItemStack; +import com.glodblock.github.util.ObjectArrayIterator; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.Constants; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Iterator; +import java.util.stream.Stream; + +public class AeStackInventoryImpl > implements AeStackInventory { + + private final StorageChannel channel; + private final T[] inv; + private final IAEAppEngInventory owner; + + @SuppressWarnings("unchecked") + public AeStackInventoryImpl(StorageChannel channel, int slotCount, @Nullable IAEAppEngInventory owner) { + this.channel = channel; + this.inv = (T[])new IAEStack[slotCount]; + this.owner = owner; + } + + public AeStackInventoryImpl(StorageChannel channel, int slotCount) { + this(channel, slotCount, null); + } + + @Override + public int getSlotCount() { + return inv.length; + } + + @Override + @Nullable + public T getStack(int slot) { + return inv[slot]; + } + + @Override + public void setStack(int slot, @Nullable T stack) { + inv[slot] = stack; + if (owner != null) { + owner.saveChanges(); + } + } + + @Override + public Iterator iterator() { + return new ObjectArrayIterator<>(inv); + } + + @Override + public Stream stream() { + return Arrays.stream(inv); + } + + public void writeToNbt(NBTTagCompound tag) { + NBTTagList stacksTag = new NBTTagList(); + for (T stack : inv) { + if (stack == null) { + stacksTag.appendTag(new NBTTagCompound()); + } else { + NBTTagCompound stackTag = new NBTTagCompound(); + stack.writeToNBT(stackTag); + stacksTag.appendTag(stackTag); + } + } + tag.setTag("Contents", stacksTag); + } + + public void writeToNbt(NBTTagCompound parentTag, String key) { + NBTTagCompound tag = new NBTTagCompound(); + writeToNbt(tag); + parentTag.setTag(key, tag); + } + + @SuppressWarnings("unchecked") + public void readFromNbt(NBTTagCompound tag) { + NBTTagList stacksTag = tag.getTagList("Contents", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < inv.length; i++) { + NBTTagCompound stackTag = stacksTag.getCompoundTagAt(i); + if (channel == StorageChannel.ITEMS) { + inv[i] = stackTag == null ? null : (T) AEItemStack.loadItemStackFromNBT(stackTag); + } + else { + inv[i] = stackTag == null ? null : (T) AEFluidStack.loadFluidStackFromNBT(stackTag); + } + } + } + + public void readFromNbt(NBTTagCompound parentTag, String key) { + readFromNbt(parentTag.getCompoundTag(key)); + } + +} diff --git a/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryAdaptor.java b/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryAdaptor.java new file mode 100644 index 00000000..69e5c2e1 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryAdaptor.java @@ -0,0 +1,161 @@ +package com.glodblock.github.inventory; + +import appeng.api.config.FuzzyMode; +import appeng.util.InventoryAdaptor; +import appeng.util.inv.IInventoryDestination; +import appeng.util.inv.ItemSlot; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.common.tile.TileFluidInterface; +import com.glodblock.github.util.Ae2Reflect; +import com.glodblock.github.util.Util; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; +import net.minecraftforge.fluids.IFluidHandler; + +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.Iterator; + +public class FluidConvertingInventoryAdaptor extends InventoryAdaptor { + + public static InventoryAdaptor wrap(TileEntity capProvider, EnumFacing face) { + // sometimes i wish 1.7.10 has cap system. + ForgeDirection f = Util.from(face); + TileEntity inter = capProvider.getWorldObj().getTileEntity(capProvider.xCoord + f.offsetX, capProvider.yCoord + f.offsetY, capProvider.zCoord + f.offsetZ); + if (!(inter instanceof TileFluidInterface)) return InventoryAdaptor.getAdaptor(capProvider, f); + IInventory item = capProvider instanceof IInventory ? (IInventory) capProvider : null; + IFluidHandler fluid = capProvider instanceof IFluidHandler ? (IFluidHandler) capProvider : null; + return new FluidConvertingInventoryAdaptor(item, fluid, face); + } + + private final InventoryAdaptor invItems; + private final IFluidHandler invFluids; + private final ForgeDirection side; + + public FluidConvertingInventoryAdaptor(@Nullable IInventory invItems, @Nullable IFluidHandler invFluids, EnumFacing facing) { + this.invItems = invItems != null ? InventoryAdaptor.getAdaptor(invItems, Util.from(facing)) : null; + this.invFluids = invFluids; + this.side = Util.from(facing); + } + + @Override + public ItemStack addItems(ItemStack toBeAdded) { + if (toBeAdded.getItem() instanceof ItemFluidPacket) { + if (invFluids != null) { + FluidStack fluid = ItemFluidPacket.getFluidStack(toBeAdded); + if (fluid != null) { + int filled = invFluids.fill(side, fluid, true); + if (filled > 0) { + fluid.amount -= filled; + return ItemFluidPacket.newStack(fluid); + } + } + } + return toBeAdded; + } + return invItems != null ? invItems.addItems(toBeAdded) : toBeAdded; + } + + @Override + public ItemStack simulateAdd(ItemStack toBeSimulated) { + if (toBeSimulated.getItem() instanceof ItemFluidPacket) { + if (invFluids != null) { + FluidStack fluid = ItemFluidPacket.getFluidStack(toBeSimulated); + if (fluid != null) { + int filled = invFluids.fill(side, fluid, false); + if (filled > 0) { + fluid.amount -= filled; + return ItemFluidPacket.newStack(fluid); + } + } + } + return toBeSimulated; + } + return invItems != null ? invItems.simulateAdd(toBeSimulated) : toBeSimulated; + } + + @Override + public ItemStack removeItems(int amount, ItemStack filter, IInventoryDestination destination) { + return invItems != null ? invItems.removeItems(amount, filter, destination) : null; + } + + @Override + public ItemStack simulateRemove(int amount, ItemStack filter, IInventoryDestination destination) { + return invItems != null ? invItems.simulateRemove(amount, filter, destination) : null; + } + + @Override + public ItemStack removeSimilarItems(int amount, ItemStack filter, FuzzyMode fuzzyMode, IInventoryDestination destination) { + return invItems != null ? invItems.removeSimilarItems(amount, filter, fuzzyMode, destination) : null; + } + + @Override + public ItemStack simulateSimilarRemove(int amount, ItemStack filter, FuzzyMode fuzzyMode, IInventoryDestination destination) { + return invItems != null ? invItems.simulateSimilarRemove(amount, filter, fuzzyMode, destination) : null; + } + + @Override + public boolean containsItems() { + if (invFluids != null) { + for (FluidTankInfo tank : invFluids.getTankInfo(side)) { + FluidStack fluid = tank.fluid; + if (fluid != null && fluid.amount > 0) { + return true; + } + } + } + return invItems != null && invItems.containsItems(); + } + + public boolean hasSlots() { + return (invFluids != null && invFluids.getTankInfo(side).length > 0) + || (invItems != null); + } + + @Override + public Iterator iterator() { + return new SlotIterator( + invFluids != null ? invFluids.getTankInfo(side) : new FluidTankInfo[0], + invItems != null ? invItems.iterator() : Collections.emptyIterator()); + } + + private static class SlotIterator implements Iterator { + + private final FluidTankInfo[] tanks; + private final Iterator itemSlots; + private int nextSlotIndex = 0; + + SlotIterator(FluidTankInfo[] tanks, Iterator itemSlots) { + this.tanks = tanks; + this.itemSlots = itemSlots; + } + + @Override + public boolean hasNext() { + return nextSlotIndex < tanks.length || itemSlots.hasNext(); + } + + @Override + public ItemSlot next() { + if (nextSlotIndex < tanks.length) { + FluidStack fluid = tanks[nextSlotIndex].fluid; + ItemSlot slot = new ItemSlot(); + slot.setSlot(nextSlotIndex++); + slot.setItemStack(fluid != null ? ItemFluidPacket.newStack(fluid) : null); + Ae2Reflect.setItemSlotExtractable(slot, false); + return slot; + } else { + ItemSlot slot = itemSlots.next(); + slot.setSlot(nextSlotIndex++); + return slot; + } + } + + } + +} diff --git a/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryCrafting.java b/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryCrafting.java new file mode 100644 index 00000000..48bf3156 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryCrafting.java @@ -0,0 +1,32 @@ +package com.glodblock.github.inventory; + +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +public class FluidConvertingInventoryCrafting extends InventoryCrafting { + + public FluidConvertingInventoryCrafting(Container container, int width, int height) { + super(container, width, height); + } + + @Override + public void setInventorySlotContents(int index, ItemStack stack) { + if (stack.getItem() instanceof ItemFluidDrop) { + FluidStack fluid = ItemFluidDrop.getFluidStack(stack); + if (fluid != null) { + super.setInventorySlotContents(index, ItemFluidPacket.newStack(new FluidStack(fluid, stack.stackSize))); + } else { + // wtf? + super.setInventorySlotContents(index, ItemFluidPacket.newStack(new FluidStack(FluidRegistry.WATER, 1000))); + } + } else { + super.setInventorySlotContents(index, stack); + } + } + +} diff --git a/src/main/java/com/glodblock/github/inventory/IAEFluidInventory.java b/src/main/java/com/glodblock/github/inventory/IAEFluidInventory.java new file mode 100644 index 00000000..79ed92c7 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/IAEFluidInventory.java @@ -0,0 +1,7 @@ +package com.glodblock.github.inventory; + +@FunctionalInterface +public interface IAEFluidInventory +{ + void onFluidInventoryChanged( final IAEFluidTank inv, final int slot ); +} diff --git a/src/main/java/com/glodblock/github/inventory/IAEFluidTank.java b/src/main/java/com/glodblock/github/inventory/IAEFluidTank.java new file mode 100644 index 00000000..8fde96a1 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/IAEFluidTank.java @@ -0,0 +1,13 @@ +package com.glodblock.github.inventory; + +import appeng.api.storage.data.IAEFluidStack; +import net.minecraftforge.fluids.IFluidHandler; + +public interface IAEFluidTank extends IFluidHandler { + void setFluidInSlot( final int slot, final IAEFluidStack fluid ); + + IAEFluidStack getFluidInSlot( final int slot ); + + int getSlots(); + +} diff --git a/src/main/java/com/glodblock/github/inventory/InventoryHandler.java b/src/main/java/com/glodblock/github/inventory/InventoryHandler.java new file mode 100644 index 00000000..91193715 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/InventoryHandler.java @@ -0,0 +1,51 @@ +package com.glodblock.github.inventory; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.network.CPacketSwitchGuis; +import com.glodblock.github.util.BlockPos; +import cpw.mods.fml.common.network.IGuiHandler; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; + +import javax.annotation.Nullable; + +public class InventoryHandler implements IGuiHandler { + + public static void switchGui(GuiType guiType) { + FluidCraft.proxy.netHandler.sendToServer(new CPacketSwitchGuis(guiType)); + } + + public static void openGui(EntityPlayer player, World world, BlockPos pos, EnumFacing face, GuiType guiType) { + player.openGui(FluidCraft.INSTANCE, + (guiType.ordinal() << 3) | face.ordinal(), world, pos.getX(), pos.getY(), pos.getZ()); + } + + @Nullable + @Override + public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + int faceOrd = id & 0x7; + if (faceOrd > EnumFacing.values().length) { + return null; + } + EnumFacing face = EnumFacing.getFront(faceOrd); + GuiType type = GuiType.getByOrdinal(id >>> 3); + return type != null ? type.guiFactory.createServerGui(player, world, x, y, z, face) : null; + } + + @SideOnly(Side.CLIENT) + @Nullable + @Override + public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + int faceOrd = id & 0x7; + if (faceOrd > EnumFacing.values().length) { + return null; + } + EnumFacing face = EnumFacing.getFront(faceOrd); + GuiType type = GuiType.getByOrdinal(id >>> 3); + return type != null ? type.guiFactory.createClientGui(player, world, x, y, z, face) : null; + } +} diff --git a/src/main/java/com/glodblock/github/inventory/PatternConsumer.java b/src/main/java/com/glodblock/github/inventory/PatternConsumer.java new file mode 100644 index 00000000..ae8ce6d8 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/PatternConsumer.java @@ -0,0 +1,9 @@ +package com.glodblock.github.inventory; + +import appeng.api.storage.data.IAEItemStack; + +public interface PatternConsumer { + + void acceptPattern(IAEItemStack[] inputs, IAEItemStack[] outputs); + +} diff --git a/src/main/java/com/glodblock/github/inventory/gui/GuiFactory.java b/src/main/java/com/glodblock/github/inventory/gui/GuiFactory.java new file mode 100644 index 00000000..df59218e --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/gui/GuiFactory.java @@ -0,0 +1,20 @@ +package com.glodblock.github.inventory.gui; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; + +import javax.annotation.Nullable; + +public interface GuiFactory { + + @Nullable + Object createServerGui(EntityPlayer player, World world, int x, int y, int z, EnumFacing face); + + @SideOnly(Side.CLIENT) + @Nullable + Object createClientGui(EntityPlayer player, World world, int x, int y, int z, EnumFacing face); + +} diff --git a/src/main/java/com/glodblock/github/inventory/gui/GuiType.java b/src/main/java/com/glodblock/github/inventory/gui/GuiType.java new file mode 100644 index 00000000..b8e69fa3 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/gui/GuiType.java @@ -0,0 +1,107 @@ +package com.glodblock.github.inventory.gui; + +import appeng.api.storage.ITerminalHost; +import appeng.container.implementations.ContainerCraftAmount; +import appeng.container.implementations.ContainerCraftingStatus; +import com.glodblock.github.client.gui.*; +import com.glodblock.github.client.gui.container.ContainerFluidCraftConfirm; +import com.glodblock.github.client.gui.container.ContainerFluidPacketDecoder; +import com.glodblock.github.client.gui.container.ContainerFluidPatternEncoder; +import com.glodblock.github.client.gui.container.ContainerFluidPatternTerminal; +import com.glodblock.github.common.parts.PartFluidPatternTerminal; +import com.glodblock.github.common.tile.TileFluidPacketDecoder; +import com.glodblock.github.common.tile.TileFluidPatternEncoder; +import com.google.common.collect.ImmutableList; +import net.minecraft.entity.player.EntityPlayer; + +import javax.annotation.Nullable; +import java.util.List; + +public enum GuiType { + + FLUID_PAT_TERM_CRAFTING_STATUS(new PartGuiFactory(PartFluidPatternTerminal.class) { + @Override + protected Object createServerGui(EntityPlayer player, PartFluidPatternTerminal inv) { + return new ContainerCraftingStatus(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, PartFluidPatternTerminal inv) { + return new GuiFluidPatternTerminalCraftingStatus(player.inventory, inv); + } + }), + + FLUID_PATTERN_TERMINAL(new PartGuiFactory(ITerminalHost.class) { + @Override + protected Object createServerGui(EntityPlayer player, ITerminalHost inv) { + return new ContainerFluidPatternTerminal(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, ITerminalHost inv) { + return new GuiFluidPatternTerminal(player.inventory, inv); + } + }), + + FLUID_PATTERN_ENCODER(new TileGuiFactory(TileFluidPatternEncoder.class) { + @Override + protected Object createServerGui(EntityPlayer player, TileFluidPatternEncoder inv) { + return new ContainerFluidPatternEncoder(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, TileFluidPatternEncoder inv) { + return new GuiFluidPatternEncoder(player.inventory, inv); + } + }), + + FLUID_CRAFTING_CONFIRM(new PartGuiFactory(PartFluidPatternTerminal.class) { + @Override + protected Object createServerGui(EntityPlayer player, PartFluidPatternTerminal inv) { + return new ContainerFluidCraftConfirm(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, PartFluidPatternTerminal inv) { + return new GuiFluidCraftConfirm(player.inventory, inv); + } + }), + + FLUID_CRAFTING_AMOUNT(new PartGuiFactory(PartFluidPatternTerminal.class) { + @Override + protected Object createServerGui(EntityPlayer player, PartFluidPatternTerminal inv) { + return new ContainerCraftAmount(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, PartFluidPatternTerminal inv) { + return new GuiFluidCraftAmount(player.inventory, inv); + } + }), + + FLUID_PACKET_DECODER(new TileGuiFactory(TileFluidPacketDecoder.class) { + @Override + protected Object createServerGui(EntityPlayer player, TileFluidPacketDecoder inv) { + return new ContainerFluidPacketDecoder(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, TileFluidPacketDecoder inv) { + return new GuiFluidPacketDecoder(player.inventory, inv); + } + }); + + public static final List VALUES = ImmutableList.copyOf(values()); + + @Nullable + public static GuiType getByOrdinal(int ordinal) { + return ordinal < 0 || ordinal >= VALUES.size() ? null : VALUES.get(ordinal); + } + + public final GuiFactory guiFactory; + + GuiType(GuiFactory guiFactory) { + this.guiFactory = guiFactory; + } + +} diff --git a/src/main/java/com/glodblock/github/inventory/gui/MouseRegionManager.java b/src/main/java/com/glodblock/github/inventory/gui/MouseRegionManager.java new file mode 100644 index 00000000..e87bef8b --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/gui/MouseRegionManager.java @@ -0,0 +1,84 @@ +package com.glodblock.github.inventory.gui; + +import com.glodblock.github.util.Ae2Reflect; +import net.minecraft.client.audio.PositionedSoundRecord; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + +public class MouseRegionManager { + private final GuiContainer gui; + private final List regions = new ArrayList<>(); + private final FontRenderer font; + + public MouseRegionManager(GuiContainer gui, FontRenderer font) { + this.gui = gui; + this.font = font; + } + + public void addRegion(int x, int y, int width, int height, Handler handler) { + regions.add(new Region(x, y, width, height, handler)); + } + + public boolean onClick(int mX, int mY, int button) { + mX -= Ae2Reflect.getGuiLeft(gui); + mY -= Ae2Reflect.getGuiTop(gui); + for (Region region : regions) { + if (region.containsMouse(mX, mY) && region.handler.onClick(button)) { + gui.mc.getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1F)); + return false; + } + } + return true; + } + + public void render(int mX, int mY) { + mX -= Ae2Reflect.getGuiLeft(gui); + mY -= Ae2Reflect.getGuiTop(gui); + for (Region region : regions) { + if (region.containsMouse(mX, mY)) { + List tooltip = region.handler.getTooltip(); + if (tooltip != null) { + return; + } + } + } + } + + private static class Region { + + private final int x, y, width, height; + private final Handler handler; + + Region(int x, int y, int width, int height, Handler handler) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.handler = handler; + } + + boolean containsMouse(int mX, int mY) { + return mX >= x && mX < x + width && mY >= y && mY < y + height; + } + + } + + public interface Handler { + + @Nullable + default List getTooltip() { + return null; + } + + default boolean onClick(int button) { + return false; + } + + } + +} diff --git a/src/main/java/com/glodblock/github/inventory/gui/PartGuiFactory.java b/src/main/java/com/glodblock/github/inventory/gui/PartGuiFactory.java new file mode 100644 index 00000000..11e5a725 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/gui/PartGuiFactory.java @@ -0,0 +1,28 @@ +package com.glodblock.github.inventory.gui; + +import appeng.api.parts.IPart; +import appeng.api.parts.IPartHost; +import com.glodblock.github.util.Util; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; + +import javax.annotation.Nullable; + +public abstract class PartGuiFactory extends TileGuiFactory { + + PartGuiFactory(Class invClass) { + super(invClass); + } + + @Nullable + @Override + protected T getInventory(TileEntity tile, EnumFacing face) { + if (tile instanceof IPartHost) { + IPart part = ((IPartHost)tile).getPart(Util.from(face)); + if (invClass.isInstance(part)) { + return invClass.cast(part); + } + } + return null; + } +} diff --git a/src/main/java/com/glodblock/github/inventory/gui/TileGuiFactory.java b/src/main/java/com/glodblock/github/inventory/gui/TileGuiFactory.java new file mode 100644 index 00000000..4ac4eab1 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/gui/TileGuiFactory.java @@ -0,0 +1,66 @@ +package com.glodblock.github.inventory.gui; + +import appeng.container.AEBaseContainer; +import appeng.container.ContainerOpenContext; +import com.glodblock.github.util.Util; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; + +import javax.annotation.Nullable; + +public abstract class TileGuiFactory implements GuiFactory { + + protected final Class invClass; + + TileGuiFactory(Class invClass) { + this.invClass = invClass; + } + + @Nullable + protected T getInventory(TileEntity tile, EnumFacing face) { + return invClass.isInstance(tile) ? invClass.cast(tile) : null; + } + + @Nullable + @Override + public Object createServerGui(EntityPlayer player, World world, int x, int y, int z, EnumFacing face) { + TileEntity tile = world.getTileEntity(x, y, z); + if (tile == null) { + return null; + } + T inv = getInventory(tile, face); + if (inv == null) { + return null; + } + Object gui = createServerGui(player, inv); + if (gui instanceof AEBaseContainer) { + ContainerOpenContext ctx = new ContainerOpenContext(inv); + ctx.setWorld(world); + ctx.setX(x); + ctx.setY(y); + ctx.setZ(z); + ctx.setSide(Util.from(face)); + ((AEBaseContainer)gui).setOpenContext(ctx); + } + return gui; + } + + @Nullable + protected abstract Object createServerGui(EntityPlayer player, T inv); + + @Nullable + @Override + public Object createClientGui(EntityPlayer player, World world, int x, int y, int z, EnumFacing face) { + TileEntity tile = world.getTileEntity(x, y, z); + if (tile == null) { + return null; + } + T inv = getInventory(tile, face); + return inv != null ? createClientGui(player, inv) : null; + } + + @Nullable + protected abstract Object createClientGui(EntityPlayer player, T inv); +} diff --git a/src/main/java/com/glodblock/github/inventory/slot/SlotFluid.java b/src/main/java/com/glodblock/github/inventory/slot/SlotFluid.java new file mode 100644 index 00000000..9390a301 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/slot/SlotFluid.java @@ -0,0 +1,15 @@ +package com.glodblock.github.inventory.slot; + +import appeng.api.storage.data.IAEItemStack; + +import javax.annotation.Nullable; + +public interface SlotFluid { + + @Nullable + IAEItemStack getAeStack(); + + void setAeStack(@Nullable IAEItemStack stack, boolean sync); + + +} diff --git a/src/main/java/com/glodblock/github/inventory/slot/SlotSingleItem.java b/src/main/java/com/glodblock/github/inventory/slot/SlotSingleItem.java new file mode 100644 index 00000000..f664ec39 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/slot/SlotSingleItem.java @@ -0,0 +1,102 @@ +package com.glodblock.github.inventory.slot; + +import com.glodblock.github.util.Util; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +public class SlotSingleItem extends Slot { + + private final Slot delegate; + + public SlotSingleItem(Slot delegate) { + super(delegate.inventory, delegate.getSlotIndex(), delegate.xDisplayPosition, delegate.yDisplayPosition); + this.delegate = delegate; + } + + @Override + public ItemStack getStack() { + ItemStack stack = delegate.getStack(); + return stack == null ? null : Util.copyStackWithSize(stack, 1); + } + + // delegated + + @Override + public void onSlotChange(ItemStack p_75220_1_, ItemStack p_75220_2_) { + delegate.onSlotChange(p_75220_1_, p_75220_2_); + } + + @Override + public void onPickupFromSlot(EntityPlayer thePlayer, ItemStack stack) { + delegate.onPickupFromSlot(thePlayer, stack); + } + + @Override + public boolean isItemValid(ItemStack stack) { + return delegate.isItemValid(stack); + } + + @Override + public boolean getHasStack() { + return delegate.getHasStack(); + } + + @Override + public void putStack(ItemStack stack) { + delegate.putStack(stack); + } + + @Override + public void onSlotChanged() { + delegate.onSlotChanged(); + } + + @Override + public int getSlotStackLimit() { + return delegate.getSlotStackLimit(); + } + + @Override + public ItemStack decrStackSize(int amount) { + return delegate.decrStackSize(amount); + } + + @Override + public boolean isSlotInInventory(IInventory inv, int slotIn) { + return delegate.isSlotInInventory(inv, slotIn); + } + + @Override + public boolean canTakeStack(EntityPlayer playerIn) { + return delegate.canTakeStack(playerIn); + } + + @Override + @SideOnly(Side.CLIENT) + public boolean func_111238_b() { + return delegate.func_111238_b(); + } + + @Override + @SideOnly(Side.CLIENT) + public ResourceLocation getBackgroundIconTexture() { + return delegate.getBackgroundIconTexture(); + } + + @Override + @SideOnly(Side.CLIENT) + public void setBackgroundIconTexture(ResourceLocation texture) { + delegate.setBackgroundIconTexture(texture); + } + + @Override + public int getSlotIndex() { + return delegate.getSlotIndex(); + } + +} diff --git a/src/main/java/com/glodblock/github/loader/ChannelLoader.java b/src/main/java/com/glodblock/github/loader/ChannelLoader.java new file mode 100644 index 00000000..317a7f5c --- /dev/null +++ b/src/main/java/com/glodblock/github/loader/ChannelLoader.java @@ -0,0 +1,22 @@ +package com.glodblock.github.loader; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.network.*; +import cpw.mods.fml.relauncher.Side; + +public class ChannelLoader implements Runnable { + @Override + public void run() { + int id = 0; + FluidCraft.proxy.netHandler.registerMessage(new CPacketSwitchGuis.Handler(), CPacketSwitchGuis.class, id ++, Side.SERVER); + FluidCraft.proxy.netHandler.registerMessage(new CPacketFluidPatternTermBtns.Handler(), CPacketFluidPatternTermBtns.class, id ++, Side.SERVER); + FluidCraft.proxy.netHandler.registerMessage(new CPacketEncodePattern.Handler(), CPacketEncodePattern.class, id ++, Side.SERVER); + FluidCraft.proxy.netHandler.registerMessage(new SPacketMEInventoryUpdate.Handler(), SPacketMEInventoryUpdate.class, id ++, Side.CLIENT); + FluidCraft.proxy.netHandler.registerMessage(new CPacketCraftRequest.Handler(), CPacketCraftRequest.class, id ++, Side.SERVER); + FluidCraft.proxy.netHandler.registerMessage(new CPacketInventoryAction.Handler(), CPacketInventoryAction.class, id ++, Side.SERVER); + FluidCraft.proxy.netHandler.registerMessage(new CPacketSetTargetItem.Handler(), CPacketSetTargetItem.class, id ++, Side.SERVER); + FluidCraft.proxy.netHandler.registerMessage(new CPacketSwitchGuis.Handler(), CPacketSwitchGuis.class, id ++, Side.CLIENT); + FluidCraft.proxy.netHandler.registerMessage(new SPacketFluidSlot.Handler(), SPacketFluidSlot.class, id ++, Side.SERVER); + FluidCraft.proxy.netHandler.registerMessage(new CPacketTransferRecipe.Handler(), CPacketTransferRecipe.class, id ++, Side.SERVER); + } +} diff --git a/src/main/java/com/glodblock/github/loader/ItemAndBlockHolder.java b/src/main/java/com/glodblock/github/loader/ItemAndBlockHolder.java new file mode 100644 index 00000000..67d1d1ba --- /dev/null +++ b/src/main/java/com/glodblock/github/loader/ItemAndBlockHolder.java @@ -0,0 +1,24 @@ +package com.glodblock.github.loader; + +import com.glodblock.github.common.block.BlockFluidDiscretizer; +import com.glodblock.github.common.block.BlockFluidInterface; +import com.glodblock.github.common.block.BlockFluidPacketDecoder; +import com.glodblock.github.common.block.BlockFluidPatternEncoder; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidEncodedPattern; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.common.item.ItemPartFluidPatternTerminal; + +public class ItemAndBlockHolder { + + public static ItemFluidDrop DROP = new ItemFluidDrop().register(); + public static ItemFluidEncodedPattern PATTERN = new ItemFluidEncodedPattern().register(); + public static ItemPartFluidPatternTerminal FLUID_TERMINAL = new ItemPartFluidPatternTerminal().register(); + public static ItemFluidPacket PACKET = new ItemFluidPacket().register(); + + public static BlockFluidDiscretizer DISCRETIZER = new BlockFluidDiscretizer().register(); + public static BlockFluidPatternEncoder ENCODER = new BlockFluidPatternEncoder().register(); + public static BlockFluidPacketDecoder DECODER = new BlockFluidPacketDecoder().register(); + public static BlockFluidInterface INTERFACE = new BlockFluidInterface().register(); + +} diff --git a/src/main/java/com/glodblock/github/loader/ListenerLoader.java b/src/main/java/com/glodblock/github/loader/ListenerLoader.java new file mode 100644 index 00000000..16fd725f --- /dev/null +++ b/src/main/java/com/glodblock/github/loader/ListenerLoader.java @@ -0,0 +1,12 @@ +package com.glodblock.github.loader; + +import com.glodblock.github.client.ClientHelper; + +public class ListenerLoader implements Runnable { + + @Override + public void run() { + ClientHelper.register(); + } + +} diff --git a/src/main/java/com/glodblock/github/loader/RenderLoader.java b/src/main/java/com/glodblock/github/loader/RenderLoader.java new file mode 100644 index 00000000..8ecf61b2 --- /dev/null +++ b/src/main/java/com/glodblock/github/loader/RenderLoader.java @@ -0,0 +1,14 @@ +package com.glodblock.github.loader; + +import com.glodblock.github.client.render.ItemDropRender; +import com.glodblock.github.client.render.ItemPacketRender; + +public class RenderLoader implements Runnable { + + @Override + public void run() { + new ItemDropRender(); + new ItemPacketRender(); + } + +} diff --git a/src/main/java/com/glodblock/github/nei/FluidPatternTerminalRecipeTransferHandler.java b/src/main/java/com/glodblock/github/nei/FluidPatternTerminalRecipeTransferHandler.java new file mode 100644 index 00000000..ea2b5ebb --- /dev/null +++ b/src/main/java/com/glodblock/github/nei/FluidPatternTerminalRecipeTransferHandler.java @@ -0,0 +1,50 @@ +package com.glodblock.github.nei; + +import codechicken.nei.api.IOverlayHandler; +import codechicken.nei.recipe.IRecipeHandler; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.gui.GuiFluidPatternTerminal; +import com.glodblock.github.nei.object.OrderStack; +import com.glodblock.github.nei.recipes.FluidRecipe; +import com.glodblock.github.network.CPacketTransferRecipe; +import net.minecraft.client.gui.inventory.GuiContainer; + +import java.util.HashSet; +import java.util.List; + +public class FluidPatternTerminalRecipeTransferHandler implements IOverlayHandler { + + public static final FluidPatternTerminalRecipeTransferHandler INSTANCE = new FluidPatternTerminalRecipeTransferHandler(); + public static final HashSet notOtherSet = new HashSet<>(); + public static final HashSet craftSet = new HashSet<>(); + + static { + notOtherSet.add("smelting"); + notOtherSet.add("brewing"); + craftSet.add("crafting"); + craftSet.add("crafting2x2"); + } + + @Override + public void overlayRecipe(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, boolean shift) { + if (isCorrectGui(firstGui)) { + List> in = FluidRecipe.getPackageInputs(recipe, recipeIndex); + List> out = FluidRecipe.getPackageOutputs(recipe, recipeIndex, !notUseOther(recipe)); + boolean craft = shouldCraft(recipe); + FluidCraft.proxy.netHandler.sendToServer(new CPacketTransferRecipe(in, out, craft)); + } + } + + private boolean isCorrectGui(GuiContainer firstGui) { + return firstGui instanceof GuiFluidPatternTerminal; + } + + private boolean notUseOther(IRecipeHandler recipeHandler) { + return notOtherSet.contains(recipeHandler.getOverlayIdentifier()); + } + + private boolean shouldCraft(IRecipeHandler recipeHandler) { + return craftSet.contains(recipeHandler.getOverlayIdentifier()); + } + +} diff --git a/src/main/java/com/glodblock/github/nei/NEI_FC_Config.java b/src/main/java/com/glodblock/github/nei/NEI_FC_Config.java new file mode 100644 index 00000000..1b327f05 --- /dev/null +++ b/src/main/java/com/glodblock/github/nei/NEI_FC_Config.java @@ -0,0 +1,27 @@ +package com.glodblock.github.nei; + +import codechicken.nei.api.API; +import codechicken.nei.api.IConfigureNEI; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.gui.GuiFluidPatternTerminal; +import com.glodblock.github.nei.recipes.FluidRecipe; + +public class NEI_FC_Config implements IConfigureNEI { + + @Override + public void loadConfig() { + for (String identifier : FluidRecipe.getSupportRecipes()) { + API.registerGuiOverlayHandler(GuiFluidPatternTerminal.class, FluidPatternTerminalRecipeTransferHandler.INSTANCE, identifier); + } + } + + @Override + public String getName() { + return FluidCraft.MODNAME; + } + + @Override + public String getVersion() { + return FluidCraft.VERSION; + } +} diff --git a/src/main/java/com/glodblock/github/nei/object/IFluidDummy.java b/src/main/java/com/glodblock/github/nei/object/IFluidDummy.java new file mode 100644 index 00000000..acc7d17a --- /dev/null +++ b/src/main/java/com/glodblock/github/nei/object/IFluidDummy.java @@ -0,0 +1,9 @@ +package com.glodblock.github.nei.object; + +import net.minecraftforge.fluids.FluidStack; + +public interface IFluidDummy { + + FluidStack getFluidStack(); + +} diff --git a/src/main/java/com/glodblock/github/nei/object/IRecipeExtractor.java b/src/main/java/com/glodblock/github/nei/object/IRecipeExtractor.java new file mode 100644 index 00000000..9419c7a6 --- /dev/null +++ b/src/main/java/com/glodblock/github/nei/object/IRecipeExtractor.java @@ -0,0 +1,13 @@ +package com.glodblock.github.nei.object; + +import codechicken.nei.PositionedStack; + +import java.util.List; + +public interface IRecipeExtractor { + + List> getInputIngredients(List rawInputs); + + List> getOutputIngredients(List rawOutputs); + +} diff --git a/src/main/java/com/glodblock/github/nei/object/IllegalOrderStackID.java b/src/main/java/com/glodblock/github/nei/object/IllegalOrderStackID.java new file mode 100644 index 00000000..203d3a0d --- /dev/null +++ b/src/main/java/com/glodblock/github/nei/object/IllegalOrderStackID.java @@ -0,0 +1,9 @@ +package com.glodblock.github.nei.object; + +public class IllegalOrderStackID extends RuntimeException { + + public IllegalOrderStackID(int id) { + super("Illegal type id: " + id); + } + +} diff --git a/src/main/java/com/glodblock/github/nei/object/OrderStack.java b/src/main/java/com/glodblock/github/nei/object/OrderStack.java new file mode 100644 index 00000000..b2e285eb --- /dev/null +++ b/src/main/java/com/glodblock/github/nei/object/OrderStack.java @@ -0,0 +1,106 @@ +package com.glodblock.github.nei.object; + +import codechicken.nei.PositionedStack; +import com.glodblock.github.util.Util; +import cpw.mods.fml.common.network.ByteBufUtils; +import io.netty.buffer.ByteBuf; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.oredict.OreDictionary; + +import javax.annotation.Nullable; + +public class OrderStack { + + private final T RealStack; + private final int index; + + public final static int ITEM = 1; + public final static int FLUID = 2; + public final static int CUSTOM = 3; + + public OrderStack(T stack, int order) { + if (stack == null || order < 0) + throw new IllegalArgumentException("Trying to create a null or negative order stack!"); + this.RealStack = stack; + this.index = order; + } + + public T getStack() { + return RealStack; + } + + public int getIndex() { + return index; + } + + public static OrderStack pack(PositionedStack stack, int index) { + if (stack != null && stack.items != null && stack.items.length > 0) { + if (Items.feather.getDamage(stack.items[0]) == OreDictionary.WILDCARD_VALUE) { + ItemStack tmp = stack.items[0].copy(); + tmp.setItemDamage(0); + return new OrderStack<>(tmp, index); + } + else return new OrderStack<>(stack.items[0].copy(), index); + } + return null; + } + + public static OrderStack packFluid(PositionedStack stack, int index) { + if (stack != null && stack.items != null && stack.items.length > 0) { + FluidStack fluid = Util.getFluidFromItem(stack.items[0]); + if (fluid != null) return new OrderStack<>(fluid.copy(), index); + else return pack(stack, index); + } + return null; + } + + protected void customNBTWriter(NBTTagCompound buf) { + } + + protected T customNBTReader(NBTTagCompound buf) { + return null; + } + + public final void writeToNBT(NBTTagCompound buf) { + if (RealStack instanceof ItemStack) { + NBTTagCompound tmp = new NBTTagCompound(); + tmp.setByte("t", (byte) ITEM); + ((ItemStack) RealStack).writeToNBT(tmp); + buf.setTag(index + ":", tmp); + } + else if (RealStack instanceof FluidStack) { + NBTTagCompound tmp = new NBTTagCompound(); + tmp.setByte("t", (byte) FLUID); + ((FluidStack) RealStack).writeToNBT(tmp); + buf.setTag(index + ":", tmp); + } + else { + NBTTagCompound tmp = new NBTTagCompound(); + tmp.setByte("t", (byte) CUSTOM); + customNBTWriter(tmp); + buf.setTag(index + ":", tmp); + } + } + + public static OrderStack readFromNBT(NBTTagCompound buf, @Nullable OrderStack dummy, int index) { + if (!buf.hasKey(index + ":")) return null; + NBTTagCompound info = buf.getCompoundTag(index + ":"); + byte id = info.getByte("t"); + switch (id) { + case ITEM: + return new OrderStack<>(ItemStack.loadItemStackFromNBT(info), index); + case FLUID: + return new OrderStack<>(FluidStack.loadFluidStackFromNBT(info), index); + case CUSTOM: + if (dummy == null) throw new IllegalOrderStackID(id); + return new OrderStack<>(dummy.customNBTReader(buf), index); + default: + throw new IllegalOrderStackID(id); + } + } + +} diff --git a/src/main/java/com/glodblock/github/nei/recipes/DefaultExtractorLoader.java b/src/main/java/com/glodblock/github/nei/recipes/DefaultExtractorLoader.java new file mode 100644 index 00000000..89c8083c --- /dev/null +++ b/src/main/java/com/glodblock/github/nei/recipes/DefaultExtractorLoader.java @@ -0,0 +1,24 @@ +package com.glodblock.github.nei.recipes; + +import com.glodblock.github.nei.recipes.extractor.GregTech5RecipeExtractor; +import com.glodblock.github.nei.recipes.extractor.VanillaRecipeExtractor; +import com.glodblock.github.util.ModAndClassUtil; +import gregtech.api.util.GT_Recipe; + +public class DefaultExtractorLoader implements Runnable { + + @Override + public void run() { + FluidRecipe.addRecipeMap("smelting", new VanillaRecipeExtractor(false)); + FluidRecipe.addRecipeMap("brewing", new VanillaRecipeExtractor(false)); + FluidRecipe.addRecipeMap("crafting", new VanillaRecipeExtractor(true)); + FluidRecipe.addRecipeMap("crafting2x2", new VanillaRecipeExtractor(true)); + + if (ModAndClassUtil.GT5) { + for (GT_Recipe.GT_Recipe_Map tMap : GT_Recipe.GT_Recipe_Map.sMappings) { + FluidRecipe.addRecipeMap(tMap.mNEIName, new GregTech5RecipeExtractor(tMap.mNEIName.equals("gt.recipe.scanner") || tMap.mNEIName.equals("gt.recipe.fakeAssemblylineProcess"))); + } + } + } + +} diff --git a/src/main/java/com/glodblock/github/nei/recipes/FluidRecipe.java b/src/main/java/com/glodblock/github/nei/recipes/FluidRecipe.java new file mode 100644 index 00000000..afb1a465 --- /dev/null +++ b/src/main/java/com/glodblock/github/nei/recipes/FluidRecipe.java @@ -0,0 +1,42 @@ +package com.glodblock.github.nei.recipes; + +import codechicken.nei.PositionedStack; +import codechicken.nei.recipe.IRecipeHandler; +import com.glodblock.github.nei.object.IRecipeExtractor; +import com.glodblock.github.nei.object.OrderStack; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +public final class FluidRecipe { + + private static final HashMap IdentifierMap = new HashMap<>(); + + public static void addRecipeMap(String recipeIdentifier, IRecipeExtractor extractor) { + IdentifierMap.put(recipeIdentifier, extractor); + } + + public static List> getPackageInputs(IRecipeHandler recipe, int index) { + if (recipe == null || !IdentifierMap.containsKey(recipe.getOverlayIdentifier())) return new ArrayList<>(); + IRecipeExtractor extractor = IdentifierMap.get(recipe.getOverlayIdentifier()); + if (extractor == null) return new ArrayList<>(); + List tmp = new ArrayList<>(recipe.getIngredientStacks(index)); + return extractor.getInputIngredients(tmp); + } + + public static List> getPackageOutputs(IRecipeHandler recipe, int index, boolean useOther) { + if (recipe == null || !IdentifierMap.containsKey(recipe.getOverlayIdentifier())) return new ArrayList<>(); + IRecipeExtractor extractor = IdentifierMap.get(recipe.getOverlayIdentifier()); + if (extractor == null) return new ArrayList<>(); + List tmp = new ArrayList<>(Collections.singleton(recipe.getResultStack(index))); + if (useOther) tmp.addAll(recipe.getOtherStacks(index)); + return extractor.getOutputIngredients(tmp); + } + + public static List getSupportRecipes() { + return new ArrayList<>(IdentifierMap.keySet()); + } + +} diff --git a/src/main/java/com/glodblock/github/nei/recipes/extractor/GregTech5RecipeExtractor.java b/src/main/java/com/glodblock/github/nei/recipes/extractor/GregTech5RecipeExtractor.java new file mode 100644 index 00000000..ffcbc6af --- /dev/null +++ b/src/main/java/com/glodblock/github/nei/recipes/extractor/GregTech5RecipeExtractor.java @@ -0,0 +1,94 @@ +package com.glodblock.github.nei.recipes.extractor; + +import codechicken.nei.PositionedStack; +import com.glodblock.github.nei.object.IRecipeExtractor; +import com.glodblock.github.nei.object.OrderStack; +import gregtech.common.items.GT_FluidDisplayItem; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class GregTech5RecipeExtractor implements IRecipeExtractor { + + boolean r; + + public GregTech5RecipeExtractor(boolean removeSpecial) { + r = removeSpecial; + } + + @Override + public List> getInputIngredients(List rawInputs) { + List compressed = compress(rawInputs); + if (r) compressed.remove(compressed.size() - 1); + List> tmp = new LinkedList<>(); + for (int i = 0; i < compressed.size(); i ++) { + if (compressed.get(i) == null) continue; + ItemStack item = compressed.get(i).items[0]; + OrderStack stack; + if (item.getItem() instanceof GT_FluidDisplayItem) { + NBTTagCompound aNBT = item.getTagCompound(); + int amt = (int) aNBT.getLong("mFluidDisplayAmount"); + if (amt <= 0) continue; + stack = new OrderStack<>(new FluidStack(FluidRegistry.getFluid(item.getItemDamage()), amt), i); + tmp.add(stack); + } else { + stack = OrderStack.pack(compressed.get(i), i); + if (stack != null) tmp.add(stack); + } + } + return tmp; + } + + @Override + public List> getOutputIngredients(List rawOutputs) { + List compressed = compress(rawOutputs); + if (r) compressed.remove(compressed.size() - 1); + List> tmp = new LinkedList<>(); + for (int i = 0; i < compressed.size(); i ++) { + if (compressed.get(i) == null) continue; + ItemStack item = compressed.get(i).items[0]; + OrderStack stack; + if (item.getItem() instanceof GT_FluidDisplayItem) { + NBTTagCompound aNBT = item.getTagCompound(); + int amt = (int) aNBT.getLong("mFluidDisplayAmount"); + if (amt <= 0) continue; + stack = new OrderStack<>(new FluidStack(FluidRegistry.getFluid(item.getItemDamage()), amt), i); + tmp.add(stack); + } else { + stack = OrderStack.pack(compressed.get(i), i); + if (stack != null) tmp.add(stack); + } + } + return tmp; + } + + private List compress(List list) { + List comp = new LinkedList<>(); + for (PositionedStack positionedStack : list) { + if (positionedStack == null) continue; + ItemStack currentStack = positionedStack.items[0]; + if (currentStack.stackSize == 0) continue; + boolean find = false; + for (PositionedStack storedStack : comp) { + if (storedStack == null) continue; + ItemStack firstStack = storedStack.items[0]; + boolean areItemStackEqual = firstStack.isItemEqual(currentStack) && ItemStack.areItemStackTagsEqual(firstStack, currentStack); + if (areItemStackEqual && (firstStack.stackSize + currentStack.stackSize) <= firstStack.getMaxStackSize()) { + find = true; + storedStack.items[0].stackSize = firstStack.stackSize + currentStack.stackSize; + } + } + if (!find) { + comp.add(positionedStack.copy()); + } + } + return comp.stream().filter(Objects::nonNull).collect(Collectors.toList()); + } + +} diff --git a/src/main/java/com/glodblock/github/nei/recipes/extractor/VanillaRecipeExtractor.java b/src/main/java/com/glodblock/github/nei/recipes/extractor/VanillaRecipeExtractor.java new file mode 100644 index 00000000..f56ed528 --- /dev/null +++ b/src/main/java/com/glodblock/github/nei/recipes/extractor/VanillaRecipeExtractor.java @@ -0,0 +1,46 @@ +package com.glodblock.github.nei.recipes.extractor; + +import codechicken.nei.PositionedStack; +import com.glodblock.github.nei.object.IRecipeExtractor; +import com.glodblock.github.nei.object.OrderStack; + +import java.util.LinkedList; +import java.util.List; + +public class VanillaRecipeExtractor implements IRecipeExtractor { + + private boolean c; + + public VanillaRecipeExtractor(boolean isCraft) { + c = isCraft; + } + + @Override + public List> getInputIngredients(List rawInputs) { + List> tmp = new LinkedList<>(); + for (int i = 0; i < rawInputs.size(); i ++) { + if (rawInputs.get(i) == null) continue; + final int col = (rawInputs.get(i).relx - 25) / 18; + final int row = (rawInputs.get(i).rely - 6) / 18; + int index = col + row * 3; + OrderStack stack = OrderStack.pack(rawInputs.get(i), c ? index : i); + if (stack != null) tmp.add(stack); + } + return tmp; + } + + @Override + public List> getOutputIngredients(List rawOutputs) { + List> tmp = new LinkedList<>(); + for (int i = 0; i < rawOutputs.size(); i ++) { + if (rawOutputs.get(i) == null) continue; + final int col = (rawOutputs.get(i).relx - 25) / 18; + final int row = (rawOutputs.get(i).rely - 6) / 18; + int index = col + row * 3; + OrderStack stack = OrderStack.pack(rawOutputs.get(i), c ? index : i); + if (stack != null) tmp.add(stack); + } + return tmp; + } + +} diff --git a/src/main/java/com/glodblock/github/network/CPacketCraftRequest.java b/src/main/java/com/glodblock/github/network/CPacketCraftRequest.java new file mode 100644 index 00000000..d93a60b4 --- /dev/null +++ b/src/main/java/com/glodblock/github/network/CPacketCraftRequest.java @@ -0,0 +1,118 @@ +package com.glodblock.github.network; + +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridHost; +import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.ICraftingGrid; +import appeng.api.networking.crafting.ICraftingJob; +import appeng.container.ContainerOpenContext; +import appeng.container.implementations.ContainerCraftAmount; +import appeng.core.AELog; +import com.glodblock.github.client.gui.container.ContainerFluidCraftConfirm; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.util.BlockPos; +import com.glodblock.github.util.Util; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +import javax.annotation.Nullable; +import java.util.Objects; +import java.util.concurrent.Future; + +public class CPacketCraftRequest implements IMessage { + + private long amount; + private boolean heldShift; + + public CPacketCraftRequest() { + } + + public CPacketCraftRequest( final int craftAmt, final boolean shift ) { + amount = craftAmt; + heldShift = shift; + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeLong(amount); + buf.writeBoolean(heldShift); + } + + @Override + public void fromBytes(ByteBuf buf) { + amount = buf.readLong(); + heldShift = buf.readBoolean(); + } + + public static class Handler implements IMessageHandler { + + @Nullable + @Override + public IMessage onMessage(CPacketCraftRequest message, MessageContext ctx) { + if( ctx.getServerHandler().playerEntity.openContainer instanceof ContainerCraftAmount) + { + EntityPlayerMP player = ctx.getServerHandler().playerEntity; + final ContainerCraftAmount cca = (ContainerCraftAmount) ctx.getServerHandler().playerEntity.openContainer; + final Object target = cca.getTarget(); + if( target instanceof IGridHost) + { + final IGridHost gh = (IGridHost) target; + final IGridNode gn = gh.getGridNode( ForgeDirection.UNKNOWN ); + + if( gn == null ) + { + return null; + } + + final IGrid g = gn.getGrid(); + if( g == null || cca.getItemToCraft() == null ) + { + return null; + } + + cca.getItemToCraft().setStackSize( message.amount ); + + Future futureJob = null; + try + { + final ICraftingGrid cg = g.getCache( ICraftingGrid.class ); + futureJob = cg.beginCraftingJob( cca.getWorld(), cca.getGrid(), cca.getActionSrc(), cca.getItemToCraft(), null ); + + final ContainerOpenContext context = cca.getOpenContext(); + if( context != null ) + { + + final TileEntity te = context.getTile(); + InventoryHandler.openGui(player, player.worldObj, new BlockPos(te), Objects.requireNonNull(Util.from(context.getSide())), GuiType.FLUID_CRAFTING_CONFIRM); + + if( player.openContainer instanceof ContainerFluidCraftConfirm) + { + final ContainerFluidCraftConfirm ccc = (ContainerFluidCraftConfirm) player.openContainer; + ccc.setAutoStart( message.heldShift ); + ccc.setJob( futureJob ); + cca.detectAndSendChanges(); + } + } + } + catch( final Throwable e ) + { + if( futureJob != null ) + { + futureJob.cancel( true ); + } + AELog.debug( e ); + } + } + } + return null; + } + + } + +} diff --git a/src/main/java/com/glodblock/github/network/CPacketEncodePattern.java b/src/main/java/com/glodblock/github/network/CPacketEncodePattern.java new file mode 100644 index 00000000..b025844c --- /dev/null +++ b/src/main/java/com/glodblock/github/network/CPacketEncodePattern.java @@ -0,0 +1,38 @@ +package com.glodblock.github.network; + +import com.glodblock.github.client.gui.container.ContainerFluidPatternEncoder; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayerMP; + +import javax.annotation.Nullable; + +public class CPacketEncodePattern implements IMessage { + + @Override + public void toBytes(ByteBuf buf) { + // NO-OP + } + + @Override + public void fromBytes(ByteBuf buf) { + // NO-OP + } + + public static class Handler implements IMessageHandler { + + @Nullable + @Override + public IMessage onMessage(CPacketEncodePattern message, MessageContext ctx) { + EntityPlayerMP player = ctx.getServerHandler().playerEntity; + if (player.openContainer instanceof ContainerFluidPatternEncoder) { + ((ContainerFluidPatternEncoder)player.openContainer).encodePattern(); + } + return null; + } + + } + +} diff --git a/src/main/java/com/glodblock/github/network/CPacketFluidPatternTermBtns.java b/src/main/java/com/glodblock/github/network/CPacketFluidPatternTermBtns.java new file mode 100644 index 00000000..374143e2 --- /dev/null +++ b/src/main/java/com/glodblock/github/network/CPacketFluidPatternTermBtns.java @@ -0,0 +1,95 @@ +package com.glodblock.github.network; + +import com.glodblock.github.client.gui.container.ContainerFluidCraftConfirm; +import com.glodblock.github.client.gui.container.ContainerFluidPatternTerminal; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; +import net.minecraft.inventory.Container; + +public class CPacketFluidPatternTermBtns implements IMessage { + + private String Name = ""; + private String Value = ""; + + public CPacketFluidPatternTermBtns( final String name, final String value ) { + Name = name; + Value = value; + } + + public CPacketFluidPatternTermBtns() { + // NO-OP + } + + @Override + public void fromBytes(ByteBuf buf) { + int leName = buf.readInt(); + int leVal = buf.readInt(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < leName; i ++) { + sb.append(buf.readChar()); + } + Name = sb.toString(); + sb = new StringBuilder(); + for (int i = 0; i < leVal; i ++) { + sb.append(buf.readChar()); + } + Value = sb.toString(); + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeInt(Name.length()); + buf.writeInt(Value.length()); + for (int i = 0; i < Name.length(); i ++) { + buf.writeChar(Name.charAt(i)); + } + for (int i = 0; i < Value.length(); i ++) { + buf.writeChar(Value.charAt(i)); + } + } + + public static class Handler implements IMessageHandler { + + @Override + public IMessage onMessage(CPacketFluidPatternTermBtns message, MessageContext ctx) { + String Name = message.Name; + String Value = message.Value; + final Container c = ctx.getServerHandler().playerEntity.openContainer; + if( Name.startsWith( "PatternTerminal." ) && c instanceof ContainerFluidPatternTerminal) + { + final ContainerFluidPatternTerminal cpt = (ContainerFluidPatternTerminal) c; + switch (Name) { + case "PatternTerminal.CraftMode": + cpt.getPatternTerminal().setCraftingRecipe(Value.equals("1")); + break; + case "PatternTerminal.Encode": + if (Value.equals("2")) + cpt.encodeAndMoveToInventory(); + else + cpt.encode(); + break; + case "PatternTerminal.Clear": + cpt.clear(); + break; + case "PatternTerminal.Substitute": + cpt.getPatternTerminal().setSubstitution(Value.equals("1")); + break; + case "PatternTerminal.Double": + cpt.doubleStacks(Value.equals("1")); + break; + } + } else if(Name.equals( "Terminal.Cpu" ) && c instanceof ContainerFluidCraftConfirm) { + final ContainerFluidCraftConfirm qk = (ContainerFluidCraftConfirm) c; + qk.cycleCpu( Value.equals( "Next" ) ); + } + else if( Name.equals( "Terminal.Start" ) && c instanceof ContainerFluidCraftConfirm ) { + final ContainerFluidCraftConfirm qk = (ContainerFluidCraftConfirm) c; + qk.startJob(); + } + return null; + } + + } +} diff --git a/src/main/java/com/glodblock/github/network/CPacketInventoryAction.java b/src/main/java/com/glodblock/github/network/CPacketInventoryAction.java new file mode 100644 index 00000000..681977cb --- /dev/null +++ b/src/main/java/com/glodblock/github/network/CPacketInventoryAction.java @@ -0,0 +1,124 @@ +package com.glodblock.github.network; + +import appeng.api.storage.data.IAEItemStack; +import appeng.container.AEBaseContainer; +import appeng.container.ContainerOpenContext; +import appeng.container.implementations.ContainerCraftAmount; +import appeng.core.sync.GuiBridge; +import appeng.helpers.InventoryAction; +import appeng.util.Platform; +import appeng.util.item.AEItemStack; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.util.BlockPos; +import com.glodblock.github.util.Util; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.tileentity.TileEntity; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.util.Objects; + +public class CPacketInventoryAction implements IMessage { + + private InventoryAction action; + private int slot; + private long id; + private IAEItemStack stack; + private boolean isEmpty; + + public CPacketInventoryAction() { + } + + public CPacketInventoryAction( final InventoryAction action, final int slot, final int id ) { + this.action = action; + this.slot = slot; + this.id = id; + this.stack = null; + this.isEmpty = true; + } + + public CPacketInventoryAction(final InventoryAction action, final int slot, final int id , IAEItemStack stack) { + this.action = action; + this.slot = slot; + this.id = id; + this.stack = stack; + this.isEmpty = stack == null; + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeInt(action.ordinal()); + buf.writeInt(slot); + buf.writeLong(id); + buf.writeBoolean(isEmpty); + if (!isEmpty) { + try { + stack.writeToPacket(buf); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Override + public void fromBytes(ByteBuf buf) { + action = InventoryAction.values()[buf.readInt()]; + slot = buf.readInt(); + id = buf.readLong(); + isEmpty = buf.readBoolean(); + if (!isEmpty) { + try { + stack = AEItemStack.loadItemStackFromPacket(buf); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public static class Handler implements IMessageHandler { + + @Nullable + @Override + public IMessage onMessage(CPacketInventoryAction message, MessageContext ctx) { + final EntityPlayerMP sender = ctx.getServerHandler().playerEntity; + if( sender.openContainer instanceof AEBaseContainer ) + { + final AEBaseContainer baseContainer = (AEBaseContainer) sender.openContainer; + if( message.action == InventoryAction.AUTO_CRAFT ) + { + final ContainerOpenContext context = baseContainer.getOpenContext(); + if( context != null ) + { + final TileEntity te = context.getTile(); + InventoryHandler.openGui( sender, te.getWorldObj(), new BlockPos(te), Objects.requireNonNull(Util.from(baseContainer.getOpenContext().getSide())), GuiType.FLUID_CRAFTING_AMOUNT ); + + if( sender.openContainer instanceof ContainerCraftAmount ) + { + final ContainerCraftAmount cca = (ContainerCraftAmount) sender.openContainer; + + if( baseContainer.getTargetStack() != null ) + { + cca.getCraftingItem().putStack( baseContainer.getTargetStack().getItemStack() ); + cca.setItemToCraft( baseContainer.getTargetStack() ); + } + + cca.detectAndSendChanges(); + } + } + } + else + { + baseContainer.doAction( sender, message.action, message.slot, message.id ); + } + } + return null; + } + + } + +} diff --git a/src/main/java/com/glodblock/github/network/CPacketSetTargetItem.java b/src/main/java/com/glodblock/github/network/CPacketSetTargetItem.java new file mode 100644 index 00000000..2e9f6cbf --- /dev/null +++ b/src/main/java/com/glodblock/github/network/CPacketSetTargetItem.java @@ -0,0 +1,56 @@ +package com.glodblock.github.network; + +import appeng.api.storage.data.IAEItemStack; +import appeng.container.AEBaseContainer; +import appeng.util.item.AEItemStack; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; +import net.minecraft.inventory.Container; + +import java.io.IOException; + +public class CPacketSetTargetItem implements IMessage { + + private IAEItemStack stack; + + public CPacketSetTargetItem() { + } + + public CPacketSetTargetItem(IAEItemStack stack) { + this.stack = stack; + } + + @Override + public void toBytes(ByteBuf buf) { + try { + stack.writeToPacket(buf); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public void fromBytes(ByteBuf buf) { + try { + stack = AEItemStack.loadItemStackFromPacket(buf); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static class Handler implements IMessageHandler { + + @Override + public IMessage onMessage(CPacketSetTargetItem message, MessageContext ctx) { + Container c = ctx.getServerHandler().playerEntity.openContainer; + if (c instanceof AEBaseContainer) { + ((AEBaseContainer) c).setTargetStack(message.stack); + } + return null; + } + + } + +} diff --git a/src/main/java/com/glodblock/github/network/CPacketSwitchGuis.java b/src/main/java/com/glodblock/github/network/CPacketSwitchGuis.java new file mode 100644 index 00000000..7c7ce1c2 --- /dev/null +++ b/src/main/java/com/glodblock/github/network/CPacketSwitchGuis.java @@ -0,0 +1,68 @@ +package com.glodblock.github.network; + +import appeng.container.AEBaseContainer; +import appeng.container.ContainerOpenContext; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.util.BlockPos; +import com.glodblock.github.util.Util; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.Container; +import net.minecraft.tileentity.TileEntity; + +import javax.annotation.Nullable; +import java.util.Objects; + +public class CPacketSwitchGuis implements IMessage { + + private GuiType guiType; + + public CPacketSwitchGuis(GuiType guiType) { + this.guiType = guiType; + } + + public CPacketSwitchGuis() { + // NO-OP + } + + @Override + public void fromBytes(ByteBuf byteBuf) { + guiType = GuiType.getByOrdinal(byteBuf.readByte()); + } + + @Override + public void toBytes(ByteBuf byteBuf) { + byteBuf.writeByte(guiType != null ? guiType.ordinal() : 0); + } + + public static class Handler implements IMessageHandler { + @Nullable + @Override + public IMessage onMessage(CPacketSwitchGuis message, MessageContext ctx) { + if (message.guiType == null) { + return null; + } + EntityPlayerMP player = ctx.getServerHandler().playerEntity; + Container cont = player.openContainer; + if (!(cont instanceof AEBaseContainer)) { + return null; + } + ContainerOpenContext context = ((AEBaseContainer)cont).getOpenContext(); + if (context == null) { + return null; + } + TileEntity te = context.getTile(); + if (te == null) { + return null; + } + InventoryHandler.openGui(player, player.worldObj, new BlockPos(te), Objects.requireNonNull(Util.from(context.getSide())), message.guiType); + return null; + } + + } +} + diff --git a/src/main/java/com/glodblock/github/network/CPacketTransferRecipe.java b/src/main/java/com/glodblock/github/network/CPacketTransferRecipe.java new file mode 100644 index 00000000..864e03d9 --- /dev/null +++ b/src/main/java/com/glodblock/github/network/CPacketTransferRecipe.java @@ -0,0 +1,128 @@ +package com.glodblock.github.network; + +import com.glodblock.github.client.gui.container.ContainerFluidPatternTerminal; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.nei.object.OrderStack; +import cpw.mods.fml.common.network.ByteBufUtils; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.fluids.FluidStack; + +import javax.annotation.Nullable; +import java.util.LinkedList; +import java.util.List; + +public class CPacketTransferRecipe implements IMessage { + + private List> inputs; + private List> outputs; + private boolean isCraft; + private final static int MAX_INDEX = 16; + + public CPacketTransferRecipe(){ + } + + public CPacketTransferRecipe(List> IN, List> OUT, boolean craft) { + this.inputs = IN; + this.outputs = OUT; + this.isCraft = craft; + } + + //I should use GZIP to compress the message, but i'm too lazy. + //NBT to ByteBuf has a compress stream + @Override + public void toBytes(ByteBuf buf) { + buf.writeBoolean(isCraft); + NBTTagCompound nbt_m = new NBTTagCompound(); + NBTTagCompound nbt_i = new NBTTagCompound(); + NBTTagCompound nbt_o = new NBTTagCompound(); + for (OrderStack stack : inputs) { + stack.writeToNBT(nbt_i); + } + for (OrderStack stack : outputs) { + stack.writeToNBT(nbt_o); + } + nbt_m.setTag("i", nbt_i); + nbt_m.setTag("o", nbt_o); + ByteBufUtils.writeTag(buf, nbt_m); + } + + @Override + public void fromBytes(ByteBuf buf) { + isCraft = buf.readBoolean(); + inputs = new LinkedList<>(); + outputs = new LinkedList<>(); + NBTTagCompound nbt_m = ByteBufUtils.readTag(buf); + NBTTagCompound nbt_i = nbt_m.getCompoundTag("i"); + NBTTagCompound nbt_o = nbt_m.getCompoundTag("o"); + for (int i = 0; i < MAX_INDEX; i ++) { + OrderStack tmp = OrderStack.readFromNBT(nbt_i, null, i); + if (tmp != null) inputs.add(tmp); + } + for (int i = 0; i < MAX_INDEX; i ++) { + OrderStack tmp = OrderStack.readFromNBT(nbt_o, null, i); + if (tmp != null) outputs.add(tmp); + } + } + + public static class Handler implements IMessageHandler { + + @Nullable + @Override + public IMessage onMessage(CPacketTransferRecipe message, MessageContext ctx) { + Container c = ctx.getServerHandler().playerEntity.openContainer; + if (c instanceof ContainerFluidPatternTerminal) { + ContainerFluidPatternTerminal cf = (ContainerFluidPatternTerminal) c; + cf.getPatternTerminal().setCraftingRecipe(message.isCraft); + IInventory inputSlot = cf.getInventoryByName("crafting"); + IInventory outputSlot = cf.getInventoryByName("output"); + for (int i = 0; i < inputSlot.getSizeInventory(); i ++) { + inputSlot.setInventorySlotContents(i, null); + } + for (int i = 0; i < outputSlot.getSizeInventory(); i ++) { + outputSlot.setInventorySlotContents(i, null); + } + for (OrderStack stack : message.inputs) { + if (stack != null) { + int index = stack.getIndex(); + ItemStack stack1; + if (stack.getStack() instanceof ItemStack) { + stack1 = ((ItemStack) stack.getStack()).copy(); + } + else if (stack.getStack() instanceof FluidStack) { + stack1 = ItemFluidPacket.newStack((FluidStack) stack.getStack()); + } + else throw new UnsupportedOperationException("Trying to get an unsupported item!"); + if (index < inputSlot.getSizeInventory()) + inputSlot.setInventorySlotContents(index, stack1); + } + } + for (OrderStack stack : message.outputs) { + if (stack != null) { + int index = stack.getIndex(); + ItemStack stack1; + if (stack.getStack() instanceof ItemStack) { + stack1 = ((ItemStack) stack.getStack()).copy(); + } + else if (stack.getStack() instanceof FluidStack) { + stack1 = ItemFluidPacket.newStack((FluidStack) stack.getStack()); + } + else throw new UnsupportedOperationException("Trying to get an unsupported item!"); + if (index < outputSlot.getSizeInventory()) + outputSlot.setInventorySlotContents(index, stack1); + } + } + c.onCraftMatrixChanged(inputSlot); + c.onCraftMatrixChanged(outputSlot); + } + return null; + } + } + +} diff --git a/src/main/java/com/glodblock/github/network/SPacketFluidSlot.java b/src/main/java/com/glodblock/github/network/SPacketFluidSlot.java new file mode 100644 index 00000000..daa323d6 --- /dev/null +++ b/src/main/java/com/glodblock/github/network/SPacketFluidSlot.java @@ -0,0 +1,68 @@ +package com.glodblock.github.network; + +import appeng.api.storage.data.IAEFluidStack; +import appeng.util.item.AEFluidStack; +import com.glodblock.github.client.gui.IFluidSyncContainer; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; +import net.minecraft.inventory.Container; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class SPacketFluidSlot implements IMessage { + + private Map list; + + public SPacketFluidSlot() { + } + + public SPacketFluidSlot(Map data) { + this.list = data; + } + + @Override + public void fromBytes(ByteBuf buf) { + int size = buf.readInt(); + this.list = new HashMap<>(); + try { + for (int i = 0; i < size; i ++) { + int id = buf.readInt(); + IAEFluidStack fluid = AEFluidStack.loadFluidStackFromPacket(buf); + list.put(id, fluid); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeInt(list.size()); + try { + for (Map.Entry fs : list.entrySet()) { + buf.writeInt(fs.getKey()); + fs.getValue().writeToPacket(buf); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static class Handler implements IMessageHandler { + + @Override + public IMessage onMessage(SPacketFluidSlot message, MessageContext ctx) { + final Container c = ctx.getServerHandler().playerEntity.openContainer; + if( c instanceof IFluidSyncContainer) + { + ( (IFluidSyncContainer) c ).receiveFluidSlots( message.list ); + } + return null; + } + } + +} diff --git a/src/main/java/com/glodblock/github/network/SPacketMEInventoryUpdate.java b/src/main/java/com/glodblock/github/network/SPacketMEInventoryUpdate.java new file mode 100644 index 00000000..271ec56c --- /dev/null +++ b/src/main/java/com/glodblock/github/network/SPacketMEInventoryUpdate.java @@ -0,0 +1,84 @@ +package com.glodblock.github.network; + +import appeng.api.storage.data.IAEItemStack; +import appeng.util.item.AEItemStack; +import com.glodblock.github.client.gui.GuiFCBaseMonitor; +import com.glodblock.github.client.gui.GuiFluidCraftConfirm; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; + +import java.io.IOException; +import java.nio.BufferOverflowException; +import java.util.LinkedList; +import java.util.List; + +public class SPacketMEInventoryUpdate implements IMessage { + + private List list; + private byte ref; + + public SPacketMEInventoryUpdate() { + ref = 0; + list = new LinkedList<>(); + } + + public SPacketMEInventoryUpdate(byte b) { + this.ref = b; + list = new LinkedList<>(); + } + + @Override + public void fromBytes(ByteBuf buf) { + long amount = buf.readLong(); + ref = buf.readByte(); + list = new LinkedList<>(); + try { + for (int i = 0; i < amount; i ++) { + list.add(AEItemStack.loadItemStackFromPacket(buf)); + } + } catch (IOException io) { + io.printStackTrace(); + } + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeLong(list.size()); + buf.writeByte(ref); + try { + for (IAEItemStack itemStack : list) { + itemStack.writeToPacket(buf); + } + } catch (IOException io) { + io.printStackTrace(); + } + } + + public void appendItem( final IAEItemStack is ) throws BufferOverflowException { + list.add(is); + } + + public boolean isEmpty() { + return this.list.isEmpty(); + } + + public static class Handler implements IMessageHandler { + + @Override + public IMessage onMessage(SPacketMEInventoryUpdate message, MessageContext ctx) { + final GuiScreen gs = Minecraft.getMinecraft().currentScreen; + if( gs instanceof GuiFCBaseMonitor) + { + ( (GuiFCBaseMonitor) gs ).postUpdate(message.list); + } + else if ( gs instanceof GuiFluidCraftConfirm) { + ( (GuiFluidCraftConfirm) gs ).postUpdate( message.list, message.ref ); + } + return null; + } + } +} diff --git a/src/main/java/com/glodblock/github/proxy/ClientProxy.java b/src/main/java/com/glodblock/github/proxy/ClientProxy.java new file mode 100644 index 00000000..878a28c0 --- /dev/null +++ b/src/main/java/com/glodblock/github/proxy/ClientProxy.java @@ -0,0 +1,23 @@ +package com.glodblock.github.proxy; + +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; + +public class ClientProxy extends CommonProxy { + + @Override + public void preInit(FMLPreInitializationEvent event){ + super.preInit(event); + } + + @Override + public void init(FMLInitializationEvent event){ + super.init(event); + } + + @Override + public void postInit(FMLPostInitializationEvent event){ + super.postInit(event); + } +} diff --git a/src/main/java/com/glodblock/github/proxy/CommonProxy.java b/src/main/java/com/glodblock/github/proxy/CommonProxy.java new file mode 100644 index 00000000..1b02c687 --- /dev/null +++ b/src/main/java/com/glodblock/github/proxy/CommonProxy.java @@ -0,0 +1,20 @@ +package com.glodblock.github.proxy; + +import com.glodblock.github.FluidCraft; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.network.NetworkRegistry; +import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper; + +public class CommonProxy { + + public final SimpleNetworkWrapper netHandler = NetworkRegistry.INSTANCE.newSimpleChannel(FluidCraft.MODID); + + public void preInit(FMLPreInitializationEvent event){} + + public void init(FMLInitializationEvent event){} + + public void postInit(FMLPostInitializationEvent event){} + +} diff --git a/src/main/java/com/glodblock/github/util/Ae2Reflect.java b/src/main/java/com/glodblock/github/util/Ae2Reflect.java new file mode 100644 index 00000000..74e9ad08 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/Ae2Reflect.java @@ -0,0 +1,237 @@ +package com.glodblock.github.util; + +import appeng.api.implementations.IUpgradeableHost; +import appeng.api.networking.crafting.ICraftingCPU; +import appeng.client.gui.AEBaseGui; +import appeng.client.gui.implementations.GuiCraftingStatus; +import appeng.client.gui.widgets.GuiTabButton; +import appeng.client.render.AppEngRenderItem; +import appeng.container.implementations.ContainerUpgradeable; +import appeng.container.implementations.CraftingCPURecord; +import appeng.helpers.MultiCraftingTracker; +import appeng.util.inv.ItemSlot; +import com.glodblock.github.client.gui.GuiBaseFluidPatternTerminal; +import com.glodblock.github.client.gui.GuiFCBaseMonitor; +import com.glodblock.github.client.gui.container.ContainerFluidPatternTerminal; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Set; + +public class Ae2Reflect { + + private static final Field fInventory_container; + private static final Field fInventory_width; + private static final Field fInventory_stackList; + private static final Field fAEContainer_upgradeable; + private static final Method mItemSlot_setExtractable; + private static final Method mTracker_isBusy; + private static final Method mTracker_cancel; + + static { + try { + fInventory_container = reflectField(InventoryCrafting.class, "eventHandler"); + fInventory_width = reflectField(InventoryCrafting.class, "inventoryWidth"); + fInventory_stackList = reflectField(InventoryCrafting.class, "stackList"); + fAEContainer_upgradeable = reflectField(ContainerUpgradeable.class, "upgradeable"); + mItemSlot_setExtractable = reflectMethod(ItemSlot.class, "setExtractable", boolean.class); + mTracker_isBusy = reflectMethod(MultiCraftingTracker.class, "isBusy", int.class); + mTracker_cancel = reflectMethod(MultiCraftingTracker.class, "cancel"); + } catch (Exception e) { + throw new IllegalStateException("Failed to initialize AE2 reflection hacks!", e); + } + } + + public static Method reflectMethod(Class owner, String name, Class... paramTypes) throws NoSuchMethodException { + Method m = owner.getDeclaredMethod(name, paramTypes); + m.setAccessible(true); + return m; + } + + public static Field reflectField(Class owner, String name) throws NoSuchFieldException { + Field f = owner.getDeclaredField(name); + f.setAccessible(true); + return f; + } + + @SuppressWarnings("unchecked") + public static T readField(Object owner, Field field) { + try { + return (T)field.get(owner); + } catch (Exception e) { + throw new IllegalStateException("Failed to read field: " + field); + } + } + + public static void writeField(Object owner, Field field, Object value) { + try { + field.set(owner, value); + } catch (Exception e) { + throw new IllegalStateException("Failed to write field: " + field); + } + } + + public static void doCancel(MultiCraftingTracker mct) { + try { + mTracker_cancel.invoke(mct); + } catch (Exception e) { + throw new IllegalStateException("Failed to invoke method: " + mTracker_cancel, e); + } + } + + public static boolean getBusy(MultiCraftingTracker mct, int slot) { + try { + return (boolean) mTracker_isBusy.invoke(mct, slot); + } catch (Exception e) { + throw new IllegalStateException("Failed to invoke method: " + mTracker_isBusy, e); + } + } + + public static IUpgradeableHost getUpgrade(ContainerUpgradeable container) { + return Ae2Reflect.readField(container, fAEContainer_upgradeable); + } + + public static Container getCraftContainer(InventoryCrafting inv) { + return Ae2Reflect.readField(inv, fInventory_container); + } + + public static int getCraftWidth(InventoryCrafting inv) { + return Ae2Reflect.readField(inv, fInventory_width); + } + + public static ItemStack[] getCraftStackList(InventoryCrafting inv) { + return Ae2Reflect.readField(inv, fInventory_stackList); + } + + public static void setItemSlotExtractable(ItemSlot slot, boolean extractable) { + try { + mItemSlot_setExtractable.invoke(slot, extractable); + } catch (Exception e) { + throw new IllegalStateException("Failed to invoke method: " + mItemSlot_setExtractable, e); + } + } + + private static final Field fAEBaseGui_stackSizeRenderer; + private static final Field fGuiCraftingStatus_originalGuiBtn; + private static final Field fGuiPatternTerm_container; + private static final Field fGuiCPUStatus_icon; + private static final Field fGuiMEMonitorable_monitorableContainer; + private static final Field fGuiMEMonitorable_configSrc; + private static final Field fGuiMEMonitorable_craftingStatusBtn; + private static final Field fGuiContainer_guiLeft; + private static final Field fGuiContainer_guiTop; + private static final Field fCPU_cpu; + private static final Field fCPU_myName; + private static final Field fCPU_processors; + private static final Field fCPU_size; + private static final Field fGui_drag; + private static final Method mGuiPatternTerm_inventorySlots; + private static final Method mGuiPatternTerm_reservedSpace; + private static final Method mGuiPatternTerm_reservedSpaceSetter; + + static { + try { + fAEBaseGui_stackSizeRenderer = Ae2Reflect.reflectField(AEBaseGui.class, "aeRenderItem"); + fGuiCraftingStatus_originalGuiBtn = Ae2Reflect.reflectField(GuiCraftingStatus.class, "originalGuiBtn"); + fGuiPatternTerm_container = Ae2Reflect.reflectField(GuiBaseFluidPatternTerminal.class, "container"); + fGuiMEMonitorable_monitorableContainer = Ae2Reflect.reflectField(GuiFCBaseMonitor.class, "monitorableContainer"); + fGuiMEMonitorable_configSrc = Ae2Reflect.reflectField(GuiFCBaseMonitor.class, "configSrc"); + fGuiMEMonitorable_craftingStatusBtn = Ae2Reflect.reflectField(GuiFCBaseMonitor.class, "craftingStatusBtn"); + fGuiCPUStatus_icon = Ae2Reflect.reflectField(GuiCraftingStatus.class, "myIcon"); + fGuiContainer_guiLeft = Ae2Reflect.reflectField(GuiContainer.class, "guiLeft"); + fGuiContainer_guiTop = Ae2Reflect.reflectField(GuiContainer.class, "guiTop"); + fCPU_cpu = Ae2Reflect.reflectField(CraftingCPURecord.class, "cpu"); + fCPU_myName = Ae2Reflect.reflectField(CraftingCPURecord.class, "myName"); + fCPU_processors = Ae2Reflect.reflectField(CraftingCPURecord.class, "processors"); + fCPU_size = Ae2Reflect.reflectField(CraftingCPURecord.class, "size"); + fGui_drag = Ae2Reflect.reflectField(AEBaseGui.class, "drag_click"); + mGuiPatternTerm_inventorySlots = Ae2Reflect.reflectMethod(AEBaseGui.class, "getInventorySlots"); + mGuiPatternTerm_reservedSpace = Ae2Reflect.reflectMethod(GuiFCBaseMonitor.class, "getReservedSpace"); + mGuiPatternTerm_reservedSpaceSetter = Ae2Reflect.reflectMethod(GuiFCBaseMonitor.class, "setReservedSpace", int.class); + } catch (Exception e) { + throw new IllegalStateException("Failed to initialize AE2 reflection hacks!", e); + } + } + + @SuppressWarnings("unchecked") + public static List getInventorySlots(AEBaseGui gui) { + try { + return (List) mGuiPatternTerm_inventorySlots.invoke(gui); + } catch (Exception e) { + throw new IllegalStateException("Failed to invoke method: " + mGuiPatternTerm_inventorySlots, e); + } + } + + public static void rewriteIcon(GuiCraftingStatus gui, ItemStack icon) { + Ae2Reflect.writeField(gui, fGuiCPUStatus_icon, icon); + } + + public static Set getDragClick(AEBaseGui gui) { + return Ae2Reflect.readField(gui, fGui_drag); + } + + public static ICraftingCPU getCPU(CraftingCPURecord cpu) { + return Ae2Reflect.readField(cpu, fCPU_cpu); + } + + public static String getName(CraftingCPURecord cpu) { + return Ae2Reflect.readField(cpu, fCPU_myName); + } + + public static int getProcessors(CraftingCPURecord cpu) { + return Ae2Reflect.readField(cpu, fCPU_processors); + } + + public static long getSize(CraftingCPURecord cpu) { + return Ae2Reflect.readField(cpu, fCPU_size); + } + + public static int getGuiLeft(GuiContainer gui) { + return Ae2Reflect.readField(gui, fGuiContainer_guiLeft); + } + + public static int getGuiTop(GuiContainer gui) { + return Ae2Reflect.readField(gui, fGuiContainer_guiTop); + } + + public static void setReservedSpace(GuiFCBaseMonitor gui, int size) { + try { + mGuiPatternTerm_reservedSpaceSetter.invoke(gui, size); + } catch (Exception e) { + throw new IllegalStateException("Failed to invoke method: " + mGuiPatternTerm_reservedSpaceSetter, e); + } + } + + public static int getReservedSpace(GuiFCBaseMonitor gui) { + try { + return (int) mGuiPatternTerm_reservedSpace.invoke(gui); + } catch (Exception e) { + throw new IllegalStateException("Failed to invoke method: " + mGuiPatternTerm_reservedSpace, e); + } + } + + public static AppEngRenderItem getStackSizeRenderer(AEBaseGui gui) { + return Ae2Reflect.readField(gui, fAEBaseGui_stackSizeRenderer); + } + + public static GuiTabButton getOriginalGuiButton(GuiCraftingStatus gui) { + return Ae2Reflect.readField(gui, fGuiCraftingStatus_originalGuiBtn); + } + + public static void setGuiContainer(GuiBaseFluidPatternTerminal instance, ContainerFluidPatternTerminal container) { + Ae2Reflect.writeField(instance, fGuiPatternTerm_container, container); + Ae2Reflect.writeField(instance, fGuiMEMonitorable_monitorableContainer, container); + Ae2Reflect.writeField(instance, fGuiMEMonitorable_configSrc, container.getConfigManager()); + } + + public static GuiTabButton getCraftingStatusButton(GuiFCBaseMonitor gui) { + return Ae2Reflect.readField(gui, fGuiMEMonitorable_craftingStatusBtn); + } + +} diff --git a/src/main/java/com/glodblock/github/util/BlockPos.java b/src/main/java/com/glodblock/github/util/BlockPos.java new file mode 100644 index 00000000..45897d2e --- /dev/null +++ b/src/main/java/com/glodblock/github/util/BlockPos.java @@ -0,0 +1,46 @@ +package com.glodblock.github.util; + +import net.minecraft.tileentity.TileEntity; + +import javax.annotation.Nonnull; + +public class BlockPos { + + private final int x; + private final int y; + private final int z; + + public BlockPos(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public BlockPos(@Nonnull TileEntity te) { + this.x = te.xCoord; + this.y = te.yCoord; + this.z = te.zCoord; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public int getZ() { + return z; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof BlockPos) { + BlockPos pos = (BlockPos) obj; + return pos.x == x && pos.y == y && pos.z == z; + } + return false; + } + +} diff --git a/src/main/java/com/glodblock/github/util/FluidPatternDetails.java b/src/main/java/com/glodblock/github/util/FluidPatternDetails.java new file mode 100644 index 00000000..a3cb37da --- /dev/null +++ b/src/main/java/com/glodblock/github/util/FluidPatternDetails.java @@ -0,0 +1,199 @@ +package com.glodblock.github.util; + +import appeng.api.networking.crafting.ICraftingPatternDetails; +import appeng.api.storage.data.IAEItemStack; +import appeng.util.item.AEItemStack; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class FluidPatternDetails implements ICraftingPatternDetails, Comparable{ + + private final ItemStack patternStack; + private IAEItemStack patternStackAe; + private IAEItemStack[] inputs = null, inputsCond = null, outputs = null, outputsCond = null; + private int priority = 0; + + public FluidPatternDetails(ItemStack stack) { + this.patternStack = stack; + this.patternStackAe = Objects.requireNonNull(AEItemStack.create(stack)); // s2g + } + + @Override + public ItemStack getPattern() { + return patternStack; + } + + @Override + public int getPriority() { + return priority; + } + + @Override + public void setPriority(int priority) { + this.priority = priority; + } + + @Override + public boolean isCraftable() { + return false; + } + + @Override + public boolean canSubstitute() { + return false; + } + + @Override + public IAEItemStack[] getInputs() { + return checkInitialized(inputs); + } + + @Override + public IAEItemStack[] getCondensedInputs() { + return checkInitialized(inputsCond); + } + + public boolean setInputs(IAEItemStack[] inputs) { + for (IAEItemStack stack : inputs) { // see note at top of class + if (stack == null) { + return false; + } + } + IAEItemStack[] condensed = condenseStacks(inputs); + if (condensed.length == 0) { + return false; + } + this.inputs = inputs; + this.inputsCond = condensed; + return true; + } + + @Override + public IAEItemStack[] getOutputs() { + return checkInitialized(outputs); + } + + @Override + public IAEItemStack[] getCondensedOutputs() { + return checkInitialized(outputsCond); + } + + public boolean setOutputs(IAEItemStack[] outputs) { + for (IAEItemStack stack : outputs) { // see note at top of class + if (stack == null) { + return false; + } + } + IAEItemStack[] condensed = condenseStacks(outputs); + if (condensed.length == 0) { + return false; + } + this.outputs = outputs; + this.outputsCond = condensed; + return true; + } + + private static IAEItemStack[] condenseStacks(IAEItemStack[] stacks) { + // AE item stacks are equivalent iff they are of the same item type (not accounting for stack size) + // thus, it's not the semantically-correct definition of "equal" but it's useful for matching item types + Map accMap = new HashMap<>(); + for (IAEItemStack stack : stacks) { + if (stack != null) { + IAEItemStack acc = accMap.get(stack); + if (acc == null) { + accMap.put(stack, stack.copy()); + } else { + acc.add(stack); + } + } + } + return accMap.values().toArray(new IAEItemStack[0]); + } + + @Override + public ItemStack getOutput(InventoryCrafting craftingInv, World world) { + throw new IllegalStateException("Not a crafting recipe!"); + } + + @Override + public boolean isValidItemForSlot(int slotIndex, ItemStack itemStack, World world) { + throw new IllegalStateException("Not a crafting recipe!"); + } + + private static T checkInitialized(@Nullable T value) { + if (value == null) { + throw new IllegalStateException("Pattern is not initialized!"); + } + return value; + } + + @Override + public int hashCode() { + return patternStackAe.hashCode(); + } + + @Override + public boolean equals(Object obj) { + // ae2 null-checks the pattern stack here for some reason, but doesn't null-check in hashCode() + // this is inconsistent, so i've just decided to assert non-null in the constructor, which is to say that + // the pattern stack can never be null here + return obj instanceof FluidPatternDetails && patternStackAe.equals(((FluidPatternDetails)obj).patternStackAe); + } + + @Override + public int compareTo(FluidPatternDetails o) { + return Integer.compare(o.priority, this.priority); + } + + public ItemStack writeToStack() { + NBTTagCompound tag = new NBTTagCompound(); + tag.setTag("Inputs", writeStackArray(checkInitialized(inputs))); + tag.setTag("Outputs", writeStackArray(checkInitialized(outputs))); + patternStack.setTagCompound(tag); + patternStackAe = Objects.requireNonNull(AEItemStack.create(patternStack)); + return patternStack; + } + + public static NBTTagList writeStackArray(IAEItemStack[] stacks) { + NBTTagList listTag = new NBTTagList(); + for (IAEItemStack stack : stacks) { + if (stack != null) { + // see note at top of class + NBTTagCompound stackTag = new NBTTagCompound(); + stack.writeToNBT(stackTag); + listTag.appendTag(stackTag); + } + } + return listTag; + } + + public boolean readFromStack() { + if (!patternStack.hasTagCompound()) { + return false; + } + NBTTagCompound tag = Objects.requireNonNull(patternStack.getTagCompound()); + // may be possible to enter a partially-correct state if setInputs succeeds but setOutputs failed + // but outside code should treat it as completely incorrect and not attempt to make calls + return setInputs(readStackArray(tag.getTagList("Inputs", Constants.NBT.TAG_COMPOUND), 9)) + && setOutputs(readStackArray(tag.getTagList("Outputs", Constants.NBT.TAG_COMPOUND), 3)); + } + + public static IAEItemStack[] readStackArray(NBTTagList listTag, int maxCount) { + // see note at top of class + IAEItemStack[] stacks = new IAEItemStack[Math.min(listTag.tagCount(), maxCount)]; + for (int i = 0; i < stacks.length; i++) { + stacks[i] = AEItemStack.loadItemStackFromNBT(listTag.getCompoundTagAt(i)); + } + return stacks; + } + +} diff --git a/src/main/java/com/glodblock/github/util/FluidSyncHelper.java b/src/main/java/com/glodblock/github/util/FluidSyncHelper.java new file mode 100644 index 00000000..d5bc1848 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/FluidSyncHelper.java @@ -0,0 +1,94 @@ +package com.glodblock.github.util; + + +import appeng.api.storage.data.IAEFluidStack; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.inventory.AEFluidInventory; +import com.glodblock.github.inventory.IAEFluidTank; +import com.glodblock.github.network.SPacketFluidSlot; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.ICrafting; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class FluidSyncHelper { + private final IAEFluidTank inv; + private final IAEFluidTank cache; + private final int idOffset; + + public FluidSyncHelper(final IAEFluidTank inv, final int idOffset ) + { + this.inv = inv; + this.cache = new AEFluidInventory( null, inv.getSlots() ); + this.idOffset = idOffset; + } + + public void sendFull( final Iterable listeners ) + { + this.sendDiffMap( this.createDiffMap( true ), listeners ); + } + + public void sendDiff( final Iterable listeners ) + { + this.sendDiffMap( this.createDiffMap( false ), listeners ); + } + + public void readPacket( final Map data ) + { + for( int i = 0; i < this.inv.getSlots(); ++i ) + { + if( data.containsKey( i + this.idOffset ) ) + { + this.inv.setFluidInSlot( i, data.get( i + this.idOffset ) ); + } + } + } + + private void sendDiffMap( final Map data, final Iterable listeners ) + { + if( data.isEmpty() ) + { + return; + } + + for( final ICrafting l : listeners ) + { + if( l instanceof EntityPlayerMP) + { + FluidCraft.proxy.netHandler.sendTo( new SPacketFluidSlot( data ), (EntityPlayerMP) l ); + } + } + } + + private Map createDiffMap(final boolean full ) + { + final Map ret = new HashMap<>(); + for( int i = 0; i < this.inv.getSlots(); ++i ) + { + if( full || !this.equalsSlot( i ) ) + { + ret.put( i + this.idOffset, this.inv.getFluidInSlot( i ) ); + } + if( !full ) + { + this.cache.setFluidInSlot( i, this.inv.getFluidInSlot( i ) ); + } + } + return ret; + } + + private boolean equalsSlot(int slot ) + { + final IAEFluidStack stackA = this.inv.getFluidInSlot( slot ); + final IAEFluidStack stackB = this.cache.getFluidInSlot( slot ); + + if( !Objects.equals( stackA, stackB ) ) + { + return false; + } + + return stackA == null || stackA.getStackSize() == stackB.getStackSize(); + } +} diff --git a/src/main/java/com/glodblock/github/util/ModAndClassUtil.java b/src/main/java/com/glodblock/github/util/ModAndClassUtil.java new file mode 100644 index 00000000..49b122d7 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/ModAndClassUtil.java @@ -0,0 +1,30 @@ +package com.glodblock.github.util; + +import appeng.api.config.ActionItems; +import cpw.mods.fml.common.Loader; + +public final class ModAndClassUtil { + + public static boolean GT5 = false; + public static boolean GT6 = false; + + public static boolean isDoubleButton; + + public static void init() { + try { + ActionItems x = ActionItems.DOUBLE; + isDoubleButton = true; + } catch (Exception e) { + isDoubleButton = false; + } + + if (Loader.isModLoaded("gregtech") && !Loader.isModLoaded("gregapi")) + GT5 = true; + if (Loader.isModLoaded("gregapi") && Loader.isModLoaded("gregapi_post")) + GT6 = true; + + } + + + +} diff --git a/src/main/java/com/glodblock/github/util/NameConst.java b/src/main/java/com/glodblock/github/util/NameConst.java new file mode 100644 index 00000000..ca588030 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/NameConst.java @@ -0,0 +1,29 @@ +package com.glodblock.github.util; + +import com.glodblock.github.FluidCraft; + +public class NameConst { + + public static final String BLOCK_FLUID_DISCRETIZER = "fluid_discretizer"; + public static final String BLOCK_FLUID_PATTERN_ENCODER = "fluid_pattern_encoder"; + public static final String BLOCK_FLUID_PACKET_DECODER = "fluid_packet_decoder"; + public static final String BLOCK_FLUID_INTERFACE = "fluid_interface"; + + public static final String ITEM_FLUID_DROP = "fluid_drop"; + public static final String ITEM_FLUID_ENCODED_PATTERN = "fluid_encoded_pattern"; + public static final String ITEM_PART_FLUID_PATTERN_TERMINAL = "part_fluid_pattern_terminal"; + public static final String ITEM_FLUID_PACKET = "fluid_packet"; + + public static final String TT_KEY = FluidCraft.MODID + ".tooltip."; + public static final String TT_INVALID_FLUID = TT_KEY + "invalid_fluid"; + public static final String TT_FLUID_PACKET = TT_KEY + "fluid_packet"; + public static final String TT_ENCODE_PATTERN = TT_KEY + "encode_pattern"; + + public static final String RES_KEY = FluidCraft.MODID + ":"; + + public static final String GUI_KEY = FluidCraft.MODID + ".gui."; + public static final String GUI_FLUID_PATTERN_TERMINAL = GUI_KEY + ITEM_PART_FLUID_PATTERN_TERMINAL; + public static final String GUI_FLUID_PATTERN_ENCODER = GUI_KEY + BLOCK_FLUID_PATTERN_ENCODER; + public static final String GUI_FLUID_PACKET_DECODER = GUI_KEY + BLOCK_FLUID_PACKET_DECODER; + +} diff --git a/src/main/java/com/glodblock/github/util/ObjectArrayIterator.java b/src/main/java/com/glodblock/github/util/ObjectArrayIterator.java new file mode 100644 index 00000000..7f86db6d --- /dev/null +++ b/src/main/java/com/glodblock/github/util/ObjectArrayIterator.java @@ -0,0 +1,163 @@ +package com.glodblock.github.util; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * An {@link java.util.Iterator Iterator} over an array of objects. + *

+ * This iterator does not support {@link #remove}, as the object array cannot be + * structurally modified. + *

+ * The iterator implements a {@link #reset} method, allowing the reset of the iterator + * back to the start if required. + * + * @param the type to iterate over + * @since 3.0 + * @version $Id: ObjectArrayIterator.java 1734648 2016-03-11 23:51:22Z ggregory $ + */ +public class ObjectArrayIterator implements /*Resettable*/ Iterator { + + /** The array */ + final E[] array; + /** The start index to loop from */ + final int startIndex; + /** The end index to loop to */ + final int endIndex; + /** The current iterator index */ + int index = 0; + + //------------------------------------------------------------------------- + /** + * Constructs an ObjectArrayIterator that will iterate over the values in the + * specified array. + * + * @param array the array to iterate over + * @throws NullPointerException if array is null + */ + @SafeVarargs + public ObjectArrayIterator(final E... array) { + this(array, 0, array.length); + } + + /** + * Constructs an ObjectArrayIterator that will iterate over the values in the + * specified array from a specific start index. + * + * @param array the array to iterate over + * @param start the index to start iterating at + * @throws NullPointerException if array is null + * @throws IndexOutOfBoundsException if the start index is out of bounds + */ + public ObjectArrayIterator(final E array[], final int start) { + this(array, start, array.length); + } + + /** + * Construct an ObjectArrayIterator that will iterate over a range of values + * in the specified array. + * + * @param array the array to iterate over + * @param start the index to start iterating at + * @param end the index (exclusive) to finish iterating at + * @throws IndexOutOfBoundsException if the start or end index is out of bounds + * @throws IllegalArgumentException if end index is before the start + * @throws NullPointerException if array is null + */ + public ObjectArrayIterator(final E array[], final int start, final int end) { + super(); + if (start < 0) { + throw new ArrayIndexOutOfBoundsException("Start index must not be less than zero"); + } + if (end > array.length) { + throw new ArrayIndexOutOfBoundsException("End index must not be greater than the array length"); + } + if (start > array.length) { + throw new ArrayIndexOutOfBoundsException("Start index must not be greater than the array length"); + } + if (end < start) { + throw new IllegalArgumentException("End index must not be less than start index"); + } + this.array = array; + this.startIndex = start; + this.endIndex = end; + this.index = start; + } + + // Iterator interface + //------------------------------------------------------------------------- + + /** + * Returns true if there are more elements to return from the array. + * + * @return true if there is a next element to return + */ + @Override + public boolean hasNext() { + return this.index < this.endIndex; + } + + /** + * Returns the next element in the array. + * + * @return the next element in the array + * @throws NoSuchElementException if all the elements in the array + * have already been returned + */ + @Override + public E next() { + if (hasNext() == false) { + throw new NoSuchElementException(); + } + return this.array[this.index++]; + } + + /** + * Throws {@link UnsupportedOperationException}. + * + * @throws UnsupportedOperationException always + */ + @Override + public void remove() { + throw new UnsupportedOperationException("remove() method is not supported for an ObjectArrayIterator"); + } + + // Properties + //------------------------------------------------------------------------- + + /** + * Gets the array that this iterator is iterating over. + * + * @return the array this iterator iterates over + */ + public E[] getArray() { + return this.array; + } + + /** + * Gets the start index to loop from. + * + * @return the start index + */ + public int getStartIndex() { + return this.startIndex; + } + + /** + * Gets the end index to loop to. + * + * @return the end index + */ + public int getEndIndex() { + return this.endIndex; + } + + /** + * Resets the iterator back to the start index. + */ + //@Override + public void reset() { + this.index = this.startIndex; + } + +} diff --git a/src/main/java/com/glodblock/github/util/RenderUtil.java b/src/main/java/com/glodblock/github/util/RenderUtil.java new file mode 100644 index 00000000..a0ef8c1d --- /dev/null +++ b/src/main/java/com/glodblock/github/util/RenderUtil.java @@ -0,0 +1,32 @@ +package com.glodblock.github.util; + +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.IIcon; + +public final class RenderUtil { + + public static void renderItemIcon(IIcon icon, double size, double z, float nx, float ny, float nz) { + renderItemIcon(icon, 0.0D, 0.0D, size, size, z, nx, ny, nz); + } + + public static void renderItemIcon(IIcon icon, double xStart, double yStart, double xEnd, double yEnd, double z, float nx, float ny, float nz) { + if (icon == null) { + return; + } + Tessellator.instance.startDrawingQuads(); + Tessellator.instance.setNormal(nx, ny, nz); + if (nz > 0.0F) { + Tessellator.instance.addVertexWithUV(xStart, yStart, z, icon.getMinU(), icon.getMinV()); + Tessellator.instance.addVertexWithUV(xEnd, yStart, z, icon.getMaxU(), icon.getMinV()); + Tessellator.instance.addVertexWithUV(xEnd, yEnd, z, icon.getMaxU(), icon.getMaxV()); + Tessellator.instance.addVertexWithUV(xStart, yEnd, z, icon.getMinU(), icon.getMaxV()); + } else { + Tessellator.instance.addVertexWithUV(xStart, yEnd, z, icon.getMinU(), icon.getMaxV()); + Tessellator.instance.addVertexWithUV(xEnd, yEnd, z, icon.getMaxU(), icon.getMaxV()); + Tessellator.instance.addVertexWithUV(xEnd, yStart, z, icon.getMaxU(), icon.getMinV()); + Tessellator.instance.addVertexWithUV(xStart, yStart, z, icon.getMinU(), icon.getMinV()); + } + Tessellator.instance.draw(); + } + +} diff --git a/src/main/java/com/glodblock/github/util/SetBackedMachineSet.java b/src/main/java/com/glodblock/github/util/SetBackedMachineSet.java new file mode 100644 index 00000000..6336362b --- /dev/null +++ b/src/main/java/com/glodblock/github/util/SetBackedMachineSet.java @@ -0,0 +1,60 @@ +package com.glodblock.github.util; + +import appeng.api.networking.IGridHost; +import appeng.api.networking.IGridNode; +import appeng.api.networking.IMachineSet; + +import javax.annotation.Nonnull; +import java.util.Iterator; +import java.util.Set; +import java.util.Spliterator; +import java.util.function.Consumer; + +public class SetBackedMachineSet implements IMachineSet { + + private final Class machineClass; + private final Set backingSet; + + public SetBackedMachineSet(Class machineClass, Set backingSet) { + this.machineClass = machineClass; + this.backingSet = backingSet; + } + + @Nonnull + @Override + public Class getMachineClass() { + return machineClass; + } + + @Override + public int size() { + return backingSet.size(); + } + + @Override + public boolean isEmpty() { + return backingSet.isEmpty(); + } + + @Override + public boolean contains(Object o) { + //noinspection SuspiciousMethodCalls + return backingSet.contains(o); + } + + @Override + public Iterator iterator() { + return backingSet.iterator(); + } + + @Override + public void forEach(Consumer action) { + backingSet.forEach(action); + } + + @Override + public Spliterator spliterator() { + return backingSet.spliterator(); + } + +} diff --git a/src/main/java/com/glodblock/github/util/Util.java b/src/main/java/com/glodblock/github/util/Util.java new file mode 100644 index 00000000..155f4721 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/Util.java @@ -0,0 +1,102 @@ +package com.glodblock.github.util; + +import appeng.api.config.SecurityPermissions; +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridHost; +import appeng.api.networking.IGridNode; +import appeng.api.networking.security.ISecurityGrid; +import appeng.api.parts.IPart; +import com.glodblock.github.common.item.ItemFluidPacket; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidContainerItem; + +public final class Util { + + public static EnumFacing from(ForgeDirection direction) { + switch (direction) { + case WEST: return EnumFacing.EAST; + case EAST: return EnumFacing.WEST; + case UNKNOWN: return null; + default: { + int o = direction.ordinal(); + return EnumFacing.values()[o]; + } + } + } + + public static ForgeDirection from(EnumFacing direction) { + switch (direction) { + case WEST: return ForgeDirection.EAST; + case EAST: return ForgeDirection.WEST; + default: { + int o = direction.ordinal(); + return ForgeDirection.values()[o]; + } + } + } + + public static boolean hasPermission(EntityPlayer player, SecurityPermissions permission, IGrid grid) { + return grid == null || hasPermission(player, permission, (ISecurityGrid) grid.getCache(ISecurityGrid.class)); + } + + public static boolean hasPermission(EntityPlayer player, SecurityPermissions permission, IGridHost host) { + return hasPermission(player, permission, host, ForgeDirection.UNKNOWN); + } + + public static boolean hasPermission(EntityPlayer player, SecurityPermissions permission, IGridHost host, ForgeDirection side) { + return host == null || hasPermission(player, permission, host.getGridNode(side)); + } + + public static boolean hasPermission(EntityPlayer player, SecurityPermissions permission, IGridNode host) { + return host == null || hasPermission(player, permission, host.getGrid()); + } + + public static boolean hasPermission(EntityPlayer player, SecurityPermissions permission, IPart part) { + return part == null || hasPermission(player, permission, part.getGridNode()); + } + + public static boolean hasPermission(EntityPlayer player, SecurityPermissions permission, ISecurityGrid securityGrid) { + return player == null || permission == null || securityGrid == null || securityGrid.hasPermission(player, permission); + } + + public static ItemStack copyStackWithSize(ItemStack itemStack, int size) + { + if (size == 0 || itemStack == null) + return null; + ItemStack copy = itemStack.copy(); + copy.stackSize = size; + return copy; + } + + public static FluidStack getFluidFromItem(ItemStack stack) { + if (stack != null && (stack.getItem() instanceof IFluidContainerItem || FluidContainerRegistry.isContainer(stack))) { + if (stack.getItem() instanceof IFluidContainerItem) { + FluidStack fluid = ((IFluidContainerItem) stack.getItem()).getFluid(stack); + if (fluid != null) { + FluidStack fluid0 = fluid.copy(); + fluid0.amount *= stack.stackSize; + return fluid0; + } + } + if (FluidContainerRegistry.isContainer(stack)) { + FluidStack fluid = FluidContainerRegistry.getFluidForFilledItem(stack); + if (fluid != null) { + FluidStack fluid0 = fluid.copy(); + fluid0.amount *= stack.stackSize; + return fluid0; + } + } + } + return null; + } + + public static boolean isFluidPacket(ItemStack stack) { + return stack != null && stack.getItem() instanceof ItemFluidPacket; + } + +} diff --git a/src/main/resources/assets/ae2fc/lang/en_US.lang b/src/main/resources/assets/ae2fc/lang/en_US.lang new file mode 100644 index 00000000..dde8ce6d --- /dev/null +++ b/src/main/resources/assets/ae2fc/lang/en_US.lang @@ -0,0 +1,17 @@ +item.fluid_drop.name=drop of %s +item.fluid_encoded_pattern.name=Encode Pattern +item.part_fluid_pattern_terminal.name=ME Fluid Pattern Terminal +item.fluid_packet.name=Fluid Packet + +tile.fluid_discretizer.name=Fluid Discretizer +tile.fluid_pattern_encoder.name=Fluid Pattern Encoder +tile.fluid_packet_decoder.name=ME Fluid Packet Decoder +tile.fluid_interface.name=Fluid Interface + +ae2fc.tooltip.invalid_fluid=Invalid fluid! +ae2fc.tooltip.encode_pattern=Encode Patter +ae2fc.tooltip.fluid_packet=Use a Fluid Packet Decoder to\nconvert this back into fluid. + +ae2fc.gui.part_fluid_pattern_terminal=Fluid Pattern Terminal +ae2fc.gui.fluid_pattern_encoder=Fluid Pattern Encoder +ae2fc.gui.fluid_packet_decoder=ME Fluid Packet Decoder diff --git a/src/main/resources/assets/ae2fc/textures/blocks/fluid_discretizer.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_discretizer.png new file mode 100644 index 00000000..d08e7976 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_discretizer.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/fluid_interface.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_interface.png new file mode 100644 index 00000000..1fd54c43 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_interface.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/fluid_interface_a.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_interface_a.png new file mode 100644 index 00000000..d8948d15 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_interface_a.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/fluid_interface_arrow.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_interface_arrow.png new file mode 100644 index 00000000..36345e39 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_interface_arrow.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/fluid_packet_decoder.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_packet_decoder.png new file mode 100644 index 00000000..623fb299 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_packet_decoder.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoder.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoder.png new file mode 100644 index 00000000..96753339 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoder.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoderBottom.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoderBottom.png new file mode 100644 index 00000000..38ca52d3 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoderBottom.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoderSide.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoderSide.png new file mode 100644 index 00000000..b2b56014 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoderSide.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/pattern_terminal_bright.png b/src/main/resources/assets/ae2fc/textures/blocks/pattern_terminal_bright.png new file mode 100644 index 00000000..11e59a01 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/pattern_terminal_bright.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/pattern_terminal_dark.png b/src/main/resources/assets/ae2fc/textures/blocks/pattern_terminal_dark.png new file mode 100644 index 00000000..44e4c64f Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/pattern_terminal_dark.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/pattern_terminal_medium.png b/src/main/resources/assets/ae2fc/textures/blocks/pattern_terminal_medium.png new file mode 100644 index 00000000..a9271aa8 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/pattern_terminal_medium.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/terminal_broad.png b/src/main/resources/assets/ae2fc/textures/blocks/terminal_broad.png new file mode 100644 index 00000000..5c35091f Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/terminal_broad.png differ diff --git a/src/main/resources/assets/ae2fc/textures/gui/fluid_packet_decoder.png b/src/main/resources/assets/ae2fc/textures/gui/fluid_packet_decoder.png new file mode 100644 index 00000000..4e17ee57 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/gui/fluid_packet_decoder.png differ diff --git a/src/main/resources/assets/ae2fc/textures/gui/fluid_pattern_encoder.png b/src/main/resources/assets/ae2fc/textures/gui/fluid_pattern_encoder.png new file mode 100644 index 00000000..045611f8 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/gui/fluid_pattern_encoder.png differ diff --git a/src/main/resources/assets/ae2fc/textures/items/fluid_drop.png b/src/main/resources/assets/ae2fc/textures/items/fluid_drop.png new file mode 100644 index 00000000..32ae84ab Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/items/fluid_drop.png differ diff --git a/src/main/resources/assets/ae2fc/textures/items/fluid_encoded_pattern.png b/src/main/resources/assets/ae2fc/textures/items/fluid_encoded_pattern.png new file mode 100644 index 00000000..1a19d070 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/items/fluid_encoded_pattern.png differ