diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
new file mode 100644
index 00000000..b8db7758
--- /dev/null
+++ b/.github/workflows/nightly.yml
@@ -0,0 +1,58 @@
+# This workflow uses actions that are not certified by GitHub.
+# They are provided by a third-party and are governed by
+# separate terms of service, privacy policy, and support
+# documentation.
+# This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created
+# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle
+
+name: TesseractAPI Nightly
+on:
+ push:
+ branches:
+ - dev
+ pull_request:
+ branches:
+ - dev
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up JDK 11
+ uses: actions/setup-java@v2
+ with:
+ java-version: '11'
+ distribution: 'adopt'
+ server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
+ settings-path: ${{ github.workspace }} # location for the settings.xml file
+ - name: Setup Gradle Dependencies Cache
+ uses: actions/cache@v2
+ with:
+ path: ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-caches-${{ hashFiles('**/*.gradle','**/gradle/wrapper/gradle-wrapper.properties','**/*.properties') }}
+ - name: Build with Gradle
+ uses: gradle/gradle-build-action@4137be6a8bf7d7133955359dbd952c0ca73b1021
+ with:
+ arguments: build
+ # The USERNAME and TOKEN need to correspond to the credential environment variables used in
+ # the publishing section of your build.gradle
+ - name: Upload Artifact
+ uses: actions/upload-artifact@v2
+ with:
+ name: TesseractAPI JAR
+ path: build/libs
+ env:
+ USERNAME: ${{ github.actor }}
+ TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Cleanup Gradle Cache
+ # Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
+ # Restoring these files from a GitHub Actions cache might cause problems for future builds.
+ run: |
+ rm -f ~/.gradle/caches/modules-2/modules-2.lock
+ rm -f ~/.gradle/caches/modules-2/gc.properties
diff --git a/.gitignore b/.gitignore
index d7973e18..acc4382d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,3 +24,6 @@ run
# Files from Forge MDK
forge*changelog.txt
+
+.vscode
+mcmodsrepo/
diff --git a/build.gradle b/build.gradle
index 6759e39b..3b621758 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,100 +1,208 @@
buildscript {
repositories {
+ maven { url 'https://files.minecraftforge.net/maven' }
+ jcenter()
+ mavenCentral()
+ gradlePluginPortal()
maven {
- url "https://plugins.gradle.org/m2/"
+ name = 'parchment'
+ url = 'https://maven.parchmentmc.org'
}
}
dependencies {
- classpath "com.github.jengelman.gradle.plugins:shadow:5.2.0"
+ classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1+', changing: true
+ classpath 'org.parchmentmc:librarian:1.+'
}
}
-
plugins {
id 'maven-publish'
- id 'java'
+ id 'com.github.johnrengelman.shadow' version '7.1.0'
+}
+
+def isCI = System.getenv("GITHUB_ACTION")
+def isRELEASE = System.getenv("GITHUB_RELEASE")
+def gitHash() {
+ String hash = System.getenv("GITHUB_SHA")
+ if (hash != null) return hash.substring(0,8)
+ return ""
}
+
+apply plugin: 'net.minecraftforge.gradle'
+apply plugin: "eclipse"
apply plugin: "com.github.johnrengelman.shadow"
-//evaluationDependsOn(':version')
+apply plugin: 'java'
+apply plugin: 'org.parchmentmc.librarian.forgegradle'
+archivesBaseName = 'TesseractAPI'
+version = "${minecraft_version}-${mod_version}"
+group = "com.github.gregtech-intergalactical"
+
+if (isCI) {
+ version = version + "-" + gitHash()
+}
-group = 'com.github.gregtech-intergalactical' // http://maven.apache.org/guides/mini/guide-naming-conventions.html
-archivesBaseName = 'tesseract'
+java.toolchain.languageVersion = JavaLanguageVersion.of(8)
+configurations {
+ shadow
+}
+minecraft {
+ // The mappings can be changed at any time, and must be in the following format.
+ // snapshot_YYYYMMDD Snapshot are built nightly.
+ // stable_# Stables are built at the discretion of the MCP team.
+ // Use non-default mappings at your own risk. they may not always work.
+ // Simply re-run your setup task after changing the mappings to update your workspace.
+ mappings channel: 'parchment', version: '2021.10.17-1.16.5'
+ // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
+
+ // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
+
+ // Default run configurations.
+ // These can be tweaked, removed, or duplicated as needed.
+ runs {
+ client {
+ workingDirectory project.file('run')
+
+ // Recommended logging data for a userdev environment
+ property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
+
+ // Recommended logging level for the console
+ property 'forge.logging.console.level', 'debug'
+
+ mods {
+ tesseractapi {
+ source sourceSets.main
+ }
+ }
+ }
-sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
+ server {
+ workingDirectory project.file('run')
-assemble.dependsOn shadowJar
+ // Recommended logging data for a userdev environment
+ property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
-configurations {
- embed
- deobf
+ // Recommended logging level for the console
+ property 'forge.logging.console.level', 'debug'
- embed.extendsFrom(implementation)
- testCompile.extendsFrom(shadow)
-}
+ mods {
+ tesseractapi {
+ source sourceSets.main
+ }
+ }
+ }
-shadowJar {
- configurations = [project.configurations.embed]
+ data {
+ workingDirectory project.file('run')
+
+ // Recommended logging data for a userdev environment
+ property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
+
+ // Recommended logging level for the console
+ property 'forge.logging.console.level', 'debug'
+
+ args '--mod', 'tesseract', '--all', '--output', '"' + rootProject.file('src/generated/resources/') + '"',
+ '--existing', '"' + sourceSets.main.resources.srcDirs[0] + '"'
+
+ mods {
+ tesseractapi {
+ source sourceSets.main
+ }
+ }
+ }
+ }
}
+
+
// Deobfuscated jar; development purposes.
-import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
-task deobfJar(type: ShadowJar) {
- from sourceSets.main.output
- configurations = [project.configurations.deobf]
- classifier "dev"
-}
+//import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
repositories {
jcenter()
- maven { url = 'https://files.minecraftforge.net/maven' }
+}
+afterEvaluate { project ->
+ project.tasks.publishToMavenLocal {
+ onlyIf {
+ return rootProject.name == "${modid}"
+ }
+ }
+}
+task sourcesJar(type: Jar) {
+ from sourceSets.main.allSource
+ archiveBaseName.set(project.archivesBaseName)
+ archiveVersion.set("${project.version}")
+ archiveClassifier.set('sources')
}
+/*task javadocJar(type: Jar, dependsOn: javadoc) {
+ from javadoc.destinationDir
+ archiveClassifier.set('javadoc')
+}*/
+shadowJar {
+ configurations = [project.configurations.shadow]
+ archiveClassifier.set('')
+}
+reobf {
+ shadowJar {}
+}
dependencies {
- // Main dependencies:
- // Declare here your dependencies here with:
- // 'shadow' if the jar shouldn't be included in the fat jar,
- // 'implementation' if the jar should be included in the jar
- shadow 'org.apache.commons:commons-collections4:4.4'
- shadow 'it.unimi.dsi:fastutil:8.2.1'
-
- // Test dependencies:
- testImplementation 'junit:junit:4.11'
-
- // Embedded dependencies:
- // Those will be included in the fat jar.
- // You will likely not edit those dependencies.
- if (rootProject.name == "tesseract") {
- embed project(path: ':forge', configuration: 'archives')
- deobf project(path: ':forge', configuration: 'deobf')
- } else {
- embed project(path: ':tesseract:forge', configuration: 'archives')
- deobf project(path: ':tesseract:forge', configuration: 'deobf')
- }
-
- //embed project(path: ':fabric', configuration: 'archives') TODO coming soon(tm).
+ minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
+ testImplementation('junit:junit:4.11')
}
+afterEvaluate { project ->
+ project.tasks.publishToMavenLocal {
+ onlyIf {
+ return rootProject.name == "${modid}"
+ }
+ }
+}
+if (isCI) {
+ jar.finalizedBy('reobfJar')
+ println("In CI mode")
+}
jar {
zip64 true
+ manifest {
+ attributes([
+ "Specification-Title": project.name,
+ "Specification-Vendor": "GregTech Intergalactical",
+ "Specification-Version": project.version,
+ "Implementation-Title": project.name,
+ "Implementation-Version": project.version,
+ "Implementation-Vendor": "GregTech Intergalactical",
+ "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
+ ])
+ }
}
-// Maven publishing:
-
-static def configurePublishingRepositories(repositoryHandler) {
- if (System.env.MAVEN_URL) {
- repositoryHandler.maven {
- url = System.env.MAVEN_URL
-
- if (System.env.MAVEN_USERNAME && System.env.MAVEN_PASSWORD) {
- authentication {
- basic(BasicAuthentication)
- }
-
+artifacts {
+ archives jar, shadowJar, sourcesJar//, javadocJar
+}
+publishing {
+ tasks.publish.dependsOn 'build', 'reobfJar'
+ publications {
+ mavenJava(MavenPublication) {
+ //artifactId = archivesBaseName
+ artifact shadowJar
+ }
+ }
+ repositories {
+ if (isCI && isRELEASE) {
+ maven {
+ name = "GitHubPackages"
+ url = "https://maven.pkg.github.com/GregTech-Intergalactical/TesseractAPI"
credentials {
- username = System.env.USERNAME
- password = System.env.PASSWORD
+ username = System.getenv("GITHUB_ACTOR")
+ password = System.getenv("GITHUB_TOKEN")
}
}
+ } else {
+ maven { url "file:///${project.projectDir}/mcmodsrepo"}
}
}
-}
\ No newline at end of file
+ //repositories {
+ // rootProject.configurePublishingRepositories(delegate)
+ //}
+}
+
diff --git a/forge/build.gradle b/forge/build.gradle
index 3a07d958..96c126a6 100644
--- a/forge/build.gradle
+++ b/forge/build.gradle
@@ -18,9 +18,14 @@ plugins {
apply plugin: 'net.minecraftforge.gradle'
apply plugin: "com.github.johnrengelman.shadow"
-archivesBaseName = 'tesseract-forge'
-version = rootProject.version
-group = rootProject.group
+
+apply plugin: 'java'
+
+archivesBaseName = 'tesseractforge'
+version = "0.0.1"
+group = "com.github.gregtech-intergalactical"
+
+sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
minecraft {
// The mappings can be changed at any time, and must be in the following format.
@@ -46,7 +51,7 @@ minecraft {
property 'forge.logging.console.level', 'debug'
mods {
- tesseract {
+ tesseractforge {
source sourceSets.main
}
}
@@ -62,7 +67,7 @@ minecraft {
property 'forge.logging.console.level', 'debug'
mods {
- tesseract {
+ tesseractforge {
source sourceSets.main
}
}
@@ -77,11 +82,11 @@ minecraft {
// Recommended logging level for the console
property 'forge.logging.console.level', 'debug'
- args '--mod', 'tesseract', '--all', '--output', '"' + rootProject.file('src/generated/resources/') + '"',
+ args '--mod', 'tesseractforge', '--all', '--output', '"' + rootProject.file('src/generated/resources/') + '"',
'--existing', '"' + sourceSets.main.resources.srcDirs[0] + '"'
mods {
- tesseract {
+ tesseractforge {
source sourceSets.main
}
}
@@ -103,30 +108,34 @@ shadowJar {
// Deobfuscated jar; development purposes.
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
-task deobfJar(type: ShadowJar, dependsOn: 'classes') {
+task deobfJar(type: ShadowJar) {
from sourceSets.main.output
configurations = [project.configurations.embed]
- classifier "dev"
+ classifier "deobf"
+ //dependsOn gradle.includedBuild("tesseract").task(":deobfJar")
}
-// Sources jar; development purposes.
-task sourcesJar(type: Jar) {
+task sourcesJar(type: ShadowJar, dependsOn: classes) {
+ description = 'Creates a JAR containing the source code.'
+ classifier 'sources'
from sourceSets.main.allSource
- classifier "sources"
+}
+
+artifacts {
+ archives sourcesJar
+ archives deobfJar
}
repositories {
jcenter()
}
+
dependencies {
minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
- if (rootProject.name == "tesseract") {
- embed project(path: ":")
- } else {
- embed project(path: ":tesseract")
- }
+ embed project(':tesseract')//(group: 'com.github.gregtech-intergalactical', name: 'tesseract')
}
+
publishing {
publications {
forge(MavenPublication) {
@@ -140,6 +149,6 @@ publishing {
//}
}
-artifacts {
- deobf deobfJar
+jar {
+ zip64 true
}
\ No newline at end of file
diff --git a/forge/gradle/wrapper/gradle-wrapper.jar b/forge/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..7a3265ee
Binary files /dev/null and b/forge/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/forge/gradle/wrapper/gradle-wrapper.properties b/forge/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..d4ac5175
--- /dev/null
+++ b/forge/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Thu Jul 02 03:20:41 CEST 2020
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/forge/gradlew b/forge/gradlew
new file mode 100755
index 00000000..cccdd3d5
--- /dev/null
+++ b/forge/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# 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\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# 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
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+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" -a "$nonstop" = "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"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # 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
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/forge/settings.gradle b/forge/settings.gradle
new file mode 100644
index 00000000..9607644d
--- /dev/null
+++ b/forge/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = 'tesseractforge'
+
diff --git a/forge/src/main/java/tesseract/Tesseract.java b/forge/src/main/java/tesseract/Tesseract.java
deleted file mode 100644
index 2fb832ac..00000000
--- a/forge/src/main/java/tesseract/Tesseract.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package tesseract;
-
-import net.minecraft.item.ItemStack;
-import net.minecraftforge.common.MinecraftForge;
-import net.minecraftforge.eventbus.api.SubscribeEvent;
-import net.minecraftforge.fluids.FluidStack;
-import net.minecraftforge.fml.common.Mod;
-import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
-import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent;
-import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
-import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
-import tesseract.api.GraphWrapper;
-import tesseract.api.gt.IGTCable;
-import tesseract.api.gt.IGTNode;
-import tesseract.api.fluid.IFluidNode;
-import tesseract.api.fluid.IFluidPipe;
-import tesseract.api.fe.FEController;
-import tesseract.api.fe.IFECable;
-import tesseract.api.fe.IFENode;
-import tesseract.api.item.IItemNode;
-import tesseract.api.item.IItemPipe;
-import tesseract.api.item.ItemController;
-import tesseract.controller.Energy;
-import tesseract.controller.Fluid;
-
-@Mod(Tesseract.API_ID)
-@Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD)
-public class Tesseract {
-
- public static final String API_ID = "tesseract";
- public static final String API_NAME = "Tesseract API";
- public static final String VERSION = "0.0.1";
- public static final String DEPENDS = "";
-
- public static GraphWrapper FE_ENERGY;
- public static GraphWrapper GT_ENERGY;
- public static GraphWrapper> FLUID;
- public static GraphWrapper> ITEM;
-
- public Tesseract() {
- FMLJavaModLoadingContext.get().getModEventBus().register(this);
- MinecraftForge.EVENT_BUS.register(this);
- }
-
- @SubscribeEvent
- public void init(FMLServerAboutToStartEvent e) {
- FE_ENERGY = new GraphWrapper<>(FEController::new);
- GT_ENERGY = new GraphWrapper<>(Energy::new);
- FLUID = new GraphWrapper<>(Fluid::new);
- ITEM = new GraphWrapper<>(ItemController::new);
- }
-}
diff --git a/forge/src/main/java/tesseract/controller/Energy.java b/forge/src/main/java/tesseract/controller/Energy.java
deleted file mode 100644
index 1959955e..00000000
--- a/forge/src/main/java/tesseract/controller/Energy.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package tesseract.controller;
-
-import net.minecraft.util.math.BlockPos;
-import net.minecraft.world.Explosion;
-import tesseract.api.gt.GTController;
-
-// TODO: Make explosions depend on voltage, amp
-public class Energy extends GTController {
-
- /**
- * Creates instance of the tesseract.controller.
- *
- * @param dim The dimension id.
- */
- public Energy(int dim) {
- super(dim);
- }
-
- @Override
- public void onNodeOverVoltage(int dim, long pos, int voltage) {
- Utils.getServerWorld(dim).ifPresent(w -> Utils.createExplosion(w, BlockPos.fromLong(pos), 4.0F, Explosion.Mode.BREAK));
- }
-
- @Override
- public void onCableOverAmperage(int dim, long pos, int amperage) {
- Utils.getServerWorld(dim).ifPresent(w -> Utils.createFireAround(w, BlockPos.fromLong(pos)));
- }
-
- @Override
- public void onCableOverVoltage(int dim, long pos, int voltage) {
- Utils.getServerWorld(dim).ifPresent(w -> Utils.createFireAround(w, BlockPos.fromLong(pos)));
- }
-}
diff --git a/forge/src/main/java/tesseract/controller/Fluid.java b/forge/src/main/java/tesseract/controller/Fluid.java
deleted file mode 100644
index 7a4db565..00000000
--- a/forge/src/main/java/tesseract/controller/Fluid.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package tesseract.controller;
-
-import net.minecraft.block.Blocks;
-import net.minecraft.fluid.Fluids;
-import net.minecraft.util.math.BlockPos;
-import net.minecraft.world.Explosion;
-import tesseract.api.fluid.FluidController;
-import tesseract.api.fluid.FluidData;
-import tesseract.api.fluid.IFluidNode;
-
-import javax.annotation.Nonnull;
-
-// TODO: Make explosions depend on pressure, capacity, temperature
-public class Fluid extends FluidController> {
-
- /**
- * Creates instance of the tesseract.controller.
- *
- * @param dim The dimension id.
- */
- public Fluid(int dim) {
- super(dim);
- }
-
- @Override
- public void onPipeOverPressure(int dim, long pos, int pressure) {
- Utils.getServerWorld(dim).ifPresent(w -> Utils.createExplosion(w, BlockPos.fromLong(pos), 4.0F, Explosion.Mode.BREAK));
- }
-
- @Override
- public void onPipeOverCapacity(int dim, long pos, int capacity) {
- Utils.getServerWorld(dim).ifPresent(w -> Utils.createExplosion(w, BlockPos.fromLong(pos), 1.0F, Explosion.Mode.NONE));
- }
-
- @Override
- public void onPipeOverTemp(int dim, long pos, int temperature) {
- Utils.getServerWorld(dim).ifPresent(w -> w.setBlockState(BlockPos.fromLong(pos), temperature >= Fluids.LAVA.getAttributes().getTemperature() ? Blocks.LAVA.getDefaultState() : Blocks.FIRE.getDefaultState()));
- }
-
- @Override
- public void onPipeGasLeak(int dim, long pos, @Nonnull FluidData fluid) {
- T resource = fluid.getStack();
- // resource.setAmount((int)(resource.getAmount() * AntimatterConfig.GAMEPLAY.PIPE_LEAK));
- }
-}
diff --git a/forge/src/main/java/tesseract/controller/Utils.java b/forge/src/main/java/tesseract/controller/Utils.java
deleted file mode 100644
index 25a5cc3f..00000000
--- a/forge/src/main/java/tesseract/controller/Utils.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package tesseract.controller;
-
-import net.minecraft.block.Blocks;
-import net.minecraft.particles.ParticleTypes;
-import net.minecraft.util.Direction;
-import net.minecraft.util.math.BlockPos;
-import net.minecraft.world.Explosion;
-import net.minecraft.world.dimension.DimensionType;
-import net.minecraft.world.server.ServerWorld;
-import net.minecraftforge.fml.server.ServerLifecycleHooks;
-
-import java.util.Optional;
-
-public class Utils {
- public static Optional getServerWorld(int dimension) {
- DimensionType type = DimensionType.getById(dimension);
- if (type == null) return Optional.empty();
- return Optional.of(ServerLifecycleHooks.getCurrentServer().getWorld(type));
- }
-
- public static void createExplosion(ServerWorld world, BlockPos pos, float explosionRadius, Explosion.Mode modeIn) {
- world.createExplosion(null, pos.getX(), pos.getY() + 0.0625D, pos.getZ(), explosionRadius, true, modeIn);
- world.spawnParticle(ParticleTypes.SMOKE, pos.getX(), pos.getY() + 0.5D, pos.getZ(), 1, 0, 0, 0, 0.0D);
- }
-
- public static void createFireAround(ServerWorld world, BlockPos pos) {
- boolean fired = false;
- for (Direction side : Direction.values()) {
- BlockPos offset = pos.offset(side);
- if (world.getBlockState(offset) == Blocks.AIR.getDefaultState()) {
- world.setBlockState(offset, Blocks.FIRE.getDefaultState());
- fired = true;
- }
- }
- if (!fired) world.setBlockState(pos, Blocks.FIRE.getDefaultState());
- }
-}
diff --git a/gradle.properties b/gradle.properties
index 784899a6..535bffbc 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -2,3 +2,12 @@
# This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs=-Xmx3G
org.gradle.daemon=false
+
+mod_version=0.1
+
+mappings_version=20210309-1.16.5
+minecraft_version=1.16.5
+forge_version=36.2.29
+jei_version=1.16.4:7.6.1.71
+
+modid=TesseractAPI
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 5028f28f..e750102e 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/settings.gradle b/settings.gradle
index 687b0c33..2c0ddb45 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,14 +1,2 @@
-pluginManagement {
- repositories {
- gradlePluginPortal()
+rootProject.name = "${modid}"
- maven { url = 'https://files.axelandre42.ovh/maven/' }
- maven { url = 'https://files.minecraftforge.net/maven/' }
- jcenter()
- mavenCentral()
- }
-}
-
-rootProject.name = 'tesseract'
-include ':version'
-include ':forge'
diff --git a/src/main/java/tesseract/Tesseract.java b/src/main/java/tesseract/Tesseract.java
new file mode 100644
index 00000000..bebd6bb8
--- /dev/null
+++ b/src/main/java/tesseract/Tesseract.java
@@ -0,0 +1,94 @@
+package tesseract;
+
+import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
+import net.minecraft.world.IWorld;
+import net.minecraft.world.World;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.event.TickEvent;
+import net.minecraftforge.event.world.WorldEvent;
+import net.minecraftforge.fml.common.Mod;
+import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
+import net.minecraftforge.fml.event.server.FMLServerStoppedEvent;
+import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import tesseract.api.GraphWrapper;
+import tesseract.api.capability.TesseractGTCapability;
+import tesseract.api.fluid.FluidTransaction;
+import tesseract.api.fluid.IFluidNode;
+import tesseract.api.fluid.IFluidPipe;
+import tesseract.api.gt.GTTransaction;
+import tesseract.api.gt.IGTCable;
+import tesseract.api.gt.IGTNode;
+import tesseract.api.item.IItemNode;
+import tesseract.api.item.IItemPipe;
+import tesseract.api.item.ItemController;
+import tesseract.api.item.ItemTransaction;
+import tesseract.controller.Energy;
+import tesseract.controller.Fluid;
+
+import java.util.Set;
+import java.util.function.Consumer;
+
+@Mod(Tesseract.API_ID)
+//@Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD)
+public class Tesseract {
+
+ public static final String API_ID = "tesseractapi";
+ public static final String API_NAME = "Tesseract API";
+ public static final String VERSION = "0.0.1";
+ public static final String DEPENDS = "";
+
+ public static final Logger LOGGER = LogManager.getLogger(API_ID);
+
+ private final static Set firstTick = new ObjectOpenHashSet<>();
+ //public static GraphWrapper FE_ENERGY = new GraphWrapper<>(FEController::new);
+ public static GraphWrapper GT_ENERGY = new GraphWrapper<>(Energy::new, IGTNode.GT_GETTER);
+ public static GraphWrapper FLUID = new GraphWrapper<>(Fluid::new, IFluidNode.GETTER);
+ public static GraphWrapper ITEM = new GraphWrapper<>(ItemController::new, IItemNode.GETTER);
+
+ public static final int HEALTH_CHECK_TIME = 1000;
+
+ public Tesseract() {
+ FMLJavaModLoadingContext.get().getModEventBus().addListener(this::commonSetup);
+ MinecraftForge.EVENT_BUS.addListener(this::serverStoppedEvent);
+ MinecraftForge.EVENT_BUS.addListener(this::worldUnloadEvent);
+ MinecraftForge.EVENT_BUS.addListener(this::onServerTick);
+ }
+
+ public static boolean hadFirstTick(IWorld world) {
+ return firstTick.contains(world);
+ }
+
+ public void commonSetup(FMLCommonSetupEvent event) {
+ TesseractGTCapability.register();
+ }
+
+ public void serverStoppedEvent(FMLServerStoppedEvent e) {
+ firstTick.clear();
+ //FE_ENERGY.clear();
+ GraphWrapper.getWrappers().forEach(GraphWrapper::clear);
+ }
+
+ public void worldUnloadEvent(WorldEvent.Unload e) {
+ if (!(e.getWorld() instanceof World) || ((World) e.getWorld()).isClientSide) return;
+ //FE_ENERGY.removeWorld((World) e.getWorld());
+ GraphWrapper.getWrappers().forEach(g -> g.removeWorld((World)e.getWorld()));
+ firstTick.remove(e.getWorld());
+ }
+
+ public void onServerTick(TickEvent.WorldTickEvent event) {
+ if (event.side.isClient()) return;
+ World dim = event.world;
+ if (!hadFirstTick(dim)) {
+ firstTick.add(event.world);
+ GraphWrapper.getWrappers().forEach(t -> t.onFirstTick(dim));
+ }
+ if (event.phase == TickEvent.Phase.START) {
+ GraphWrapper.getWrappers().forEach(t -> t.tick(dim));
+ }
+ if (HEALTH_CHECK_TIME > 0 && event.world.getGameTime() % HEALTH_CHECK_TIME == 0) {
+ GraphWrapper.getWrappers().forEach(GraphWrapper::healthCheck);
+ }
+ }
+}
diff --git a/src/main/java/tesseract/api/Consumer.java b/src/main/java/tesseract/api/Consumer.java
index 5b4f78b6..ba526835 100644
--- a/src/main/java/tesseract/api/Consumer.java
+++ b/src/main/java/tesseract/api/Consumer.java
@@ -1,22 +1,24 @@
package tesseract.api;
-import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
-import tesseract.graph.Path;
+import static java.lang.Integer.compare;
import java.util.Comparator;
-import static java.lang.Integer.compare;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
+import tesseract.api.capability.TesseractBaseCapability;
+import tesseract.graph.Path;
/**
* A class that acts as a wrapper for a node component.
*/
-abstract public class Consumer {
+abstract public class Consumer {
protected final N node;
protected final ConnectionType connection;
- protected Long2ObjectMap full;
- protected Long2ObjectMap cross;
+ protected Long2ObjectMap full = Long2ObjectMaps.emptyMap();
+ protected Long2ObjectMap cross = Long2ObjectMaps.emptyMap();
protected int distance;
// Way of the sorting by the priority level and the distance to the node
@@ -28,16 +30,32 @@ abstract public class Consumer {
* @param node The node instance.
* @param path The path information.
*/
- protected Consumer(N node, Path path) {
+ protected Consumer(N node, N producer, Path path) {
this.node = node;
if (path != null) {
- full = path.getFull();
+ full = path.getFull();
cross = path.getCross();
}
+ int fullSize = full.size();
+ if (producer instanceof TesseractBaseCapability) {
+ TesseractBaseCapability> cap = (TesseractBaseCapability>) producer;
+ long pos = cap.tile.getBlockPos().asLong();
+ if (full.size() == 0) {
+ full = Long2ObjectMaps.singleton(pos, (C) cap.tile);
+ } else {
+ full.put(pos, (C) cap.tile);
+ }
+ if (cross.size() == 0) {
+ cross = Long2ObjectMaps.singleton(pos, (C) cap.tile);
+ } else {
+ cross.put(pos, (C) cap.tile);
+ }
+ }
+ int crossSize = cross.size();
- if (cross == null || cross.size() == 0) {
- connection = (full == null) ? ConnectionType.ADJACENT : ConnectionType.SINGLE;
+ if (crossSize == 0) {
+ connection = (fullSize == 0) ? ConnectionType.ADJACENT : ConnectionType.SINGLE;
} else {
connection = ConnectionType.VARIATE;
}
@@ -53,6 +71,7 @@ public void init() {
onConnectorCatch(connector);
}
}
+
}
/**
@@ -83,7 +102,6 @@ public ConnectionType getConnection() {
public Long2ObjectMap getCross() {
return cross;
}
-
/**
* @return Gets the full path of connectors.
*/
diff --git a/src/main/java/tesseract/api/Controller.java b/src/main/java/tesseract/api/Controller.java
index 1311f1c0..3cb4046f 100644
--- a/src/main/java/tesseract/api/Controller.java
+++ b/src/main/java/tesseract/api/Controller.java
@@ -1,24 +1,29 @@
package tesseract.api;
+import net.minecraft.world.World;
+import tesseract.graph.Graph;
import tesseract.graph.Group;
import tesseract.graph.INode;
+
/**
* Class acts as a controller in the group of some components.
*/
-abstract public class Controller implements ITickingController {
+abstract public class Controller implements ITickingController {
protected int tick;
- protected final int dim;
- protected Group group;
+ protected final World dim;
+ protected Group group;
+ protected final Graph.INodeGetter getter;
/**
* Creates instance of the controller.
*
- * @param dim The dimension id.
+ * @param supplier The world.
*/
- protected Controller(int dim) {
- this.dim = dim;
+ protected Controller(World supplier, Graph.INodeGetter getter) {
+ this.dim = supplier;
+ this.getter = getter;
}
/**
@@ -26,9 +31,8 @@ protected Controller(int dim) {
*
* @param container The group this controller handles.
*/
- @SuppressWarnings("unchecked")
- public Controller set(INode container) {
- this.group = (Group) container;
+ public Controller set(INode container) {
+ this.group = (Group) container;
return this;
}
@@ -42,9 +46,13 @@ public void tick() {
onFrame();
}
}
-
/**
* Frame handler, which executes each second.
*/
protected abstract void onFrame();
-}
+
+ @Override
+ public World getWorld() {
+ return this.dim;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/tesseract/api/GraphWrapper.java b/src/main/java/tesseract/api/GraphWrapper.java
index 6797edde..e43ee343 100644
--- a/src/main/java/tesseract/api/GraphWrapper.java
+++ b/src/main/java/tesseract/api/GraphWrapper.java
@@ -1,55 +1,93 @@
package tesseract.api;
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
-import tesseract.graph.*;
+import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
+import it.unimi.dsi.fastutil.longs.LongSet;
+import it.unimi.dsi.fastutil.objects.*;
+import net.minecraft.util.Direction;
+import net.minecraft.world.IWorld;
+import net.minecraft.world.World;
+import net.minecraftforge.common.util.LazyOptional;
+import tesseract.Tesseract;
+import tesseract.graph.Cache;
+import tesseract.graph.Graph;
+import tesseract.graph.Graph.INodeGetter;
+import tesseract.graph.Group;
+import tesseract.graph.NodeCache;
+import tesseract.util.Pos;
-import java.util.function.IntFunction;
+import javax.annotation.Nonnull;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
-public class GraphWrapper {
+public class GraphWrapper {
- protected final Int2ObjectMap> graph = new Int2ObjectOpenHashMap<>();
- protected final IntFunction> supplier;
+ private static final ObjectSet> ALL_WRAPPERS = new ObjectOpenHashSet<>();
+
+ protected final Object2ObjectMap> graph = new Object2ObjectOpenHashMap<>();
+ protected final BiFunction, Controller> supplier;
+ protected final ICapabilityGetter getter;
+ private final Map PENDING_NODES = new Object2ObjectOpenHashMap<>();
/**
* Creates a graph wrapper.
*
* @param supplier The default controller supplier.
*/
- public GraphWrapper(IntFunction> supplier) {
+ public GraphWrapper(BiFunction, Controller> supplier, ICapabilityGetter getter) {
this.supplier = supplier;
+ this.getter = getter;
+ ALL_WRAPPERS.add(this);
}
/**
* Creates an instance of a class for a given node.
*
- * @param dim The dimension id where the node will be added.
- * @param pos The position at which the node will be added.
- * @param node The node object.
+ * @param dim The dimension id where the node will be added.
+ * @param pos The position at which the node will be added.
*/
- public void registerNode(int dim, long pos, N node) {
- getGraph(dim).addNode(pos, new Cache<>(node), supplier.apply(dim));
- }
+ /*public void registerNode(IWorld dim, long pos, Direction side, BiFunction node) {
+ if (dim.isClientSide())
+ return;
+ getGraph(dim).addNode(pos, node, side, () -> supplier.apply(dim instanceof World ? ((World) dim) : null),
+ Tesseract.hadFirstTick(dim));
+ }*/
/**
- * Creates an instance of a class for a given connector.
+ * Registers a connector into Tesseract.
*
- * @param dim The dimension id where the node will be added.
- * @param pos The position at which the node will be added.
+ * @param dim The dimension id where the node will be added.
+ * @param pos The position at which the node will be added.
* @param connector The connector object.
*/
- public void registerConnector(int dim, long pos, C connector) {
- getGraph(dim).addConnector(pos, new Cache<>(connector), supplier.apply(dim));
+ public void registerConnector(World dim, long pos, C connector, boolean regular) {
+ if (dim.isClientSide())
+ return;
+ getGraph(dim).addConnector(pos, new Cache<>(connector));
+ if (!Tesseract.hadFirstTick(dim)) {
+ PENDING_NODES.computeIfAbsent(dim, d -> new LongOpenHashSet()).add(pos);
+ } else {
+ addNodes(dim, pos);
+ }
+ }
+
+ public void blockUpdate(World dim, long connector, long node) {
+ if (dim.isClientSide()) return;
+ update(dim, node, Pos.subToDir(connector, node), false);
}
/**
- * Gets the graph for the type and dimension and will be instantiated if it does not already exist.
+ * Gets the graph for the type and dimension and will be instantiated if it does
+ * not already exist.
*
* @param dim The dimension id.
* @return The graph instance for the world.
*/
- public Graph getGraph(int dim) {
- return graph.computeIfAbsent(dim, k -> new Graph<>());
+ public Graph getGraph(IWorld dim) {
+ assert !dim.isClientSide();
+ INodeGetter get = (a,b,c) -> getter.get((World)dim,a,b,c);
+ return graph.computeIfAbsent(dim, k -> new Graph<>(() -> supplier.apply((World) dim, get)));
}
/**
@@ -59,18 +97,166 @@ public Graph getGraph(int dim) {
* @param pos The position at which the electric component is exist.
* @return The controller object. (Can be null)
*/
- public ITickingController getController(int dim, long pos) {
- Group, ?> group = getGraph(dim).getGroupAt(pos);
- return group != null ? group.getController() : null;
+ @Nonnull
+ public ITickingController getController(World dim, long pos) {
+ if (dim.isClientSide()) {
+ throw new IllegalStateException("Call to GraphWrapper::getController on client side!");
+ }
+ Group group = getGraph(dim).getGroupAt(pos);
+ INodeGetter get = (a, b, c) -> getter.get((World) dim, a, b, c);
+
+ return group != null ? group.getController() : supplier.apply(dim, get);
+ }
+
+ /**
+ * Primary update method in Tesseract, receiving capability invalidations and block updates.
+ *
+ * @param pos the node position.
+ */
+ private void update(World dim, long pos, @Nonnull Direction side, boolean isInvalidate) {
+ //offset to the connector.
+ long cPos = Pos.offset(pos, side);
+ Graph graph = getGraph(dim);
+ Group group = graph.getGroupAt(cPos);
+ if (group == null) return;
+ //only update nodes
+ Cache cCache = group.getConnector(cPos);
+ if (cCache == null) {
+ NodeCache nodeCache = group.getNodes().get(cPos);
+ if (nodeCache == null) return;
+ }
+ NodeCache cache = group.getNodes().get(pos);
+ INodeGetter get = (a, b, c) -> getter.get(dim, a, b, c);
+ if (cache == null) {
+ cache = new NodeCache<>(pos, get, (a, b) -> this.validate(graph, a, b), (a, b) -> this.update(dim, b, a, true));
+ graph.addNode(pos, cache);
+ } else {
+ if (isInvalidate) {
+ if (cache.updateSide(side)) {
+ group.getController().change();
+ return;
+ }
+ }
+ updateNode(graph, pos);
+ }
+ }
+
+ /**
+ * Adds a node to the graph at the specified position.
+ *
+ * @param pos The position at which the node will be added.
+ */
+ public void addNodes(World dim, long pos) {
+ Graph graph = getGraph(dim);
+ INodeGetter get = (a, b, c) -> getter.get(dim, a, b, c);
+ for (Direction dir : Graph.DIRECTIONS) {
+ final long nodePos = Pos.offset(pos, dir);
+ NodeCache cache = new NodeCache<>(nodePos, get, (a, b) -> this.validate(graph, a, b), (a, b) -> this.update(dim, b, a, true));
+ graph.addNode(nodePos, cache);
+ }
+ }
+
+
+ public void onFirstTick(World dim) {
+ LongSet set = PENDING_NODES.remove(dim);
+ if (set != null) set.forEach((Consumer super Long>) l -> this.addNodes(dim, l));
+ }
+
+
+ private void updateNode(Graph graph, long nodePos) {
+ Group group = graph.getGroupAt(nodePos);
+ if (group == null) {
+ return;
+ }
+ NodeCache cache = group.getNodes().get(nodePos);
+ if (cache == null) return;
+ int count = cache.count();
+ boolean ok = updateNodeSides(cache);
+ if ((cache.count() != count) || cache.count() == 0) {
+ graph.removeAt(nodePos);
+ if (ok) {
+ graph.addNode(nodePos, cache);
+ }
+ } else {
+ group.getController().change();
+ }
}
+ /**
+ * Removes an entry from the Group, potentially splitting it if needed. By
+ * calling this function, the caller asserts that this group contains the
+ * specified position; the function may misbehave if the group does not actually
+ * contain the specified position.
+ *
+ * @param pos The position of the entry to remove.
+ */
+ private boolean removeAt(Graph graph, long pos) {
+ Group gr = graph.getGroupAt(pos);
+ if (gr == null) return false;
+ boolean ok = graph.removeAt(pos);
+ if (ok) {
+ for (Direction dir : Graph.DIRECTIONS) {
+ updateNode(graph, Pos.offset(pos, dir));
+ }
+ }
+ return ok;
+ }
+
+ private boolean updateNodeSides(NodeCache node) {
+ for (int i = 0; i < Graph.DIRECTIONS.length; i++) {
+ node.updateSide(Graph.DIRECTIONS[i]);
+ }
+ return node.count() > 0;
+ }
+
+
+ boolean validate(Graph graph, Direction side, long pos) {
+ Group group = graph.getGroupAt(Pos.offset(pos, side));
+ if (group == null) return false;
+ Cache conn = group.getConnector(Pos.offset(pos, side));
+ if (conn != null) {
+ return conn.value().validate(side.getOpposite());
+ }
+ //NodeCache cache = group.getNodes().get(Pos.offset(pos, side));
+ return false;
+ }
+
+
/**
* Removes an instance of a class at the given position.
*
* @param dim The dimension id where the electric component will be added.
* @param pos The position at which the electric component will be added.
*/
- public void remove(int dim, long pos) {
- getGraph(dim).removeAt(pos);
+ public boolean remove(World dim, long pos) {
+ if (dim.isClientSide())
+ return false;
+ return removeAt(getGraph(dim), pos);
+ }
+
+ public void tick(World dim) {
+ Graph g = graph.get(dim);
+ if (g != null)
+ g.getGroups().forEach((pos, gr) -> gr.getController().tick());
+ }
+
+ public static Set> getWrappers() {
+ return ObjectSets.unmodifiable(ALL_WRAPPERS);
+ }
+
+ public void removeWorld(World world) {
+ this.graph.remove(world);
+ }
+
+ public void clear() {
+ this.graph.clear();
+ }
+
+ public void healthCheck() {
+ this.graph.values().forEach(v -> v.getGroups().values().forEach(Group::healthCheck));
+ }
+
+ public interface ICapabilityGetter {
+ T get(World level, long pos, Direction capSide, Runnable capCallback);
}
}
diff --git a/src/main/java/tesseract/api/IConnectable.java b/src/main/java/tesseract/api/IConnectable.java
index e1604a77..b263abea 100644
--- a/src/main/java/tesseract/api/IConnectable.java
+++ b/src/main/java/tesseract/api/IConnectable.java
@@ -1,6 +1,7 @@
package tesseract.api;
-import tesseract.util.Dir;
+import net.minecraft.util.Direction;
+import tesseract.util.Pos;
/**
* A simple interface for representing connectable objects.
@@ -11,5 +12,15 @@ public interface IConnectable {
* @param direction The direction vector.
* @return True if connect to the direction, false otherwise.
*/
- boolean connects(Dir direction);
+ boolean connects(Direction direction);
+
+ boolean validate(Direction dir);
+
+ default long traverse(long pos, Direction dir) {
+ return Pos.offset(pos, dir);
+ }
+
+ default boolean path() {
+ return false;
+ }
}
diff --git a/src/main/java/tesseract/api/ITickHost.java b/src/main/java/tesseract/api/ITickHost.java
deleted file mode 100644
index f1d2addf..00000000
--- a/src/main/java/tesseract/api/ITickHost.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package tesseract.api;
-
-/**
- * Represents a tile entity providing server ticks for the group controller
- */
-public interface ITickHost {
-
- /**
- * Set new controller pointer (or null).
- * If the host already contains new non-null controller, then don't reset it to null.
- * @param oldController The previous controller node.
- * @param newController The new controller node.
- */
- void reset(ITickingController oldController, ITickingController newController);
-}
diff --git a/src/main/java/tesseract/api/ITickingController.java b/src/main/java/tesseract/api/ITickingController.java
index cbf334c9..00bb0756 100644
--- a/src/main/java/tesseract/api/ITickingController.java
+++ b/src/main/java/tesseract/api/ITickingController.java
@@ -1,11 +1,20 @@
package tesseract.api;
+import net.minecraft.util.Direction;
+import net.minecraft.world.World;
+import tesseract.api.capability.ITransactionModifier;
+import tesseract.graph.Graph;
import tesseract.graph.INode;
+import javax.annotation.Nonnull;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+
/**
* Interface abstracting ticking behaviour for the groups in the graph.
*/
-public interface ITickingController {
+public interface ITickingController {
/**
* Server tick handler.
@@ -19,13 +28,29 @@ public interface ITickingController {
/**
* Creates new controller for split group.
+ *
* @param group New group.
* @return New controller for the group.
*/
- ITickingController clone(INode group);
+ ITickingController clone(INode group);
/**
* @return To get simple things like a some information.
*/
- String[] getInfo();
+ void getInfo(long pos, @Nonnull List list);
+
+ /**
+ * Core method of Tesseract. Inserts an object into this pipe.
+ * @param producerPos the position of the producer
+ * @param side the side at which the object was inserted into the pipe.
+ * @param transaction the transaction object.
+ */
+ void insert(long producerPos, Direction side, T transaction, ITransactionModifier modifier);
+
+ /**
+ * Returns the active world for this ticking controller.
+ *
+ * @return the world object.
+ */
+ World getWorld();
}
diff --git a/src/main/java/tesseract/api/Transaction.java b/src/main/java/tesseract/api/Transaction.java
new file mode 100644
index 00000000..9baa3e34
--- /dev/null
+++ b/src/main/java/tesseract/api/Transaction.java
@@ -0,0 +1,89 @@
+package tesseract.api;
+
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Consumer;
+
+public abstract class Transaction {
+ private final ObjectArrayList> onCommit;
+ private final ObjectArrayList transmitted;
+ private final Consumer consumer;
+ private boolean cancelled;
+
+ public Transaction(final Consumer consumed) {
+ this.transmitted = new ObjectArrayList<>(1);
+ this.onCommit = new ObjectArrayList<>(1);
+ this.consumer = consumed;
+ this.cancelled = false;
+ }
+
+ protected T addData(T t) {
+ if (cancelled) return t;
+ this.transmitted.add(t);
+ return t;
+ }
+
+ public T getLast() {
+ if (transmitted.size() == 0) throw new IllegalStateException("call to Transaction::getLast without data");
+ return transmitted.get(transmitted.size()-1);
+ }
+
+ public Iterable getOffset(int j) {
+ return () ->{
+ Iterator t = this.transmitted.iterator();
+ for (int i = 0; i < j; i++) {
+ t.next();
+ }
+ return t;
+ };
+ }
+
+ public List getData() {
+ return cancelled ? Collections.emptyList() : transmitted;
+ }
+
+ public void onCommit(Consumer consumer) {
+ if (cancelled) return;
+ this.onCommit.ensureCapacity(transmitted.size());
+ this.onCommit.add(transmitted.size() - 1, consumer);
+ }
+
+ public void pushCallback(Consumer consumer) {
+ if (cancelled || this.onCommit.size() == 0) return;
+ Consumer current = this.onCommit.get(this.onCommit.size()-1);
+ if (current != null) {
+ this.onCommit.add(this.onCommit.size()-1, current.andThen(consumer));
+ }
+ }
+
+ public void pushCallback(Consumer consumer, int j) {
+ if (cancelled || this.onCommit.size() == 0) return;
+ Consumer current = this.onCommit.get(j);
+ if (current != null) {
+ this.onCommit.add(j, current.andThen(consumer));
+ }
+ }
+
+
+ public void cancel() {
+ this.cancelled = true;
+ }
+
+ public void commit() {
+ if (cancelled) return;
+ for (int i = 0; i < transmitted.size(); i++) {
+ if (onCommit.get(i) != null) {
+ onCommit.get(i).accept(transmitted.get(i));
+ }
+ this.consumer.accept(transmitted.get(i));
+ }
+ }
+
+ public abstract boolean isValid();
+
+ public abstract boolean canContinue();
+
+}
diff --git a/src/main/java/tesseract/api/capability/ITransactionModifier.java b/src/main/java/tesseract/api/capability/ITransactionModifier.java
new file mode 100644
index 00000000..6a2c2dd2
--- /dev/null
+++ b/src/main/java/tesseract/api/capability/ITransactionModifier.java
@@ -0,0 +1,11 @@
+package tesseract.api.capability;
+
+
+import net.minecraft.util.Direction;
+
+@FunctionalInterface
+public interface ITransactionModifier {
+ void modify(Object stack, Direction in, Direction out, boolean simulate);
+
+ ITransactionModifier EMPTY = (a,b,c,d) -> {};
+}
diff --git a/src/main/java/tesseract/api/capability/TesseractBaseCapability.java b/src/main/java/tesseract/api/capability/TesseractBaseCapability.java
new file mode 100644
index 00000000..abd43e5c
--- /dev/null
+++ b/src/main/java/tesseract/api/capability/TesseractBaseCapability.java
@@ -0,0 +1,24 @@
+package tesseract.api.capability;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.Direction;
+import tesseract.api.IConnectable;
+
+public abstract class TesseractBaseCapability {
+ public final T tile;
+ public final Direction side;
+ public final boolean isNode;
+ public final ITransactionModifier callback;
+ protected boolean isSending;
+
+ public TesseractBaseCapability(T tile, Direction side, boolean isNode, ITransactionModifier callback) {
+ this.tile = tile;
+ this.side = side;
+ this.isNode = isNode;
+ this.callback = callback;
+ this.isSending = false;
+ }
+}
diff --git a/src/main/java/tesseract/api/capability/TesseractFluidCapability.java b/src/main/java/tesseract/api/capability/TesseractFluidCapability.java
new file mode 100644
index 00000000..16f0040e
--- /dev/null
+++ b/src/main/java/tesseract/api/capability/TesseractFluidCapability.java
@@ -0,0 +1,117 @@
+package tesseract.api.capability;
+
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.Direction;
+import net.minecraft.util.math.BlockPos;
+import net.minecraftforge.common.util.LazyOptional;
+import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
+import net.minecraftforge.fluids.capability.IFluidHandler;
+import tesseract.Tesseract;
+import tesseract.api.fluid.*;
+import tesseract.graph.Graph;
+import tesseract.graph.Path;
+import tesseract.util.Pos;
+
+import javax.annotation.Nonnull;
+
+
+public class TesseractFluidCapability extends TesseractBaseCapability implements IFluidNode {
+
+ private FluidTransaction old;
+
+ public TesseractFluidCapability(T tile, Direction dir, boolean isNode, ITransactionModifier callback) {
+ super(tile, dir, isNode, callback);
+ }
+
+ @Override
+ public int getTanks() {
+ return 1;
+ }
+
+ @Nonnull
+ @Override
+ public FluidStack getFluidInTank(int tank) {
+ return FluidStack.EMPTY;
+ }
+
+ @Override
+ public int getTankCapacity(int tank) {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
+ return true;
+ }
+
+ @Override
+ public int fill(FluidStack resource, FluidAction action) {
+ if (this.isSending) return 0;
+ this.isSending = true;
+ if (action.execute()) {
+ if (old == null) {
+ this.isSending = false;
+ return 0;
+ }
+ old.commit();
+ } else {
+ long pos = tile.getBlockPos().asLong();
+ FluidTransaction transaction = new FluidTransaction(resource.copy(), a -> {
+ });
+ if (!this.isNode) {
+ Tesseract.FLUID.getController(tile.getLevel(), pos).insert(pos, side, transaction, callback);
+ } else {
+ for (Direction dir : Graph.DIRECTIONS) {
+ if (dir == side || !this.tile.connects(dir)) continue;
+ Tesseract.FLUID.getController(tile.getLevel(), pos).insert(Pos.offset(pos, dir), dir.getOpposite(), transaction, callback);
+ }
+ }
+ this.old = transaction;
+ }
+ this.isSending = false;
+ return resource.getAmount() - this.old.stack.getAmount();
+ }
+
+ @Nonnull
+ @Override
+ public FluidStack drain(FluidStack resource, FluidAction action) {
+ return FluidStack.EMPTY;
+ }
+
+ @Nonnull
+ @Override
+ public FluidStack drain(int maxDrain, FluidAction action) {
+ return FluidStack.EMPTY;
+ }
+
+ @Override
+ public int getPriority(Direction direction) {
+ return 0;
+ }
+
+ @Override
+ public boolean canOutput() {
+ return true;
+ }
+
+ @Override
+ public boolean canInput() {
+ return true;
+ }
+
+ @Override
+ public boolean canInput(Direction direction) {
+ return true;
+ }
+
+ @Override
+ public boolean canOutput(Direction direction) {
+ return true;
+ }
+
+ @Override
+ public boolean canInput(FluidStack fluid, Direction direction) {
+ return true;
+ }
+}
diff --git a/src/main/java/tesseract/api/capability/TesseractGTCapability.java b/src/main/java/tesseract/api/capability/TesseractGTCapability.java
new file mode 100644
index 00000000..e9ddc133
--- /dev/null
+++ b/src/main/java/tesseract/api/capability/TesseractGTCapability.java
@@ -0,0 +1,248 @@
+package tesseract.api.capability;
+
+import javax.annotation.Nullable;
+
+import net.minecraft.nbt.CompoundNBT;
+import net.minecraft.nbt.INBT;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.Direction;
+import net.minecraft.util.math.BlockPos;
+import net.minecraftforge.common.capabilities.Capability;
+import net.minecraftforge.common.capabilities.CapabilityInject;
+import net.minecraftforge.common.capabilities.CapabilityManager;
+import net.minecraftforge.common.util.LazyOptional;
+import tesseract.Tesseract;
+import tesseract.api.gt.*;
+import tesseract.graph.Graph;
+import tesseract.graph.Path;
+import tesseract.util.Pos;
+
+public class TesseractGTCapability extends TesseractBaseCapability implements IEnergyHandler {
+ @CapabilityInject(IEnergyHandler.class)
+ public static final Capability ENERGY_HANDLER_CAPABILITY;
+
+ static {
+ ENERGY_HANDLER_CAPABILITY = null;
+ }
+
+ public static void register() {
+ CapabilityManager.INSTANCE.register(IEnergyHandler.class, new Capability.IStorage() {
+ @Nullable
+ @Override
+ public INBT writeNBT(Capability capability, IEnergyHandler instance, Direction side) {
+ return null;
+ }
+
+ @Override
+ public void readNBT(Capability capability, IEnergyHandler instance, Direction side, INBT nbt) {
+
+ }
+ }, () -> new IEnergyHandler() {
+ @Override
+ public GTConsumer.State getState() {
+ return null;
+ }
+
+ @Override
+ public CompoundNBT serializeNBT() {
+ return new CompoundNBT();
+ }
+
+ @Override
+ public void deserializeNBT(CompoundNBT nbt) {
+
+ }
+
+ @Override
+ public boolean insert(GTTransaction transaction) {
+ return false;
+ }
+
+ @Override
+ public boolean extractEnergy(GTTransaction.TransferData data) {
+ return false;
+ }
+
+ @Override
+ public boolean addEnergy(GTTransaction.TransferData data) {
+ return false;
+ }
+
+ @Override
+ public GTTransaction extract(GTTransaction.Mode mode) {
+ return new GTTransaction(0, 0, a -> {
+ });
+ }
+
+ @Override
+ public long getEnergy() {
+ return 0;
+ }
+
+ @Override
+ public long getCapacity() {
+ return 0;
+ }
+
+ @Override
+ public long getOutputAmperage() {
+ return 0;
+ }
+
+ @Override
+ public long getOutputVoltage() {
+ return 0;
+ }
+
+ @Override
+ public long getInputAmperage() {
+ return 0;
+ }
+
+ @Override
+ public long getInputVoltage() {
+ return 0;
+ }
+
+ @Override
+ public boolean canOutput() {
+ return false;
+ }
+
+ @Override
+ public boolean canInput() {
+ return false;
+ }
+
+ @Override
+ public boolean canInput(Direction direction) {
+ return false;
+ }
+
+ @Override
+ public boolean canOutput(Direction direction) {
+ return false;
+ }
+ });
+ }
+
+ private final IGTCable cable;
+
+ public TesseractGTCapability(T tile, Direction dir, boolean isNode, ITransactionModifier modifier) {
+ super(tile, dir, isNode, modifier);
+ this.cable = tile;
+ }
+
+ @Override
+ public boolean insert(GTTransaction transaction) {
+ boolean flag = false;
+ if (this.isSending) return false;
+ this.isSending = true;
+ long pos = tile.getBlockPos().asLong();
+ if (!this.isNode) {
+ long old = transaction.getAvailableAmps();
+ Tesseract.GT_ENERGY.getController(tile.getLevel(), pos).insert(pos, side, transaction, callback);
+ flag = transaction.getAvailableAmps() < old;
+ } else {
+ for (Direction dir : Graph.DIRECTIONS) {
+ if (dir == side || !this.tile.connects(dir)) continue;
+ Tesseract.GT_ENERGY.getController(tile.getLevel(), pos).insert(Pos.offset(pos, dir), dir.getOpposite(), transaction, callback);
+ }
+ }
+ this.isSending = false;
+ return flag;
+ }
+
+ @Override
+ public boolean extractEnergy(GTTransaction.TransferData data) {
+ return false;
+ }
+
+ @Override
+ public boolean addEnergy(GTTransaction.TransferData data) {
+ return false;
+ }
+
+ @Override
+ public GTTransaction extract(GTTransaction.Mode mode) {
+ return new GTTransaction(0, 0, a -> {
+ });
+ }
+
+ @Override
+ public long getEnergy() {
+ return 0;
+ }
+
+ @Override
+ public long getCapacity() {
+ return 0;
+ }
+
+
+
+ @Override
+ public long availableAmpsInput() {
+ return Long.MAX_VALUE;
+ }
+
+ @Override
+ public long availableAmpsOutput() {
+ return Long.MAX_VALUE;
+ }
+
+ @Override
+ public long getOutputAmperage() {
+ return Long.MAX_VALUE;
+ }
+
+ @Override
+ public long getOutputVoltage() {
+ return cable.getVoltage();
+ }
+
+ @Override
+ public long getInputAmperage() {
+ return Long.MAX_VALUE;
+ }
+
+ @Override
+ public long getInputVoltage() {
+ return cable.getVoltage();
+ }
+
+ @Override
+ public boolean canOutput() {
+ return true;
+ }
+
+ @Override
+ public boolean canInput() {
+ return true;
+ }
+
+ @Override
+ public boolean canInput(Direction direction) {
+ return true;
+ }
+
+ @Override
+ public boolean canOutput(Direction direction) {
+ return true;
+ }
+
+ @Override
+ public GTConsumer.State getState() {
+ return new GTConsumer.State(this);
+ }
+
+ @Override
+ public CompoundNBT serializeNBT() {
+ return null;
+ }
+
+ @Override
+ public void deserializeNBT(CompoundNBT nbt) {
+
+ }
+}
diff --git a/src/main/java/tesseract/api/capability/TesseractItemCapability.java b/src/main/java/tesseract/api/capability/TesseractItemCapability.java
new file mode 100644
index 00000000..d99bbc5e
--- /dev/null
+++ b/src/main/java/tesseract/api/capability/TesseractItemCapability.java
@@ -0,0 +1,108 @@
+package tesseract.api.capability;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.Direction;
+import net.minecraft.util.math.BlockPos;
+import net.minecraftforge.common.util.LazyOptional;
+import net.minecraftforge.items.CapabilityItemHandler;
+import net.minecraftforge.items.IItemHandler;
+import tesseract.Tesseract;
+import tesseract.api.item.IItemNode;
+import tesseract.api.item.IItemPipe;
+import tesseract.api.item.ItemTransaction;
+import tesseract.graph.Graph;
+import tesseract.util.Pos;
+
+
+public class TesseractItemCapability extends TesseractBaseCapability implements IItemNode {
+
+ private ItemTransaction old;
+
+ public TesseractItemCapability(T tile, Direction dir, boolean isNode, ITransactionModifier onTransaction) {
+ super(tile, dir, isNode, onTransaction);
+ }
+
+ @Override
+ public int getSlots() {
+ return 1;
+ }
+
+ @Nonnull
+ @Override
+ public ItemStack getStackInSlot(int slot) {
+ return ItemStack.EMPTY;
+ }
+
+ @Nonnull
+ @Override
+ public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) {
+ if (!simulate) {
+ old.commit();
+ } else {
+ if (this.isSending) return stack;
+ this.isSending = true;
+ ItemTransaction transaction = new ItemTransaction(stack, a -> {});
+ long pos = tile.getBlockPos().asLong();
+ if (!isNode) {
+ Tesseract.ITEM.getController(tile.getLevel(), pos).insert(pos, this.side, transaction, callback);
+ } else {
+ for (Direction dir : Graph.DIRECTIONS) {
+ if (dir == this.side || !this.tile.connects(dir)) continue;
+ Tesseract.ITEM.getController(tile.getLevel(), pos).insert(Pos.offset(pos, dir), dir.getOpposite(), transaction, callback);
+ }
+ }
+ this.old = transaction;
+ }
+ this.isSending = false;
+ return old.stack.copy();
+ }
+
+ @Nonnull
+ @Override
+ public ItemStack extractItem(int slot, int amount, boolean simulate) {
+ return ItemStack.EMPTY;
+ }
+
+ @Override
+ public int getSlotLimit(int slot) {
+ return 1;
+ }
+
+ @Override
+ public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
+ return true;
+ }
+
+ @Override
+ public int getPriority(Direction direction) {
+ return 0;
+ }
+
+ @Override
+ public boolean isEmpty(int slot) {
+ return false;
+ }
+
+ @Override
+ public boolean canOutput() {
+ return true;
+ }
+
+ @Override
+ public boolean canInput() {
+ return true;
+ }
+
+ @Override
+ public boolean canInput(Direction direction) {
+ return true;
+ }
+
+ @Override
+ public boolean canOutput(Direction direction) {
+ return true;
+ }
+}
diff --git a/src/main/java/tesseract/api/fe/FEConsumer.java b/src/main/java/tesseract/api/fe/FEConsumer.java
index 293f496f..964f457e 100644
--- a/src/main/java/tesseract/api/fe/FEConsumer.java
+++ b/src/main/java/tesseract/api/fe/FEConsumer.java
@@ -22,10 +22,10 @@ public class FEConsumer extends Consumer {
* Creates instance of the consumer.
*
* @param consumer The consumer node.
- * @param path The path information.
+ * @param path The path information.
*/
protected FEConsumer(IFENode consumer, Path path) {
- super(consumer, path);
+ super(consumer, null, path);
init();
}
@@ -33,7 +33,7 @@ protected FEConsumer(IFENode consumer, Path path) {
* Adds energy to the node. Returns quantity of energy that was accepted.
*
* @param maxReceive Amount of energy to be inserted.
- * @param simulate If true, the insertion will only be simulated.
+ * @param simulate If true, the insertion will only be simulated.
* @return Amount of energy that was (or would have been, if simulated) accepted by the storage.
*/
public long insert(long maxReceive, boolean simulate) {
diff --git a/src/main/java/tesseract/api/fe/FEController.java b/src/main/java/tesseract/api/fe/FEController.java
index ad59c81b..9c020ecc 100644
--- a/src/main/java/tesseract/api/fe/FEController.java
+++ b/src/main/java/tesseract/api/fe/FEController.java
@@ -6,22 +6,22 @@
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import net.minecraft.util.Direction;
+import net.minecraft.world.World;
import tesseract.api.Controller;
import tesseract.api.ITickingController;
-import tesseract.graph.Cache;
-import tesseract.graph.Grid;
-import tesseract.graph.INode;
-import tesseract.graph.Path;
-import tesseract.util.Dir;
+import tesseract.api.capability.ITransactionModifier;
+import tesseract.graph.*;
import tesseract.util.Node;
import tesseract.util.Pos;
+import javax.annotation.Nonnull;
import java.util.List;
/**
* Class acts as a controller in the group of a energy components.
*/
-public class FEController extends Controller {
+public class FEController extends Controller {
private long totalEnergy, lastEnergy;
private final Long2LongMap holders = new Long2LongOpenHashMap();
@@ -29,11 +29,11 @@ public class FEController extends Controller {
/**
* Creates instance of the controller.
-
- * @param dim The dimension id.
+ *
+ * @param world The world.
*/
- public FEController(int dim) {
- super(dim);
+ public FEController(World world) {
+ super(world, null);
holders.defaultReturnValue(-1L);
}
@@ -45,19 +45,20 @@ public FEController(int dim) {
* Finally, it will pre-build consumer objects which are available for the producers. So each producer has a list of possible
* consumers with unique information about paths, loss, ect.
*
+ *
* @see tesseract.graph.Grid (Cache)
*/
@Override
public void change() {
data.clear();
- for (Long2ObjectMap.Entry> e : group.getNodes().long2ObjectEntrySet()) {
+ for (Long2ObjectMap.Entry> e : group.getNodes().long2ObjectEntrySet()) {
long pos = e.getLongKey();
- IFENode producer = e.getValue().value();
+ IFENode producer = null;//e.getValue().value();
if (producer.canOutput()) {
Pos position = new Pos(pos);
- for (Dir direction : Dir.VALUES) {
+ for (Direction direction : Graph.DIRECTIONS) {
if (producer.canOutput(direction)) {
List consumers = new ObjectArrayList<>();
long side = position.offset(direction).asLong();
@@ -97,7 +98,7 @@ public void change() {
/**
* Merge the existing consumers with new ones.
*
- * @param producer The producer node.
+ * @param producer The producer node.
* @param consumers The consumer nodes.
*/
private void onMerge(IFENode producer, List consumers) {
@@ -117,11 +118,11 @@ private void onMerge(IFENode producer, List consumers) {
* Adds available consumers to the list.
*
* @param consumers The consumer nodes.
- * @param path The paths to consumers.
- * @param pos The position of the producer.
+ * @param path The paths to consumers.
+ * @param pos The position of the producer.
*/
private void onCheck(List consumers, Path path, long pos) {
- IFENode node = group.getNodes().get(pos).value();
+ IFENode node = null;//group.getNodes().get(pos).value();
if (node.canInput()) consumers.add(new FEConsumer(node, path));
}
@@ -213,6 +214,11 @@ public void tick() {
}
}
+ // @Override
+ // public int insert(long producerPos, long direction, Integer stack, boolean simulate) {
+ // return 0;
+ // }
+
@Override
protected void onFrame() {
lastEnergy = totalEnergy;
@@ -220,14 +226,24 @@ protected void onFrame() {
}
@Override
- public String[] getInfo() {
- return new String[]{
- "Total Energy: ".concat(Long.toString(lastEnergy))
- };
+ public void getInfo(long pos, @Nonnull List list) {
+ this.group.getGroupInfo(pos, list);
+ list.add(String.format("FE Data size: %d", this.data.size()));
}
+ /*@Override
+ public void insert(long producerPos, long pipePos, Integer transaction) {
+
+ }*/
+
@Override
public ITickingController clone(INode group) {
return new FEController(dim).set(group);
}
+
+ @Override
+ public void insert(long producerPos, Direction side, Integer transaction, ITransactionModifier modifier) {
+ // TODO Auto-generated method stub
+
+ }
}
\ No newline at end of file
diff --git a/src/main/java/tesseract/api/fe/IFECable.java b/src/main/java/tesseract/api/fe/IFECable.java
index 6d8f1f61..0f6ab714 100644
--- a/src/main/java/tesseract/api/fe/IFECable.java
+++ b/src/main/java/tesseract/api/fe/IFECable.java
@@ -9,6 +9,7 @@ public interface IFECable extends IConnectable {
/**
* Returns the maximum amount of energy that this item component will permit to pass through or be received in a single tick.
+ *
* @return A positive integer representing the maximum packets, zero or negative indicates that this component accepts no energy.
*/
long getCapacity();
diff --git a/src/main/java/tesseract/api/fe/IFENode.java b/src/main/java/tesseract/api/fe/IFENode.java
index 05edfbd0..50f4b2af 100644
--- a/src/main/java/tesseract/api/fe/IFENode.java
+++ b/src/main/java/tesseract/api/fe/IFENode.java
@@ -1,7 +1,7 @@
package tesseract.api.fe;
+import net.minecraft.util.Direction;
import tesseract.api.IConnectable;
-import tesseract.util.Dir;
/**
* A flux node is the unit of interaction with flux inventories.
@@ -14,16 +14,18 @@ public interface IFENode extends IConnectable {
/**
* Adds energy to the node. Returns quantity of energy that was accepted.
+ *
* @param maxReceive Maximum amount of energy to be inserted.
- * @param simulate If true, the insertion will only be simulated.
+ * @param simulate If true, the insertion will only be simulated.
* @return Amount of energy that was (or would have been, if simulated) accepted by the storage.
*/
long insert(long maxReceive, boolean simulate);
/**
* Removes energy from the node. Returns quantity of energy that was removed.
+ *
* @param maxExtract Maximum amount of energy to be extracted.
- * @param simulate If true, the extraction will only be simulated.
+ * @param simulate If true, the extraction will only be simulated.
* @return Amount of energy that was (or would have been, if simulated) extracted from the storage.
*/
long extract(long maxExtract, boolean simulate);
@@ -45,20 +47,23 @@ public interface IFENode extends IConnectable {
/**
* Gets if this storage can have energy extracted.
+ *
* @return If this is false, then any calls to extractEnergy will return 0.
*/
boolean canOutput();
/**
* Used to determine if this storage can receive energy.
+ *
* @return If this is false, then any calls to receiveEnergy will return 0.
*/
boolean canInput();
/**
* Used to determine which sides can output energy (if any).
+ *
* @param direction Direction to the output.
* @return Returns true if the given direction is output side.
*/
- boolean canOutput(Dir direction);
+ boolean canOutput(Direction direction);
}
diff --git a/src/main/java/tesseract/api/fluid/FluidConsumer.java b/src/main/java/tesseract/api/fluid/FluidConsumer.java
index eb8cd12e..c67e5875 100644
--- a/src/main/java/tesseract/api/fluid/FluidConsumer.java
+++ b/src/main/java/tesseract/api/fluid/FluidConsumer.java
@@ -1,29 +1,41 @@
package tesseract.api.fluid;
+
+import net.minecraft.util.Direction;
+import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.capability.IFluidHandler;
+import tesseract.api.ConnectionType;
import tesseract.api.Consumer;
import tesseract.graph.Path;
-import tesseract.util.Dir;
+
/**
* A class that acts as a container for a fluid consumer.
*/
-public class FluidConsumer extends Consumer> {
+public class FluidConsumer extends Consumer {
private int isProof = 1;
private int minCapacity = Integer.MAX_VALUE;
+
+ public int getMinPressure() {
+ return minPressure;
+ }
+
private int minPressure = Integer.MAX_VALUE;
private int minTemperature = Integer.MAX_VALUE;
- private final Dir input;
+ public final Direction input;
+
+ public long lowestPipePosition = -1;
/**
* Creates instance of the consumer.
*
* @param consumer The consumer node.
- * @param path The path information.
- * @param dir The added direction.
+ * @param path The path information.
+ * @param dir The added direction.
*/
- protected FluidConsumer(IFluidNode consumer, Path path, Dir dir) {
- super(consumer, path);
+ public FluidConsumer(IFluidNode consumer,IFluidNode producer, Path path, Direction dir) {
+ super(consumer,producer, path);
init();
this.input = dir;
}
@@ -31,19 +43,19 @@ protected FluidConsumer(IFluidNode consumer, Path path, Dir dir)
/**
* Adds fluid to the node. Returns amount of fluid that was filled.
*
- * @param data FluidData attempting to fill the tank.
+ * @param data FluidData attempting to fill the tank.
* @param simulate If true, the fill will only be simulated.
* @return Amount of fluid that was accepted (or would be, if simulated) by the tank.
*/
- public int insert(FluidData data, boolean simulate) {
- return node.insert(data, simulate);
+ public int insert(FluidStack data, boolean simulate) {
+ return node.fill(data, simulate ? IFluidHandler.FluidAction.SIMULATE : IFluidHandler.FluidAction.EXECUTE);
}
/**
* @param fluid The Fluid to be queried.
* @return If the tank can hold the fluid (EVER, not at the time of query).
*/
- public boolean canHold(Object fluid) {
+ public boolean canHold(FluidStack fluid) {
return node.canInput(fluid, input);
}
@@ -56,12 +68,11 @@ public int getPriority() {
/**
* @param temperature The current temperature.
- * @param pressure The current pressure.
- * @param proof True if current liquid is in a gas state.
+ * @param proof True if current liquid is in a gas state.
* @return Checks that the consumer is able to receive fluid.
*/
- public boolean canHandle(int temperature, int pressure, boolean proof) {
- return minTemperature >= temperature && minPressure >= pressure && isProof == (proof ? 1 : 0);
+ public boolean canHandle(int temperature, boolean proof) {
+ return minTemperature >= temperature /*&& minPressure >= pressure */ && isProof == (proof ? 1 : 0);
}
@Override
@@ -69,6 +80,9 @@ protected void onConnectorCatch(IFluidPipe pipe) {
isProof = Math.min(isProof, pipe.isGasProof() ? 1 : 0);
minTemperature = Math.min(minTemperature, pipe.getTemperature());
minCapacity = Math.min(minCapacity, pipe.getCapacity());
+ if (pipe.getPressure() < minPressure && connection == ConnectionType.SINGLE) {
+ lowestPipePosition = this.getFull().long2ObjectEntrySet().stream().filter(t -> t.getValue() == pipe).findFirst().get().getLongKey();
+ }
minPressure = Math.min(minPressure, pipe.getPressure());
}
}
diff --git a/src/main/java/tesseract/api/fluid/FluidController.java b/src/main/java/tesseract/api/fluid/FluidController.java
index a07e3e0e..7ffb53a0 100644
--- a/src/main/java/tesseract/api/fluid/FluidController.java
+++ b/src/main/java/tesseract/api/fluid/FluidController.java
@@ -1,20 +1,22 @@
package tesseract.api.fluid;
-import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
-import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
-import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
-import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
+import it.unimi.dsi.fastutil.longs.*;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import net.minecraft.util.Direction;
+import net.minecraft.util.Tuple;
+import net.minecraft.world.World;
+import net.minecraftforge.fluids.FluidStack;
import tesseract.api.ConnectionType;
import tesseract.api.Consumer;
import tesseract.api.Controller;
import tesseract.api.ITickingController;
+import tesseract.api.capability.ITransactionModifier;
+import tesseract.api.capability.TesseractBaseCapability;
import tesseract.graph.*;
-import tesseract.util.Dir;
import tesseract.util.Node;
import tesseract.util.Pos;
-import java.util.Comparator;
+import javax.annotation.Nonnull;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
@@ -22,63 +24,74 @@
/**
* Class acts as a controller in the group of a fluid components.
*/
-public class FluidController> extends Controller implements IFluidEvent {
+public class FluidController extends Controller
+ implements IFluidEvent {
+ public final static boolean HARDCORE_PIPES = false;
+ public final static boolean SLOOSH = false;
+ public static double PIPE_LEAK = 0.8;
private long totalPressure, lastPressure;
- private int maxTemperature, isLeaking, lastTemperature, lastLeaking;
- private final Long2ObjectMap> holders = new Long2ObjectLinkedOpenHashMap<>();
- private final Object2ObjectMap>>> data = new Object2ObjectLinkedOpenHashMap<>();
+ private int maxTemperature, lastTemperature;
+ private boolean isLeaking, lastLeaking;
+ private final Long2ObjectMap