Compare commits

..

42 Commits

Author SHA1 Message Date
Sebastian Hartte 5da5315a5b Post-merge fixes. Reformat. Optimize Imports. 2020-09-20 14:47:25 +02:00
Sebastian Hartte f3c44c64c2 Merge remote-tracking branch 'origin/master' into fabric/master
# Conflicts:
#	build.gradle
#	gradle.properties
#	src/api/java/appeng/api/util/DimensionalCoord.java
#	src/main/java/appeng/block/paint/PaintSplotchesBakedModel.java
#	src/main/java/appeng/bootstrap/BlockDefinitionBuilder.java
#	src/main/java/appeng/client/gui/AEBaseScreen.java
#	src/main/java/appeng/client/gui/implementations/CraftAmountScreen.java
#	src/main/java/appeng/client/gui/implementations/CraftConfirmScreen.java
#	src/main/java/appeng/client/gui/implementations/CraftingStatusScreen.java
#	src/main/java/appeng/client/gui/implementations/InterfaceScreen.java
#	src/main/java/appeng/client/gui/implementations/InterfaceTerminalScreen.java
#	src/main/java/appeng/client/gui/implementations/LevelEmitterScreen.java
#	src/main/java/appeng/client/gui/implementations/NumberEntryWidget.java
#	src/main/java/appeng/client/gui/implementations/PriorityScreen.java
#	src/main/java/appeng/client/gui/widgets/IconButton.java
#	src/main/java/appeng/client/gui/widgets/NumberBox.java
#	src/main/java/appeng/client/gui/widgets/SettingToggleButton.java
#	src/main/java/appeng/client/gui/widgets/TabButton.java
#	src/main/java/appeng/client/render/DelegateBakedModel.java
#	src/main/java/appeng/client/render/DummyFluidDispatcherBakedModel.java
#	src/main/java/appeng/client/render/FacadeBakedItemModel.java
#	src/main/java/appeng/client/render/FacadeDispatcherBakedModel.java
#	src/main/java/appeng/client/render/cablebus/P2PTunnelFrequencyBakedModel.java
#	src/main/java/appeng/client/render/crafting/EncodedPatternBakedModel.java
#	src/main/java/appeng/client/render/model/AutoRotatingBakedModel.java
#	src/main/java/appeng/client/render/model/BiometricCardBakedModel.java
#	src/main/java/appeng/client/render/model/ColorApplicatorBakedModel.java
#	src/main/java/appeng/client/render/model/GlassBakedModel.java
#	src/main/java/appeng/client/render/model/MemoryCardBakedModel.java
#	src/main/java/appeng/client/render/model/SkyCompassBakedModel.java
#	src/main/java/appeng/client/render/tesr/ChestTileEntityRenderer.java
#	src/main/java/appeng/container/AEBaseContainer.java
#	src/main/java/appeng/container/ContainerLocator.java
#	src/main/java/appeng/container/guisync/SyncData.java
#	src/main/java/appeng/container/implementations/CellWorkbenchContainer.java
#	src/main/java/appeng/container/implementations/CondenserContainer.java
#	src/main/java/appeng/container/implementations/ContainerHelper.java
#	src/main/java/appeng/container/implementations/CraftConfirmContainer.java
#	src/main/java/appeng/container/implementations/CraftingCPUContainer.java
#	src/main/java/appeng/container/implementations/CraftingCPURecord.java
#	src/main/java/appeng/container/implementations/CraftingStatusContainer.java
#	src/main/java/appeng/container/implementations/IOPortContainer.java
#	src/main/java/appeng/container/implementations/InscriberContainer.java
#	src/main/java/appeng/container/implementations/InterfaceTerminalContainer.java
#	src/main/java/appeng/container/implementations/LevelEmitterContainer.java
#	src/main/java/appeng/container/implementations/MEMonitorableContainer.java
#	src/main/java/appeng/container/implementations/MolecularAssemblerContainer.java
#	src/main/java/appeng/container/implementations/PatternTermContainer.java
#	src/main/java/appeng/container/implementations/PriorityContainer.java
#	src/main/java/appeng/container/implementations/QuartzKnifeContainer.java
#	src/main/java/appeng/container/implementations/SpatialIOPortContainer.java
#	src/main/java/appeng/container/implementations/VibrationChamberContainer.java
#	src/main/java/appeng/container/implementations/WirelessTermContainer.java
#	src/main/java/appeng/core/AEConfig.java
#	src/main/java/appeng/core/AppEngBootstrap.java
#	src/main/java/appeng/core/Registration.java
#	src/main/java/appeng/core/api/definitions/ApiItems.java
#	src/main/java/appeng/core/features/registries/WorldGenRegistry.java
#	src/main/java/appeng/core/sync/network/NetworkHandler.java
#	src/main/java/appeng/core/worlddata/WorldData.java
#	src/main/java/appeng/datagen/providers/loot/BlockDropProvider.java
#	src/main/java/appeng/debug/ChunkLoaderBlockEntity.java
#	src/main/java/appeng/debug/ReplicatorCardItem.java
#	src/main/java/appeng/entity/GrowingCrystalEntity.java
#	src/main/java/appeng/fluids/client/gui/FluidLevelEmitterScreen.java
#	src/main/java/appeng/fluids/client/gui/FluidTerminalScreen.java
#	src/main/java/appeng/fluids/container/FluidConfigurableContainer.java
#	src/main/java/appeng/fluids/container/FluidInterfaceContainer.java
#	src/main/java/appeng/fluids/container/FluidLevelEmitterContainer.java
#	src/main/java/appeng/fluids/container/FluidTerminalContainer.java
#	src/main/java/appeng/fluids/util/AEFluidInventory.java
#	src/main/java/appeng/items/misc/CrystalSeedItem.java
#	src/main/java/appeng/items/misc/CrystalSeedRendering.java
#	src/main/java/appeng/items/storage/SpatialStorageCellItem.java
#	src/main/java/appeng/me/cluster/implementations/QuantumCluster.java
#	src/main/java/appeng/mixins/feature/ConfiguredFeaturesAccessor.java
#	src/main/java/appeng/mixins/spatial/BiomesMixin.java
#	src/main/java/appeng/mixins/spatial/DimensionTypeMixin.java
#	src/main/java/appeng/mixins/spatial/EntityMixin.java
#	src/main/java/appeng/mixins/spatial/SkyRenderMixin.java
#	src/main/java/appeng/mixins/structure/BiomeAccessor.java
#	src/main/java/appeng/mixins/structure/GenerationSettingsAccessor.java
#	src/main/java/appeng/parts/automation/FormationPlanePart.java
#	src/main/java/appeng/parts/automation/PlaneBakedModel.java
#	src/main/java/appeng/server/subcommands/SpatialStorageCommand.java
#	src/main/java/appeng/server/subcommands/TestMeteoritesCommand.java
#	src/main/java/appeng/server/subcommands/TestOreGenCommand.java
#	src/main/java/appeng/spatial/SpatialStorageBiome.java
#	src/main/java/appeng/spatial/SpatialStorageChunkGenerator.java
#	src/main/java/appeng/spatial/SpatialStorageDimensionIds.java
#	src/main/java/appeng/spatial/SpatialStorageHelper.java
#	src/main/java/appeng/util/Platform.java
#	src/main/java/appeng/worldgen/BiomeModifier.java
#	src/main/java/appeng/worldgen/meteorite/MeteoriteStructureStart.java
#	src/main/java/appeng/worldgen/meteorite/fallout/FalloutCopy.java
#	src/main/resources/assets/appliedenergistics2/textures/guis/states.png
2020-09-20 14:11:22 +02:00
Sebastian Hartte b8f48407cd Fix tooltip rendering. 2020-09-20 01:06:53 +02:00
Sebastian Hartte 489b0f635e Merge remote-tracking branch 'origin/8.0.x-1.16.1' 2020-09-20 00:42:52 +02:00
shartte e6fb553a53 Fixes #4741: Rework Crafting CPU cycling and extract commonalities into a separate class. (#4742)
Also Fixes:
- Enter key confirms the "Confirm Crafting" dialog again
- Right Mouse Button correctly cycles backwards through CPUs, while left mouse button forward
- Fixes an internal problem with syncing CPU names
- Naming of unnamed CPUs begins at #1 now
2020-09-20 00:26:34 +02:00
Sebastian Hartte cacd824db3 Remove unused field indicating availability of client classes. 2020-09-19 18:20:11 +02:00
yueh 876bb52087 Update forge mappings to 20200916-1.16.2 (#4749) 2020-09-19 17:32:23 +02:00
Sebastian Hartte 1b4969c8e7 Formatting fixes. 2020-09-19 16:58:37 +02:00
Sebastian Hartte f2427ee347 Fixes #4747: The chunk unload event was triggering before the chunk was actually saved to disk, which means disconnecting grid connections at that point led to grid nodes not saving their data to the chunk. 2020-09-19 16:54:30 +02:00
Sebastian Hartte 4aa9c92a68 Fixes #4747: Server unload event was destroying grids before the associated nodes were saved, leading to player ids not being saved correctly when quitting the server. 2020-09-19 16:49:44 +02:00
shartte 971a9d22e8 Improvements to the usability of the number entry widgets (Priority, Level Emitter, Craft Amount): (#4737)
- Fixed tab order
- Introduced focus state for corner buttons
- Allowed the player to enter any text, but add validation that only persist it if it is a valid number
- Enter will now confirm these dialogs and return to the previous dialog
- The text field is automatically focused and its contents are selected
2020-09-19 16:27:29 +02:00
Sebastian Hartte b5a90357c0 Fix ME Chest attributes being exposed on the wrong side. 2020-09-19 13:59:09 +02:00
Sebastian Hartte 5be0adbc89 Fixed Mixins that were targeting the wrong class/methods. 2020-09-19 02:48:59 +02:00
Sebastian Hartte d8e5f4fed5 Fixed formatating after migrating mappings. 2020-09-19 02:41:53 +02:00
Sebastian Hartte 47dfc19b7c Renamed mixin after mapping update. 2020-09-19 02:40:51 +02:00
Sebastian Hartte 45f5851079 Updated versions, and mappings. 2020-09-19 02:40:35 +02:00
Sebastian Hartte 76efe6026d Add an indicator that shows the number of active crafting jobs. 2020-09-18 21:34:42 +02:00
yueh 4e03cbd356 Simply build all branches 2020-09-18 10:32:06 +02:00
Sebastian Hartte ce058b006c Fixes #4748: badly filtered inventory leads to crashes, also expose the ME storage again. 2020-09-18 03:11:33 +02:00
yueh 9005db6f1c Fix yaml syntax 2020-09-17 21:42:20 +02:00
yueh 58afe755b8 Build PRs for all release branches (#4746) 2020-09-17 21:37:53 +02:00
Sebastian Hartte f368f9dac2 Fixes #4697: Show number of required items in condenser tooltips. 2020-09-17 14:33:43 +02:00
Sebastian Hartte e5b45d51cc Minor style fixes. 2020-09-17 11:43:29 +02:00
shartte 5a1d5356d1 Fixes #4733: Fix a crash bug when an external machine tries draining fluids from a fluid interface without a filter. (#4738) 2020-09-16 23:13:18 +02:00
Sebastian Hartte 5aef82b9ef Optimized Imports 2020-09-16 21:35:47 +02:00
Sebastian Hartte 483f93f977 Post-merge fixes and item generator fix. 2020-09-16 20:12:38 +02:00
Sebastian Hartte 1759f92164 Prevent FG from force-exiting the daemon if runData is used. 2020-09-16 19:51:22 +02:00
Sebastian Hartte e50c13e570 Rolled back the memory change since it'll cause a daemon to launch even during a CI build. 2020-09-16 19:29:47 +02:00
Sebastian Hartte c0575e11b0 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
2020-09-16 18:57:15 +02:00
Sebastian Hartte 749dd35f88 Updated forge and increased memory for IDE-sync daemon. 2020-09-16 18:18:22 +02:00
Sebastian Hartte ca79a377bd Merge remote-tracking branch 'origin/8.0.x-1.16.1'
# Conflicts:
#	gradle/scripts/dependencies.gradle
2020-09-16 17:49:59 +02:00
Sebastian Hartte 475c8ff5a1 Adapt the same sorting logic used for items stored in the network for items obtained from patterns, which fixes items from patterns not being able to be shift-clicked into new patterns. 2020-09-16 17:44:49 +02:00
yueh 5b3ccf26d0 Merge all gradle files (#4732)
* Merge all gradle files

The specific build files are now much smaller, so a single one is mostly acceptable now.
Also updates Gradle to 5.6.3

* Disable the Mixin annotation processor when importing this project into IntelliJ since it should only be needed to generate refmaps on an actual build.

* Removed Sonarqube and JaCoCo plugins.

Co-authored-by: Sebastian Hartte <sebastian@hartte.de>
2020-09-14 14:14:00 +02:00
Sebastian Hartte e73dbe4891 Updated Forge / MC to 1.16.3
Keep Mappings
Allow higher range for MC + Forge versions
2020-09-14 02:02:59 +02:00
Sebastian Hartte 38244000c9 Fixes #4731: Take the position where the user clicked the handle into account when calculating the new scrollbar position.
Also fixes: The scrollbar did not subtract the handle height when determining the available space for moving the handle, thus introducing drift the further down a user scrolled.
Also fixes: The scrollbar did not resize it's trackbar when the ME inventory screens were resized and the number of rows changed, same for craft confirm.
2020-09-13 23:12:59 +02:00
Sebastian Hartte d87ff9d1e7 Formatting fixes. 2020-09-13 22:18:38 +02:00
Sebastian Hartte 4ba97ec899 Remove unnecessary debug prints, and rename methods. 2020-09-13 22:11:40 +02:00
Sebastian Hartte 0147e1ddfb Fixes #4730 and also introduces repeat-pageup/pagedown when holding the mouse on the area above or below the scrollbar handle. 2020-09-13 22:09:47 +02:00
yueh 621d2ee715 Fixes #4728: Mark all offloading threads as daemons (#4729) 2020-09-13 11:55:18 +02:00
Sebastian Hartte 31ecdfbe0a Use the correct method to update an entities position forcefully. 2020-09-11 18:04:17 +02:00
shartte d07937fa93 Render Performance Improvements (#4721)
* Return a fixed bounding box for frustrum culling of AE tile entity renderers to prevent Forge from re-retrieving the TE from the world and calculating the collision box (very costly for cables).

* Changed dynamic cable bus lighting to be based on block states to improved rendering speed and fix optifine issues. (Potential fix for #4716).
2020-09-10 22:56:50 +02:00
shartte 65f58913a4 Make players assume ownership of networks when they place security stations onto unsecured ones (#4714)
* Fixes #4712: When a security station is placed onto an unsecured network, the placer assumes ownership of the entire network. Otherwise the contiguous network would not necessarily reconnect in the same way when the chunk is reloaded due to differing player-ids throughout the network.
In addition, changes to the node's owner were not being persisted due to the host never being marked as dirty.

* Fix formatting
2020-09-10 22:34:16 +02:00
117 changed files with 1756 additions and 1358 deletions
+2 -1
View File
@@ -2,7 +2,8 @@ name: 'Build PRs'
on: on:
pull_request: pull_request:
branches: [ master ] branches:
- '*'
jobs: jobs:
build: build:
+211 -81
View File
@@ -47,84 +47,6 @@ repositories {
} }
} }
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
compileJava {
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
options.deprecation = false
}
// ensure everything uses UTF-8 and not some random codepage chosen by gradle
compileJava.options.encoding = 'UTF-8'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
// Create version number
ext.pr = System.getenv('PR_NUMBER') ?: ""
if (ext.pr) {
version = version + "+pr." + ext.pr
}
ext.branch = System.getenv('BRANCH') ?: ""
if (ext.branch) {
version = version + "+branch." + ext.branch
}
ext.tag = System.getenv('TAG') ?: ""
if (ext.tag && ext.tag.startsWith("fabric/v")) {
version = ext.tag.substring("fabric/v".length())
// Validate that the rest is a semver version
if (version ==~ /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/) {
println("::set-env name=VERSION::${version}")
} else {
throw new GradleException("Invalid semver: $version")
}
}
// Maven group and artifact name
group = artifact_group
archivesBaseName = artifact_basename
sourceSets {
api
main {
compileClasspath += sourceSets.api.output
runtimeClasspath += sourceSets.api.output
resources {
srcDir 'src/generated/resources'
}
}
datagen {
compileClasspath += sourceSets.api.output
runtimeClasspath += sourceSets.api.output
compileClasspath += sourceSets.main.output
runtimeClasspath += sourceSets.main.output
}
test {
compileClasspath += sourceSets.api.output
runtimeClasspath += sourceSets.api.output
}
siteexport {
compileClasspath += sourceSets.api.output
runtimeClasspath += sourceSets.api.output
compileClasspath += sourceSets.main.output
runtimeClasspath += sourceSets.main.output
}
}
configurations {
apiCompile.extendsFrom(compileClasspath)
datagenCompile.extendsFrom(compileClasspath)
siteexportCompile.extendsFrom(compileClasspath)
siteexportRuntime.extendsFrom(runtimeClasspath)
}
apply from: 'gradle/scripts/spotless.gradle'
minecraft {
accessWidener "src/main/resources/appliedenergistics2.accesswidener"
}
dependencies { dependencies {
minecraft "com.mojang:minecraft:${project.minecraft_version}" minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
@@ -163,6 +85,87 @@ dependencies {
// unit test dependencies // unit test dependencies
testCompile "junit:junit:4.13" testCompile "junit:junit:4.13"
} }
group = artifact_group
archivesBaseName = artifact_basename
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
compileJava {
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
options.deprecation = false
}
// ensure everything uses UTF-8 and not some random codepage chosen by gradle
compileJava.options.encoding = 'UTF-8'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
///////////////////
// Version Number
ext.pr = System.getenv('PR_NUMBER') ?: ""
if (ext.pr) {
version = version + "+pr." + ext.pr
}
ext.branch = System.getenv('BRANCH') ?: ""
if (ext.branch) {
version = version + "+branch." + ext.branch
}
ext.tag = System.getenv('TAG') ?: ""
if (ext.tag && ext.tag.startsWith("fabric/v")) {
version = ext.tag.substring("fabric/v".length())
// Validate that the rest is a semver version
if (version ==~ /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/) {
println("::set-env name=VERSION::${version}")
} else {
throw new GradleException("Invalid semver: $version")
}
}
ext.isAlpha = project.version.contains("alpha")
ext.isBeta = project.version.contains("beta")
sourceSets {
api
main {
compileClasspath += sourceSets.api.output
runtimeClasspath += sourceSets.api.output
resources {
srcDir 'src/generated/resources'
}
}
datagen {
compileClasspath += sourceSets.api.output
runtimeClasspath += sourceSets.api.output
compileClasspath += sourceSets.main.output
runtimeClasspath += sourceSets.main.output
}
test {
compileClasspath += sourceSets.api.output
runtimeClasspath += sourceSets.api.output
}
siteexport {
compileClasspath += sourceSets.api.output
runtimeClasspath += sourceSets.api.output
compileClasspath += sourceSets.main.output
runtimeClasspath += sourceSets.main.output
}
}
configurations {
apiCompile.extendsFrom(compileClasspath)
datagenCompile.extendsFrom(compileClasspath)
siteexportCompile.extendsFrom(compileClasspath)
siteexportRuntime.extendsFrom(runtimeClasspath)
}
////////////////////
// Forge/Minecraft
minecraft {
accessWidener "src/main/resources/appliedenergistics2.accesswidener"
}
processResources { processResources {
inputs.property "version", project.version inputs.property "version", project.version
@@ -177,10 +180,76 @@ processResources {
} }
} }
apply from: 'gradle/scripts/artifacts.gradle' //////////////
apply from: 'gradle/scripts/curseforge.gradle' // Aritfacts
processResources {
exclude '.cache'
}
// configure the maven publication 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"),
"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
}
// 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/**"
// 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 +308,64 @@ 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") && !version.endsWith("-SNAPSHOT")) {
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
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
}
}
}
////////////////
// 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()
}
}
}
+5 -10
View File
@@ -3,24 +3,19 @@ version=0.0.0-SNAPSHOT
artifact_group=appeng artifact_group=appeng
artifact_basename=appliedenergistics2-fabric artifact_basename=appliedenergistics2-fabric
kotlin.code.style=official
org.gradle.jvmargs=-Xmx2G org.gradle.jvmargs=-Xmx2G
# Fabric Properties # Fabric Properties
# Check these on https://modmuss50.me/fabric.html # Check these on https://modmuss50.me/fabric.html
minecraft_version=1.16.2 minecraft_version=1.16.3
yarn_mappings=1.16.2+build.6 yarn_mappings=1.16.3+build.11
loader_version=0.9.2+build.206 loader_version=0.9.3+build.207
#Fabric api #Fabric api
fabric_version=0.20.1+build.401-1.16 fabric_version=0.21.0+build.407-1.16
loom_version=0.4-SNAPSHOT loom_version=0.5-SNAPSHOT
# Kotlin
kotlin_version=1.3.61
fabric_kotlin_version=1.3.61+build.1
# Dependencies # Dependencies
libblockattributes_version=0.8.0 libblockattributes_version=0.8.0
-78
View File
@@ -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
}
-50
View File
@@ -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
}
}
}
-42
View File
@@ -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"
}
-32
View File
@@ -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'])
}
}
-1
View File
@@ -10,7 +10,6 @@ pluginManagement {
plugins { plugins {
id "fabric-loom" version loom_version id "fabric-loom" version loom_version
id "org.jetbrains.kotlin.jvm" version kotlin_version
} }
} }
@@ -53,10 +53,10 @@ public interface ICraftingHelper {
* @param stack If null, a new item will be created to hold the encoded pattern. * @param stack If null, a new item will be created to hold the encoded pattern.
* Otherwise the given item must already contains an encoded * Otherwise the given item must already contains an encoded
* pattern that will be overwritten. * pattern that will be overwritten.
* @throws IllegalArgumentException If either in or out contain only empty
* ItemStacks.
* @return A new encoded pattern, or the given stack with the pattern encoded in * @return A new encoded pattern, or the given stack with the pattern encoded in
* it. * it.
* @throws IllegalArgumentException If either in or out contain only empty
* ItemStacks.
*/ */
ItemStack encodeProcessingPattern(@Nullable ItemStack stack, ItemStack[] in, ItemStack[] out); ItemStack encodeProcessingPattern(@Nullable ItemStack stack, ItemStack[] in, ItemStack[] out);
@@ -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);
@@ -86,7 +86,7 @@ public class CableBusBlock extends AEBaseTileBlock<CableBusBlockEntity> implemen
public CableBusBlock() { public CableBusBlock() {
super(defaultProps(AEMaterials.GLASS).nonOpaque().dropsNothing().dynamicBounds() super(defaultProps(AEMaterials.GLASS).nonOpaque().dropsNothing().dynamicBounds()
.lightLevel(state -> state.get(LIGHT_LEVEL))); .luminance(state -> state.get(LIGHT_LEVEL)));
setDefaultState(getDefaultState().with(LIGHT_LEVEL, 0)); setDefaultState(getDefaultState().with(LIGHT_LEVEL, 0));
} }
@@ -38,11 +38,11 @@ import appeng.helpers.Splotch;
*/ */
class PaintSplotchesBakedModel implements BakedModel, FabricBakedModel { class PaintSplotchesBakedModel implements BakedModel, FabricBakedModel {
private static final SpriteIdentifier TEXTURE_PAINT1 = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, private static final SpriteIdentifier TEXTURE_PAINT1 = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/paint1")); new Identifier(AppEng.MOD_ID, "block/paint1"));
private static final SpriteIdentifier TEXTURE_PAINT2 = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, private static final SpriteIdentifier TEXTURE_PAINT2 = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/paint2")); new Identifier(AppEng.MOD_ID, "block/paint2"));
private static final SpriteIdentifier TEXTURE_PAINT3 = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, private static final SpriteIdentifier TEXTURE_PAINT3 = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/paint3")); new Identifier(AppEng.MOD_ID, "block/paint3"));
private final Sprite[] textures; private final Sprite[] textures;
@@ -36,18 +36,18 @@ import appeng.core.AppEng;
class QnbFormedBakedModel implements BakedModel, FabricBakedModel { class QnbFormedBakedModel implements BakedModel, FabricBakedModel {
private static final SpriteIdentifier TEXTURE_LINK = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, private static final SpriteIdentifier TEXTURE_LINK = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/quantum_link")); new Identifier(AppEng.MOD_ID, "block/quantum_link"));
private static final SpriteIdentifier TEXTURE_RING = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, private static final SpriteIdentifier TEXTURE_RING = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/quantum_ring")); new Identifier(AppEng.MOD_ID, "block/quantum_ring"));
private static final SpriteIdentifier TEXTURE_RING_LIGHT = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, private static final SpriteIdentifier TEXTURE_RING_LIGHT = new SpriteIdentifier(
new Identifier(AppEng.MOD_ID, "block/quantum_ring_light")); SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new Identifier(AppEng.MOD_ID, "block/quantum_ring_light"));
private static final SpriteIdentifier TEXTURE_RING_LIGHT_CORNER = new SpriteIdentifier( private static final SpriteIdentifier TEXTURE_RING_LIGHT_CORNER = new SpriteIdentifier(
SpriteAtlasTexture.BLOCK_ATLAS_TEX, new Identifier(AppEng.MOD_ID, "block/quantum_ring_light_corner")); SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new Identifier(AppEng.MOD_ID, "block/quantum_ring_light_corner"));
private static final SpriteIdentifier TEXTURE_CABLE_GLASS = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, private static final SpriteIdentifier TEXTURE_CABLE_GLASS = new SpriteIdentifier(
new Identifier(AppEng.MOD_ID, "part/cable/glass/transparent")); SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new Identifier(AppEng.MOD_ID, "part/cable/glass/transparent"));
private static final SpriteIdentifier TEXTURE_COVERED_CABLE = new SpriteIdentifier( private static final SpriteIdentifier TEXTURE_COVERED_CABLE = new SpriteIdentifier(
SpriteAtlasTexture.BLOCK_ATLAS_TEX, new Identifier(AppEng.MOD_ID, "part/cable/covered/transparent")); SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new Identifier(AppEng.MOD_ID, "part/cable/covered/transparent"));
private static final float DEFAULT_RENDER_MIN = 2.0f; private static final float DEFAULT_RENDER_MIN = 2.0f;
private static final float DEFAULT_RENDER_MAX = 14.0f; private static final float DEFAULT_RENDER_MAX = 14.0f;
@@ -106,6 +106,7 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
private Stopwatch dbl_clickTimer = Stopwatch.createStarted(); private Stopwatch dbl_clickTimer = Stopwatch.createStarted();
private ItemStack dbl_whichItem = ItemStack.EMPTY; private ItemStack dbl_whichItem = ItemStack.EMPTY;
private Slot bl_clicked; private Slot bl_clicked;
private boolean handlingRightClick;
protected final List<CustomSlotWidget> guiSlots = new ArrayList<>(); protected final List<CustomSlotWidget> guiSlots = new ArrayList<>();
public AEBaseScreen(T container, PlayerInventory playerInventory, Text title) { public AEBaseScreen(T container, PlayerInventory playerInventory, Text title) {
@@ -284,12 +285,18 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
public boolean mouseClicked(final double xCoord, final double yCoord, final int btn) { public boolean mouseClicked(final double xCoord, final double yCoord, final int btn) {
this.drag_click.clear(); this.drag_click.clear();
// Forward right-clicks as-if they were left-clicks
if (btn == 1) { if (btn == 1) {
for (final Object o : this.buttons) { handlingRightClick = true;
final AbstractButtonWidget widget = (AbstractButtonWidget) o; try {
if (widget.isMouseOver(xCoord, yCoord)) { for (final Object o : this.buttons) {
return super.mouseClicked(xCoord, yCoord, 0); final AbstractButtonWidget widget = (AbstractButtonWidget) o;
if (widget.isMouseOver(xCoord, yCoord)) {
return super.mouseClicked(xCoord, yCoord, 0);
}
} }
} finally {
handlingRightClick = false;
} }
} }
@@ -300,22 +307,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.x, mouseY - this.y)) {
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()) {
@@ -622,15 +643,7 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
} }
protected Text getGuiDisplayName(final Text in) { protected Text getGuiDisplayName(final Text in) {
return this.hasCustomInventoryName() ? new LiteralText(this.getInventoryName()) : in; return title.getString().isEmpty() ? in : title;
}
private boolean hasCustomInventoryName() {
return this.handler.getCustomName() != null;
}
private String getInventoryName() {
return this.handler.getCustomName();
} }
/** /**
@@ -798,6 +811,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();
@@ -805,6 +823,14 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
} }
} }
/**
* Returns true while the current event being handled is a click of the right
* mouse button.
*/
public boolean isHandlingRightClick() {
return handlingRightClick;
}
public List<Rectangle> getExclusionZones() { public List<Rectangle> getExclusionZones() {
return Lists.newArrayList(new Rectangle(x, y, backgroundWidth, backgroundHeight)); return Lists.newArrayList(new Rectangle(x, y, backgroundWidth, backgroundHeight));
} }
@@ -46,22 +46,28 @@ public class CraftAmountScreen extends AEBaseScreen<CraftAmountContainer> {
public void init() { public void init() {
super.init(); super.init();
this.amountToCraft = new NumberEntryWidget(this, 20, 30, 138, 62, NumberEntryType.CRAFT_ITEM_COUNT, value -> { this.amountToCraft = new NumberEntryWidget(this, 20, 30, 138, 62, NumberEntryType.CRAFT_ITEM_COUNT);
});
this.amountToCraft.setValue(1); this.amountToCraft.setValue(1);
this.amountToCraft.setTextFieldBounds(62, 57, 50); this.amountToCraft.setTextFieldBounds(62, 57, 50);
this.amountToCraft.setMinValue(1); this.amountToCraft.setMinValue(1);
this.amountToCraft.setHideValidationIcon(true);
this.amountToCraft.addButtons(children::add, this::addButton); this.amountToCraft.addButtons(children::add, this::addButton);
this.next = this this.next = this
.addButton(new ButtonWidget(this.x + 128, this.y + 51, 38, 20, GuiText.Next.text(), this::confirm)); .addButton(new ButtonWidget(this.x + 128, this.y + 51, 38, 20, GuiText.Next.text(), this::confirm));
this.amountToCraft.setOnConfirm(() -> this.confirm(this.next));
subGui.addBackButton(this::addButton, 154, 0); subGui.addBackButton(this::addButton, 154, 0);
changeFocus(true);
} }
private void confirm(ButtonWidget button) { private void confirm(ButtonWidget button) {
NetworkHandler.instance() int amount = this.amountToCraft.getIntValue().orElse(0);
.sendToServer(new CraftRequestPacket((int) this.amountToCraft.getValue(), hasShiftDown())); if (amount <= 0) {
return;
}
NetworkHandler.instance().sendToServer(new CraftRequestPacket(amount, hasShiftDown()));
} }
@Override @Override
@@ -77,23 +83,9 @@ public class CraftAmountScreen extends AEBaseScreen<CraftAmountContainer> {
this.bindTexture("guis/craft_amt.png"); this.bindTexture("guis/craft_amt.png");
drawTexture(matrices, offsetX, offsetY, 0, 0, this.backgroundWidth, this.backgroundHeight); drawTexture(matrices, offsetX, offsetY, 0, 0, this.backgroundWidth, this.backgroundHeight);
this.next.active = this.amountToCraft.getValue() > 0; this.next.active = this.amountToCraft.getIntValue().orElse(0) > 0;
this.amountToCraft.render(matrices, offsetX, offsetY, partialTicks); this.amountToCraft.render(matrices, offsetX, offsetY, partialTicks);
} }
@Override
public boolean keyPressed(int keyCode, int scanCode, int p_keyPressed_3_) {
if (keyCode == 28) {
this.next.onPress();
return true;
} else {
return super.keyPressed(keyCode, scanCode, p_keyPressed_3_);
}
}
protected String getBackground() {
return "guis/craftAmt.png";
}
} }
@@ -25,6 +25,8 @@ import java.util.List;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import org.lwjgl.glfw.GLFW;
import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
@@ -73,10 +75,6 @@ public class CraftConfirmScreen extends AEBaseScreen<CraftConfirmContainer> {
this.setScrollBar(scrollbar); this.setScrollBar(scrollbar);
} }
boolean isAutoStart() {
return this.handler.isAutoStart();
}
@Override @Override
public void init() { public void init() {
super.init(); super.init();
@@ -87,12 +85,14 @@ public class CraftConfirmScreen extends AEBaseScreen<CraftConfirmContainer> {
this.addButton(this.start); this.addButton(this.start);
this.selectCPU = new ButtonWidget(this.x + (219 - 180) / 2, this.y + this.backgroundHeight - 68, 180, 20, this.selectCPU = new ButtonWidget(this.x + (219 - 180) / 2, this.y + this.backgroundHeight - 68, 180, 20,
GuiText.CraftingCPU.withSuffix(": ").append(GuiText.Automatic.text()), btn -> selectNextCpu()); getNextCpuButtonLabel(), btn -> selectNextCpu());
this.selectCPU.active = false; this.selectCPU.active = false;
this.addButton(this.selectCPU); this.addButton(this.selectCPU);
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
@@ -133,22 +133,22 @@ public class CraftConfirmScreen extends AEBaseScreen<CraftConfirmContainer> {
} }
private void updateCPUButtonText() { private void updateCPUButtonText() {
Text btnTextText = GuiText.CraftingCPU.withSuffix(": ").append(GuiText.Automatic.text()); this.selectCPU.setMessage(getNextCpuButtonLabel());
if (this.handler.getSelectedCpu() >= 0)// && status.selectedCpu < status.cpus.size() ) }
{
if (this.handler.getName() != null) {
final String name = this.handler.getName().asTruncatedString(20);
btnTextText = GuiText.CraftingCPU.withSuffix(": " + name);
} else {
btnTextText = GuiText.CraftingCPU.withSuffix(": #" + this.handler.getSelectedCpu());
}
}
private Text getNextCpuButtonLabel() {
if (this.handler.hasNoCPU()) { if (this.handler.hasNoCPU()) {
btnTextText = GuiText.NoCraftingCPUs.text(); return GuiText.NoCraftingCPUs.text();
} }
this.selectCPU.setMessage(btnTextText); Text cpuName;
if (this.handler.cpuName == null) {
cpuName = GuiText.Automatic.text();
} else {
cpuName = this.handler.cpuName;
}
return GuiText.CraftingCPU.withSuffix(": ").append(cpuName);
} }
private boolean isSimulation() { private boolean isSimulation() {
@@ -440,7 +440,7 @@ public class CraftConfirmScreen extends AEBaseScreen<CraftConfirmContainer> {
@Override @Override
public boolean keyPressed(int keyCode, int scanCode, int p_keyPressed_3_) { public boolean keyPressed(int keyCode, int scanCode, int p_keyPressed_3_) {
if (!this.checkHotbarKeys(keyCode, scanCode)) { if (!this.checkHotbarKeys(keyCode, scanCode)) {
if (keyCode == 28) { if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER) {
this.start(); this.start();
return true; return true;
} }
@@ -449,7 +449,7 @@ public class CraftConfirmScreen extends AEBaseScreen<CraftConfirmContainer> {
} }
private void selectNextCpu() { private void selectNextCpu() {
final boolean backwards = getClient().mouse.wasRightButtonClicked(); final boolean backwards = isHandlingRightClick();
NetworkHandler.instance().sendToServer(new ConfigValuePacket("Terminal.Cpu", backwards ? "Prev" : "Next")); NetworkHandler.instance().sendToServer(new ConfigValuePacket("Terminal.Cpu", backwards ? "Prev" : "Next"));
} }
@@ -44,12 +44,12 @@ public class CraftingStatusScreen extends CraftingCPUScreen<CraftingStatusContai
super.init(); super.init();
this.selectCPU = new ButtonWidget(this.x + 8, this.y + this.backgroundHeight - 25, 150, 20, this.selectCPU = new ButtonWidget(this.x + 8, this.y + this.backgroundHeight - 25, 150, 20,
GuiText.CraftingCPU.withSuffix(": ").append(GuiText.NoCraftingCPUs.text()), btn -> selectNextCpu()); getNextCpuButtonLabel(), btn -> selectNextCpu());
this.addButton(this.selectCPU); this.addButton(this.selectCPU);
subGui.addBackButton(btn -> { subGui.addBackButton(btn -> {
addButton(btn); addButton(btn);
btn.setHideEdge(13); btn.setHideEdge(true);
}, 213, -4); }, 213, -4);
} }
@@ -60,23 +60,14 @@ public class CraftingStatusScreen extends CraftingCPUScreen<CraftingStatusContai
} }
private void updateCPUButtonText() { private void updateCPUButtonText() {
Text btnTextText = GuiText.NoCraftingJobs.text(); this.selectCPU.setMessage(getNextCpuButtonLabel());
}
if (this.handler.selectedCpu >= 0)// && status.selectedCpu < status.cpus.size() )
{
if (this.handler.myName != null) {
final String name = this.handler.myName.asTruncatedString(20);
btnTextText = GuiText.CPUs.withSuffix(": " + name);
} else {
btnTextText = GuiText.CPUs.withSuffix(": #" + this.handler.selectedCpu);
}
}
private Text getNextCpuButtonLabel() {
if (this.handler.noCPU) { if (this.handler.noCPU) {
btnTextText = GuiText.NoCraftingJobs.text(); return GuiText.NoCraftingJobs.text();
} }
return GuiText.CraftingCPU.withSuffix(": ").append(handler.cpuName);
this.selectCPU.setMessage(btnTextText);
} }
@Override @Override
@@ -84,9 +75,8 @@ public class CraftingStatusScreen extends CraftingCPUScreen<CraftingStatusContai
return in; // the cup name is on the button return in; // the cup name is on the button
} }
// FIXME: Extract to separate class? Shared with GuiCraftConfirm
private void selectNextCpu() { private void selectNextCpu() {
final boolean backwards = client.mouse.wasRightButtonClicked(); final boolean backwards = isHandlingRightClick();
NetworkHandler.instance().sendToServer(new ConfigValuePacket("Terminal.Cpu", backwards ? "Prev" : "Next")); NetworkHandler.instance().sendToServer(new ConfigValuePacket("Terminal.Cpu", backwards ? "Prev" : "Next"));
} }
@@ -87,7 +87,7 @@ public class InterfaceScreen extends UpgradeableScreen<InterfaceContainer> {
} }
private void selectNextInterfaceMode() { private void selectNextInterfaceMode() {
final boolean backwards = getClient().mouse.wasRightButtonClicked(); final boolean backwards = isHandlingRightClick();
NetworkHandler.instance().sendToServer(new ConfigButtonPacket(Settings.INTERFACE_TERMINAL, backwards)); NetworkHandler.instance().sendToServer(new ConfigButtonPacket(Settings.INTERFACE_TERMINAL, backwards));
} }
@@ -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);
@@ -34,8 +34,6 @@ import appeng.client.gui.widgets.ServerSettingToggleButton;
import appeng.client.gui.widgets.SettingToggleButton; import appeng.client.gui.widgets.SettingToggleButton;
import appeng.container.implementations.LevelEmitterContainer; import appeng.container.implementations.LevelEmitterContainer;
import appeng.core.localization.GuiText; import appeng.core.localization.GuiText;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ConfigValuePacket;
public class LevelEmitterScreen extends UpgradeableScreen<LevelEmitterContainer> { public class LevelEmitterScreen extends UpgradeableScreen<LevelEmitterContainer> {
@@ -51,15 +49,18 @@ public class LevelEmitterScreen extends UpgradeableScreen<LevelEmitterContainer>
public void init() { public void init() {
super.init(); super.init();
this.level = new NumberEntryWidget(this, 20, 17, 138, 62, NumberEntryType.LEVEL_ITEM_COUNT, this.level = new NumberEntryWidget(this, 20, 17, 138, 62, NumberEntryType.LEVEL_ITEM_COUNT);
this::onLevelChange);
this.level.setTextFieldBounds(25, 44, 75); this.level.setTextFieldBounds(25, 44, 75);
this.level.addButtons(children::add, this::addButton); this.level.addButtons(children::add, this::addButton);
handler.setTextField(this.level); this.level.setValue(handler.getReportingValue());
this.level.setOnChange(this::saveReportingValue);
this.level.setOnConfirm(this::onClose);
this.changeFocus(true);
} }
private void onLevelChange(long level) { private void saveReportingValue() {
NetworkHandler.instance().sendToServer(new ConfigValuePacket("LevelEmitter.Value", String.valueOf(level))); this.level.getLongValue().ifPresent(handler::setReportingValue);
} }
@Override @Override
@@ -26,6 +26,7 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.Slot;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import me.shedaniel.math.Rectangle; import me.shedaniel.math.Rectangle;
@@ -51,6 +52,7 @@ import appeng.client.gui.widgets.SettingToggleButton;
import appeng.client.gui.widgets.TabButton; import appeng.client.gui.widgets.TabButton;
import appeng.client.me.InternalSlotME; import appeng.client.me.InternalSlotME;
import appeng.client.me.ItemRepo; import appeng.client.me.ItemRepo;
import appeng.client.render.StackSizeRenderer;
import appeng.container.implementations.CraftingStatusContainer; import appeng.container.implementations.CraftingStatusContainer;
import appeng.container.implementations.MEMonitorableContainer; import appeng.container.implementations.MEMonitorableContainer;
import appeng.container.slot.AppEngSlot; import appeng.container.slot.AppEngSlot;
@@ -237,7 +239,7 @@ public class MEMonitorableScreen<T extends MEMonitorableContainer> extends AEBas
if (this.viewCell || this instanceof WirelessTermScreen) { if (this.viewCell || this instanceof WirelessTermScreen) {
this.craftingStatusBtn = this.addButton(new TabButton(this.x + 170, this.y - 4, 2 + 11 * 16, this.craftingStatusBtn = this.addButton(new TabButton(this.x + 170, this.y - 4, 2 + 11 * 16,
GuiText.CraftingStatus.text(), this.itemRenderer, btn -> showCraftingStatus())); GuiText.CraftingStatus.text(), this.itemRenderer, btn -> showCraftingStatus()));
this.craftingStatusBtn.setHideEdge(13); this.craftingStatusBtn.setHideEdge(true);
} }
this.isAutoFocus = SearchBoxMode.AUTOSEARCH == searchMode || SearchBoxMode.JEI_AUTOSEARCH == searchMode this.isAutoFocus = SearchBoxMode.AUTOSEARCH == searchMode || SearchBoxMode.JEI_AUTOSEARCH == searchMode
@@ -283,6 +285,8 @@ public class MEMonitorableScreen<T extends MEMonitorableContainer> extends AEBas
craftingGridOffsetX -= 25; craftingGridOffsetX -= 25;
craftingGridOffsetY -= 6; craftingGridOffsetY -= 6;
this.setScrollBar();
} }
@Override @Override
@@ -292,6 +296,16 @@ public class MEMonitorableScreen<T extends MEMonitorableContainer> extends AEBas
this.currentMouseX = mouseX; this.currentMouseX = mouseX;
this.currentMouseY = mouseY; this.currentMouseY = mouseY;
// Show the number of active crafting jobs
if (this.craftingStatusBtn != null && handler.activeCraftingJobs != -1) {
// The stack size renderer expects a 16x16 slot, while the button is normally
// bigger
int x = this.craftingStatusBtn.x + (this.craftingStatusBtn.getWidth() - 16) / 2;
int y = this.craftingStatusBtn.y + (this.craftingStatusBtn.getHeight() - 16) / 2;
StackSizeRenderer.renderSizeLabel(textRenderer, x - this.x, y - this.y,
new LiteralText(String.valueOf(handler.activeCraftingJobs)));
}
} }
@Override @Override
@@ -356,6 +370,7 @@ public class MEMonitorableScreen<T extends MEMonitorableContainer> extends AEBas
if (this.searchField != null) { if (this.searchField != null) {
this.searchField.render(matrices, mouseX, mouseY, partialTicks); this.searchField.render(matrices, mouseX, mouseY, partialTicks);
} }
} }
protected String getBackground() { protected String getBackground() {
@@ -2,41 +2,58 @@ package appeng.client.gui.implementations;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.LongConsumer;
import net.minecraft.client.font.TextRenderer; import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.Element; import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import appeng.client.gui.AEBaseScreen; import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.NumberEntryType; import appeng.client.gui.NumberEntryType;
import appeng.client.gui.widgets.ITickingWidget; import appeng.client.gui.widgets.ConfirmableTextField;
import appeng.client.gui.widgets.NumberBox; import appeng.client.gui.widgets.ValidationIcon;
import appeng.core.AEConfig; import appeng.core.AEConfig;
/** /**
* A utility widget that consists of a text-field to enter a number with * A utility widget that consists of a text-field to enter a number with
* attached buttons to increment/decrement the number in fixed intervals. * attached buttons to increment/decrement the number in fixed intervals.
*/ */
public class NumberEntryWidget implements ITickingWidget { public class NumberEntryWidget extends DrawableHelper {
private static final Text INVALID_NUMBER = new TranslatableText("gui.appliedenergistics2.validation.InvalidNumber");
private static final String NUMBER_LESS_THAN_MIN_VALUE = "gui.appliedenergistics2.validation.NumberLessThanMinValue";
private static final Text PLUS = Text.of("+"); private static final Text PLUS = Text.of("+");
private static final Text MINUS = Text.of("-"); private static final Text MINUS = Text.of("-");
private static final int TEXT_COLOR_ERROR = 0xFF1900;
private static final int TEXT_COLOR_NORMAL = 0xFFFFFF;
private final AEBaseScreen<?> parent; private final AEBaseScreen<?> parent;
private final int x; private final int x;
private final int y; private final int y;
private final NumberBox level; private final ConfirmableTextField textField;
private final NumberEntryType type; private final NumberEntryType type;
private List<ButtonWidget> buttons; private List<ButtonWidget> buttons;
private long minValue;
private ValidationIcon validationIcon;
public NumberEntryWidget(AEBaseScreen<?> parent, int x, int y, int width, int height, NumberEntryType type, // Called when the value changes
LongConsumer changeListener) { private Runnable onChange;
// Called when the user presses enter while there's a valid number in the field
private Runnable onConfirm;
private boolean hideValidationIcon;
public NumberEntryWidget(AEBaseScreen<?> parent, int x, int y, int width, int height, NumberEntryType type) {
this.parent = parent; this.parent = parent;
this.x = x; this.x = x;
this.y = y; this.y = y;
@@ -45,27 +62,50 @@ public class NumberEntryWidget implements ITickingWidget {
TextRenderer font = parent.getClient().textRenderer; TextRenderer font = parent.getClient().textRenderer;
int inputX = parent.getX() + x; int inputX = parent.getX() + x;
int inputY = parent.getY() + y; int inputY = parent.getY() + y;
this.level = new NumberBox(font, inputX, inputY, width, font.fontHeight, type.getInputType(), changeListener); this.textField = new ConfirmableTextField(font, inputX, inputY, width, font.fontHeight, LiteralText.EMPTY);
this.level.setHasBorder(false); this.textField.setHasBorder(false);
this.level.setMaxLength(16); this.textField.setMaxLength(16);
this.level.setEditableColor(0xFFFFFF); this.textField.setEditableColor(TEXT_COLOR_NORMAL);
this.level.setVisible(true); this.textField.setVisible(true);
parent.setInitialFocus(this.level); this.textField.setSelected(true);
parent.setInitialFocus(this.textField);
this.textField.setChangedListener(text -> {
validate();
if (onChange != null) {
this.onChange.run();
}
});
this.textField.setOnConfirm(() -> {
// Only confirm if it's actually valid
if (this.onConfirm != null && getLongValue().isPresent()) {
this.onConfirm.run();
}
});
validate();
}
public void setOnConfirm(Runnable callback) {
this.onConfirm = callback;
}
public void setOnChange(Runnable callback) {
this.onChange = callback;
} }
public void setActive(boolean active) { public void setActive(boolean active) {
this.level.active = active; this.textField.active = active;
this.buttons.forEach(b -> b.active = active); this.buttons.forEach(b -> b.active = active);
} }
public void setTextFieldBounds(int x, int y, int width) { public void setTextFieldBounds(int x, int y, int width) {
this.level.x = parent.getX() + x; this.textField.x = parent.getX() + x;
this.level.y = parent.getY() + y; this.textField.y = parent.getY() + y;
this.level.setWidth(width); this.textField.setWidth(width);
} }
public void setMinValue(long minValue) { public void setMinValue(long minValue) {
this.level.setMinValue(minValue); this.minValue = minValue;
validate();
} }
public void addButtons(Consumer<Element> addChildren, Consumer<ButtonWidget> addButton) { public void addButtons(Consumer<Element> addChildren, Consumer<ButtonWidget> addButton) {
@@ -78,54 +118,116 @@ public class NumberEntryWidget implements ITickingWidget {
int left = parent.getX() + x; int left = parent.getX() + x;
int top = parent.getY() + y; int top = parent.getY() + y;
List<ButtonWidget> buttons = new ArrayList<>(8); List<ButtonWidget> buttons = new ArrayList<>(9);
buttons.add(new ButtonWidget(left, top, 22, 20, makeLabel(PLUS, a), btn -> addQty(a))); buttons.add(new ButtonWidget(left, top, 22, 20, makeLabel(PLUS, a), btn -> addQty(a)));
buttons.add(new ButtonWidget(left + 28, top, 28, 20, makeLabel(PLUS, b), btn -> addQty(b))); buttons.add(new ButtonWidget(left + 28, top, 28, 20, makeLabel(PLUS, b), btn -> addQty(b)));
buttons.add(new ButtonWidget(left + 62, top, 32, 20, makeLabel(PLUS, c), btn -> addQty(c))); buttons.add(new ButtonWidget(left + 62, top, 32, 20, makeLabel(PLUS, c), btn -> addQty(c)));
buttons.add(new ButtonWidget(left + 100, top, 38, 20, makeLabel(PLUS, d), btn -> addQty(d))); buttons.add(new ButtonWidget(left + 100, top, 38, 20, makeLabel(PLUS, d), btn -> addQty(d)));
// Need to add these now for sensible tab-order
buttons.forEach(addButton);
// Placing this here will give a sensible tab order // Placing this here will give a sensible tab order
addChildren.accept(this.level); addChildren.accept(this.textField);
buttons.add(new ButtonWidget(left, top + 42, 22, 20, makeLabel(MINUS, a), btn -> addQty(-a))); buttons.add(new ButtonWidget(left, top + 42, 22, 20, makeLabel(MINUS, a), btn -> addQty(-a)));
buttons.add(new ButtonWidget(left + 28, top + 42, 28, 20, makeLabel(MINUS, b), btn -> addQty(-b))); buttons.add(new ButtonWidget(left + 28, top + 42, 28, 20, makeLabel(MINUS, b), btn -> addQty(-b)));
buttons.add(new ButtonWidget(left + 62, top + 42, 32, 20, makeLabel(MINUS, c), btn -> addQty(-c))); buttons.add(new ButtonWidget(left + 62, top + 42, 32, 20, makeLabel(MINUS, c), btn -> addQty(-c)));
buttons.add(new ButtonWidget(left + 100, top + 42, 38, 20, makeLabel(MINUS, d), btn -> addQty(-d))); buttons.add(new ButtonWidget(left + 100, top + 42, 38, 20, makeLabel(MINUS, d), btn -> addQty(-d)));
// This element is not focusable
if (!hideValidationIcon) {
this.validationIcon = new ValidationIcon(left + 104, top + 27);
buttons.add(this.validationIcon);
}
// Add the rest to the tab order
buttons.subList(4, buttons.size()).forEach(addButton);
this.buttons = buttons; this.buttons = buttons;
this.buttons.forEach(addButton);
// we need to re-validate because the icon may now be present and needs it's
// initial state
this.validate();
} }
private void addQty(final long i) { /**
long currentValue = this.level.getValue(); * Returns the integer value currently in the text-field, if it is a valid
long minValue = this.level.getMinValue(); * number and is within the allowed min/max value.
this.level.setText(String.valueOf(Math.max(minValue, currentValue + i))); */
public OptionalInt getIntValue() {
String text = textField.getText().trim();
try {
int value = Integer.parseInt(text, 10);
if (value < minValue) {
return OptionalInt.empty();
}
return OptionalInt.of(value);
} catch (NumberFormatException ignored) {
return OptionalInt.empty();
}
} }
public void render(MatrixStack matrices, int mouseX, int mouseY, float partialTicks) { /**
this.level.render(matrices, mouseX, mouseY, partialTicks); * Returns the long value currently in the text-field, if it is a valid number
} * and is within the allowed min/max value.
*/
public void setValue(long value, boolean skipNotify) { public OptionalLong getLongValue() {
this.level.setValue(value, skipNotify); String text = textField.getText().trim();
try {
long value = Long.parseLong(text, 10);
if (value < minValue) {
return OptionalLong.empty();
}
return OptionalLong.of(value);
} catch (NumberFormatException ignored) {
return OptionalLong.empty();
}
} }
public void setValue(long value) { public void setValue(long value) {
setValue(value, false); this.textField.setText(String.valueOf(Math.max(minValue, value)));
this.textField.setCursorToEnd();
this.textField.setSelectionStart(0);
validate();
} }
public long getValue() { private void addQty(final long i) {
return level.getValue(); getLongValue().ifPresent(currentValue -> setValue(currentValue + i));
} }
@Override public void render(MatrixStack matrices, int mouseX, int mouseY, float partialTicks) {
public void tick() { this.textField.render(matrices, mouseX, mouseY, partialTicks);
this.level.tick(); }
private void validate() {
List<Text> validationErrors = new ArrayList<>();
String text = textField.getText().trim();
try {
long value = Long.parseLong(text, 10);
if (value < minValue) {
validationErrors.add(new TranslatableText(NUMBER_LESS_THAN_MIN_VALUE, minValue));
}
} catch (NumberFormatException ignored) {
validationErrors.add(INVALID_NUMBER);
}
boolean valid = validationErrors.isEmpty();
this.textField.setEditableColor(valid ? TEXT_COLOR_NORMAL : TEXT_COLOR_ERROR);
if (this.validationIcon != null) {
this.validationIcon.setValid(valid);
this.validationIcon.setTooltip(validationErrors);
}
} }
private Text makeLabel(Text prefix, int amount) { private Text makeLabel(Text prefix, int amount) {
return prefix.copy().append(String.valueOf(amount)); return prefix.copy().append(String.valueOf(amount));
} }
public void setHideValidationIcon(boolean hideValidationIcon) {
this.hideValidationIcon = hideValidationIcon;
}
} }
@@ -18,6 +18,8 @@
package appeng.client.gui.implementations; package appeng.client.gui.implementations;
import java.util.OptionalInt;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text; import net.minecraft.text.Text;
@@ -26,8 +28,6 @@ import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.NumberEntryType; import appeng.client.gui.NumberEntryType;
import appeng.container.implementations.PriorityContainer; import appeng.container.implementations.PriorityContainer;
import appeng.core.localization.GuiText; import appeng.core.localization.GuiText;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ConfigValuePacket;
public class PriorityScreen extends AEBaseScreen<PriorityContainer> { public class PriorityScreen extends AEBaseScreen<PriorityContainer> {
@@ -38,24 +38,38 @@ public class PriorityScreen extends AEBaseScreen<PriorityContainer> {
public PriorityScreen(PriorityContainer container, PlayerInventory playerInventory, Text title) { public PriorityScreen(PriorityContainer container, PlayerInventory playerInventory, Text title) {
super(container, playerInventory, title); super(container, playerInventory, title);
this.subGui = new AESubScreen(this, container.getPriorityHost()); this.subGui = new AESubScreen(this, container.getPriorityHost());
// This is the effective size of the background image
backgroundWidth = 175;
backgroundHeight = 128;
} }
@Override @Override
public void init() { public void init() {
super.init(); super.init();
this.priority = new NumberEntryWidget(this, 20, 30, 138, 62, NumberEntryType.PRIORITY, this::onPriorityChange); this.priority = new NumberEntryWidget(this, 20, 30, 138, 62, NumberEntryType.PRIORITY);
this.priority.setTextFieldBounds(62, 57, 50); this.priority.setTextFieldBounds(62, 57, 50);
this.priority.setMinValue(Integer.MIN_VALUE); this.priority.setMinValue(Integer.MIN_VALUE);
handler.setTextField(this.priority); this.priority.setValue(this.handler.getPriorityValue());
this.priority.addButtons(children::add, this::addButton); this.priority.addButtons(children::add, this::addButton);
this.subGui.addBackButton(this::addButton, 154, 0); this.subGui.addBackButton(this::addButton, 154, 0);
this.priority.setOnChange(this::savePriority);
this.priority.setOnConfirm(() -> {
savePriority();
this.subGui.goBack();
});
changeFocus(true);
} }
private void onPriorityChange(long priority) { private void savePriority() {
NetworkHandler.instance() OptionalInt priority = this.priority.getIntValue();
.sendToServer(new ConfigValuePacket("PriorityHost.Priority", String.valueOf(priority))); if (priority.isPresent()) {
handler.setPriority(priority.getAsInt());
}
} }
@Override @Override
@@ -66,13 +80,10 @@ public class PriorityScreen extends AEBaseScreen<PriorityContainer> {
@Override @Override
public void drawBG(MatrixStack matrices, final int offsetX, final int offsetY, final int mouseX, final int mouseY, public void drawBG(MatrixStack matrices, final int offsetX, final int offsetY, final int mouseX, final int mouseY,
float partialTicks) { float partialTicks) {
this.bindTexture(getBackground()); this.bindTexture("guis/priority.png");
drawTexture(matrices, offsetX, offsetY, 0, 0, this.backgroundWidth, this.backgroundHeight); drawTexture(matrices, offsetX, offsetY, 0, 0, this.backgroundWidth, this.backgroundHeight);
this.priority.render(matrices, mouseX, mouseY, partialTicks); this.priority.render(matrices, mouseX, mouseY, partialTicks);
} }
protected String getBackground() {
return "guis/priority.png";
}
} }
@@ -0,0 +1,51 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, 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 org.lwjgl.glfw.GLFW;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.text.Text;
public class ConfirmableTextField extends TextFieldWidget {
private Runnable onConfirm;
public ConfirmableTextField(TextRenderer fontRenderer, int x, int y, int width, int height, Text text) {
super(fontRenderer, x, y, width, height, text);
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
if (isActive() && (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER)) {
if (this.onConfirm != null) {
this.onConfirm.run();
}
return true;
}
return super.keyPressed(keyCode, scanCode, modifiers);
}
public void setOnConfirm(Runnable onConfirm) {
this.onConfirm = onConfirm;
}
}
@@ -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();
}
}
@@ -22,6 +22,7 @@ import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.sound.SoundManager;
import net.minecraft.client.texture.TextureManager; import net.minecraft.client.texture.TextureManager;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
@@ -33,6 +34,10 @@ public abstract class IconButton extends ButtonWidget implements ITooltip {
private boolean halfSize = false; private boolean halfSize = false;
private boolean disableClickSound = false;
private boolean disableBackground = false;
public IconButton(final int x, final int y, PressAction onPress) { public IconButton(final int x, final int y, PressAction onPress) {
super(x, y, 16, 16, LiteralText.EMPTY, onPress); super(x, y, 16, 16, LiteralText.EMPTY, onPress);
} }
@@ -42,6 +47,13 @@ public abstract class IconButton extends ButtonWidget implements ITooltip {
this.active = vis; this.active = vis;
} }
@Override
public void playDownSound(SoundManager soundManager) {
if (!disableClickSound) {
super.playDownSound(soundManager);
}
}
@Override @Override
public void renderButton(MatrixStack matrices, final int mouseX, final int mouseY, float partial) { public void renderButton(MatrixStack matrices, final int mouseX, final int mouseY, float partial) {
@@ -72,7 +84,9 @@ public abstract class IconButton extends ButtonWidget implements ITooltip {
final int uv_y = iconIndex / 16; final int uv_y = iconIndex / 16;
final int uv_x = iconIndex - uv_y * 16; final int uv_x = iconIndex - uv_y * 16;
drawTexture(matrices, 0, 0, 256 - 16, 256 - 16, 16, 16); if (!disableBackground) {
drawTexture(matrices, 0, 0, 256 - 16, 256 - 16, 16, 16);
}
drawTexture(matrices, 0, 0, uv_x * 16, uv_y * 16, 16, 16); drawTexture(matrices, 0, 0, uv_x * 16, uv_y * 16, 16, 16);
RenderSystem.popMatrix(); RenderSystem.popMatrix();
} else { } else {
@@ -85,12 +99,18 @@ public abstract class IconButton extends ButtonWidget implements ITooltip {
final int uv_y = iconIndex / 16; final int uv_y = iconIndex / 16;
final int uv_x = iconIndex - uv_y * 16; final int uv_x = iconIndex - uv_y * 16;
drawTexture(matrices, this.x, this.y, 256 - 16, 256 - 16, 16, 16); if (!disableBackground) {
drawTexture(matrices, this.x, this.y, 256 - 16, 256 - 16, 16, 16);
}
drawTexture(matrices, this.x, this.y, uv_x * 16, uv_y * 16, 16, 16); drawTexture(matrices, this.x, this.y, uv_x * 16, uv_y * 16, 16, 16);
} }
RenderSystem.enableDepthTest(); RenderSystem.enableDepthTest();
RenderSystem.color4f(1.0f, 1.0f, 1.0f, 1.0f);
if (isHovered()) {
renderToolTip(matrices, mouseX, mouseY);
}
} }
RenderSystem.color4f(1.0f, 1.0f, 1.0f, 1.0f);
} }
protected abstract int getIconIndex(); protected abstract int getIconIndex();
@@ -133,4 +153,20 @@ public abstract class IconButton extends ButtonWidget implements ITooltip {
this.halfSize = halfSize; this.halfSize = halfSize;
} }
public boolean isDisableClickSound() {
return disableClickSound;
}
public void setDisableClickSound(boolean disableClickSound) {
this.disableClickSound = disableClickSound;
}
public boolean isDisableBackground() {
return disableBackground;
}
public void setDisableBackground(boolean disableBackground) {
this.disableBackground = disableBackground;
}
} }
@@ -1,153 +0,0 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, 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.util.function.LongConsumer;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.text.LiteralText;
public class NumberBox extends TextFieldWidget {
private final LongConsumer changeListener;
private long lastValue;
private long minValue = 0;
private long maxValue;
public NumberBox(final TextRenderer fontRenderer, final int x, final int y, final int width, final int height,
final Class<?> type, LongConsumer changeListener) {
super(fontRenderer, x, y, width, height, new LiteralText("0"));
this.setText("0");
setChangedListener(this::handleTextChanged);
this.lastValue = 0;
this.changeListener = changeListener;
if (type == int.class || type == Integer.class) {
maxValue = Integer.MAX_VALUE;
} else {
maxValue = Long.MAX_VALUE;
}
}
// NOTE: This method MUST NOT BE NAMED like a method in the superclass because
// of a ForgeGradle remapping bug
// since it'll not remap this method's name, but it will remap the name of the
// method reference above.
private void handleTextChanged(String text) {
if (text.isEmpty()) {
setText("0"); // Will call onTextChanged recursively
return;
}
boolean canBeNegative = canBeNegative();
if (canBeNegative && text.equals("-")) {
// Allow this as a special case to make typing in a negative number easier
return;
}
StringBuilder sanitized = new StringBuilder(text);
boolean encounteredNonZero = false;
for (int i = 0; i < sanitized.length(); i++) {
char ch = sanitized.charAt(i);
if (canBeNegative && i == 0 && ch == '-') {
continue; // Allow leading minus sign
}
if (ch >= '1' && ch <= '9') {
encounteredNonZero = true;
continue;
}
if (ch != '0' || !encounteredNonZero) {
sanitized.deleteCharAt(i--);
}
}
if (sanitized.length() == 0) {
sanitized.append('0');
}
String sanitizedStr = sanitized.toString();
if (!sanitizedStr.equals(text)) {
setText(sanitizedStr); // Will call onTextChanged recursively
return;
}
if (getValue() < minValue) {
setText(String.valueOf(minValue)); // Will call onTextChanged recursively
return;
}
if (getValue() > maxValue) {
setText(String.valueOf(maxValue)); // Will call onTextChanged recursively
return;
}
reportChange();
}
private void reportChange() {
long value = getValue();
if (value != lastValue) {
lastValue = value;
changeListener.accept(value);
}
}
public void setValue(long value, boolean skipNotify) {
// This check avoid changing the cursor position needlessly
if (value == this.getValue()) {
return;
}
if (skipNotify) {
lastValue = value;
}
setText(String.valueOf(value));
}
public long getValue() {
if (getText().equals("-") && canBeNegative()) {
return lastValue; // Allow this as a special case to type in a negative number more easily
}
return Long.parseLong(getText());
}
@Override
public boolean keyPressed(int p_keyPressed_1_, int p_keyPressed_2_, int p_keyPressed_3_) {
if (super.keyPressed(p_keyPressed_1_, p_keyPressed_2_, p_keyPressed_3_)) {
return true;
}
// Swallow key presses for numbers because they would otherwise trigger the
// hotbar swapping unintentionally
return isFocused() && p_keyPressed_1_ >= '0' && p_keyPressed_1_ <= '9';
}
public void setMinValue(long minValue) {
this.minValue = minValue;
}
public long getMinValue() {
return minValue;
}
private boolean canBeNegative() {
return minValue < 0;
}
}
@@ -18,18 +18,74 @@
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.Rect2i;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier;
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 Identifier TEXTURE = new Identifier("minecraft",
"textures/gui/container/creative_inventory/tabs.png");
/**
* Rectangle in the source texture that contains the sprite for an enabled
* handle.
*/
private static final Rect2i ENABLED = new Rect2i(232, 0, HANDLE_WIDTH, HANDLE_HEIGHT);
/**
* Rectangle in the source texture that contains the sprite for a disabled
* handle.
*/
private static final Rect2i DISABLED = new Rect2i(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 +93,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"); setZOffset(g.getZOffset());
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;
Rect2i 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;
} }
drawTexture(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 +208,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();
}
} }
@@ -25,6 +25,7 @@ import java.util.function.Predicate;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
@@ -47,6 +48,7 @@ import appeng.api.config.StorageFilter;
import appeng.api.config.TerminalStyle; import appeng.api.config.TerminalStyle;
import appeng.api.config.ViewItems; import appeng.api.config.ViewItems;
import appeng.api.config.YesNo; import appeng.api.config.YesNo;
import appeng.client.gui.AEBaseScreen;
import appeng.core.localization.ButtonToolTips; import appeng.core.localization.ButtonToolTips;
import appeng.util.EnumCycler; import appeng.util.EnumCycler;
@@ -89,9 +91,11 @@ public class SettingToggleButton<T extends Enum<T>> extends IconButton {
registerApp(16 * 7, Settings.CONDENSER_OUTPUT, CondenserOutput.TRASH, ButtonToolTips.CondenserOutput, registerApp(16 * 7, Settings.CONDENSER_OUTPUT, CondenserOutput.TRASH, ButtonToolTips.CondenserOutput,
ButtonToolTips.Trash); ButtonToolTips.Trash);
registerApp(16 * 7 + 1, Settings.CONDENSER_OUTPUT, CondenserOutput.MATTER_BALLS, registerApp(16 * 7 + 1, Settings.CONDENSER_OUTPUT, CondenserOutput.MATTER_BALLS,
ButtonToolTips.CondenserOutput, ButtonToolTips.MatterBalls); ButtonToolTips.CondenserOutput,
ButtonToolTips.MatterBalls.text(CondenserOutput.MATTER_BALLS.requiredPower));
registerApp(16 * 7 + 2, Settings.CONDENSER_OUTPUT, CondenserOutput.SINGULARITY, registerApp(16 * 7 + 2, Settings.CONDENSER_OUTPUT, CondenserOutput.SINGULARITY,
ButtonToolTips.CondenserOutput, ButtonToolTips.Singularity); ButtonToolTips.CondenserOutput,
ButtonToolTips.Singularity.text(CondenserOutput.SINGULARITY.requiredPower));
registerApp(16 * 9 + 1, Settings.ACCESS, AccessRestriction.READ, ButtonToolTips.IOMode, registerApp(16 * 9 + 1, Settings.ACCESS, AccessRestriction.READ, ButtonToolTips.IOMode,
ButtonToolTips.Read); ButtonToolTips.Read);
@@ -230,7 +234,13 @@ public class SettingToggleButton<T extends Enum<T>> extends IconButton {
} }
private void triggerPress() { private void triggerPress() {
boolean backwards = MinecraftClient.getInstance().mouse.wasRightButtonClicked(); boolean backwards = false;
// This isn't great, but we don't get any information about right-clicks
// otherwise
Screen currentScreen = MinecraftClient.getInstance().currentScreen;
if (currentScreen instanceof AEBaseScreen) {
backwards = ((AEBaseScreen<?>) currentScreen).isHandlingRightClick();
}
onPress.handle(this, backwards); onPress.handle(this, backwards);
} }
@@ -31,7 +31,7 @@ import net.minecraft.util.Identifier;
public class TabButton extends ButtonWidget implements ITooltip { public class TabButton extends ButtonWidget implements ITooltip {
public static final Identifier TEXTURE_STATES = new Identifier("appliedenergistics2", "textures/guis/states.png"); public static final Identifier TEXTURE_STATES = new Identifier("appliedenergistics2", "textures/guis/states.png");
private final ItemRenderer itemRenderer; private final ItemRenderer itemRenderer;
private int hideEdge = 0; private boolean hideEdge;
private int myIcon = -1; private int myIcon = -1;
private ItemStack myItem; private ItemStack myItem;
@@ -69,14 +69,17 @@ public class TabButton extends ButtonWidget implements ITooltip {
RenderSystem.enableAlphaTest(); RenderSystem.enableAlphaTest();
int uv_x = (this.hideEdge > 0 ? 11 : 13); // Selects the button border from the sprite-sheet, where each type occupies a
// 2x2 slot
int uv_x = 8 + (this.hideEdge ? 0 : 2);
int uv_y = 12 + (this.isFocused() ? 2 : 0);
final int offsetX = this.hideEdge > 0 ? 1 : 0; final int offsetX = this.hideEdge ? 1 : 0;
drawTexture(matrices, this.x, this.y, uv_x * 16, 0, 25, 22); drawTexture(matrices, this.x, this.y, uv_x * 16, uv_y * 16, 25, 22);
if (this.myIcon >= 0) { if (this.myIcon >= 0) {
final int uv_y = this.myIcon / 16; uv_y = this.myIcon / 16;
uv_x = this.myIcon - uv_y * 16; uv_x = this.myIcon - uv_y * 16;
drawTexture(matrices, offsetX + this.x + 3, this.y + 3, uv_x * 16, uv_y * 16, 16, 16); drawTexture(matrices, offsetX + this.x + 3, this.y + 3, uv_x * 16, uv_y * 16, 16, 16);
@@ -122,11 +125,11 @@ public class TabButton extends ButtonWidget implements ITooltip {
return this.visible; return this.visible;
} }
public int getHideEdge() { public boolean getHideEdge() {
return this.hideEdge; return this.hideEdge;
} }
public void setHideEdge(final int hideEdge) { public void setHideEdge(final boolean hideEdge) {
this.hideEdge = hideEdge; this.hideEdge = hideEdge;
} }
} }
@@ -0,0 +1,64 @@
package appeng.client.gui.widgets;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
/**
* Displays a small icon that shows validation errors for some input control.
*/
public class ValidationIcon extends IconButton {
private final List<Text> tooltip = new ArrayList<>();
private boolean valid;
public ValidationIcon(int x, int y) {
super(x, y, btn -> {
});
setDisableBackground(true);
setDisableClickSound(true);
setHalfSize(true);
}
public void setValid(boolean valid) {
setVisibility(!valid);
if (valid) {
this.tooltip.clear();
}
}
public void setTooltip(List<Text> lines) {
this.tooltip.clear();
this.tooltip.addAll(lines);
}
@Override
protected int getIconIndex() {
return 16 * 8;
}
@Override
public boolean changeFocus(boolean flag) {
return false; // Cannot focus this element
}
@Override
public void renderToolTip(MatrixStack matrices, int mouseX, int mouseY) {
if (this.tooltip.isEmpty()) {
return;
}
MinecraftClient client = MinecraftClient.getInstance();
Screen screen = client.currentScreen;
if (screen == null) {
return;
}
screen.renderTooltip(matrices, this.tooltip, x, y);
}
}
@@ -104,7 +104,7 @@ class CableBuilder {
throw new IllegalStateException("Cable type " + cableType + " does not support connections."); throw new IllegalStateException("Cable type " + cableType + " does not support connections.");
} }
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, textureFolder + color.name().toLowerCase(Locale.ROOT))); new Identifier(AppEng.MOD_ID, textureFolder + color.name().toLowerCase(Locale.ROOT)));
} }
@@ -74,7 +74,7 @@ public enum CableCoreType {
} }
public SpriteIdentifier getTexture(AEColor color) { public SpriteIdentifier getTexture(AEColor color) {
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, this.textureFolder + "/" + color.name().toLowerCase(Locale.ROOT))); new Identifier(AppEng.MOD_ID, this.textureFolder + "/" + color.name().toLowerCase(Locale.ROOT)));
} }
@@ -18,7 +18,7 @@ import appeng.core.AppEng;
public class P2PTunnelFrequencyModel implements BasicUnbakedModel { public class P2PTunnelFrequencyModel implements BasicUnbakedModel {
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "part/p2p_tunnel_frequency")); new Identifier(AppEng.MOD_ID, "part/p2p_tunnel_frequency"));
@Nullable @Nullable
@@ -47,7 +47,8 @@ public class SmartCableTextures {
new Identifier(AppEng.MOD_ID, "part/cable/smart/channels_12"), // new Identifier(AppEng.MOD_ID, "part/cable/smart/channels_12"), //
new Identifier(AppEng.MOD_ID, "part/cable/smart/channels_13"), // new Identifier(AppEng.MOD_ID, "part/cable/smart/channels_13"), //
new Identifier(AppEng.MOD_ID, "part/cable/smart/channels_14")// new Identifier(AppEng.MOD_ID, "part/cable/smart/channels_14")//
}).map(e -> new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, e)).toArray(SpriteIdentifier[]::new); }).map(e -> new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, e))
.toArray(SpriteIdentifier[]::new);
// Textures used to display channels on smart cables. There's two sets of 5 // Textures used to display channels on smart cables. There's two sets of 5
// textures each, and // textures each, and
@@ -115,7 +115,7 @@ public class CraftingCubeModel implements BasicUnbakedModel {
} }
private static SpriteIdentifier texture(String name) { private static SpriteIdentifier texture(String name) {
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/crafting/" + name)); new Identifier(AppEng.MOD_ID, "block/crafting/" + name));
} }
} }
@@ -25,7 +25,7 @@ import appeng.core.AppEng;
public class BiometricCardModel implements BasicUnbakedModel { public class BiometricCardModel implements BasicUnbakedModel {
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/biometric_card_base"); public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/biometric_card_base");
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "item/biometric_card_hash")); new Identifier(AppEng.MOD_ID, "item/biometric_card_hash"));
@Override @Override
@@ -26,11 +26,11 @@ public class ColorApplicatorModel implements BasicUnbakedModel {
private static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/color_applicator_colored"); private static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/color_applicator_colored");
private static final SpriteIdentifier TEXTURE_DARK = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, private static final SpriteIdentifier TEXTURE_DARK = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_dark")); new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_dark"));
private static final SpriteIdentifier TEXTURE_MEDIUM = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, private static final SpriteIdentifier TEXTURE_MEDIUM = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_medium")); new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_medium"));
private static final SpriteIdentifier TEXTURE_BRIGHT = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, private static final SpriteIdentifier TEXTURE_BRIGHT = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_bright")); new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_bright"));
@Override @Override
@@ -62,13 +62,13 @@ class GlassBakedModel implements BakedModel, FabricBakedModel {
private static final byte[][][] OFFSETS = generateOffsets(); private static final byte[][][] OFFSETS = generateOffsets();
// Alternating textures based on position // Alternating textures based on position
static final SpriteIdentifier TEXTURE_A = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, static final SpriteIdentifier TEXTURE_A = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier("appliedenergistics2:block/glass/quartz_glass_a")); new Identifier("appliedenergistics2:block/glass/quartz_glass_a"));
static final SpriteIdentifier TEXTURE_B = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, static final SpriteIdentifier TEXTURE_B = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier("appliedenergistics2:block/glass/quartz_glass_b")); new Identifier("appliedenergistics2:block/glass/quartz_glass_b"));
static final SpriteIdentifier TEXTURE_C = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, static final SpriteIdentifier TEXTURE_C = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier("appliedenergistics2:block/glass/quartz_glass_c")); new Identifier("appliedenergistics2:block/glass/quartz_glass_c"));
static final SpriteIdentifier TEXTURE_D = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, static final SpriteIdentifier TEXTURE_D = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier("appliedenergistics2:block/glass/quartz_glass_d")); new Identifier("appliedenergistics2:block/glass/quartz_glass_d"));
// Frame texture // Frame texture
@@ -81,7 +81,7 @@ class GlassBakedModel implements BakedModel, FabricBakedModel {
private static SpriteIdentifier[] generateTexturesFrame() { private static SpriteIdentifier[] generateTexturesFrame() {
return IntStream.range(1, 16).mapToObj(Integer::toBinaryString).map(s -> Strings.padStart(s, 4, '0')) return IntStream.range(1, 16).mapToObj(Integer::toBinaryString).map(s -> Strings.padStart(s, 4, '0'))
.map(s -> new Identifier("appliedenergistics2:block/glass/quartz_glass_frame" + s)) .map(s -> new Identifier("appliedenergistics2:block/glass/quartz_glass_frame" + s))
.map(rl -> new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, rl)) .map(rl -> new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, rl))
.toArray(SpriteIdentifier[]::new); .toArray(SpriteIdentifier[]::new);
} }
@@ -25,7 +25,7 @@ import appeng.core.AppEng;
public class MemoryCardModel implements BasicUnbakedModel { public class MemoryCardModel implements BasicUnbakedModel {
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/memory_card_base"); public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/memory_card_base");
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "item/memory_card_hash")); new Identifier(AppEng.MOD_ID, "item/memory_card_hash"));
@Override @Override
@@ -59,7 +59,7 @@ public class SpatialPylonModel implements BasicUnbakedModel {
} }
private static SpriteIdentifier getTexturePath(SpatialPylonTextureType type) { private static SpriteIdentifier getTexturePath(SpatialPylonTextureType type) {
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/spatial_pylon/" + type.name().toLowerCase(Locale.ROOT))); new Identifier(AppEng.MOD_ID, "block/spatial_pylon/" + type.name().toLowerCase(Locale.ROOT)));
} }
@@ -38,7 +38,7 @@ public final class InscriberTESR extends BlockEntityRenderer<InscriberBlockEntit
private static final float ITEM_RENDER_SCALE = 1.0f / 1.2f; private static final float ITEM_RENDER_SCALE = 1.0f / 1.2f;
private static final SpriteIdentifier TEXTURE_INSIDE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, private static final SpriteIdentifier TEXTURE_INSIDE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/inscriber_inside")); new Identifier(AppEng.MOD_ID, "block/inscriber_inside"));
public static final ImmutableList<SpriteIdentifier> SPRITES = ImmutableList.of(TEXTURE_INSIDE); public static final ImmutableList<SpriteIdentifier> SPRITES = ImmutableList.of(TEXTURE_INSIDE);
@@ -66,10 +66,8 @@ import appeng.container.slot.PlayerInvSlot;
import appeng.core.AELog; import appeng.core.AELog;
import appeng.core.Api; import appeng.core.Api;
import appeng.core.sync.network.NetworkHandler; import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ConfigValuePacket;
import appeng.core.sync.packets.InventoryActionPacket; import appeng.core.sync.packets.InventoryActionPacket;
import appeng.core.sync.packets.TargetItemStackPacket; import appeng.core.sync.packets.TargetItemStackPacket;
import appeng.helpers.ICustomNameObject;
import appeng.helpers.InventoryAction; import appeng.helpers.InventoryAction;
import appeng.me.helpers.PlayerSource; import appeng.me.helpers.PlayerSource;
import appeng.mixins.ScreenHandlerListeners; import appeng.mixins.ScreenHandlerListeners;
@@ -88,11 +86,9 @@ public abstract class AEBaseContainer extends ScreenHandler {
private final IGuiItemObject obj; private final IGuiItemObject obj;
private final HashMap<Integer, SyncData> syncData = new HashMap<>(); private final HashMap<Integer, SyncData> syncData = new HashMap<>();
private boolean isContainerValid = true; private boolean isContainerValid = true;
private String customName;
private ContainerLocator locator; private ContainerLocator locator;
private IMEInventoryHandler<IAEItemStack> cellInv; private IMEInventoryHandler<IAEItemStack> cellInv;
private IEnergySource powerSrc; private IEnergySource powerSrc;
private boolean sentCustomName;
private int ticksSinceCheck = 900; private int ticksSinceCheck = 900;
private IAEItemStack clientRequestedTargetItem = null; private IAEItemStack clientRequestedTargetItem = null;
@@ -317,9 +313,7 @@ public abstract class AEBaseContainer extends ScreenHandler {
@Override @Override
public void sendContentUpdates() { public void sendContentUpdates() {
this.sendCustomName(); if (isServer()) {
if (Platform.isServer()) {
if (this.tileEntity != null if (this.tileEntity != null
&& this.tileEntity.getWorld().getBlockEntity(this.tileEntity.getPos()) != this.tileEntity) { && this.tileEntity.getWorld().getBlockEntity(this.tileEntity.getPos()) != this.tileEntity) {
this.setValidContainer(false); this.setValidContainer(false);
@@ -886,43 +880,6 @@ public abstract class AEBaseContainer extends ScreenHandler {
this.sendContentUpdates(); this.sendContentUpdates();
} }
private void sendCustomName() {
// FIXME: Trash this, this is handled by NamedContainerProvider now
if (!this.sentCustomName) {
this.sentCustomName = true;
if (Platform.isServer()) {
ICustomNameObject name = null;
if (this.part instanceof ICustomNameObject) {
name = (ICustomNameObject) this.part;
}
if (this.tileEntity instanceof ICustomNameObject) {
name = (ICustomNameObject) this.tileEntity;
}
if (this.obj instanceof ICustomNameObject) {
name = (ICustomNameObject) this.obj;
}
if (this instanceof ICustomNameObject) {
name = (ICustomNameObject) this;
}
if (name != null) {
if (name.hasCustomInventoryName()) {
this.setCustomName(name.getCustomInventoryName().getString());
}
if (this.getCustomName() != null) {
NetworkHandler.instance().sendTo(new ConfigValuePacket("CustomName", this.getCustomName()),
(ServerPlayerEntity) this.getPlayerInventory().player);
}
}
}
}
}
public void swapSlotContents(final int slotA, final int slotB) { public void swapSlotContents(final int slotA, final int slotB) {
final Slot a = this.getSlot(slotA); final Slot a = this.getSlot(slotA);
final Slot b = this.getSlot(slotB); final Slot b = this.getSlot(slotB);
@@ -1012,14 +969,6 @@ public abstract class AEBaseContainer extends ScreenHandler {
this.cellInv = cellInv; this.cellInv = cellInv;
} }
public String getCustomName() {
return this.customName;
}
public void setCustomName(final String customName) {
this.customName = customName;
}
public PlayerInventory getPlayerInventory() { public PlayerInventory getPlayerInventory() {
return this.invPlayer; return this.invPlayer;
} }
@@ -1048,4 +997,18 @@ public abstract class AEBaseContainer extends ScreenHandler {
this.powerSrc = powerSrc; this.powerSrc = powerSrc;
} }
/**
* Returns whether this container instance lives on the client.
*/
protected boolean isClient() {
return invPlayer.player.getEntityWorld().isClient();
}
/**
* Returns whether this container instance lives on the server.
*/
protected boolean isServer() {
return !isClient();
}
} }
@@ -89,6 +89,8 @@ public class SyncData {
NetworkHandler.instance().sendTo(new ConfigValuePacket("SyncDat." + this.channel, json), NetworkHandler.instance().sendTo(new ConfigValuePacket("SyncDat." + this.channel, json),
(ServerPlayerEntity) o); (ServerPlayerEntity) o);
} }
this.clientVersion = val;
return;
} }
// Types other than Text must be non-null // Types other than Text must be non-null
@@ -50,7 +50,6 @@ import appeng.container.slot.RestrictedInputSlot;
import appeng.core.Api; import appeng.core.Api;
import appeng.tile.misc.CellWorkbenchBlockEntity; import appeng.tile.misc.CellWorkbenchBlockEntity;
import appeng.util.EnumCycler; import appeng.util.EnumCycler;
import appeng.util.Platform;
import appeng.util.helpers.ItemHandlerUtil; import appeng.util.helpers.ItemHandlerUtil;
import appeng.util.inv.WrapperSupplierItemHandler; import appeng.util.inv.WrapperSupplierItemHandler;
import appeng.util.iterators.NullIterator; import appeng.util.iterators.NullIterator;
@@ -143,7 +142,7 @@ public class CellWorkbenchContainer extends UpgradeableContainer {
@Override @Override
public void sendContentUpdates() { public void sendContentUpdates() {
final ItemStack is = this.workBench.getInventoryByName("cell").getInvStack(0); final ItemStack is = this.workBench.getInventoryByName("cell").getInvStack(0);
if (Platform.isServer()) { if (isServer()) {
for (final ScreenHandlerListener listener : this.getListeners()) { for (final ScreenHandlerListener listener : this.getListeners()) {
if (this.prevStack != is) { if (this.prevStack != is) {
// if the bars changed an item was probably made, so just send shit! // if the bars changed an item was probably made, so just send shit!
@@ -34,7 +34,6 @@ import appeng.container.interfaces.IProgressProvider;
import appeng.container.slot.OutputSlot; import appeng.container.slot.OutputSlot;
import appeng.container.slot.RestrictedInputSlot; import appeng.container.slot.RestrictedInputSlot;
import appeng.tile.misc.CondenserBlockEntity; import appeng.tile.misc.CondenserBlockEntity;
import appeng.util.Platform;
public class CondenserContainer extends AEBaseContainer implements IProgressProvider { public class CondenserContainer extends AEBaseContainer implements IProgressProvider {
@@ -76,13 +75,13 @@ public class CondenserContainer extends AEBaseContainer implements IProgressProv
@Override @Override
public void sendContentUpdates() { public void sendContentUpdates() {
if (Platform.isServer()) { if (isServer()) {
final double maxStorage = this.condenser.getStorage(); final double maxStorage = this.condenser.getStorage();
final double requiredEnergy = this.condenser.getRequiredPower(); final double requiredEnergy = this.condenser.getRequiredPower();
this.requiredEnergy = requiredEnergy == 0 ? (int) maxStorage : (int) Math.min(requiredEnergy, maxStorage); this.requiredEnergy = requiredEnergy == 0 ? (int) maxStorage : (int) Math.min(requiredEnergy, maxStorage);
this.storedPower = (int) this.condenser.getStoredPower(); this.storedPower = (int) this.condenser.getStoredPower();
this.setOutput((CondenserOutput) this.condenser.getConfigManager().getSetting(Settings.CONDENSER_OUTPUT)); this.output = (CondenserOutput) this.condenser.getConfigManager().getSetting(Settings.CONDENSER_OUTPUT);
} }
super.sendContentUpdates(); super.sendContentUpdates();
@@ -102,7 +101,4 @@ public class CondenserContainer extends AEBaseContainer implements IProgressProv
return this.output; return this.output;
} }
private void setOutput(final CondenserOutput output) {
this.output = output;
}
} }
@@ -1,5 +1,7 @@
package appeng.container.implementations; package appeng.container.implementations;
import java.util.function.Function;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
@@ -12,9 +14,7 @@ import net.minecraft.screen.ScreenHandler;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import appeng.api.config.SecurityPermissions; import appeng.api.config.SecurityPermissions;
import appeng.api.features.IWirelessTermHandler; import appeng.api.features.IWirelessTermHandler;
@@ -44,6 +44,8 @@ public final class ContainerHelper<C extends AEBaseContainer, I> {
private final SecurityPermissions requiredPermission; private final SecurityPermissions requiredPermission;
private Function<I, Text> containerTitleStrategy = this::getDefaultContainerTitle;
public ContainerHelper(ContainerFactory<C, I> factory, Class<I> interfaceClass) { public ContainerHelper(ContainerFactory<C, I> factory, Class<I> interfaceClass) {
this(factory, interfaceClass, null); this(factory, interfaceClass, null);
} }
@@ -55,19 +57,47 @@ public final class ContainerHelper<C extends AEBaseContainer, I> {
this.factory = factory; this.factory = factory;
} }
/**
* Specifies a custom strategy for obtaining a custom container name.
* <p>
* The stratgy should return {@link LiteralText#EMPTY} if there's no custom
* name.
*/
public ContainerHelper<C, I> withContainerTitle(Function<I, Text> containerTitleStrategy) {
this.containerTitleStrategy = containerTitleStrategy;
return this;
}
/** /**
* Opens a container that is based around a single block entity. The tile * Opens a container that is based around a single block entity. The tile
* entity's position is encoded in the packet buffer. * entity's position is encoded in the packet buffer.
*/ */
public C fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf packetBuf) { public C fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf packetBuf) {
return fromNetwork(windowId, inv, packetBuf, (accessObj, container, buffer) -> {
});
}
/**
* Same as {@link #open}, but allows or additional data to be read from the
* packet, and passed onto the container.
*/
public C fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf packetBuf,
InitialDataDeserializer<C, I> initialDataDeserializer) {
I host = getHostFromLocator(inv.player, ContainerLocator.read(packetBuf)); I host = getHostFromLocator(inv.player, ContainerLocator.read(packetBuf));
if (host != null) { if (host != null) {
return factory.create(windowId, inv, host); C container = factory.create(windowId, inv, host);
initialDataDeserializer.deserializeInitialData(host, container, packetBuf);
return container;
} }
return null; return null;
} }
public boolean open(PlayerEntity player, ContainerLocator locator) { public boolean open(PlayerEntity player, ContainerLocator locator) {
return open(player, locator, (accessObj, buffer) -> {
});
}
public boolean open(PlayerEntity player, ContainerLocator locator, InitialDataSerializer<I> initialDataSerializer) {
if (!(player instanceof ServerPlayerEntity)) { if (!(player instanceof ServerPlayerEntity)) {
// Cannot open containers on the client or for non-players // Cannot open containers on the client or for non-players
// FIXME logging? // FIXME logging?
@@ -84,9 +114,9 @@ public final class ContainerHelper<C extends AEBaseContainer, I> {
return false; return false;
} }
Text title = findContainerTitle(player.world, locator, accessInterface); Text title = containerTitleStrategy.apply(accessInterface);
player.openHandledScreen(new HandlerFactory(locator, title, accessInterface)); player.openHandledScreen(new HandlerFactory(locator, title, accessInterface, initialDataSerializer));
return true; return true;
} }
@@ -99,15 +129,20 @@ public final class ContainerHelper<C extends AEBaseContainer, I> {
private final Text title; private final Text title;
public HandlerFactory(ContainerLocator locator, Text title, I accessInterface) { private final InitialDataSerializer<I> initialDataSerializer;
public HandlerFactory(ContainerLocator locator, Text title, I accessInterface,
InitialDataSerializer<I> initialDataSerializer) {
this.locator = locator; this.locator = locator;
this.title = title; this.title = title;
this.accessInterface = accessInterface; this.accessInterface = accessInterface;
this.initialDataSerializer = initialDataSerializer;
} }
@Override @Override
public void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf buf) { public void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf buf) {
locator.write(buf); locator.write(buf);
initialDataSerializer.serializeInitialData(accessInterface, buf);
} }
@Override @Override
@@ -127,28 +162,6 @@ public final class ContainerHelper<C extends AEBaseContainer, I> {
} }
private Text findContainerTitle(World world, ContainerLocator locator, I accessInterface) {
if (accessInterface instanceof ICustomNameObject) {
ICustomNameObject customNameObject = (ICustomNameObject) accessInterface;
if (customNameObject.hasCustomInventoryName()) {
return customNameObject.getCustomInventoryName();
}
}
// Use block name at position
// FIXME: this is not right, we'd need to check the part's item stack, or custom
// naming interface impl
// FIXME: Should move this up, because at this point, it's hard to know where
// the terminal host came from (part or tile)
if (locator.hasBlockPos()) {
return new TranslatableText(world.getBlockState(locator.getBlockPos()).getBlock().getTranslationKey());
}
return new LiteralText("Unknown");
}
private I getHostFromLocator(PlayerEntity player, ContainerLocator locator) { private I getHostFromLocator(PlayerEntity player, ContainerLocator locator) {
if (locator.hasItemIndex()) { if (locator.hasItemIndex()) {
return getHostFromPlayerInventory(player, locator); return getHostFromPlayerInventory(player, locator);
@@ -225,6 +238,24 @@ public final class ContainerHelper<C extends AEBaseContainer, I> {
C create(int windowId, PlayerInventory playerInv, I accessObj); C create(int windowId, PlayerInventory playerInv, I accessObj);
} }
/**
* Strategy used to serialize initial data for opening the container on the
* client-side into the packet that is sent to the client.
*/
@FunctionalInterface
public interface InitialDataSerializer<I> {
void serializeInitialData(I host, PacketByteBuf buffer);
}
/**
* Strategy used to deserialize initial data for opening the container on the
* client-side from the packet received by the server.
*/
@FunctionalInterface
public interface InitialDataDeserializer<C, I> {
void deserializeInitialData(I host, C container, PacketByteBuf buffer);
}
private boolean checkPermission(PlayerEntity player, Object accessInterface) { private boolean checkPermission(PlayerEntity player, Object accessInterface) {
if (requiredPermission != null) { if (requiredPermission != null) {
@@ -235,4 +266,15 @@ public final class ContainerHelper<C extends AEBaseContainer, I> {
} }
private Text getDefaultContainerTitle(I accessInterface) {
if (accessInterface instanceof ICustomNameObject) {
ICustomNameObject customNameObject = (ICustomNameObject) accessInterface;
if (customNameObject.hasCustomInventoryName()) {
return customNameObject.getCustomInventoryName();
}
}
return LiteralText.EMPTY;
}
} }
@@ -19,14 +19,8 @@
package appeng.container.implementations; package appeng.container.implementations;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableSet;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
@@ -66,9 +60,8 @@ import appeng.me.helpers.PlayerSource;
import appeng.parts.reporting.CraftingTerminalPart; import appeng.parts.reporting.CraftingTerminalPart;
import appeng.parts.reporting.PatternTerminalPart; import appeng.parts.reporting.PatternTerminalPart;
import appeng.parts.reporting.TerminalPart; import appeng.parts.reporting.TerminalPart;
import appeng.util.Platform;
public class CraftConfirmContainer extends AEBaseContainer { public class CraftConfirmContainer extends AEBaseContainer implements CraftingCPUCyclingContainer {
public static ScreenHandlerType<CraftConfirmContainer> TYPE; public static ScreenHandlerType<CraftConfirmContainer> TYPE;
@@ -83,98 +76,51 @@ public class CraftConfirmContainer extends AEBaseContainer {
return helper.open(player, locator); return helper.open(player, locator);
} }
private final ArrayList<CraftingCPURecord> cpus = new ArrayList<>(); private final CraftingCPUCycler cpuCycler;
private ICraftingCPU selectedCpu;
private Future<ICraftingJob> job; private Future<ICraftingJob> job;
private ICraftingJob result; private ICraftingJob result;
@GuiSync(0) @GuiSync(0)
public long bytesUsed; public long bytesUsed;
@GuiSync(1)
public long cpuBytesAvail;
@GuiSync(2)
public int cpuCoProcessors;
@GuiSync(3) @GuiSync(3)
public boolean autoStart = false; public boolean autoStart = false;
@GuiSync(4) @GuiSync(4)
public boolean simulation = true; public boolean simulation = true;
@GuiSync(5)
public int selectedCpu = -1; // Indicates whether any CPUs are available
@GuiSync(6) @GuiSync(6)
public boolean noCPU = true; public boolean noCPU = true;
// Properties of the currently selected crafting CPU, this can be null
// if no CPUs are available, or if an automatic one is selected
@GuiSync(1)
public long cpuBytesAvail;
@GuiSync(2)
public int cpuCoProcessors;
@GuiSync(7) @GuiSync(7)
public Text myName; public Text cpuName;
public CraftConfirmContainer(int id, PlayerInventory ip, ITerminalHost te) { public CraftConfirmContainer(int id, PlayerInventory ip, ITerminalHost te) {
super(TYPE, id, ip, te); super(TYPE, id, ip, te);
this.cpuCycler = new CraftingCPUCycler(this::cpuMatches, this::onCPUSelectionChanged);
// A player can select no crafting CPU to use a suitable one automatically
this.cpuCycler.setAllowNoSelection(true);
} }
public void cycleCpu(final boolean next) { @Override
if (next) { public void cycleSelectedCPU(final boolean next) {
this.setSelectedCpu(this.getSelectedCpu() + 1); this.cpuCycler.cycleCpu(next);
} else {
this.setSelectedCpu(this.getSelectedCpu() - 1);
}
if (this.getSelectedCpu() < -1) {
this.setSelectedCpu(this.cpus.size() - 1);
} else if (this.getSelectedCpu() >= this.cpus.size()) {
this.setSelectedCpu(-1);
}
if (this.getSelectedCpu() == -1) {
this.setCpuAvailableBytes(0);
this.setCpuCoProcessors(0);
this.setName(null);
} else {
CraftingCPURecord cpu = this.cpus.get(this.getSelectedCpu());
this.setName(cpu.getName());
this.setCpuAvailableBytes(cpu.getSize());
this.setCpuCoProcessors(cpu.getProcessors());
}
} }
@Override @Override
public void sendContentUpdates() { public void sendContentUpdates() {
if (Platform.isClient()) { if (isClient()) {
return; return;
} }
final ICraftingGrid cc = this.getGrid().getCache(ICraftingGrid.class); this.cpuCycler.detectAndSendChanges(this.getGrid());
final ImmutableSet<ICraftingCPU> cpuSet = cc.getCpus();
int matches = 0;
boolean changed = false;
for (final ICraftingCPU c : cpuSet) {
boolean found = false;
for (final CraftingCPURecord ccr : this.cpus) {
if (ccr.getCpu() == c) {
found = true;
break;
}
}
final boolean matched = this.cpuMatches(c);
if (matched) {
matches++;
}
if (found == !matched) {
changed = true;
}
}
if (changed || this.cpus.size() != matches) {
this.cpus.clear();
for (final ICraftingCPU c : cpuSet) {
if (this.cpuMatches(c)) {
this.cpus.add(new CraftingCPURecord(c.getAvailableStorage(), c.getCoProcessors(), c));
}
}
this.sendCPUs();
}
this.setNoCPU(this.cpus.isEmpty());
super.sendContentUpdates(); super.sendContentUpdates();
@@ -277,22 +223,6 @@ public class CraftConfirmContainer extends AEBaseContainer {
return c.getAvailableStorage() >= this.getUsedBytes() && !c.isBusy(); return c.getAvailableStorage() >= this.getUsedBytes() && !c.isBusy();
} }
private void sendCPUs() {
Collections.sort(this.cpus);
if (this.getSelectedCpu() >= this.cpus.size()) {
this.setSelectedCpu(-1);
this.setCpuAvailableBytes(0);
this.setCpuCoProcessors(0);
this.setName(null);
} else if (this.getSelectedCpu() != -1) {
CraftingCPURecord cpu = this.cpus.get(this.getSelectedCpu());
this.setName(cpu.getName());
this.setCpuAvailableBytes(cpu.getSize());
this.setCpuCoProcessors(cpu.getProcessors());
}
}
public void startJob() { public void startJob() {
ScreenHandlerType<?> originalGui = null; ScreenHandlerType<?> originalGui = null;
@@ -315,9 +245,7 @@ public class CraftConfirmContainer extends AEBaseContainer {
if (this.result != null && !this.isSimulation()) { if (this.result != null && !this.isSimulation()) {
final ICraftingGrid cc = this.getGrid().getCache(ICraftingGrid.class); final ICraftingGrid cc = this.getGrid().getCache(ICraftingGrid.class);
final ICraftingLink g = cc.submitJob(this.result, null, final ICraftingLink g = cc.submitJob(this.result, null, this.selectedCpu, true, this.getActionSrc());
this.getSelectedCpu() == -1 ? null : this.cpus.get(this.getSelectedCpu()).getCpu(), true,
this.getActionSrc());
this.setAutoStart(false); this.setAutoStart(false);
if (g != null && originalGui != null && this.getLocator() != null) { if (g != null && originalGui != null && this.getLocator() != null) {
ContainerOpener.openContainer(originalGui, getPlayerInventory().player, getLocator()); ContainerOpener.openContainer(originalGui, getPlayerInventory().player, getLocator());
@@ -347,6 +275,22 @@ public class CraftConfirmContainer extends AEBaseContainer {
} }
} }
private void onCPUSelectionChanged(CraftingCPURecord cpuRecord, boolean cpusAvailable) {
noCPU = !cpusAvailable;
if (cpuRecord == null) {
cpuBytesAvail = 0;
cpuCoProcessors = 0;
cpuName = null;
selectedCpu = null;
} else {
cpuBytesAvail = cpuRecord.getSize();
cpuCoProcessors = cpuRecord.getProcessors();
cpuName = cpuRecord.getName();
selectedCpu = cpuRecord.getCpu();
}
}
public World getWorld() { public World getWorld() {
return this.getPlayerInv().player.world; return this.getPlayerInv().player.world;
} }
@@ -371,42 +315,18 @@ public class CraftConfirmContainer extends AEBaseContainer {
return this.cpuBytesAvail; return this.cpuBytesAvail;
} }
private void setCpuAvailableBytes(final long cpuBytesAvail) {
this.cpuBytesAvail = cpuBytesAvail;
}
public int getCpuCoProcessors() { public int getCpuCoProcessors() {
return this.cpuCoProcessors; return this.cpuCoProcessors;
} }
private void setCpuCoProcessors(final int cpuCoProcessors) {
this.cpuCoProcessors = cpuCoProcessors;
}
public int getSelectedCpu() {
return this.selectedCpu;
}
private void setSelectedCpu(final int selectedCpu) {
this.selectedCpu = selectedCpu;
}
public Text getName() { public Text getName() {
return this.myName; return this.cpuName;
}
private void setName(@Nullable final Text myName) {
this.myName = myName;
} }
public boolean hasNoCPU() { public boolean hasNoCPU() {
return this.noCPU; return this.noCPU;
} }
private void setNoCPU(final boolean noCPU) {
this.noCPU = noCPU;
}
public boolean isSimulation() { public boolean isSimulation() {
return this.simulation; return this.simulation;
} }
@@ -26,7 +26,7 @@ import net.minecraft.network.PacketByteBuf;
import net.minecraft.screen.ScreenHandlerListener; import net.minecraft.screen.ScreenHandlerListener;
import net.minecraft.screen.ScreenHandlerType; import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text; import net.minecraft.text.LiteralText;
import appeng.api.config.SecurityPermissions; import appeng.api.config.SecurityPermissions;
import appeng.api.networking.IGrid; import appeng.api.networking.IGrid;
@@ -46,24 +46,28 @@ import appeng.core.Api;
import appeng.core.sync.network.NetworkHandler; import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ConfigValuePacket; import appeng.core.sync.packets.ConfigValuePacket;
import appeng.core.sync.packets.MEInventoryUpdatePacket; import appeng.core.sync.packets.MEInventoryUpdatePacket;
import appeng.helpers.ICustomNameObject;
import appeng.me.cluster.implementations.CraftingCPUCluster; import appeng.me.cluster.implementations.CraftingCPUCluster;
import appeng.tile.crafting.CraftingBlockEntity; import appeng.tile.crafting.CraftingBlockEntity;
import appeng.util.Platform;
public class CraftingCPUContainer extends AEBaseContainer public class CraftingCPUContainer extends AEBaseContainer implements IMEMonitorHandlerReceiver<IAEItemStack> {
implements IMEMonitorHandlerReceiver<IAEItemStack>, ICustomNameObject {
public static ScreenHandlerType<CraftingCPUContainer> TYPE; public static ScreenHandlerType<CraftingCPUContainer> TYPE;
private static final ContainerHelper<CraftingCPUContainer, CraftingBlockEntity> helper = new ContainerHelper<>( private static final ContainerHelper<CraftingCPUContainer, CraftingBlockEntity> helper = new ContainerHelper<>(
CraftingCPUContainer::new, CraftingBlockEntity.class, SecurityPermissions.CRAFT); CraftingCPUContainer::new, CraftingBlockEntity.class, SecurityPermissions.CRAFT)
.withContainerTitle(craftingTileEntity -> {
// Use the cluster's custom name instead of the right-clicked block entities one
CraftingCPUCluster cluster = craftingTileEntity.getCluster();
if (cluster != null && cluster.getName() != null) {
return cluster.getName();
}
return LiteralText.EMPTY;
});
private final IItemList<IAEItemStack> list = Api.instance().storage().getStorageChannel(IItemStorageChannel.class) private final IItemList<IAEItemStack> list = Api.instance().storage().getStorageChannel(IItemStorageChannel.class)
.createList(); .createList();
private IGrid network; private final IGrid network;
private CraftingCPUCluster monitor = null; private CraftingCPUCluster monitor = null;
private Text cpuName = null;
@GuiSync(0) @GuiSync(0)
public long eta = -1; public long eta = -1;
@@ -77,14 +81,16 @@ public class CraftingCPUContainer extends AEBaseContainer
final IActionHost host = (IActionHost) (te instanceof IActionHost ? te : null); final IActionHost host = (IActionHost) (te instanceof IActionHost ? te : null);
if (host != null && host.getActionableNode() != null) { if (host != null && host.getActionableNode() != null) {
this.setNetwork(host.getActionableNode().getGrid()); this.network = host.getActionableNode().getGrid();
} else {
this.network = null;
} }
if (te instanceof CraftingBlockEntity) { if (te instanceof CraftingBlockEntity) {
this.setCPU(((CraftingBlockEntity) te).getCluster()); this.setCPU(((CraftingBlockEntity) te).getCluster());
} }
if (this.getNetwork() == null && Platform.isServer()) { if (this.getNetwork() == null && isServer()) {
this.setValidContainer(false); this.setValidContainer(false);
} }
} }
@@ -114,15 +120,13 @@ public class CraftingCPUContainer extends AEBaseContainer
} }
if (c instanceof CraftingCPUCluster) { if (c instanceof CraftingCPUCluster) {
this.cpuName = c.getName(); this.monitor = (CraftingCPUCluster) c;
this.setMonitor((CraftingCPUCluster) c);
this.list.resetStatus(); this.list.resetStatus();
this.getMonitor().getListOfItem(this.list, CraftingItemList.ALL); this.getMonitor().getListOfItem(this.list, CraftingItemList.ALL);
this.getMonitor().addListener(this, null); this.getMonitor().addListener(this, null);
this.setEstimatedTime(0); this.setEstimatedTime(0);
} else { } else {
this.setMonitor(null); this.monitor = null;
this.cpuName = null;
this.setEstimatedTime(-1); this.setEstimatedTime(-1);
} }
} }
@@ -153,7 +157,7 @@ public class CraftingCPUContainer extends AEBaseContainer
@Override @Override
public void sendContentUpdates() { public void sendContentUpdates() {
if (Platform.isServer() && this.getMonitor() != null && !this.list.isEmpty()) { if (isServer() && this.getMonitor() != null && !this.list.isEmpty()) {
try { try {
if (this.getEstimatedTime() >= 0) { if (this.getEstimatedTime() >= 0) {
final long elapsedTime = this.getMonitor().getElapsedTime(); final long elapsedTime = this.getMonitor().getElapsedTime();
@@ -218,16 +222,6 @@ public class CraftingCPUContainer extends AEBaseContainer
} }
@Override
public Text getCustomInventoryName() {
return this.cpuName;
}
@Override
public boolean hasCustomInventoryName() {
return this.cpuName != null;
}
public long getEstimatedTime() { public long getEstimatedTime() {
return this.eta; return this.eta;
} }
@@ -240,15 +234,8 @@ public class CraftingCPUContainer extends AEBaseContainer
return this.monitor; return this.monitor;
} }
private void setMonitor(final CraftingCPUCluster monitor) {
this.monitor = monitor;
}
IGrid getNetwork() { IGrid getNetwork() {
return this.network; return this.network;
} }
private void setNetwork(final IGrid network) {
this.network = network;
}
} }
@@ -0,0 +1,131 @@
package appeng.container.implementations;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import com.google.common.collect.ImmutableSet;
import net.minecraft.text.LiteralText;
import appeng.api.networking.IGrid;
import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.networking.crafting.ICraftingGrid;
/**
* Utility class for dialogs that can cycle through crafting CPUs
*/
class CraftingCPUCycler {
@FunctionalInterface
public interface ChangeListener {
void onChange(CraftingCPURecord selectedCpu, boolean cpusAvailable);
}
private final Predicate<ICraftingCPU> cpuFilter;
private final ChangeListener changeListener;
private final List<CraftingCPURecord> cpus = new ArrayList<>();
private int selectedCpu = -1;
private boolean initialDataSent = false;
private boolean allowNoSelection;
public CraftingCPUCycler(Predicate<ICraftingCPU> cpuFilter, ChangeListener changeListener) {
this.cpuFilter = cpuFilter;
this.changeListener = changeListener;
}
public void detectAndSendChanges(IGrid network) {
final ICraftingGrid cc = network.getCache(ICraftingGrid.class);
final ImmutableSet<ICraftingCPU> cpuSet = cc.getCpus();
int matches = 0;
boolean changed = !initialDataSent;
initialDataSent = true;
for (final ICraftingCPU c : cpuSet) {
boolean found = false;
for (final CraftingCPURecord ccr : this.cpus) {
if (ccr.getCpu() == c) {
found = true;
break;
}
}
final boolean matched = this.cpuFilter.test(c);
if (matched) {
matches++;
}
if (found == !matched) {
changed = true;
}
}
if (changed || this.cpus.size() != matches) {
this.cpus.clear();
for (final ICraftingCPU c : cpuSet) {
if (this.cpuFilter.test(c)) {
this.cpus.add(new CraftingCPURecord(c.getAvailableStorage(), c.getCoProcessors(), c));
}
}
// Sort and assign numeric IDs in case they have no names
Collections.sort(this.cpus);
for (int i = 0; i < this.cpus.size(); i++) {
CraftingCPURecord cpu = cpus.get(i);
if (cpu.getName() == null) {
cpu.setName(new LiteralText("#" + (i + 1)));
}
}
this.notifyListener();
}
}
public void cycleCpu(final boolean next) {
if (next) {
this.selectedCpu++;
} else {
this.selectedCpu--;
}
// If "no CPU" is a valid selection, then -1 is the first potential item
int lowerLimit = this.allowNoSelection ? -1 : 0;
if (this.selectedCpu < lowerLimit) {
this.selectedCpu = this.cpus.size() - 1;
} else if (this.selectedCpu >= this.cpus.size()) {
this.selectedCpu = lowerLimit;
}
this.notifyListener();
}
public boolean isAllowNoSelection() {
return allowNoSelection;
}
public void setAllowNoSelection(boolean allowNoSelection) {
this.allowNoSelection = allowNoSelection;
}
private void notifyListener() {
if (this.selectedCpu >= this.cpus.size()) {
this.selectedCpu = -1;
}
// Force the selected CPU to the first available CPU unless no-selection is
// explicitly allowed
if (!this.allowNoSelection && this.selectedCpu == -1 && !this.cpus.isEmpty()) {
this.selectedCpu = 0;
}
if (this.selectedCpu != -1) {
this.changeListener.onChange(this.cpus.get(this.selectedCpu), true);
} else {
this.changeListener.onChange(null, !this.cpus.isEmpty());
}
}
}
@@ -0,0 +1,12 @@
package appeng.container.implementations;
/**
* Implemented on screens that show information about a crafting CPU and allow
* the CPU to be cycled. Is triggered by receiving a config value packet with
* name <code>Terminal.Cpu</code>.
*/
public interface CraftingCPUCyclingContainer {
void cycleSelectedCPU(boolean forward);
}
@@ -25,16 +25,16 @@ import net.minecraft.text.Text;
import appeng.api.networking.crafting.ICraftingCPU; import appeng.api.networking.crafting.ICraftingCPU;
public class CraftingCPURecord implements Comparable<CraftingCPURecord> { public class CraftingCPURecord implements Comparable<CraftingCPURecord> {
private final Text myName;
private final ICraftingCPU cpu; private final ICraftingCPU cpu;
private final long size; private final long size;
private final int processors; private final int processors;
private Text name;
public CraftingCPURecord(final long size, final int coProcessors, final ICraftingCPU server) { public CraftingCPURecord(final long size, final int coProcessors, final ICraftingCPU server) {
this.size = size; this.size = size;
this.processors = coProcessors; this.processors = coProcessors;
this.cpu = server; this.cpu = server;
this.myName = server.getName(); this.name = server.getName();
} }
@Override @Override
@@ -50,10 +50,6 @@ public class CraftingCPURecord implements Comparable<CraftingCPURecord> {
return this.cpu; return this.cpu;
} }
Text getName() {
return this.myName;
}
int getProcessors() { int getProcessors() {
return this.processors; return this.processors;
} }
@@ -61,4 +57,13 @@ public class CraftingCPURecord implements Comparable<CraftingCPURecord> {
long getSize() { long getSize() {
return this.size; return this.size;
} }
public Text getName() {
return name;
}
public void setName(Text name) {
this.name = name;
}
} }
@@ -18,12 +18,6 @@
package appeng.container.implementations; package appeng.container.implementations;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.google.common.collect.ImmutableSet;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
@@ -31,14 +25,13 @@ import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import appeng.api.config.SecurityPermissions; import appeng.api.config.SecurityPermissions;
import appeng.api.networking.IGrid;
import appeng.api.networking.crafting.ICraftingCPU; import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.storage.ITerminalHost; import appeng.api.storage.ITerminalHost;
import appeng.container.ContainerLocator; import appeng.container.ContainerLocator;
import appeng.container.guisync.GuiSync; import appeng.container.guisync.GuiSync;
import appeng.util.Platform;
public class CraftingStatusContainer extends CraftingCPUContainer { public class CraftingStatusContainer extends CraftingCPUContainer implements CraftingCPUCyclingContainer {
public static ScreenHandlerType<CraftingStatusContainer> TYPE; public static ScreenHandlerType<CraftingStatusContainer> TYPE;
@@ -53,13 +46,13 @@ public class CraftingStatusContainer extends CraftingCPUContainer {
return helper.open(player, locator); return helper.open(player, locator);
} }
private final List<CraftingCPURecord> cpus = new ArrayList<>(); private final CraftingCPUCycler cpuCycler = new CraftingCPUCycler(this::cpuMatches, this::onCPUSelectionChanged);
@GuiSync(5)
public int selectedCpu = -1;
@GuiSync(6) @GuiSync(6)
public boolean noCPU = true; public boolean noCPU = true;
@GuiSync(7) @GuiSync(7)
public Text myName; public Text cpuName;
public CraftingStatusContainer(int id, final PlayerInventory ip, final ITerminalHost te) { public CraftingStatusContainer(int id, final PlayerInventory ip, final ITerminalHost te) {
super(TYPE, id, ip, te); super(TYPE, id, ip, te);
@@ -67,43 +60,9 @@ public class CraftingStatusContainer extends CraftingCPUContainer {
@Override @Override
public void sendContentUpdates() { public void sendContentUpdates() {
if (Platform.isServer() && this.getNetwork() != null) { IGrid network = this.getNetwork();
final ICraftingGrid cc = this.getNetwork().getCache(ICraftingGrid.class); if (isServer() && network != null) {
final ImmutableSet<ICraftingCPU> cpuSet = cc.getCpus(); cpuCycler.detectAndSendChanges(network);
int matches = 0;
boolean changed = false;
for (final ICraftingCPU c : cpuSet) {
boolean found = false;
for (final CraftingCPURecord ccr : this.cpus) {
if (ccr.getCpu() == c) {
found = true;
}
}
final boolean matched = this.cpuMatches(c);
if (matched) {
matches++;
}
if (found == !matched) {
changed = true;
}
}
if (changed || this.cpus.size() != matches) {
this.cpus.clear();
for (final ICraftingCPU c : cpuSet) {
if (this.cpuMatches(c)) {
this.cpus.add(new CraftingCPURecord(c.getAvailableStorage(), c.getCoProcessors(), c));
}
}
this.sendCPUs();
}
this.noCPU = this.cpus.isEmpty();
} }
super.sendContentUpdates(); super.sendContentUpdates();
@@ -113,52 +72,20 @@ public class CraftingStatusContainer extends CraftingCPUContainer {
return c.isBusy(); return c.isBusy();
} }
private void sendCPUs() { private void onCPUSelectionChanged(CraftingCPURecord cpuRecord, boolean cpusAvailable) {
Collections.sort(this.cpus); noCPU = !cpusAvailable;
if (cpuRecord == null) {
if (this.selectedCpu >= this.cpus.size()) { cpuName = null;
this.selectedCpu = -1; setCPU(null);
this.myName = null;
} else if (this.selectedCpu != -1) {
this.myName = this.cpus.get(this.selectedCpu).getName();
}
if (this.selectedCpu == -1 && this.cpus.size() > 0) {
this.selectedCpu = 0;
}
if (this.selectedCpu != -1) {
if (this.cpus.get(this.selectedCpu).getCpu() != this.getMonitor()) {
this.setCPU(this.cpus.get(this.selectedCpu).getCpu());
}
} else { } else {
this.setCPU(null); cpuName = cpuRecord.getName();
setCPU(cpuRecord.getCpu());
} }
} }
public void cycleCpu(final boolean next) { @Override
if (next) { public void cycleSelectedCPU(boolean forward) {
this.selectedCpu++; this.cpuCycler.cycleCpu(forward);
} else {
this.selectedCpu--;
}
if (this.selectedCpu < -1) {
this.selectedCpu = this.cpus.size() - 1;
} else if (this.selectedCpu >= this.cpus.size()) {
this.selectedCpu = -1;
}
if (this.selectedCpu == -1 && this.cpus.size() > 0) {
this.selectedCpu = 0;
}
if (this.selectedCpu == -1) {
this.myName = null;
this.setCPU(null);
} else {
this.myName = this.cpus.get(this.selectedCpu).getName();
this.setCPU(this.cpus.get(this.selectedCpu).getCpu());
}
} }
} }
@@ -36,7 +36,6 @@ import appeng.container.slot.FakeTypeOnlySlot;
import appeng.container.slot.OptionalTypeOnlyFakeSlot; import appeng.container.slot.OptionalTypeOnlyFakeSlot;
import appeng.container.slot.RestrictedInputSlot; import appeng.container.slot.RestrictedInputSlot;
import appeng.parts.automation.FormationPlanePart; import appeng.parts.automation.FormationPlanePart;
import appeng.util.Platform;
public class FormationPlaneContainer extends UpgradeableContainer { public class FormationPlaneContainer extends UpgradeableContainer {
@@ -108,7 +107,7 @@ public class FormationPlaneContainer extends UpgradeableContainer {
public void sendContentUpdates() { public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false); this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) { if (isServer()) {
this.setFuzzyMode((FuzzyMode) this.getUpgradeable().getConfigManager().getSetting(Settings.FUZZY_MODE)); this.setFuzzyMode((FuzzyMode) this.getUpgradeable().getConfigManager().getSetting(Settings.FUZZY_MODE));
this.setPlaceMode((YesNo) this.getUpgradeable().getConfigManager().getSetting(Settings.PLACE_BLOCK)); this.setPlaceMode((YesNo) this.getUpgradeable().getConfigManager().getSetting(Settings.PLACE_BLOCK));
} }
@@ -35,7 +35,6 @@ import appeng.container.guisync.GuiSync;
import appeng.container.slot.OutputSlot; import appeng.container.slot.OutputSlot;
import appeng.container.slot.RestrictedInputSlot; import appeng.container.slot.RestrictedInputSlot;
import appeng.tile.storage.IOPortBlockEntity; import appeng.tile.storage.IOPortBlockEntity;
import appeng.util.Platform;
public class IOPortContainer extends UpgradeableContainer { public class IOPortContainer extends UpgradeableContainer {
@@ -112,7 +111,7 @@ public class IOPortContainer extends UpgradeableContainer {
public void sendContentUpdates() { public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false); this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) { if (isServer()) {
this.setOperationMode( this.setOperationMode(
(OperationMode) this.getUpgradeable().getConfigManager().getSetting(Settings.OPERATION_MODE)); (OperationMode) this.getUpgradeable().getConfigManager().getSetting(Settings.OPERATION_MODE));
this.setFullMode( this.setFullMode(
@@ -36,7 +36,6 @@ import appeng.container.slot.RestrictedInputSlot;
import appeng.core.Api; import appeng.core.Api;
import appeng.tile.misc.InscriberBlockEntity; import appeng.tile.misc.InscriberBlockEntity;
import appeng.tile.misc.InscriberRecipes; import appeng.tile.misc.InscriberRecipes;
import appeng.util.Platform;
/** /**
* @author AlgorithmX2 * @author AlgorithmX2
@@ -120,7 +119,7 @@ public class InscriberContainer extends UpgradeableContainer implements IProgres
public void sendContentUpdates() { public void sendContentUpdates() {
this.standardDetectAndSendChanges(); this.standardDetectAndSendChanges();
if (Platform.isServer()) { if (isServer()) {
this.maxProcessingTime = this.ti.getMaxProcessingTime(); this.maxProcessingTime = this.ti.getMaxProcessingTime();
this.processingTime = this.ti.getProcessingTime(); this.processingTime = this.ti.getProcessingTime();
} }
@@ -55,7 +55,6 @@ import appeng.parts.reporting.InterfaceTerminalPart;
import appeng.tile.inventory.AppEngInternalInventory; import appeng.tile.inventory.AppEngInternalInventory;
import appeng.tile.misc.InterfaceBlockEntity; import appeng.tile.misc.InterfaceBlockEntity;
import appeng.util.InventoryAdaptor; import appeng.util.InventoryAdaptor;
import appeng.util.Platform;
import appeng.util.helpers.ItemHandlerUtil; import appeng.util.helpers.ItemHandlerUtil;
import appeng.util.inv.AdaptorFixedInv; import appeng.util.inv.AdaptorFixedInv;
import appeng.util.inv.WrapperCursorItemHandler; import appeng.util.inv.WrapperCursorItemHandler;
@@ -88,7 +87,7 @@ public final class InterfaceTerminalContainer extends AEBaseContainer {
public InterfaceTerminalContainer(int id, final PlayerInventory ip, final InterfaceTerminalPart anchor) { public InterfaceTerminalContainer(int id, final PlayerInventory ip, final InterfaceTerminalPart anchor) {
super(TYPE, id, ip, anchor); super(TYPE, id, ip, anchor);
if (Platform.isServer()) { if (isServer()) {
this.grid = anchor.getActionableNode().getGrid(); this.grid = anchor.getActionableNode().getGrid();
} }
@@ -97,7 +96,7 @@ public final class InterfaceTerminalContainer extends AEBaseContainer {
@Override @Override
public void sendContentUpdates() { public void sendContentUpdates() {
if (Platform.isClient()) { if (isClient()) {
return; return;
} }
@@ -18,8 +18,6 @@
package appeng.container.implementations; package appeng.container.implementations;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
@@ -33,13 +31,13 @@ import appeng.api.config.RedstoneMode;
import appeng.api.config.SecurityPermissions; import appeng.api.config.SecurityPermissions;
import appeng.api.config.Settings; import appeng.api.config.Settings;
import appeng.api.config.YesNo; import appeng.api.config.YesNo;
import appeng.client.gui.implementations.NumberEntryWidget;
import appeng.container.ContainerLocator; import appeng.container.ContainerLocator;
import appeng.container.guisync.GuiSync; import appeng.container.guisync.GuiSync;
import appeng.container.slot.FakeTypeOnlySlot; import appeng.container.slot.FakeTypeOnlySlot;
import appeng.container.slot.RestrictedInputSlot; import appeng.container.slot.RestrictedInputSlot;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ConfigValuePacket;
import appeng.parts.automation.LevelEmitterPart; import appeng.parts.automation.LevelEmitterPart;
import appeng.util.Platform;
public class LevelEmitterContainer extends UpgradeableContainer { public class LevelEmitterContainer extends UpgradeableContainer {
@@ -49,38 +47,46 @@ public class LevelEmitterContainer extends UpgradeableContainer {
LevelEmitterContainer::new, LevelEmitterPart.class, SecurityPermissions.BUILD); LevelEmitterContainer::new, LevelEmitterPart.class, SecurityPermissions.BUILD);
public static LevelEmitterContainer fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf buf) { public static LevelEmitterContainer fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf buf) {
return helper.fromNetwork(windowId, inv, buf); return helper.fromNetwork(windowId, inv, buf, (host, container, buffer) -> {
container.reportingValue = buffer.readVarLong();
});
} }
public static boolean open(PlayerEntity player, ContainerLocator locator) { public static boolean open(PlayerEntity player, ContainerLocator locator) {
return helper.open(player, locator); return helper.open(player, locator, (host, buffer) -> {
buffer.writeVarLong(host.getReportingValue());
});
} }
private final LevelEmitterPart lvlEmitter; private final LevelEmitterPart lvlEmitter;
@Environment(EnvType.CLIENT)
private NumberEntryWidget textField;
@GuiSync(2) @GuiSync(2)
public LevelType lvType; public LevelType lvType;
@GuiSync(3) @GuiSync(3)
public long EmitterValue = -1;
@GuiSync(4)
public YesNo cmType; public YesNo cmType;
// Only synced once on container-open, and only used on client
private long reportingValue;
public LevelEmitterContainer(int id, final PlayerInventory ip, final LevelEmitterPart te) { public LevelEmitterContainer(int id, final PlayerInventory ip, final LevelEmitterPart te) {
super(TYPE, id, ip, te); super(TYPE, id, ip, te);
this.lvlEmitter = te; this.lvlEmitter = te;
} }
@Environment(EnvType.CLIENT) public long getReportingValue() {
public void setTextField(final NumberEntryWidget level) { return reportingValue;
this.textField = level;
this.textField.setValue(this.EmitterValue);
} }
public void setLevel(final long l, final PlayerEntity player) { public void setReportingValue(long reportingValue) {
this.lvlEmitter.setReportingValue(l); if (isClient()) {
this.EmitterValue = l; if (reportingValue != this.reportingValue) {
this.reportingValue = reportingValue;
NetworkHandler.instance()
.sendToServer(new ConfigValuePacket("LevelEmitter.Value", String.valueOf(reportingValue)));
}
} else {
this.lvlEmitter.setReportingValue(reportingValue);
}
} }
@Override @Override
@@ -116,7 +122,6 @@ public class LevelEmitterContainer extends UpgradeableContainer {
@Override @Override
public int availableUpgrades() { public int availableUpgrades() {
return 1; return 1;
} }
@@ -124,8 +129,7 @@ public class LevelEmitterContainer extends UpgradeableContainer {
public void sendContentUpdates() { public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false); this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) { if (isServer()) {
this.EmitterValue = this.lvlEmitter.getReportingValue();
this.setCraftingMode( this.setCraftingMode(
(YesNo) this.getUpgradeable().getConfigManager().getSetting(Settings.CRAFT_VIA_REDSTONE)); (YesNo) this.getUpgradeable().getConfigManager().getSetting(Settings.CRAFT_VIA_REDSTONE));
this.setLevelMode((LevelType) this.getUpgradeable().getConfigManager().getSetting(Settings.LEVEL_TYPE)); this.setLevelMode((LevelType) this.getUpgradeable().getConfigManager().getSetting(Settings.LEVEL_TYPE));
@@ -137,15 +141,6 @@ public class LevelEmitterContainer extends UpgradeableContainer {
this.standardDetectAndSendChanges(); this.standardDetectAndSendChanges();
} }
@Override
public void onUpdate(final String field, final Object oldValue, final Object newValue) {
if (field.equals("EmitterValue")) {
if (this.textField != null) {
this.textField.setValue(this.EmitterValue);
}
}
}
@Override @Override
public YesNo getCraftingMode() { public YesNo getCraftingMode() {
return this.cmType; return this.cmType;
@@ -163,4 +158,5 @@ public class LevelEmitterContainer extends UpgradeableContainer {
private void setLevelMode(final LevelType lvType) { private void setLevelMode(final LevelType lvType) {
this.lvType = lvType; this.lvType = lvType;
} }
} }
@@ -46,6 +46,8 @@ import appeng.api.implementations.tiles.IViewCellStorage;
import appeng.api.networking.IGrid; import appeng.api.networking.IGrid;
import appeng.api.networking.IGridHost; import appeng.api.networking.IGridHost;
import appeng.api.networking.IGridNode; import appeng.api.networking.IGridNode;
import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.networking.energy.IEnergyGrid; import appeng.api.networking.energy.IEnergyGrid;
import appeng.api.networking.energy.IEnergySource; import appeng.api.networking.energy.IEnergySource;
import appeng.api.networking.security.IActionHost; import appeng.api.networking.security.IActionHost;
@@ -73,7 +75,6 @@ import appeng.core.sync.packets.MEInventoryUpdatePacket;
import appeng.me.helpers.ChannelPowerSrc; import appeng.me.helpers.ChannelPowerSrc;
import appeng.util.ConfigManager; import appeng.util.ConfigManager;
import appeng.util.IConfigManagerHost; import appeng.util.IConfigManagerHost;
import appeng.util.Platform;
public class MEMonitorableContainer extends AEBaseContainer public class MEMonitorableContainer extends AEBaseContainer
implements IConfigManagerHost, IConfigurableObject, IMEMonitorHandlerReceiver<IAEItemStack> { implements IConfigManagerHost, IConfigurableObject, IMEMonitorHandlerReceiver<IAEItemStack> {
@@ -101,6 +102,13 @@ public class MEMonitorableContainer extends AEBaseContainer
public boolean canAccessViewCells = false; public boolean canAccessViewCells = false;
@GuiSync(98) @GuiSync(98)
public boolean hasPower = false; public boolean hasPower = false;
/**
* The number of active crafting jobs in the network. -1 means unknown and will
* hide the label on the screen.
*/
@GuiSync(100)
public int activeCraftingJobs = -1;
private IConfigManagerHost gui; private IConfigManagerHost gui;
private IConfigManager serverCM; private IConfigManager serverCM;
private IGridNode networkNode; private IGridNode networkNode;
@@ -122,7 +130,7 @@ public class MEMonitorableContainer extends AEBaseContainer
this.clientCM.registerSetting(Settings.VIEW_MODE, ViewItems.ALL); this.clientCM.registerSetting(Settings.VIEW_MODE, ViewItems.ALL);
this.clientCM.registerSetting(Settings.SORT_DIRECTION, SortDir.ASCENDING); this.clientCM.registerSetting(Settings.SORT_DIRECTION, SortDir.ASCENDING);
if (Platform.isServer()) { if (isServer()) {
this.serverCM = monitorable.getConfigManager(); this.serverCM = monitorable.getConfigManager();
this.monitor = monitorable this.monitor = monitorable
@@ -183,12 +191,14 @@ public class MEMonitorableContainer extends AEBaseContainer
@Override @Override
public void sendContentUpdates() { public void sendContentUpdates() {
if (Platform.isServer()) { if (isServer()) {
if (this.monitor != this.host if (this.monitor != this.host
.getInventory(Api.instance().storage().getStorageChannel(IItemStorageChannel.class))) { .getInventory(Api.instance().storage().getStorageChannel(IItemStorageChannel.class))) {
this.setValidContainer(false); this.setValidContainer(false);
} }
this.updateActiveCraftingJobs();
for (final Settings set : this.serverCM.getSettings()) { for (final Settings set : this.serverCM.getSettings()) {
final Enum<?> sideLocal = this.serverCM.getSetting(set); final Enum<?> sideLocal = this.serverCM.getSetting(set);
final Enum<?> sideRemote = this.clientCM.getSetting(set); final Enum<?> sideRemote = this.clientCM.getSetting(set);
@@ -286,8 +296,38 @@ public class MEMonitorableContainer extends AEBaseContainer
this.queueInventory(c); this.queueInventory(c);
} }
private void updateActiveCraftingJobs() {
IGridNode hostNode = networkNode;
if (hostNode == null) {
// Wireless terminals do not directly expose the target grid (even though they
// have one)
if (host instanceof IActionHost) {
hostNode = ((IActionHost) host).getActionableNode();
}
}
IGrid grid = null;
if (hostNode != null) {
grid = hostNode.getGrid();
}
if (grid == null) {
// No grid to query crafting jobs from
this.activeCraftingJobs = -1;
return;
}
int activeJobs = 0;
ICraftingGrid craftingGrid = grid.getCache(ICraftingGrid.class);
for (ICraftingCPU cpus : craftingGrid.getCpus()) {
if (cpus.isBusy()) {
activeJobs++;
}
}
this.activeCraftingJobs = activeJobs;
}
private void queueInventory(final ScreenHandlerListener c) { private void queueInventory(final ScreenHandlerListener c) {
if (Platform.isServer() && c instanceof PlayerEntity && this.monitor != null) { if (isServer() && c instanceof PlayerEntity && this.monitor != null) {
try { try {
MEInventoryUpdatePacket piu = new MEInventoryUpdatePacket(); MEInventoryUpdatePacket piu = new MEInventoryUpdatePacket();
final IItemList<IAEItemStack> monitorCache = this.monitor.getStorageList(); final IItemList<IAEItemStack> monitorCache = this.monitor.getStorageList();
@@ -356,7 +396,7 @@ public class MEMonitorableContainer extends AEBaseContainer
@Override @Override
public IConfigManager getConfigManager() { public IConfigManager getConfigManager() {
if (Platform.isServer()) { if (isServer()) {
return this.serverCM; return this.serverCM;
} }
return this.clientCM; return this.clientCM;
@@ -42,7 +42,6 @@ import appeng.container.slot.RestrictedInputSlot;
import appeng.core.Api; import appeng.core.Api;
import appeng.items.misc.EncodedPatternItem; import appeng.items.misc.EncodedPatternItem;
import appeng.tile.crafting.MolecularAssemblerBlockEntity; import appeng.tile.crafting.MolecularAssemblerBlockEntity;
import appeng.util.Platform;
public class MolecularAssemblerContainer extends UpgradeableContainer implements IProgressProvider { public class MolecularAssemblerContainer extends UpgradeableContainer implements IProgressProvider {
@@ -148,7 +147,7 @@ public class MolecularAssemblerContainer extends UpgradeableContainer implements
public void sendContentUpdates() { public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false); this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) { if (isServer()) {
this.setRedStoneMode( this.setRedStoneMode(
(RedstoneMode) this.getUpgradeable().getConfigManager().getSetting(Settings.REDSTONE_CONTROLLED)); (RedstoneMode) this.getUpgradeable().getConfigManager().getSetting(Settings.REDSTONE_CONTROLLED));
} }
@@ -43,7 +43,6 @@ import appeng.container.guisync.GuiSync;
import appeng.core.Api; import appeng.core.Api;
import appeng.core.sync.network.NetworkHandler; import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.MEInventoryUpdatePacket; import appeng.core.sync.packets.MEInventoryUpdatePacket;
import appeng.util.Platform;
import appeng.util.item.AEItemStack; import appeng.util.item.AEItemStack;
public class NetworkStatusContainer extends AEBaseContainer { public class NetworkStatusContainer extends AEBaseContainer {
@@ -83,7 +82,7 @@ public class NetworkStatusContainer extends AEBaseContainer {
} }
} }
if (this.network == null && Platform.isServer()) { if (this.network == null && isServer()) {
this.setValidContainer(false); this.setValidContainer(false);
} }
} }
@@ -100,7 +99,7 @@ public class NetworkStatusContainer extends AEBaseContainer {
@Override @Override
public void sendContentUpdates() { public void sendContentUpdates() {
this.delay++; this.delay++;
if (Platform.isServer() && this.delay > 15 && this.network != null) { if (isServer() && this.delay > 15 && this.network != null) {
this.delay = 0; this.delay = 0;
final IEnergyGrid eg = this.network.getCache(IEnergyGrid.class); final IEnergyGrid eg = this.network.getCache(IEnergyGrid.class);
@@ -297,9 +297,9 @@ public class PatternTermContainer extends MEMonitorableContainer
@Override @Override
public boolean isSlotEnabled(final int idx) { public boolean isSlotEnabled(final int idx) {
if (idx == 1) { if (idx == 1) {
return Platform.isServer() ? !this.getPatternTerminal().isCraftingRecipe() : !this.isCraftingMode(); return isServer() ? !this.getPatternTerminal().isCraftingRecipe() : !this.isCraftingMode();
} else if (idx == 2) { } else if (idx == 2) {
return Platform.isServer() ? this.getPatternTerminal().isCraftingRecipe() : this.isCraftingMode(); return isServer() ? this.getPatternTerminal().isCraftingRecipe() : this.isCraftingMode();
} else { } else {
return false; return false;
} }
@@ -401,7 +401,7 @@ public class PatternTermContainer extends MEMonitorableContainer
@Override @Override
public void sendContentUpdates() { public void sendContentUpdates() {
super.sendContentUpdates(); super.sendContentUpdates();
if (Platform.isServer()) { if (isServer()) {
if (this.isCraftingMode() != this.getPatternTerminal().isCraftingRecipe()) { if (this.isCraftingMode() != this.getPatternTerminal().isCraftingRecipe()) {
this.setCraftingMode(this.getPatternTerminal().isCraftingRecipe()); this.setCraftingMode(this.getPatternTerminal().isCraftingRecipe());
this.updateOrderOfOutputSlots(); this.updateOrderOfOutputSlots();
@@ -423,7 +423,7 @@ public class PatternTermContainer extends MEMonitorableContainer
@Override @Override
public void onSlotChange(final Slot s) { public void onSlotChange(final Slot s) {
if (s == this.patternSlotOUT && Platform.isServer()) { if (s == this.patternSlotOUT && isServer()) {
for (final ScreenHandlerListener listener : this.getListeners()) { for (final ScreenHandlerListener listener : this.getListeners()) {
for (int i = 0; i < this.slots.size(); i++) { for (int i = 0; i < this.slots.size(); i++) {
Slot slot = this.slots.get(i); Slot slot = this.slots.get(i);
@@ -438,7 +438,7 @@ public class PatternTermContainer extends MEMonitorableContainer
this.sendContentUpdates(); this.sendContentUpdates();
} }
if (s == this.craftSlot && Platform.isClient()) { if (s == this.craftSlot && isClient()) {
this.getAndUpdateOutput(); this.getAndUpdateOutput();
} }
} }
@@ -18,8 +18,6 @@
package appeng.container.implementations; package appeng.container.implementations;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
@@ -28,12 +26,11 @@ import net.minecraft.screen.ScreenHandlerType;
import appeng.api.config.SecurityPermissions; import appeng.api.config.SecurityPermissions;
import appeng.api.parts.IPart; import appeng.api.parts.IPart;
import appeng.client.gui.implementations.NumberEntryWidget;
import appeng.container.AEBaseContainer; import appeng.container.AEBaseContainer;
import appeng.container.ContainerLocator; import appeng.container.ContainerLocator;
import appeng.container.guisync.GuiSync; import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ConfigValuePacket;
import appeng.helpers.IPriorityHost; import appeng.helpers.IPriorityHost;
import appeng.util.Platform;
public class PriorityContainer extends AEBaseContainer { public class PriorityContainer extends AEBaseContainer {
@@ -43,59 +40,53 @@ public class PriorityContainer extends AEBaseContainer {
PriorityContainer::new, IPriorityHost.class, SecurityPermissions.BUILD); PriorityContainer::new, IPriorityHost.class, SecurityPermissions.BUILD);
public static PriorityContainer fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf buf) { public static PriorityContainer fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf buf) {
return helper.fromNetwork(windowId, inv, buf); return helper.fromNetwork(windowId, inv, buf, (host, container, buffer) -> {
container.priorityValue = buffer.readVarInt();
});
} }
public static boolean open(PlayerEntity player, ContainerLocator locator) { public static boolean open(PlayerEntity player, ContainerLocator locator) {
return helper.open(player, locator); return helper.open(player, locator, (host, buffer) -> buffer.writeVarInt(host.getPriority()));
} }
private final IPriorityHost priHost; private final IPriorityHost priHost;
@Environment(EnvType.CLIENT) private int priorityValue;
private NumberEntryWidget textField;
@GuiSync(2)
public long PriorityValue = -1;
public PriorityContainer(int id, final PlayerInventory ip, final IPriorityHost te) { public PriorityContainer(int id, final PlayerInventory ip, final IPriorityHost te) {
super(TYPE, id, ip, (BlockEntity) (te instanceof BlockEntity ? te : null), super(TYPE, id, ip, (BlockEntity) (te instanceof BlockEntity ? te : null),
(IPart) (te instanceof IPart ? te : null)); (IPart) (te instanceof IPart ? te : null));
this.priHost = te; this.priHost = te;
this.priorityValue = te.getPriority();
} }
@Environment(EnvType.CLIENT) public void setPriority(final int newValue) {
public void setTextField(final NumberEntryWidget level) { if (newValue != priorityValue) {
this.textField = level; if (isClient()) {
this.textField.setValue(this.PriorityValue, true); // If for whatever reason the client enters the value first, do not update based
} // on incoming server data
this.priorityValue = newValue;
public void setPriority(final int newValue, final PlayerEntity player) { NetworkHandler.instance()
this.priHost.setPriority(newValue); .sendToServer(new ConfigValuePacket("PriorityHost.Priority", String.valueOf(newValue)));
this.PriorityValue = newValue; } else {
this.priHost.setPriority(newValue);
this.priorityValue = newValue;
}
}
} }
@Override @Override
public void sendContentUpdates() { public void sendContentUpdates() {
super.sendContentUpdates(); super.sendContentUpdates();
this.verifyPermissions(SecurityPermissions.BUILD, false); this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) {
this.PriorityValue = this.priHost.getPriority();
}
} }
@Override public int getPriorityValue() {
public void onUpdate(final String field, final Object oldValue, final Object newValue) { return priorityValue;
if (field.equals("PriorityValue")) {
if (this.textField != null) {
this.textField.setValue(this.PriorityValue, true);
}
}
super.onUpdate(field, oldValue, newValue);
} }
public IPriorityHost getPriorityHost() { public IPriorityHost getPriorityHost() {
return this.priHost; return this.priHost;
} }
} }
@@ -37,7 +37,6 @@ import appeng.core.Api;
import appeng.items.contents.QuartzKnifeObj; import appeng.items.contents.QuartzKnifeObj;
import appeng.items.materials.MaterialItem; import appeng.items.materials.MaterialItem;
import appeng.tile.inventory.AppEngInternalInventory; import appeng.tile.inventory.AppEngInternalInventory;
import appeng.util.Platform;
public class QuartzKnifeContainer extends AEBaseContainer { public class QuartzKnifeContainer extends AEBaseContainer {
@@ -142,7 +141,7 @@ public class QuartzKnifeContainer extends AEBaseContainer {
} }
private void makePlate() { private void makePlate() {
if (Platform.isServer()) { if (isServer()) {
if (!inSlot.getSlot(0).extract(1).isEmpty()) { if (!inSlot.getSlot(0).extract(1).isEmpty()) {
final ItemStack item = QuartzKnifeContainer.this.toolInv.getItemStack(); final ItemStack item = QuartzKnifeContainer.this.toolInv.getItemStack();
final ItemStack before = item.copy(); final ItemStack before = item.copy();
@@ -35,7 +35,6 @@ import appeng.container.guisync.GuiSync;
import appeng.container.slot.OutputSlot; import appeng.container.slot.OutputSlot;
import appeng.container.slot.RestrictedInputSlot; import appeng.container.slot.RestrictedInputSlot;
import appeng.tile.spatial.SpatialIOPortBlockEntity; import appeng.tile.spatial.SpatialIOPortBlockEntity;
import appeng.util.Platform;
public class SpatialIOPortContainer extends AEBaseContainer { public class SpatialIOPortContainer extends AEBaseContainer {
@@ -65,7 +64,7 @@ public class SpatialIOPortContainer extends AEBaseContainer {
public SpatialIOPortContainer(int id, final PlayerInventory ip, final SpatialIOPortBlockEntity spatialIOPort) { public SpatialIOPortContainer(int id, final PlayerInventory ip, final SpatialIOPortBlockEntity spatialIOPort) {
super(TYPE, id, ip, spatialIOPort, null); super(TYPE, id, ip, spatialIOPort, null);
if (Platform.isServer()) { if (isServer()) {
this.network = spatialIOPort.getGridNode(AEPartLocation.INTERNAL).getGrid(); this.network = spatialIOPort.getGridNode(AEPartLocation.INTERNAL).getGrid();
} }
@@ -89,7 +88,7 @@ public class SpatialIOPortContainer extends AEBaseContainer {
public void sendContentUpdates() { public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false); this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) { if (isServer()) {
this.delay++; this.delay++;
if (this.delay > 15 && this.network != null) { if (this.delay > 15 && this.network != null) {
this.delay = 0; this.delay = 0;
@@ -45,7 +45,6 @@ import appeng.container.slot.OptionalTypeOnlyFakeSlot;
import appeng.container.slot.RestrictedInputSlot; import appeng.container.slot.RestrictedInputSlot;
import appeng.core.Api; import appeng.core.Api;
import appeng.parts.misc.StorageBusPart; import appeng.parts.misc.StorageBusPart;
import appeng.util.Platform;
import appeng.util.helpers.ItemHandlerUtil; import appeng.util.helpers.ItemHandlerUtil;
import appeng.util.iterators.NullIterator; import appeng.util.iterators.NullIterator;
@@ -125,7 +124,7 @@ public class StorageBusContainer extends UpgradeableContainer {
public void sendContentUpdates() { public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false); this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) { if (isServer()) {
this.setFuzzyMode((FuzzyMode) this.getUpgradeable().getConfigManager().getSetting(Settings.FUZZY_MODE)); this.setFuzzyMode((FuzzyMode) this.getUpgradeable().getConfigManager().getSetting(Settings.FUZZY_MODE));
this.setReadWriteMode( this.setReadWriteMode(
(AccessRestriction) this.getUpgradeable().getConfigManager().getSetting(Settings.ACCESS)); (AccessRestriction) this.getUpgradeable().getConfigManager().getSetting(Settings.ACCESS));
@@ -52,7 +52,6 @@ import appeng.container.slot.RestrictedInputSlot;
import appeng.items.contents.NetworkToolViewer; import appeng.items.contents.NetworkToolViewer;
import appeng.items.tools.NetworkToolItem; import appeng.items.tools.NetworkToolItem;
import appeng.parts.automation.ExportBusPart; import appeng.parts.automation.ExportBusPart;
import appeng.util.Platform;
public class UpgradeableContainer extends AEBaseContainer implements IOptionalSlotHost { public class UpgradeableContainer extends AEBaseContainer implements IOptionalSlotHost {
@@ -200,7 +199,7 @@ public class UpgradeableContainer extends AEBaseContainer implements IOptionalSl
public void sendContentUpdates() { public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false); this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) { if (isServer()) {
final IConfigManager cm = this.getUpgradeable().getConfigManager(); final IConfigManager cm = this.getUpgradeable().getConfigManager();
this.loadSettingsFromHost(cm); this.loadSettingsFromHost(cm);
} }
@@ -29,7 +29,6 @@ import appeng.container.guisync.GuiSync;
import appeng.container.interfaces.IProgressProvider; import appeng.container.interfaces.IProgressProvider;
import appeng.container.slot.RestrictedInputSlot; import appeng.container.slot.RestrictedInputSlot;
import appeng.tile.misc.VibrationChamberBlockEntity; import appeng.tile.misc.VibrationChamberBlockEntity;
import appeng.util.Platform;
public class VibrationChamberContainer extends AEBaseContainer implements IProgressProvider { public class VibrationChamberContainer extends AEBaseContainer implements IProgressProvider {
@@ -65,7 +64,7 @@ public class VibrationChamberContainer extends AEBaseContainer implements IProgr
@Override @Override
public void sendContentUpdates() { public void sendContentUpdates() {
if (Platform.isServer()) { if (isServer()) {
this.remainingBurnTime = this.vibrationChamber.getMaxBurnTime() <= 0 ? 0 this.remainingBurnTime = this.vibrationChamber.getMaxBurnTime() <= 0 ? 0
: (int) (100.0 * this.vibrationChamber.getBurnTime() / this.vibrationChamber.getMaxBurnTime()); : (int) (100.0 * this.vibrationChamber.getBurnTime() / this.vibrationChamber.getMaxBurnTime());
this.burnSpeed = this.remainingBurnTime <= 0 ? 0 : this.vibrationChamber.getBurnSpeed(); this.burnSpeed = this.remainingBurnTime <= 0 ? 0 : this.vibrationChamber.getBurnSpeed();
@@ -28,7 +28,6 @@ import appeng.container.ContainerLocator;
import appeng.core.AEConfig; import appeng.core.AEConfig;
import appeng.core.localization.PlayerMessages; import appeng.core.localization.PlayerMessages;
import appeng.helpers.WirelessTerminalGuiObject; import appeng.helpers.WirelessTerminalGuiObject;
import appeng.util.Platform;
public class WirelessTermContainer extends MEPortableCellContainer { public class WirelessTermContainer extends MEPortableCellContainer {
@@ -57,7 +56,7 @@ public class WirelessTermContainer extends MEPortableCellContainer {
super.sendContentUpdates(); super.sendContentUpdates();
if (!this.wirelessTerminalGUIObject.rangeCheck()) { if (!this.wirelessTerminalGUIObject.rangeCheck()) {
if (Platform.isServer() && this.isValidContainer()) { if (isServer() && this.isValidContainer()) {
this.getPlayerInv().player.sendSystemMessage(PlayerMessages.OutOfRange.get(), Util.NIL_UUID); this.getPlayerInv().player.sendSystemMessage(PlayerMessages.OutOfRange.get(), Util.NIL_UUID);
} }
@@ -34,7 +34,7 @@ import appeng.core.sync.network.INetworkInfo;
public abstract class BasePacket { public abstract class BasePacket {
/** /**
* Sadly {@link PacketBuffer#readString()} gets inlined by Proguard which means * Sadly {@link PacketByteBuf#readString()} gets inlined by Proguard which means
* it's not available on the Server. This field has the default string length * it's not available on the Server. This field has the default string length
* that is used for writeString, which then also should be used for readString * that is used for writeString, which then also should be used for readString
* when it has no special length requirements. * when it has no special length requirements.
@@ -37,7 +37,7 @@ import appeng.container.AEBaseContainer;
import appeng.container.implementations.CellWorkbenchContainer; import appeng.container.implementations.CellWorkbenchContainer;
import appeng.container.implementations.CraftConfirmContainer; import appeng.container.implementations.CraftConfirmContainer;
import appeng.container.implementations.CraftingCPUContainer; import appeng.container.implementations.CraftingCPUContainer;
import appeng.container.implementations.CraftingStatusContainer; import appeng.container.implementations.CraftingCPUCyclingContainer;
import appeng.container.implementations.LevelEmitterContainer; import appeng.container.implementations.LevelEmitterContainer;
import appeng.container.implementations.NetworkToolContainer; import appeng.container.implementations.NetworkToolContainer;
import appeng.container.implementations.PatternTermContainer; import appeng.container.implementations.PatternTermContainer;
@@ -97,12 +97,9 @@ public class ConfigValuePacket extends BasePacket {
final ItemStack is = player.getStackInHand(hand); final ItemStack is = player.getStackInHand(hand);
final IMouseWheelItem si = (IMouseWheelItem) is.getItem(); final IMouseWheelItem si = (IMouseWheelItem) is.getItem();
si.onWheel(is, this.Value.equals("WheelUp")); si.onWheel(is, this.Value.equals("WheelUp"));
} else if (this.Name.equals("Terminal.Cpu") && c instanceof CraftingStatusContainer) { } else if (this.Name.equals("Terminal.Cpu") && c instanceof CraftingCPUCyclingContainer) {
final CraftingStatusContainer qk = (CraftingStatusContainer) c; final CraftingCPUCyclingContainer qk = (CraftingCPUCyclingContainer) c;
qk.cycleCpu(this.Value.equals("Next")); qk.cycleSelectedCPU(this.Value.equals("Next"));
} else if (this.Name.equals("Terminal.Cpu") && c instanceof CraftConfirmContainer) {
final CraftConfirmContainer qk = (CraftConfirmContainer) c;
qk.cycleCpu(this.Value.equals("Next"));
} else if (this.Name.equals("Terminal.Start") && c instanceof CraftConfirmContainer) { } else if (this.Name.equals("Terminal.Start") && c instanceof CraftConfirmContainer) {
final CraftConfirmContainer qk = (CraftConfirmContainer) c; final CraftConfirmContainer qk = (CraftConfirmContainer) c;
qk.startJob(); qk.startJob();
@@ -117,13 +114,13 @@ public class ConfigValuePacket extends BasePacket {
sc.toggleSetting(this.Value, player); sc.toggleSetting(this.Value, player);
} else if (this.Name.equals("PriorityHost.Priority") && c instanceof PriorityContainer) { } else if (this.Name.equals("PriorityHost.Priority") && c instanceof PriorityContainer) {
final PriorityContainer pc = (PriorityContainer) c; final PriorityContainer pc = (PriorityContainer) c;
pc.setPriority(Integer.parseInt(this.Value), player); pc.setPriority(Integer.parseInt(this.Value));
} else if (this.Name.equals("LevelEmitter.Value") && c instanceof LevelEmitterContainer) { } else if (this.Name.equals("LevelEmitter.Value") && c instanceof LevelEmitterContainer) {
final LevelEmitterContainer lvc = (LevelEmitterContainer) c; final LevelEmitterContainer lvc = (LevelEmitterContainer) c;
lvc.setLevel(Long.parseLong(this.Value), player); lvc.setReportingValue(Long.parseLong(this.Value));
} else if (this.Name.equals("FluidLevelEmitter.Value") && c instanceof FluidLevelEmitterContainer) { } else if (this.Name.equals("FluidLevelEmitter.Value") && c instanceof FluidLevelEmitterContainer) {
final FluidLevelEmitterContainer lvc = (FluidLevelEmitterContainer) c; final FluidLevelEmitterContainer lvc = (FluidLevelEmitterContainer) c;
lvc.setLevel(Long.parseLong(this.Value), player); lvc.setReportingValue(Long.parseLong(this.Value));
} else if (this.Name.startsWith("PatternTerminal.") && c instanceof PatternTermContainer) { } else if (this.Name.startsWith("PatternTerminal.") && c instanceof PatternTermContainer) {
final PatternTermContainer cpt = (PatternTermContainer) c; final PatternTermContainer cpt = (PatternTermContainer) c;
if (this.Name.equals("PatternTerminal.CraftMode")) { if (this.Name.equals("PatternTerminal.CraftMode")) {
@@ -191,9 +188,7 @@ public class ConfigValuePacket extends BasePacket {
public void clientPacketData(final INetworkInfo network, final PlayerEntity player) { public void clientPacketData(final INetworkInfo network, final PlayerEntity player) {
final ScreenHandler c = player.currentScreenHandler; final ScreenHandler c = player.currentScreenHandler;
if (this.Name.equals("CustomName") && c instanceof AEBaseContainer) { if (this.Name.startsWith("SyncDat.")) {
((AEBaseContainer) c).setCustomName(this.Value);
} else if (this.Name.startsWith("SyncDat.")) {
((AEBaseContainer) c).stringSync(Integer.parseInt(this.Name.substring(8)), this.Value); ((AEBaseContainer) c).stringSync(Integer.parseInt(this.Name.substring(8)), this.Value);
} else if (this.Name.equals("CraftingStatus") && this.Value.equals("Clear")) { } else if (this.Name.equals("CraftingStatus") && this.Value.equals("Clear")) {
final Screen gs = MinecraftClient.getInstance().currentScreen; final Screen gs = MinecraftClient.getInstance().currentScreen;
@@ -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) {
@@ -33,9 +33,9 @@ import net.minecraft.world.World;
import alexiil.mc.lib.attributes.AttributeList; import alexiil.mc.lib.attributes.AttributeList;
import alexiil.mc.lib.attributes.Simulation; import alexiil.mc.lib.attributes.Simulation;
import alexiil.mc.lib.attributes.item.FixedItemInv;
import alexiil.mc.lib.attributes.item.ItemExtractable; import alexiil.mc.lib.attributes.item.ItemExtractable;
import alexiil.mc.lib.attributes.item.filter.ExactItemStackFilter; import alexiil.mc.lib.attributes.item.filter.ExactItemStackFilter;
import alexiil.mc.lib.attributes.item.filter.ItemFilter;
import appeng.tile.AEBaseBlockEntity; import appeng.tile.AEBaseBlockEntity;
@@ -43,7 +43,7 @@ public class ItemGenBlockEntity extends AEBaseBlockEntity {
private static final Queue<ItemStack> POSSIBLE_ITEMS = new ArrayDeque<>(); private static final Queue<ItemStack> POSSIBLE_ITEMS = new ArrayDeque<>();
private final ItemExtractable handler = new QueuedItemHandler(); private final QueuedItemHandler handler = new QueuedItemHandler();
public ItemGenBlockEntity(BlockEntityType<?> tileEntityTypeIn) { public ItemGenBlockEntity(BlockEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn); super(tileEntityTypeIn);
@@ -77,22 +77,24 @@ public class ItemGenBlockEntity extends AEBaseBlockEntity {
to.offer(handler); to.offer(handler);
} }
class QueuedItemHandler implements ItemExtractable { static class QueuedItemHandler implements FixedItemInv {
@Override @Override
public ItemStack attemptExtraction(ItemFilter itemFilter, int maxAmount, Simulation simulation) { public ItemExtractable getExtractable() {
// When item filter asks for a specific item, just return that return (itemFilter, i, simulation) -> {
if (itemFilter instanceof ExactItemStackFilter) { // When item filter asks for a specific item, just return that
return ((ExactItemStackFilter) itemFilter).stack.copy(); if (itemFilter instanceof ExactItemStackFilter) {
} return ((ExactItemStackFilter) itemFilter).stack.copy();
}
final ItemStack is = POSSIBLE_ITEMS.peek(); final ItemStack is = POSSIBLE_ITEMS.peek();
if (is == null || !itemFilter.matches(is)) { if (is == null || !itemFilter.matches(is)) {
return ItemStack.EMPTY; return ItemStack.EMPTY;
} }
return simulation == Simulation.SIMULATE ? is.copy() : this.getNextItem(); return simulation == Simulation.SIMULATE ? is.copy() : getNextItem();
};
} }
private ItemStack getNextItem() { private ItemStack getNextItem() {
@@ -101,7 +103,28 @@ public class ItemGenBlockEntity extends AEBaseBlockEntity {
POSSIBLE_ITEMS.add(is); POSSIBLE_ITEMS.add(is);
return is.copy(); return is.copy();
} }
}
; @Override
public int getSlotCount() {
return 1;
}
@Override
public ItemStack getInvStack(int i) {
return POSSIBLE_ITEMS.peek().copy();
}
@Override
public boolean isItemValidForSlot(int i, ItemStack itemStack) {
return false;
}
@Override
public boolean setInvStack(int i, ItemStack itemStack, Simulation simulation) {
if (itemStack.isEmpty()) {
getNextItem(); // Go to next item
}
return itemStack.isEmpty();
}
}
} }
@@ -20,7 +20,6 @@ package appeng.decorative.solid;
import net.minecraft.block.AbstractGlassBlock; import net.minecraft.block.AbstractGlassBlock;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.Material;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
public class QuartzGlassBlock extends AbstractGlassBlock { public class QuartzGlassBlock extends AbstractGlassBlock {
@@ -74,6 +74,6 @@ public class TinyTNTPrimedRenderer extends EntityRenderer<TinyTNTPrimedEntity> {
@Override @Override
public Identifier getTexture(final TinyTNTPrimedEntity entity) { public Identifier getTexture(final TinyTNTPrimedEntity entity) {
return SpriteAtlasTexture.BLOCK_ATLAS_TEX; return SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE;
} }
} }
@@ -11,8 +11,6 @@ import appeng.client.gui.implementations.NumberEntryWidget;
import appeng.client.gui.implementations.UpgradeableScreen; import appeng.client.gui.implementations.UpgradeableScreen;
import appeng.client.gui.widgets.ServerSettingToggleButton; import appeng.client.gui.widgets.ServerSettingToggleButton;
import appeng.core.localization.GuiText; import appeng.core.localization.GuiText;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ConfigValuePacket;
import appeng.fluids.client.gui.widgets.FluidSlotWidget; import appeng.fluids.client.gui.widgets.FluidSlotWidget;
import appeng.fluids.container.FluidLevelEmitterContainer; import appeng.fluids.container.FluidLevelEmitterContainer;
@@ -28,17 +26,24 @@ public class FluidLevelEmitterScreen extends UpgradeableScreen<FluidLevelEmitter
public void init() { public void init() {
super.init(); super.init();
this.level = new NumberEntryWidget(this, 20, 17, 138, 62, NumberEntryType.LEVEL_FLUID_VOLUME, this.level = new NumberEntryWidget(this, 20, 17, 138, 62, NumberEntryType.LEVEL_FLUID_VOLUME);
this::onLevelChange);
this.level.setTextFieldBounds(25, 44, 75); this.level.setTextFieldBounds(25, 44, 75);
handler.setTextField(this.level);
this.level.addButtons(children::add, this::addButton); this.level.addButtons(children::add, this::addButton);
this.level.setValue(handler.getReportingValue());
this.level.setOnChange(this::saveReportingValue);
this.level.setOnConfirm(this::onClose);
this.changeFocus(true);
final int y = 40; final int y = 40;
final int x = 80 + 57; final int x = 80 + 57;
this.guiSlots.add(new FluidSlotWidget(this.handler.getFluidConfigInventory(), 0, 0, x, y)); this.guiSlots.add(new FluidSlotWidget(this.handler.getFluidConfigInventory(), 0, 0, x, y));
} }
private void saveReportingValue() {
this.level.getLongValue().ifPresent(handler::setReportingValue);
}
@Override @Override
protected void addButtons() { protected void addButtons() {
this.redstoneMode = new ServerSettingToggleButton<>(this.x - 18, this.y + 28, Settings.REDSTONE_EMITTER, this.redstoneMode = new ServerSettingToggleButton<>(this.x - 18, this.y + 28, Settings.REDSTONE_EMITTER,
@@ -79,8 +84,4 @@ public class FluidLevelEmitterScreen extends UpgradeableScreen<FluidLevelEmitter
protected void handleButtonVisibility() { protected void handleButtonVisibility() {
} }
private void onLevelChange(long level) {
NetworkHandler.instance().sendToServer(new ConfigValuePacket("FluidLevelEmitter.Value", String.valueOf(level)));
}
} }
@@ -21,7 +21,6 @@ import appeng.container.implementations.UpgradeableContainer;
import appeng.fluids.helper.FluidSyncHelper; import appeng.fluids.helper.FluidSyncHelper;
import appeng.fluids.util.AEFluidStack; import appeng.fluids.util.AEFluidStack;
import appeng.fluids.util.IAEFluidTank; import appeng.fluids.util.IAEFluidTank;
import appeng.util.Platform;
public abstract class FluidConfigurableContainer extends UpgradeableContainer implements IFluidSyncContainer { public abstract class FluidConfigurableContainer extends UpgradeableContainer implements IFluidSyncContainer {
private FluidSyncHelper sync = null; private FluidSyncHelper sync = null;
@@ -76,7 +75,7 @@ public abstract class FluidConfigurableContainer extends UpgradeableContainer im
@Override @Override
protected void standardDetectAndSendChanges() { protected void standardDetectAndSendChanges() {
if (Platform.isServer()) { if (isServer()) {
this.getSyncHelper().sendDiff(this.getListeners()); this.getSyncHelper().sendDiff(this.getListeners());
// clear out config items that are no longer valid (eg capacity upgrade removed) // clear out config items that are no longer valid (eg capacity upgrade removed)
@@ -36,7 +36,6 @@ import appeng.fluids.helper.DualityFluidInterface;
import appeng.fluids.helper.FluidSyncHelper; import appeng.fluids.helper.FluidSyncHelper;
import appeng.fluids.helper.IFluidInterfaceHost; import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.fluids.util.IAEFluidTank; import appeng.fluids.util.IAEFluidTank;
import appeng.util.Platform;
public class FluidInterfaceContainer extends FluidConfigurableContainer { public class FluidInterfaceContainer extends FluidConfigurableContainer {
@@ -81,7 +80,7 @@ public class FluidInterfaceContainer extends FluidConfigurableContainer {
public void sendContentUpdates() { public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false); this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) { if (isServer()) {
this.tankSync.sendDiff(this.getListeners()); this.tankSync.sendDiff(this.getListeners());
} }
@@ -1,7 +1,5 @@
package appeng.fluids.container; package appeng.fluids.container;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
@@ -10,13 +8,12 @@ import net.minecraft.screen.ScreenHandlerType;
import appeng.api.config.RedstoneMode; import appeng.api.config.RedstoneMode;
import appeng.api.config.SecurityPermissions; import appeng.api.config.SecurityPermissions;
import appeng.api.config.Settings; import appeng.api.config.Settings;
import appeng.client.gui.implementations.NumberEntryWidget;
import appeng.container.ContainerLocator; import appeng.container.ContainerLocator;
import appeng.container.guisync.GuiSync;
import appeng.container.implementations.ContainerHelper; import appeng.container.implementations.ContainerHelper;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ConfigValuePacket;
import appeng.fluids.parts.FluidLevelEmitterPart; import appeng.fluids.parts.FluidLevelEmitterPart;
import appeng.fluids.util.IAEFluidTank; import appeng.fluids.util.IAEFluidTank;
import appeng.util.Platform;
public class FluidLevelEmitterContainer extends FluidConfigurableContainer { public class FluidLevelEmitterContainer extends FluidConfigurableContainer {
public static ScreenHandlerType<FluidLevelEmitterContainer> TYPE; public static ScreenHandlerType<FluidLevelEmitterContainer> TYPE;
@@ -25,34 +22,41 @@ public class FluidLevelEmitterContainer extends FluidConfigurableContainer {
FluidLevelEmitterContainer::new, FluidLevelEmitterPart.class, SecurityPermissions.BUILD); FluidLevelEmitterContainer::new, FluidLevelEmitterPart.class, SecurityPermissions.BUILD);
public static FluidLevelEmitterContainer fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf buf) { public static FluidLevelEmitterContainer fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf buf) {
return helper.fromNetwork(windowId, inv, buf); return helper.fromNetwork(windowId, inv, buf, (host, container, buffer) -> {
container.reportingValue = buffer.readVarLong();
});
} }
public static boolean open(PlayerEntity player, ContainerLocator locator) { public static boolean open(PlayerEntity player, ContainerLocator locator) {
return helper.open(player, locator); return helper.open(player, locator, (host, buffer) -> {
buffer.writeVarLong(host.getReportingValue());
});
} }
private final FluidLevelEmitterPart lvlEmitter; private final FluidLevelEmitterPart lvlEmitter;
@Environment(EnvType.CLIENT) // Only synced once on container-open, and only used on client
private NumberEntryWidget textField; private long reportingValue;
@GuiSync(3)
public long EmitterValue = -1;
public FluidLevelEmitterContainer(int id, final PlayerInventory ip, final FluidLevelEmitterPart te) { public FluidLevelEmitterContainer(int id, final PlayerInventory ip, final FluidLevelEmitterPart te) {
super(TYPE, id, ip, te); super(TYPE, id, ip, te);
this.lvlEmitter = te; this.lvlEmitter = te;
} }
@Environment(EnvType.CLIENT) public long getReportingValue() {
public void setTextField(final NumberEntryWidget level) { return reportingValue;
this.textField = level;
this.textField.setValue(this.EmitterValue);
} }
public void setLevel(final long l, final PlayerEntity player) { public void setReportingValue(long reportingValue) {
this.lvlEmitter.setReportingValue(l); if (isClient()) {
this.EmitterValue = l; if (reportingValue != this.reportingValue) {
this.reportingValue = reportingValue;
NetworkHandler.instance()
.sendToServer(new ConfigValuePacket("FluidLevelEmitter.Value", String.valueOf(reportingValue)));
}
} else {
this.lvlEmitter.setReportingValue(reportingValue);
}
} }
@Override @Override
@@ -74,8 +78,7 @@ public class FluidLevelEmitterContainer extends FluidConfigurableContainer {
public void sendContentUpdates() { public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false); this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) { if (isServer()) {
this.EmitterValue = this.lvlEmitter.getReportingValue();
this.setRedStoneMode( this.setRedStoneMode(
(RedstoneMode) this.getUpgradeable().getConfigManager().getSetting(Settings.REDSTONE_EMITTER)); (RedstoneMode) this.getUpgradeable().getConfigManager().getSetting(Settings.REDSTONE_EMITTER));
} }
@@ -83,15 +86,6 @@ public class FluidLevelEmitterContainer extends FluidConfigurableContainer {
this.standardDetectAndSendChanges(); this.standardDetectAndSendChanges();
} }
@Override
public void onUpdate(final String field, final Object oldValue, final Object newValue) {
if (field.equals("EmitterValue")) {
if (this.textField != null) {
this.textField.setValue(this.EmitterValue);
}
}
}
@Override @Override
public IAEFluidTank getFluidConfigInventory() { public IAEFluidTank getFluidConfigInventory() {
return this.lvlEmitter.getConfig(); return this.lvlEmitter.getConfig();
@@ -44,7 +44,6 @@ import appeng.container.slot.RestrictedInputSlot;
import appeng.core.Api; import appeng.core.Api;
import appeng.fluids.parts.FluidStorageBusPart; import appeng.fluids.parts.FluidStorageBusPart;
import appeng.fluids.util.IAEFluidTank; import appeng.fluids.util.IAEFluidTank;
import appeng.util.Platform;
import appeng.util.iterators.NullIterator; import appeng.util.iterators.NullIterator;
/** /**
@@ -129,7 +128,7 @@ public class FluidStorageBusContainer extends FluidConfigurableContainer {
public void sendContentUpdates() { public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false); this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) { if (isServer()) {
this.setFuzzyMode((FuzzyMode) this.getUpgradeable().getConfigManager().getSetting(Settings.FUZZY_MODE)); this.setFuzzyMode((FuzzyMode) this.getUpgradeable().getConfigManager().getSetting(Settings.FUZZY_MODE));
this.setReadWriteMode( this.setReadWriteMode(
(AccessRestriction) this.getUpgradeable().getConfigManager().getSetting(Settings.ACCESS)); (AccessRestriction) this.getUpgradeable().getConfigManager().getSetting(Settings.ACCESS));
@@ -124,7 +124,7 @@ public class FluidTerminalContainer extends AEBaseContainer
this.clientCM.registerSetting(Settings.SORT_BY, SortOrder.NAME); this.clientCM.registerSetting(Settings.SORT_BY, SortOrder.NAME);
this.clientCM.registerSetting(Settings.SORT_DIRECTION, SortDir.ASCENDING); this.clientCM.registerSetting(Settings.SORT_DIRECTION, SortDir.ASCENDING);
this.clientCM.registerSetting(Settings.VIEW_MODE, ViewItems.ALL); this.clientCM.registerSetting(Settings.VIEW_MODE, ViewItems.ALL);
if (Platform.isServer()) { if (isServer()) {
this.serverCM = terminal.getConfigManager(); this.serverCM = terminal.getConfigManager();
this.monitor = terminal this.monitor = terminal
.getInventory(Api.instance().storage().getStorageChannel(IFluidStorageChannel.class)); .getInventory(Api.instance().storage().getStorageChannel(IFluidStorageChannel.class));
@@ -196,7 +196,7 @@ public class FluidTerminalContainer extends AEBaseContainer
} }
private void queueInventory(final ScreenHandlerListener c) { private void queueInventory(final ScreenHandlerListener c) {
if (Platform.isServer() && c instanceof PlayerEntity && this.monitor != null) { if (isServer() && c instanceof PlayerEntity && this.monitor != null) {
try { try {
MEFluidInventoryUpdatePacket piu = new MEFluidInventoryUpdatePacket(); MEFluidInventoryUpdatePacket piu = new MEFluidInventoryUpdatePacket();
final IItemList<IAEFluidStack> monitorCache = this.monitor.getStorageList(); final IItemList<IAEFluidStack> monitorCache = this.monitor.getStorageList();
@@ -221,14 +221,14 @@ public class FluidTerminalContainer extends AEBaseContainer
@Override @Override
public IConfigManager getConfigManager() { public IConfigManager getConfigManager() {
if (Platform.isServer()) { if (isServer()) {
return this.serverCM; return this.serverCM;
} }
return this.clientCM; return this.clientCM;
} }
public void setTargetStack(final IAEFluidStack stack) { public void setTargetStack(final IAEFluidStack stack) {
if (Platform.isClient()) { if (isClient()) {
if (stack == null && this.clientRequestedTargetFluid == null) { if (stack == null && this.clientRequestedTargetFluid == null) {
return; return;
} }
@@ -251,7 +251,7 @@ public class FluidTerminalContainer extends AEBaseContainer
@Override @Override
public void sendContentUpdates() { public void sendContentUpdates() {
if (Platform.isServer()) { if (isServer()) {
if (this.monitor != this.terminal if (this.monitor != this.terminal
.getInventory(Api.instance().storage().getStorageChannel(IFluidStorageChannel.class))) { .getInventory(Api.instance().storage().getStorageChannel(IFluidStorageChannel.class))) {
this.setValidContainer(false); this.setValidContainer(false);
@@ -18,13 +18,14 @@
package appeng.fluids.helper; package appeng.fluids.helper;
import java.math.RoundingMode;
import java.util.Optional; import java.util.Optional;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import alexiil.mc.lib.attributes.AttributeList; import alexiil.mc.lib.attributes.AttributeList;
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume; import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
import alexiil.mc.lib.attributes.item.FixedItemInv; import alexiil.mc.lib.attributes.item.FixedItemInv;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
@@ -319,8 +320,8 @@ public class DualityFluidInterface
toStore.setStackSize(-toStore.getStackSize()); toStore.setStackSize(-toStore.getStackSize());
// make sure strange things didn't happen... // make sure strange things didn't happen...
final FluidVolume canExtract = this.tanks.drain(slot, toStore.getFluidStack(), false); final FluidAmount canExtract = this.tanks.drain(slot, toStore.getFluidStack(), false);
if (canExtract.isEmpty() || canExtract.getAmount() != toStore.getStackSize()) { if (canExtract.isZero() || canExtract.asLong(1000, RoundingMode.DOWN) != toStore.getStackSize()) {
changed = true; changed = true;
} else { } else {
IAEFluidStack notStored = Platform.poweredInsert(src, dest, toStore, this.interfaceRequestSource); IAEFluidStack notStored = Platform.poweredInsert(src, dest, toStore, this.interfaceRequestSource);
@@ -329,8 +330,8 @@ public class DualityFluidInterface
if (toStore.getStackSize() > 0) { if (toStore.getStackSize() > 0) {
// extract items! // extract items!
changed = true; changed = true;
final FluidVolume removed = this.tanks.drain(slot, toStore.getFluidStack(), true); final FluidAmount removed = this.tanks.drain(slot, toStore.getFluidStack(), true);
if (removed.isEmpty() || toStore.getStackSize() != removed.getAmount()) { if (removed.isZero() || toStore.getStackSize() != removed.asLong(1000, RoundingMode.DOWN)) {
throw new IllegalStateException("bad attempt at managing tanks. ( drain )"); throw new IllegalStateException("bad attempt at managing tanks. ( drain )");
} }
} }
@@ -19,6 +19,14 @@ import appeng.core.AELog;
import appeng.util.Platform; import appeng.util.Platform;
public class AEFluidInventory implements IAEFluidTank { public class AEFluidInventory implements IAEFluidTank {
/**
* While this may seem redundant, it helps since this class heavily mixes AE
* fluids stacks, which use null to represent "nothing", and Minecraft's
* FluidStack, which uses #isEmpty() to represent nothing.
*/
private static final IAEFluidStack EMPTY_AE_FLUIDSTACK = null;
private final IAEFluidStack[] fluids; private final IAEFluidStack[] fluids;
private final IAEFluidInventory handler; private final IAEFluidInventory handler;
private final int capacity; private final int capacity;
@@ -48,13 +56,13 @@ public class AEFluidInventory implements IAEFluidTank {
public void setFluidInSlot(final int slot, final IAEFluidStack fluid) { public void setFluidInSlot(final int slot, final IAEFluidStack fluid) {
if (slot >= 0 && slot < this.getSlots()) { if (slot >= 0 && slot < this.getSlots()) {
if (Objects.equals(this.fluids[slot], fluid)) { if (Objects.equals(this.fluids[slot], fluid)) {
if (fluid != null && fluid.getStackSize() != this.fluids[slot].getStackSize()) { if (fluid != EMPTY_AE_FLUIDSTACK && fluid.getStackSize() != this.fluids[slot].getStackSize()) {
this.fluids[slot].setStackSize(Math.min(fluid.getStackSize(), this.capacity)); this.fluids[slot].setStackSize(Math.min(fluid.getStackSize(), this.capacity));
this.onContentChanged(slot); this.onContentChanged(slot);
} }
} else { } else {
if (fluid == null) { if (fluid == EMPTY_AE_FLUIDSTACK) {
this.fluids[slot] = null; this.fluids[slot] = EMPTY_AE_FLUIDSTACK;
} else { } else {
this.fluids[slot] = fluid.copy(); this.fluids[slot] = fluid.copy();
this.fluids[slot].setStackSize(Math.min(fluid.getStackSize(), this.capacity)); this.fluids[slot].setStackSize(Math.min(fluid.getStackSize(), this.capacity));
@@ -76,7 +84,7 @@ public class AEFluidInventory implements IAEFluidTank {
if (slot >= 0 && slot < this.getSlots()) { if (slot >= 0 && slot < this.getSlots()) {
return this.fluids[slot]; return this.fluids[slot];
} }
return null; return EMPTY_AE_FLUIDSTACK;
} }
@Override @Override
@@ -99,7 +107,7 @@ public class AEFluidInventory implements IAEFluidTank {
if (tank < 0 || tank >= fluids.length) { if (tank < 0 || tank >= fluids.length) {
return FluidVolumeUtil.EMPTY; return FluidVolumeUtil.EMPTY;
} }
return fluids[tank] == null ? FluidVolumeUtil.EMPTY : fluids[tank].getFluidStack(); return fluids[tank] == EMPTY_AE_FLUIDSTACK ? FluidVolumeUtil.EMPTY : fluids[tank].getFluidStack();
} }
@Override @Override
@@ -119,13 +127,13 @@ public class AEFluidInventory implements IAEFluidTank {
final IAEFluidStack fluid = this.fluids[slot]; final IAEFluidStack fluid = this.fluids[slot];
if (fluid != null && !fluid.getFluidStack().equals(resource)) { if (fluid != EMPTY_AE_FLUIDSTACK && !fluid.getFluidStack().equals(resource)) {
return 0; return 0;
} }
int amountToStore = this.capacity; int amountToStore = this.capacity;
if (fluid != null) { if (fluid != EMPTY_AE_FLUIDSTACK) {
amountToStore -= fluid.getStackSize(); amountToStore -= fluid.getStackSize();
} }
@@ -143,19 +151,19 @@ public class AEFluidInventory implements IAEFluidTank {
return amountToStore; return amountToStore;
} }
public FluidVolume drain(final int slot, final FluidVolume resource, final boolean doDrain) { public FluidAmount drain(final int slot, final FluidVolume resource, final boolean doDrain) {
final IAEFluidStack fluid = this.fluids[slot]; final IAEFluidStack fluid = this.fluids[slot];
if (resource.isEmpty() || fluid == null || !fluid.getFluidStack().equals(resource)) { if (resource.isEmpty() || fluid == EMPTY_AE_FLUIDSTACK || !fluid.getFluidStack().equals(resource)) {
return null; return FluidAmount.ZERO;
} }
int toDrain = (int) resource.getAmount_F().asLong(1000, RoundingMode.DOWN); int toDrain = (int) resource.getAmount_F().asLong(1000, RoundingMode.DOWN);
return this.drain(slot, toDrain, doDrain); return this.drain(slot, toDrain, doDrain);
} }
public FluidVolume drain(final int slot, final int maxDrain, boolean doDrain) { public FluidAmount drain(final int slot, final int maxDrain, boolean doDrain) {
final IAEFluidStack fluid = this.fluids[slot]; final IAEFluidStack fluid = this.fluids[slot];
if (fluid == null || maxDrain <= 0) { if (fluid == EMPTY_AE_FLUIDSTACK || maxDrain <= 0) {
return null; return FluidAmount.ZERO;
} }
int drained = maxDrain; int drained = maxDrain;
@@ -163,15 +171,15 @@ public class AEFluidInventory implements IAEFluidTank {
drained = (int) fluid.getStackSize(); drained = (int) fluid.getStackSize();
} }
FluidVolume stack = fluid.getFluidStack().withAmount(FluidAmount.of(drained, 1000)); FluidAmount amount = FluidAmount.of(drained, 1000);
if (doDrain) { if (doDrain) {
fluid.setStackSize(fluid.getStackSize() - drained); fluid.setStackSize(fluid.getStackSize() - drained);
if (fluid.getStackSize() <= 0) { if (fluid.getStackSize() <= 0) {
this.fluids[slot] = null; this.fluids[slot] = EMPTY_AE_FLUIDSTACK;
} }
this.onContentChanged(slot); this.onContentChanged(slot);
} }
return stack; return amount;
} }
public void writeToNBT(final CompoundTag data, final String name) { public void writeToNBT(final CompoundTag data, final String name) {
@@ -185,7 +193,7 @@ public class AEFluidInventory implements IAEFluidTank {
try { try {
final CompoundTag c = new CompoundTag(); final CompoundTag c = new CompoundTag();
if (this.fluids[x] != null) { if (this.fluids[x] != EMPTY_AE_FLUIDSTACK) {
this.fluids[x].writeToNBT(c); this.fluids[x].writeToNBT(c);
} }
+7 -32
View File
@@ -35,8 +35,8 @@ import com.google.common.base.Stopwatch;
import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
@@ -73,7 +73,7 @@ public class TickHandler {
ServerTickEvents.END_SERVER_TICK.register(this::onAfterServerTick); ServerTickEvents.END_SERVER_TICK.register(this::onAfterServerTick);
ServerTickEvents.START_WORLD_TICK.register(this::onBeforeWorldTick); ServerTickEvents.START_WORLD_TICK.register(this::onBeforeWorldTick);
ServerTickEvents.END_WORLD_TICK.register(this::onAfterWorldTick); ServerTickEvents.END_WORLD_TICK.register(this::onAfterWorldTick);
ServerLifecycleEvents.SERVER_STOPPING.register(this::onServerStopping); ServerWorldEvents.UNLOAD.register(this::onUnloadWorld);
} }
public static TickHandler instance() { public static TickHandler instance() {
@@ -135,38 +135,13 @@ public class TickHandler {
this.getRepo().clear(); this.getRepo().clear();
} }
// FIXME FABRIC It does not look like worlds can ever unload in Fabric. public void onUnloadWorld(MinecraftServer server, ServerWorld world) {
// FIXME FABRIC public void unloadWorld(final WorldEvent.Unload ev) {
// FIXME FABRIC if (Platform.isServer()) // for no there is no reason to care about this on the client...
// FIXME FABRIC {
// FIXME FABRIC final List<IGridNode> toDestroy = new ArrayList<>();
// FIXME FABRIC
// FIXME FABRIC this.getRepo().updateNetworks();
// FIXME FABRIC for (final Grid g : this.getRepo().networks) {
// FIXME FABRIC for (final IGridNode n : g.getNodes()) {
// FIXME FABRIC if (n.getWorld() == ev.getWorld()) {
// FIXME FABRIC toDestroy.add(n);
// FIXME FABRIC }
// FIXME FABRIC }
// FIXME FABRIC }
// FIXME FABRIC
// FIXME FABRIC for (final IGridNode n : toDestroy) {
// FIXME FABRIC n.destroy();
// FIXME FABRIC }
// FIXME FABRIC }
// FIXME FABRIC }
/**
* This is primarily useful for an integrated server being stopped, and can be
* fully replaced by the event above once world unload events hit.
*/
private void onServerStopping(MinecraftServer server) {
final List<IGridNode> toDestroy = new ArrayList<>(); final List<IGridNode> toDestroy = new ArrayList<>();
this.server.updateNetworks();
for (final Grid g : this.server.networks) { this.getRepo().updateNetworks();
for (final Grid g : this.getRepo().networks) {
for (final IGridNode n : g.getNodes()) { for (final IGridNode n : g.getNodes()) {
WorldAccess nodeWorld = n.getWorld(); if (n.getWorld() == world) {
if (nodeWorld instanceof ServerWorld && ((ServerWorld) nodeWorld).getServer() == server) {
toDestroy.add(n); toDestroy.add(n);
} }
} }
@@ -20,7 +20,6 @@ package appeng.integration.modules.jei;
import me.shedaniel.rei.api.AutoTransferHandler; import me.shedaniel.rei.api.AutoTransferHandler;
import me.shedaniel.rei.api.RecipeDisplay; import me.shedaniel.rei.api.RecipeDisplay;
import me.shedaniel.rei.api.TransferRecipeDisplay;
import appeng.container.implementations.CraftingTermContainer; import appeng.container.implementations.CraftingTermContainer;
@@ -20,7 +20,6 @@ package appeng.integration.modules.jei;
import me.shedaniel.rei.api.AutoTransferHandler; import me.shedaniel.rei.api.AutoTransferHandler;
import me.shedaniel.rei.api.RecipeDisplay; import me.shedaniel.rei.api.RecipeDisplay;
import me.shedaniel.rei.api.TransferRecipeDisplay;
import me.shedaniel.rei.plugin.DefaultPlugin; import me.shedaniel.rei.plugin.DefaultPlugin;
import appeng.container.implementations.PatternTermContainer; import appeng.container.implementations.PatternTermContainer;
@@ -111,7 +111,7 @@ abstract class RecipeTransferHandler<T extends ScreenHandler & IContainerCraftin
if (i < flatIngredients.size()) { if (i < flatIngredients.size()) {
ItemStack displayedIngredient = first.getItemStack(); ItemStack displayedIngredient = first.getItemStack();
if (displayedIngredient != null) { if (displayedIngredient != null) {
flatIngredients.set(i, Ingredient.method_26964(Stream.of(displayedIngredient))); flatIngredients.set(i, Ingredient.ofStacks(Stream.of(displayedIngredient)));
} }
} }
} }
@@ -47,6 +47,6 @@ public final class Tracer {
BlockState blockState = world.getBlockState(pos); BlockState blockState = world.getBlockState(pos);
LookDirection playerRay = Platform.getPlayerRay(player); LookDirection playerRay = Platform.getPlayerRay(player);
return blockState.getCollisionShape(world, pos).rayTrace(playerRay.getA(), playerRay.getB(), pos); return blockState.getCollisionShape(world, pos).raycast(playerRay.getA(), playerRay.getB(), pos);
} }
} }
@@ -38,7 +38,6 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag; import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
@@ -54,7 +54,7 @@ import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult; import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.minecraft.world.RayTraceContext; import net.minecraft.world.RaycastContext;
import net.minecraft.world.World; import net.minecraft.world.World;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
@@ -219,7 +219,7 @@ public class EntropyManipulatorItem extends AEBasePoweredItem implements IBlockT
// considered for onItemUse // considered for onItemUse
@Override @Override
public TypedActionResult<ItemStack> use(final World w, final PlayerEntity p, final Hand hand) { public TypedActionResult<ItemStack> use(final World w, final PlayerEntity p, final Hand hand) {
final BlockHitResult target = rayTrace(w, p, RayTraceContext.FluidHandling.ANY); final BlockHitResult target = raycast(w, p, RaycastContext.FluidHandling.ANY);
if (target.getType() != HitResult.Type.BLOCK) { if (target.getType() != HitResult.Type.BLOCK) {
BlockPos pos = target.getBlockPos(); BlockPos pos = target.getBlockPos();
@@ -48,7 +48,7 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box; import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.RayTraceContext; import net.minecraft.world.RaycastContext;
import net.minecraft.world.World; import net.minecraft.world.World;
import alexiil.mc.lib.attributes.item.FixedItemInv; import alexiil.mc.lib.attributes.item.FixedItemInv;
@@ -200,7 +200,7 @@ public class MatterCannonItem extends AEBasePoweredItem implements IStorageCell<
final float f1 = 0.3F; final float f1 = 0.3F;
final Box boundingBox = entity1.getBoundingBox().expand(f1, f1, f1); final Box boundingBox = entity1.getBoundingBox().expand(f1, f1, f1);
final Vec3d intersection = boundingBox.rayTrace(Vec3d, Vec3d1).orElse(null); final Vec3d intersection = boundingBox.raycast(Vec3d, Vec3d1).orElse(null);
if (intersection != null) { if (intersection != null) {
final double nd = Vec3d.squaredDistanceTo(intersection); final double nd = Vec3d.squaredDistanceTo(intersection);
@@ -214,9 +214,9 @@ public class MatterCannonItem extends AEBasePoweredItem implements IStorageCell<
} }
} }
RayTraceContext rayTraceContext = new RayTraceContext(Vec3d, Vec3d1, RayTraceContext.ShapeType.COLLIDER, RaycastContext rayTraceContext = new RaycastContext(Vec3d, Vec3d1, RaycastContext.ShapeType.COLLIDER,
RayTraceContext.FluidHandling.NONE, p); RaycastContext.FluidHandling.NONE, p);
HitResult pos = w.rayTrace(rayTraceContext); HitResult pos = w.raycast(rayTraceContext);
final Vec3d vec = new Vec3d(d0, d1, d2); final Vec3d vec = new Vec3d(d0, d1, d2);
if (entity != null && pos.getType() != HitResult.Type.MISS && pos.getPos().squaredDistanceTo(vec) > closest) { if (entity != null && pos.getType() != HitResult.Type.MISS && pos.getPos().squaredDistanceTo(vec) > closest) {
@@ -307,7 +307,7 @@ public class MatterCannonItem extends AEBasePoweredItem implements IStorageCell<
final float f1 = 0.3F; final float f1 = 0.3F;
final Box boundingBox = entity1.getBoundingBox().expand(f1, f1, f1); final Box boundingBox = entity1.getBoundingBox().expand(f1, f1, f1);
final Vec3d intersection = boundingBox.rayTrace(Vec3d, Vec3d1).orElse(null); final Vec3d intersection = boundingBox.raycast(Vec3d, Vec3d1).orElse(null);
if (intersection != null) { if (intersection != null) {
final double nd = Vec3d.squaredDistanceTo(intersection); final double nd = Vec3d.squaredDistanceTo(intersection);
@@ -322,10 +322,10 @@ public class MatterCannonItem extends AEBasePoweredItem implements IStorageCell<
} }
} }
RayTraceContext rayTraceContext = new RayTraceContext(Vec3d, Vec3d1, RayTraceContext.ShapeType.COLLIDER, RaycastContext rayTraceContext = new RaycastContext(Vec3d, Vec3d1, RaycastContext.ShapeType.COLLIDER,
RayTraceContext.FluidHandling.NONE, p); RaycastContext.FluidHandling.NONE, p);
final Vec3d vec = new Vec3d(d0, d1, d2); final Vec3d vec = new Vec3d(d0, d1, d2);
HitResult pos = w.rayTrace(rayTraceContext); HitResult pos = w.raycast(rayTraceContext);
if (entity != null && pos.getType() != HitResult.Type.MISS if (entity != null && pos.getType() != HitResult.Type.MISS
&& pos.getPos().squaredDistanceTo(vec) > closest) { && pos.getPos().squaredDistanceTo(vec) > closest) {
pos = new EntityHitResult(entity, entityIntersection); pos = new EntityHitResult(entity, entityIntersection);
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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();
} }
@@ -12,7 +12,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.util.registry.BuiltinRegistries; import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.RegistryKey; import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes; import net.minecraft.world.biome.BuiltinBiomes;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@@ -23,21 +23,21 @@ import appeng.spatial.SpatialStorageDimensionIds;
* This only needs to be here because the server-side will create a dynamic * This only needs to be here because the server-side will create a dynamic
* registry manager long before our mod is initialized. * registry manager long before our mod is initialized.
*/ */
@Mixin(Biomes.class) @Mixin(BuiltinBiomes.class)
public class BiomesMixin { public class BuiltinBiomesMixin {
@Unique @Unique
private static final Logger LOGGER = LogManager.getLogger(); private static final Logger LOGGER = LogManager.getLogger();
@Shadow @Shadow
private static Int2ObjectMap<RegistryKey<Biome>> BIOMES; private static Int2ObjectMap<RegistryKey<Biome>> BY_RAW_ID;
@Inject(method = "<clinit>", at = @At("TAIL")) @Inject(method = "<clinit>", at = @At("TAIL"))
private static void registerBiomes(CallbackInfo ci) { private static void registerBiomes(CallbackInfo ci) {
BuiltinRegistries.add(BuiltinRegistries.BIOME, SpatialStorageDimensionIds.BIOME_KEY.getValue(), BuiltinRegistries.add(BuiltinRegistries.BIOME, SpatialStorageDimensionIds.BIOME_KEY.getValue(),
SpatialStorageBiome.INSTANCE); SpatialStorageBiome.INSTANCE);
int rawId = BuiltinRegistries.BIOME.getRawId(SpatialStorageBiome.INSTANCE); int rawId = BuiltinRegistries.BIOME.getRawId(SpatialStorageBiome.INSTANCE);
RegistryKey<Biome> prev = BIOMES.put(rawId, SpatialStorageDimensionIds.BIOME_KEY); RegistryKey<Biome> prev = BY_RAW_ID.put(rawId, SpatialStorageDimensionIds.BIOME_KEY);
if (prev != null) { if (prev != null) {
LOGGER.warn("Biome with raw-id {} was already registered: {}", rawId, prev); LOGGER.warn("Biome with raw-id {} was already registered: {}", rawId, prev);
} }
@@ -49,7 +49,7 @@ public class DimensionTypeMixin {
dimensionType); dimensionType);
} }
@Inject(method = "method_28517", at = @At("RETURN")) @Inject(method = "createDefaultDimensionOptions", at = @At("RETURN"))
private static void buildDimensionRegistry(Registry<DimensionType> dimensionTypes, Registry<Biome> biomes, private static void buildDimensionRegistry(Registry<DimensionType> dimensionTypes, Registry<Biome> biomes,
Registry<ChunkGeneratorSettings> chunkGeneratorSettings, long seed, Registry<ChunkGeneratorSettings> chunkGeneratorSettings, long seed,
CallbackInfoReturnable<SimpleRegistry<DimensionOptions>> cir) { CallbackInfoReturnable<SimpleRegistry<DimensionOptions>> cir) {
@@ -8,7 +8,6 @@ import net.minecraft.fluid.Fluid;
import net.minecraft.tag.FluidTags; import net.minecraft.tag.FluidTags;
import net.minecraft.tag.RequiredTagList; import net.minecraft.tag.RequiredTagList;
import net.minecraft.tag.Tag; import net.minecraft.tag.Tag;
import net.minecraft.tag.TagGroup;
@Mixin(FluidTags.class) @Mixin(FluidTags.class)
public interface FluidTagsAccessor { public interface FluidTagsAccessor {

Some files were not shown because too many files have changed in this diff Show More