Merge remote-tracking branch 'origin/master' into fabric/master
# Conflicts: # build.gradle # gradle.properties # gradle/scripts/artifacts.gradle # gradle/scripts/curseforge.gradle # gradle/wrapper/gradle-wrapper.jar # gradle/wrapper/gradle-wrapper.properties # src/main/java/appeng/block/networking/CableBusBlock.java # src/main/java/appeng/client/gui/AEBaseScreen.java # src/main/java/appeng/client/gui/implementations/InterfaceTerminalScreen.java # src/main/java/appeng/client/gui/widgets/Scrollbar.java # src/main/java/appeng/core/sync/packets/JEIRecipePacket.java # src/main/java/appeng/tile/AEBaseBlockEntity.java # src/main/resources/META-INF/mods.toml
This commit is contained in:
+145
-9
@@ -47,6 +47,26 @@ repositories {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
|
||||||
|
|
||||||
|
// compile against provided APIs
|
||||||
|
compileOnly "mezz.jei:jei-${jei_minecraft_version}:${jei_version}:api"
|
||||||
|
compileOnly "mcjty.theoneprobe:TheOneProbe-${minecraft_release}:${minecraft_release}-${top_version}:api"
|
||||||
|
|
||||||
|
// Runtime, Mods
|
||||||
|
runtimeOnly fg.deobf("mezz.jei:jei-${jei_minecraft_version}:${jei_version}")
|
||||||
|
runtimeOnly fg.deobf("mcjty.theoneprobe:TheOneProbe-${minecraft_release}:${minecraft_release}-${top_version}")
|
||||||
|
|
||||||
|
// unit test dependencies
|
||||||
|
testCompile "junit:junit:4.13"
|
||||||
|
|
||||||
|
// Annotation Processors
|
||||||
|
annotationProcessor 'org.spongepowered:mixin:0.8:processor'
|
||||||
|
}
|
||||||
|
group = artifact_group
|
||||||
|
archivesBaseName = artifact_basename
|
||||||
|
|
||||||
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
compileJava {
|
compileJava {
|
||||||
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
@@ -59,7 +79,10 @@ tasks.withType(JavaCompile) {
|
|||||||
options.encoding = 'UTF-8'
|
options.encoding = 'UTF-8'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create version number
|
///////////////////
|
||||||
|
// Version Number
|
||||||
|
version = version_major + "." + version_minor + "." + version_patch
|
||||||
|
|
||||||
ext.pr = System.getenv('PR_NUMBER') ?: ""
|
ext.pr = System.getenv('PR_NUMBER') ?: ""
|
||||||
if (ext.pr) {
|
if (ext.pr) {
|
||||||
version = version + "+pr." + ext.pr
|
version = version + "+pr." + ext.pr
|
||||||
@@ -81,9 +104,8 @@ if (ext.tag && ext.tag.startsWith("fabric/v")) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maven group and artifact name
|
ext.isAlpha = project.version.contains("alpha")
|
||||||
group = artifact_group
|
ext.isBeta = project.version.contains("beta")
|
||||||
archivesBaseName = artifact_basename
|
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
api
|
api
|
||||||
@@ -119,8 +141,8 @@ configurations {
|
|||||||
siteexportRuntime.extendsFrom(runtimeClasspath)
|
siteexportRuntime.extendsFrom(runtimeClasspath)
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: 'gradle/scripts/spotless.gradle'
|
////////////////////
|
||||||
|
// Forge/Minecraft
|
||||||
minecraft {
|
minecraft {
|
||||||
accessWidener "src/main/resources/appliedenergistics2.accesswidener"
|
accessWidener "src/main/resources/appliedenergistics2.accesswidener"
|
||||||
}
|
}
|
||||||
@@ -177,10 +199,74 @@ processResources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: 'gradle/scripts/artifacts.gradle'
|
//////////////
|
||||||
apply from: 'gradle/scripts/curseforge.gradle'
|
// Aritfacts
|
||||||
|
processResources {
|
||||||
|
exclude '.cache'
|
||||||
|
}
|
||||||
|
|
||||||
// configure the maven publication
|
jar {
|
||||||
|
finalizedBy 'reobfJar'
|
||||||
|
finalizedBy 'signJar'
|
||||||
|
|
||||||
|
from sourceSets.main.output.classesDirs
|
||||||
|
from sourceSets.api.output.classesDirs
|
||||||
|
from sourceSets.main.output.resourcesDir
|
||||||
|
from sourceSets.api.output.resourcesDir
|
||||||
|
|
||||||
|
manifest {
|
||||||
|
attributes([
|
||||||
|
"Specification-Title": "Applied Energistics 2",
|
||||||
|
"Specification-Vendor": "TeamAppliedEnergistics",
|
||||||
|
"Specification-Version": "${project.version}",
|
||||||
|
"Implementation-Title": "${project.name}",
|
||||||
|
"Implementation-Version": "${project.version}",
|
||||||
|
"Implementation-Vendor" :"TeamAppliedEnergistics",
|
||||||
|
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
|
||||||
|
"MixinConfigs": "appliedenergistics2.mixins.json"
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task javadocs(type: Javadoc) {
|
||||||
|
classpath = sourceSets.main.compileClasspath
|
||||||
|
source = sourceSets.api.java
|
||||||
|
include "appeng/api/**"
|
||||||
|
|
||||||
|
options.addStringOption('Xdoclint:none', '-quiet')
|
||||||
|
options.encoding = 'UTF-8'
|
||||||
|
options.charSet = 'UTF-8'
|
||||||
|
}
|
||||||
|
|
||||||
|
task javadocJar(type: Jar, dependsOn: javadocs) {
|
||||||
|
classifier = "javadoc"
|
||||||
|
from javadoc.destinationDir
|
||||||
|
}
|
||||||
|
task sourcesJar(type: Jar) {
|
||||||
|
classifier = "sources"
|
||||||
|
from sourceSets.main.allJava
|
||||||
|
from sourceSets.api.allJava
|
||||||
|
}
|
||||||
|
|
||||||
|
task apiJar(type: Jar) {
|
||||||
|
classifier = "api"
|
||||||
|
from sourceSets.api.output
|
||||||
|
include "appeng/api/**"
|
||||||
|
|
||||||
|
// TODO: when FG bug is fixed, remove allJava from the api jar.
|
||||||
|
// https://github.com/MinecraftForge/ForgeGradle/issues/369
|
||||||
|
// Gradle should be able to pull them from the -sources jar.
|
||||||
|
from sourceSets.api.allJava
|
||||||
|
}
|
||||||
|
|
||||||
|
artifacts {
|
||||||
|
archives javadocJar
|
||||||
|
archives sourcesJar
|
||||||
|
archives apiJar
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////
|
||||||
|
// Maven publish
|
||||||
publishing {
|
publishing {
|
||||||
if (!version.endsWith("-SNAPSHOT")) {
|
if (!version.endsWith("-SNAPSHOT")) {
|
||||||
publications {
|
publications {
|
||||||
@@ -239,3 +325,53 @@ task runSiteExport(type: RunClientTask, dependsOn: downloadAssets, group: "ae2",
|
|||||||
classpath sourceSets.main.output
|
classpath sourceSets.main.output
|
||||||
classpath sourceSets.siteexport.output
|
classpath sourceSets.siteexport.output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////
|
||||||
|
// Spotless
|
||||||
|
spotless {
|
||||||
|
java {
|
||||||
|
target 'src/*/java/appeng/**/*.java'
|
||||||
|
|
||||||
|
indentWithSpaces()
|
||||||
|
eclipse().configFile 'codeformat/codeformat.xml'
|
||||||
|
importOrderFile 'codeformat/ae2.importorder'
|
||||||
|
}
|
||||||
|
format 'json', {
|
||||||
|
target 'src/*/resources/**/*.json'
|
||||||
|
targetExclude 'src/generated/resources/**'
|
||||||
|
prettier().config(['parser': 'json'])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// Curse Forge
|
||||||
|
if (System.getenv("CURSEFORGE")) {
|
||||||
|
def cfReleaseType = "release"
|
||||||
|
if (ext.isAlpha) {
|
||||||
|
cfReleaseType = "alpha"
|
||||||
|
} else if (ext.isBeta) {
|
||||||
|
cfReleaseType = "beta"
|
||||||
|
}
|
||||||
|
|
||||||
|
curseforge {
|
||||||
|
apiKey = System.getenv("CURSEFORGE")
|
||||||
|
project {
|
||||||
|
id = project.curseforge_project
|
||||||
|
changelogType = "markdown"
|
||||||
|
changelog = System.getenv("CHANGELOG") ?: "Please visit our [releases](https://github.com/AppliedEnergistics/Applied-Energistics-2/releases) for a changelog"
|
||||||
|
releaseType = cfReleaseType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// IntelliJ Project Import
|
||||||
|
// The Mixin annotation process does not have an obfuscation source when running through the IntelliJ compiler,
|
||||||
|
// thus we have to prevent it from being activated as part of importing this Gradle project into IntelliJ.
|
||||||
|
if (System.getProperty("idea.sync.active") == "true") {
|
||||||
|
afterEvaluate {
|
||||||
|
tasks.withType(JavaCompile).all {
|
||||||
|
it.options.annotationProcessorPath = files()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Applied Energistics 2.
|
|
||||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
|
||||||
*
|
|
||||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
processResources {
|
|
||||||
exclude '.cache'
|
|
||||||
}
|
|
||||||
|
|
||||||
jar {
|
|
||||||
finalizedBy 'remapJar'
|
|
||||||
|
|
||||||
from sourceSets.main.output.classesDirs
|
|
||||||
from sourceSets.api.output.classesDirs
|
|
||||||
from sourceSets.main.output.resourcesDir
|
|
||||||
from sourceSets.api.output.resourcesDir
|
|
||||||
|
|
||||||
manifest {
|
|
||||||
attributes([
|
|
||||||
"Specification-Title": "Applied Energistics 2",
|
|
||||||
"Specification-Vendor": "TeamAppliedEnergistics",
|
|
||||||
"Specification-Version": "${project.version}",
|
|
||||||
"Implementation-Title": "${project.name}",
|
|
||||||
"Implementation-Version": "${project.version}",
|
|
||||||
"Implementation-Vendor" :"TeamAppliedEnergistics",
|
|
||||||
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task javadocs(type: Javadoc) {
|
|
||||||
classpath = sourceSets.main.compileClasspath
|
|
||||||
source = sourceSets.api.java
|
|
||||||
include "appeng/api/**"
|
|
||||||
|
|
||||||
options.addStringOption('Xdoclint:none', '-quiet')
|
|
||||||
options.encoding = 'UTF-8'
|
|
||||||
options.charSet = 'UTF-8'
|
|
||||||
}
|
|
||||||
|
|
||||||
task javadocJar(type: Jar, dependsOn: javadocs) {
|
|
||||||
classifier = "javadoc"
|
|
||||||
from javadoc.destinationDir
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
|
|
||||||
// if it is present.
|
|
||||||
// If you remove this task, sources will not be generated.
|
|
||||||
task sourcesJar(type: Jar, dependsOn: classes) {
|
|
||||||
classifier = "sources"
|
|
||||||
from sourceSets.main.allSource
|
|
||||||
from sourceSets.api.allSource
|
|
||||||
}
|
|
||||||
|
|
||||||
task apiJar(type: Jar) {
|
|
||||||
classifier = "api"
|
|
||||||
from sourceSets.api.output
|
|
||||||
include "appeng/api/**"
|
|
||||||
}
|
|
||||||
|
|
||||||
artifacts {
|
|
||||||
archives javadocJar
|
|
||||||
archives sourcesJar
|
|
||||||
archives apiJar
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Applied Energistics 2.
|
|
||||||
* Copyright (c) 2020, TeamAppliedEnergistics, All rights reserved.
|
|
||||||
*
|
|
||||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
*g GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
def isAlpha = project.version.contains("alpha")
|
|
||||||
def isBeta = project.version.contains("beta")
|
|
||||||
|
|
||||||
def cfReleaseType = "release"
|
|
||||||
if (isAlpha) {
|
|
||||||
cfReleaseType = "alpha"
|
|
||||||
} else if (isBeta) {
|
|
||||||
cfReleaseType = "beta"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (System.getenv("CURSEFORGE") && !version.endsWith("-SNAPSHOT")) {
|
|
||||||
curseforge {
|
|
||||||
apiKey = System.getenv("CURSEFORGE")
|
|
||||||
project {
|
|
||||||
id = project.curseforge_project
|
|
||||||
changelogType = "markdown"
|
|
||||||
changelog = System.getenv("CHANGELOG") ?: "Please visit our [releases](https://github.com/AppliedEnergistics/Applied-Energistics-2/releases) for a changelog"
|
|
||||||
releaseType = cfReleaseType
|
|
||||||
addGameVersion project.minecraft_version
|
|
||||||
addGameVersion "Fabric"
|
|
||||||
mainArtifact(remapJar.archiveFile) {
|
|
||||||
displayName = "${project.version} [FABRIC]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
options {
|
|
||||||
forgeGradleIntegration = false
|
|
||||||
}
|
|
||||||
afterEvaluate {
|
|
||||||
tasks.getByName("curseforge${project.curseforge_project}").dependsOn remapJar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Applied Energistics 2.
|
|
||||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
|
||||||
*
|
|
||||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenLocal()
|
|
||||||
|
|
||||||
maven { // modmaven, maven proxy
|
|
||||||
name 'modmaven'
|
|
||||||
url "https://modmaven.k-4u.nl/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
|
|
||||||
|
|
||||||
// compile against provided APIs
|
|
||||||
compileOnly "mezz.jei:jei-${jei_minecraft_version}:${jei_version}:api"
|
|
||||||
compileOnly "mcjty.theoneprobe:TheOneProbe-${minecraft_release}:${minecraft_release}-${top_version}:api"
|
|
||||||
|
|
||||||
// Runtime, Mods
|
|
||||||
runtimeOnly fg.deobf("mezz.jei:jei-${jei_minecraft_version}:${jei_version}")
|
|
||||||
runtimeOnly fg.deobf("mcjty.theoneprobe:TheOneProbe-${minecraft_release}:${minecraft_release}-${top_version}")
|
|
||||||
//runtimeOnly fg.deobf("team.chisel.ctm:CTM:${ctm_version}")
|
|
||||||
|
|
||||||
// unit test dependencies
|
|
||||||
testCompile "junit:junit:4.13"
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Applied Energistics 2.
|
|
||||||
* Copyright (c) 2013 - 2020, AlgorithmX2, All rights reserved.
|
|
||||||
*
|
|
||||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
*g GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
spotless {
|
|
||||||
java {
|
|
||||||
target 'src/*/java/appeng/**/*.java'
|
|
||||||
|
|
||||||
indentWithSpaces()
|
|
||||||
eclipse().configFile 'codeformat/codeformat.xml'
|
|
||||||
importOrderFile 'codeformat/ae2.importorder'
|
|
||||||
}
|
|
||||||
format 'json', {
|
|
||||||
target 'src/*/resources/**/*.json'
|
|
||||||
targetExclude 'src/generated/resources/**'
|
|
||||||
prettier().config(['parser': 'json'])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -28,4 +28,9 @@ public enum GridNotification {
|
|||||||
* the visible connections for this node have changed, useful for cable.
|
* the visible connections for this node have changed, useful for cable.
|
||||||
*/
|
*/
|
||||||
CONNECTIONS_CHANGED,
|
CONNECTIONS_CHANGED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the owner of the grid node has changed, and the node needs to be re-saved
|
||||||
|
*/
|
||||||
|
OWNER_CHANGED
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ public interface IGridBlock {
|
|||||||
AEColor getGridColor();
|
AEColor getGridColor();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies your IGridBlock that changes were made to your connections
|
* Called by the {@link IGridNode} to notify its {@link IGridBlock} about
|
||||||
|
* events.
|
||||||
*/
|
*/
|
||||||
void onGridNotification(@Nonnull GridNotification notification);
|
void onGridNotification(@Nonnull GridNotification notification);
|
||||||
|
|
||||||
|
|||||||
@@ -300,22 +300,36 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.getScrollBar() != null) {
|
// Forward left mouse button down events to the scrollbar
|
||||||
this.getScrollBar().click(xCoord - this.x, yCoord - this.y);
|
if (btn == 0 && this.getScrollBar() != null) {
|
||||||
|
if (this.getScrollBar().mouseDown(xCoord - this.x, yCoord - this.y)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.mouseClicked(xCoord, yCoord, btn);
|
return super.mouseClicked(xCoord, yCoord, btn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseDragged(double mouseX, double mouseY, int mouseButton, double dragX, double dragY) {
|
public boolean mouseReleased(double mouseX, double mouseY, int button) {
|
||||||
|
// Forward left mouse button up events to the scrollbar
|
||||||
|
if (button == 0 && this.getScrollBar() != null) {
|
||||||
|
if (this.getScrollBar().mouseUp(mouseX - this.guiLeft, mouseY - this.guiTop)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.mouseReleased(mouseX, mouseY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseDragged(double mouseX, double mouseY, int mouseButton, double dragX, double dragY) {
|
||||||
final Slot slot = this.getSlot((int) mouseX, (int) mouseY);
|
final Slot slot = this.getSlot((int) mouseX, (int) mouseY);
|
||||||
final ItemStack itemstack = getPlayer().inventory.getCursorStack();
|
final ItemStack itemstack = getPlayer().inventory.getCursorStack();
|
||||||
|
|
||||||
if (this.getScrollBar() != null) {
|
if (this.getScrollBar() != null) {
|
||||||
// FIXME: Coordinate system of mouseX/mouseY is unclear
|
// FIXME: Coordinate system of mouseX/mouseY is unclear
|
||||||
this.getScrollBar().click((int) mouseX - this.x, (int) mouseY - this.y);
|
this.getScrollBar().mouseDragged((int) mouseX - this.x, (int) mouseY - this.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slot instanceof FakeSlot && !itemstack.isEmpty()) {
|
if (slot instanceof FakeSlot && !itemstack.isEmpty()) {
|
||||||
@@ -798,6 +812,11 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
|
|||||||
|
|
||||||
public void tick() {
|
public void tick() {
|
||||||
super.tick();
|
super.tick();
|
||||||
|
|
||||||
|
if (this.getScrollBar() != null) {
|
||||||
|
this.getScrollBar().tick();
|
||||||
|
}
|
||||||
|
|
||||||
for (Element child : children) {
|
for (Element child : children) {
|
||||||
if (child instanceof ITickingWidget) {
|
if (child instanceof ITickingWidget) {
|
||||||
((ITickingWidget) child).tick();
|
((ITickingWidget) child).tick();
|
||||||
|
|||||||
@@ -93,6 +93,8 @@ public class CraftConfirmScreen extends AEBaseScreen<CraftConfirmContainer> {
|
|||||||
|
|
||||||
addButton(new ButtonWidget(this.x + 6, this.y + this.backgroundHeight - 25, 50, 20, GuiText.Cancel.text(),
|
addButton(new ButtonWidget(this.x + 6, this.y + this.backgroundHeight - 25, 50, 20, GuiText.Cancel.text(),
|
||||||
btn -> subGui.goBack()));
|
btn -> subGui.goBack()));
|
||||||
|
|
||||||
|
this.setScrollBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -70,8 +70,7 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
|
|||||||
|
|
||||||
public InterfaceTerminalScreen(InterfaceTerminalContainer container, PlayerInventory playerInventory, Text title) {
|
public InterfaceTerminalScreen(InterfaceTerminalContainer container, PlayerInventory playerInventory, Text title) {
|
||||||
super(container, playerInventory, title);
|
super(container, playerInventory, title);
|
||||||
final Scrollbar scrollbar = new Scrollbar();
|
this.setScrollBar(new Scrollbar().setLeft(175).setTop(18).setHeight(106));
|
||||||
this.setScrollBar(scrollbar);
|
|
||||||
this.backgroundWidth = 195;
|
this.backgroundWidth = 195;
|
||||||
this.backgroundHeight = 222;
|
this.backgroundHeight = 222;
|
||||||
}
|
}
|
||||||
@@ -80,10 +79,6 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
|
|||||||
public void init() {
|
public void init() {
|
||||||
super.init();
|
super.init();
|
||||||
|
|
||||||
this.getScrollBar().setLeft(175);
|
|
||||||
this.getScrollBar().setHeight(106);
|
|
||||||
this.getScrollBar().setTop(18);
|
|
||||||
|
|
||||||
this.searchField = new AETextField(this.textRenderer, this.x + 104, this.y + 4, 65, 12);
|
this.searchField = new AETextField(this.textRenderer, this.x + 104, this.y + 4, 65, 12);
|
||||||
this.searchField.setHasBorder(false);
|
this.searchField.setHasBorder(false);
|
||||||
this.searchField.setMaxLength(25);
|
this.searchField.setMaxLength(25);
|
||||||
|
|||||||
@@ -283,6 +283,8 @@ public class MEMonitorableScreen<T extends MEMonitorableContainer> extends AEBas
|
|||||||
craftingGridOffsetX -= 25;
|
craftingGridOffsetX -= 25;
|
||||||
craftingGridOffsetY -= 6;
|
craftingGridOffsetY -= 6;
|
||||||
|
|
||||||
|
this.setScrollBar();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Applied Energistics 2.
|
||||||
|
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||||
|
*
|
||||||
|
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package appeng.client.gui.widgets;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class can be used to implement repeating events such as holding down a
|
||||||
|
* button to fire an event repeatedly while the button is still being held, or
|
||||||
|
* repeatedly scrolling down a page, while the mouse is held down on the
|
||||||
|
* scrollbar.
|
||||||
|
*/
|
||||||
|
public class EventRepeater {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* -1 if no repeat event is scheduled. Otherwise contains the
|
||||||
|
* {@link System#nanoTime()} at which the next event should occur.
|
||||||
|
*/
|
||||||
|
private long nextEventTime = -1;
|
||||||
|
|
||||||
|
private EventCallback eventCallback = null;
|
||||||
|
|
||||||
|
private final long eventDelay; // In nanoseconds
|
||||||
|
|
||||||
|
private final long eventInterval; // In nanoseconds
|
||||||
|
|
||||||
|
public EventRepeater(Duration delay, Duration interval) {
|
||||||
|
this.eventDelay = delay.toNanos();
|
||||||
|
this.eventInterval = interval.toNanos();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
if (this.eventCallback == null) {
|
||||||
|
return; // No event scheduled
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use nanoTime here because it is monotonically increasing, while
|
||||||
|
// System.currentTimeMillis is not
|
||||||
|
long nanoTime = System.nanoTime();
|
||||||
|
if (nanoTime < this.nextEventTime) {
|
||||||
|
return; // Event time not reached
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before triggering, recompute the next event, since
|
||||||
|
// the event callback itself may reschedule/cancel, and
|
||||||
|
// we should not overwrite that
|
||||||
|
this.nextEventTime = nanoTime + this.eventInterval;
|
||||||
|
this.eventCallback.trigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule the given callback to be called after a given initial delay, and
|
||||||
|
* then after the given interval repeatedly.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Replaces any previously queued callback.
|
||||||
|
*/
|
||||||
|
public void repeat(EventCallback callback) {
|
||||||
|
long time = System.nanoTime();
|
||||||
|
this.eventCallback = callback;
|
||||||
|
this.nextEventTime = time + eventDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRepeating() {
|
||||||
|
return this.eventCallback != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop repeating the event.
|
||||||
|
*/
|
||||||
|
public void stop() {
|
||||||
|
this.eventCallback = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface EventCallback {
|
||||||
|
void trigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -18,18 +18,76 @@
|
|||||||
|
|
||||||
package appeng.client.gui.widgets;
|
package appeng.client.gui.widgets;
|
||||||
|
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import java.time.Duration;
|
||||||
|
|
||||||
import net.minecraft.client.gui.DrawableHelper;
|
import net.minecraft.client.gui.DrawableHelper;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.Rectangle2d;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
import appeng.client.gui.AEBaseScreen;
|
import appeng.client.gui.AEBaseScreen;
|
||||||
|
|
||||||
public class Scrollbar implements IScrollSource {
|
/**
|
||||||
|
* Implements a vertical scrollbar using Vanilla's scrollbar handle texture from
|
||||||
|
* the creative tab.
|
||||||
|
* <p>
|
||||||
|
* It is expected that the background of the UI contains a pre-baked scrollbar
|
||||||
|
* track border, and that the exact rectangle of that track is set on this
|
||||||
|
* object via {@link #setLeft(int)}, {@link #setTop(int)} and
|
||||||
|
* {@link #setHeight(int)}. While the width of the track can also be set, the
|
||||||
|
* drawn handle will use vanilla's sprite width (see {@link #HANDLE_WIDTH}.
|
||||||
|
*/
|
||||||
|
public class Scrollbar extends DrawableHelper implements IScrollSource {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Width of the scrollbar handle sprite in the source texture.
|
||||||
|
*/
|
||||||
|
private static final int HANDLE_WIDTH = 12;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Height of the scrollbar handle sprite in the source texture.
|
||||||
|
*/
|
||||||
|
private static final int HANDLE_HEIGHT = 15;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Texture containing the scrollbar handle sprites.
|
||||||
|
*/
|
||||||
|
private static final ResourceLocation TEXTURE = new ResourceLocation("minecraft",
|
||||||
|
"textures/gui/container/creative_inventory/tabs.png");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rectangle in the source texture that contains the sprite for an enabled
|
||||||
|
* handle.
|
||||||
|
*/
|
||||||
|
private static final Rectangle2d ENABLED = new Rectangle2d(232, 0, HANDLE_WIDTH, HANDLE_HEIGHT);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rectangle in the source texture that contains the sprite for a disabled
|
||||||
|
* handle.
|
||||||
|
*/
|
||||||
|
private static final Rectangle2d DISABLED = new Rectangle2d(232 + HANDLE_WIDTH, 0, HANDLE_WIDTH, HANDLE_HEIGHT);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The screen x-coordinate of the scrollbar's inner track.
|
||||||
|
*/
|
||||||
private int displayX = 0;
|
private int displayX = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The screen y-coordinate of the scrollbar's inner track.
|
||||||
|
*/
|
||||||
private int displayY = 0;
|
private int displayY = 0;
|
||||||
private int width = 12;
|
|
||||||
|
/**
|
||||||
|
* The inner width of the scrollbar track.
|
||||||
|
*/
|
||||||
|
private int width = HANDLE_WIDTH;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The inner height of the scrollbar track.
|
||||||
|
*/
|
||||||
private int height = 16;
|
private int height = 16;
|
||||||
private int pageSize = 1;
|
private int pageSize = 1;
|
||||||
|
|
||||||
@@ -37,20 +95,58 @@ public class Scrollbar implements IScrollSource {
|
|||||||
private int minScroll = 0;
|
private int minScroll = 0;
|
||||||
private int currentScroll = 0;
|
private int currentScroll = 0;
|
||||||
|
|
||||||
private final DrawableHelper drawable = new DrawableHelper() {
|
/**
|
||||||
};
|
* True if the scrollbar's handle is currently being dragged.
|
||||||
|
*/
|
||||||
|
private boolean dragging;
|
||||||
|
/**
|
||||||
|
* The y-coordinate relative to the upper edge of the scrollbar handle, where
|
||||||
|
* the user pressed the mouse button to drag. While dragging, this is applied as
|
||||||
|
* an offset to the effective scrollbar position.
|
||||||
|
*/
|
||||||
|
private int dragYOffset;
|
||||||
|
|
||||||
|
private final EventRepeater eventRepeater = new EventRepeater(Duration.ofMillis(250), Duration.ofMillis(150));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the handle of the scrollbar.
|
||||||
|
* <p>
|
||||||
|
* The GUI is assumed to already contain a prebaked scrollbar track in its
|
||||||
|
* background.
|
||||||
|
*/
|
||||||
public void draw(MatrixStack matrices, final AEBaseScreen<?> g) {
|
public void draw(MatrixStack matrices, final AEBaseScreen<?> g) {
|
||||||
g.bindTexture("minecraft", "gui/container/creative_inventory/tabs.png");
|
setBlitOffset(g.getBlitOffset());
|
||||||
RenderSystem.color4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
||||||
|
|
||||||
drawable.setZOffset(g.getZOffset());
|
// Draw the track (nice for debugging)
|
||||||
|
// fill(matrices, displayX, displayY, this.displayX + width, this.displayY +
|
||||||
|
// height, 0xffff0000);
|
||||||
|
|
||||||
|
g.bindTexture(TEXTURE);
|
||||||
|
|
||||||
|
int yOffset;
|
||||||
|
Rectangle2d sourceRect;
|
||||||
if (this.getRange() == 0) {
|
if (this.getRange() == 0) {
|
||||||
drawable.drawTexture(matrices, this.displayX, this.displayY, 232 + this.width, 0, this.width, 15);
|
yOffset = 0;
|
||||||
|
sourceRect = DISABLED;
|
||||||
} else {
|
} else {
|
||||||
final int offset = (this.currentScroll - this.minScroll) * (this.height - 15) / this.getRange();
|
yOffset = getHandleYOffset();
|
||||||
drawable.drawTexture(matrices, this.displayX, offset + this.displayY, 232, 0, this.width, 15);
|
sourceRect = ENABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blit(matrices, this.displayX, this.displayY + yOffset, sourceRect.getX(), sourceRect.getY(),
|
||||||
|
sourceRect.getWidth(), sourceRect.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the y-position of the scrollbar handle in relation to the upper edge
|
||||||
|
* of the scrollbar's track.
|
||||||
|
*/
|
||||||
|
private int getHandleYOffset() {
|
||||||
|
if (getRange() == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int availableHeight = this.height - HANDLE_HEIGHT;
|
||||||
|
return (this.currentScroll - this.minScroll) * availableHeight / this.getRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getRange() {
|
private int getRange() {
|
||||||
@@ -114,24 +210,96 @@ public class Scrollbar implements IScrollSource {
|
|||||||
return this.currentScroll;
|
return this.currentScroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void click(final double x, final double y) {
|
public boolean mouseDown(double x, double y) {
|
||||||
if (this.getRange() == 0) {
|
this.dragging = false;
|
||||||
|
|
||||||
|
// Clicks to the left or right of the scrollbar don't do anything
|
||||||
|
if (x < displayX || x >= displayX + width) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clicks to the top or bottom don't do anything either
|
||||||
|
int relY = (int) Math.round(y - displayY);
|
||||||
|
if (relY < 0 || relY >= height) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do nothing when there's no range, but swallow the event
|
||||||
|
if (getRange() == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handleYOffset = getHandleYOffset();
|
||||||
|
|
||||||
|
if (relY < handleYOffset) {
|
||||||
|
// Clicks above the handle will page up, repeatedly
|
||||||
|
pageUp();
|
||||||
|
eventRepeater.repeat(this::pageUp);
|
||||||
|
|
||||||
|
} else if (relY < handleYOffset + HANDLE_HEIGHT) {
|
||||||
|
// Clicks on the handle will initiate dragging it
|
||||||
|
this.dragging = true;
|
||||||
|
this.dragYOffset = relY - handleYOffset;
|
||||||
|
} else {
|
||||||
|
// Clicks below the handle will page down, repeatedly
|
||||||
|
pageDown();
|
||||||
|
eventRepeater.repeat(this::pageDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean mouseUp(double x, double y) {
|
||||||
|
this.dragging = false;
|
||||||
|
this.eventRepeater.stop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseDragged(double x, double y) {
|
||||||
|
if (this.getRange() == 0 || !this.dragging || this.eventRepeater.isRepeating()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x > this.displayX && x <= this.displayX + this.width) {
|
// Compute the position of the mouse (adjusted for where it grabbed the handle,
|
||||||
if (y > this.displayY && y <= this.displayY + this.height) {
|
// so as if it grabbed
|
||||||
this.currentScroll = (int) (y - this.displayY);
|
// the upper edge of it) within the scrollable area of the track (minus the
|
||||||
this.currentScroll = this.minScroll + ((this.currentScroll * 2 * this.getRange() / this.height));
|
// handle height).
|
||||||
this.currentScroll = (this.currentScroll + 1) >> 1;
|
double handleUpperEdgeY = y - this.displayY - this.dragYOffset;
|
||||||
this.applyRange();
|
double availableHeight = this.height - HANDLE_HEIGHT;
|
||||||
}
|
double position = MathHelper.clamp(handleUpperEdgeY / availableHeight, 0.0, 1.0);
|
||||||
}
|
|
||||||
|
this.currentScroll = this.minScroll + (int) Math.round(position * this.getRange());
|
||||||
|
this.applyRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void wheel(double delta) {
|
public void wheel(double delta) {
|
||||||
|
// Do nothing when there's no range
|
||||||
|
if (getRange() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
delta = Math.max(Math.min(-delta, 1), -1);
|
delta = Math.max(Math.min(-delta, 1), -1);
|
||||||
this.currentScroll += delta * this.pageSize;
|
this.currentScroll += delta * this.pageSize;
|
||||||
this.applyRange();
|
this.applyRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ticks the scrollbar for the purposes of input-repeats (since mouse-downs are
|
||||||
|
* not repeat-triggered), used to repeatedly page-up or page-down when the mouse
|
||||||
|
* is held in the area above or below the scrollbar handle.
|
||||||
|
*/
|
||||||
|
public void tick() {
|
||||||
|
this.eventRepeater.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pageUp() {
|
||||||
|
this.currentScroll -= this.pageSize;
|
||||||
|
this.applyRange();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pageDown() {
|
||||||
|
this.currentScroll += this.pageSize;
|
||||||
|
this.applyRange();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
package appeng.core.sync.packets;
|
package appeng.core.sync.packets;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@@ -325,15 +326,10 @@ public class JEIRecipePacket extends BasePacket {
|
|||||||
*/
|
*/
|
||||||
private IAEItemStack findBestMatchingItemStack(Ingredient ingredients, IPartitionList<IAEItemStack> filter,
|
private IAEItemStack findBestMatchingItemStack(Ingredient ingredients, IPartitionList<IAEItemStack> filter,
|
||||||
IMEMonitor<IAEItemStack> storage, IContainerCraftingPacket cct) {
|
IMEMonitor<IAEItemStack> storage, IContainerCraftingPacket cct) {
|
||||||
return Arrays.stream(getMatchingStacks(ingredients)).map(AEItemStack::fromItemStack) //
|
Stream<AEItemStack> stacks = Arrays.stream(getMatchingStacks(ingredients))//
|
||||||
.filter(r -> r != null && (filter == null || filter.isListed(r))) //
|
.map(AEItemStack::fromItemStack) //
|
||||||
.map(s -> {
|
.filter(r -> r != null && (filter == null || filter.isListed(r)));
|
||||||
// Determine the stored count
|
return getMostStored(stacks, storage, cct);
|
||||||
IAEItemStack stored = storage.extractItems(s.copy().setStackSize(Long.MAX_VALUE),
|
|
||||||
Actionable.SIMULATE, cct.getActionSource());
|
|
||||||
return Pair.of(s, stored != null ? stored.getStackSize() : 0);
|
|
||||||
}).min((left, right) -> Long.compare(right.getSecond(), left.getSecond()))//
|
|
||||||
.map(Pair::getFirst).orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -344,16 +340,30 @@ public class JEIRecipePacket extends BasePacket {
|
|||||||
*/
|
*/
|
||||||
private IAEItemStack findBestMatchingPattern(Ingredient ingredients, IPartitionList<IAEItemStack> filter,
|
private IAEItemStack findBestMatchingPattern(Ingredient ingredients, IPartitionList<IAEItemStack> filter,
|
||||||
ICraftingGrid crafting, IMEMonitor<IAEItemStack> storage, IContainerCraftingPacket cct) {
|
ICraftingGrid crafting, IMEMonitor<IAEItemStack> storage, IContainerCraftingPacket cct) {
|
||||||
return Arrays.stream(getMatchingStacks(ingredients)).map(AEItemStack::fromItemStack)
|
Stream<IAEItemStack> stacks = Arrays.stream(getMatchingStacks(ingredients))//
|
||||||
.filter(r -> r != null && (filter == null || filter.isListed(r)))
|
.map(AEItemStack::fromItemStack)//
|
||||||
.map(s -> s.setCraftable(!crafting.getCraftingFor(s, null, 0, null).isEmpty()))
|
.filter(r -> r != null && (filter == null || filter.isListed(r)))//
|
||||||
.filter(IAEItemStack::isCraftable).map(s -> {
|
.map(s -> s.setCraftable(!crafting.getCraftingFor(s, null, 0, null).isEmpty()))//
|
||||||
final IAEItemStack stored = storage.extractItems(s, Actionable.SIMULATE, cct.getActionSource());
|
.filter(IAEItemStack::isCraftable);
|
||||||
return s.setStackSize(stored != null ? stored.getStackSize() : 0);
|
return getMostStored(stacks, storage, cct);
|
||||||
}).min((left, right) -> {
|
}
|
||||||
final int craftable = Boolean.compare(left.isCraftable(), right.isCraftable());
|
|
||||||
return craftable != 0 ? craftable : Long.compare(right.getStackSize(), left.getStackSize());
|
/**
|
||||||
}).orElse(null);
|
* From a stream of AE item stacks, pick the one with the highest available
|
||||||
|
* amount in the network. Returns null if the stream is empty.
|
||||||
|
*/
|
||||||
|
private static IAEItemStack getMostStored(Stream<? extends IAEItemStack> stacks, IMEMonitor<IAEItemStack> storage,
|
||||||
|
IContainerCraftingPacket cct) {
|
||||||
|
return stacks//
|
||||||
|
.map(s -> {
|
||||||
|
// Determine the stored count
|
||||||
|
IAEItemStack stored = storage.extractItems(s.copy().setStackSize(Long.MAX_VALUE),
|
||||||
|
Actionable.SIMULATE, cct.getActionSource());
|
||||||
|
return Pair.of(s, stored != null ? stored.getStackSize() : 0);
|
||||||
|
})//
|
||||||
|
.min((left, right) -> Long.compare(right.getSecond(), left.getSecond()))//
|
||||||
|
.map(Pair::getFirst)//
|
||||||
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleProcessing(ScreenHandler con, IContainerCraftingPacket cct, Recipe<?> recipe) {
|
private void handleProcessing(ScreenHandler con, IContainerCraftingPacket cct, Recipe<?> recipe) {
|
||||||
|
|||||||
@@ -327,8 +327,9 @@ public class GridNode implements IGridNode, IPathItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPlayerID(final int playerID) {
|
public void setPlayerID(final int playerID) {
|
||||||
if (playerID >= 0) {
|
if (playerID >= 0 && this.playerID != playerID) {
|
||||||
this.playerID = playerID;
|
this.playerID = playerID;
|
||||||
|
gridProxy.onGridNotification(GridNotification.OWNER_CHANGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -96,7 +96,11 @@ public class CraftingGridCache
|
|||||||
nextDetail) -> nextDetail.getPriority() - firstDetail.getPriority();
|
nextDetail) -> nextDetail.getPriority() - firstDetail.getPriority();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final ThreadFactory factory = ar -> new Thread(ar, "AE Crafting Calculator");
|
final ThreadFactory factory = ar -> {
|
||||||
|
final Thread crafting = new Thread(ar, "AE Crafting Calculator");
|
||||||
|
crafting.setDaemon(true);
|
||||||
|
return crafting;
|
||||||
|
};
|
||||||
|
|
||||||
CRAFTING_POOL = Executors.newCachedThreadPool(factory);
|
CRAFTING_POOL = Executors.newCachedThreadPool(factory);
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-2
@@ -81,8 +81,16 @@ public class SecurityCache implements ISecurityGrid {
|
|||||||
private void updateSecurityKey() {
|
private void updateSecurityKey() {
|
||||||
final long lastCode = this.securityKey;
|
final long lastCode = this.securityKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placing a security station will propagate the security station's owner to all
|
||||||
|
* connected grid nodes to prevent the network from not reforming due to
|
||||||
|
* different owners later.
|
||||||
|
*/
|
||||||
|
int newOwner = -1;
|
||||||
if (this.securityProvider.size() == 1) {
|
if (this.securityProvider.size() == 1) {
|
||||||
this.securityKey = this.securityProvider.get(0).getSecurityKey();
|
ISecurityProvider securityProvider = this.securityProvider.get(0);
|
||||||
|
this.securityKey = securityProvider.getSecurityKey();
|
||||||
|
newOwner = securityProvider.getOwner();
|
||||||
} else {
|
} else {
|
||||||
this.securityKey = -1;
|
this.securityKey = -1;
|
||||||
}
|
}
|
||||||
@@ -90,7 +98,11 @@ public class SecurityCache implements ISecurityGrid {
|
|||||||
if (lastCode != this.securityKey) {
|
if (lastCode != this.securityKey) {
|
||||||
this.getGrid().postEvent(new MENetworkSecurityChange());
|
this.getGrid().postEvent(new MENetworkSecurityChange());
|
||||||
for (final IGridNode n : this.getGrid().getNodes()) {
|
for (final IGridNode n : this.getGrid().getNodes()) {
|
||||||
((GridNode) n).setLastSecurityKey(this.securityKey);
|
GridNode gridNode = (GridNode) n;
|
||||||
|
gridNode.setLastSecurityKey(this.securityKey);
|
||||||
|
if (gridNode.getPlayerID() != newOwner) {
|
||||||
|
gridNode.setPlayerID(newOwner);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -279,6 +279,11 @@ public class AENetworkProxy implements IGridBlock {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGridNotification(final GridNotification notification) {
|
public void onGridNotification(final GridNotification notification) {
|
||||||
|
if (notification == GridNotification.OWNER_CHANGED) {
|
||||||
|
gp.saveChanges();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.gp instanceof CablePart) {
|
if (this.gp instanceof CablePart) {
|
||||||
((CablePart) this.gp).markForUpdate();
|
((CablePart) this.gp).markForUpdate();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,4 +28,7 @@ public interface IGridProxyable extends IGridHost {
|
|||||||
DimensionalCoord getLocation();
|
DimensionalCoord getLocation();
|
||||||
|
|
||||||
void gridChanged();
|
void gridChanged();
|
||||||
|
|
||||||
|
void saveChanges();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ public final class CompassThreadFactory implements ThreadFactory {
|
|||||||
@Override
|
@Override
|
||||||
public Thread newThread(@Nonnull final Runnable job) {
|
public Thread newThread(@Nonnull final Runnable job) {
|
||||||
Preconditions.checkNotNull(job);
|
Preconditions.checkNotNull(job);
|
||||||
|
final Thread compass = new Thread(job, "AE Compass Service");
|
||||||
|
compass.setDaemon(true);
|
||||||
|
|
||||||
return new Thread(job, "AE Compass Service");
|
return compass;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user