Compare commits

...

28 Commits

Author SHA1 Message Date
Neeve 20a1fec6fb Recache OreDict Buses on RegEx changes & adjust visibility logic (#395) 2024-02-05 13:05:31 +11:00
Yang Xizhi 0fffc829ab Fix invalid pattern outputs throwing NPE in crafting grid (#393) 2024-02-01 19:14:33 +11:00
NotMyWing 88635d9a8d Do not check white-/blacklist on extract
Slightly rollbacks #384, since extractables are filtered in getAvailableItems
Allows extracting inaccessible items from cells and overriding SB behavior via reporting non-extractables
2024-02-01 18:33:13 +11:00
Neeve 0fd0ed1b1c Fix Fluid Cells having no upgrades (#392) 2024-01-31 19:37:05 +11:00
Neeve 87f884228e Fix ME Storage Buses reporting contents regardless of settings (#384) 2024-01-30 16:10:52 +11:00
Serenibyss 3495d3dfd4 Use LoadingCache instead of HashMap for CableBusBakedModel (#385) 2024-01-30 14:19:50 +11:00
ZHAY10086 0acb03b83d Add zh_cn.lang entries for Sticky Card (#381) 2024-01-21 13:55:57 +11:00
Serenibyss 9adb0359dd Fix player UUID lookup server issue (#380) 2024-01-20 23:44:34 +11:00
Serenibyss ac259dce6a Fix Network Tool not working (#377) 2024-01-16 15:56:12 +11:00
Neeve 7a6d49412e Fix minor slot merge/update regressions (#376) 2024-01-16 15:55:13 +11:00
Yang Xizhi 10f47a560a Fix transformers causing NCDF on specific servers (#374) 2024-01-16 12:36:22 +11:00
Serenibyss a8f0bbe06b Add Sticky Card (#371)
Co-authored-by: NotMyWing <winwyv@gmail.com>
2024-01-16 12:27:13 +11:00
Serenibyss dd3cdfcec5 Fix landing/running particles for cable bus (#372)
Co-authored-by: NotMyWing <winwyv@gmail.com>
2024-01-15 13:40:01 -06:00
Neeve 503f14f0a6 Fix minor slot stack size regression (#375) 2024-01-15 13:39:04 -06:00
Neeve 30af345ceb Update mod base name (#373) 2024-01-16 01:13:04 +11:00
Serenibyss e8af0f228b Update ME IO Port tasks on grid changes (#370) 2024-01-15 18:01:53 +11:00
Serenibyss 0291ceff30 Fix Toast server crash (#367) 2024-01-14 13:15:45 +11:00
NotMyWing d0614ba7d8 Clear modVersion 2024-01-13 17:18:41 +11:00
Neeve 54366e2b35 Initialize GHA workflows for pushing & caching (#359) 2024-01-13 16:58:14 +11:00
Serenibyss d128b0c228 Fix ME Interface Terminal input search not checking beyond first input (#364) 2024-01-13 16:57:54 +11:00
Neeve f7aa4c92bc Fix CellInventory stack size data losses (#363)
Migrates the total item count and serialized stack sizes to `long`
2024-01-13 16:56:26 +11:00
Serenibyss 0709d2dfc4 Color applicator improvements (#360)
* Now properly updates the Applicator's set color when a dye runs out, instead of staying stuck on a color which has no dye left
* Holding Applicator in offhand will now paint cables on placement
* Middle-clicking a colored tile while holding an Applicator in main or off hand will now set the Applicator's color to that color, if the dye is available in the Applicator
2024-01-12 18:21:24 +11:00
mczph 2ea08a3fc9 zh_cn translation fix and additions (#361) 2024-01-09 21:02:40 -06:00
Serenibyss 8c7185f8ff Update buildscripts (#354) 2024-01-09 17:47:53 +11:00
Serenibyss f7651fff29 Add part placement preview, render all part boxes on hover (#349) 2024-01-09 15:53:52 +11:00
Serenibyss 51f2a42367 Tweak transparent Smart Cable texture (#356) 2024-01-09 15:43:36 +11:00
Serenibyss 4829ec8286 Remove part layer api in favor of capabilities (#355) 2024-01-08 09:52:05 -06:00
Serenibyss 0b7341e4a8 Allow for math expressions in GuiCraftAmount textbox (#353) 2024-01-07 13:55:22 +11:00
93 changed files with 2655 additions and 1807 deletions
-25
View File
@@ -1,25 +0,0 @@
name: Build mod
on: [ push, pull_request, workflow_dispatch ]
jobs:
build:
name: Build mod
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: '8'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew -Pnet.minecraftforge.gradle.disableUpdateChecker=true build
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: appliedenergistics2
path: build/libs
+68
View File
@@ -0,0 +1,68 @@
# Publishes built jars to distribution platforms
name: Publish
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+' # any semver tag, e.g. 1.2.3
env:
# type of release
RELEASE_TYPE: "release"
jobs:
Publish:
runs-on: ubuntu-latest
permissions:
contents: write # needed to create GitHub releases
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Check for Duplicate Tags
run: |
if git rev-parse -q --verify "refs/tags/${{ github.ref }}" >/dev/null; then
echo "Tag already exists. A version bump is required."
exit 1
fi
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '17'
- name: Build Project
uses: gradle/gradle-build-action@v2
with:
arguments: 'build --build-cache --daemon' # use the daemon here so the rest of the process is faster
generate-job-summary: false
gradle-home-cache-includes: |
caches
jdks
notifications
wrapper
- name: Publish to GitHub
uses: softprops/action-gh-release@v1
with:
files: "build/libs/*.jar"
generate_release_notes: true
fail_on_unmatched_files: true
- name: Publish to Curseforge
uses: gradle/gradle-build-action@v2
env:
CURSEFORGE_API_KEY: "${{secrets.CURSEFORGE_API_KEY}}"
CURSEFORGE_PROJECT_ID: "${{secrets.CURSEFORGE_PROJECT_ID}}"
RELEASE_TYPE: "${{env.RELEASE_TYPE}}"
with:
arguments: 'curseforge --daemon'
generate-job-summary: false
gradle-home-cache-includes: |
caches
jdks
notifications
wrapper
+39
View File
@@ -0,0 +1,39 @@
# Updates the Gradle Cache when relevant files change
name: Update Gradle Cache
on:
workflow_dispatch:
push:
branches:
- master
paths:
- "gradle**" # covers gradle folder, gradle.properties, gradlew
- "build.gradle*"
- "settings.gradle*"
- "src/main/resources/*_at.cfg" # access transformers
jobs:
Update_Cache:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '17'
- name: Update Cache
uses: gradle/gradle-build-action@v2
with:
arguments: 'test --build-cache --no-daemon' # disable daemon since only one gradle operation will happen
generate-job-summary: false
gradle-home-cache-includes: |
caches
jdks
notifications
wrapper
cache-write-only: true
+76 -25
View File
@@ -1,32 +1,83 @@
# exclude all
/*
.nopublish
# include important folders
# need gradle
!gradle/
!gradlew
!gradlew.bat
!build.gradle
!gradle.properties
!settings.gradle
!.travis.yml
### Windows ###
# include markdowns
!README.md
!LICENSE
thumbs.db
*.db
# include sourcecode
!src/
### Java ###
# include git important files
!.gitmodules
!.gitignore
*.class
# code format to reduce noise in git commits
!codeformat/
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Github specific files and directories
!.github/
# Package Files #
*.war
*.ear
*.txt
# Explicit ignores
Thumbs.db
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Eclipse ###
*.pydevproject
.metadata
.gradle
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
/eclipse
# Eclipse Core
.project
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# JDT-specific (Eclipse Java Development Tools)
.classpath
# Java annotation processor (APT)
.factorypath
# PDT-specific
.buildpath
# sbteclipse plugin
.target
# TeXlipse plugin
.texlipse
### Intellij IDEA ###
*.iml
*.ipr
*.iws
.idea/
.idea_modules/
/classes/
/out/
/build/
# Linux
*~
run/
logs/
-33
View File
@@ -1,33 +0,0 @@
sudo: required
dist: trusty
language: java
jdk:
- oraclejdk8
- openjdk8
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
- rm -f $HOME/.gradle/caches/minecraft/ForgeVersion.json
- rm -f $HOME/.gradle/caches/minecraft/ForgeVersion.json.etag
- rm -fr $HOME/.gradle/caches/minecraft/deobfedDeps
- rm -f $HOME/.gradle/caches/*/fileHashes/fileHashes.bin
- rm -f $HOME/.gradle/caches/*/fileHashes/fileHashes.lock
cache:
directories:
- '$HOME/.m2/repository'
- '$HOME/.sonar/cache'
- '$HOME/.gradle/wrapper'
- '$HOME/.gradle/caches'
addons:
sonarcloud:
organization: "appliedenergistics"
install: "./gradlew setupCIWorkspace"
script:
- "./gradlew build"
- "./gradlew test"
- "./gradlew sonarqube"
+338 -138
View File
@@ -1,3 +1,4 @@
//version: 1704659416
/*
* DO NOT CHANGE THIS FILE!
* Also, you may replace this file at any time if there is an update available.
@@ -19,23 +20,24 @@ import static org.gradle.internal.logging.text.StyledTextOutput.Style
plugins {
id 'java'
id 'java-library'
id 'base'
id 'eclipse'
id 'maven-publish'
id 'org.jetbrains.gradle.plugin.idea-ext' version '1.1.7'
id 'com.gtnewhorizons.retrofuturagradle' version '1.3.19'
id 'net.darkhax.curseforgegradle' version '1.0.14' apply false
id 'com.modrinth.minotaur' version '2.8.0' apply false
id 'com.gtnewhorizons.retrofuturagradle' version '1.3.25'
id 'net.darkhax.curseforgegradle' version '1.1.17' apply false
id 'com.modrinth.minotaur' version '2.8.6' apply false
id 'com.diffplug.spotless' version '6.13.0' apply false
id 'com.palantir.git-version' version '3.0.0' apply false
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
}
if (verifySettingsGradle()) {
throw new GradleException("Settings has been updated, please re-run task.")
id 'org.jetbrains.kotlin.jvm' version '1.8.0' apply false
id 'org.jetbrains.kotlin.kapt' version '1.8.0' apply false
id 'com.google.devtools.ksp' version '1.8.0-1.0.9' apply false
}
def out = services.get(StyledTextOutputFactory).create('an-output')
// Project properties
// Required properties: we don't know how to handle these being missing gracefully
@@ -50,31 +52,72 @@ checkPropertyExists("mixinsPackage")
checkPropertyExists("coreModClass")
checkPropertyExists("containsMixinsAndOrCoreModOnly")
// Optional properties: we can assume some default behavior if these are missing
propertyDefaultIfUnset("modVersion", "")
propertyDefaultIfUnset("includeMCVersionJar", false)
propertyDefaultIfUnset("autoUpdateBuildScript", false)
propertyDefaultIfUnset("modArchivesBaseName", project.modId)
propertyDefaultIfUnsetWithEnvVar("developmentEnvironmentUserName", "Developer", "DEV_USERNAME")
propertyDefaultIfUnset("generateGradleTokenClass", "")
propertyDefaultIfUnset("gradleTokenModId", "")
propertyDefaultIfUnset("gradleTokenModName", "")
propertyDefaultIfUnset("gradleTokenVersion", "")
propertyDefaultIfUnset("useSrcApiPath", false)
propertyDefaultIfUnset("includeWellKnownRepositories", true)
propertyDefaultIfUnset("includeCommonDevEnvMods", true)
propertyDefaultIfUnset("noPublishedSources", false)
propertyDefaultIfUnset("forceEnableMixins", false)
propertyDefaultIfUnsetWithEnvVar("enableCoreModDebug", false, "CORE_MOD_DEBUG")
propertyDefaultIfUnset("generateMixinConfig", true)
propertyDefaultIfUnset("usesShadowedDependencies", false)
propertyDefaultIfUnset("minimizeShadowedDependencies", true)
propertyDefaultIfUnset("relocateShadowedDependencies", true)
propertyDefaultIfUnset("separateRunDirectories", false)
propertyDefaultIfUnset("versionDisplayFormat", '$MOD_NAME \u2212 $VERSION')
propertyDefaultIfUnsetWithEnvVar("modrinthProjectId", "", "MODRINTH_PROJECT_ID")
propertyDefaultIfUnset("modrinthRelations", "")
propertyDefaultIfUnsetWithEnvVar("curseForgeProjectId", "", "CURSEFORGE_PROJECT_ID")
propertyDefaultIfUnset("curseForgeRelations", "")
propertyDefaultIfUnsetWithEnvVar("releaseType", "release", "RELEASE_TYPE")
propertyDefaultIfUnset("generateDefaultChangelog", false)
propertyDefaultIfUnset("customMavenPublishUrl", "")
propertyDefaultIfUnset("mavenArtifactGroup", getDefaultArtifactGroup())
propertyDefaultIfUnset("enableModernJavaSyntax", false)
propertyDefaultIfUnset("enableSpotless", false)
propertyDefaultIfUnset("enableJUnit", false)
propertyDefaultIfUnsetWithEnvVar("deploymentDebug", false, "DEPLOYMENT_DEBUG")
// Project property assertions
final String javaSourceDir = 'src/main/java/'
final String scalaSourceDir = 'src/main/scala/'
// If Kotlin is supported, add the path here
final String kotlinSourceDir = 'src/main/kotlin/'
final String modGroupPath = modGroup.toString().replace('.' as char, '/' as char)
final String apiPackagePath = apiPackage.toString().replace('.' as char, '/' as char)
String targetPackageJava = javaSourceDir + modGroupPath
String targetPackageScala = scalaSourceDir + modGroupPath
String targetPackageKotlin = kotlinSourceDir + modGroupPath
// If Kotlin is supported, add the path here
if (!getFile(targetPackageJava).exists() && !getFile(targetPackageScala).exists()) {
throw new GradleException("Could not resolve \"modGroup\"! Could not find ${targetPackageJava} or ${targetPackageScala}")
if (!getFile(targetPackageJava).exists() && !getFile(targetPackageScala).exists() && !getFile(targetPackageKotlin).exists()) {
throw new GradleException("Could not resolve \"modGroup\"! Could not find ${targetPackageJava} or ${targetPackageScala} or ${targetPackageKotlin}")
}
if (apiPackage) {
targetPackageJava = 'src/api/java/' + modGroupPath + '/api'
targetPackageScala = 'src/api/java/' + modGroupPath + '/api'
if (!getFile(targetPackageJava).exists() && !getFile(targetPackageScala).exists()) {
throw new GradleException("Could not resolve \"apiPackage\"! Could not find ${targetPackageJava} or ${targetPackageScala}")
final String endApiPath = modGroupPath + '/' + apiPackagePath
if (useSrcApiPath) {
targetPackageJava = 'src/api/java/' + endApiPath
targetPackageScala = 'src/api/scala/' + endApiPath
targetPackageKotlin = 'src/api/kotlin/' + endApiPath
} else {
targetPackageJava = javaSourceDir + endApiPath
targetPackageScala = scalaSourceDir + endApiPath
targetPackageKotlin = kotlinSourceDir + endApiPath
}
if (!getFile(targetPackageJava).exists() && !getFile(targetPackageScala).exists() && !getFile(targetPackageKotlin).exists()) {
throw new GradleException("Could not resolve \"apiPackage\"! Could not find ${targetPackageJava} or ${targetPackageScala} or ${targetPackageKotlin}")
}
}
@@ -96,8 +139,9 @@ if (usesMixins.toBoolean()) {
final String mixinPackagePath = mixinsPackage.toString().replaceAll('\\.', '/')
targetPackageJava = javaSourceDir + modGroupPath + '/' + mixinPackagePath
targetPackageScala = scalaSourceDir + modGroupPath + '/' + mixinPackagePath
if (!getFile(targetPackageJava).exists()) {
throw new GradleException("Could not resolve \"mixinsPackage\"! Could not find ${targetPackageJava} or ${targetPackageScala}")
targetPackageKotlin = kotlinSourceDir + modGroupPath + '/' + mixinPackagePath
if (!getFile(targetPackageJava).exists() && !getFile(targetPackageScala).exists() && !getFile(targetPackageKotlin).exists()) {
throw new GradleException("Could not resolve \"mixinsPackage\"! Could not find ${targetPackageJava} or ${targetPackageScala} or ${targetPackageKotlin}")
}
}
@@ -106,13 +150,105 @@ if (coreModClass) {
String targetFileJava = javaSourceDir + modGroupPath + '/' + coreModPath + '.java'
String targetFileScala = scalaSourceDir + modGroupPath + '/' + coreModPath + '.scala'
String targetFileScalaJava = scalaSourceDir + modGroupPath + '/' + coreModPath + '.java'
if (!getFile(targetFileJava).exists() && !getFile(targetFileScala).exists() && !getFile(targetFileScalaJava).exists()) {
throw new GradleException("Could not resolve \"coreModClass\"! Could not find " + targetFileJava)
String targetFileKotlin = kotlinSourceDir + modGroupPath + '/' + coreModPath + '.kt'
if (!getFile(targetFileJava).exists() && !getFile(targetFileScala).exists() && !getFile(targetFileScalaJava).exists() && !getFile(targetFileKotlin).exists()) {
throw new GradleException("Could not resolve \"coreModClass\"! Could not find ${targetFileJava} or ${targetFileScala} or ${targetFileScalaJava} or ${targetFileKotlin}")
}
}
// Plugin application
// Scala
if (getFile('src/main/scala').exists()) {
apply plugin: 'scala'
}
if (getFile('src/main/kotlin').exists()) {
apply plugin: 'org.jetbrains.kotlin.jvm'
}
// Kotlin
pluginManager.withPlugin('org.jetbrains.kotlin.jvm') {
kotlin {
jvmToolchain(8)
}
def disabledKotlinTaskList = [
"kaptGenerateStubsMcLauncherKotlin",
"kaptGenerateStubsPatchedMcKotlin",
"kaptGenerateStubsInjectedTagsKotlin",
"compileMcLauncherKotlin",
"compilePatchedMcKotlin",
"compileInjectedTagsKotlin",
"kaptMcLauncherKotlin",
"kaptPatchedMcKotlin",
"kaptInjectedTagsKotlin",
"kspMcLauncherKotlin",
"kspPatchedMcKotlin",
"kspInjectedTagsKotlin",
]
tasks.configureEach { task ->
if (task.name in disabledKotlinTaskList) {
task.enabled = false
}
}
}
// Spotless
//noinspection GroovyAssignabilityCheck
project.extensions.add(com.diffplug.blowdryer.Blowdryer, 'Blowdryer', com.diffplug.blowdryer.Blowdryer) // make Blowdryer available in plugin application
if (enableSpotless.toBoolean()) {
apply plugin: 'com.diffplug.spotless'
// Spotless auto-formatter
// See https://github.com/diffplug/spotless/tree/main/plugin-gradle
// Can be locally toggled via spotless:off/spotless:on comments
spotless {
encoding 'UTF-8'
format 'misc', {
target '.gitignore'
trimTrailingWhitespace()
indentWithSpaces(4)
endWithNewline()
}
java {
target 'src/main/java/**/*.java', 'src/test/java/**/*.java' // exclude api as they are not our files
def orderFile = project.file('spotless.importorder')
if (!orderFile.exists()) {
orderFile = Blowdryer.file('spotless.importorder')
}
def formatFile = project.file('spotless.eclipseformat.xml')
if (!formatFile.exists()) {
formatFile = Blowdryer.file('spotless.eclipseformat.xml')
}
toggleOffOn()
importOrderFile(orderFile)
removeUnusedImports()
endWithNewline()
//noinspection GroovyAssignabilityCheck
eclipse('4.19.0').configFile(formatFile)
}
kotlin {
target 'src/*/kotlin/**/*.kt'
toggleOffOn()
ktfmt('0.39')
trimTrailingWhitespace()
indentWithSpaces(4)
endWithNewline()
}
scala {
target 'src/*/scala/**/*.scala'
scalafmt('3.7.1')
}
}
}
// Git version checking, also checking for if this is a submodule
if (project.file('.git/HEAD').isFile() || project.file('.git').isFile()) {
apply plugin: 'com.palantir.git-version'
@@ -123,6 +259,9 @@ if (usesShadowedDependencies.toBoolean()) {
apply plugin: 'com.github.johnrengelman.shadow'
}
// Configure Java
java {
toolchain {
if (enableModernJavaSyntax.toBoolean()) {
@@ -164,8 +303,11 @@ tasks.withType(ScalaCompile).configureEach {
// Allow others using this buildscript to have custom gradle code run
if (getFile('addon.gradle').exists()) {
apply from: 'addon.gradle'
} else if (getFile('addon.gradle.kts').exists()) {
apply from: 'addon.gradle.kts'
}
// Configure Minecraft
// Try to gather mod version from git tags if version is not manually specified
@@ -181,23 +323,24 @@ if (!modVersion) {
}
}
if (includeMCVersionJar.toBoolean()) {
if (includeMCVersionJar.toBoolean()){
version = "${minecraftVersion}-${modVersion}"
} else {
}
else {
version = modVersion
}
group = modGroup
archivesBaseName = modArchivesBaseName
base {
archivesName = modArchivesBaseName
}
minecraft {
mcVersion = minecraftVersion
username = developmentEnvironmentUserName.toString()
useDependencyAccessTransformers = true
setMcpMappingChannel("stable")
setMcpMappingVersion("39")
// Automatic token injection with RetroFuturaGradle
if (gradleTokenModId) {
injectedTags.put gradleTokenModId, modId
@@ -209,22 +352,30 @@ minecraft {
injectedTags.put gradleTokenVersion, modVersion
}
injectedTags.put("VERSION", project.version)
injectedTags.put("AEVERSION", aeversion)
injectedTags.put("AECHANNEL", aechannel)
injectedTags.put("AEBUILD", aebuild)
// JVM arguments
extraRunJvmArguments.add("-ea:${modGroup}")
if (usesMixins.toBoolean()) {
extraRunJvmArguments.addAll([
'-Dmixin.hotSwap=true',
'-Dmixin.checks.interfaces=true',
'-Dmixin.debug.export=true'
'-Dmixin.hotSwap=true',
'-Dmixin.checks.interfaces=true',
'-Dmixin.debug.export=true'
])
}
if (coreModClass) {
extraRunJvmArguments.add("-Dfml.coreMods.load=${modGroup}.${coreModClass}")
if (enableCoreModDebug.toBoolean()) {
extraRunJvmArguments.addAll([
'-Dlegacy.debugClassLoading=true',
'-Dlegacy.debugClassLoadingFiner=true',
'-Dlegacy.debugClassLoadingSave=true'
])
}
}
if (coreModClass) {
for (runTask in ['runClient', 'runServer']) {
tasks.named(runTask).configure {
extraJvmArgs.add("-Dfml.coreMods.load=${modGroup}.${coreModClass}")
}
}
}
@@ -236,17 +387,6 @@ tasks.named('processIdeaSettings').configure {
dependsOn('injectTags')
}
tasks.register("generateMcModInfo") {
}
tasks.register("generatePackMcMeta") {
}
tasks.named('processIdeaSettings').configure {
dependsOn('injectTags')
}
// Repositories
@@ -263,46 +403,63 @@ repositories.configureEach { repo ->
// Allow adding custom repositories to the buildscript
if (getFile('repositories.gradle').exists()) {
apply from: 'repositories.gradle'
} else if (getFile('repositories.gradle.kts').exists()) {
apply from: 'repositories.gradle.kts'
}
repositories {
exclusiveContent {
forRepository {
//noinspection ForeignDelegate
maven {
name = 'Curse Maven'
url = 'https://www.cursemaven.com'
if (includeWellKnownRepositories.toBoolean() || includeCommonDevEnvMods.toBoolean()) {
exclusiveContent {
forRepository {
//noinspection ForeignDelegate
maven {
name = 'Curse Maven'
url = 'https://www.cursemaven.com'
// url = 'https://beta.cursemaven.com'
}
}
filter {
includeGroup 'curse.maven'
}
}
filter {
includeGroup 'curse.maven'
}
}
exclusiveContent {
forRepository {
//noinspection ForeignDelegate
maven {
name = 'Modrinth'
url = 'https://api.modrinth.com/maven'
exclusiveContent {
forRepository {
//noinspection ForeignDelegate
maven {
name = 'Modrinth'
url = 'https://api.modrinth.com/maven'
}
}
filter {
includeGroup 'maven.modrinth'
}
}
filter {
includeGroup 'maven.modrinth'
maven {
name 'Cleanroom Maven'
url 'https://maven.cleanroommc.com'
}
maven {
name 'BlameJared Maven'
url 'https://maven.blamejared.com'
}
maven {
name 'GTNH Maven'
url 'https://nexus.gtnewhorizons.com/repository/public/'
}
}
maven {
name 'Cleanroom Maven'
url 'https://maven.cleanroommc.com'
if (usesMixins.toBoolean() || forceEnableMixins.toBoolean()) {
// need to add this here even if we did not above
if (!includeWellKnownRepositories.toBoolean()) {
maven {
name 'Cleanroom Maven'
url 'https://maven.cleanroommc.com'
}
}
}
maven {
name 'BlameJared Maven'
url 'https://maven.blamejared.com'
}
gradlePluginPortal()
mavenCentral()
mavenLocal()
mavenLocal() // Must be last for caching to work
}
// Dependencies
// Configure dependency configurations
@@ -318,32 +475,31 @@ configurations {
}
}
String mixinProviderSpec = 'zone.rong:mixinbooter:8.9'
dependencies {
if (usesMixins.toBoolean() || forceEnableMixins.toBoolean()) {
implementation 'zone.rong:mixinbooter:7.0'
String mixin = 'org.spongepowered:mixin:0.8.3'
if (usesMixins.toBoolean()) {
mixin = modUtils.enableMixins(mixin, "mixins.${modId}.refmap.json")
}
api(mixin) {
transitive = false
}
annotationProcessor(mixin) {
transitive = false
}
if (usesMixins.toBoolean()) {
annotationProcessor 'org.ow2.asm:asm-debug-all:5.2'
// should use 24.1.1 but 30.0+ has a vulnerability fix
annotationProcessor 'com.google.guava:guava:30.0-jre'
// should use 2.8.6 but 2.8.9+ has a vulnerability fix
annotationProcessor 'com.google.code.gson:gson:2.8.9'
mixinProviderSpec = modUtils.enableMixins(mixinProviderSpec, "mixins.${modId}.refmap.json")
api (mixinProviderSpec) {
transitive = false
}
annotationProcessor(mixinProviderSpec) {
transitive = false
}
} else if (forceEnableMixins.toBoolean()) {
runtimeOnly(mixinProviderSpec)
}
if (enableJUnit.toBoolean()) {
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1'
testImplementation 'org.hamcrest:hamcrest:2.2'
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
if (enableModernJavaSyntax.toBoolean()) {
@@ -364,8 +520,11 @@ dependencies {
testCompileOnly "me.eigenraven.java8unsupported:java-8-unsupported-shim:1.0.0"
}
compileOnlyApi 'org.jetbrains:annotations:23.0.0'
annotationProcessor 'org.jetbrains:annotations:23.0.0'
compileOnlyApi 'org.jetbrains:annotations:24.1.0'
annotationProcessor 'org.jetbrains:annotations:24.1.0'
patchedMinecraft('net.minecraft:launchwrapper:1.17.2') {
transitive = false
}
if (includeCommonDevEnvMods.toBoolean()) {
implementation 'mezz.jei:jei_1.12.2:4.16.1.302'
@@ -374,11 +533,20 @@ dependencies {
}
}
if (getFile('gradle/scripts/dependencies.gradle').exists()) {
apply from: 'gradle/scripts/dependencies.gradle'
pluginManager.withPlugin('org.jetbrains.kotlin.kapt') {
if (usesMixins.toBoolean()) {
dependencies {
kapt(mixinProviderSpec)
}
}
}
if (getFile('dependencies.gradle').exists()) {
apply from: 'dependencies.gradle'
} else if (getFile('dependencies.gradle.kts').exists()) {
apply from: 'dependencies.gradle.kts'
}
apply from: 'gradle/scripts/optional.gradle'
// Test configuration
@@ -412,6 +580,7 @@ test {
}
}
// Resource processing and jar building
processResources {
@@ -464,20 +633,20 @@ tasks.register('generateAssets') {
mcmodInfoFile.text = """[{
"modid": "\${modid}",
"name": "\${modname}",
"description": "A Mod about Matter, Energy and using them to conquer the world..",
"description": "An example mod for Minecraft 1.12.2 with Forge",
"version": "\${version}",
"mcversion": "\${mcversion}",
"logoFile": "assets/appliedenergistics2/meta/logo.png",
"url": "https://github.com/PrototypeTrousers/Applied-Energistics-2",
"authorList": ["AlgorithmX2"],
"credits": "AlgorithmX2",
"logoFile": "",
"url": "",
"authorList": [],
"credits": "",
"dependencies": []
}]
"""
}
// mixins.{modid}.json
if (usesMixins.toBoolean()) {
if (usesMixins.toBoolean() && generateMixinConfig.toBoolean()) {
def mixinConfigFile = getFile("src/main/resources/mixins.${modId}.json")
if (!mixinConfigFile.exists()) {
def mixinConfigRefmap = "mixins.${modId}.refmap.json"
@@ -514,26 +683,49 @@ jar {
}
}
from sourceSets.api.output
dependsOn apiClasses
if (useSrcApiPath && apiPackage) {
from sourceSets.api.output
dependsOn apiClasses
// specify which files are really included, can control which APIs should be in
include "appeng/**"
include "assets/**"
include "mcmod.info"
include "pack.mcmeta"
include "META-INF/appliedenergistics2_at.cfg"
include "${modGroupPath}/**"
include "assets/**"
include "mcmod.info"
include "pack.mcmeta"
if (accessTransformersFile) {
include "META-INF/${accessTransformersFile}"
}
}
}
// Configure default run tasks
if (separateRunDirectories.toBoolean()) {
runClient {
workingDir = file('run/client')
}
runServer {
workingDir = file('run/server')
}
}
// Create API library jar
tasks.register('apiJar', Jar) {
archiveClassifier.set 'api'
from(sourceSets.api.java) {
include "${modGroupPath}/${apiPackagePath}/**"
}
if (useSrcApiPath) {
from(sourceSets.api.java) {
include "${modGroupPath}/${apiPackagePath}/**"
}
from(sourceSets.api.output) {
include "${modGroupPath}/${apiPackagePath}/**"
}
} else {
from(sourceSets.main.java) {
include "${modGroupPath}/${apiPackagePath}/**"
}
from(sourceSets.api.output) {
include "${modGroupPath}/${apiPackagePath}/**"
from(sourceSets.main.output) {
include "${modGroupPath}/${apiPackagePath}/**"
}
}
}
@@ -566,7 +758,7 @@ if (usesShadowedDependencies.toBoolean()) {
finalizedBy(tasks.shadowJar)
}
tasks.named('reobfJar', ReobfuscatedJar) {
inputJar.set(tasks.named('shadowJar', ShadowJar).flatMap({ it.archiveFile }))
inputJar.set(tasks.named('shadowJar', ShadowJar).flatMap({it.archiveFile}))
}
AdhocComponentWithVariants javaComponent = (AdhocComponentWithVariants) project.components.findByName('java')
javaComponent.withVariantsFromConfiguration(configurations.shadowRuntimeElements) {
@@ -701,7 +893,7 @@ tasks.register('generateChangelog') {
.collect { ['--', it] }).flatten())
if (changelog) {
changelog = "Changes since ${lastTag}:\n${{ ("\n" + changelog).replaceAll("\n", "\n* ") }}"
changelog = "Changes since ${lastTag}:\n${{("\n" + changelog).replaceAll("\n", "\n* ")}}"
}
def f = getFile('build/changelog.md')
changelog = changelog ?: 'There have been no changes.'
@@ -727,7 +919,7 @@ if (cfApiKey.isPresent() || deploymentDebug.toBoolean()) {
def changelogFile = getChangelog()
def changelogRaw = changelogFile.exists() ? changelogFile.getText('UTF-8') : ""
mainFile.displayName = "${modName}: ${modVersion}"
mainFile.displayName = versionDisplayFormat.replace('$MOD_NAME', modName).replace('$VERSION', modVersion)
mainFile.releaseType = getReleaseType()
mainFile.changelog = changelogRaw
mainFile.changelogType = 'markdown'
@@ -743,6 +935,12 @@ if (cfApiKey.isPresent() || deploymentDebug.toBoolean()) {
}
String[] parts = dep.split(':')
String type = parts[0], slug = parts[1]
def types = [
'req' : 'requiredDependency', 'required': 'requiredDependency',
'opt' : 'optionalDependency', 'optional': 'optionalDependency',
'embed' : 'embeddedLibrary', 'embedded': 'embeddedLibrary',
'incomp': 'incompatible', 'fail' : 'incompatible']
if (types.containsKey(type)) type = types[type]
if (!(type in ['requiredDependency', 'embeddedLibrary', 'optionalDependency', 'tool', 'incompatible'])) {
throw new Exception('Invalid Curseforge dependency type: ' + type)
}
@@ -767,6 +965,7 @@ if (modrinthApiKey.isPresent() || deploymentDebug.toBoolean()) {
modrinth {
token = modrinthApiKey.getOrElse('debug_token')
projectId = modrinthProjectId
versionName = versionDisplayFormat.replace('$MOD_NAME', modName).replace('$VERSION', modVersion)
changelog = changelogFile.exists() ? changelogFile.getText('UTF-8') : ""
versionType = getReleaseType()
versionNumber = modVersion
@@ -784,7 +983,7 @@ if (modrinthApiKey.isPresent() || deploymentDebug.toBoolean()) {
}
String[] parts = dep.split(':')
String[] qual = parts[0].split('-')
addModrinthDep(qual[0], qual[1], parts[1])
addModrinthDep(qual[0], qual.length > 1 ? qual[1] : 'project', parts[1])
}
}
tasks.modrinth.dependsOn(build)
@@ -793,9 +992,17 @@ if (modrinthApiKey.isPresent() || deploymentDebug.toBoolean()) {
def addModrinthDep(String scope, String type, String name) {
com.modrinth.minotaur.dependencies.Dependency dep
def types = [
'req' : 'required',
'opt' : 'optional',
'embed' : 'embedded',
'incomp': 'incompatible', 'fail': 'incompatible']
if (types.containsKey(scope)) scope = types[scope]
if (!(scope in ['required', 'optional', 'incompatible', 'embedded'])) {
throw new Exception('Invalid modrinth dependency scope: ' + scope)
}
types = ['proj': 'project', '': 'project', 'p': 'project', 'ver': 'version', 'v': 'version']
if (types.containsKey(type)) type = types[type]
switch (type) {
case 'project':
dep = new ModDependency(name, scope)
@@ -823,8 +1030,8 @@ if (customMavenPublishUrl) {
}
// providers is not available here, use System for getting env vars
groupId = System.getenv('ARTIFACT_GROUP_ID') ?: project.group
artifactId = System.getenv('ARTIFACT_ID') ?: project.name
groupId = System.getenv('ARTIFACT_GROUP_ID') ?: project.mavenArtifactGroup
artifactId = System.getenv('ARTIFACT_ID') ?: project.modArchivesBaseName
version = System.getenv('RELEASE_VERSION') ?: publishedVersion
}
}
@@ -862,7 +1069,6 @@ def getReleaseType() {
* Next, if 'generateDefaultChangelog' option is enabled, use that.
* Otherwise, try to use a CHANGELOG.md file at root directory.
*/
def getChangelog() {
def final changelogEnv = providers.environmentVariable('CHANGELOG_LOCATION')
if (changelogEnv.isPresent()) {
@@ -877,7 +1083,7 @@ def getChangelog() {
// Buildscript updating
def buildscriptGradleVersion = '8.1.1'
def buildscriptGradleVersion = '8.5'
tasks.named('wrapper', Wrapper).configure {
gradleVersion = buildscriptGradleVersion
@@ -912,29 +1118,18 @@ static URL availableBuildScriptUrl() {
new URL("https://raw.githubusercontent.com/GregTechCEu/Buildscripts/master/build.gradle")
}
static URL exampleSettingsGradleUrl() {
static URL availableSettingsGradleUrl() {
new URL("https://raw.githubusercontent.com/GregTechCEu/Buildscripts/master/settings.gradle")
}
boolean verifySettingsGradle() {
def settingsFile = getFile("settings.gradle")
if (!settingsFile.exists()) {
println("Downloading default settings.gradle")
exampleSettingsGradleUrl().withInputStream { i -> settingsFile.withOutputStream { it << i } }
return true
}
return false
}
boolean performBuildScriptUpdate() {
if (isNewBuildScriptVersionAvailable()) {
def buildscriptFile = getFile("build.gradle")
def settingsFile = getFile("settings.gradle")
availableBuildScriptUrl().withInputStream { i -> buildscriptFile.withOutputStream { it << i } }
availableSettingsGradleUrl().withInputStream { i -> settingsFile.withOutputStream { it << i } }
def out = services.get(StyledTextOutputFactory).create('buildscript-update-output')
out.style(Style.Success).print("Build script updated. Please REIMPORT the project or RESTART your IDE!")
if (verifySettingsGradle()) {
throw new GradleException("Settings has been updated, please re-run task.")
}
return true
}
return false
@@ -981,6 +1176,11 @@ tasks.register('faq') {
// Helpers
def getDefaultArtifactGroup() {
def lastIndex = project.modGroup.lastIndexOf('.')
return lastIndex < 0 ? project.modGroup : project.modGroup.substring(0, lastIndex)
}
def getFile(String relativePath) {
return new File(projectDir, relativePath)
}
@@ -1024,4 +1224,4 @@ def getLastTag() {
def githubTag = providers.environmentVariable('GITHUB_TAG')
return runShell('git describe --abbrev=0 --tags ' +
(githubTag.isPresent() ? runShell('git rev-list --tags --skip=1 --max-count=1') : ''))
}
}
+52
View File
@@ -0,0 +1,52 @@
//file:noinspection DependencyNotationArgument
// TODO remove when fixed in RFG ^
/*
* Add your dependencies here. Common configurations:
* - implementation("group:name:version:classifier"): if you need this for internal implementation details of the mod.
* Available at compiletime and runtime for your environment.
*
* - compileOnlyApi("g:n:v:c"): if you need this for internal implementation details of the mod.
* Available at compiletime but not runtime for your environment.
*
* - annotationProcessor("g:n:v:c"): mostly for java compiler plugins, if you know you need this, use it, otherwise don't worry
*
* - testCONFIG("g:n:v:c"): replace CONFIG by one of the above, same as above but for the test sources instead of main
*
* You can exclude transitive dependencies (dependencies of the chosen dependency) by appending { transitive = false } if needed.
*
* To add a mod with CurseMaven, replace '("g:n:v:c")' in the above with 'rfg.deobf("curse.maven:project_slug-project_id:file_id")'
* Example: implementation rfg.deobf("curse.maven:gregtech-ce-unofficial-557242:4527757")
*
* To shadow a dependency, use 'shadowImplementation'. For more info, see https://github.com/GregTechCEu/Buildscripts/blob/master/docs/shadow.md
*
* For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph
*/
dependencies {
// Mods always in-game
implementation rfg.deobf("curse.maven:gregtechceu-557242:4429261") // GTCEu
implementation rfg.deobf("curse.maven:codechicken-lib-1-8-242818:2779848") // CCL 3.2.3.358
implementation rfg.deobf("curse.maven:baubles-227083:2518667") // Baubles
implementation rfg.deobf("curse.maven:industrial-craft-242638:2547175") // IC2
implementation rfg.deobf("curse.maven:forestry-59751:2684780") // Forestry
// Mods only in code by default
compileOnly "curse.maven:chisel-235279:2915375"
compileOnly "curse.maven:hwyla-253449:2568751"
compileOnly "curse.maven:recipe-stages-280554:3405072"
compileOnly "curse.maven:item-stages-280316:2696769"
compileOnly "curse.maven:game-stages-268655:2951844"
compileOnly "net.darkhax.tesla:Tesla-1.12.2:1.0.63"
compileOnly "curse.maven:CoFHCore-69162:2920433"
compileOnly "CraftTweaker2:CraftTweaker2-API:4.1.20.684"
compileOnly "curse.maven:inventory-tweaks-223094:2482482"
compileOnly "curse.maven:inventory-bogo-sorter-632327:4399738"
compileOnly rfg.deobf("curse.maven:ctm-267602:2915363") // CTM 1.0.2.31
compileOnly rfg.deobf("curse.maven:actually-additions-228404:3117927") // ActuallyAdditions r152
}
minecraft {
injectedTags.put('AEVERSION', aeversion)
injectedTags.put('AECHANNEL', aechannel)
injectedTags.put('AEBUILD', aebuild)
}
+109 -73
View File
@@ -1,148 +1,184 @@
modName = AE2 Unofficial Extended Life
# This is a case-sensitive string to identify your mod. Convention is to use lower case.
modId = appliedenergistics2
modGroup = appeng
# Version of your mod.
# This field can be left empty if you want your mod's version to be determined by the latest git tag instead.
modVersion =
# AE2 Specific Version Settings
aeversion=rv6
aechannel=stable
aebuild=7
aegroup=appeng
aebasename=appliedenergistics2
#########################################################
# Versions #
#########################################################
minecraft_version=1.12.2
mcp_mappings=snapshot_20171003
forge_version=14.23.5.2847
#########################################################
# Installable #
#########################################################
hwyla_version=1.8.26-B41_1.12.2
#########################################################
# Provided APIs #
#########################################################
jei_version=4.16.1.302
tesla_version=1.0.63
ic2_version=2.8.73-ex112
top_version=1.12-1.4.23-16
crafttweaker_version=4.1.20.684
ctm_version=MC1.12.2-0.3.1.16
forestry_version=5.8.2.387
#########################################################
# Deployment #
#########################################################
website_version=1.12.2
curse_versions=1.12.2
mapping_channel=snapshot
mapping_version=20171003
# Run Configurations
minecraft_username=Developer
extra_jvm_args=
modName=AE2 Unofficial Extended Life
# This is a case-sensitive string to identify your mod. Convention is to use lower case.
modId=appliedenergistics2
modGroup=appeng
# Version of your mod.
# This field can be left empty if you want your mod's version to be determined by the latest git tag instead.
modVersion=rv6-stable-7-extended_life-v0.55.29
# Whether to use the old jar naming structure (modid-mcversion-version) instead of the new version (modid-version)
includeMCVersionJar=false
includeMCVersionJar = false
# The name of your jar when you produce builds, not including any versioning info
modArchivesBaseName=appliedenergistics2
modArchivesBaseName = ae2-uel
# Will update your build.gradle automatically whenever an update is available
autoUpdateBuildScript=false
minecraftVersion=1.12.2
autoUpdateBuildScript = false
minecraftVersion = 1.12.2
# Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you
# restart Minecraft in development. Choose this dependent on your mod:
# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name
# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty
# Alternatively this can be set with the 'DEV_USERNAME' environment variable.
developmentEnvironmentUserName=Developer
developmentEnvironmentUserName = Developer
# Enables using modern java syntax (up to version 17) via Jabel, while still targeting JVM 8.
# See https://github.com/bsideup/jabel for details on how this works.
# Using this requires that you use a Java 17 JDK for development.
enableModernJavaSyntax=true
enableModernJavaSyntax = true
# Generate a class with String fields for the mod id, name and version named with the fields below
generateGradleTokenClass=appeng.Tags
gradleTokenModId=
gradleTokenModName=
gradleTokenVersion=VERSION
generateGradleTokenClass = appeng.Tags
gradleTokenModId = MODID
gradleTokenModName = MODNAME
gradleTokenVersion = VERSION
# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can
# leave this property empty.
# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api
apiPackage=api
apiPackage = api
# If you want to keep your API code in src/api instead of src/main
useSrcApiPath = true
# Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/
# There can be multiple files in a comma-separated list.
# Example value: mymodid_at.cfg,jei_at.cfg
accessTransformersFile=appliedenergistics2_at.cfg
accessTransformersFile = appliedenergistics2_at.cfg
# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled!
usesMixins=false
usesMixins = false
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
mixinsPackage=
mixinsPackage =
# Automatically generates a mixin config json if enabled, with the name mixins.modid.json
generateMixinConfig = false
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
# Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin
coreModClass=core.AE2ELCore
coreModClass = core.AE2ELCore
# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod (meaning that
# there is no class annotated with @Mod) you want this to be true. When in doubt: leave it on false!
containsMixinsAndOrCoreModOnly=false
containsMixinsAndOrCoreModOnly = false
# Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins.
forceEnableMixins=false
forceEnableMixins = false
# Outputs pre-transformed and post-transformed loaded classes to run/CLASSLOADER_TEMP. Can be used in combination with
# diff to see exactly what your ASM or Mixins are changing in the target file.
# Optionally can be specified with the 'CORE_MOD_DEBUG' env var. Will output a lot of files!
enableCoreModDebug = false
# Adds CurseMaven, Modrinth Maven, BlameJared maven, and some more well-known 1.12.2 repositories
includeWellKnownRepositories=true
includeWellKnownRepositories = true
# Adds JEI and TheOneProbe to your development environment. Adds them as 'implementation', meaning they will
# be available at compiletime and runtime for your mod (in-game and in-code).
# Overrides the above setting to be always true, as these repositories are needed to fetch the mods
includeCommonDevEnvMods=true
includeCommonDevEnvMods = true
# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated in your jar. It is your
# responsibility check the licence and request permission for distribution, if required.
usesShadowedDependencies=false
usesShadowedDependencies = false
# If disabled, won't remove unused classes from shaded dependencies. Some libraries use reflection to access
# their own classes, making the minimization unreliable.
minimizeShadowedDependencies=true
minimizeShadowedDependencies = true
# If disabled, won't rename the shadowed classes.
relocateShadowedDependencies=true
relocateShadowedDependencies = true
# Separate run directories into "run/client" for runClient task, and "run/server" for runServer task.
# Useful for debugging a server and client simultaneously. If not enabled, it will be in the standard location "run/"
separateRunDirectories = false
# The display name format of versions published to Curse and Modrinth. $MOD_NAME and $VERSION are available variables.
# Default: $MOD_NAME \u2212 $VERSION. \u2212 is the minus character which looks much better than the hyphen minus on Curse.
versionDisplayFormat = $MOD_NAME \u2212 $VERSION
# Publishing to modrinth requires you to set the MODRINTH_API_KEY environment variable to your current modrinth API token.
# The project's ID on Modrinth. Can be either the slug or the ID.
# Leave this empty if you don't want to publish on Modrinth.
# Alternatively this can be set with the 'MODRINTH_PROJECT_ID' environment variable.
modrinthProjectId=
modrinthProjectId =
# The project's relations on Modrinth. You can use this to refer to other projects on Modrinth.
# Syntax: scope1-type1:name1;scope2-type2:name2;...
# Where scope can be one of [required, optional, incompatible, embedded],
# type can be one of [project, version],
# and the name is the Modrinth project or version slug/id of the other mod.
# Example: required-project:jei;optional-project:top;incompatible-project:gregtech
modrinthRelations=
modrinthRelations =
# Publishing to CurseForge requires you to set the CURSEFORGE_API_KEY environment variable to one of your CurseForge API tokens.
# The project's numeric ID on CurseForge. You can find this in the About Project box.
# Leave this empty if you don't want to publish on CurseForge.
# Alternatively this can be set with the 'CURSEFORGE_PROJECT_ID' environment variable.
curseForgeProjectId=
curseForgeProjectId =
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
# Syntax: type1:name1;type2:name2;...
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
# and the name is the CurseForge project slug of the other mod.
# Example: requiredDependency:railcraft;embeddedLibrary:cofhlib;incompatible:buildcraft
curseForgeRelations=
curseForgeRelations =
# This project's release type on CurseForge and/or Modrinth
# Alternatively this can be set with the 'RELEASE_TYPE' environment variable.
# Allowed types: release, beta, alpha
releaseType=beta
releaseType = release
# Generate a default changelog for releases. Requires git to be installed, as it uses it to generate a changelog of
# commits since the last tagged release.
generateDefaultChangelog=false
generateDefaultChangelog = false
# Prevent the source code from being published
noPublishedSources=false
noPublishedSources = false
# Publish to a custom maven location. Follows a few rules:
# Group ID can be set with the 'ARTIFACT_GROUP_ID' environment variable, default to 'project.group'
# Artifact ID can be set with the 'ARTIFACT_ID' environment variable, default to 'project.name'
# Version can be set with the 'RELEASE_VERSION' environment variable, default to 'modVersion'
# For maven credentials:
# Username is set with the 'MAVEN_USER' environment variable, default to "NONE"
# Password is set with the 'MAVEN_PASSWORD' environment variable, default to "NONE"
customMavenPublishUrl =
# The group for maven artifacts. Defaults to the 'project.modGroup' until the last '.' (if any).
# So 'mymod' becomes 'mymod' and 'com.myname.mymodid' 'becomes com.myname'
mavenArtifactGroup =
# Enable spotless checks
# Enforces code formatting on your source code
# By default this will use the files found here: https://github.com/GregTechCEu/Buildscripts/tree/master/spotless
# to format your code. However, you can create your own version of these files and place them in your project's
# root directory to apply your own formatting options instead.
enableSpotless=false
enableSpotless = false
# Enable JUnit testing platform used for testing your code.
# Uses JUnit 5. See guide and documentation here: https://junit.org/junit5/docs/current/user-guide/
enableJUnit=true
enableJUnit = true
# Deployment debug setting
# Uncomment this to test deployments to CurseForge and Modrinth
# Alternatively, you can set the 'DEPLOYMENT_DEBUG' environment variable.
deploymentDebug=false
deploymentDebug = false
# Gradle Settings
# Effectively applies the '--stacktrace' flag by default
org.gradle.logging.stacktrace=all
org.gradle.logging.stacktrace = all
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
# This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs=-Xmx3G
org.gradle.jvmargs = -Xmx3G
-116
View File
@@ -1,116 +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 {
url "https://cursemaven.com"
}
maven {
name = "CurseForge"
url = "https://minecraft.curseforge.com/api/maven/"
}
maven {
name "Mobius"
url "http://mobiusstrip.eu/maven"
}
maven {
name = "JEI repo"
url "http://dvs1.progwml6.com/files/maven"
}
maven {
name "Ellpeck"
url "https://maven.ellpeck.de"
}
maven {
name = "CoFH Maven"
url = "http://maven.covers1624.net"
}
maven { // TheOneProbe
name 'tterrag maven'
url "http://maven.tterrag.com/"
}
maven { // McJtyLib
name 'mcjty'
url "http://maven.k-4u.nl/"
}
maven { // CraftTweaker
name 'jared maven'
url "http://maven.blamejared.com/"
}
//maven { // modmaven, maven proxy
// name 'modmaven'
// url "https://modmaven.k-4u.nl/"
//}
}
configurations {
mods
}
dependencies {
// deobfCompile "gregtechce:gregtech:1.12.2:1.15.1.735"
// installable runtime dependencies
implementation rfg.deobf("curse.maven:gregtechceu-557242:4429261")
compileOnly "curse.maven:chisel-235279:2915375"
implementation rfg.deobf("curse.maven:baubles-227083:2518667")
//mods "mcp.mobius.waila:Hwyla:${hwyla_version}"
mods "curse.maven:hwyla-253449:2568751"
mods "net.industrial-craft:industrialcraft-2:${ic2_version}:dev"
mods "mcjty.theoneprobe:TheOneProbe-${minecraft_version}:${top_version}"
// compile against provided APIs
compileOnly "mezz.jei:jei_${minecraft_version}:${jei_version}:api"
//compileOnly "mcp.mobius.waila:Hwyla:${hwyla_version}"
compileOnly "curse.maven:hwyla-253449:2568751"
//Code chicken lib, GTCE dependency
implementation rfg.deobf("curse.maven:CCL-242818:2779848")
compileOnly "curse.maven:recipe-stages-280554:3405072"
compileOnly "curse.maven:item-stages-280316:2696769"
compileOnly "curse.maven:game-stages-268655:2951844"
compileOnly "net.darkhax.tesla:Tesla-1.12.2:${tesla_version}"
//compileOnly "net.industrial-craft:industrialcraft-2:${ic2_version}:api"
implementation rfg.deobf("curse.maven:industrial-craft-242638:2547175")
compileOnly "mcjty.theoneprobe:TheOneProbe-1.12:${top_version}:api"
compileOnly "curse.maven:CoFHCore-69162:2920433"
compileOnly "CraftTweaker2:CraftTweaker2-API:${crafttweaker_version}"
compileOnly "curse.maven:inventory-tweaks-223094:2482482"
compileOnly "curse.maven:inventory-bogo-sorter-632327:4399738"
compileOnly "team.chisel.ctm:CTM:${ctm_version}"
compileOnly "de.ellpeck.actuallyadditions:ActuallyAdditions:1.12.2-r152.16:api"
implementation rfg.deobf("curse.maven:forestry-59751:2684780")
// at runtime, use the full JEI jar
runtimeOnly "mezz.jei:jei_${minecraft_version}:${jei_version}"
// unit test dependencies
testImplementation "junit:junit:4.12"
}
-54
View File
@@ -1,54 +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>.
*/
// HWYLA
tasks.register('installHwyla', Copy) {
dependsOn "deinstallHwyla"
from { configurations.mods }
include "**/*Hwyla*.jar"
into file("/run/mods")
}
tasks.register('deinstallHwyla', Delete) {
delete fileTree(dir: "/run/mods", include: "*Hwyla*.jar")
}
// IC2
tasks.register('installIC2', Copy) {
dependsOn "deinstallIC2"
from { configurations.mods }
include "**/*industrialcraft-2*.jar"
into file("/run/mods")
}
tasks.register('deinstallIC2', Delete) {
delete fileTree(dir: "/run/mods", include: "*industrialcraft-2*.jar")
}
// TOP
tasks.register('installTop', Copy) {
dependsOn["deinstallTop"]
from { configurations.mods }
include "**/*TheOneProbe*.jar"
into file("/run/mods")
}
tasks.register('deinstallTop', Delete) {
delete fileTree(dir: "/run/mods", include: "*TheOneProbe*.jar")
}
+2 -1
View File
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+8 -4
View File
@@ -85,9 +85,6 @@ done
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,10 +130,13 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
@@ -197,6 +197,10 @@ if "$cygwin" || "$msys" ; then
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
Vendored
+32 -24
View File
@@ -1,4 +1,20 @@
@if "%DEBUG%" == "" @echo off
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -9,19 +25,23 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +55,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,38 +65,26 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
+9 -5
View File
@@ -3,9 +3,7 @@ pluginManagement {
maven {
// RetroFuturaGradle
name 'GTNH Maven'
//noinspection HttpUrlsUsage
url 'http://jenkins.usrv.eu:8081/nexus/content/groups/public/'
allowInsecureProtocol = true
url 'https://nexus.gtnewhorizons.com/repository/public/'
//noinspection GroovyAssignabilityCheck
mavenContent {
includeGroup 'com.gtnewhorizons'
@@ -19,8 +17,14 @@ pluginManagement {
}
plugins {
id 'com.diffplug.blowdryerSetup' version '1.7.0'
// Automatic toolchain provisioning
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.4.0'
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0'
}
rootProject.name = rootProject.projectDir.getName()
blowdryerSetup {
repoSubfolder 'spotless'
github 'GregTechCEu/Buildscripts', 'tag', 'v1.0.7'
}
rootProject.name = rootProject.projectDir.getName()
+5 -1
View File
@@ -81,7 +81,11 @@ public enum Settings
PLACE_BLOCK( EnumSet.of( YesNo.YES, YesNo.NO ) ),
SCHEDULING_MODE( EnumSet.allOf( SchedulingMode.class ) );
SCHEDULING_MODE( EnumSet.allOf( SchedulingMode.class ) ),
STICKY_MODE( EnumSet.of( YesNo.YES, YesNo.NO ) ),
;
private final EnumSet<? extends Enum<?>> values;
@@ -40,6 +40,7 @@ public enum Upgrades {
REDSTONE(0),
CRAFTING(0),
MAGNET(0),
STICKY(0),
/**
* Diamond Tier Upgrades.
@@ -100,6 +100,8 @@ public interface IMaterials {
IItemDefinition cardCrafting();
IItemDefinition cardSticky();
IItemDefinition enderDust();
IItemDefinition flour();
@@ -41,6 +41,13 @@ import appeng.api.util.AEPartLocation;
public interface IFacadeContainer
{
/**
* Checks if the {@link IFacadePart} can be added to the given side.
*
* @return true if the facade can be successfully added
*/
boolean canAddFacade( IFacadePart a );
/**
* Attempts to add the {@link IFacadePart} to the given side.
*
+50 -26
View File
@@ -24,6 +24,7 @@
package appeng.api.parts;
import appeng.api.util.AEPartLocation;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumActionResult;
@@ -32,35 +33,11 @@ import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nullable;
public interface IPartHelper
{
/**
* Register a new layer with the part layer system, this allows you to write an in between between tile entities and
* parts.
*
* AE By Default includes,
*
* 1. ISidedInventory ( and by extension IInventory. )
*
* 2. IFluidHandler Forge Fluids
*
* 3. IPowerEmitter BC Power output.
*
* 4. IPowerReceptor BC Power input.
*
* 5. IEnergySink IC2 Power input.
*
* 6. IEnergySource IC2 Power output.
*
* 7. IPipeConnection BC Pipe Connections
*
* As long as a valid layer is registered for a interface you can simply implement that interface on a part get
* implement it.
*
* @return true on success, false on failure, usually a error will be logged as well.
*/
boolean registerNewLayer( String string, String layerInterface );
/**
* use in use item, to try and place a IBusItem
@@ -79,4 +56,51 @@ public interface IPartHelper
* @return the render mode
*/
CableRenderMode getCableRenderMode();
/**
* Try to get a part at a specific place in the world.
*
* @param w world the part is in
* @param pos pos of the part host
* @param side side to test for a part on.
*
* @return the part if it exists, null otherwise
*/
@Nullable
IPart getPart( World w, BlockPos pos, AEPartLocation side );
/**
* Try to get a part host at a specific place in the world.
*
* @param w world the part host is in
* @param pos pos of the part host
*
* @return the part host if it exists, null otherwise
*/
@Nullable
IPartHost getPartHost( World w, BlockPos pos );
/**
* Get a part host if it exists, or place one if it doesn't.
*
* @param w world the part host is in
* @param pos pos to get or place the part host
* @param force whether to skip permission and existing block checks and forcibly place the part host here.
* @param p the placing player, or null if none
*
* @return the existing or created part host, or null if it didn't already exist and part host is unable to be placed.
*/
@Nullable
IPartHost getOrPlacePartHost( World w, BlockPos pos, boolean force, @Nullable EntityPlayer p );
/**
* Test if a part host can be successfully placed at a given position by the provided player.
*
* @param w world the part host is in
* @param pos pos to test for part host placement
* @param p the placing player, or null if none
*
* @return if the part can be placed at the provided world and position
*/
boolean canPlacePartHost( World w, BlockPos pos, @Nullable EntityPlayer p );
}
+13 -7
View File
@@ -145,13 +145,24 @@ public interface IPartHost extends ICustomCableConnection
*/
SelectedPart selectPart( Vec3d pos );
/**
* Same as {@link #selectPart(Vec3d)}, but with global instead of local coordinates.
*/
default SelectedPart selectPartGlobal( Vec3d pos ) {
DimensionalCoord globalPos = getLocation();
return selectPart(pos.subtract(
globalPos.getPos().getX(),
globalPos.getPos().getY(),
globalPos.getPos().getZ()));
}
/**
* can be used by parts to trigger the tile or part to save.
*/
void markForSave();
/**
* part of the {@link LayerBase}
* called when parts are added or removed
*/
void partChanged();
@@ -169,11 +180,6 @@ public interface IPartHost extends ICustomCableConnection
*/
boolean isEmpty();
/**
* @return a mutable list of flags you can adjust to track state.
*/
Set<LayerFlags> getLayerFlags();
/**
* remove host from world...
*/
@@ -191,4 +197,4 @@ public interface IPartHost extends ICustomCableConnection
*/
boolean isInWorld();
}
}
@@ -1,98 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2013 AlgorithmX2
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package appeng.api.parts;
import java.util.Set;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import appeng.api.util.AEPartLocation;
/**
* All Layers must extends this, this get part implementation is provided to interface with the parts, however a real
* implementation will be used at runtime.
*
* TODO: Consider removing and replacing with capabilities.
*/
public abstract class LayerBase extends TileEntity // implements IPartHost
{
/**
* Grants access for the layer to the parts of the host.
*
* This Method looks silly, that is because its not used at runtime, a real implementation will be used instead.
*
* @param side side of part
*
* @return the part for the requested side.
*/
public IPart getPart( final AEPartLocation side )
{
return null; // place holder.
}
/**
* Grants access for the layer to the parts of the host.
*
* This Method looks silly, that is because its not used at runtime, a real implementation will be used instead.
*
* @param side side of part
*
* @return the part for the requested side.
*/
public IPart getPart( final EnumFacing side )
{
return null; // place holder.
}
/**
* called when the parts change in the container, YOU MUST CALL super.PartChanged();
*/
public void notifyNeighbors()
{
}
/**
* called when the parts change in the container, YOU MUST CALL super.PartChanged();
*/
public void partChanged()
{
}
/**
* @return a mutable list of flags you can adjust to track state.
*/
public Set<LayerFlags> getLayerFlags()
{
return null; // place holder.
}
public void markForSave()
{
// something!
}
}
@@ -1,35 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2013 AlgorithmX2
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package appeng.api.parts;
/**
* TODO: Consider removing and replacing with capabilities.
*/
public enum LayerFlags
{
IC2_ENET
}
@@ -89,4 +89,12 @@ public interface IMEInventoryHandler<T extends IAEStack<T>> extends IMEInventory
* @return true, if this inventory is valid for this pass.
*/
boolean validForPass( int i );
/**
* Gets whether an inventory is "Sticky" i.e. only it and other sticky storages that have partitions with certain
* items are allowed to be put into sticky storages.
*/
default boolean isSticky() {
return false;
}
}
@@ -29,9 +29,10 @@ import appeng.block.AEBaseTileBlock;
import appeng.client.UnlistedProperty;
import appeng.client.render.cablebus.CableBusBakedModel;
import appeng.client.render.cablebus.CableBusRenderState;
import appeng.core.Api;
import appeng.client.render.cablebus.FacadeRenderState;
import appeng.core.AppEng;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketCableBusLandingParticle;
import appeng.core.sync.packets.PacketClick;
import appeng.helpers.AEGlassMaterial;
import appeng.integration.abstraction.IAEFacade;
@@ -71,10 +72,12 @@ import net.minecraft.util.math.RayTraceResult.Type;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.property.ExtendedBlockState;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.IUnlistedProperty;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@@ -91,10 +94,6 @@ public class BlockCableBus extends AEBaseTileBlock implements IAEFacade {
private static final ICableBusContainer NULL_CABLE_BUS = new NullCableBusContainer();
private static Class<? extends AEBaseTile> noTesrTile;
private static Class<? extends AEBaseTile> tesrTile;
public BlockCableBus() {
super(AEGlassMaterial.INSTANCE);
this.setLightOpacity(0);
@@ -303,6 +302,90 @@ public class BlockCableBus extends AEBaseTileBlock implements IAEFacade {
return true;
}
@Override
public boolean addRunningEffects(IBlockState state, World world, BlockPos pos, Entity entity) {
if (world.isRemote) {
addRunningParticle(world, pos, entity);
}
return true;
}
@SideOnly(Side.CLIENT)
private void addRunningParticle(World world, BlockPos pos, Entity entity) {
final ICableBusContainer cb = this.cb(world, pos);
final IBakedModel model = Minecraft.getMinecraft().getBlockRendererDispatcher().getModelForState(this.getDefaultState());
if (!(model instanceof CableBusBakedModel cableBusModel)) {
return;
}
final CableBusRenderState renderState = cb.getRenderState();
final TextureAtlasSprite texture = getSpriteForParticle(renderState, cableBusModel);
if (texture != null) {
final double d0 = entity.posX + (world.rand.nextFloat() - 0.5f) * entity.width;
final double d1 = entity.getEntityBoundingBox().minY + 0.1f;
final double d2 = entity.posZ + (world.rand.nextFloat() - 0.5f) * entity.width;
final ParticleDigging particle = new DestroyFX(world, d0, d1, d2, -entity.motionX * 4.0f, 1.5f, -entity.motionZ * 4.0f, this.getDefaultState()).setBlockPos(pos);
particle.setParticleTexture(texture);
Minecraft.getMinecraft().effectRenderer.addEffect(particle);
}
}
@Override
public boolean addLandingEffects(IBlockState state, WorldServer world, BlockPos pos, IBlockState iblockstate, EntityLivingBase entity, int numberOfParticles) {
// for reasons only notch can explain, this method is only called on the server, so we have to sync
// a packet to all tracking players for landing particle effects
if (!world.isRemote) {
final PacketCableBusLandingParticle packet = new PacketCableBusLandingParticle(pos, entity, numberOfParticles);
final NetworkRegistry.TargetPoint point = new NetworkRegistry.TargetPoint(world.provider.getDimension(), pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 32);
NetworkHandler.instance().sendToAllTracking(packet, point);
}
return true;
}
@SideOnly(Side.CLIENT)
public void addLandingParticle(BlockPos pos, double entityX, double entityY, double entityZ, int numberOfParticles) {
final World world = Minecraft.getMinecraft().world;
final ICableBusContainer cb = this.cb(world, pos);
final IBakedModel model = Minecraft.getMinecraft().getBlockRendererDispatcher().getModelForState(this.getDefaultState());
if (!(model instanceof CableBusBakedModel cableBusModel)) {
return;
}
final TextureAtlasSprite texture = getSpriteForParticle(cb.getRenderState(), cableBusModel);
if (texture != null) {
final Vec3d startVec = new Vec3d(entityX, entityY, entityZ);
final Vec3d endVec = startVec.add(0.0f, -4.0f, 0.0f);
RayTraceResult result = world.rayTraceBlocks(startVec, endVec, true, false, true);
final double speed = 0.15f;
if (result != null && result.typeOfHit == Type.BLOCK && numberOfParticles != 0) {
for (int i = 0; i < numberOfParticles; i++) {
final double d0 = world.rand.nextGaussian() * speed;
final double d1 = world.rand.nextGaussian() * speed;
final double d2 = world.rand.nextGaussian() * speed;
final ParticleDigging particle = new DestroyFX(world, entityX, entityY, entityZ, d0, d1, d2, this.getDefaultState()).setBlockPos(pos);
particle.setParticleTexture(texture);
Minecraft.getMinecraft().effectRenderer.addEffect(particle);
}
}
}
}
@SideOnly(Side.CLIENT)
private TextureAtlasSprite getSpriteForParticle(CableBusRenderState renderState, CableBusBakedModel cableBusModel) {
final FacadeRenderState frs = renderState.getFacades().get(EnumFacing.UP);
if (frs != null) {
final IBlockState state = frs.getSourceBlock();
final IBakedModel model = Minecraft.getMinecraft().getBlockRendererDispatcher().getModelForState(state);
return model.getParticleTexture();
}
return Platform.pickRandom(cableBusModel.getParticleTextures(renderState));
}
@Override
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block blockIn, BlockPos fromPos) {
if (Platform.isServer()) {
@@ -378,10 +461,9 @@ public class BlockCableBus extends AEBaseTileBlock implements IAEFacade {
}
public void setupTile() {
noTesrTile = Api.INSTANCE.partHelper().getCombinedInstance(TileCableBus.class);
this.setTileEntity(noTesrTile);
this.setTileEntity(TileCableBus.class);
GameRegistry.registerTileEntity(noTesrTile, AppEng.MOD_ID.toLowerCase() + ":" + "BlockCableBus");
GameRegistry.registerTileEntity(TileCableBus.class, AppEng.MOD_ID.toLowerCase() + ":" + "BlockCableBus");
if (Platform.isClient()) {
setupTesr();
@@ -390,9 +472,8 @@ public class BlockCableBus extends AEBaseTileBlock implements IAEFacade {
@SideOnly(Side.CLIENT)
private static void setupTesr() {
tesrTile = Api.INSTANCE.partHelper().getCombinedInstance(TileCableBusTESR.class);
GameRegistry.registerTileEntity(tesrTile, AppEng.MOD_ID.toLowerCase() + ":" + "ClientOnly_TESR_CableBus");
ClientRegistry.bindTileEntitySpecialRenderer(BlockCableBus.getTesrTile(), new CableBusTESR());
GameRegistry.registerTileEntity(TileCableBusTESR.class, AppEng.MOD_ID.toLowerCase() + ":" + "ClientOnly_TESR_CableBus");
ClientRegistry.bindTileEntitySpecialRenderer(TileCableBusTESR.class, new CableBusTESR());
}
@Override
@@ -438,14 +519,6 @@ public class BlockCableBus extends AEBaseTileBlock implements IAEFacade {
super.onEntityWalk(world, pos, entityIn);
}
public static Class<? extends AEBaseTile> getNoTesrTile() {
return noTesrTile;
}
public static Class<? extends AEBaseTile> getTesrTile() {
return tesrTile;
}
// Helper to get access to the protected constructor
@SideOnly(Side.CLIENT)
private static class DestroyFX extends ParticleDigging {
+15 -1
View File
@@ -54,6 +54,7 @@ import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Items;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumHand;
@@ -82,6 +83,7 @@ import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import static appeng.client.KeyBindings.WCT;
import static appeng.client.KeyBindings.WFT;
@@ -372,4 +374,16 @@ public class ClientHelper extends ServerHelper {
public boolean isActionKey(ActionKey key, int pressedKeyCode) {
return this.bindings.get(key).isActiveAndMatches(pressedKeyCode);
}
}
@Override
public EntityPlayer getPlayerByUUID(UUID uuid) {
if (Platform.isClient()) {
if (Minecraft.getMinecraft().player.getUniqueID().equals(uuid)) {
return Minecraft.getMinecraft().player;
}
return null;
} else {
return super.getPlayerByUUID(uuid);
}
}
}
@@ -0,0 +1,208 @@
package appeng.client.gui;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.Stack;
public class MathExpressionParser {
private final Stack<String> postfixStack = new Stack<>();
private final Stack<Character> opStack = new Stack<>();
private static final int[] OPERATOR_PRIORITY = new int[] { 0, 3, 2, 1, -1, 1, 0, 2 };
public static double parse(String expression) {
double result;
if (expression == null) return Double.NaN;
expression = expression.replace(" ", "");
if (expression.length() == 1 && Character.isDigit(expression.charAt(0))) {
return expression.charAt(0) - '0';
}
try {
expression = transform(expression);
result = new MathExpressionParser().calculate(expression);
} catch (Exception e) {
return Double.NaN;
}
return result;
}
/**
* replace '-' with '~'
* e.g.-2+-1*(-3E-2)-(-1) -> ~2+~1*(~3E~2)-(~1)
*/
private static String transform(String expression) {
char[] arr = expression.toCharArray();
for (int i = 0; i < arr.length; i++) {
if (arr[i] == '-') {
if (i == 0) {
arr[i] = '~';
} else {
char c = arr[i - 1];
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == 'E' || c == 'e') {
arr[i] = '~';
}
}
}
}
if (arr[0] == '~' || arr[1] == '(') {
arr[0] = '-';
return "0" + new String(arr);
} else {
return new String(arr);
}
}
public double calculate(String expression) {
Stack<String> resultStack = new Stack<>();
prepare(expression);
Collections.reverse(postfixStack);
String firstValue, secondValue, currentValue;
while (!postfixStack.isEmpty()) {
currentValue = postfixStack.pop();
if (!isOperator(currentValue.charAt(0))) {
currentValue = currentValue.replace("~", "-");
resultStack.push(currentValue);
} else {
secondValue = resultStack.pop();
firstValue = resultStack.pop();
firstValue = firstValue.replace("~", "-");
secondValue = secondValue.replace("~", "-");
String tempResult = calculate(firstValue, secondValue, currentValue.charAt(0));
resultStack.push(String.valueOf(tempResult));
}
}
return Double.parseDouble(resultStack.pop());
}
private void prepare(String expression) {
opStack.push(',');
char[] arr = expression.toCharArray();
int currentIndex = 0;
int count = 0;
char currentOp, peekOp;
for (int i = 0; i < arr.length; i++) {
currentOp = arr[i];
if (isOperator(currentOp)) {
if (count > 0) {
postfixStack.push(new String(arr, currentIndex, count));
}
peekOp = opStack.peek();
if (currentOp == ')') {
while (opStack.peek() != '(') {
postfixStack.push(String.valueOf(opStack.pop()));
}
opStack.pop();
} else {
while (currentOp != '(' && peekOp != ',' && compare(currentOp, peekOp)) {
postfixStack.push(String.valueOf(opStack.pop()));
peekOp = opStack.peek();
}
opStack.push(currentOp);
}
count = 0;
currentIndex = i + 1;
} else {
count++;
}
}
if (count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {
postfixStack.push(new String(arr, currentIndex, count));
}
while (opStack.peek() != ',') {
postfixStack.push(String.valueOf(opStack.pop()));
}
}
private static boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
}
private static boolean compare(char cur, char peek) {
return OPERATOR_PRIORITY[(peek) - 40] >= OPERATOR_PRIORITY[(cur) - 40];
}
private String calculate(String firstValue, String secondValue, char currentOp) {
return switch (currentOp) {
case '+' -> add(firstValue, secondValue);
case '-' -> sub(firstValue, secondValue);
case '*' -> mul(firstValue, secondValue);
case '/' -> div(firstValue, secondValue);
default -> "";
};
}
public static String add(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return String.valueOf(b1.add(b2));
}
/**
* subtraction
*
* @param v1 p1
* @param v2 p2
* @return sub
*/
public static String sub(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return String.valueOf(b1.subtract(b2));
}
/**
* multiplication
*
* @param v1 p1
* @param v2 p2
* @return mul
*/
public static String mul(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return String.valueOf(b1.multiply(b2));
}
/**
* division. e = 10^-10
*
* @param v1 p1
* @param v2 p2
* @return div
*/
public static String div(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return String.valueOf(b1.divide(b2, 16, RoundingMode.HALF_UP));
}
/**
* rounding
*
* @param v p
* @param scale scale
* @return result
*/
public static double round(double v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(v));
return b.divide(BigDecimal.ONE, scale, RoundingMode.HALF_UP).doubleValue();
}
public static String round(String v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(v);
return String.valueOf(b.divide(BigDecimal.ONE, scale, RoundingMode.HALF_UP));
}
}
@@ -22,10 +22,9 @@ package appeng.client.gui.implementations;
import appeng.api.AEApi;
import appeng.api.definitions.IDefinitions;
import appeng.api.definitions.IParts;
import appeng.api.features.IWirelessTermHandler;
import appeng.api.storage.ITerminalHost;
import appeng.client.gui.AEBaseGui;
import appeng.client.gui.widgets.GuiNumberBox;
import appeng.client.gui.MathExpressionParser;
import appeng.client.gui.widgets.GuiTabButton;
import appeng.container.AEBaseContainer;
import appeng.container.implementations.ContainerCraftAmount;
@@ -42,6 +41,7 @@ import appeng.parts.reporting.PartExpandedProcessingPatternTerminal;
import appeng.parts.reporting.PartPatternTerminal;
import appeng.parts.reporting.PartTerminal;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack;
import org.lwjgl.input.Keyboard;
@@ -50,7 +50,7 @@ import java.io.IOException;
public class GuiCraftAmount extends AEBaseGui {
private GuiNumberBox amountToCraft;
private GuiTextField amountToCraft;
private GuiTabButton originalGuiBtn;
private GuiButton next;
@@ -126,7 +126,7 @@ public class GuiCraftAmount extends AEBaseGui {
this.buttonList.add(this.originalGuiBtn = new GuiTabButton(this.guiLeft + 154, this.guiTop, myIcon, myIcon.getDisplayName(), this.itemRender));
}
this.amountToCraft = new GuiNumberBox(this.fontRenderer, this.guiLeft + 62, this.guiTop + 57, 59, this.fontRenderer.FONT_HEIGHT, Integer.class);
this.amountToCraft = new GuiTextField(0, this.fontRenderer, this.guiLeft + 62, this.guiTop + 57, 59, this.fontRenderer.FONT_HEIGHT);
this.amountToCraft.setEnableBackgroundDrawing(false);
this.amountToCraft.setMaxStringLength(16);
this.amountToCraft.setTextColor(0xFFFFFF);
@@ -149,8 +149,17 @@ public class GuiCraftAmount extends AEBaseGui {
this.drawTexturedModalRect(offsetX, offsetY, 0, 0, this.xSize, this.ySize);
try {
long amt = Long.parseLong(this.amountToCraft.getText());
this.next.enabled = (!this.amountToCraft.getText().isEmpty() && amt > 0);
String out = this.amountToCraft.getText();
double resultD = MathExpressionParser.parse(out);
long amt;
if (resultD <= 0 || Double.isNaN(resultD)) {
amt = 0;
} else {
amt = (long) MathExpressionParser.round(resultD, 0);
}
this.next.enabled = amt > 0;
} catch (final NumberFormatException e) {
this.next.enabled = false;
}
@@ -164,33 +173,7 @@ public class GuiCraftAmount extends AEBaseGui {
if (key == Keyboard.KEY_RETURN || key == Keyboard.KEY_NUMPADENTER) {
this.actionPerformed(this.next);
}
if ((key == 211 || key == 205 || key == 203 || key == 14 || character == '-' || Character.isDigit(character)) && this.amountToCraft
.textboxKeyTyped(character, key)) {
try {
String out = this.amountToCraft.getText();
boolean fixed = false;
while (out.startsWith("0") && out.length() > 1) {
out = out.substring(1);
fixed = true;
}
if (fixed) {
this.amountToCraft.setText(out);
}
if (out.isEmpty()) {
out = "0";
}
final long result = Long.parseLong(out);
if (result < 0) {
this.amountToCraft.setText("1");
}
} catch (final NumberFormatException e) {
// :P
}
} else {
if (!this.amountToCraft.textboxKeyTyped(character, key)) {
super.keyTyped(character, key);
}
}
@@ -207,7 +190,15 @@ public class GuiCraftAmount extends AEBaseGui {
}
if (btn == this.next) {
NetworkHandler.instance().sendToServer(new PacketCraftRequest(Integer.parseInt(this.amountToCraft.getText()), isShiftKeyDown()));
double resultD = MathExpressionParser.parse(this.amountToCraft.getText());
int result;
if (resultD <= 0 || Double.isNaN(resultD)) {
result = 1;
} else {
result = (int) MathExpressionParser.round(resultD, 0);
}
NetworkHandler.instance().sendToServer(new PacketCraftRequest(result, isShiftKeyDown()));
}
} catch (final NumberFormatException e) {
// nope..
@@ -226,22 +217,15 @@ public class GuiCraftAmount extends AEBaseGui {
try {
String out = this.amountToCraft.getText();
boolean fixed = false;
while (out.startsWith("0") && out.length() > 1) {
out = out.substring(1);
fixed = true;
}
double resultD = MathExpressionParser.parse(out);
int result;
if (fixed) {
this.amountToCraft.setText(out);
if (resultD <= 0 || Double.isNaN(resultD)) {
result = 0;
} else {
result = (int) MathExpressionParser.round(resultD, 0);
}
if (out.isEmpty()) {
out = "0";
}
long result = Integer.parseInt(out);
if (result == 1 && i > 1) {
result = 0;
}
@@ -251,8 +235,7 @@ public class GuiCraftAmount extends AEBaseGui {
result = 1;
}
out = Long.toString(result);
Integer.parseInt(out);
out = Integer.toString(result);
this.amountToCraft.setText(out);
} catch (final NumberFormatException e) {
// :P
@@ -50,6 +50,7 @@ import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentString;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fml.common.Loader;
import org.lwjgl.input.Mouse;
@@ -567,15 +568,15 @@ public class GuiInterfaceTerminal extends AEBaseGui {
return searchTerm.matches(GuiText.InvalidPattern.getLocal());
}
NBTTagList tag = new NBTTagList();
final NBTTagList tag;
if (pass == 0) {
tag = encodedValue.getTagList("in", 10);
tag = encodedValue.getTagList("in", Constants.NBT.TAG_COMPOUND);
} else {
tag = encodedValue.getTagList("out", 10);
tag = encodedValue.getTagList("out", Constants.NBT.TAG_COMPOUND);
}
boolean foundMatchingItemStack = false;
final String[] splitTerm = searchTerm.split(" ");
for (int i = 0; i < tag.tagCount(); i++) {
final ItemStack parsedItemStack = new ItemStack(tag.getCompoundTagAt(i));
@@ -584,7 +585,7 @@ public class GuiInterfaceTerminal extends AEBaseGui {
.getItemDisplayName(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class).createStack(parsedItemStack))
.toLowerCase();
for (String term : searchTerm.split(" ")) {
for (String term : splitTerm) {
if (term.length() > 1 && (term.startsWith("-") || term.startsWith("!"))) {
term = term.substring(1);
if (displayName.contains(term)) {
@@ -592,8 +593,6 @@ public class GuiInterfaceTerminal extends AEBaseGui {
}
} else if (displayName.contains(term)) {
foundMatchingItemStack = true;
} else {
return false;
}
}
}
@@ -24,6 +24,10 @@ import appeng.api.parts.IPartModel;
import appeng.api.util.AECableType;
import appeng.api.util.AEColor;
import appeng.block.networking.BlockCableBus;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.cache.Weigher;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.BakedQuad;
@@ -38,6 +42,7 @@ import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.common.property.IExtendedBlockState;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.Map.Entry;
@@ -45,8 +50,6 @@ import java.util.Map.Entry;
public class CableBusBakedModel implements IBakedModel {
static final Map<CableBusRenderState, List<BakedQuad>> CABLE_MODEL_CACHE = new HashMap<>();
private final CableBuilder cableBuilder;
private final FacadeBuilder facadeBuilder;
@@ -57,11 +60,24 @@ public class CableBusBakedModel implements IBakedModel {
private final TextureMap textureMap = Minecraft.getMinecraft().getTextureMapBlocks();
private final LoadingCache<CableBusRenderState, List<BakedQuad>> cableModelCache;
CableBusBakedModel(CableBuilder cableBuilder, FacadeBuilder facadeBuilder, Map<ResourceLocation, IBakedModel> partModels, TextureAtlasSprite particleTexture) {
this.cableBuilder = cableBuilder;
this.facadeBuilder = facadeBuilder;
this.partModels = partModels;
this.particleTexture = particleTexture;
this.cableModelCache = CacheBuilder.newBuilder()
.maximumWeight(5000)
.weigher((Weigher<CableBusRenderState, List<BakedQuad>>) (k, v) -> v.size())
.build(new CacheLoader<>() {
@Override
public List<BakedQuad> load(@Nonnull CableBusRenderState rs) {
final List<BakedQuad> model = new ArrayList<>();
addCableQuads(rs, model);
return model;
}
});
}
@Override
@@ -82,12 +98,7 @@ public class CableBusBakedModel implements IBakedModel {
if (layer == BlockRenderLayer.CUTOUT) {
// First, handle the cable at the center of the cable bus
final List<BakedQuad> cableModel = CABLE_MODEL_CACHE.computeIfAbsent(renderState, k ->
{
final List<BakedQuad> model = new ArrayList<>();
this.addCableQuads(renderState, model);
return model;
});
final List<BakedQuad> cableModel = cableModelCache.getUnchecked(renderState);
quads.addAll(cableModel);
// Then handle attachments
@@ -27,26 +27,21 @@ import com.google.common.collect.ImmutableMap;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.client.resource.IResourceType;
import net.minecraftforge.client.resource.ISelectiveResourceReloadListener;
import net.minecraftforge.client.resource.VanillaResourceType;
import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.TRSRTransformation;
import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* The built-in model for the cable bus block.
*/
public class CableBusModel implements IModel, ISelectiveResourceReloadListener {
public class CableBusModel implements IModel {
private final PartModels partModels;
@@ -106,12 +101,4 @@ public class CableBusModel implements IModel, ISelectiveResourceReloadListener {
public IModelState getDefaultState() {
return TRSRTransformation.identity();
}
@Override
public void onResourceManagerReload(IResourceManager resourceManager, Predicate<IResourceType> resourcePredicate) {
if (resourcePredicate.test(VanillaResourceType.MODELS)) {
CableBusBakedModel.CABLE_MODEL_CACHE.clear();
}
}
}
@@ -399,7 +399,7 @@ public abstract class AEBaseContainer extends Container {
return ItemStack.EMPTY; // don't insert duplicate encoded patterns to interfaces
}
int maxSize = Math.max(tis.getMaxStackSize(), d.getSlotStackLimit());
int maxSize = Math.min(tis.getMaxStackSize(), d.getSlotStackLimit());
int placeAble = maxSize - t.getCount();
@@ -435,7 +435,7 @@ public abstract class AEBaseContainer extends Container {
if (d.isItemValid(tis)) {
if (!d.getHasStack()) {
int maxSize = Math.max(tis.getMaxStackSize(), d.getSlotStackLimit());
int maxSize = Math.min(tis.getMaxStackSize(), d.getSlotStackLimit());
final ItemStack tmp = tis.copy();
if (tmp.getCount() > maxSize) {
@@ -964,26 +964,34 @@ public abstract class AEBaseContainer extends Container {
if (!draggedStack.isEmpty()) {
if (appEngSlot.isItemValid(draggedStack)) {
if (slotStack.getItem() == draggedStack.getItem() && slotStack.getMetadata() == draggedStack.getMetadata() && ItemStack.areItemStackTagsEqual(slotStack, draggedStack)) {
var maxSize = Math.max(appEngSlot.getSlotStackLimit(), draggedStack.getMaxStackSize());
var maxInsertable = Math.min(draggedStack.getCount(), maxSize - appEngSlot.getStack().getCount());
var toInsert = Math.min(maxInsertable, dragType == 0 ? maxInsertable : 1);
// Slot size or stack size, whichever is smaller.
var maxSize = Math.min(appEngSlot.getSlotStackLimit(), draggedStack.getMaxStackSize());
draggedStack.shrink(toInsert);
slotStack.grow(toInsert);
// The maximum number of items that can be inserted into the slot, non-negative.
var maxInsertable = Math.min(draggedStack.getCount(),
Math.max(0, maxSize - appEngSlot.getStack().getCount()));
slot.onSlotChanged();
return ItemStack.EMPTY;
if (maxInsertable != 0) {
var toInsert = Math.min(maxInsertable, dragType == 0 ? maxInsertable : 1);
draggedStack.shrink(toInsert);
slotStack.grow(toInsert);
slot.putStack(slot.getStack());
return ItemStack.EMPTY;
}
}
}
}
// Fixes taking and halving issues from oversized slots.
else if (dragType == 0 || dragType == 1) {
if (slot.canTakeStack(player) && !slotStack.isEmpty()) {
var result = slotStack.copy();
var toTake = Math.min(slotStack.getCount(), slotStack.getMaxStackSize());
this.invPlayer.setItemStack(slot.decrStackSize(dragType == 0 ? toTake : (toTake + 1) / 2));
slot.onTake(player, invPlayer.getItemStack());
return ItemStack.EMPTY;
slot.putStack(slot.getStack());
return result;
}
}
@@ -50,6 +50,9 @@ public class ContainerStorageBus extends ContainerUpgradeable {
@GuiSync(4)
public StorageFilter storageFilter = StorageFilter.EXTRACTABLE_ONLY;
@GuiSync(7)
public YesNo stickyMode = YesNo.NO;
public ContainerStorageBus(final InventoryPlayer ip, final PartStorageBus te) {
super(ip, te);
this.storageBus = te;
@@ -111,6 +114,7 @@ public class ContainerStorageBus extends ContainerUpgradeable {
this.setFuzzyMode((FuzzyMode) this.getUpgradeable().getConfigManager().getSetting(Settings.FUZZY_MODE));
this.setReadWriteMode((AccessRestriction) this.getUpgradeable().getConfigManager().getSetting(Settings.ACCESS));
this.setStorageFilter((StorageFilter) this.getUpgradeable().getConfigManager().getSetting(Settings.STORAGE_FILTER));
this.setStickyMode((YesNo) this.getUpgradeable().getConfigManager().getSetting(Settings.STICKY_MODE));
}
this.standardDetectAndSendChanges();
@@ -168,4 +172,12 @@ public class ContainerStorageBus extends ContainerUpgradeable {
private void setStorageFilter(final StorageFilter storageFilter) {
this.storageFilter = storageFilter;
}
public YesNo getStickyMode() {
return this.stickyMode;
}
private void setStickyMode(final YesNo stickyMode) {
this.stickyMode = stickyMode;
}
}
+6
View File
@@ -83,6 +83,7 @@ public final class AEConfig extends Configuration implements IConfigurableObject
private int craftingCalculationTimePerTick = 5;
private PowerUnits selectedPowerUnit = PowerUnits.AE;
private boolean showCraftableTooltip = true;
private boolean showPlacementPreview = true;
// Spatial IO/Dimension
private int storageProviderID = -1;
@@ -257,6 +258,7 @@ public final class AEConfig extends Configuration implements IConfigurableObject
this.useLargeFonts = this.get("Client", "useTerminalUseLargeFont", false).getBoolean(false);
this.useColoredCraftingStatus = this.get("Client", "useColoredCraftingStatus", true).getBoolean(true);
this.showCraftableTooltip = this.get("Client", "showCraftableTooltip", true, "Whether to add \"Craftable\" to item tooltips when they can be crafted automatically.").getBoolean(true);
this.showPlacementPreview = this.get("Client", "showPlacementPreview", true, "Whether to show a preview of part and facade placement.").getBoolean(true);
// load buttons..
for (int btnNum = 0; btnNum < 4; btnNum++) {
@@ -514,6 +516,10 @@ public final class AEConfig extends Configuration implements IConfigurableObject
return this.showCraftableTooltip;
}
public boolean showPlacementPreview() {
return this.showPlacementPreview;
}
public boolean isDisableColoredCableRecipesInJEI() {
return this.disableColoredCableRecipesInJEI;
}
@@ -25,6 +25,7 @@ import appeng.client.ActionKey;
import appeng.client.EffectType;
import appeng.core.sync.AppEngPacket;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
@@ -32,6 +33,7 @@ import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.Random;
import java.util.UUID;
public abstract class CommonHelper {
@@ -66,4 +68,5 @@ public abstract class CommonHelper {
public abstract boolean isActionKey(@Nonnull final ActionKey key, int pressedKeyCode);
public abstract EntityPlayer getPlayerByUUID(UUID uuid);
}
+21 -3
View File
@@ -54,13 +54,13 @@ import appeng.core.stats.PartItemPredicate;
import appeng.core.stats.Stats;
import appeng.core.worlddata.SpatialDimensionManager;
import appeng.fluids.registries.BasicFluidCellGuiHandler;
import appeng.hooks.WrenchClickHook;
import appeng.hooks.TickHandler;
import appeng.items.materials.ItemMaterial;
import appeng.items.parts.ItemFacade;
import appeng.items.parts.ItemPart;
import appeng.loot.ChestLoot;
import appeng.me.cache.*;
import appeng.parts.PartPlacement;
import appeng.recipes.AEItemResolver;
import appeng.recipes.AERecipeLoader;
import appeng.recipes.game.DisassembleRecipe;
@@ -109,7 +109,6 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -193,7 +192,7 @@ final class Registration {
MinecraftForge.EVENT_BUS.register(TickHandler.INSTANCE);
MinecraftForge.EVENT_BUS.register(new PartPlacement());
MinecraftForge.EVENT_BUS.register(new WrenchClickHook());
if (AEConfig.instance().isFeatureEnabled(AEFeature.CHEST_LOOT)) {
MinecraftForge.EVENT_BUS.register(new ChestLoot());
@@ -365,15 +364,19 @@ final class Registration {
// Storage Cells
Upgrades.FUZZY.registerItem(items.cell1k(), 1);
Upgrades.INVERTER.registerItem(items.cell1k(), 1);
Upgrades.STICKY.registerItem(items.cell1k(), 1);
Upgrades.FUZZY.registerItem(items.cell4k(), 1);
Upgrades.INVERTER.registerItem(items.cell4k(), 1);
Upgrades.STICKY.registerItem(items.cell4k(), 1);
Upgrades.FUZZY.registerItem(items.cell16k(), 1);
Upgrades.INVERTER.registerItem(items.cell16k(), 1);
Upgrades.STICKY.registerItem(items.cell16k(), 1);
Upgrades.FUZZY.registerItem(items.cell64k(), 1);
Upgrades.INVERTER.registerItem(items.cell64k(), 1);
Upgrades.STICKY.registerItem(items.cell64k(), 1);
Upgrades.FUZZY.registerItem(items.portableCell(), 1);
Upgrades.INVERTER.registerItem(items.portableCell(), 1);
@@ -384,14 +387,29 @@ final class Registration {
Upgrades.FUZZY.registerItem(AEApi.instance().definitions().materials().cardMagnet(), 1);
Upgrades.INVERTER.registerItem(AEApi.instance().definitions().materials().cardMagnet(), 1);
// Fluid Cells
Upgrades.INVERTER.registerItem(items.fluidCell1k(), 1);
Upgrades.STICKY.registerItem(items.fluidCell1k(), 1);
Upgrades.INVERTER.registerItem(items.fluidCell4k(), 1);
Upgrades.STICKY.registerItem(items.fluidCell4k(), 1);
Upgrades.INVERTER.registerItem(items.fluidCell16k(), 1);
Upgrades.STICKY.registerItem(items.fluidCell16k(), 1);
Upgrades.INVERTER.registerItem(items.fluidCell64k(), 1);
Upgrades.STICKY.registerItem(items.fluidCell64k(), 1);
// Storage Bus
Upgrades.FUZZY.registerItem(parts.storageBus(), 1);
Upgrades.INVERTER.registerItem(parts.storageBus(), 1);
Upgrades.CAPACITY.registerItem(parts.storageBus(), 5);
Upgrades.STICKY.registerItem(parts.storageBus(), 1);
// Storage Bus Fluids
Upgrades.INVERTER.registerItem(parts.fluidStorageBus(), 1);
Upgrades.CAPACITY.registerItem(parts.fluidStorageBus(), 5);
Upgrades.STICKY.registerItem(parts.fluidStorageBus(), 1);
// Formation Plane
Upgrades.FUZZY.registerItem(parts.formationPlane(), 1);
@@ -60,6 +60,10 @@ public class ApiClientHelper implements IClientHelper {
lines.add("[" + GuiText.Partitioned.getLocal() + "]" + " - " + list + ' ' + GuiText.Precise.getLocal());
}
if (handler.isSticky()) {
lines.add(GuiText.Sticky.getLocal());
}
if (Minecraft.getMinecraft().gameSettings.advancedItemTooltips || Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) {
IItemHandler inv = cellInventory.getConfigInventory();
cellInventory.getAvailableItems((IItemList) itemList);
+52 -282
View File
@@ -19,18 +19,18 @@
package appeng.core.api;
import appeng.api.AEApi;
import appeng.api.definitions.ITileDefinition;
import appeng.api.parts.CableRenderMode;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartHelper;
import appeng.api.parts.LayerBase;
import appeng.core.AELog;
import appeng.core.AppEng;
import appeng.parts.PartPlacement;
import appeng.tile.AEBaseTile;
import appeng.tile.networking.TileCableBus;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import appeng.api.parts.IPartHost;
import appeng.api.util.AEPartLocation;
import appeng.util.Platform;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
@@ -39,243 +39,15 @@ import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.commons.ClassRemapper;
import org.objectweb.asm.commons.Remapper;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.*;
import org.jetbrains.annotations.Nullable;
public class ApiPart implements IPartHelper {
private final LoadingCache<CacheKey, Class<? extends AEBaseTile>> cache = CacheBuilder.newBuilder()
.build(new CacheLoader<CacheKey, Class<? extends AEBaseTile>>() {
@Override
public Class<? extends AEBaseTile> load(CacheKey key) throws Exception {
return ApiPart.this.generateCombinedClass(key);
}
});
private final Map<Class<?>, String> interfaces2Layer = new HashMap<>();
private final List<String> desc = new ArrayList<>();
/**
* Conceptually this method will build a new class hierarchy that is rooted at the given base class, and includes a
* chain of all registered layers.
* <p/>
* To accomplish this, it takes the first registered layer, replaces it's inheritance from LayerBase with an
* inheritance from the given baseClass,
* and uses the resulting class as the parent class for the next registered layer, for which it repeats this
* process. This process is then repeated
* until a class hierarchy of all layers is formed. While janking out the inheritance from LayerBase, it'll make
* also sure that calls to that
* classes method will instead be forwarded to the superclass that was inserted as part of the described process.
* <p/>
* Example: If layers A and B are registered, and TileCableBus is passed in as the baseClass, a synthetic class
* A_B_TileCableBus should be returned,
* which has A_B_TileCableBus -extends-> B_TileCableBus -extends-> TileCableBus as it's class hierarchy, where
* A_B_TileCableBus has been generated
* from A, and B_TileCableBus has been generated from B.
*/
public Class<? extends AEBaseTile> getCombinedInstance(final Class<? extends AEBaseTile> baseClass) {
if (this.desc.isEmpty()) {
// No layers registered...
return baseClass;
}
return this.cache.getUnchecked(new CacheKey(baseClass, this.desc));
}
private Class<? extends AEBaseTile> generateCombinedClass(CacheKey cacheKey) {
final Class<? extends AEBaseTile> parentClass;
// Get the list of interfaces that still need to be implemented beyond the current one
List<String> remainingInterfaces = cacheKey.getInterfaces().subList(1, cacheKey.getInterfaces().size());
// We are not at the root of the class hierarchy yet
if (!remainingInterfaces.isEmpty()) {
CacheKey parentKey = new CacheKey(cacheKey.getBaseClass(), remainingInterfaces);
parentClass = this.cache.getUnchecked(parentKey);
} else {
parentClass = cacheKey.getBaseClass();
}
// Which interface should be implemented in this layer?
String interfaceName = cacheKey.getInterfaces().get(0);
try {
// This is the particular interface that this layer was registered for. Loading the class may fail if i.e.
// an API is broken or not present
// and in this case, the layer will be skipped!
Class<?> interfaceClass = Class.forName(interfaceName);
String layerImpl = this.interfaces2Layer.get(interfaceClass);
return this.getClassByDesc(parentClass, layerImpl);
} catch (final Throwable t) {
AELog.warn("Error loading " + interfaceName);
AELog.debug(t);
return parentClass;
}
}
@SuppressWarnings("unchecked")
private Class<? extends AEBaseTile> getClassByDesc(Class<? extends AEBaseTile> baseClass, final String next) {
final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
final ClassNode n = this.getReader(next);
final String originalName = n.name;
try {
n.name = n.name + '_' + baseClass.getSimpleName();
n.superName = baseClass.getName().replace('.', '/');
} catch (final Throwable t) {
AELog.debug(t);
}
for (final MethodNode mn : n.methods) {
final Iterator<AbstractInsnNode> i = mn.instructions.iterator();
while (i.hasNext()) {
this.processNode(i.next(), n.superName);
}
}
final DefaultPackageClassNameRemapper remapper = new DefaultPackageClassNameRemapper();
remapper.inputOutput.put("appeng/api/parts/LayerBase", n.superName);
remapper.inputOutput.put(originalName, n.name);
n.accept(new ClassRemapper(cw, remapper));
// n.accept( cw );
// n.accept( new TraceClassVisitor( new PrintWriter( System.out ) ) );
final byte[] byteArray = cw.toByteArray();
final int size = byteArray.length;
final Class clazz = this.loadClass(n.name.replace("/", "."), byteArray);
try {
final Object fish = clazz.newInstance();
boolean hasError = false;
if (!baseClass.isInstance(fish)) {
hasError = true;
AELog.error("Error, Expected layer to implement " + baseClass + " did not.");
}
if (fish instanceof LayerBase) {
hasError = true;
AELog.error("Error, Expected layer to NOT implement LayerBase but it DID.");
}
if (!(fish instanceof TileCableBus)) {
hasError = true;
AELog.error("Error, Expected layer to implement TileCableBus did not.");
}
if (!(fish instanceof TileEntity)) {
hasError = true;
AELog.error("Error, Expected layer to implement TileEntity did not.");
}
if (!hasError) {
AELog.info("Layer: " + n.name + " loaded successfully - " + size + " bytes");
}
} catch (final Throwable t) {
AELog.error("Layer: " + n.name + " Failed.");
AELog.debug(t);
}
return clazz;
}
private ClassNode getReader(final String name) {
final String path = '/' + name.replace(".", "/") + ".class";
final InputStream is = this.getClass().getResourceAsStream(path);
try {
final ClassReader cr = new ClassReader(is);
final ClassNode cn = new ClassNode();
cr.accept(cn, ClassReader.EXPAND_FRAMES);
return cn;
} catch (final IOException e) {
throw new IllegalStateException("Error loading " + name, e);
}
}
private void processNode(final AbstractInsnNode next, final String nePar) {
if (next instanceof MethodInsnNode) {
final MethodInsnNode min = (MethodInsnNode) next;
if (min.owner.equals("appeng/api/parts/LayerBase")) {
min.owner = nePar;
}
}
}
private Class loadClass(final String name, byte[] b) {
// override classDefine (as it is protected) and define the class.
Class clazz = null;
try {
final ClassLoader loader = this.getClass().getClassLoader();// ClassLoader.getSystemClassLoader();
final Class<ClassLoader> root = ClassLoader.class;
final Class<? extends ClassLoader> cls = loader.getClass();
final Method defineClassMethod = root.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
final Method runTransformersMethod = cls.getDeclaredMethod("runTransformers", String.class, String.class, byte[].class);
runTransformersMethod.setAccessible(true);
defineClassMethod.setAccessible(true);
try {
final Object[] argsA = {
name,
name,
b
};
b = (byte[]) runTransformersMethod.invoke(loader, argsA);
final Object[] args = {
name,
b,
0,
b.length
};
clazz = (Class) defineClassMethod.invoke(loader, args);
} finally {
runTransformersMethod.setAccessible(false);
defineClassMethod.setAccessible(false);
}
} catch (final Exception e) {
AELog.debug(e);
throw new IllegalStateException("Unable to manage part API.", e);
}
return clazz;
}
@Override
public boolean registerNewLayer(final String layer, final String layerInterface) {
try {
final Class<?> layerInterfaceClass = Class.forName(layerInterface);
if (this.interfaces2Layer.get(layerInterfaceClass) == null) {
this.interfaces2Layer.put(layerInterfaceClass, layer);
this.desc.add(layerInterface);
return true;
} else {
AELog.info("Layer " + layer + " not registered, " + layerInterface + " already has a layer.");
}
} catch (final Throwable ignored) {
}
return false;
}
@Override
public EnumActionResult placeBus(final ItemStack is, final BlockPos pos, final EnumFacing side, final EntityPlayer player, final EnumHand hand, final World w) {
return PartPlacement.place(is, pos, side, player, hand, w, PartPlacement.PlaceType.PLACE_ITEM, 0);
return PartPlacement.place(is, pos, side, player, hand, w);
}
@Override
@@ -283,57 +55,55 @@ public class ApiPart implements IPartHelper {
return AppEng.proxy.getRenderMode();
}
private static class DefaultPackageClassNameRemapper extends Remapper {
@Nullable
@Override
public IPart getPart(World w, BlockPos pos, AEPartLocation side) {
final TileEntity tile = w.getTileEntity(pos);
if (tile instanceof IPartHost partHost) {
return partHost.getPart(side);
}
return null;
}
private final HashMap<String, String> inputOutput = new HashMap<>();
@Nullable
@Override
public IPartHost getPartHost(World w, BlockPos pos) {
final TileEntity tile = w.getTileEntity(pos);
if (tile instanceof IPartHost partHost) {
return partHost;
}
return null;
}
@Override
public String map(final String typeName) {
final String o = this.inputOutput.get(typeName);
if (o == null) {
return typeName;
@Nullable
@Override
public IPartHost getOrPlacePartHost(World w, BlockPos pos, boolean force, @Nullable EntityPlayer p) {
final TileEntity tile = w.getTileEntity(pos);
if (tile instanceof IPartHost partHost) {
return partHost;
} else {
if (!force && !canPlacePartHost(w, pos, p)) {
return null;
}
return o;
final ITileDefinition multiPart = AEApi.instance().definitions().blocks().multiPart();
if (!multiPart.isEnabled()) return null;
Block blk = multiPart.maybeBlock().orElse(null);
if (blk == null) return null;
final IBlockState state = blk.getDefaultState();
w.setBlockState(pos, state, 3);
return w.getTileEntity(pos) instanceof IPartHost host ? host : null;
}
}
private static class CacheKey {
private final Class<? extends AEBaseTile> baseClass;
private final List<String> interfaces;
private CacheKey(Class<? extends AEBaseTile> baseClass, List<String> interfaces) {
this.baseClass = baseClass;
this.interfaces = ImmutableList.copyOf(interfaces);
@Override
public boolean canPlacePartHost(World w, BlockPos pos, @Nullable EntityPlayer p) {
if (p != null && !Platform.hasPermissions(w, pos, p)) {
return false;
}
private Class<? extends AEBaseTile> getBaseClass() {
return this.baseClass;
}
private List<String> getInterfaces() {
return this.interfaces;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || this.getClass() != o.getClass()) {
return false;
}
CacheKey cacheKey = (CacheKey) o;
return this.baseClass.equals(cacheKey.baseClass) && this.interfaces.equals(cacheKey.interfaces);
}
@Override
public int hashCode() {
int result = this.baseClass.hashCode();
result = 31 * result + this.interfaces.hashCode();
return result;
}
final Block blk = w.getBlockState(pos).getBlock();
return blk == null || blk.isReplaceable(w, pos);
}
}
@@ -90,6 +90,7 @@ public final class ApiMaterials implements IMaterials {
private final IItemDefinition cardFuzzy;
private final IItemDefinition cardInverter;
private final IItemDefinition cardCrafting;
private final IItemDefinition cardSticky;
private final IItemDefinition enderDust;
private final IItemDefinition flour;
@@ -208,6 +209,7 @@ public final class ApiMaterials implements IMaterials {
this.cardFuzzy = new DamagedItemDefinition("material.card.fuzzy", materials.createMaterial(MaterialType.CARD_FUZZY));
this.cardInverter = new DamagedItemDefinition("material.card.inverter", materials.createMaterial(MaterialType.CARD_INVERTER));
this.cardCrafting = new DamagedItemDefinition("material.card.crafting", materials.createMaterial(MaterialType.CARD_CRAFTING));
this.cardSticky = new DamagedItemDefinition("material.card.sticky", materials.createMaterial(MaterialType.CARD_STICKY));
this.enderDust = new DamagedItemDefinition("material.dust.ender", materials.createMaterial(MaterialType.ENDER_DUST));
this.flour = new DamagedItemDefinition("material.flour", materials.createMaterial(MaterialType.FLOUR));
@@ -425,6 +427,11 @@ public final class ApiMaterials implements IMaterials {
return this.cardCrafting;
}
@Override
public IItemDefinition cardSticky() {
return this.cardSticky;
}
@Override
public IItemDefinition enderDust() {
return this.enderDust;
@@ -195,6 +195,7 @@ public enum GuiText {
Partitioned,
Precise,
Fuzzy,
Sticky,
// Used in a terminal to indicate that an item is craftable
SmallFontCraft,
@@ -44,8 +44,6 @@ public class AppEngPacketHandlerBase {
PACKET_CONFIG_BUTTON(PacketConfigButton.class),
PACKET_PART_PLACEMENT(PacketPartPlacement.class),
PACKET_LIGHTNING(PacketLightning.class),
PACKET_MATTER_CANNON(PacketMatterCannon.class),
@@ -88,7 +86,13 @@ public class AppEngPacketHandlerBase {
PACKET_TERMINAL_KEYBIND(PacketTerminalUse.class),
PACKET_CRAFTING_TOAST(PacketCraftingToast.class);
PACKET_CRAFTING_TOAST(PacketCraftingToast.class),
PACKET_COLOR_APPLICATOR_SELECT_COLOR(PacketColorApplicatorSelectColor.class),
PACKET_CABLE_BUS_LANDING_PARTICLE(PacketCableBusLandingParticle.class),
;
private final Class<? extends AppEngPacket> packetClass;
@@ -112,6 +112,10 @@ public class NetworkHandler {
this.ec.sendToAllAround(message.getProxy(), point);
}
public void sendToAllTracking(final AppEngPacket message, final NetworkRegistry.TargetPoint point) {
this.ec.sendToAllTracking(message.getProxy(), point);
}
public void sendToDimension(final AppEngPacket message, final int dimensionId) {
this.ec.sendToDimension(message.getProxy(), dimensionId);
}
@@ -0,0 +1,55 @@
package appeng.core.sync.packets;
import appeng.block.networking.BlockCableBus;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class PacketCableBusLandingParticle extends AppEngPacket {
private BlockPos pos;
private double entityX;
private double entityY;
private double entityZ;
private int numberOfParticles;
public PacketCableBusLandingParticle(final ByteBuf stream) {
this.pos = BlockPos.fromLong(stream.readLong());
this.entityX = stream.readDouble();
this.entityY = stream.readDouble();
this.entityZ = stream.readDouble();
this.numberOfParticles = stream.readInt();
}
public PacketCableBusLandingParticle(final BlockPos pos, final Entity entity, final int numberOfParticles) {
final ByteBuf data = Unpooled.buffer();
data.writeInt(this.getPacketID());
data.writeLong(pos.toLong());
data.writeDouble(entity.posX);
data.writeDouble(entity.posY);
data.writeDouble(entity.posZ);
data.writeInt(numberOfParticles);
this.configureWrite(data);
}
@Override
@SideOnly(Side.CLIENT)
public void clientPacketData(INetworkInfo network, AppEngPacket packet, EntityPlayer player) {
final World world = Minecraft.getMinecraft().world;
final IBlockState state = world.getBlockState(pos);
if (state.getBlock() instanceof BlockCableBus cb) {
cb.addLandingParticle(pos, entityX, entityY, entityZ, numberOfParticles);
}
}
}
@@ -19,16 +19,10 @@
package appeng.core.sync.packets;
import appeng.api.AEApi;
import appeng.api.definitions.IComparableDefinition;
import appeng.api.definitions.IItems;
import appeng.api.implementations.items.IMemoryCard;
import appeng.api.implementations.items.MemoryCardMessages;
import appeng.block.networking.BlockCableBus;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo;
import appeng.items.tools.ToolNetworkTool;
import appeng.items.tools.powered.ToolColorApplicator;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.block.Block;
@@ -99,10 +93,6 @@ public class PacketClick extends AppEngPacket {
@Override
public void serverPacketData(final INetworkInfo manager, final AppEngPacket packet, final EntityPlayer player) {
final ItemStack is = player.inventory.getCurrentItem();
final IItems items = AEApi.instance().definitions().items();
final IComparableDefinition maybeMemoryCard = items.memoryCard();
final IComparableDefinition maybeColorApplicator = items.colorApplicator();
final BlockPos pos = new BlockPos(this.x, this.y, this.z);
if (this.leftClick) {
final Block block = player.world.getBlockState(pos).getBlock();
@@ -110,19 +100,9 @@ public class PacketClick extends AppEngPacket {
((BlockCableBus) block).onBlockClickPacket(player.world, pos, player, this.hand, new Vec3d(this.hitX, this.hitY, this.hitZ));
}
} else {
if (!is.isEmpty()) {
if (is.getItem() instanceof ToolNetworkTool) {
final ToolNetworkTool tnt = (ToolNetworkTool) is.getItem();
tnt.serverSideToolLogic(is, player, this.hand, player.world, pos, this.side, this.hitX, this.hitY,
this.hitZ);
} else if (maybeMemoryCard.isSameAs(is)) {
final IMemoryCard mem = (IMemoryCard) is.getItem();
mem.notifyUser(player, MemoryCardMessages.SETTINGS_CLEARED);
is.setTagCompound(null);
} else if (maybeColorApplicator.isSameAs(is)) {
final ToolColorApplicator mem = (ToolColorApplicator) is.getItem();
mem.cycleColors(is, mem.getColor(is), 1);
}
final ItemStack is = player.inventory.getCurrentItem();
if (!is.isEmpty() && is.getItem() instanceof ToolNetworkTool tnt) {
tnt.serverSideToolLogic(is, player, hand, player.world, pos, side, hitX, hitY, hitZ);
}
}
}
@@ -0,0 +1,53 @@
package appeng.core.sync.packets;
import appeng.api.util.AEColor;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo;
import appeng.items.tools.powered.ToolColorApplicator;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import javax.annotation.Nullable;
public class PacketColorApplicatorSelectColor extends AppEngPacket {
@Nullable
private AEColor color = null;
@SuppressWarnings("unused")
public PacketColorApplicatorSelectColor(final ByteBuf stream) {
if (stream.readBoolean()) {
byte colorIdx = stream.readByte();
AEColor[] values = AEColor.values();
if (colorIdx >= 0 && colorIdx < values.length) {
this.color = values[colorIdx];
}
}
}
public PacketColorApplicatorSelectColor(@Nullable final AEColor color) {
final ByteBuf data = Unpooled.buffer();
data.writeInt(this.getPacketID());
if (color != null) {
data.writeBoolean(true);
data.writeByte(color.ordinal());
} else {
data.writeBoolean(false);
}
this.configureWrite(data);
}
@Override
public void serverPacketData(INetworkInfo manager, AppEngPacket packet, EntityPlayer player) {
switchColor(player.getHeldItemMainhand(), color);
switchColor(player.getHeldItemOffhand(), color);
}
private static void switchColor(ItemStack stack, AEColor color) {
if (!stack.isEmpty() && stack.getItem() instanceof ToolColorApplicator colorApp) {
colorApp.setActiveColor(stack, color);
}
}
}
@@ -11,6 +11,8 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import java.io.IOException;
@@ -39,11 +41,15 @@ public class PacketCraftingToast extends AppEngPacket {
@Override
public void clientPacketData(INetworkInfo network, AppEngPacket packet, EntityPlayer player) {
if (AEConfig.instance().isFeatureEnabled(AEFeature.CRAFTING_TOASTS)) {
Minecraft.getMinecraft()
.getToastGui().add(new CraftingStatusToast(stack.asItemStackRepresentation(), cancelled));
doCraftingToast();
}
}
@SideOnly(Side.CLIENT)
private void doCraftingToast() {
Minecraft.getMinecraft().getToastGui().add(new CraftingStatusToast(stack.asItemStackRepresentation(), cancelled));
}
@Override
public void serverPacketData(INetworkInfo manager, AppEngPacket packet, EntityPlayer player) {}
}
@@ -1,79 +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>.
*/
package appeng.core.sync.packets;
import appeng.core.AppEng;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo;
import appeng.parts.PartPlacement;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
public class PacketPartPlacement extends AppEngPacket {
private int x;
private int y;
private int z;
private int face;
private float eyeHeight;
private EnumHand hand;
// automatic.
public PacketPartPlacement(final ByteBuf stream) {
this.x = stream.readInt();
this.y = stream.readInt();
this.z = stream.readInt();
this.face = stream.readByte();
this.eyeHeight = stream.readFloat();
this.hand = EnumHand.values()[stream.readByte()];
}
// api
public PacketPartPlacement(final BlockPos pos, final EnumFacing face, final float eyeHeight, final EnumHand hand) {
final ByteBuf data = Unpooled.buffer();
data.writeInt(this.getPacketID());
data.writeInt(pos.getX());
data.writeInt(pos.getY());
data.writeInt(pos.getZ());
data.writeByte(face.ordinal());
data.writeFloat(eyeHeight);
data.writeByte(hand.ordinal());
this.configureWrite(data);
}
@Override
public void serverPacketData(final INetworkInfo manager, final AppEngPacket packet, final EntityPlayer player) {
final EntityPlayerMP sender = (EntityPlayerMP) player;
AppEng.proxy.updateRenderMode(sender);
PartPlacement.setEyeHeight(this.eyeHeight);
PartPlacement.place(sender.getHeldItem(this.hand), new BlockPos(this.x, this.y, this.z), EnumFacing.VALUES[this.face], sender, this.hand,
sender.world,
PartPlacement.PlaceType.INTERACT_FIRST_PASS, 0);
AppEng.proxy.updateRenderMode(null);
}
}
@@ -24,13 +24,19 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.io.ByteStreams;
import net.minecraft.launchwrapper.IClassTransformer;
import net.minecraft.launchwrapper.Launch;
import net.minecraftforge.fml.common.Loader;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.ClassRemapper;
import org.objectweb.asm.commons.Remapper;
import org.objectweb.asm.tree.*;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import java.io.IOException;
import java.io.InputStream;
@@ -43,23 +49,29 @@ public class AE2ELTransformer implements IClassTransformer {
@Override
public byte[] transform(String name, String transformedName, byte[] basicClass) {
if (Loader.instance().getIndexedModList().get("stackup") != null) {
return basicClass;
}
transformedName = transformedName.replace('/', '.');
Consumer<ClassNode> consumer = (n) -> {
};
if ("net.minecraftforge.common.ForgeHooks".equals(transformedName)) {
ClassReader cr = new ClassReader(basicClass);
ClassWriter cw = new SafeClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
ClassVisitor cv = new PickBlockPatch(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
}
Consumer<ClassNode> consumer = (n) -> {};
Consumer<ClassNode> emptyConsumer = consumer;
if ("net.minecraft.item.ItemStack".equals(transformedName)) {
consumer = consumer.andThen(ItemStackPatch::patchCountGetSet);
} else if ("net.minecraft.network.PacketBuffer".equals(transformedName)) {
consumer = consumer.andThen((node) -> {
spliceClasses(node, "appeng.core.transformer.PacketBufferPatch",
"readItemStack", "func_150791_c",
"writeItemStack", "func_150788_a");
});
if (Loader.instance().getIndexedModList().get("stackup") == null) {
if ("net.minecraft.item.ItemStack".equals(transformedName)) {
consumer = consumer.andThen(ItemStackPatch::patchCountGetSet);
} else if ("net.minecraft.network.PacketBuffer".equals(transformedName)) {
consumer = consumer.andThen((node) -> {
spliceClasses(node, "appeng.core.transformer.PacketBufferPatch",
"readItemStack", "func_150791_c",
"writeItemStack", "func_150788_a");
});
}
}
if (consumer != emptyConsumer) {
@@ -181,4 +193,39 @@ public class AE2ELTransformer implements IClassTransformer {
}
private static class SafeClassWriter extends ClassWriter {
public SafeClassWriter(int flags) {
super(flags);
}
@Override
protected String getCommonSuperClass(final String type1, final String type2) {
Class<?> c, d;
// clueless
ClassLoader classLoader = Launch.classLoader;
try {
c = Class.forName(type1.replace('/', '.'), false, classLoader);
d = Class.forName(type2.replace('/', '.'), false, classLoader);
} catch (Exception e) {
throw new RuntimeException(e.toString());
}
if (c.isAssignableFrom(d)) {
return type1;
}
if (d.isAssignableFrom(c)) {
return type2;
}
if (c.isInterface() || d.isInterface()) {
return "java/lang/Object";
} else {
do {
c = c.getSuperclass();
} while (!c.isAssignableFrom(d));
return c.getName().replace('.', '/');
}
}
}
}
@@ -0,0 +1,76 @@
package appeng.core.transformer;
import appeng.api.AEApi;
import appeng.api.definitions.IItemDefinition;
import appeng.api.implementations.tiles.IColorableTile;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketColorApplicatorSelectColor;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class PickBlockPatch extends ClassVisitor {
public PickBlockPatch(ClassVisitor cv) {
super(Opcodes.ASM5, cv);
}
@SuppressWarnings("unused")
public static boolean testColorApplicatorPickBlock(RayTraceResult result, EntityPlayer player, World world) {
if (player == null || player.world == null || result == null || result.typeOfHit != RayTraceResult.Type.BLOCK) {
return false;
}
IItemDefinition applicator = AEApi.instance().definitions().items().colorApplicator();
if (!applicator.isSameAs(player.getHeldItemMainhand()) && !applicator.isSameAs(player.getHeldItemOffhand())) {
return false;
}
TileEntity tile = player.world.getTileEntity(result.getBlockPos());
if (tile instanceof IColorableTile colorableTile) {
NetworkHandler.instance().sendToServer(new PacketColorApplicatorSelectColor(colorableTile.getColor()));
return true;
}
return false;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if ("onPickBlock".equals(name)) {
return new OnPickBlockVisitor(mv);
}
return mv;
}
private static class OnPickBlockVisitor extends MethodVisitor implements Opcodes {
public OnPickBlockVisitor(MethodVisitor mv) {
super(Opcodes.ASM5, mv);
}
@Override
public void visitCode() {
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(
INVOKESTATIC,
"appeng/core/transformer/PickBlockPatch",
"testColorApplicatorPickBlock",
"(Lnet/minecraft/util/math/RayTraceResult;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/world/World;)Z",
false);
mv.visitInsn(DUP);
Label exitLabel = new Label();
mv.visitJumpInsn(IFEQ, exitLabel);
mv.visitInsn(IRETURN);
mv.visitLabel(exitLabel);
}
}
}
@@ -44,9 +44,14 @@ public class FacadeContainer implements IFacadeContainer {
this.storage = cbs;
}
@Override
public boolean canAddFacade(IFacadePart a) {
return this.getFacade(a.getSide()) == null;
}
@Override
public boolean addFacade(final IFacadePart a) {
if (this.getFacade(a.getSide()) == null) {
if (canAddFacade(a)) {
this.storage.setFacade(a.getSide().ordinal(), a);
return true;
}
@@ -80,6 +80,7 @@ import net.minecraftforge.fluids.capability.IFluidHandler;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -220,11 +221,13 @@ public class PartFluidStorageBus extends PartUpgradeable implements IGridTickabl
@Override
public void postChange(final IBaseMonitor<IAEFluidStack> monitor, final Iterable<IAEFluidStack> change, final IActionSource source) {
if (this.getProxy().isActive()) {
var filteredChanges = this.filterChanges(change);
AccessRestriction currentAccess = (AccessRestriction) ((ConfigManager) this.getConfigManager()).getSetting(Settings.ACCESS);
if (readOncePass) {
readOncePass = false;
try {
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class), change, this.source);
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class), filteredChanges, this.source);
} catch (final GridAccessException e) {
// :(
}
@@ -234,7 +237,7 @@ public class PartFluidStorageBus extends PartUpgradeable implements IGridTickabl
return;
}
try {
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class), change, source);
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class), filteredChanges, source);
} catch (final GridAccessException e) {
// :(
}
@@ -426,6 +429,7 @@ public class PartFluidStorageBus extends PartUpgradeable implements IGridTickabl
this.handler.setBaseAccess((AccessRestriction) this.getConfigManager().getSetting(Settings.ACCESS));
this.handler.setWhitelist(this.getInstalledUpgrades(Upgrades.INVERTER) > 0 ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST);
this.handler.setPriority(this.getPriority());
this.handler.setStorageFilter((StorageFilter) this.getConfigManager().getSetting(Settings.STORAGE_FILTER));
final IItemList<IAEFluidStack> priorityList = AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class).createList();
@@ -437,6 +441,10 @@ public class PartFluidStorageBus extends PartUpgradeable implements IGridTickabl
}
}
if (this.getInstalledUpgrades(Upgrades.STICKY) > 0) {
this.handler.setSticky(true);
}
if (this.getInstalledUpgrades(Upgrades.FUZZY) > 0) {
this.handler.setPartitionList(new FuzzyPriorityList<IAEFluidStack>(priorityList, (FuzzyMode) this.getConfigManager().getSetting(Settings.FUZZY_MODE)));
} else {
@@ -533,4 +541,26 @@ public class PartFluidStorageBus extends PartUpgradeable implements IGridTickabl
public GuiBridge getGuiBridge() {
return GuiBridge.GUI_STORAGEBUS_FLUID;
}
// TODO: 1/28/2024 Unify both methods.
/**
* Filters the changes to only include items that pass the storage filter.
* Optimally, this should be handled by the underlying monitor.
*
* @see appeng.parts.misc.PartStorageBus#filterChanges
*/
protected Iterable<IAEFluidStack> filterChanges(Iterable<IAEFluidStack> change) {
var storageFilter = this.getConfigManager().getSetting(Settings.STORAGE_FILTER);
if (storageFilter == StorageFilter.EXTRACTABLE_ONLY) {
var filteredList = new ArrayList<IAEFluidStack>();
for (final IAEFluidStack stack : change) {
if (this.handler.passesBlackOrWhitelist(stack)) {
filteredList.add(stack);
}
}
return filteredList;
}
return change;
}
}
@@ -1,28 +0,0 @@
package appeng.helpers;
import appeng.util.Platform;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.fml.server.FMLServerHandler;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public class PlayerHelper {
@Nullable
public static EntityPlayerMP getPlayerByUUID(UUID uuid) {
final MinecraftServer server;
if (Platform.isClientInstall()) {
server = Minecraft.getMinecraft().getIntegratedServer();
} else {
server = FMLServerHandler.instance().getServer();
}
if (server == null) {
return null;
}
return server.getPlayerList().getPlayerByUUID(uuid);
}
}
@@ -0,0 +1,208 @@
package appeng.hooks;
import appeng.api.AEApi;
import appeng.api.parts.IFacadePart;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartHost;
import appeng.api.parts.IPartItem;
import appeng.api.parts.SelectedPart;
import appeng.api.util.AEPartLocation;
import appeng.core.AEConfig;
import appeng.facade.FacadePart;
import appeng.facade.IFacadeItem;
import appeng.items.parts.ItemFacade;
import appeng.parts.BusCollisionHelper;
import appeng.parts.PartPlacement;
import appeng.parts.PartPlacement.Placement;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraftforge.client.event.DrawBlockHighlightEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.opengl.GL11;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
@SideOnly(Side.CLIENT)
@Mod.EventBusSubscriber(Side.CLIENT)
public class RenderBlockOutlineHook {
@SubscribeEvent
public static void onDrawHighlightEvent(DrawBlockHighlightEvent event) {
if (event.getTarget() == null) return;
// noinspection ConstantConditions
if (event.getTarget().getBlockPos() == null) return;
if (event.getTarget().typeOfHit != RayTraceResult.Type.BLOCK) return;
EntityPlayer player = event.getPlayer();
ItemStack stack = player.getHeldItemMainhand();
RayTraceResult hitResult = event.getTarget();
if (player.world.getBlockState(hitResult.getBlockPos()).getBlock() == Blocks.AIR) {
return;
}
if (replaceBlockOutline(player, stack, hitResult, event.getPartialTicks())) {
event.setCanceled(true);
}
}
private static boolean replaceBlockOutline(EntityPlayer player, ItemStack stack, RayTraceResult hitResult, float partialTicks) {
BlockPos pos = hitResult.getBlockPos();
// Render the placement preview
if (AEConfig.instance().showPlacementPreview()) {
renderPartPlacementPreview(player, hitResult, stack, partialTicks);
}
IPartHost host = AEApi.instance().partHelper().getPartHost(player.world, pos);
if (host != null) {
// Try to render facade placement preview here, since it's a
// convenient time to do it due to having the Part Host already.
if (AEConfig.instance().showPlacementPreview()) {
renderFacadePlacementPreview(host, player, hitResult, stack, partialTicks);
}
// Render the Part Host block outline, which is done differently from default behavior
SelectedPart selectedPart = host.selectPartGlobal(hitResult.hitVec);
if (selectedPart.facade != null) {
renderFacade(selectedPart.facade, host, pos, selectedPart.side.getFacing(), player, partialTicks, false, false);
return true;
}
if (selectedPart.part != null) {
renderPart(selectedPart.part, pos, selectedPart.side.getFacing(), player, partialTicks, false, false);
return true;
}
}
return false;
}
/** Render a placement preview for a part item, if possible. */
private static void renderPartPlacementPreview(EntityPlayer player, RayTraceResult hitResult, ItemStack stack, float partialTicks) {
if (!(stack.getItem() instanceof IPartItem<?> partItem)) return;
Placement placement = PartPlacement.getPartPlacement(player, player.world, stack, hitResult.getBlockPos(), hitResult.sideHit);
if (placement == null) return;
if (!player.world.getWorldBorder().contains(placement.pos())) return;
IPart part = partItem.createPartFromItemStack(stack);
if (part == null) return;
// Render with two depth passes to render behind blocks
renderPart(part, placement.pos(), placement.side(), player, partialTicks, true, true);
renderPart(part, placement.pos(), placement.side(), player, partialTicks, true, false);
}
/** Render a placement preview for a facade item, if possible. */
private static void renderFacadePlacementPreview(@Nonnull IPartHost host, EntityPlayer player, RayTraceResult hitResult, ItemStack stack, float partialTicks) {
if (!(stack.getItem() instanceof IFacadeItem facadeItem)) return;
Placement placement = PartPlacement.getPartPlacement(player, player.world, stack, hitResult.getBlockPos(), hitResult.sideHit);
if (placement == null) return;
FacadePart part = facadeItem.createPartFromItemStack(stack, AEPartLocation.fromFacing(placement.side()));
if (part == null) return;
if (!ItemFacade.canPlaceFacade(host, part)) return;
// Render with two depth passes to render behind blocks
renderFacade(part, host, placement.pos(), placement.side(), player, partialTicks, true, true);
renderFacade(part, host, placement.pos(), placement.side(), player, partialTicks, true, false);
}
/** Render a part block outline. */
private static void renderPart(IPart part, BlockPos pos, EnumFacing side, EntityPlayer player, float partialTicks, boolean preview, boolean insideBlock) {
List<AxisAlignedBB> boxes = new ArrayList<>();
IPartCollisionHelper helper = new BusCollisionHelper(boxes, AEPartLocation.fromFacing(side), player, true);
part.getBoxes(helper);
offsetBoxes(boxes, pos, player, partialTicks);
renderBoxes(boxes, preview, insideBlock);
}
/** Render a facade block outline. */
private static void renderFacade(IFacadePart facade, IPartHost host, BlockPos pos, EnumFacing side, EntityPlayer player, float partialTicks, boolean preview, boolean insideBlock) {
List<AxisAlignedBB> boxes = new ArrayList<>();
IPartCollisionHelper helper = new BusCollisionHelper(boxes, AEPartLocation.fromFacing(side), player, true);
facade.getBoxes(helper, player);
// Render a cable anchor part box as well if there is no part
// attachment on this side, and if we are in a preview render pass.
if (host.getPart(side) == null && preview) {
addAnchorBox(helper);
}
offsetBoxes(boxes, pos, player, partialTicks);
renderBoxes(boxes, preview, insideBlock);
}
/**
* Render the provided list of AABB boxes as a block outline.
*
* @param preview Whether this is a preview placement or a normal block outline. Determines coloration of the outline.
* @param insideBlock Whether to disable depth test and darken the outline. Will draw behind other blocks.
*/
private static void renderBoxes(List<AxisAlignedBB> boxes, boolean preview, boolean insideBlock) {
GlStateManager.enableBlend();
GlStateManager.tryBlendFuncSeparate(
GlStateManager.SourceFactor.SRC_ALPHA,
GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA,
GlStateManager.SourceFactor.ONE,
GlStateManager.DestFactor.ZERO);
GlStateManager.glLineWidth(2.0F);
GlStateManager.disableTexture2D();
GlStateManager.depthMask(false);
if (insideBlock) {
GL11.glDisable(GL11.GL_DEPTH_TEST);
}
for (AxisAlignedBB box : boxes) {
RenderGlobal.drawSelectionBoundingBox(
box,
preview ? 1 : 0,
preview ? 1 : 0,
preview ? 1 : 0,
insideBlock ? 0.2F : preview ? 0.6F : 0.4F);
}
if (insideBlock) {
GL11.glEnable(GL11.GL_DEPTH_TEST);
}
GlStateManager.depthMask(true);
GlStateManager.enableTexture2D();
GlStateManager.disableBlend();
}
/** Offset each box in the list to the appropriate render position. */
private static void offsetBoxes(List<AxisAlignedBB> boxes, BlockPos pos, EntityPlayer player, float partialTicks) {
double dX = player.lastTickPosX + (player.posX - player.lastTickPosX) * partialTicks;
double dY = player.lastTickPosY + (player.posY - player.lastTickPosY) * partialTicks;
double dZ = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks;
boxes.replaceAll(box -> box.offset(pos.getX() - dX, pos.getY() - dY, pos.getZ() - dZ).grow(0.002D));
}
/** Adds a cable anchor box to the collision helper. This does NOT offset the box! */
private static void addAnchorBox(IPartCollisionHelper helper) {
ItemStack anchorStack = AEApi.instance().definitions().parts().cableAnchor().maybeStack(1).orElse(null);
if (anchorStack != null && anchorStack.getItem() instanceof IPartItem<?> anchorPartItem) {
IPart anchorPart = anchorPartItem.createPartFromItemStack(anchorStack);
if (anchorPart != null) {
anchorPart.getBoxes(helper);
}
}
}
}
@@ -0,0 +1,86 @@
package appeng.hooks;
import appeng.api.parts.IPartHost;
import appeng.api.parts.PartItemStack;
import appeng.api.parts.SelectedPart;
import appeng.api.util.DimensionalCoord;
import appeng.util.LookDirection;
import appeng.util.Platform;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import java.util.ArrayList;
import java.util.List;
/**
* Wrench action, handled in event rather than item to support implementors of our wrench api
*/
public class WrenchClickHook {
@SubscribeEvent
public void playerInteract(final PlayerInteractEvent event) {
// Only handle the main hand event
if (event.getHand() != EnumHand.MAIN_HAND) return;
if (event instanceof PlayerInteractEvent.RightClickBlock && !event.getEntityPlayer().world.isRemote) {
EntityPlayer player = event.getEntityPlayer();
EnumHand hand = event.getHand();
BlockPos pos = event.getPos();
World world = event.getWorld();
ItemStack held = event.getItemStack();
if (!Platform.hasPermissions(new DimensionalCoord(world, pos), player)) {
return;
}
if (player.isSneaking() && Platform.isWrench(player, held, pos)) {
Block block = world.getBlockState(pos).getBlock();
TileEntity tile = world.getTileEntity(pos);
if (!(tile instanceof IPartHost host)) {
return;
}
final LookDirection dir = Platform.getPlayerRay(player, player.getEyeHeight());
final RayTraceResult mop = block.collisionRayTrace(world.getBlockState(pos), world, pos, dir.getA(), dir.getB());
if (mop != null) {
final SelectedPart sp = host.selectPartGlobal(mop.hitVec);
if (sp == null) {
return;
}
final List<ItemStack> is = new ArrayList<>();
if (sp.part != null) {
is.add(sp.part.getItemStack(PartItemStack.WRENCH));
sp.part.getDrops(is, true);
host.removePart(sp.side, false);
}
if (sp.facade != null) {
is.add(sp.facade.getItemStack());
host.getFacadeContainer().removeFacade(host, sp.side);
Platform.notifyBlocksOfNeighbors(world, pos);
}
if (host.isEmpty()) {
host.cleanup();
}
if (!is.isEmpty()) {
Platform.spawnDrops(world, pos, is);
}
} else {
player.swingArm(hand);
}
}
}
}
}
@@ -166,6 +166,8 @@ public final class ItemMaterial extends AEBaseItem implements IStorageComponent,
return Upgrades.MAGNET;
case CARD_QUANTUM_LINK:
return Upgrades.QUANTUM_LINK;
case CARD_STICKY:
return Upgrades.STICKY;
default:
return null;
}
@@ -120,7 +120,9 @@ public enum MaterialType {
CARD_PATTERN_EXPANSION(58, "material_card_pattern_expansion", EnumSet.of(AEFeature.ADVANCED_CARDS)),
CARD_QUANTUM_LINK(59, "material_card_quantum_link", EnumSet.of(AEFeature.ADVANCED_CARDS, AEFeature.QUANTUM_LINKING_CARD)),
CARD_MAGNET(60, "material_card_magnet", EnumSet.of(AEFeature.BASIC_CARDS));
CARD_MAGNET(60, "material_card_magnet", EnumSet.of(AEFeature.BASIC_CARDS)),
CARD_STICKY(61, "material_card_sticky", EnumSet.of(AEFeature.BASIC_CARDS)),
;
private final Set<AEFeature> features;
@@ -22,6 +22,8 @@ package appeng.items.parts;
import appeng.api.AEApi;
import appeng.api.exceptions.MissingDefinitionException;
import appeng.api.parts.IAlphaPassItem;
import appeng.api.parts.IFacadePart;
import appeng.api.parts.IPartHost;
import appeng.api.util.AEPartLocation;
import appeng.core.AELog;
import appeng.core.FacadeConfig;
@@ -40,7 +42,9 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent;
import java.util.ArrayList;
import java.util.List;
@@ -59,7 +63,62 @@ public class ItemFacade extends AEBaseItem implements IFacadeItem, IAlphaPassIte
@Override
public EnumActionResult onItemUseFirst(final EntityPlayer player, final World world, final BlockPos pos, final EnumFacing side, final float hitX, final float hitY, final float hitZ, final EnumHand hand) {
return AEApi.instance().partHelper().placeBus(player.getHeldItem(hand), pos, side, player, hand, world);
ItemStack stack = player.getHeldItem(hand);
if (stack.getItem() != this) {
return EnumActionResult.PASS;
}
FacadePart facade = createPartFromItemStack(stack, AEPartLocation.fromFacing(side));
if (!placeFacade(facade, world, pos)) {
return EnumActionResult.FAIL;
}
if (!world.isRemote) {
if (!player.isCreative()) {
stack.grow(-1);
if (stack.isEmpty()) {
player.setHeldItem(hand, ItemStack.EMPTY);
MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(player, stack, hand));
}
}
return EnumActionResult.SUCCESS;
} else {
player.swingArm(hand);
return EnumActionResult.PASS;
}
}
private static boolean placeFacade(FacadePart facade, World world, BlockPos pos) {
IPartHost host = AEApi.instance().partHelper().getPartHost(world, pos);
if (host == null) {
return false;
}
if (!canPlaceFacade(host, facade)) {
return false;
}
if (!host.getFacadeContainer().addFacade(facade)) {
return false;
}
host.markForSave();
host.markForUpdate();
return true;
}
public static boolean canPlaceFacade(IPartHost host, FacadePart facade) {
if (host.getPart(AEPartLocation.INTERNAL) == null) {
return false;
}
return host.getFacadeContainer().canAddFacade(facade);
}
public static IFacadePart createFacade(ItemStack held, AEPartLocation side) {
if (held.getItem() instanceof IFacadeItem facadeItem) {
return facadeItem.createPartFromItemStack(held, side);
}
return null;
}
@Override
@@ -60,6 +60,7 @@ import net.minecraft.item.ItemSnowball;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
@@ -71,11 +72,13 @@ import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.oredict.OreDictionary;
import org.apache.commons.lang3.text.WordUtils;
import javax.annotation.Nullable;
import java.util.*;
public class ToolColorApplicator extends AEBasePoweredItem implements IStorageCell<IAEItemStack>, IItemGroup, IBlockTool, IMouseWheelItem {
private static final double POWER_PER_USE = 100;
private static final Map<Integer, AEColor> ORE_TO_COLOR = new HashMap<>();
static {
@@ -97,17 +100,27 @@ public class ToolColorApplicator extends AEBasePoweredItem implements IStorageCe
return this.onItemUse(p.getHeldItem(hand), p, w, pos, hand, side, hitX, hitY, hitZ);
}
@Override
public ActionResult<ItemStack> onItemRightClick(World w, EntityPlayer p, EnumHand hand) {
ItemStack stack = p.getHeldItem(hand);
if (p.isSneaking()) {
if (!w.isRemote) {
cycleColors(stack, getColor(stack), 1);
}
return ActionResult.newResult(EnumActionResult.SUCCESS, stack);
}
return ActionResult.newResult(EnumActionResult.PASS, stack);
}
@Override
public EnumActionResult onItemUse(ItemStack is, EntityPlayer p, World w, BlockPos pos, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) {
if (p.isSneaking()) return EnumActionResult.PASS;
final Block blk = w.getBlockState(pos).getBlock();
ItemStack paintBall = this.getColor(is);
final IMEInventory<IAEItemStack> inv = AEApi.instance()
.registries()
.cell()
.getCellInventory(is, null,
AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
final IMEInventory<IAEItemStack> inv = getInventory(is);
if (inv != null) {
final IAEItemStack option = inv.extractItems(AEItemStack.fromItemStack(paintBall), Actionable.SIMULATE, new BaseActionSource());
@@ -122,15 +135,13 @@ public class ToolColorApplicator extends AEBasePoweredItem implements IStorageCe
return EnumActionResult.FAIL;
}
final double powerPerUse = 100;
if (!paintBall.isEmpty() && paintBall.getItem() instanceof ItemSnowball) {
final TileEntity te = w.getTileEntity(pos);
// clean cables.
if (te instanceof IColorableTile) {
if (this.getAECurrentPower(is) > powerPerUse && ((IColorableTile) te).getColor() != AEColor.TRANSPARENT) {
if (this.getAECurrentPower(is) > POWER_PER_USE && ((IColorableTile) te).getColor() != AEColor.TRANSPARENT) {
if (((IColorableTile) te).recolourBlock(side, AEColor.TRANSPARENT, p)) {
inv.extractItems(AEItemStack.fromItemStack(paintBall), Actionable.MODULATE, new BaseActionSource());
this.extractAEPower(is, powerPerUse, Actionable.MODULATE);
consumeItem(is, paintBall, false);
return EnumActionResult.SUCCESS;
}
}
@@ -139,30 +150,79 @@ public class ToolColorApplicator extends AEBasePoweredItem implements IStorageCe
// clean paint balls..
final Block testBlk = w.getBlockState(pos.offset(side)).getBlock();
final TileEntity painted = w.getTileEntity(pos.offset(side));
if (this.getAECurrentPower(is) > powerPerUse && testBlk instanceof BlockPaint && painted instanceof TilePaint) {
inv.extractItems(AEItemStack.fromItemStack(paintBall), Actionable.MODULATE, new BaseActionSource());
this.extractAEPower(is, powerPerUse, Actionable.MODULATE);
if (this.getAECurrentPower(is) > POWER_PER_USE && testBlk instanceof BlockPaint && painted instanceof TilePaint) {
consumeItem(is, paintBall, false);
((TilePaint) painted).cleanSide(side.getOpposite());
return EnumActionResult.SUCCESS;
}
} else if (!paintBall.isEmpty()) {
final AEColor color = this.getColorFromItem(paintBall);
if (color != null && this.getAECurrentPower(is) > powerPerUse) {
if (color != null && this.getAECurrentPower(is) > POWER_PER_USE) {
if (color != AEColor.TRANSPARENT && this.recolourBlock(blk, side, w, pos, side, color, p)) {
inv.extractItems(AEItemStack.fromItemStack(paintBall), Actionable.MODULATE, new BaseActionSource());
this.extractAEPower(is, powerPerUse, Actionable.MODULATE);
consumeItem(is, paintBall, false);
return EnumActionResult.SUCCESS;
}
}
}
}
if (p.isSneaking()) {
this.cycleColors(is, paintBall, 1);
return EnumActionResult.FAIL;
}
public boolean consumeColor(ItemStack applicator, AEColor color, boolean simulate) {
final IMEInventory<IAEItemStack> inv = getInventory(applicator);
if (inv == null) return false;
ItemStack paintItem = null;
for (final IAEItemStack what : inv.getAvailableItems(getChannel().createList())) {
final ItemStack def = what.createItemStack();
def.setCount(1);
if (getColorFromItem(def) == color) {
paintItem = def;
}
}
return EnumActionResult.FAIL;
if (paintItem != null) {
return consumeItem(applicator, paintItem, simulate);
}
return false;
}
public boolean consumeItem(ItemStack applicator, ItemStack paintItem, boolean simulate) {
final IMEInventory<IAEItemStack> inv = getInventory(applicator);
if (inv == null) return false;
final Actionable mode = simulate ? Actionable.SIMULATE : Actionable.MODULATE;
boolean success = inv.extractItems(AEItemStack.fromItemStack(paintItem), mode, new BaseActionSource()) != null
&& this.extractAEPower(applicator, POWER_PER_USE, mode) >= POWER_PER_USE;
// Clear the color when we run out
if (success && !simulate && ItemStack.areItemStacksEqual(paintItem, getColor(applicator))) {
if (inv.extractItems(AEItemStack.fromItemStack(paintItem), Actionable.SIMULATE, new BaseActionSource()) == null) {
setColor(applicator, ItemStack.EMPTY);
}
}
return success;
}
public boolean setActiveColor(ItemStack applicator, @Nullable AEColor color) {
if (color == null) {
setColor(applicator, ItemStack.EMPTY);
return true;
}
final IMEInventory<IAEItemStack> inv = getInventory(applicator);
if (inv == null) return false;
for (IAEItemStack stack : inv.getAvailableItems(getChannel().createList())) {
ItemStack def = stack.getDefinition();
if (getColorFromItem(def) == color) {
setColor(applicator, def);
return true;
}
}
return false;
}
@Override
@@ -191,8 +251,7 @@ public class ToolColorApplicator extends AEBasePoweredItem implements IStorageCe
return AEColor.TRANSPARENT;
}
if (paintBall.getItem() instanceof ItemPaintBall) {
final ItemPaintBall ipb = (ItemPaintBall) paintBall.getItem();
if (paintBall.getItem() instanceof ItemPaintBall ipb) {
return ipb.getColor(paintBall);
} else {
final int[] id = OreDictionary.getOreIDs(paintBall);
@@ -207,6 +266,13 @@ public class ToolColorApplicator extends AEBasePoweredItem implements IStorageCe
return null;
}
private IMEInventory<IAEItemStack> getInventory(ItemStack stack) {
return AEApi.instance()
.registries()
.cell()
.getCellInventory(stack, null, getChannel());
}
public ItemStack getColor(final ItemStack is) {
final NBTTagCompound c = is.getTagCompound();
if (c != null && c.hasKey("color")) {
@@ -223,14 +289,9 @@ public class ToolColorApplicator extends AEBasePoweredItem implements IStorageCe
private ItemStack findNextColor(final ItemStack is, final ItemStack anchor, final int scrollOffset) {
ItemStack newColor = ItemStack.EMPTY;
final IMEInventory<IAEItemStack> inv = AEApi.instance()
.registries()
.cell()
.getCellInventory(is, null,
AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
final IMEInventory<IAEItemStack> inv = getInventory(is);
if (inv != null) {
final IItemList<IAEItemStack> itemList = inv
.getAvailableItems(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class).createList());
final IItemList<IAEItemStack> itemList = inv.getAvailableItems(getChannel().createList());
if (anchor.isEmpty()) {
final IAEItemStack firstItem = itemList.getFirstItem();
if (firstItem != null) {
@@ -243,11 +304,8 @@ public class ToolColorApplicator extends AEBasePoweredItem implements IStorageCe
list.add(i);
}
Collections.sort(list, (a, b) -> Integer.compare(a.getItemDamage(), b.getItemDamage()));
if (list.size() <= 0) {
return ItemStack.EMPTY;
}
Collections.sort(list, Comparator.comparingInt(IAEItemStack::getItemDamage));
if (list.isEmpty()) return ItemStack.EMPTY;
IAEItemStack where = list.getFirst();
int cycles = 1 + list.size();
+3
View File
@@ -221,6 +221,9 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
// new craftables!
for (final ICraftingPatternDetails details : this.craftingMethods.keySet()) {
for (IAEItemStack out : details.getOutputs()) {
if (out == null) {
continue;
}
out = out.copy();
out.reset();
out.setCraftable(true);
@@ -41,12 +41,12 @@ import appeng.api.util.WorldCoord;
import appeng.container.ContainerNull;
import appeng.core.AEConfig;
import appeng.core.AELog;
import appeng.core.AppEng;
import appeng.core.features.AEFeature;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketCraftingToast;
import appeng.crafting.*;
import appeng.helpers.PatternHelper;
import appeng.helpers.PlayerHelper;
import appeng.me.cache.CraftingGridCache;
import appeng.me.cluster.IAECluster;
import appeng.me.helpers.MachineSource;
@@ -57,6 +57,7 @@ import appeng.util.Platform;
import appeng.util.item.AEItemStack;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@@ -395,10 +396,10 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU {
if (this.finalOutput == null) return;
if (!AEConfig.instance().isFeatureEnabled(AEFeature.CRAFTING_TOASTS)) return;
var player = PlayerHelper.getPlayerByUUID(this.requestingPlayerUUID);
if (player != null) {
var player = AppEng.proxy.getPlayerByUUID(this.requestingPlayerUUID);
if (player instanceof EntityPlayerMP playerMP) {
try {
NetworkHandler.instance().sendTo(new PacketCraftingToast(this.finalOutput, cancelled), player);
NetworkHandler.instance().sendTo(new PacketCraftingToast(this.finalOutput, cancelled), playerMP);
} catch (IOException ignored) {}
}
}
@@ -160,4 +160,8 @@ public class MEMonitorHandler<T extends IAEStack<T>> implements IMEMonitor<T> {
return this.getHandler().validForPass(i);
}
@Override
public boolean isSticky() {
return this.internalHandler.isSticky();
}
}
@@ -51,8 +51,8 @@ public abstract class AbstractCellInventory<T extends IAEStack<T>> implements IC
private final NBTTagCompound tagCompound;
protected final ISaveProvider container;
private int maxItemTypes = MAX_ITEM_TYPES;
private short storedItems = 0;
private int storedItemCount = 0;
private short storedItemTypes = 0;
private long storedItemCount = 0;
protected IItemList<T> cellItems;
private final ItemStack i;
protected final IStorageCell<T> cellType;
@@ -81,8 +81,8 @@ public abstract class AbstractCellInventory<T extends IAEStack<T>> implements IC
this.container = container;
this.tagCompound = Platform.openNbtData(o);
this.storedItems = this.tagCompound.getShort(ITEM_TYPE_TAG);
this.storedItemCount = this.tagCompound.getInteger(ITEM_COUNT_TAG);
this.storedItemTypes = this.tagCompound.getShort(ITEM_TYPE_TAG);
this.storedItemCount = this.tagCompound.getLong(ITEM_COUNT_TAG);
this.cellItems = null;
}
@@ -101,7 +101,7 @@ public abstract class AbstractCellInventory<T extends IAEStack<T>> implements IC
return;
}
int itemCount = 0;
long itemCount = 0;
// add new pretty stuff...
int x = 0;
@@ -111,25 +111,25 @@ public abstract class AbstractCellInventory<T extends IAEStack<T>> implements IC
final NBTTagCompound g = new NBTTagCompound();
v.writeToNBT(g);
this.tagCompound.setTag(ITEM_SLOT_KEYS[x], g);
this.tagCompound.setInteger(ITEM_SLOT_COUNT_KEYS[x], (int) v.getStackSize());
this.tagCompound.setLong(ITEM_SLOT_COUNT_KEYS[x], v.getStackSize());
x++;
}
final short oldStoredItems = this.storedItems;
final short oldStoredItems = this.storedItemTypes;
this.storedItems = (short) this.cellItems.size();
this.storedItemTypes = (short) this.cellItems.size();
if (this.cellItems.isEmpty()) {
this.tagCompound.removeTag(ITEM_TYPE_TAG);
} else {
this.tagCompound.setShort(ITEM_TYPE_TAG, this.storedItems);
this.tagCompound.setShort(ITEM_TYPE_TAG, this.storedItemTypes);
}
this.storedItemCount = itemCount;
if (itemCount == 0) {
this.tagCompound.removeTag(ITEM_COUNT_TAG);
} else {
this.tagCompound.setInteger(ITEM_COUNT_TAG, itemCount);
this.tagCompound.setLong(ITEM_COUNT_TAG, itemCount);
}
// clean any old crusty stuff...
@@ -143,7 +143,7 @@ public abstract class AbstractCellInventory<T extends IAEStack<T>> implements IC
protected void saveChanges() {
// recalculate values
this.storedItems = (short) this.cellItems.size();
this.storedItemTypes = (short) this.cellItems.size();
this.storedItemCount = 0;
for (final T v : this.cellItems) {
this.storedItemCount += v.getStackSize();
@@ -165,12 +165,12 @@ public abstract class AbstractCellInventory<T extends IAEStack<T>> implements IC
this.cellItems.resetStatus(); // clears totals and stuff.
final int types = (int) this.getStoredItemTypes();
final long types = this.getStoredItemTypes();
boolean needsUpdate = false;
for (int slot = 0; slot < types; slot++) {
NBTTagCompound compoundTag = this.tagCompound.getCompoundTag(ITEM_SLOT_KEYS[slot]);
int stackSize = this.tagCompound.getInteger(ITEM_SLOT_COUNT_KEYS[slot]);
long stackSize = this.tagCompound.getLong(ITEM_SLOT_COUNT_KEYS[slot]);
needsUpdate |= !this.loadCellItem(compoundTag, stackSize);
}
@@ -186,7 +186,7 @@ public abstract class AbstractCellInventory<T extends IAEStack<T>> implements IC
* @param stackSize
* @return true when successfully loaded
*/
protected abstract boolean loadCellItem(NBTTagCompound compoundTag, int stackSize);
protected abstract boolean loadCellItem(NBTTagCompound compoundTag, long stackSize);
@Override
public IItemList<T> getAvailableItems(final IItemList<T> out) {
@@ -256,14 +256,14 @@ public abstract class AbstractCellInventory<T extends IAEStack<T>> implements IC
@Override
public long getStoredItemTypes() {
return this.storedItems;
return this.storedItemTypes;
}
@Override
public long getRemainingItemTypes() {
final long basedOnStorage = this.getFreeBytes() / this.getBytesPerType();
final long baseOnTotal = this.getTotalItemTypes() - this.getStoredItemTypes();
return basedOnStorage > baseOnTotal ? baseOnTotal : basedOnStorage;
return Math.min(basedOnStorage, baseOnTotal);
}
@Override
@@ -205,7 +205,7 @@ public class BasicCellInventory<T extends IAEStack<T>> extends AbstractCellInven
}
@Override
protected boolean loadCellItem(NBTTagCompound compoundTag, int stackSize) {
protected boolean loadCellItem(NBTTagCompound compoundTag, long stackSize) {
// Now load the item stack
final T t;
try {
@@ -56,6 +56,7 @@ public class BasicCellInventoryHandler<T extends IAEStack<T>> extends MEInventor
boolean hasInverter = false;
boolean hasFuzzy = false;
boolean hasSticky = false;
for (int x = 0; x < upgrades.getSlots(); x++) {
final ItemStack is = upgrades.getStackInSlot(x);
@@ -69,6 +70,9 @@ public class BasicCellInventoryHandler<T extends IAEStack<T>> extends MEInventor
case INVERTER:
hasInverter = true;
break;
case STICKY:
hasSticky = true;
break;
default:
}
}
@@ -87,6 +91,10 @@ public class BasicCellInventoryHandler<T extends IAEStack<T>> extends MEInventor
this.setWhitelist(hasInverter ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST);
if (hasSticky) {
setSticky(true);
}
if (!priorityList.isEmpty()) {
if (hasFuzzy) {
this.setPartitionList(new FuzzyPriorityList<>(priorityList, fzMode));
@@ -40,7 +40,6 @@ public class DriveWatcher<T extends IAEStack<T>> extends MEInventoryHandler<T> {
private final ICellHandler handler;
private final TileDrive drive;
private final IActionSource source;
public DriveWatcher(final ICellInventoryHandler<T> i, final ItemStack is, final ICellHandler han, final TileDrive drive) {
super(i, i.getChannel());
this.is = is;
@@ -100,4 +99,13 @@ public class DriveWatcher<T extends IAEStack<T>> extends MEInventoryHandler<T> {
return extractable;
}
@Override
public boolean isSticky() {
if (this.getInternal() instanceof ICellInventoryHandler<?> cellInventoryHandler) {
return cellInventoryHandler.isSticky();
}
return super.isSticky();
}
}
@@ -22,6 +22,7 @@ package appeng.me.storage;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
import appeng.api.config.IncludeExclude;
import appeng.api.config.StorageFilter;
import appeng.api.networking.security.IActionSource;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEInventoryHandler;
@@ -38,11 +39,14 @@ public class MEInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHa
private int myPriority;
private IncludeExclude myWhitelist;
private AccessRestriction myAccess;
private StorageFilter storageFilter;
private IPartitionList<T> myPartitionList;
private AccessRestriction cachedAccessRestriction;
private boolean hasReadAccess;
private boolean hasWriteAccess;
private boolean isSticky;
private boolean gettingAvailableContent;
public MEInventoryHandler(final IMEInventory<T> i, final IStorageChannel<T> channel) {
if (i instanceof IMEInventoryHandler) {
@@ -76,7 +80,7 @@ public class MEInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHa
this.hasWriteAccess = this.cachedAccessRestriction.hasPermission(AccessRestriction.WRITE);
}
IPartitionList<T> getPartitionList() {
public IPartitionList<T> getPartitionList() {
return this.myPartitionList;
}
@@ -95,7 +99,7 @@ public class MEInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHa
@Override
public T extractItems(final T request, final Actionable type, final IActionSource src) {
if (!this.hasReadAccess) {
if (!this.canExtract(request)) {
return null;
}
@@ -104,11 +108,27 @@ public class MEInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHa
@Override
public IItemList<T> getAvailableItems(final IItemList<T> out) {
if (!this.hasReadAccess) {
if (this.gettingAvailableContent || !this.hasReadAccess) {
return out;
}
return this.internal.getAvailableItems(out);
this.gettingAvailableContent = true;
try {
if (this.storageFilter == StorageFilter.EXTRACTABLE_ONLY) {
var stackList = this.internal.getAvailableItems(this.getChannel().createList());
for (final T t : stackList) {
if (this.shouldItemBeAvailable(t)) {
out.add(t);
}
}
} else {
return this.internal.getAvailableItems(out);
}
} finally {
this.gettingAvailableContent = false;
}
return out;
}
@Override
@@ -135,13 +155,11 @@ public class MEInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHa
return false;
}
if (this.myWhitelist == IncludeExclude.BLACKLIST && this.myPartitionList.isListed(input)) {
if (!this.passesBlackOrWhitelist(input)) {
return false;
}
if (this.myPartitionList.isEmpty() || this.myWhitelist == IncludeExclude.BLACKLIST) {
return this.internal.canAccept(input);
}
return this.myPartitionList.isListed(input) && this.internal.canAccept(input);
return this.internal.canAccept(input);
}
@Override
@@ -166,4 +184,40 @@ public class MEInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHa
public IMEInventory<T> getInternal() {
return this.internal;
}
@Override
public boolean isSticky() {
return isSticky;
}
public void setSticky(boolean isSticky) {
this.isSticky = isSticky;
}
protected boolean canExtract(T request) {
return this.hasReadAccess;
}
private boolean shouldItemBeAvailable(T t) {
return this.hasReadAccess && this.passesBlackOrWhitelist(t);
}
public boolean passesBlackOrWhitelist(T input) {
if (this.myPartitionList.isEmpty()) {
return true;
}
return switch (this.myWhitelist) {
case WHITELIST -> this.myPartitionList.isListed(input);
case BLACKLIST -> !this.myPartitionList.isListed(input);
};
}
public StorageFilter getStorageFilter() {
return storageFilter;
}
public void setStorageFilter(StorageFilter storageFilter) {
this.storageFilter = storageFilter;
}
}
@@ -31,6 +31,7 @@ import appeng.api.storage.IStorageChannel;
import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IItemList;
import appeng.me.cache.SecurityCache;
import net.minecraft.network.Packet;
import java.util.*;
@@ -45,19 +46,24 @@ public class NetworkInventoryHandler<T extends IAEStack<T>> implements IMEInvent
private final IStorageChannel<T> myChannel;
private final SecurityCache security;
private final NavigableMap<Integer, List<IMEInventoryHandler<T>>> priorityInventory;
private final NavigableMap<Integer, List<IMEInventoryHandler<T>>> stickyPriorityInventory;
private int myPass = 0;
public NetworkInventoryHandler(final IStorageChannel<T> chan, final SecurityCache security) {
this.myChannel = chan;
this.security = security;
this.priorityInventory = new TreeMap<>(PRIORITY_SORTER);
this.stickyPriorityInventory = new TreeMap<>(PRIORITY_SORTER);
}
public void addNewStorage(final IMEInventoryHandler<T> h) {
final int priority = h.getPriority();
List<IMEInventoryHandler<T>> list = this.priorityInventory.get(priority);
if (list == null) {
this.priorityInventory.put(priority, list = new ArrayList<>());
final List<IMEInventoryHandler<T>> list;
if (h.isSticky()) {
list = this.stickyPriorityInventory.computeIfAbsent(priority, $ -> new ArrayList<>());
} else {
list = this.priorityInventory.computeIfAbsent(priority, $ -> new ArrayList<>());
}
list.add(h);
@@ -74,6 +80,25 @@ public class NetworkInventoryHandler<T extends IAEStack<T>> implements IMEInvent
return input;
}
boolean stickyInventoryFound = false;
// For this pass we do return input if the item is able to go into a sticky inventory. We NEVER want to try and
// insert the item into a non-sticky inventory if it could already go into a sticky inventory.
for (final List<IMEInventoryHandler<T>> stickyInvList : this.stickyPriorityInventory.values()) {
Iterator<IMEInventoryHandler<T>> ii = stickyInvList.iterator();
while (ii.hasNext() && input != null) {
final IMEInventoryHandler<T> inv = ii.next();
if (inv.validForPass(1) && inv.canAccept(input) && (inv.isPrioritized(input) || inv.extractItems(input, Actionable.SIMULATE, src) != null)) {
input = inv.injectItems(input, type, src);
stickyInventoryFound = true;
}
}
}
if (stickyInventoryFound) {
this.surface(this, type);
return input;
}
for (final List<IMEInventoryHandler<T>> invList : this.priorityInventory.values()) {
Iterator<IMEInventoryHandler<T>> ii = invList.iterator();
while (ii.hasNext() && input != null) {
@@ -186,6 +211,16 @@ public class NetworkInventoryHandler<T extends IAEStack<T>> implements IMEInvent
}
}
for (List<IMEInventoryHandler<T>> invList : this.stickyPriorityInventory.descendingMap().values()) {
final Iterator<IMEInventoryHandler<T>> jj = invList.iterator();
while (jj.hasNext() && output.getStackSize() < req) {
final IMEInventoryHandler<T> inv = jj.next();
request.setStackSize(req - output.getStackSize());
output.add(inv.extractItems(request, mode, src));
}
}
this.surface(this, mode);
if (output.getStackSize() <= 0) {
@@ -201,15 +236,21 @@ public class NetworkInventoryHandler<T extends IAEStack<T>> implements IMEInvent
return out;
}
// for (Entry<Integer, IMEInventoryHandler<T>> h : priorityInventory.entries())
for (final List<IMEInventoryHandler<T>> i : this.priorityInventory.values()) {
out = iterateInventories(out, priorityInventory);
out = iterateInventories(out, stickyPriorityInventory);
this.surface(this, Actionable.SIMULATE);
return out;
}
private IItemList<T> iterateInventories(IItemList<T> out, final NavigableMap<Integer, List<IMEInventoryHandler<T>>> map) {
for (final List<IMEInventoryHandler<T>> i : map.values()) {
for (final IMEInventoryHandler<T> j : i) {
out = j.getAvailableItems(out);
}
}
this.surface(this, Actionable.SIMULATE);
return out;
}
@@ -37,6 +37,7 @@ import appeng.core.AELog;
import appeng.core.AEConfig;
import appeng.facade.FacadeContainer;
import appeng.helpers.AEMultiTile;
import appeng.items.parts.ItemFacade;
import appeng.me.GridConnection;
import appeng.parts.networking.PartCable;
import appeng.util.Platform;
@@ -65,7 +66,6 @@ import java.util.*;
public class CableBusContainer extends CableBusStorage implements AEMultiTile, ICableBusContainer {
private static final ThreadLocal<Boolean> IS_LOADING = new ThreadLocal<>();
private final EnumSet<LayerFlags> myLayerFlags = EnumSet.noneOf(LayerFlags.class);
private YesNo hasRedstone = YesNo.UNDECIDED;
private IPartHost tcb;
// TODO 1.10.2-R - does somebody seriously want to make parts TESR??? Hope not.
@@ -111,7 +111,7 @@ public class CableBusContainer extends CableBusStorage implements AEMultiTile, I
@Override
public boolean canAddPart(ItemStack is, final AEPartLocation side) {
if (PartPlacement.isFacade(is, side) != null) {
if (ItemFacade.createFacade(is, side) != null) {
return true;
}
@@ -424,11 +424,6 @@ public class CableBusContainer extends CableBusStorage implements AEMultiTile, I
return true;
}
@Override
public Set<LayerFlags> getLayerFlags() {
return this.myLayerFlags;
}
@Override
public void cleanup() {
this.tcb.cleanup();
+64 -328
View File
@@ -18,377 +18,113 @@
package appeng.parts;
import appeng.api.AEApi;
import appeng.api.definitions.IBlockDefinition;
import appeng.api.definitions.IItems;
import appeng.api.parts.*;
import appeng.api.util.AEPartLocation;
import appeng.api.util.DimensionalCoord;
import appeng.core.AppEng;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketClick;
import appeng.core.sync.packets.PacketPartPlacement;
import appeng.facade.IFacadeItem;
import appeng.util.LookDirection;
import appeng.util.Platform;
import net.minecraft.block.Block;
import com.github.bsideup.jabel.Desugar;
import net.minecraft.block.SoundType;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nullable;
public class PartPlacement {
private static float eyeHeight = 0.0f;
private final ThreadLocal<Object> placing = new ThreadLocal<>();
private boolean wasCanceled = false;
public static EnumActionResult place(final ItemStack held, final BlockPos pos, EnumFacing side, final EntityPlayer player, final EnumHand hand, final World world) {
if (!(held.getItem() instanceof IPartItem<?>)) {
return EnumActionResult.PASS;
}
public static EnumActionResult place(final ItemStack held, final BlockPos pos, EnumFacing side, final EntityPlayer player, final EnumHand hand, final World world, PlaceType pass, final int depth) {
if (depth > 3) {
// determine where the part would be placed
Placement placement = getPartPlacement(player, world, held, pos, side);
if (placement == null) {
return EnumActionResult.FAIL;
}
if (!held.isEmpty() && Platform.isWrench(player, held, pos) && player.isSneaking()) {
if (!Platform.hasPermissions(new DimensionalCoord(world, pos), player)) {
return EnumActionResult.FAIL;
}
final Block block = world.getBlockState(pos).getBlock();
final TileEntity tile = world.getTileEntity(pos);
IPartHost host = null;
if (tile instanceof IPartHost) {
host = (IPartHost) tile;
}
if (host != null) {
if (!world.isRemote) {
final LookDirection dir = Platform.getPlayerRay(player, getEyeOffset(player));
final RayTraceResult mop = block.collisionRayTrace(world.getBlockState(pos), world, pos, dir.getA(), dir.getB());
if (mop != null) {
final List<ItemStack> is = new ArrayList<>();
final SelectedPart sp = selectPart(player, host,
mop.hitVec.add(-mop.getBlockPos().getX(), -mop.getBlockPos().getY(), -mop.getBlockPos().getZ()));
if (sp.part != null) {
is.add(sp.part.getItemStack(PartItemStack.WRENCH));
sp.part.getDrops(is, true);
host.removePart(sp.side, false);
}
if (sp.facade != null) {
is.add(sp.facade.getItemStack());
host.getFacadeContainer().removeFacade(host, sp.side);
Platform.notifyBlocksOfNeighbors(world, pos);
}
if (host.isEmpty()) {
host.cleanup();
}
if (!is.isEmpty()) {
Platform.spawnDrops(world, pos, is);
}
}
} else {
player.swingArm(hand);
NetworkHandler.instance().sendToServer(new PacketPartPlacement(pos, side, getEyeOffset(player), hand));
}
return EnumActionResult.SUCCESS;
}
return EnumActionResult.PASS;
}
TileEntity tile = world.getTileEntity(pos);
IPartHost host = null;
if (tile instanceof IPartHost) {
host = (IPartHost) tile;
}
if (!held.isEmpty()) {
final IFacadePart fp = isFacade(held, AEPartLocation.fromFacing(side));
if (fp != null) {
if (host != null) {
if (!world.isRemote) {
if (host.getPart(AEPartLocation.INTERNAL) == null) {
return EnumActionResult.FAIL;
}
if (host.canAddPart(held, AEPartLocation.fromFacing(side))) {
if (host.getFacadeContainer().addFacade(fp)) {
host.markForSave();
host.markForUpdate();
if (!player.capabilities.isCreativeMode) {
held.grow(-1);
if (held.getCount() == 0) {
player.setHeldItem(hand, ItemStack.EMPTY);
MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(player, held, hand));
}
}
return EnumActionResult.SUCCESS;
}
}
} else {
player.swingArm(hand);
NetworkHandler.instance().sendToServer(new PacketPartPlacement(pos, side, getEyeOffset(player), hand));
return EnumActionResult.SUCCESS;
}
}
return EnumActionResult.FAIL;
}
}
if (held.isEmpty()) {
final Block block = world.getBlockState(pos).getBlock();
if (host != null && player.isSneaking() && block != null) {
final LookDirection dir = Platform.getPlayerRay(player, getEyeOffset(player));
final RayTraceResult mop = block.collisionRayTrace(world.getBlockState(pos), world, pos, dir.getA(), dir.getB());
if (mop != null) {
mop.hitVec = mop.hitVec.add(-mop.getBlockPos().getX(), -mop.getBlockPos().getY(), -mop.getBlockPos().getZ());
final SelectedPart sPart = selectPart(player, host, mop.hitVec);
if (sPart != null && sPart.part != null) {
if (sPart.part.onShiftActivate(player, hand, mop.hitVec)) {
if (world.isRemote) {
NetworkHandler.instance().sendToServer(new PacketPartPlacement(pos, side, getEyeOffset(player), hand));
}
return EnumActionResult.SUCCESS;
}
}
}
}
}
if (held.isEmpty() || !(held.getItem() instanceof IPartItem)) {
return EnumActionResult.PASS;
}
BlockPos te_pos = pos;
final IBlockDefinition multiPart = AEApi.instance().definitions().blocks().multiPart();
if (host == null && pass == PlaceType.PLACE_ITEM) {
EnumFacing offset = null;
final Block blkID = world.getBlockState(pos).getBlock();
if (blkID != null && !blkID.isReplaceable(world, pos)) {
offset = side;
if (Platform.isServer()) {
side = side.getOpposite();
}
}
te_pos = offset == null ? pos : pos.offset(offset);
tile = world.getTileEntity(te_pos);
if (tile instanceof IPartHost) {
host = (IPartHost) tile;
}
final Optional<ItemStack> maybeMultiPartStack = multiPart.maybeStack(1);
final Optional<Block> maybeMultiPartBlock = multiPart.maybeBlock();
final Optional<ItemBlock> maybeMultiPartItemBlock = multiPart.maybeItemBlock();
final boolean hostIsNotPresent = host == null;
final boolean multiPartPresent = maybeMultiPartBlock.isPresent() && maybeMultiPartStack.isPresent() && maybeMultiPartItemBlock.isPresent();
final boolean canMultiPartBePlaced = maybeMultiPartBlock.get().canPlaceBlockAt(world, te_pos);
if (hostIsNotPresent && multiPartPresent && canMultiPartBePlaced && maybeMultiPartItemBlock.get()
.placeBlockAt(maybeMultiPartStack.get(), player,
world, te_pos, side, 0.5f, 0.5f, 0.5f, maybeMultiPartBlock.get().getDefaultState())) {
if (!world.isRemote) {
tile = world.getTileEntity(te_pos);
if (tile instanceof IPartHost) {
host = (IPartHost) tile;
}
pass = PlaceType.INTERACT_SECOND_PASS;
} else {
player.swingArm(hand);
NetworkHandler.instance().sendToServer(new PacketPartPlacement(pos, side, getEyeOffset(player), hand));
return EnumActionResult.SUCCESS;
}
} else if (host != null && !host.canAddPart(held, AEPartLocation.fromFacing(side))) {
return EnumActionResult.FAIL;
}
}
if (host == null) {
return EnumActionResult.PASS;
}
if (!host.canAddPart(held, AEPartLocation.fromFacing(side))) {
if (pass == PlaceType.INTERACT_FIRST_PASS || pass == PlaceType.PLACE_ITEM) {
te_pos = pos.offset(side);
final Block blkID = world.getBlockState(te_pos).getBlock();
if (blkID == null || blkID.isReplaceable(world, te_pos) || host != null) {
return place(held, te_pos, side.getOpposite(), player, hand, world,
pass == PlaceType.INTERACT_FIRST_PASS ? PlaceType.INTERACT_SECOND_PASS : PlaceType.PLACE_ITEM, depth + 1);
}
}
return EnumActionResult.PASS;
// then try to place it
IPart part = placePart(player, world, held, placement.pos(), placement.side(), hand);
if (part == null) {
return EnumActionResult.FAIL;
}
// handle placement logic with the stack
if (!world.isRemote) {
final IBlockState state = world.getBlockState(pos);
final LookDirection dir = Platform.getPlayerRay(player, getEyeOffset(player));
final RayTraceResult mop = state.getBlock().collisionRayTrace(state, world, pos, dir.getA(), dir.getB());
if (mop != null) {
final SelectedPart sp = selectPart(player, host,
mop.hitVec.add(-mop.getBlockPos().getX(), -mop.getBlockPos().getY(), -mop.getBlockPos().getZ()));
if (sp.part != null) {
if (!player.isSneaking() && sp.part.onActivate(player, hand, mop.hitVec)) {
return EnumActionResult.FAIL;
}
}
}
final DimensionalCoord dc = host.getLocation();
if (!Platform.hasPermissions(dc, player)) {
return EnumActionResult.FAIL;
}
final AEPartLocation mySide = host.addPart(held, AEPartLocation.fromFacing(side), player, hand);
if (mySide != null) {
multiPart.maybeBlock().ifPresent(multiPartBlock ->
{
final SoundType ss = multiPartBlock.getSoundType(state, world, pos, player);
world.playSound(null, pos, ss.getPlaceSound(), SoundCategory.BLOCKS, (ss.getVolume() + 1.0F) / 2.0F, ss.getPitch() * 0.8F);
});
if (!player.capabilities.isCreativeMode) {
held.grow(-1);
if (held.getCount() == 0) {
player.setHeldItem(hand, ItemStack.EMPTY);
MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(player, held, hand));
}
if (player != null && !player.isCreative()) {
held.shrink(1);
if (held.getCount() == 0) {
player.setHeldItem(hand, ItemStack.EMPTY);
MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(player, held, hand));
}
}
return EnumActionResult.SUCCESS;
} else {
player.swingArm(hand);
return EnumActionResult.PASS;
}
return EnumActionResult.SUCCESS;
}
private static float getEyeOffset(final EntityPlayer p) {
if (p.world.isRemote) {
return Platform.getEyeOffset(p);
public static IPart placePart(@Nullable EntityPlayer player, World world, ItemStack partItem, BlockPos pos, EnumFacing side, EnumHand hand) {
IPartHost host = AEApi.instance().partHelper().getOrPlacePartHost(world, pos, false, player);
if (host == null) {
return null;
}
return getEyeHeight();
}
private static SelectedPart selectPart(final EntityPlayer player, final IPartHost host, final Vec3d pos) {
AppEng.proxy.updateRenderMode(player);
final SelectedPart sp = host.selectPart(pos);
AppEng.proxy.updateRenderMode(null);
return sp;
}
public static IFacadePart isFacade(final ItemStack held, final AEPartLocation side) {
if (held.getItem() instanceof IFacadeItem) {
return ((IFacadeItem) held.getItem()).createPartFromItemStack(held, side);
AEPartLocation location = host.addPart(partItem, AEPartLocation.fromFacing(side), player, hand);
IPart part = host.getPart(location);
if (part == null) {
if (host.isEmpty()) {
host.cleanup();
}
return null;
}
IBlockState multiPartState = AEApi.instance().definitions().blocks().multiPart().maybeBlock().get().getDefaultState();
SoundType soundType = multiPartState.getBlock().getSoundType(multiPartState, world, pos, null);
world.playSound(null, pos, soundType.getPlaceSound(), SoundCategory.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F);
return part;
}
@Nullable
public static Placement getPartPlacement(@Nullable EntityPlayer player, World world, ItemStack partStack, BlockPos pos, EnumFacing side) {
if (canPlacePartOnBlock(player, world, partStack, pos, side)) {
return new Placement(pos, side);
}
// If the part cannot be placed directly in the block, try the opposite side of
// the adjacent block. This is somewhat similar to how torches are placed.
pos = pos.offset(side);
side = side.getOpposite();
if (canPlacePartOnBlock(player, world, partStack, pos, side)) {
return new Placement(pos, side);
}
// can't place the part
return null;
}
@SubscribeEvent
public void playerInteract(final TickEvent.ClientTickEvent event) {
this.wasCanceled = false;
}
public static boolean canPlacePartOnBlock(@Nullable EntityPlayer player, World world, ItemStack partStack, BlockPos pos, EnumFacing side) {
IPartHost host = AEApi.instance().partHelper().getPartHost(world, pos);
@SubscribeEvent
public void playerInteract(final PlayerInteractEvent event) {
// Only handle the main hand event
if (event.getHand() != EnumHand.MAIN_HAND) {
return;
// There is no host at the location, we also cannot place one
if (host == null && !AEApi.instance().partHelper().canPlacePartHost(world, pos, player)) {
return false;
}
if (event instanceof PlayerInteractEvent.RightClickEmpty && event.getEntityPlayer().world.isRemote) {
// re-check to see if this event was already channeled, cause these two events are really stupid...
final RayTraceResult mop = Platform.rayTrace(event.getEntityPlayer(), true, false);
final Minecraft mc = Minecraft.getMinecraft();
final float f = 1.0F;
final double d0 = mc.playerController.getBlockReachDistance();
final Vec3d vec3 = mc.getRenderViewEntity().getPositionEyes(f);
if (mop != null && mop.hitVec.distanceTo(vec3) < d0) {
final World w = event.getEntity().world;
final TileEntity te = w.getTileEntity(mop.getBlockPos());
if (te instanceof IPartHost && this.wasCanceled) {
event.setCanceled(true);
}
} else {
final ItemStack held = event.getEntityPlayer().getHeldItem(event.getHand());
final IItems items = AEApi.instance().definitions().items();
boolean supportedItem = items.memoryCard().isSameAs(held);
supportedItem |= items.colorApplicator().isSameAs(held);
if (event.getEntityPlayer().isSneaking() && !held.isEmpty() && supportedItem) {
NetworkHandler.instance().sendToServer(new PacketClick(event.getPos(), event.getFace(), 0, 0, 0, event.getHand()));
}
}
} else if (event instanceof PlayerInteractEvent.RightClickBlock && !event.getEntityPlayer().world.isRemote) {
if (this.placing.get() != null) {
return;
}
this.placing.set(event);
final ItemStack held = event.getEntityPlayer().getHeldItem(event.getHand());
if (place(held, event.getPos(), event.getFace(), event.getEntityPlayer(), event.getHand(), event.getEntityPlayer().world,
PlaceType.INTERACT_FIRST_PASS, 0) == EnumActionResult.SUCCESS) {
event.setCanceled(true);
this.wasCanceled = true;
}
this.placing.set(null);
}
// Either there is no host, then we assume a freshly placed host will always accept our part,
// or there is a host, and it has a free side.
return host == null || host.canAddPart(partStack, AEPartLocation.fromFacing(side));
}
private static float getEyeHeight() {
return eyeHeight;
@Desugar
public record Placement(BlockPos pos, EnumFacing side) {
}
public static void setEyeHeight(final float eyeHeight) {
PartPlacement.eyeHeight = eyeHeight;
}
public enum PlaceType {
PLACE_ITEM, INTERACT_FIRST_PASS, INTERACT_SECOND_PASS
}
}
}
@@ -48,6 +48,7 @@ public abstract class UpgradeInventory extends AppEngInternalInventory implement
private int patternExpansionUpgrades = 0;
private int magnetUpgrades = 0;
private int quantumUpgrades = 0;
private int stickyUpgrades = 0;
public UpgradeInventory(final IAEAppEngInventory parent, final int s) {
super(null, s, 1);
@@ -85,6 +86,8 @@ public abstract class UpgradeInventory extends AppEngInternalInventory implement
return this.magnetUpgrades;
case QUANTUM_LINK:
return this.quantumUpgrades;
case STICKY:
return this.stickyUpgrades;
default:
return 0;
}
@@ -94,7 +97,7 @@ public abstract class UpgradeInventory extends AppEngInternalInventory implement
private void updateUpgradeInfo() {
this.cached = true;
this.patternExpansionUpgrades = this.inverterUpgrades = this.capacityUpgrades = this.redstoneUpgrades = this.speedUpgrades = this.fuzzyUpgrades = this.craftingUpgrades = magnetUpgrades = quantumUpgrades = 0;
this.patternExpansionUpgrades = this.inverterUpgrades = this.capacityUpgrades = this.redstoneUpgrades = this.speedUpgrades = this.fuzzyUpgrades = this.craftingUpgrades = magnetUpgrades = quantumUpgrades = stickyUpgrades = 0;
for (final ItemStack is : this) {
if (is == null || is.getItem() == Items.AIR || !(is.getItem() instanceof IUpgradeModule)) {
@@ -129,6 +132,10 @@ public abstract class UpgradeInventory extends AppEngInternalInventory implement
break;
case QUANTUM_LINK:
this.quantumUpgrades++;
break;
case STICKY:
this.stickyUpgrades++;
break;
default:
break;
}
@@ -143,6 +150,7 @@ public abstract class UpgradeInventory extends AppEngInternalInventory implement
this.patternExpansionUpgrades = Math.min(this.patternExpansionUpgrades, this.getMaxInstalled(Upgrades.PATTERN_EXPANSION));
this.magnetUpgrades = Math.min(this.magnetUpgrades, this.getMaxInstalled(Upgrades.MAGNET));
this.quantumUpgrades = Math.min(this.quantumUpgrades, this.getMaxInstalled(Upgrades.QUANTUM_LINK));
this.stickyUpgrades = Math.min(this.stickyUpgrades, this.getMaxInstalled(Upgrades.STICKY));
}
@Override
@@ -111,8 +111,8 @@ public class PartOreDicStorageBus extends PartStorageBus {
this.handler.setBaseAccess((AccessRestriction) this.getConfigManager().getSetting(Settings.ACCESS));
this.handler.setWhitelist(this.getInstalledUpgrades(Upgrades.INVERTER) > 0 ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST);
this.handler.setPriority(this.priority);
this.handler.setPartitionList(this.getPriorityList());
this.handler.setStorageFilter((StorageFilter) this.getConfigManager().getSetting(Settings.STORAGE_FILTER));
if (inv instanceof IBaseMonitor) {
if (((AccessRestriction) ((ConfigManager) this.getConfigManager()).getSetting(Settings.ACCESS)).hasPermission(AccessRestriction.READ)) {
@@ -165,9 +165,7 @@ public class PartOreDicStorageBus extends PartStorageBus {
this.oreExp = oreMatch;
this.priorityList = new OreDictPriorityList<>(OreHelper.INSTANCE.getMatchingOre(oreExp), oreExp);
if (this.handler != null) {
handler.setPartitionList(this.priorityList);
}
this.resetCache(true);
this.getHost().markForSave();
}
}
@@ -80,6 +80,7 @@ import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -113,6 +114,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
this.getConfigManager().registerSetting(Settings.ACCESS, AccessRestriction.READ_WRITE);
this.getConfigManager().registerSetting(Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL);
this.getConfigManager().registerSetting(Settings.STORAGE_FILTER, StorageFilter.EXTRACTABLE_ONLY);
this.getConfigManager().registerSetting(Settings.STICKY_MODE, YesNo.NO);
this.mySrc = new MachineSource(this);
}
@@ -194,7 +196,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
return super.getInventoryByName(name);
}
private void resetCache(final boolean fullReset) {
protected void resetCache(final boolean fullReset) {
if (this.getHost() == null || this.getHost().getTile() == null || this.getHost().getTile().getWorld() == null || this.getHost().getTile().getWorld().isRemote) {
return;
}
@@ -220,11 +222,13 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
@Override
public void postChange(final IBaseMonitor<IAEItemStack> monitor, final Iterable<IAEItemStack> change, final IActionSource source) {
if (this.getProxy().isActive()) {
var filteredChanges = this.filterChanges(change);
AccessRestriction currentAccess = (AccessRestriction) ((ConfigManager) this.getConfigManager()).getSetting(Settings.ACCESS);
if (readOncePass) {
readOncePass = false;
try {
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class), change, mySrc);
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class), filteredChanges, mySrc);
} catch (final GridAccessException e) {
// :(
}
@@ -234,7 +238,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
return;
}
try {
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class), change, source);
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class), filteredChanges, source);
} catch (final GridAccessException e) {
// :(
}
@@ -315,7 +319,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
return TickRateModulation.SLEEP;
}
private void resetCache() {
protected void resetCache() {
final boolean fullReset = this.resetCacheLogic == 2;
this.resetCacheLogic = 0;
@@ -456,6 +460,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
this.handler.setBaseAccess((AccessRestriction) this.getConfigManager().getSetting(Settings.ACCESS));
this.handler.setWhitelist(this.getInstalledUpgrades(Upgrades.INVERTER) > 0 ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST);
this.handler.setPriority(this.priority);
this.handler.setStorageFilter((StorageFilter) this.getConfigManager().getSetting(Settings.STORAGE_FILTER));
final IItemList<IAEItemStack> priorityList = AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class).createList();
@@ -467,6 +472,10 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
}
}
if (this.getInstalledUpgrades(Upgrades.STICKY) > 0) {
this.handler.setSticky(true);
}
if (this.getInstalledUpgrades(Upgrades.FUZZY) > 0) {
this.handler.setPartitionList(new FuzzyPriorityList<>(priorityList, (FuzzyMode) this.getConfigManager().getSetting(Settings.FUZZY_MODE)));
} else {
@@ -566,4 +575,26 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
public GuiBridge getGuiBridge() {
return GuiBridge.GUI_STORAGEBUS;
}
// TODO: 1/28/2024 Unify both methods.
/**
* Filters the changes to only include items that pass the storage filter.
* Optimally, this should be handled by the underlying monitor.
*
* @see appeng.fluids.parts.PartFluidStorageBus#filterChanges
*/
protected Iterable<IAEItemStack> filterChanges(Iterable<IAEItemStack> change) {
var storageFilter = this.getConfigManager().getSetting(Settings.STORAGE_FILTER);
if (storageFilter == StorageFilter.EXTRACTABLE_ONLY) {
var filteredList = new ArrayList<IAEItemStack>();
for (final IAEItemStack stack : change) {
if (this.handler.passesBlackOrWhitelist(stack)) {
filteredList.add(stack);
}
}
return filteredList;
}
return change;
}
}
@@ -36,6 +36,7 @@ import appeng.api.util.AEColor;
import appeng.api.util.AEPartLocation;
import appeng.api.util.IReadOnlyCollection;
import appeng.items.parts.ItemPart;
import appeng.items.tools.powered.ToolColorApplicator;
import appeng.me.GridAccessException;
import appeng.parts.AEBasePart;
import appeng.util.Platform;
@@ -45,6 +46,7 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import java.io.IOException;
import java.util.EnumSet;
@@ -93,6 +95,22 @@ public class PartCable extends AEBasePart implements IPartCable {
}
}
@Override
public void onPlacement(EntityPlayer player, EnumHand hand, ItemStack held, AEPartLocation side) {
super.onPlacement(player, hand, held, side);
// Apply color applicator color if held in offhand
ItemStack stack = player.getHeldItem(EnumHand.OFF_HAND);
if (!stack.isEmpty() && stack.getItem() instanceof ToolColorApplicator colorApp) {
AEColor color = colorApp.getActiveColor(stack);
if (color != null && color != getCableColor() && colorApp.consumeColor(stack, color, true)) {
if (changeColor(color, player) && !player.isCreative()) {
colorApp.consumeColor(stack, color, false);
}
}
}
}
@Override
public boolean changeColor(final AEColor newColor, final EntityPlayer who) {
if (this.getCableColor() != newColor) {
@@ -42,6 +42,7 @@ import net.minecraftforge.fml.common.FMLCommonHandler;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;
public class ServerHelper extends CommonHelper {
@@ -167,4 +168,17 @@ public class ServerHelper extends CommonHelper {
public boolean isActionKey(ActionKey key, int pressedKeyCode) {
return false;
}
@Override
public EntityPlayer getPlayerByUUID(UUID uuid) {
if (!Platform.isClient()) {
final MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance();
if (server != null) {
return server.getPlayerList().getPlayerByUUID(uuid);
}
}
return null;
}
}
@@ -22,13 +22,11 @@ package appeng.tile.networking;
import appeng.api.networking.IGridNode;
import appeng.api.parts.IFacadeContainer;
import appeng.api.parts.IPart;
import appeng.api.parts.LayerFlags;
import appeng.api.parts.SelectedPart;
import appeng.api.util.AECableType;
import appeng.api.util.AEColor;
import appeng.api.util.AEPartLocation;
import appeng.api.util.DimensionalCoord;
import appeng.block.networking.BlockCableBus;
import appeng.helpers.AEMultiTile;
import appeng.helpers.ICustomCollision;
import appeng.hooks.TickHandler;
@@ -101,7 +99,7 @@ public class TileCableBus extends AEBaseTile implements AEMultiTile, ICustomColl
protected void updateTileSetting() {
if (this.getCableBus().isRequiresDynamicRender()) {
try {
final TileCableBus tcb = (TileCableBus) BlockCableBus.getTesrTile().newInstance();
final TileCableBus tcb = TileCableBusTESR.class.newInstance();
tcb.copyFrom(this);
this.getWorld().setTileEntity(this.pos, tcb);
} catch (final Throwable ignored) {
@@ -283,11 +281,6 @@ public class TileCableBus extends AEBaseTile implements AEMultiTile, ICustomColl
return this.getCableBus().isEmpty();
}
@Override
public Set<LayerFlags> getLayerFlags() {
return this.getCableBus().getLayerFlags();
}
@Override
public void cleanup() {
this.getWorld().setBlockToAir(this.pos);
@@ -19,9 +19,6 @@
package appeng.tile.networking;
import appeng.block.networking.BlockCableBus;
public class TileCableBusTESR extends TileCableBus {
/**
@@ -31,7 +28,7 @@ public class TileCableBusTESR extends TileCableBus {
protected void updateTileSetting() {
if (!this.getCableBus().isRequiresDynamicRender()) {
try {
final TileCableBus tcb = (TileCableBus) BlockCableBus.getNoTesrTile().newInstance();
final TileCableBus tcb = TileCableBus.class.newInstance();
tcb.copyFrom(this);
this.getWorld().setTileEntity(this.pos, tcb);
} catch (final Throwable ignored) {
@@ -178,6 +178,12 @@ public class TileIOPort extends AENetworkInvTile implements IUpgradeableHost, IC
}
}
@Override
public void gridChanged() {
super.gridChanged();
updateTask();
}
public void updateRedstoneState() {
final YesNo currentState = this.world.getRedstonePowerFromNeighbors(this.pos) != 0 ? YesNo.YES : YesNo.NO;
if (this.lastRedstoneState != currentState) {
+4
View File
@@ -384,6 +384,10 @@ public class Platform {
return dc.getWorld().canMineBlockBody(player, dc.getPos());
}
public static boolean hasPermissions(final World world, final BlockPos pos, final EntityPlayer player) {
return world.canMineBlockBody(player, pos);
}
/*
* Checks to see if a block is air?
*/
@@ -253,6 +253,7 @@ gui.appliedenergistics2.Renamer=Custom Name: (Enter to set)
gui.appliedenergistics2.Nothing=Nothing
gui.appliedenergistics2.CraftingToastDone=Crafting Done!
gui.appliedenergistics2.CraftingToastCancelled=Crafting Cancelled!
gui.appliedenergistics2.Sticky=Sticky
// GUI Tooltips
gui.tooltips.appliedenergistics2.Stash=Store Items
@@ -524,6 +525,7 @@ item.appliedenergistics2.material.silicon_print.name=Printed Silicon
item.appliedenergistics2.material.name_press.name=Inscriber Name Press
item.appliedenergistics2.material.sky_dust.name=Sky Stone Dust
item.appliedenergistics2.material.card_crafting.name=Crafting Card
item.appliedenergistics2.material.card_sticky.name=Sticky Card
item.appliedenergistics2.multi_part.annihilation_plane.name=ME Annihilation Plane
item.appliedenergistics2.multi_part.fluid_annihilation_plane.name=ME Fluid Annihilation Plane
@@ -45,9 +45,9 @@ tile.appliedenergistics2.smooth_sky_stone_chest.name=陨石块箱子
tile.appliedenergistics2.sky_compass.name=陨石罗盘
tile.appliedenergistics2.crafting_monitor.name=合成监控器
tile.appliedenergistics2.crafting_storage_1k.name=§61k§r合成存储器
tile.appliedenergistics2.crafting_storage_4k.name=§e4k§r4k合成存储器
tile.appliedenergistics2.crafting_storage_16k.name=§a16k§r16k合成存储器
tile.appliedenergistics2.crafting_storage_64k.name=§b64k§r64k合成存储器
tile.appliedenergistics2.crafting_storage_4k.name=§e4k§r合成存储器
tile.appliedenergistics2.crafting_storage_16k.name=§a16k§r合成存储器
tile.appliedenergistics2.crafting_storage_64k.name=§b64k§r合成存储器
tile.appliedenergistics2.crafting_accelerator.name=并行处理单元
tile.appliedenergistics2.crafting_unit.name=合成单元
tile.appliedenergistics2.molecular_assembler.name=分子装配室
@@ -251,6 +251,9 @@ gui.appliedenergistics2.SmallFontCraft=Craft
gui.appliedenergistics2.LargeFontCraft=+
gui.appliedenergistics2.Renamer=自定义名称(按下Enter以设定)
gui.appliedenergistics2.Nothing=无
gui.appliedenergistics2.CraftingToastDone=合成已完成!
gui.appliedenergistics2.CraftingToastCancelled=合成已取消!
gui.appliedenergistics2.Sticky=粘滞
// GUI Tooltips
gui.tooltips.appliedenergistics2.Stash=存储物品
@@ -522,6 +525,7 @@ item.appliedenergistics2.material.silicon_print.name=硅板
item.appliedenergistics2.material.name_press.name=名称压印模板
item.appliedenergistics2.material.sky_dust.name=陨石粉
item.appliedenergistics2.material.card_crafting.name=合成卡
item.appliedenergistics2.material.card_sticky.name=粘滞卡
item.appliedenergistics2.multi_part.annihilation_plane.name=ME破坏面板
item.appliedenergistics2.multi_part.fluid_annihilation_plane.name=ME流体破坏面板
@@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "appliedenergistics2:items/material_card_sticky"
}
}
@@ -0,0 +1,31 @@
{
"conditions": [
{
"type": "forge:and",
"values": [
{
"type": "appliedenergistics2:material_exists",
"material": "material.card_sticky"
},
{
"type": "appliedenergistics2:material_exists",
"material": "material.basic_card"
}
]
}
],
"result": {
"type": "appliedenergistics2:part",
"part": "material.card_sticky"
},
"type": "appliedenergistics2:part_shapeless",
"ingredients": [
{
"item": "minecraft:slime_ball"
},
{
"type": "appliedenergistics2:part",
"part": "material.basic_card"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 287 B

After

Width:  |  Height:  |  Size: 216 B

@@ -0,0 +1,55 @@
package appeng.client.gui;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MathExpressionParserTest {
@ParameterizedTest
@CsvSource(value = {
"1 + 2|3",
"3 *4 |12",
"1 + 2 * 3 |7",
"1 - 6|-5",
"1/3|0.333333",
"23.4 + 0.6|24",
"1 - -4|5",
"1 + 4*3*2|25",
"1/0|failed",
"1/(1 - 1)|failed",
"3 + 2 * 4 - 1 /2|10.5",
"1 + (2 * (2 * (1 + 1)))|9",
"arkazkdhz|failed",
"1 + 2 3 7 - 1|237", // whitespace is trimmed
"2 + + 2|failed",
"10e6|10000000",
"-1 -1|-2",
"- (1 + 1)|-2",
"2 * -1|-2",
"2 -2|0",
"- 1|-1",
"-1|-1",
"- - - - - 5|failed", // not able to handle multiple negations, may fix in the future
"-(-(-(-2)))|failed", // not able to handle multiple negations, may fix in the future
"1 - -1|2",
"1 + -(2|failed"
}, delimiter = '|')
void testMath(String expression, String expected) {
DecimalFormat format = new DecimalFormat("#.######", DecimalFormatSymbols.getInstance(Locale.US));
format.setParseBigDecimal(true);
format.setNegativePrefix("-");
double parsed = MathExpressionParser.parse(expression);
if (Double.isNaN(parsed)) {
assertEquals(expected, "failed");
} else {
assertEquals(expected, format.format(parsed));
}
}
}
@@ -19,9 +19,10 @@
package appeng.core.worlddata;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
/**
* Tests for {@link MeteorDataNameEncoder}
@@ -51,7 +52,7 @@ public class MeteorDataNameEncoderTest
final String expected = WITHOUT_EXPECTED;
final String actual = this.encoderWithZeroShifting.encode( WITHOUT_DIMENSION, WITHOUT_CHUNK_X, WITHOUT_CHUNK_Z );
Assert.assertEquals( expected, actual );
assertThat( expected, is(actual) );
}
@Test
@@ -60,6 +61,6 @@ public class MeteorDataNameEncoderTest
final String expected = WITH_EXPECTED;
final String actual = this.encoderWithFourShifting.encode( WITH_DIMENSION, WITH_CHUNK_X, WITH_CHUNK_Z );
Assert.assertEquals( expected, actual );
assertThat( expected, is(actual) );
}
}
@@ -2,10 +2,11 @@
package appeng.core.worlddata;
import org.junit.Assert;
import org.junit.Test;
import net.minecraft.util.math.BlockPos;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class SpatialDimensionManagerTest
@@ -45,31 +46,31 @@ public class SpatialDimensionManagerTest
{
SpatialDimensionManager manager = new SpatialDimensionManager( null );
Assert.assertEquals( ID_1, manager.createNewCellDimension( CONTENT, -1 ) );
Assert.assertEquals( ID_2, manager.createNewCellDimension( CONTENT, -1 ) );
Assert.assertEquals( ID_3, manager.createNewCellDimension( CONTENT, -1 ) );
Assert.assertEquals( ID_4, manager.createNewCellDimension( CONTENT, -1 ) );
Assert.assertEquals( ID_5, manager.createNewCellDimension( CONTENT, -1 ) );
Assert.assertEquals( ID_6, manager.createNewCellDimension( CONTENT, -1 ) );
Assert.assertEquals( ID_7, manager.createNewCellDimension( CONTENT, -1 ) );
Assert.assertEquals( ID_8, manager.createNewCellDimension( CONTENT, -1 ) );
Assert.assertEquals( ID_9, manager.createNewCellDimension( CONTENT, -1 ) );
Assert.assertEquals( ID_A, manager.createNewCellDimension( CONTENT, -1 ) );
Assert.assertEquals( ID_B, manager.createNewCellDimension( CONTENT, -1 ) );
Assert.assertEquals( ID_C, manager.createNewCellDimension( CONTENT, -1 ) );
assertThat( ID_1, is(manager.createNewCellDimension( CONTENT, -1 ) ) );
assertThat( ID_2, is(manager.createNewCellDimension( CONTENT, -1 ) ) );
assertThat( ID_3, is(manager.createNewCellDimension( CONTENT, -1 ) ) );
assertThat( ID_4, is(manager.createNewCellDimension( CONTENT, -1 ) ) );
assertThat( ID_5, is(manager.createNewCellDimension( CONTENT, -1 ) ) );
assertThat( ID_6, is(manager.createNewCellDimension( CONTENT, -1 ) ) );
assertThat( ID_7, is(manager.createNewCellDimension( CONTENT, -1 ) ) );
assertThat( ID_8, is(manager.createNewCellDimension( CONTENT, -1 ) ) );
assertThat( ID_9, is(manager.createNewCellDimension( CONTENT, -1 ) ) );
assertThat( ID_A, is(manager.createNewCellDimension( CONTENT, -1 ) ) );
assertThat( ID_B, is(manager.createNewCellDimension( CONTENT, -1 ) ) );
assertThat( ID_C, is(manager.createNewCellDimension( CONTENT, -1 ) ) );
Assert.assertEquals( POS_1, manager.getCellDimensionOrigin( ID_1 ) );
Assert.assertEquals( POS_2, manager.getCellDimensionOrigin( ID_2 ) );
Assert.assertEquals( POS_3, manager.getCellDimensionOrigin( ID_3 ) );
Assert.assertEquals( POS_4, manager.getCellDimensionOrigin( ID_4 ) );
Assert.assertEquals( POS_5, manager.getCellDimensionOrigin( ID_5 ) );
Assert.assertEquals( POS_6, manager.getCellDimensionOrigin( ID_6 ) );
Assert.assertEquals( POS_7, manager.getCellDimensionOrigin( ID_7 ) );
Assert.assertEquals( POS_8, manager.getCellDimensionOrigin( ID_8 ) );
Assert.assertEquals( POS_9, manager.getCellDimensionOrigin( ID_9 ) );
Assert.assertEquals( POS_A, manager.getCellDimensionOrigin( ID_A ) );
Assert.assertEquals( POS_B, manager.getCellDimensionOrigin( ID_B ) );
Assert.assertEquals( POS_C, manager.getCellDimensionOrigin( ID_C ) );
assertThat( POS_1, is(manager.getCellDimensionOrigin( ID_1 ) ) );
assertThat( POS_2, is(manager.getCellDimensionOrigin( ID_2 ) ) );
assertThat( POS_3, is(manager.getCellDimensionOrigin( ID_3 ) ) );
assertThat( POS_4, is(manager.getCellDimensionOrigin( ID_4 ) ) );
assertThat( POS_5, is(manager.getCellDimensionOrigin( ID_5 ) ) );
assertThat( POS_6, is(manager.getCellDimensionOrigin( ID_6 ) ) );
assertThat( POS_7, is(manager.getCellDimensionOrigin( ID_7 ) ) );
assertThat( POS_8, is(manager.getCellDimensionOrigin( ID_8 ) ) );
assertThat( POS_9, is(manager.getCellDimensionOrigin( ID_9 ) ) );
assertThat( POS_A, is(manager.getCellDimensionOrigin( ID_A ) ) );
assertThat( POS_B, is(manager.getCellDimensionOrigin( ID_B ) ) );
assertThat( POS_C, is(manager.getCellDimensionOrigin( ID_C ) ) );
}
}
@@ -19,9 +19,10 @@
package appeng.services.version;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
/**
* @author thatsIch
@@ -46,20 +47,20 @@ public class ModVersionFetcherTest
}
@Test
public void testInDev() throws Exception
public void testInDev()
{
Assert.assertEquals( this.indev.get(), new DoNotCheckVersion() );
assertThat( this.indev.get(), is( new DoNotCheckVersion() ) );
}
@Test
public void testPR() throws Exception
public void testPR()
{
Assert.assertEquals( this.pullRequest.get(), new DoNotCheckVersion() );
assertThat( this.pullRequest.get(), is( new DoNotCheckVersion() ) );
}
@Test
public void testWorking() throws Exception
public void testWorking()
{
Assert.assertEquals( this.working.get(), new DefaultVersion( 2, Channel.Beta, 8 ) );
assertThat( this.working.get(), is( new DefaultVersion( 2, Channel.Beta, 8) ) );
}
}
@@ -19,18 +19,17 @@
package appeng.services.version;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import appeng.services.version.exceptions.InvalidBuildException;
import appeng.services.version.exceptions.InvalidChannelException;
import appeng.services.version.exceptions.InvalidRevisionException;
import appeng.services.version.exceptions.InvalidVersionException;
import appeng.services.version.exceptions.MissingSeparatorException;
import appeng.services.version.exceptions.VersionCheckerException;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
@@ -63,66 +62,66 @@ public final class VersionParserTest
{
final Version version = this.parser.parse( GITHUB_VERSION );
assertEquals( version, version );
assertThat( version, is( version ) );
}
@Test
public void testParseGitHub() throws VersionCheckerException
{
assertTrue( this.parser.parse( GITHUB_VERSION ).equals( VERSION ) );
assertThat( this.parser.parse( GITHUB_VERSION ), is( VERSION ) );
}
@Test( expected = InvalidRevisionException.class )
public void parseGH_InvalidRevision() throws VersionCheckerException
@Test
public void parseGH_InvalidRevision()
{
assertFalse( this.parser.parse( GITHUB_INVALID_REVISION ).equals( VERSION ) );
assertThrows( InvalidRevisionException.class, () -> this.parser.parse( GITHUB_INVALID_REVISION ));
}
@Test( expected = InvalidChannelException.class )
public void parseGH_InvalidChannel() throws VersionCheckerException
@Test
public void parseGH_InvalidChannel()
{
assertFalse( this.parser.parse( GITHUB_INVALID_CHANNEL ).equals( VERSION ) );
assertThrows( InvalidChannelException.class, () -> this.parser.parse( GITHUB_INVALID_CHANNEL ) );
}
@Test( expected = InvalidBuildException.class )
public void parseGH_InvalidBuild() throws VersionCheckerException
@Test
public void parseGH_InvalidBuild()
{
assertFalse( this.parser.parse( GITHUB_INVALID_BUILD ).equals( VERSION ) );
assertThrows( InvalidBuildException.class, () -> this.parser.parse( GITHUB_INVALID_BUILD ) );
}
@Test
public void testParseMod() throws VersionCheckerException
{
assertTrue( this.parser.parse( MOD_VERSION ).equals( VERSION ) );
assertThat( this.parser.parse( MOD_VERSION ), is( VERSION ) );
}
@Test( expected = InvalidRevisionException.class )
public void parseMod_InvalidRevision() throws VersionCheckerException
@Test
public void parseMod_InvalidRevision()
{
assertFalse( this.parser.parse( MOD_INVALID_REVISION ).equals( VERSION ) );
assertThrows( InvalidRevisionException.class, () -> this.parser.parse( MOD_INVALID_REVISION ) );
}
@Test( expected = InvalidChannelException.class )
public void parseMod_InvalidChannel() throws VersionCheckerException
@Test
public void parseMod_InvalidChannel()
{
assertFalse( this.parser.parse( MOD_INVALID_CHANNEL ).equals( VERSION ) );
assertThrows( InvalidChannelException.class, () -> this.parser.parse( MOD_INVALID_CHANNEL ) );
}
@Test( expected = InvalidBuildException.class )
public void parseMod_InvalidBuild() throws VersionCheckerException
@Test
public void parseMod_InvalidBuild()
{
assertFalse( this.parser.parse( MOD_INVALID_BUILD ).equals( VERSION ) );
assertThrows( InvalidBuildException.class, () -> this.parser.parse( MOD_INVALID_BUILD ) );
}
@Test( expected = MissingSeparatorException.class )
public void parseGeneric_MissingSeparator() throws VersionCheckerException
@Test
public void parseGeneric_MissingSeparator()
{
assertFalse( this.parser.parse( GENERIC_MISSING_SEPARATOR ).equals( VERSION ) );
assertThrows( MissingSeparatorException.class, () -> this.parser.parse( GENERIC_MISSING_SEPARATOR ) );
}
@Test( expected = InvalidVersionException.class )
public void parseGeneric_InvalidVersion() throws VersionCheckerException
@Test
public void parseGeneric_InvalidVersion()
{
assertFalse( this.parser.parse( GENERIC_INVALID_VERSION ).equals( VERSION ) );
assertThrows( InvalidVersionException.class, () -> this.parser.parse( GENERIC_INVALID_VERSION ) );
}
}
@@ -19,8 +19,10 @@
package appeng.services.version;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
/**
@@ -43,77 +45,77 @@ public final class VersionTest
@Test
public void testDevBuild()
{
Assert.assertEquals( DO_NOT_CHECK_VERSION.formatted(), "dev build" );
assertThat( DO_NOT_CHECK_VERSION.formatted(), is( "dev build" ) );
}
@Test
public void testMissingBuild()
{
Assert.assertEquals( MISSING_VERSION.formatted(), "missing" );
assertThat( MISSING_VERSION.formatted(), is ( "missing" ) );
}
@Test
public void compareVersionToDoNotCheck()
{
Assert.assertFalse( DEFAULT_VERSION_RV2_ALPHA_8.isNewerAs( DO_NOT_CHECK_VERSION ) );
Assert.assertTrue( DO_NOT_CHECK_VERSION.isNewerAs( DEFAULT_VERSION_RV2_ALPHA_8 ) );
assertThat( DEFAULT_VERSION_RV2_ALPHA_8.isNewerAs( DO_NOT_CHECK_VERSION ), is( false ) );
assertThat( DO_NOT_CHECK_VERSION.isNewerAs( DEFAULT_VERSION_RV2_ALPHA_8 ), is( true ) );
}
@Test
public void compareVersionToMissingVersion()
{
Assert.assertTrue( DEFAULT_VERSION_RV2_ALPHA_8.isNewerAs( MISSING_VERSION ) );
Assert.assertFalse( MISSING_VERSION.isNewerAs( DEFAULT_VERSION_RV2_ALPHA_8 ) );
assertThat( DEFAULT_VERSION_RV2_ALPHA_8.isNewerAs( MISSING_VERSION ), is( true ) );
assertThat( MISSING_VERSION.isNewerAs( DEFAULT_VERSION_RV2_ALPHA_8 ), is( false ) );
}
@Test
public void compareTwoDefaultVersions()
{
Assert.assertTrue( DEFAULT_VERSION_RV2_BETA_8.isNewerAs( DEFAULT_VERSION_RV2_ALPHA_8 ) );
Assert.assertTrue( DEFAULT_VERSION_RV4_ALPHA_1.isNewerAs( DEFAULT_VERSION_RV3_BETA_8 ) );
Assert.assertTrue( DEFAULT_VERSION_RV2_BETA_9.isNewerAs( DEFAULT_VERSION_RV2_BETA_8 ) );
assertThat( DEFAULT_VERSION_RV2_BETA_8.isNewerAs( DEFAULT_VERSION_RV2_ALPHA_8 ), is( true ) );
assertThat( DEFAULT_VERSION_RV4_ALPHA_1.isNewerAs( DEFAULT_VERSION_RV3_BETA_8 ), is( true ) );
assertThat( DEFAULT_VERSION_RV2_BETA_9.isNewerAs( DEFAULT_VERSION_RV2_BETA_8 ), is( true ) );
}
@Test
public void testEqualsNonVersion()
{
Assert.assertFalse( DEFAULT_VERSION_RV2_ALPHA_8.equals( new Object() ) );
assertThat( DEFAULT_VERSION_RV2_ALPHA_8, is( not( equalTo( new Object() ) ) ) );
}
@Test
public void testEqualsUnequalBuild()
{
Assert.assertFalse( DEFAULT_VERSION_RV2_BETA_8.equals( DEFAULT_VERSION_RV2_BETA_9 ) );
assertThat( DEFAULT_VERSION_RV2_BETA_8, is( not( equalTo( DEFAULT_VERSION_RV2_BETA_9 ) ) ) );
}
@Test
public void testEqualsUnequalChannel()
{
Assert.assertFalse( DEFAULT_VERSION_RV2_BETA_8.equals( DEFAULT_VERSION_RV2_ALPHA_8 ) );
assertThat( DEFAULT_VERSION_RV2_BETA_8, is( not( equalTo( DEFAULT_VERSION_RV2_ALPHA_8 ) ) ) );
}
@Test
public void testEqualsUnequalRevision()
{
Assert.assertFalse( DEFAULT_VERSION_RV2_BETA_8.equals( DEFAULT_VERSION_RV3_BETA_8 ) );
assertThat( DEFAULT_VERSION_RV2_BETA_8, is( not( equalTo( DEFAULT_VERSION_RV3_BETA_8 ) ) ) );
}
@Test
public void testUnequalHash()
{
Assert.assertNotEquals( DEFAULT_VERSION_RV2_BETA_8.hashCode(), DEFAULT_VERSION_RV2_ALPHA_8.hashCode() );
assertThat( DEFAULT_VERSION_RV2_BETA_8.hashCode(), is( not( equalTo( DEFAULT_VERSION_RV2_ALPHA_8.hashCode() ) ) ) );
}
@Test
public void testToString()
{
Assert.assertEquals( DEFAULT_VERSION_RV2_BETA_8.toString(), "Version{revision=2, channel=Beta, build=8}" );
assertThat( DEFAULT_VERSION_RV2_BETA_8.toString(), is( "Version{revision=2, channel=Beta, build=8}" ) );
}
@Test
public void testFormatted()
{
Assert.assertEquals( DEFAULT_VERSION_RV2_BETA_8.formatted(), "rv2-beta-8" );
assertThat( DEFAULT_VERSION_RV2_BETA_8.formatted(), is( "rv2-beta-8" ) );
}
}
@@ -2,9 +2,11 @@
package appeng.util;
import static org.junit.Assert.assertEquals;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertThrows;
/*
@@ -72,75 +74,75 @@ public final class SlimReadableNumberConverterTest
private final ISlimReadableNumberConverter converter = ReadableNumberConverter.INSTANCE;
@Test( expected = AssertionError.class )
@Test
public void testConvertNeg999999()
{
assertEquals( RESULT_NEG_999999, this.converter.toSlimReadableForm( NUMBER_NEG_999999 ) );
assertThrows(AssertionError.class, () -> this.converter.toSlimReadableForm( NUMBER_NEG_999999 ) );
}
@Test( expected = AssertionError.class )
@Test
public void testConvertNeg9999()
{
assertEquals( RESULT_NEG_9999, this.converter.toSlimReadableForm( NUMBER_NEG_9999 ) );
assertThrows(AssertionError.class, () -> this.converter.toSlimReadableForm( NUMBER_NEG_9999 ) );
}
@Test( expected = AssertionError.class )
@Test
public void testConvertNeg999()
{
assertEquals( RESULT_NEG_999, this.converter.toSlimReadableForm( NUMBER_NEG_999 ) );
assertThrows(AssertionError.class, () -> this.converter.toSlimReadableForm( NUMBER_NEG_999 ) );
}
@Test
public void testConvert0()
{
assertEquals( RESULT_0, this.converter.toSlimReadableForm( NUMBER_0 ) );
assertThat( RESULT_0, is( this.converter.toSlimReadableForm( NUMBER_0 ) ) );
}
@Test
public void testConvert999()
{
assertEquals( RESULT_999, this.converter.toSlimReadableForm( NUMBER_999 ) );
assertThat( RESULT_999, is( this.converter.toSlimReadableForm( NUMBER_999 ) ) );
}
@Test
public void testConvert9999()
{
assertEquals( RESULT_9999, this.converter.toSlimReadableForm( NUMBER_9999 ) );
assertThat( RESULT_9999, is( this.converter.toSlimReadableForm( NUMBER_9999 ) ) );
}
@Test
public void testConvert10000()
{
assertEquals( RESULT_10000, this.converter.toSlimReadableForm( NUMBER_10000 ) );
assertThat( RESULT_10000, is( this.converter.toSlimReadableForm( NUMBER_10000 ) ) );
}
@Test
public void testConvert10500()
{
assertEquals( RESULT_10500, this.converter.toSlimReadableForm( NUMBER_10500 ) );
assertThat( RESULT_10500, is( this.converter.toSlimReadableForm( NUMBER_10500 ) ) );
}
@Test
public void testConvert155555()
{
assertEquals( RESULT_155555, this.converter.toSlimReadableForm( NUMBER_155555 ) );
assertThat( RESULT_155555, is( this.converter.toSlimReadableForm( NUMBER_155555 ) ) );
}
@Test
public void testConvert9999999()
{
assertEquals( RESULT_9999999, this.converter.toSlimReadableForm( NUMBER_9999999 ) );
assertThat( RESULT_9999999, is( this.converter.toSlimReadableForm( NUMBER_9999999 ) ) );
}
@Test
public void testConvert10000000()
{
assertEquals( RESULT_10000000, this.converter.toSlimReadableForm( NUMBER_10000000 ) );
assertThat( RESULT_10000000, is( this.converter.toSlimReadableForm( NUMBER_10000000 ) ) );
}
@Test
public void testConvert155555555()
{
assertEquals( RESULT_155555555, this.converter.toSlimReadableForm( NUMBER_155555555 ) );
assertThat( RESULT_155555555, is( this.converter.toSlimReadableForm( NUMBER_155555555 ) ) );
}
}
@@ -19,10 +19,10 @@
package appeng.util;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
/**
@@ -44,18 +44,18 @@ public final class UUIDMatcherTest
@Test
public void testUUID_shouldPass()
{
assertTrue( this.matcher.isUUID( IS_UUID ) );
assertThat( this.matcher.isUUID( IS_UUID ), is( true ) );
}
@Test
public void testNoUUD_shouldPass()
{
assertFalse( this.matcher.isUUID( NO_UUID ) );
assertThat( this.matcher.isUUID( NO_UUID ), is( false ) );
}
@Test
public void testInvalidUUID_shouldPass()
{
assertFalse( this.matcher.isUUID( INVALID_UUID ) );
assertThat( this.matcher.isUUID( INVALID_UUID ), is( false ) );
}
}
@@ -19,9 +19,11 @@
package appeng.util;
import static org.junit.Assert.assertEquals;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
@@ -71,75 +73,75 @@ public final class WideReadableNumberConverterTest
private final IWideReadableNumberConverter converter = ReadableNumberConverter.INSTANCE;
@Test( expected = AssertionError.class )
@Test
public void testConvertNeg999999()
{
assertEquals( RESULT_NEG_999999, this.converter.toWideReadableForm( NUMBER_NEG_999999 ) );
assertThrows( AssertionError.class, () -> this.converter.toWideReadableForm( NUMBER_NEG_999999 ) );
}
@Test( expected = AssertionError.class )
@Test
public void testConvertNeg9999()
{
assertEquals( RESULT_NEG_9999, this.converter.toWideReadableForm( NUMBER_NEG_9999 ) );
assertThrows( AssertionError.class, () -> this.converter.toWideReadableForm( NUMBER_NEG_9999 ) );
}
@Test( expected = AssertionError.class )
@Test
public void testConvertNeg999()
{
assertEquals( RESULT_NEG_999, this.converter.toWideReadableForm( NUMBER_NEG_999 ) );
assertThrows( AssertionError.class, () -> this.converter.toWideReadableForm( NUMBER_NEG_999 ) );
}
@Test
public void testConvert0()
{
assertEquals( RESULT_0, this.converter.toWideReadableForm( NUMBER_0 ) );
assertThat( RESULT_0, is( this.converter.toWideReadableForm( NUMBER_0 ) ) );
}
@Test
public void testConvert999()
{
assertEquals( RESULT_999, this.converter.toWideReadableForm( NUMBER_999 ) );
assertThat( RESULT_999, is( this.converter.toWideReadableForm( NUMBER_999 ) ) );
}
@Test
public void testConvert9999()
{
assertEquals( RESULT_9999, this.converter.toWideReadableForm( NUMBER_9999 ) );
assertThat( RESULT_9999, is( this.converter.toWideReadableForm( NUMBER_9999 ) ) );
}
@Test
public void testConvert10000()
{
assertEquals( RESULT_10000, this.converter.toWideReadableForm( NUMBER_10000 ) );
assertThat( RESULT_10000, is( this.converter.toWideReadableForm( NUMBER_10000 ) ) );
}
@Test
public void testConvert10500()
{
assertEquals( RESULT_10500, this.converter.toWideReadableForm( NUMBER_10500 ) );
assertThat( RESULT_10500, is( this.converter.toWideReadableForm( NUMBER_10500 ) ) );
}
@Test
public void testConvert155555()
{
assertEquals( RESULT_155555, this.converter.toWideReadableForm( NUMBER_155555 ) );
assertThat( RESULT_155555, is( this.converter.toWideReadableForm( NUMBER_155555 ) ) );
}
@Test
public void testConvert9999999()
{
assertEquals( RESULT_9999999, this.converter.toWideReadableForm( NUMBER_9999999 ) );
assertThat( RESULT_9999999, is( this.converter.toWideReadableForm( NUMBER_9999999 ) ) );
}
@Test
public void testConvert10000000()
{
assertEquals( RESULT_10000000, this.converter.toWideReadableForm( NUMBER_10000000 ) );
assertThat( RESULT_10000000, is( this.converter.toWideReadableForm( NUMBER_10000000 ) ) );
}
@Test
public void testConvert155555555()
{
assertEquals( RESULT_155555555, this.converter.toWideReadableForm( NUMBER_155555555 ) );
assertThat( RESULT_155555555, is( this.converter.toWideReadableForm( NUMBER_155555555 ) ) );
}
}
@@ -18,13 +18,11 @@
package appeng.util.helpers;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import appeng.api.util.AEColor;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class P2PHelperTest
@@ -50,17 +48,17 @@ public class P2PHelperTest
@Test
public void testToColors()
{
assertArrayEquals( WHITE_COLORS, this.unitUnderTest.toColors( WHITE_FREQUENCY ) );
assertArrayEquals( BLACK_COLORS, this.unitUnderTest.toColors( BLACK_FREQUENCY ) );
assertArrayEquals( MULTI_COLORS, this.unitUnderTest.toColors( MULTI_FREQUENCY ) );
assertThat( WHITE_COLORS, is( this.unitUnderTest.toColors( WHITE_FREQUENCY ) ) );
assertThat( BLACK_COLORS, is( this.unitUnderTest.toColors( BLACK_FREQUENCY ) ) );
assertThat( MULTI_COLORS, is( this.unitUnderTest.toColors( MULTI_FREQUENCY ) ) );
}
@Test
public void testFromColors()
{
assertEquals( WHITE_FREQUENCY, this.unitUnderTest.fromColors( WHITE_COLORS ) );
assertEquals( BLACK_FREQUENCY, this.unitUnderTest.fromColors( BLACK_COLORS ) );
assertEquals( MULTI_FREQUENCY, this.unitUnderTest.fromColors( MULTI_COLORS ) );
assertThat( WHITE_FREQUENCY, is( this.unitUnderTest.fromColors( WHITE_COLORS ) ) );
assertThat( BLACK_FREQUENCY, is( this.unitUnderTest.fromColors( BLACK_COLORS ) ) );
assertThat( MULTI_FREQUENCY, is( this.unitUnderTest.fromColors( MULTI_COLORS ) ) );
}
@Test
@@ -68,40 +66,39 @@ public class P2PHelperTest
{
for( short i = Short.MIN_VALUE; i < Short.MAX_VALUE; i++ )
{
assertEquals( i, this.unitUnderTest.fromColors( this.unitUnderTest.toColors( i ) ) );
assertThat( i, is( this.unitUnderTest.fromColors( this.unitUnderTest.toColors( i ) ) ));
}
}
@Test
public void testToHexDigit()
{
assertEquals( "0", this.unitUnderTest.toHexDigit( AEColor.WHITE ) );
assertEquals( "1", this.unitUnderTest.toHexDigit( AEColor.ORANGE ) );
assertEquals( "2", this.unitUnderTest.toHexDigit( AEColor.MAGENTA ) );
assertEquals( "3", this.unitUnderTest.toHexDigit( AEColor.LIGHT_BLUE ) );
assertEquals( "4", this.unitUnderTest.toHexDigit( AEColor.YELLOW ) );
assertEquals( "5", this.unitUnderTest.toHexDigit( AEColor.LIME ) );
assertEquals( "6", this.unitUnderTest.toHexDigit( AEColor.PINK ) );
assertEquals( "7", this.unitUnderTest.toHexDigit( AEColor.GRAY ) );
assertEquals( "8", this.unitUnderTest.toHexDigit( AEColor.LIGHT_GRAY ) );
assertEquals( "9", this.unitUnderTest.toHexDigit( AEColor.CYAN ) );
assertEquals( "A", this.unitUnderTest.toHexDigit( AEColor.PURPLE ) );
assertEquals( "B", this.unitUnderTest.toHexDigit( AEColor.BLUE ) );
assertEquals( "C", this.unitUnderTest.toHexDigit( AEColor.BROWN ) );
assertEquals( "D", this.unitUnderTest.toHexDigit( AEColor.GREEN ) );
assertEquals( "E", this.unitUnderTest.toHexDigit( AEColor.RED ) );
assertEquals( "F", this.unitUnderTest.toHexDigit( AEColor.BLACK ) );
assertThat( "0", is( this.unitUnderTest.toHexDigit( AEColor.WHITE ) ) );
assertThat( "1", is( this.unitUnderTest.toHexDigit( AEColor.ORANGE ) ) );
assertThat( "2", is( this.unitUnderTest.toHexDigit( AEColor.MAGENTA ) ) );
assertThat( "3", is( this.unitUnderTest.toHexDigit( AEColor.LIGHT_BLUE ) ) );
assertThat( "4", is( this.unitUnderTest.toHexDigit( AEColor.YELLOW ) ) );
assertThat( "5", is( this.unitUnderTest.toHexDigit( AEColor.LIME ) ) );
assertThat( "6", is( this.unitUnderTest.toHexDigit( AEColor.PINK ) ) );
assertThat( "7", is( this.unitUnderTest.toHexDigit( AEColor.GRAY ) ) );
assertThat( "8", is( this.unitUnderTest.toHexDigit( AEColor.LIGHT_GRAY ) ) );
assertThat( "9", is( this.unitUnderTest.toHexDigit( AEColor.CYAN ) ) );
assertThat( "A", is( this.unitUnderTest.toHexDigit( AEColor.PURPLE ) ) );
assertThat( "B", is( this.unitUnderTest.toHexDigit( AEColor.BLUE ) ) );
assertThat( "C", is( this.unitUnderTest.toHexDigit( AEColor.BROWN ) ) );
assertThat( "D", is( this.unitUnderTest.toHexDigit( AEColor.GREEN ) ) );
assertThat( "E", is( this.unitUnderTest.toHexDigit( AEColor.RED ) ) );
assertThat( "F", is( this.unitUnderTest.toHexDigit( AEColor.BLACK ) ) );
}
@Test
public void testToHexString()
{
assertEquals( HEX_WHITE_FREQUENCY, this.unitUnderTest.toHexString( WHITE_FREQUENCY ) );
assertEquals( HEX_BLACK_FREQUENCY, this.unitUnderTest.toHexString( BLACK_FREQUENCY ) );
assertEquals( HEX_MULTI_FREQUENCY, this.unitUnderTest.toHexString( MULTI_FREQUENCY ) );
assertThat( HEX_WHITE_FREQUENCY, is( this.unitUnderTest.toHexString( WHITE_FREQUENCY ) ) );
assertThat( HEX_BLACK_FREQUENCY, is( this.unitUnderTest.toHexString( BLACK_FREQUENCY ) ) );
assertThat( HEX_MULTI_FREQUENCY, is( this.unitUnderTest.toHexString( MULTI_FREQUENCY ) ) );
assertEquals( HEX_MIN_FREQUENCY, this.unitUnderTest.toHexString( Short.MIN_VALUE ) );
assertEquals( HEX_MAX_FREQUENCY, this.unitUnderTest.toHexString( Short.MAX_VALUE ) );
assertThat( HEX_MIN_FREQUENCY, is( this.unitUnderTest.toHexString( Short.MIN_VALUE ) ) );
assertThat( HEX_MAX_FREQUENCY, is( this.unitUnderTest.toHexString( Short.MAX_VALUE ) ) );
}
}