Compare commits

...
13 Commits
Author SHA1 Message Date
Raven Szewczyk d613d06471 Attempt to fix CME when opening recipes immediately after load (#403) 2023-07-16 09:00:35 +01:00
65ffbad491 Show a full recipe widget in item tooltips for bookmarked recipes (#398)
* Update buildscript

* Show a full recipe widget in item tooltips for bookmarked recipes

* Make recipe tooltips configurable and only show in the bookmarks panel

* Fix layout relative to tooltip boxes

* Fix wildcard import

* spotlessApply (#401)

Co-authored-by: GitHub GTNH Actions <>

* Fix handler tooltip offsets for new&legacy handlers

* Fix render order to draw crafting tooltips on top of container manager buttons

* Fix wrong mouse Y half-point calculation

* Allow saving recipes with empty item ingredient lists to bookmarks (e.g. fluid-only)

* Fix waila vs. non-waila tooltip offsets

Co-authored-by: Wilhelm Schuster <[email protected]>

---------

Co-authored-by: Wilhelm Schuster <[email protected]>
2023-07-10 17:38:07 +01:00
Wilhelm Schuster 885609720e Extend height hack for legacy recipe handlers (#395)
* Store heighthackhandlers.cfg as an internal asset instead of an array of strings

Is copied into the config directory upon first launch. Also, comments
are now allowed (only from the beginning of the file).

* Store serialhandlers.cfg as an internal asset instead of an array of strings

Is copied into the config directory upon first launch. Also, comments
are now allowed (only from the beginning of the file).

Removes GTNH-specific code to be replaced with a configuration file.

* Extend the height hack to also cover guiTop and getRecipePosition

Certain legacy recipe handlers hardcode even more of the NEI recipe
screen layout, requiring only the singular recipe handler switcher
widget at the top, whereas this improved NEI moves the recipe pager to
the top as well expecting recipe handler to move down another 16px. One
such mod that breaks is Immersive Engineering. To fix it we move the top
edge of the gui (guiTop) down by 16px so that the old gap calculation
works correctly. This required special handling in getRecipePosition()
and refreshSlots().

* Fix Immersive Engineering recipe handlers

* Fix Ex Nihilo recipe handlers

* Fix Thermal Expansion recipe handlers

These handlers expect only two recipes to be displayed at a time. This can only be fixed through asm AFAICT.
2023-07-08 23:23:19 +02:00
chochemandglowredman bacf246504 Adjust nei overlay to gt oregen changes (#391)
* adjust to oregen changes

* add compat for old worlds

* remove testing debug

* Update buildscript

* Adjust to changed oregenPattern API

* fix fieldname

---------

Co-authored-by: glowredman <[email protected]>
2023-07-04 18:36:35 +02:00
Wilhelm Schuster 1ab3350eb8 Adjust recipe handler scrolling again (#393)
* Update buildscript

* Rework recipe handler tab scrolling again

Move the recipe handler tab scrolling before the handler-specific
scrolling again. This ensures that tab scrolling while hovering over the
tab bar will always be possible, regardless of how a recipe handler
handles scrolling itself. This mostly reverts back to how this feature
was implemented originally with one change: the Shift-scrolling behavior
is moved outside the recipe tabs scroll handler after the recipe
handler-specific scroll handling to prevent this from overwriting any
other behavior.
2023-06-24 12:01:21 +02:00
Wilhelm Schuster f3aa12483d Expand the tooltips for the time manipulation action buttons (#392) 2023-06-15 23:19:57 +02:00
miozune d86c472790 Fix crash with IC2 setItemDamage (#387)
* Ducttape fix for crash with IC2 setItemDamage

* Use Items.feather
2023-06-01 07:20:24 +02:00
Wilhelm Schuster 4124151208 Prevent recipe handler tab scrolling from overwriting recipe handler-specific scrolling (#384)
* Rename variable in GuiRecipeTabs to avoid confusion

Based on feedback in a previous PR review.

* Make sure recipe handler-specific scrolling behavior takes precedence over recipe handler tab scrolling
2023-05-13 17:40:08 +02:00
miozune 68ad800620 Remove handlers for Et Futurum Requiem (#383)
* Update dependencies

* updateBuildScript

* Remove handlers for Et Futurum Requiem
2023-05-13 14:12:22 +02:00
Wilhelm Schuster 2c7207485d Ensure the NEI config is really only initialized once (#381)
bootNEI() is supposed to only be called once during the client's
lifetime. Turns out, if your pack has 800 mods, bootNEI() might be
called a second time before configLoaded is set to true at the end of
the plugin loading thread. This introduces a second variable that is
set at the end of the single threaded portion of bootNEI() so that it
truly can only be called once, but we can still retain the ability to
check if the plugin loading thread has finished.
2023-05-10 23:55:45 +02:00
Wilhelm Schuster e8094794c3 Allow scrolling through recipe handlers (#379)
In addition to scrolling through all recipes of a single handler, you
can now scroll through all the recipe handlers while hovering over the
handler tab bar (or anywhere in the recipe area while holding left
shift).
2023-05-09 21:57:27 +02:00
miozune ad86d8f9c5 Separate logic to get detailed string of fluid amount (#378)
* Separate logic to get detailed string of fluid amount

* updateBuildScript & spotlessApply

* probably better way
2023-05-07 20:10:18 +02:00
Wilhelm Schuster 30c87e9160 Make sure NEI plugins are loaded before processing keybindings (#375)
NEI plugins are initialized in a separate thread. If this takes too long,
the client tick handler might already be running checking the keybindings
in KeyManager while a plugin calls API.addKeyBind() which can lead to a
CME.

Reported in https://github.com/GTNewHorizons/GT-New-Horizons-Modpack/issues/13292
Thanks to @Denostrov for helping me track this down.
2023-05-05 21:01:50 +02:00
39 changed files with 701 additions and 338 deletions

No files matched your search

-7
View File
@@ -27,13 +27,6 @@ If you have issues with NEI outside of the GTNH modpack you may report them in t
* Remove TMI style
* Removed inventory Load/Save state
## Development
Before launching, you need to add
```
-Dfml.coreMods.load=codechicken.nei.asm.NEICorePlugin
```
as a command line argument to the VM.
## License
GTNH Modifications Copyright (c) 2019-2022 mitchej123 and the GTNH Team
+70 -107
View File
@@ -1,4 +1,4 @@
//version: 1680120787
//version: 1685785062
/*
DO NOT CHANGE THIS FILE!
Also, you may replace this file at any time if there is an update available.
@@ -6,29 +6,25 @@
*/
import com.diffplug.blowdryer.Blowdryer
import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.gtnewhorizons.retrofuturagradle.ObfuscationAttribute
import com.gtnewhorizons.retrofuturagradle.mcp.ReobfuscatedJar
import com.gtnewhorizons.retrofuturagradle.minecraft.RunMinecraftTask
import com.gtnewhorizons.retrofuturagradle.util.Distribution
import com.matthewprenger.cursegradle.CurseArtifact
import com.matthewprenger.cursegradle.CurseRelation
import com.modrinth.minotaur.dependencies.ModDependency
import com.modrinth.minotaur.dependencies.VersionDependency
import cpw.mods.fml.relauncher.Side
import org.gradle.api.tasks.options.Option;
import org.gradle.internal.logging.text.StyledTextOutput.Style
import org.gradle.internal.logging.text.StyledTextOutputFactory
import org.gradle.internal.xml.XmlTransformer
import org.jetbrains.gradle.ext.*
import org.jetbrains.gradle.ext.Application
import org.jetbrains.gradle.ext.Gradle
import javax.inject.Inject
import java.nio.file.Files
import java.nio.file.Paths
import java.util.concurrent.TimeUnit
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import javax.inject.Inject
buildscript {
repositories {
@@ -66,21 +62,25 @@ plugins {
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
id 'org.ajoberstar.grgit' version '4.1.1' // 4.1.1 is the last jvm8 supporting version, unused, available for addon.gradle
id 'com.github.johnrengelman.shadow' version '7.1.2' apply false
id 'com.palantir.git-version' version '0.13.0' apply false // 0.13.0 is the last jvm8 supporting version
id 'de.undercouch.download' version '5.3.0'
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
id 'com.palantir.git-version' version '3.0.0' apply false
id 'de.undercouch.download' version '5.4.0'
id 'com.github.gmazzo.buildconfig' version '3.1.0' apply false // Unused, available for addon.gradle
id 'com.diffplug.spotless' version '6.7.2' apply false
id 'com.diffplug.spotless' version '6.13.0' apply false // 6.13.0 is the last jvm8 supporting version
id 'com.modrinth.minotaur' version '2.+' apply false
id 'com.matthewprenger.cursegradle' version '1.4.0' apply false
id 'com.gtnewhorizons.retrofuturagradle' version '1.2.4'
id 'com.gtnewhorizons.retrofuturagradle' version '1.3.14'
}
print("You might want to check out './gradlew :faq' if your build fails.\n")
boolean settingsupdated = verifySettingsGradle()
settingsupdated = verifyGitAttributes() || settingsupdated
if (settingsupdated)
throw new GradleException("Settings has been updated, please re-run task.")
if (project.file('.git/HEAD').isFile()) {
// In submodules, .git is a file pointing to the real git dir
if (project.file('.git/HEAD').isFile() || project.file('.git').isFile()) {
apply plugin: 'com.palantir.git-version'
}
@@ -132,7 +132,7 @@ propertyDefaultIfUnset("enableGenericInjection", false) // On by default for new
// this is meant to be set using the user wide property file. by default we do nothing.
propertyDefaultIfUnset("ideaOverrideBuildType", "") // Can be nothing, "gradle" or "idea"
project.extensions.add(Blowdryer, "Blowdryer", Blowdryer) // Make blowdryer available in "apply from:" scripts
project.extensions.add(com.diffplug.blowdryer.Blowdryer, "Blowdryer", com.diffplug.blowdryer.Blowdryer) // Make blowdryer available in "apply from:" scripts
if (!disableSpotless) {
apply plugin: 'com.diffplug.spotless'
apply from: Blowdryer.file('spotless.gradle')
@@ -201,6 +201,14 @@ configurations {
canBeConsumed = false
canBeResolved = false
}
create("devOnlyNonPublishable") {
description = "Runtime and compiletime dependencies that are not published alongside the jar (compileOnly + runtimeOnlyNonPublishable)"
canBeConsumed = false
canBeResolved = false
}
compileOnly.extendsFrom(devOnlyNonPublishable)
runtimeOnlyNonPublishable.extendsFrom(devOnlyNonPublishable)
}
if (enableModernJavaSyntax.toBoolean()) {
@@ -214,6 +222,8 @@ if (enableModernJavaSyntax.toBoolean()) {
dependencies {
annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:1.0.0'
// workaround for https://github.com/bsideup/jabel/issues/174
annotationProcessor 'net.java.dev.jna:jna-platform:5.13.0'
compileOnly('com.github.bsideup.jabel:jabel-javac-plugin:1.0.0') {
transitive = false // We only care about the 1 annotation class
}
@@ -399,7 +409,7 @@ minecraft {
username = developmentEnvironmentUserName.toString()
lwjgl3Version = "3.3.2-SNAPSHOT"
lwjgl3Version = "3.3.2"
// Enable assertions in the current mod
extraRunJvmArguments.add("-ea:${modGroup}")
@@ -559,9 +569,10 @@ repositories {
def mixinProviderGroup = "io.github.legacymoddingmc"
def mixinProviderModule = "unimixins"
def mixinProviderVersion = "0.1.6"
def mixinProviderVersion = "0.1.7.1"
def mixinProviderSpecNoClassifer = "${mixinProviderGroup}:${mixinProviderModule}:${mixinProviderVersion}"
def mixinProviderSpec = "${mixinProviderSpecNoClassifer}:dev"
ext.mixinProviderSpec = mixinProviderSpec
dependencies {
if (usesMixins.toBoolean()) {
@@ -713,13 +724,13 @@ ext.java17PatchDependenciesCfg = configurations.create("java17PatchDependencies"
}
dependencies {
def lwjgl3ifyVersion = '1.3.3'
def lwjgl3ifyVersion = '1.3.5'
def asmVersion = '9.4'
if (modId != 'lwjgl3ify') {
java17Dependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}")
}
if (modId != 'hodgepodge') {
java17Dependencies('com.github.GTNewHorizons:Hodgepodge:2.2.4')
java17Dependencies('com.github.GTNewHorizons:Hodgepodge:2.2.13')
}
java17PatchDependencies('net.minecraft:launchwrapper:1.15') {transitive = false}
@@ -793,7 +804,7 @@ public abstract class RunHotswappableMinecraftTask extends RunMinecraftTask {
public boolean setEnableHotswap(boolean enable) { enableHotswap = enable }
@Inject
public RunHotswappableMinecraftTask(Side side, String superTask, org.gradle.api.invocation.Gradle gradle) {
public RunHotswappableMinecraftTask(Distribution side, String superTask, org.gradle.api.invocation.Gradle gradle) {
super(side, gradle)
this.lwjglVersion = 3
@@ -802,7 +813,7 @@ public abstract class RunHotswappableMinecraftTask extends RunMinecraftTask {
this.extraJvmArgs.addAll(project.provider(() -> enableHotswap ? project.hotswapJvmArgs : []))
this.classpath(project.java17PatchDependenciesCfg)
if (side == Side.CLIENT) {
if (side == Distribution.CLIENT) {
this.classpath(project.minecraftTasks.lwjgl3Configuration)
}
// Use a raw provider instead of map to not create a dependency on the task
@@ -812,9 +823,21 @@ public abstract class RunHotswappableMinecraftTask extends RunMinecraftTask {
}
this.classpath(project.java17DependenciesCfg)
}
public void setup(Project project) {
super.setup(project)
if (project.usesMixins.toBoolean()) {
this.extraJvmArgs.addAll(project.provider(() -> {
def mixinCfg = project.configurations.detachedConfiguration(project.dependencies.create(project.mixinProviderSpec))
mixinCfg.canBeConsumed = false
mixinCfg.transitive = false
enableHotswap ? ["-javaagent:" + mixinCfg.singleFile.absolutePath] : []
}))
}
}
}
def runClient17Task = tasks.register("runClient17", RunHotswappableMinecraftTask, Side.CLIENT, "runClient")
def runClient17Task = tasks.register("runClient17", RunHotswappableMinecraftTask, Distribution.CLIENT, "runClient")
runClient17Task.configure {
setup(project)
group = "Modded Minecraft"
@@ -825,7 +848,7 @@ runClient17Task.configure {
userUUID = minecraft.userUUID
}
def runServer17Task = tasks.register("runServer17", RunHotswappableMinecraftTask, Side.SERVER, "runServer")
def runServer17Task = tasks.register("runServer17", RunHotswappableMinecraftTask, Distribution.DEDICATED_SERVER, "runServer")
runServer17Task.configure {
setup(project)
group = "Modded Minecraft"
@@ -866,11 +889,6 @@ tasks.named("jar", Jar).configure {
}
if (usesShadowedDependencies.toBoolean()) {
tasks.register('relocateShadowJar', ConfigureShadowRelocation) {
target = tasks.shadowJar
prefix = modGroup + ".shadow"
enabled = relocateShadowedDependencies.toBoolean()
}
tasks.named("shadowJar", ShadowJar).configure {
manifest {
attributes(getManifestAttributes())
@@ -886,7 +904,8 @@ if (usesShadowedDependencies.toBoolean()) {
]
archiveClassifier.set('dev')
if (relocateShadowedDependencies.toBoolean()) {
dependsOn(relocateShadowJar)
relocationPrefix = modGroup + ".shadow"
enableRelocation = true
}
}
configurations.runtimeElements.outgoing.artifacts.clear()
@@ -1219,7 +1238,7 @@ def addCurseForgeRelation(String type, String name) {
// Updating
def buildscriptGradleVersion = "8.0.2"
def buildscriptGradleVersion = "8.1.1"
tasks.named('wrapper', Wrapper).configure {
gradleVersion = buildscriptGradleVersion
@@ -1251,6 +1270,23 @@ if (!project.getGradle().startParameter.isOffline() && !Boolean.getBoolean('DISA
}
}
// If you want to add more cases to this task, implement them as arguments if total amount to print gets too large
tasks.register('faq') {
group = 'GTNH Buildscript'
description = 'Prints frequently asked questions about building a project'
doLast {
print("If your build fails to fetch dependencies, run './gradlew updateDependencies'. " +
"Or you can manually check if the versions are still on the distributing sites - " +
"the links can be found in repositories.gradle and build.gradle:repositories, " +
"but not build.gradle:buildscript.repositories - those ones are for gradle plugin metadata.\n\n" +
"If your build fails to recognize the syntax of new Java versions, enable Jabel in your " +
"gradle.properties. See how it's done in GTNH ExampleMod/gradle.properties. " +
"However, keep in mind that Jabel enables only syntax features, but not APIs that were introduced in " +
"Java 9 or later.")
}
}
static URL availableBuildScriptUrl() {
new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/master/build.gradle")
}
@@ -1388,7 +1424,7 @@ static int replaceParams(File file, Map<String, String> params) {
return 0
}
// Dependency Deobfuscation
// Dependency Deobfuscation (Deprecated, use the new RFG API documented in dependencies.gradle)
def deobf(String sourceURL) {
try {
@@ -1430,11 +1466,7 @@ def deobfMaven(String repoURL, String mavenDep) {
}
def deobfCurse(String curseDep) {
try {
return deobfMaven("https://www.cursemaven.com/", "curse.maven:$curseDep")
} catch (Exception ignored) {
out.style(Style.Failure).println("Failed to get $curseDep from cursemaven.")
}
return dependencies.rfg.deobf("curse.maven:$curseDep")
}
// The method above is to be preferred. Use this method if the filename is not at the end of the URL.
@@ -1442,34 +1474,7 @@ def deobf(String sourceURL, String rawFileName) {
String bon2Version = "2.5.1"
String fileName = URLDecoder.decode(rawFileName, "UTF-8")
String cacheDir = "$project.gradle.gradleUserHomeDir/caches"
String bon2Dir = "$cacheDir/forge_gradle/deobf"
String bon2File = "$bon2Dir/BON2-${bon2Version}.jar"
String obfFile = "$cacheDir/modules-2/files-2.1/${fileName}.jar"
String deobfFile = "$cacheDir/modules-2/files-2.1/${fileName}-deobf.jar"
if (file(deobfFile).exists()) {
return files(deobfFile)
}
String mappingsVer
String remoteMappings = project.hasProperty('remoteMappings') ? project.remoteMappings : 'https://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/'
if (remoteMappings) {
String id = "${forgeVersion.split("\\.")[3]}-$minecraftVersion"
String mappingsZIP = "$cacheDir/forge_gradle/maven_downloader/de/oceanlabs/mcp/mcp_snapshot_nodoc/$id/mcp_snapshot_nodoc-${id}.zip"
zipMappings(mappingsZIP, remoteMappings, bon2Dir)
mappingsVer = "snapshot_$id"
} else {
mappingsVer = "${channel}_$mappingsVersion"
}
download.run {
src "http://jenkins.usrv.eu:8081/nexus/content/repositories/releases/com/github/parker8283/BON2/$bon2Version-CUSTOM/BON2-$bon2Version-CUSTOM-all.jar"
dest bon2File
quiet true
overwrite false
}
download.run {
src sourceURL
@@ -1477,50 +1482,8 @@ def deobf(String sourceURL, String rawFileName) {
quiet true
overwrite false
}
exec {
commandLine 'java', '-jar', bon2File, '--inputJar', obfFile, '--outputJar', deobfFile, '--mcVer', minecraftVersion, '--mappingsVer', mappingsVer, '--notch'
workingDir bon2Dir
standardOutput = new FileOutputStream("${deobfFile}.log")
}
return files(deobfFile)
return dependencies.rfg.deobf(files(obfFile))
}
def zipMappings(String zipPath, String url, String bon2Dir) {
File zipFile = new File(zipPath)
if (zipFile.exists()) {
return
}
String fieldsCache = "$bon2Dir/data/fields.csv"
String methodsCache = "$bon2Dir/data/methods.csv"
download.run {
src "${url}fields.csv"
dest fieldsCache
quiet true
}
download.run {
src "${url}methods.csv"
dest methodsCache
quiet true
}
zipFile.getParentFile().mkdirs()
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))
zos.putNextEntry(new ZipEntry("fields.csv"))
Files.copy(Paths.get(fieldsCache), zos)
zos.closeEntry()
zos.putNextEntry(new ZipEntry("methods.csv"))
Files.copy(Paths.get(methodsCache), zos)
zos.closeEntry()
zos.close()
}
// Helper methods
def checkPropertyExists(String propertyName) {
+3 -3
View File
@@ -1,7 +1,7 @@
// Add your dependencies here
dependencies {
api('com.github.GTNewHorizons:CodeChickenLib:1.1.6:dev')
api('com.github.GTNewHorizons:CodeChickenCore:1.1.10:dev')
shadowImplementation('org.apache.commons:commons-csv:1.9.0')
api('com.github.GTNewHorizons:CodeChickenLib:1.1.8:dev')
api('com.github.GTNewHorizons:CodeChickenCore:1.1.11:dev')
shadowImplementation('org.apache.commons:commons-csv:1.10.0')
}
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-11
View File
@@ -1,15 +1,4 @@
// Add any additional repositiroes for your dependencies here
repositories {
mavenCentral()
maven {
name 'GTNH Maven'
url 'http://jenkins.usrv.eu:8081/nexus/content/groups/public/'
}
maven {
url 'https://cursemaven.com'
content {
includeGroup 'curse.maven'
}
}
}
+3
View File
@@ -26,3 +26,6 @@ blowdryerSetup {
github('GTNewHorizons/ExampleMod1.7.10', 'tag', '0.2.0')
//devLocal '.' // Use this when testing config updates locally
}
rootProject.name = "NotEnoughItems"
@@ -24,6 +24,11 @@ import net.minecraft.nbt.NBTTagCompound;
import org.apache.commons.io.IOUtils;
import org.lwjgl.opengl.GL11;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import codechicken.core.CommonUtils;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanel.ItemPanelSlot;
@@ -33,11 +38,6 @@ import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
import codechicken.nei.util.ReadableNumberConverter;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
public class BookmarkPanel extends PanelWidget {
protected File bookmarkFile;
@@ -84,6 +84,10 @@ public class BookmarkPanel extends PanelWidget {
protected boolean[] todoSpaces;
protected int todoItemsCount = 0;
public BookmarkGrid() {
this.setShowRecipeTooltips(true);
}
public void setViewMode(BookmarkViewMode mode) {
if (viewMode == mode) {
return;
@@ -464,7 +468,7 @@ public class BookmarkPanel extends PanelWidget {
final ItemStack normalizedA = StackInfo.loadFromNBT(nbTagA);
BookmarkRecipeId recipeId = null;
if (handlerName != "" && ingredients != null && !ingredients.isEmpty()) {
if (handlerName != "" && ingredients != null) {
recipeId = new BookmarkRecipeId(handlerName, ingredients);
}
@@ -474,7 +478,7 @@ public class BookmarkPanel extends PanelWidget {
BGrid.removeRecipe(idx, saveIngredients);
} else {
if (saveIngredients && handlerName != "" && ingredients != null && !ingredients.isEmpty()) {
if (saveIngredients && handlerName != "" && ingredients != null) {
final Map<NBTTagCompound, Integer> unique = new HashMap<>();
final ArrayList<NBTTagCompound> sorted = new ArrayList<>();
@@ -9,9 +9,6 @@ import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -37,6 +34,8 @@ import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.io.IOUtils;
import com.google.common.collect.Lists;
import codechicken.core.ClientUtils;
import codechicken.core.GuiModListScroll;
import codechicken.lib.packet.PacketCustom;
@@ -44,25 +43,14 @@ import codechicken.nei.api.API;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.StackInfo;
import com.google.common.collect.Lists;
import cpw.mods.fml.client.CustomModLoadingErrorDisplayException;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
public class ClientHandler {
private static String[] defaultSerialHandlers = {
"WayofTime.alchemicalWizardry.client.nei.NEIAlchemyRecipeHandler" };
private static String[] defaultHeightHackHandlerRegex = { "buildcraft.compat.nei.*",
"cofh.thermalexpansion.plugins.nei.handlers.*", "crazypants.enderio.nei.*",
"forestry.factory.recipes.nei.*", "ic2.neiIntegration.core.recipehandler.*", "mariculture.plugins.nei.*",
"redgear.brewcraft.plugins.nei.*", "tconstruct.plugins.nei.*",
"WayofTime.alchemicalWizardry.client.nei.*", };
private static String[] defaultHandlerOrdering = {
"# Each line in this file should either be a comment (starts with '#') or an ordering.",
"# Ordering lines are <handler ID>,<ordering number>.",
@@ -166,16 +154,19 @@ public class ClientHandler {
if (!file.exists()) {
try (FileWriter writer = new FileWriter(file)) {
NEIClientConfig.logger.info("Creating default serial handlers list {}", file);
Collection<String> toSave = Loader.isModLoaded("dreamcraft") ? Collections.singletonList("")
: Arrays.asList(defaultSerialHandlers);
IOUtils.writeLines(toSave, "\n", writer);
URL defaultSerialHandlersResource = ClientHandler.class
.getResource("/assets/nei/cfg/serialhandlers.cfg");
if (defaultSerialHandlersResource != null) {
IOUtils.copy(defaultSerialHandlersResource.openStream(), writer);
}
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to save default serial handlers list to file {}", file, e);
}
}
try (FileReader reader = new FileReader(file)) {
NEIClientConfig.logger.info("Loading serial handlers from file {}", file);
NEIClientConfig.serialHandlers = new HashSet<>(IOUtils.readLines(reader));
NEIClientConfig.serialHandlers = IOUtils.readLines(reader).stream().filter((line) -> !line.startsWith("#"))
.collect(Collectors.toCollection(HashSet::new));
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load serial handlers from file {}", file, e);
}
@@ -186,8 +177,11 @@ public class ClientHandler {
if (!file.exists()) {
try (FileWriter writer = new FileWriter(file)) {
NEIClientConfig.logger.info("Creating default height hack handlers list {}", file);
Collection<String> toSave = Arrays.asList(defaultHeightHackHandlerRegex);
IOUtils.writeLines(toSave, "\n", writer);
URL defaultHeightHackHandlersResource = ClientHandler.class
.getResource("/assets/nei/cfg/heighthackhandlers.cfg");
if (defaultHeightHackHandlersResource != null) {
IOUtils.copy(defaultHeightHackHandlersResource.openStream(), writer);
}
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to save default height hack handlers list to file {}", file, e);
}
@@ -195,7 +189,8 @@ public class ClientHandler {
try (FileReader reader = new FileReader(file)) {
NEIClientConfig.logger.info("Loading height hack handlers from file {}", file);
NEIClientConfig.heightHackHandlerRegex = IOUtils.readLines(reader).stream().map(Pattern::compile)
NEIClientConfig.heightHackHandlerRegex = IOUtils.readLines(reader).stream()
.filter((line) -> !line.startsWith("#")).map(Pattern::compile)
.collect(Collectors.toCollection(HashSet::new));
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load height hack handlers from file {}", file, e);
@@ -276,7 +271,11 @@ public class ClientHandler {
if (!NEIClientConfig.isEnabled()) return;
KeyManager.tickKeyStates();
/*
* NEI plugins are loaded in a separate thread. Make sure loading them has finished otherwise a CME might
* occur in KeyManager if a plugin calls API.addKeyBind() during initialization.
*/
if (NEIClientConfig.isLoaded()) KeyManager.tickKeyStates();
NEIController.updateUnlimitedItems(mc.thePlayer.inventory);
if (mc.currentScreen == null) NEIController.processCreativeCycling(mc.thePlayer.inventory);
+3 -3
View File
@@ -13,15 +13,15 @@ import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IIcon;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import codechicken.nei.ThreadOperationTimer.TimeoutException;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.guihook.GuiContainerManager;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
public class ItemList {
/**
@@ -1,19 +1,24 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.drawRect;
import static codechicken.lib.gui.GuiDraw.getMousePosition;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.shader.Framebuffer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
@@ -22,6 +27,9 @@ import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.BookmarkRecipeId;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.StackInfo;
public class ItemsGrid {
@@ -43,6 +51,7 @@ public class ItemsGrid {
protected int rows;
protected int columns;
protected boolean showRecipeTooltips = false;
protected boolean[] invalidSlotMap;
@@ -150,6 +159,10 @@ public class ItemsGrid {
refreshBuffer = true;
}
public void setShowRecipeTooltips(boolean show) {
this.showRecipeTooltips = show;
}
public void refresh(GuiContainer gui) {
updateGuiOverlapSlots(gui);
shiftPage(0);
@@ -244,6 +257,120 @@ public class ItemsGrid {
}
}
private int recipeTooltipSlotIdx = -1;
private int recipeTooltipLines = 2;
private Runnable recipeTooltipUpdater = null;
private GuiRecipe<?> recipeTooltipGui = null;
public void update() {
if (recipeTooltipUpdater != null) {
recipeTooltipUpdater.run();
recipeTooltipUpdater = null;
}
if (recipeTooltipGui != null) {
recipeTooltipGui.updateAsTooltip();
}
}
private static <T> List<T> listOrEmptyList(final List<T> listOrNull) {
return listOrNull == null ? Collections.emptyList() : listOrNull;
}
private void drawRecipeTooltip(int mousex, int mousey, List<String> itemTooltip) {
if (!NEIClientConfig.isLoaded()) {
return;
}
final Minecraft mc = Minecraft.getMinecraft();
ItemPanelSlot focused = getSlotMouseOver(mousex, mousey);
if (focused == null) {
recipeTooltipSlotIdx = -1;
recipeTooltipGui = null;
return;
}
final List<Integer> mask = getMask();
int slotIdx = -1;
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) == null) {
continue;
}
if (focused.slotIndex != mask.get(i)) {
continue;
}
slotIdx = i;
break;
}
if (slotIdx == -1) {
recipeTooltipSlotIdx = -1;
recipeTooltipGui = null;
return;
}
final Point mouseover = getMousePosition();
final ItemPanelSlot panelSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
final BookmarkRecipeId recipeId;
if (panelSlot != null) {
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(panelSlot.slotIndex);
} else {
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(focused.item);
}
if (recipeId == null) {
return;
}
if (slotIdx != recipeTooltipSlotIdx) {
recipeTooltipSlotIdx = slotIdx;
recipeTooltipGui = null;
recipeTooltipUpdater = () -> {
recipeTooltipGui = GuiCraftingRecipe.createRecipeGui("item", false, false, false, focused.item);
if (recipeTooltipGui != null) {
recipeTooltipGui.limitToOneRecipe();
recipeTooltipGui.initGui(true);
recipeTooltipGui.guiTop = 0;
recipeTooltipGui.guiLeft = 0;
}
recipeTooltipLines = Math.max(1, itemTooltip.size());
};
}
if (recipeTooltipGui == null) {
return;
}
GL11.glPushMatrix();
final float tooltipYOffset;
if (mousey - marginTop > height / 2) {
tooltipYOffset = mousey - recipeTooltipGui.getHeightAsWidget() + 8;
} else {
tooltipYOffset = mousey + ((recipeTooltipLines < 2) ? 1 : 3 + ((recipeTooltipLines - 1) * 10));
}
GL11.glTranslatef(mousex, tooltipYOffset, 500);
final GuiContainer gui;
if (mc.currentScreen instanceof GuiRecipe) {
gui = ((GuiRecipe<?>) mc.currentScreen).firstGui;
} else if (mc.currentScreen instanceof GuiContainer) {
gui = (GuiContainer) mc.currentScreen;
} else {
gui = null;
}
recipeTooltipGui.drawGuiContainerBackgroundLayer(0.0f, -100, -100);
if (recipeTooltipGui.slotcontainer != null) {
@SuppressWarnings("unchecked")
List<Slot> slots = (List<Slot>) recipeTooltipGui.slotcontainer.inventorySlots;
for (Slot slot : slots) {
if (slot != null && slot.getStack() != null) {
GuiContainerManager.drawItem(slot.xDisplayPosition, slot.yDisplayPosition, slot.getStack());
}
}
}
recipeTooltipGui.drawGuiContainerForegroundLayer(-100, -100);
for (GuiButton btn : recipeTooltipGui.getOverlayButtons()) {
btn.drawButton(mc, -100, -100);
}
GL11.glPopMatrix();
}
protected void drawSlotOutline(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
if (focused != null && focused.slotIndex == slotIdx) {
drawRect(rect.x, rect.y, rect.w, rect.h, 0xee555555); // highlight
@@ -329,6 +456,16 @@ public class ItemsGrid {
}
}
public void postDrawTooltips(int mousex, int mousey, List<String> tooltip) {
if (NEIClientConfig.showRecipeTooltips() && showRecipeTooltips) {
try {
drawRecipeTooltip(mousex, mousey, tooltip);
} catch (Exception e) {
NEIClientConfig.logger.warn("Cannot draw recipe tooltip", e);
}
}
}
public void setVisible() {
if (getItems().isEmpty() && getMessageOnEmpty() != null) {
LayoutManager.addWidget(messageLabel);
@@ -280,6 +280,13 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
}
}
@Override
public void postRenderTooltips(GuiContainer gui, int mousex, int mousey, List<String> tooltip) {
if (!isHidden() && isEnabled()) {
for (Widget widget : drawWidgets) widget.postDrawTooltips(mousex, mousey, tooltip);
}
}
@Override
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
@@ -531,8 +538,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
}
@Override
public String getButtonTip() {
return getTimeTip(NEIActions.timeZones[zone], state);
public void addTooltips(List<String> tooltip) {
addTimeTip(NEIActions.timeZones[zone], state, tooltip);
}
};
}
@@ -565,9 +572,13 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
return translate("inventory." + name + "." + sfx);
}
private static String getTimeTip(String name, int state) {
String sfx = (state & 0x3) == 2 ? "enable" : "set";
return translate("inventory." + name + "." + sfx);
private static void addTimeTip(String name, int state, List<String> tooltip) {
if ((state & 0x3) == 2) {
tooltip.add(translate("inventory." + name + ".enable"));
} else {
tooltip.add(translate("inventory." + name + ".set"));
tooltip.add(EnumChatFormatting.GRAY + translate("inventory." + name + ".disable"));
}
}
private static boolean handleDisabledButtonPress(String ident, boolean rightclick) {
@@ -21,6 +21,8 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.input.Keyboard;
import com.google.common.base.Objects;
import codechicken.core.CCUpdateChecker;
import codechicken.core.ClassDiscoverer;
import codechicken.core.ClientUtils;
@@ -53,11 +55,10 @@ import codechicken.nei.recipe.RecipeCatalysts;
import codechicken.nei.recipe.RecipeInfo;
import codechicken.obfuscator.ObfuscationRun;
import com.google.common.base.Objects;
public class NEIClientConfig {
private static boolean configLoaded;
private static boolean mainNEIConfigLoaded;
private static boolean pluginNEIConfigLoaded;
private static boolean enabledOverride;
private static String worldPath;
@@ -241,6 +242,9 @@ public class NEIClientConfig {
tag.getTag("inventory.bookmarksAnimationEnabled").setComment("REI Style Animation in Bookmarks")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.bookmarksAnimationEnabled", true));
tag.getTag("inventory.recipeTooltipsEnabled").setComment("Show recipe tooltips in Bookmarks")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.recipeTooltipsEnabled", true));
tag.getTag("inventory.showRecipeMarker").setComment("Show Recipe Marker").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.showRecipeMarker", true));
@@ -463,8 +467,9 @@ public class NEIClientConfig {
}
public static void bootNEI(World world) {
if (configLoaded) return;
if (mainNEIConfigLoaded) return;
// main NEI config loading
ItemInfo.load(world);
GuiInfo.load();
RecipeInfo.load();
@@ -472,12 +477,13 @@ public class NEIClientConfig {
NEIController.load();
RecipeCatalysts.loadCatalystInfo();
configLoaded = true;
mainNEIConfigLoaded = true;
new Thread("NEI Plugin Loader") {
@Override
public void run() {
logger.debug("Started NEI plugin loading");
ClassDiscoverer classDiscoverer = new ClassDiscoverer(
test -> test.startsWith("NEI") && test.endsWith("Config.class"),
IConfigureNEI.class);
@@ -495,6 +501,13 @@ public class NEIClientConfig {
}
}
// Set pluginNEIConfigLoaded here before posting the NEIConfigsLoadedEvent. This used to be the other
// way around, but apparently if your modpack includes 800 mods the event poster might not return in
// time and cause issues when loading a world for a second time as configLoaded is still false. This may
// cause issues in case one of the event handler calls the (non-thread-safe) NEI API. I don't expect any
// handler to do this, but who knows what modders have come up with...
pluginNEIConfigLoaded = true;
logger.debug("NEI plugin loading finished");
MinecraftForge.EVENT_BUS.post(new NEIConfigsLoadedEvent());
}
}.start();
@@ -549,6 +562,10 @@ public class NEIClientConfig {
return getBooleanSetting("inventory.bookmarksAnimationEnabled");
}
public static boolean showRecipeTooltips() {
return getBooleanSetting("inventory.recipeTooltipsEnabled");
}
public static boolean showRecipeMarker() {
return getBooleanSetting("inventory.showRecipeMarker");
}
@@ -597,6 +614,10 @@ public class NEIClientConfig {
return enabledOverride && getBooleanSetting("inventory.widgetsenabled");
}
public static boolean isLoaded() {
return mainNEIConfigLoaded && pluginNEIConfigLoaded;
}
public static boolean loadHandlersFromJar() {
return !getBooleanSetting("tools.handler_load_from_config");
}
@@ -43,6 +43,8 @@ import net.minecraft.util.ResourceLocation;
import org.lwjgl.input.Keyboard;
import com.google.common.collect.Iterables;
import codechicken.lib.inventory.InventoryRange;
import codechicken.lib.inventory.InventoryUtils;
import codechicken.lib.util.LangProxy;
@@ -50,8 +52,6 @@ import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.IInfiniteItemHandler;
import codechicken.nei.api.ItemInfo;
import com.google.common.collect.Iterables;
public class NEIClientUtils extends NEIServerUtils {
public static LangProxy lang = new LangProxy("nei");
@@ -5,16 +5,15 @@ import java.util.*;
import net.minecraft.util.EnumChatFormatting;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import codechicken.core.CommonUtils;
import codechicken.core.launch.CodeChickenCorePlugin;
import codechicken.nei.api.IConfigureNEI;
import codechicken.nei.asm.NEICorePlugin;
import codechicken.nei.config.IMCHandler;
import codechicken.nei.recipe.GuiRecipeTab;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import cpw.mods.fml.client.FMLFileResourcePack;
import cpw.mods.fml.client.FMLFolderResourcePack;
import cpw.mods.fml.common.DummyModContainer;
@@ -1,6 +1,7 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
@@ -171,6 +172,11 @@ public abstract class PanelWidget extends Widget {
}
}
@Override
public void update() {
grid.update();
}
@Override
public void draw(int mousex, int mousey) {
grid.draw(mousex, mousey);
@@ -185,6 +191,11 @@ public abstract class PanelWidget extends Widget {
}
}
@Override
public void postDrawTooltips(int mx, int my, List<String> tooltip) {
grid.postDrawTooltips(mx, my, tooltip);
}
@Override
public void mouseDragged(int mousex, int mousey, int button, long heldTime) {
if (mouseDownSlot >= 0 && draggedStack == null
@@ -21,6 +21,11 @@ import net.minecraft.item.ItemStack;
import org.apache.commons.io.IOUtils;
import org.lwjgl.input.Keyboard;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import codechicken.core.CommonUtils;
import codechicken.core.gui.GuiScrollSlot;
import codechicken.lib.gui.GuiDraw;
@@ -30,11 +35,6 @@ import codechicken.nei.api.ItemFilter;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import cpw.mods.fml.common.registry.GameRegistry;
public class PresetsWidget extends Widget {
@@ -1,6 +1,7 @@
package codechicken.nei;
import com.google.common.base.Objects;
import cpw.mods.fml.common.FMLCommonHandler;
public class ThreadOperationTimer extends Thread {
@@ -14,6 +14,8 @@ public abstract class Widget {
public void postDraw(int mx, int my) {}
public void postDrawTooltips(int mx, int my, List<String> tooltip) {}
public boolean handleClick(int mx, int my, int button) {
return true;
}
@@ -24,10 +24,13 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
public static int mobOverlay = 0;
private static byte[] mobSpawnCache;
private static long mobOverlayUpdateTime;
private static String oregenPatternName;
private static boolean hasOregenPatternBeenSet = false;
public static void reset() {
mobOverlay = 0;
chunkOverlay = 0;
hasOregenPatternBeenSet = false;
}
@Override
@@ -279,15 +282,33 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
GL11.glVertex3d(x2, y2, z1 + h);
}
} else if (chunkOverlay == 3) {
int gx1 = (((entity.chunkCoordX < 0 ? entity.chunkCoordX - 3 : entity.chunkCoordX) / 3 * 3) << 4)
- intOffsetX;
int gz1 = (((entity.chunkCoordZ < 0 ? entity.chunkCoordZ - 3 : entity.chunkCoordZ) / 3 * 3) << 4)
- intOffsetZ;
if (entity.chunkCoordX < 0) {
gx1 += 16;
if (!hasOregenPatternBeenSet) {
try {
oregenPatternName = ((Enum<?>) Class.forName("gregtech.common.GT_Worldgenerator")
.getDeclaredField("oregenPattern").get(null)).name();
} catch (Exception ignored) {
oregenPatternName = "AXISSYMMETRICAL";
}
hasOregenPatternBeenSet = true;
}
if (entity.chunkCoordZ < 0) {
gz1 += 16;
int gx1;
int gz1;
if (oregenPatternName.equals("EQUAL_SPACING")) {
// gt oregen uses new regular pattern
gx1 = ((Math.floorDiv(entity.chunkCoordX, 3) * 3) << 4) - intOffsetX;
gz1 = ((Math.floorDiv(entity.chunkCoordZ, 3) * 3) << 4) - intOffsetZ;
} else {
// gt oregen uses old bugged pattern
gx1 = (((entity.chunkCoordX < 0 ? entity.chunkCoordX - 3 : entity.chunkCoordX) / 3 * 3) << 4)
- intOffsetX;
gz1 = (((entity.chunkCoordZ < 0 ? entity.chunkCoordZ - 3 : entity.chunkCoordZ) / 3 * 3) << 4)
- intOffsetZ;
if (entity.chunkCoordX < 0) {
gx1 += 16;
}
if (entity.chunkCoordZ < 0) {
gz1 += 16;
}
}
int gx2 = gx1 + 48;
int gz2 = gz1 + 48;
+2 -2
View File
@@ -12,6 +12,8 @@ import net.minecraft.item.ItemStack;
import org.lwjgl.input.Keyboard;
import com.google.common.collect.Sets;
import codechicken.nei.ItemList;
import codechicken.nei.ItemSorter;
import codechicken.nei.ItemStackSet;
@@ -37,8 +39,6 @@ import codechicken.nei.recipe.RecipeCatalysts;
import codechicken.nei.recipe.RecipeInfo;
import codechicken.nei.recipe.StackInfo;
import com.google.common.collect.Sets;
/**
* This is the main class that handles item property configuration. WARNING: DO NOT access this class until the world
* has been loaded These methods should be called from INEIConfig implementors
@@ -39,6 +39,8 @@ import net.minecraftforge.common.BiomeDictionary;
import net.minecraftforge.common.IShearable;
import net.minecraftforge.oredict.OreDictionary;
import com.google.common.collect.ArrayListMultimap;
import codechicken.core.featurehack.GameDataManipulator;
import codechicken.nei.InfiniteStackSizeHandler;
import codechicken.nei.InfiniteToolHandler;
@@ -55,9 +57,6 @@ import codechicken.nei.config.RegistryDumper;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.BrewingRecipeHandler;
import codechicken.nei.recipe.RecipeItemInputHandler;
import com.google.common.collect.ArrayListMultimap;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.registry.GameRegistry;
@@ -20,6 +20,10 @@ public abstract class ShortcutInputHandler {
public static boolean handleKeyEvent(ItemStack stackover) {
if (!NEIClientConfig.isLoaded()) {
return false;
}
if (NEIClientConfig.isKeyHashDown("gui.overlay_hide")) {
return hideOverlayRecipe();
}
@@ -67,6 +71,10 @@ public abstract class ShortcutInputHandler {
public static boolean handleMouseClick(ItemStack stackover) {
if (!NEIClientConfig.isLoaded()) {
return false;
}
if (stackover != null) {
final int button = Mouse.getEventButton();
stackover = stackover.copy();
@@ -10,6 +10,8 @@ import net.minecraft.util.ChatComponentTranslation;
import org.apache.commons.io.IOUtils;
import com.google.common.base.Objects;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.GuiUsageRecipe;
@@ -18,8 +20,6 @@ import codechicken.nei.recipe.IRecipeHandler;
import codechicken.nei.recipe.TemplateRecipeHandler;
import codechicken.nei.util.NBTJson;
import com.google.common.base.Objects;
public class HandlerDumper extends DataDumper {
public HandlerDumper(String name) {
@@ -8,12 +8,12 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.LayoutManager;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.LayoutManager;
public abstract class OptionStringSet extends Option {
public final LinkedList<String> options = new LinkedList<>();
@@ -14,6 +14,8 @@ import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiScreen;
@@ -159,33 +161,21 @@ public class GuiContainerManager {
return namelist;
}
public static String itemCountDetails(ItemStack stack) {
final FluidStack fluid = StackInfo.getFluid(stack);
int maxStackSize = stack.getMaxStackSize();
int stackSize = stack.stackSize;
String FULL_PATTERN = "Count: %s = %s * %s + %s";
String SHORT_PATTERN = "Count: %s = %s * %s";
if (fluid != null) {
maxStackSize = 144;
stackSize = fluid.amount * Math.max(1, stack.stackSize);
FULL_PATTERN = "Amount: %s L = %s * %s L + %s L";
SHORT_PATTERN = "Amount: %s L = %s * %s L";
}
@Nullable
public static String countDetails(int stackSize, int maxStackSize, String fullPattern, String shortPattern) {
if (maxStackSize > 1 && stackSize > maxStackSize) {
final int remainder = stackSize % maxStackSize;
if (remainder > 0) {
return String.format(
FULL_PATTERN,
fullPattern,
NEIClientUtils.formatNumbers(stackSize),
NEIClientUtils.formatNumbers(stackSize / maxStackSize),
NEIClientUtils.formatNumbers(maxStackSize),
NEIClientUtils.formatNumbers(remainder));
} else {
return String.format(
SHORT_PATTERN,
shortPattern,
NEIClientUtils.formatNumbers(stackSize),
NEIClientUtils.formatNumbers(stackSize / maxStackSize),
NEIClientUtils.formatNumbers(maxStackSize));
@@ -195,6 +185,31 @@ public class GuiContainerManager {
return null;
}
@Nullable
public static String itemCountDetails(ItemStack stack) {
FluidStack fluid = StackInfo.getFluid(stack);
if (fluid != null) {
return fluidAmountDetails(fluid.amount * Math.max(1, stack.stackSize));
} else {
return countDetails(
stack.stackSize,
stack.getMaxStackSize(),
"Count: %s = %s * %s + %s",
"Count: %s = %s * %s");
}
}
@SuppressWarnings("unused")
@Nullable
public static String fluidAmountDetails(FluidStack fluid) {
return fluidAmountDetails(fluid.amount);
}
@Nullable
public static String fluidAmountDetails(int amount) {
return countDetails(amount, 144, "Amount: %s L = %s * %s L + %s L", "Amount: %s L = %s * %s L");
}
/**
* The general name of this item.
*
@@ -499,6 +514,10 @@ public class GuiContainerManager {
if (tooltip.size() > 0) tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE); // add space after 'title'
drawPagedTooltip(font, mousex + 12, mousey - 12, tooltip);
for (IContainerDrawHandler drawHandler : drawHandlers) {
drawHandler.postRenderTooltips(window, mousex, mousey, tooltip);
}
}
private static int tooltipPage;
@@ -1,5 +1,7 @@
package codechicken.nei.guihook;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.inventory.Slot;
@@ -30,6 +32,17 @@ public interface IContainerDrawHandler {
*/
public void postRenderObjects(GuiContainer gui, int mousex, int mousey);
/**
* Use this to draw things that should be drawn just after vanilla slot tooltips, on top of buttons and other
* usually always-on-top widgets.
*
* @param gui An instance of the currentscreen
* @param mousex The x position of the mouse in pixels from left
* @param mousey The y position of the mouse in pixels from top
* @param tooltip The contents of the tooltip that has previously been drawn
*/
default void postRenderTooltips(GuiContainer gui, int mousex, int mousey, List<String> tooltip) {}
/**
* Render something over a slot before the item in the slot.
*
@@ -6,14 +6,14 @@ import java.util.List;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import codechicken.nei.PositionedStack;
import codechicken.nei.util.NBTJson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import codechicken.nei.PositionedStack;
import codechicken.nei.util.NBTJson;
public class BookmarkRecipeId {
public int position = -1;
@@ -121,6 +121,43 @@ public class BookmarkRecipeId {
return arr;
}
/**
* Ensures the {@link BookmarkRecipeId#recipetype} and {@link BookmarkRecipeId#position} fields point to a valid
* recipe. This is needed, because the recipe IDs are loaded lazily on first use.
*
* @param recipeHandlers The subset of recipe handlers to search for the recipe
*/
public void updateTargetRecipe(List<? extends IRecipeHandler> recipeHandlers) {
if (this.recipetype == -1 || this.position == -1) {
this.recipetype = 0;
this.position = 0;
if (this.handlerName != null) {
for (int j = 0; j < recipeHandlers.size(); j++) {
IRecipeHandler localHandler = recipeHandlers.get(j);
HandlerInfo localHandlerInfo = GuiRecipeTab.getHandlerInfo(localHandler);
if (localHandlerInfo.getHandlerName().equals(this.handlerName)) {
if (!this.ingredients.isEmpty()) {
for (int i = 0; i < localHandler.numRecipes(); i++) {
if (this.equalsIngredients(localHandler.getIngredientStacks(i))) {
this.recipetype = j;
this.position = i;
break;
}
}
}
break;
}
}
}
}
}
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
@@ -8,11 +8,11 @@ import javax.annotation.Nonnull;
import net.minecraft.item.ItemStack;
import com.google.common.collect.ForwardingList;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIServerUtils;
import com.google.common.collect.ForwardingList;
// Do not directly extend ArrayList, see Effective Java Item 16
public class CatalystInfoList extends ForwardingList<CatalystInfo> {
@@ -28,28 +28,27 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
public static boolean openRecipeGui(String outputId, final Boolean overlay, final Boolean shift,
Object... results) {
return createRecipeGui(outputId, overlay, shift, true, results) != null;
}
public static GuiRecipe<?> createRecipeGui(String outputId, final Boolean overlay, final Boolean shift,
final boolean open, Object... results) {
final Minecraft mc = NEIClientUtils.mc();
final BookmarkRecipeId recipeId = "item".equals(outputId)
? getRecipeId(mc.currentScreen, (ItemStack) results[0])
: getCurrentRecipe(mc.currentScreen);
if (overlay && recipeId == null) return false;
if (overlay && recipeId == null) return null;
final RecipeHandlerQuery<ICraftingHandler> recipeQuery = new RecipeHandlerQuery<>(
h -> h.getRecipeHandler(outputId, results),
craftinghandlers,
serialCraftingHandlers,
"Error while looking up crafting recipe",
"outputId: " + outputId,
"results: " + Arrays.toString(results));
final ArrayList<ICraftingHandler> handlers = recipeQuery.runWithProfiling("recipe.concurrent.crafting");
final ArrayList<ICraftingHandler> handlers = getCraftingHandlers(outputId, results);
if (!handlers.isEmpty()) {
GuiCraftingRecipe gui = new GuiCraftingRecipe(handlers, recipeId);
mc.displayGuiScreen(gui);
if (open) {
mc.displayGuiScreen(gui);
}
if (recipeId != null) {
gui.openTargetRecipe(gui.recipeId);
@@ -59,10 +58,22 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
gui.overlayRecipe(gui.recipeId.position, shift);
}
return true;
return gui;
}
return false;
return null;
}
public static ArrayList<ICraftingHandler> getCraftingHandlers(String outputId, Object... results) {
final RecipeHandlerQuery<ICraftingHandler> recipeQuery = new RecipeHandlerQuery<>(
h -> h.getRecipeHandler(outputId, results),
craftinghandlers,
serialCraftingHandlers,
"Error while looking up crafting recipe",
"outputId: " + outputId,
"results: " + Arrays.toString(results));
return recipeQuery.runWithProfiling("recipe.concurrent.crafting");
}
protected static BookmarkRecipeId getRecipeId(GuiScreen gui, ItemStack stackover) {
@@ -1,5 +1,7 @@
package codechicken.nei.recipe;
import static codechicken.lib.gui.GuiDraw.fontRenderer;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
@@ -11,8 +13,10 @@ import java.util.regex.Matcher;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
@@ -59,6 +63,8 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private static final int buttonWidth = 13;
private static final int buttonHeight = 12;
private boolean limitToOneRecipe = false;
// Background image
final DrawableResource bgTop = new DrawableBuilder("nei:textures/gui/recipebg.png", 0, BG_TOP_Y, 176, BG_TOP_HEIGHT)
.build();
@@ -100,6 +106,12 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private int yShift = 0;
/**
* This will only be true iff height hacking has been configured for the current recipe handler AND we are currently
* within the scope of an active {@link HeightHack} instance.
*/
private boolean isHeightHackApplied = false;
protected GuiRecipe(GuiScreen prevgui) {
super(new ContainerRecipe());
recipeTabs = new GuiRecipeTabs(this);
@@ -116,9 +128,14 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
}
/** Changes the GUI mode to only display one recipe at a time, e.g. for tooltip usage */
public void limitToOneRecipe() {
limitToOneRecipe = true;
}
/**
* Many old mods assumed a fixed NEI window height of {@code 166} pixels. Now that this is no longer the case, their
* fluid mouseover handling is broken. This helper class fixes these old mods by hacking the {@link #height}
* tooltip and click zone handling is broken. This helper class fixes these old mods by hacking the {@link #height}
* property's value so that these old mods' calculations return the correct value for the new height.
*
* <p>
@@ -128,40 +145,77 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private class HeightHack implements AutoCloseable {
private final int trueHeight;
private final int trueGuiTop;
private final GuiScreen trueGui;
private HeightHack() {
trueHeight = height;
trueGuiTop = guiTop;
trueGui = Minecraft.getMinecraft().currentScreen;
boolean applyHeightHack = NEIClientConfig.heightHackHandlerRegex.stream()
isHeightHackApplied = NEIClientConfig.heightHackHandlerRegex.stream()
.map(pattern -> pattern.matcher(handler.getHandlerId())).anyMatch(Matcher::matches);
if (applyHeightHack) {
// The old mods use the calculation ((height - 166) / 2) to compute the y-value of
// the top edge of the NEI window.
// guiTop is exactly that: the y-value of the top edge of the NEI window.
// So we set height to be equal to the inverse of this calculation, applied to
// guiTop, so that old mods get the right result back when they use this calculation.
if (isHeightHackApplied) {
// guiTop is the top edge of the recipe screen on the y-axis. Old recipe handlers expect a single paging
// widget at the top and at the bottom of the recipe screen with a height of 16px each, but GTNH NEI
// moved the bottom paging widget to the top following JEI's design, increasing the "forbidden" zone at
// the top to 32px. To fix these old recipe handlers we move guiTop down 16px so that they can keep
// working with the old 16px gap.
guiTop += 16;
// The old NEI recipe screen had a fixed width and height and was always centered on the screen. Legacy
// recipe handlers use the calculation ((height - 166) / 2) to compute the y-value of the top edge of
// the NEI window. GTNH NEI changes the layout so that the recipe screen length now has a flexible
// length and is no longer centered vertically. In order for the top-of-screen calculation to return the
// correct result, we have to hack the height field with an inverse of the calculation using the actual
// top of the recipe screen stored in guiTop.
height = (2 * guiTop) + 166;
// For reference, in case we ever need to modify width as well:
// the legacy calculation used for width is ((width - 176) / 2), which should
// evaluate to be equal to guiWidth (the x-value of the left edge of the NEI window).
// So if we wanted to override width as well, we'd do this:
// the legacy calculation used for width is ((width - 176) / 2), which should evaluate to be equal to
// guiWidth (the x-value of the left edge of the NEI recipe screen). So if we wanted to override width
// as well, we'd do this:
// width = (2 * guiWidth) + 176;
// Recipe handlers may assume the current screen is the GuiRecipe object, which is not the case in
// recipe tooltips drawn on the bookmarks panel with the main inventory open.
if (limitToOneRecipe) {
Minecraft.getMinecraft().currentScreen = GuiRecipe.this;
}
}
}
@Override
public void close() {
guiTop = trueGuiTop;
height = trueHeight;
Minecraft.getMinecraft().currentScreen = trueGui;
isHeightHackApplied = false;
}
}
@Override
@SuppressWarnings("unchecked")
public void initGui() {
initGui(false);
}
@SuppressWarnings("unchecked")
public void initGui(boolean asWidget) {
xSize = 176;
ySize = Math.min(Math.max(height - 68, 166), 370);
super.initGui();
if (!asWidget) {
super.initGui();
} else {
this.guiLeft = (this.width - this.xSize) / 2;
this.mc = Minecraft.getMinecraft();
this.fontRendererObj = mc.fontRenderer;
ScaledResolution scaledresolution = new ScaledResolution(
this.mc,
this.mc.displayWidth,
this.mc.displayHeight);
this.width = scaledresolution.getScaledWidth();
this.height = scaledresolution.getScaledHeight();
}
guiTop = (height - ySize) / 2 + 10;
currenthandlers = getCurrentRecipeHandlers(); // Probably don't comment me out
@@ -198,14 +252,23 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
final int recipesPerPage = getRecipesPerPage();
overlayButtons = new GuiButton[recipesPerPage];
final int xOffset = limitToOneRecipe ? ((xSize / 2) - 2) : (width / 2);
final String overlayKeyName = NEIClientConfig
.getKeyName(NEIClientConfig.getKeyBinding("gui.overlay_use"), true);
for (int i = 0; i < recipesPerPage; i++) {
overlayButtons[i] = new GuiNEIButton(
OVERLAY_BUTTON_ID_START + i,
(width / 2) + 65,
guiTop + 16 + (handlerInfo.getHeight() * (i + 1)) - 2,
xOffset + 65,
16 + (handlerInfo.getHeight() * (i + 1)) - 2,
buttonWidth,
buttonHeight,
"?");
if (overlayKeyName != null && limitToOneRecipe) {
overlayButtons[i].visible = true;
overlayButtons[i].displayString = overlayKeyName;
overlayButtons[i].width = fontRenderer.getStringWidth(overlayKeyName) + 6;
overlayButtons[i].xPosition = xOffset + 85 - overlayButtons[i].width;
}
}
Collections.addAll(buttonList, overlayButtons);
itemPresenceCacheRecipe = -1;
@@ -232,41 +295,17 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
initOverlayButtons();
}
public List<GuiButton> getOverlayButtons() {
return Collections.unmodifiableList(Arrays.asList(overlayButtons));
}
public void openTargetRecipe(BookmarkRecipeId recipeId) {
if (recipeId == null) {
return;
}
if (recipeId.recipetype == -1 || recipeId.position == -1) {
recipeId.recipetype = 0;
recipeId.position = 0;
if (recipeId.handlerName != null) {
for (int j = 0; j < currenthandlers.size(); j++) {
H localHandler = currenthandlers.get(j);
HandlerInfo localHandlerInfo = GuiRecipeTab.getHandlerInfo(localHandler);
if (localHandlerInfo.getHandlerName().equals(recipeId.handlerName)) {
if (!recipeId.ingredients.isEmpty()) {
for (int i = 0; i < localHandler.numRecipes(); i++) {
if (recipeId.equalsIngredients(localHandler.getIngredientStacks(i))) {
recipeId.recipetype = j;
recipeId.position = i;
break;
}
}
}
break;
}
}
}
}
recipeId.updateTargetRecipe(currenthandlers);
setRecipePage(recipeId.recipetype, recipeId.position);
}
@@ -388,8 +427,22 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
// the value of the height field will be different from in other mouseover methods, which
// could be confusing...
// First, invoke scroll handling over recipe handler tabbar. Makes sure it is not overwritten by recipe
// handler-specific scroll behavior.
if (recipeTabs.mouseScrolled(i)) return;
for (int recipe : getRecipeIndices()) if (handler.mouseScrolled(this, i, recipe)) return;
// If shift is held, try switching to the next recipe handler. Replicates the GuiRecipeTabs.mouseScrolled()
// without the checking for the cursor being inside the tabbar.
if (NEIClientUtils.shiftKey()) {
if (i < 0) nextType();
else prevType();
return;
}
// Finally, if nothing else has handled scrolling, try changing to the next recipe page.
if (new Rectangle(guiLeft, guiTop, xSize, ySize).contains(GuiDraw.getMousePosition())) {
if (i > 0) prevPage();
else nextPage();
@@ -424,6 +477,11 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
@Override
public void updateScreen() {
super.updateScreen();
updateAsTooltip();
}
/** updateScreen() that's safe to call when this isn't the currently open GUI */
public void updateAsTooltip() {
handler.onUpdate();
refreshPage();
}
@@ -440,9 +498,9 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
@Override
public List<String> handleItemTooltip(GuiContainer gui, ItemStack stack, int mousex, int mousey,
List<String> currenttip) {
// Height hacking is probably not needed as it doesn't look like any mods check mouse
// position for this method.
for (int i : getRecipeIndices()) currenttip = handler.handleItemTooltip(this, stack, currenttip, i);
try (HeightHack heightHack = new HeightHack()) {
for (int i : getRecipeIndices()) currenttip = handler.handleItemTooltip(this, stack, currenttip, i);
}
return currenttip;
}
@@ -462,11 +520,11 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
if (page < 0) page = (handler.numRecipes() - 1) / getRecipesPerPage();
}
private void nextType() {
protected void nextType() {
setRecipePage(++recipetype);
}
private void prevType() {
protected void prevType() {
setRecipePage(--recipetype);
}
@@ -528,6 +586,12 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
final int recipesPerPage = getRecipesPerPage();
for (int i = page * recipesPerPage; i < handler.numRecipes() && i < (page + 1) * recipesPerPage; i++) {
Point p = getRecipePosition(i);
// Legacy recipe handlers only expect a single paging widget at the top of the recipe screen, in contrast,
// GTNH NEI moves the recipe paging widget from the bottom to the top, which means said legacy handlers will
// position item slots 16px too high in the screen.
if (isHeightHackApplied) {
p.translate(0, 16);
}
List<PositionedStack> stacks = handler.getIngredientStacks(i);
for (PositionedStack stack : stacks) slotcontainer.addSlot(stack, p.x, p.y);
@@ -538,11 +602,13 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
PositionedStack result = handler.getResultStack(i);
if (result != null) slotcontainer.addSlot(result, p.x, p.y);
List<PositionedStack> catalysts = RecipeCatalysts.getRecipeCatalysts(handler);
for (PositionedStack catalyst : catalysts) {
int xOffset = -GuiRecipeCatalyst.ingredientSize + 1;
int yOffset = BG_TOP_Y + GuiRecipeCatalyst.fullBorder;
slotcontainer.addSlot(catalyst, xOffset, yOffset);
if (!limitToOneRecipe) {
List<PositionedStack> catalysts = RecipeCatalysts.getRecipeCatalysts(handler);
for (PositionedStack catalyst : catalysts) {
int xOffset = -GuiRecipeCatalyst.ingredientSize + 1;
int yOffset = BG_TOP_Y + GuiRecipeCatalyst.fullBorder;
slotcontainer.addSlot(catalyst, xOffset, yOffset);
}
}
}
}
@@ -576,21 +642,24 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
@Override
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) {
public void drawGuiContainerForegroundLayer(int mouseX, int mouseY) {
GuiContainerManager.enable2DRender();
final int recipesPerPage = getRecipesPerPage();
String s = handler.getRecipeName().trim();
fontRendererObj.drawStringWithShadow(s, (xSize - fontRendererObj.getStringWidth(s)) / 2, 5, 0xffffff);
s = NEIClientUtils.translate("recipe.page", page + 1, (handler.numRecipes() - 1) / recipesPerPage + 1);
fontRendererObj.drawStringWithShadow(s, (xSize - fontRendererObj.getStringWidth(s)) / 2, 19, 0xffffff);
final int ySkip = limitToOneRecipe ? 25 : 0;
if (!limitToOneRecipe) {
String s = handler.getRecipeName().trim();
fontRendererObj.drawStringWithShadow(s, (xSize - fontRendererObj.getStringWidth(s)) / 2, 5, 0xffffff);
s = NEIClientUtils.translate("recipe.page", page + 1, (handler.numRecipes() - 1) / recipesPerPage + 1);
fontRendererObj.drawStringWithShadow(s, (xSize - fontRendererObj.getStringWidth(s)) / 2, 19, 0xffffff);
}
final boolean drawItemPresence = NEIClientConfig.isJEIStyleItemPresenceOverlayVisible();
GL11.glPushMatrix();
GL11.glTranslatef(5, 32 + yShift, 0);
GL11.glTranslatef(5, 32 - ySkip + yShift, 0);
try (HeightHack heightHack = new HeightHack()) {
for (int i = page * recipesPerPage; i < handler.numRecipes() && i < (page + 1) * recipesPerPage; i++) {
handler.drawForeground(i);
if (drawItemPresence && isMouseOverOverlayButton(i - page * recipesPerPage)
if (drawItemPresence && (isMouseOverOverlayButton(i - page * recipesPerPage) || limitToOneRecipe)
&& firstGui.inventorySlots != null) {
List<PositionedStack> ingredients = handler.getIngredientStacks(i);
if (itemPresenceCacheRecipe != i || itemPresenceCacheSlots == null
@@ -610,28 +679,27 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
@Override
protected void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY) {
public void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY) {
final int recipesPerPage = getRecipesPerPage();
final int ySkip = limitToOneRecipe ? 25 : 0;
GL11.glColor4f(1, 1, 1, 1);
final int j = (width - xSize) / 2;
final int k = guiTop;
drawBackgroundTiled(j, k);
drawBackgroundTiled(guiLeft, guiTop);
drawRect(
guiLeft + borderPadding + buttonWidth - 1,
nexttype.yPosition,
guiLeft + xSize - borderPadding - buttonWidth,
nexttype.yPosition + buttonHeight,
0x30000000);
drawRect(
guiLeft + borderPadding + buttonWidth - 1,
nextpage.yPosition,
guiLeft + xSize - borderPadding - buttonWidth,
nextpage.yPosition + buttonHeight,
0x30000000);
if (NEIClientConfig.areJEIStyleTabsVisible() && !limitToOneRecipe) {
drawRect(
guiLeft + borderPadding + buttonWidth - 1,
nexttype.yPosition,
guiLeft + xSize - borderPadding - buttonWidth,
nexttype.yPosition + buttonHeight,
0x30000000);
drawRect(
guiLeft + borderPadding + buttonWidth - 1,
nextpage.yPosition,
guiLeft + xSize - borderPadding - buttonWidth,
nextpage.yPosition + buttonHeight,
0x30000000);
if (NEIClientConfig.areJEIStyleTabsVisible()) {
RenderHelper.enableGUIStandardItemLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
recipeTabs.draw(mouseX, mouseY);
@@ -642,7 +710,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
GL11.glPushMatrix();
GL11.glTranslatef(j + 5, k + 32 + yShift, 0);
GL11.glTranslatef(guiLeft + 5, guiTop - ySkip + 32 + yShift, 0);
try (HeightHack heightHack = new HeightHack()) {
for (int i = page * recipesPerPage; i < handler.numRecipes() && i < (page + 1) * recipesPerPage; i++) {
handler.drawBackground(i);
@@ -654,10 +722,12 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private void drawBackgroundTiled(int j, int k) {
// Draw the top
final int ySkip = limitToOneRecipe ? 25 : 0;
final int handlerHeight = limitToOneRecipe ? getHeightAsWidget() : ySize;
bgTop.draw(j, k + BG_TOP_Y);
// Maybe Tile the middle
final int tiledHeight = ySize - BG_TOP_HEIGHT - BG_BOTTOM_HEIGHT;
final int tiledHeight = handlerHeight - ySkip - BG_TOP_HEIGHT - BG_BOTTOM_HEIGHT;
if (tiledHeight > 0) {
final int yTileCount = tiledHeight / BG_MIDDLE_HEIGHT;
@@ -674,7 +744,11 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
// Draw the bottom
bgBottom.draw(j, k + ySize - BG_BOTTOM_HEIGHT);
bgBottom.draw(j, k + handlerHeight - ySkip - BG_BOTTOM_HEIGHT);
}
public int getHeightAsWidget() {
return (handlerInfo == null) ? ySize : (handlerInfo.getHeight() + 56);
}
@Override
@@ -710,7 +784,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
private int getRecipesPerPage() {
return getRecipesPerPage(handlerInfo);
return limitToOneRecipe ? 1 : getRecipesPerPage(handlerInfo);
}
private int getRecipesPerPage(HandlerInfo handlerInfo) {
@@ -721,7 +795,14 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
public Point getRecipePosition(int recipe) {
return new Point(5, 32 + yShift + ((recipe % getRecipesPerPage()) * handlerInfo.getHeight()));
// Legacy recipe handlers using the height hack might use getRecipePosition in combination with guiTop/height to
// position certain elements like tooltips. Since guiTop is moved down by 16px during height hacking, we need to
// reduce the vertical shift here to 16px instead of 32px.
return new Point(
5,
(isHeightHackApplied ? 16 : 32) - (limitToOneRecipe ? 25 : 0)
+ yShift
+ ((recipe % getRecipesPerPage()) * handlerInfo.getHeight()));
}
public abstract ArrayList<H> getCurrentRecipeHandlers();
@@ -1,5 +1,7 @@
package codechicken.nei.recipe;
import static codechicken.lib.gui.GuiDraw.getMousePosition;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
@@ -192,4 +194,18 @@ public class GuiRecipeTabs {
}
return false;
}
protected boolean mouseScrolled(int i) {
Point mousePosition = getMousePosition();
// Switch between recipe handlers if the cursor is over the tabbar.
if (NEIClientConfig.areJEIStyleTabsVisible() && area.contains(mousePosition)) {
if (i < 0) guiRecipe.nextType();
else guiRecipe.prevType();
return true;
}
return false;
}
}
@@ -24,11 +24,11 @@ import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import com.google.common.base.Objects;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIServerUtils;
import codechicken.nei.PositionedStack;
import com.google.common.base.Objects;
import cpw.mods.fml.common.Loader;
public class RecipeCatalysts {
@@ -8,13 +8,13 @@ import net.minecraft.client.gui.inventory.GuiCrafting;
import net.minecraft.client.gui.inventory.GuiFurnace;
import net.minecraft.client.gui.inventory.GuiInventory;
import com.google.common.base.Objects;
import codechicken.nei.OffsetPositioner;
import codechicken.nei.api.API;
import codechicken.nei.api.IOverlayHandler;
import codechicken.nei.api.IStackPositioner;
import com.google.common.base.Objects;
public class RecipeInfo {
private static class OverlayKey {
@@ -21,6 +21,7 @@ import java.util.stream.Collectors;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.inventory.Container;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@@ -29,6 +30,8 @@ import net.minecraft.tileentity.TileEntityFurnace;
import org.lwjgl.opengl.GL11;
import com.google.common.base.Stopwatch;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemList;
import codechicken.nei.NEIClientConfig;
@@ -43,8 +46,6 @@ import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.guihook.IContainerTooltipHandler;
import com.google.common.base.Stopwatch;
/**
* A Template Recipe Handler! How about that. Because it was sooo hard, and more seriously required lots of copied code
* to make a handler in the past. you can now extend this class to make your custom recipe handlers much easier to
@@ -210,7 +211,7 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
for (int i = 0; i < stack.items.length; i++) {
if (NEIServerUtils.areStacksSameTypeCrafting(ingredient, stack.items[i])) {
stack.item = stack.items[i];
stack.item.setItemDamage(ingredient.getItemDamage());
Items.feather.setDamage(stack.item, Items.feather.getDamage(ingredient));
if (ingredient.hasTagCompound()) {
stack.item.setTagCompound((NBTTagCompound) ingredient.getTagCompound().copy());
}
@@ -0,0 +1,15 @@
# Each line in this file should either be a comment (line starts with '#'), or a fully-qualified class name (that
# includes the package name) for a recipe handler. Wildcard patterns ('*') can be used to catch multiple classes with a
# single entry.
# If you delete this file, it will be regenerated with the default height hacked handlers list.
buildcraft.compat.nei.*
cofh.thermalexpansion.plugins.nei.handlers.*
crazypants.enderio.nei.*
forestry.factory.recipes.nei.*
ic2.neiIntegration.core.recipehandler.*
mariculture.plugins.nei.*
redgear.brewcraft.plugins.nei.*
tconstruct.plugins.nei.*
WayofTime.alchemicalWizardry.client.nei.*
exnihilo.compatibility.nei.*
blusunrize.immersiveengineering.client.nei.*
@@ -0,0 +1,6 @@
# This version of NEI loads recipes in parallel. Some recipe handlers have not been designed with that in mind and might
# crash. List these handlers in this file to force them to be loaded single threaded. Each line in this file should
# either be a comment (line starts with '#'), or a fully-qualified class name (that includes the package name) for a
# recipe handler.
# If you delete this file, it will be regenerated with the default serial handlers list.
WayofTime.alchemicalWizardry.client.nei.NEIAlchemyRecipeHandler
@@ -550,8 +550,6 @@ nc.crafting.nei.FusionSteamRecipeHandler,NuclearCraft:fusionReactorSteam,,Nuclea
nc.crafting.nei.ElectrolyserRecipeHandler,NuclearCraft:electrolyserIdle,,NuclearCraft,TRUE,,,,,,
nc.crafting.nei.CrusherRecipeHandler,NuclearCraft:crusherIdle,,NuclearCraft,TRUE,,,,,,
nc.crafting.nei.ElectricCrusherRecipeHandler,NuclearCraft:electricCrusherIdle,,NuclearCraft,TRUE,,,,,,
ganymedes01.etfuturum.NEI_EtFuturum_Config$NEI_Recipes_Smoker,etfuturum:smoker,,etfuturum,TRUE,,,,,,not working well
ganymedes01.etfuturum.NEI_EtFuturum_Config$NEI_Recipes_BlastFurnace,etfuturum:blast_furnace,,etfuturum,TRUE,,,,,,not working well
connor135246.campfirebackport.client.compat.nei.NEICampfireRecipeHandler,campfirebackport:campfire,,campfirebackport,TRUE,,,,,,
connor135246.campfirebackport.client.compat.nei.NEICampfireRecipeHandler,campfirebackport:soul_campfire,,campfirebackport,TRUE,,,,,,
connor135246.campfirebackport.client.compat.nei.NEICampfireStateChangerHandler,campfirebackport:campfire,,campfirebackport,TRUE,,,,,,
1 handler itemName nbtInfo modId modRequired excludedModId priority minVersion maxVersion forceClassName itemNotes
550 nc.crafting.nei.ElectrolyserRecipeHandler NuclearCraft:electrolyserIdle NuclearCraft TRUE
551 nc.crafting.nei.CrusherRecipeHandler NuclearCraft:crusherIdle NuclearCraft TRUE
552 nc.crafting.nei.ElectricCrusherRecipeHandler NuclearCraft:electricCrusherIdle NuclearCraft TRUE
ganymedes01.etfuturum.NEI_EtFuturum_Config$NEI_Recipes_Smoker etfuturum:smoker etfuturum TRUE not working well
ganymedes01.etfuturum.NEI_EtFuturum_Config$NEI_Recipes_BlastFurnace etfuturum:blast_furnace etfuturum TRUE not working well
553 connor135246.campfirebackport.client.compat.nei.NEICampfireRecipeHandler campfirebackport:campfire campfirebackport TRUE
554 connor135246.campfirebackport.client.compat.nei.NEICampfireRecipeHandler campfirebackport:soul_campfire campfirebackport TRUE
555 connor135246.campfirebackport.client.compat.nei.NEICampfireStateChangerHandler campfirebackport:campfire campfirebackport TRUE
+9 -11
View File
@@ -373,11 +373,11 @@ NEIArcFurnaceHandlerCarrot Ingot,Immersive Engineering,minecraft:carrot,,Immersi
NEIArcFurnaceHandlerExtraction,Immersive Engineering,minecraft:glowstone_dust,,ImmersiveEngineering,TRUE,,,65,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEIShaderBagHandler,Immersive Engineering,ImmersiveEngineering:shaderBag,,ImmersiveEngineering,TRUE,,,65,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEIBlueprintHandler,Immersive Engineering,ImmersiveEngineering:woodenDevice:5,,ImmersiveEngineering,TRUE,,,65,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEICokeOvenHandler,Immersive Engineering,ImmersiveEngineering:stoneDecoration:1,,ImmersiveEngineering,TRUE,,,71,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEIBlastFurnaceHandler,Immersive Engineering,ImmersiveEngineering:stoneDecoration:2,,ImmersiveEngineering,TRUE,,,71,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEISqueezerHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:2,,ImmersiveEngineering,TRUE,,,71,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEIFermenterHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:3,,ImmersiveEngineering,TRUE,,,71,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEIRefineryHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:4,,ImmersiveEngineering,TRUE,,,65,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEICokeOvenHandler,Immersive Engineering,ImmersiveEngineering:stoneDecoration:1,,ImmersiveEngineering,TRUE,,,71,166,2,,,,,,
blusunrize.immersiveengineering.client.nei.NEIBlastFurnaceHandler,Immersive Engineering,ImmersiveEngineering:stoneDecoration:2,,ImmersiveEngineering,TRUE,,,71,166,2,,,,,,
blusunrize.immersiveengineering.client.nei.NEISqueezerHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:2,,ImmersiveEngineering,TRUE,,1,64,166,2,,,,,,
blusunrize.immersiveengineering.client.nei.NEIFermenterHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:3,,ImmersiveEngineering,TRUE,,1,64,166,2,,,,,,
blusunrize.immersiveengineering.client.nei.NEIRefineryHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:4,,ImmersiveEngineering,TRUE,,,65,166,2,,,,,,
blusunrize.immersiveengineering.client.nei.NEIBottlingMachineHandler,Immersive Engineering,minecraft:glass_bottle,,ImmersiveEngineering,TRUE,,,65,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEIMetalPressHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:13,,ImmersiveEngineering,TRUE,,,65,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEICrusherHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:5,,ImmersiveEngineering,TRUE,,,71,166,5,,,,,,
@@ -410,13 +410,13 @@ cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCharger,Thermal Expansio
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCraftingMachine,Thermal Expansion,ThermalExpansion:Frame,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCraftingSecure,Thermal Expansion,ThermalExpansion:material:16,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCraftingUpgrade,Thermal Expansion,ThermalExpansion:Frame:3,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCrucible,Thermal Expansion,ThermalExpansion:Machine:4,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCrucible,Thermal Expansion,ThermalExpansion:Machine:4,,ThermalExpansion,TRUE,,,65,166,2,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerFurnace,Thermal Expansion,ThermalExpansion:Machine:0,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerInsolator,Thermal Expansion,ThermalExpansion:Machine:11,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerInsolator,Thermal Expansion,ThermalExpansion:Machine:11,,ThermalExpansion,TRUE,,,65,166,2,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerPulverizer,Thermal Expansion,ThermalExpansion:Machine:1,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerSawmill,Thermal Expansion,ThermalExpansion:Machine:2,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerSmelter,Thermal Expansion,ThermalExpansion:Machine:3,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerTransposer,Thermal Expansion,ThermalExpansion:Machine:5,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerTransposer,Thermal Expansion,ThermalExpansion:Machine:5,,ThermalExpansion,TRUE,,,65,166,2,,,,,,
mekanism.client.nei.ChemicalCrystallizerRecipeHandler,Mekanism,Mekanism:MachineBlock2:8,,Mekanism,TRUE,,,79,,4,,,,,,
mekanism.client.nei.ChemicalDissolutionChamberRecipeHandler,Mekanism,Mekanism:MachineBlock2:6,,Mekanism,TRUE,,,79,,4,,,,,,
mekanism.client.nei.ChemicalInfuserRecipeHandler,Mekanism,Mekanism:MachineBlock2:2,,Mekanism,TRUE,,,80,,4,,,,,,
@@ -437,7 +437,7 @@ mekanism.client.nei.ShapelessMekanismRecipeHandler,Mekanism,minecraft:crafting_t
mekanism.client.nei.SolarNeutronRecipeHandler,Mekanism,Mekanism:MachineBlock3:1,,Mekanism,TRUE,,,70,,5,,,,,,
mekanism.client.nei.ThermalEvaporationRecipeHandler,Mekanism,Mekanism:BasicBlock:14,,Mekanism,TRUE,,,62,,5,,,,,,
exnihilo.compatibility.nei.RecipeHandlerHammer,Ex Nihilo,exnihilo:hammer_iron,,exnihilo,TRUE,,,58,,5,,,,,,
exnihilo.compatibility.nei.RecipeHandlerSieve,Ex Nihilo,exnihilo:sifting_table,,exnihilo,TRUE,,,130,,2,,,,,,
exnihilo.compatibility.nei.RecipeHandlerSieve,Ex Nihilo,exnihilo:sifting_table,,exnihilo,TRUE,,,130,,1,,,,,,
gregtech.Alloy,GregTech-Addon,gregtech_addon:machine:56,,gregtech_addon,TRUE,,15,145,166,2,,,,,,
gregtech.Assembler,GregTech-Addon,gregtech_addon:machine:60,,gregtech_addon,TRUE,,15,145,166,2,,,,,,
gregtech.Bender,GregTech-Addon,gregtech_addon:machine:59,,gregtech_addon,TRUE,,15,145,166,2,,,,,,
@@ -499,8 +499,6 @@ nc.crafting.nei.FusionSteamRecipeHandler,NuclearCraft,NuclearCraft:fusionReactor
nc.crafting.nei.ElectrolyserRecipeHandler,NuclearCraft,NuclearCraft:electrolyserIdle,,NuclearCraft,TRUE,,,65,,4,,,,,,
nc.crafting.nei.CrusherRecipeHandler,NuclearCraft,NuclearCraft:crusherIdle,,NuclearCraft,TRUE,,,65,,4,,,,,,
nc.crafting.nei.ElectricCrusherRecipeHandler,NuclearCraft,NuclearCraft:electricCrusherIdle,,NuclearCraft,TRUE,,,65,,4,,,,,,
ganymedes01.etfuturum.NEI_EtFuturum_Config$NEI_Recipes_Smoker,EtFuturum Requiem,etfuturum:lit_smoker,,etfuturum,TRUE,,,65,166,5,,,,,,
ganymedes01.etfuturum.NEI_EtFuturum_Config$NEI_Recipes_BlastFurnace,EtFuturum Requiem,etfuturum:lit_blast_furnace,,etfuturum,TRUE,,,65,166,5,,,,,,
connor135246.campfirebackport.client.compat.nei.NEICampfireRecipeHandler,Campfire Backport,campfirebackport:campfire,,campfirebackport,TRUE,,,65,166,5,,,,,,
connor135246.campfirebackport.client.compat.nei.NEICampfireStateChangerHandler,Campfire Backport,campfirebackport:campfire_base,,campfirebackport,TRUE,,,65,166,5,,,,,,
net.blay09.mods.excompressum.compat.nei.RecipeHandlerHeavySieve,Ex Compressum,excompressum:heavySieve,,excompressum,TRUE,,,130,166,5,,,,,,
1 handler modName itemName nbtInfo modId modRequired excludedModId yShift handlerHeight handlerWidth maxRecipesPerPage imageResource imageX imageY imageWidth imageHeight itemNotes
373 NEIArcFurnaceHandlerExtraction Immersive Engineering minecraft:glowstone_dust ImmersiveEngineering TRUE 65 166 5
374 blusunrize.immersiveengineering.client.nei.NEIShaderBagHandler Immersive Engineering ImmersiveEngineering:shaderBag ImmersiveEngineering TRUE 65 166 5
375 blusunrize.immersiveengineering.client.nei.NEIBlueprintHandler Immersive Engineering ImmersiveEngineering:woodenDevice:5 ImmersiveEngineering TRUE 65 166 5
376 blusunrize.immersiveengineering.client.nei.NEICokeOvenHandler Immersive Engineering ImmersiveEngineering:stoneDecoration:1 ImmersiveEngineering TRUE 71 166 5 2
377 blusunrize.immersiveengineering.client.nei.NEIBlastFurnaceHandler Immersive Engineering ImmersiveEngineering:stoneDecoration:2 ImmersiveEngineering TRUE 71 166 5 2
378 blusunrize.immersiveengineering.client.nei.NEISqueezerHandler Immersive Engineering ImmersiveEngineering:metalMultiblock:2 ImmersiveEngineering TRUE 1 71 64 166 5 2
379 blusunrize.immersiveengineering.client.nei.NEIFermenterHandler Immersive Engineering ImmersiveEngineering:metalMultiblock:3 ImmersiveEngineering TRUE 1 71 64 166 5 2
380 blusunrize.immersiveengineering.client.nei.NEIRefineryHandler Immersive Engineering ImmersiveEngineering:metalMultiblock:4 ImmersiveEngineering TRUE 65 166 5 2
381 blusunrize.immersiveengineering.client.nei.NEIBottlingMachineHandler Immersive Engineering minecraft:glass_bottle ImmersiveEngineering TRUE 65 166 5
382 blusunrize.immersiveengineering.client.nei.NEIMetalPressHandler Immersive Engineering ImmersiveEngineering:metalMultiblock:13 ImmersiveEngineering TRUE 65 166 5
383 blusunrize.immersiveengineering.client.nei.NEICrusherHandler Immersive Engineering ImmersiveEngineering:metalMultiblock:5 ImmersiveEngineering TRUE 71 166 5
410 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCraftingMachine Thermal Expansion ThermalExpansion:Frame ThermalExpansion TRUE 65 166 5
411 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCraftingSecure Thermal Expansion ThermalExpansion:material:16 ThermalExpansion TRUE 65 166 5
412 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCraftingUpgrade Thermal Expansion ThermalExpansion:Frame:3 ThermalExpansion TRUE 65 166 5
413 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCrucible Thermal Expansion ThermalExpansion:Machine:4 ThermalExpansion TRUE 65 166 5 2
414 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerFurnace Thermal Expansion ThermalExpansion:Machine:0 ThermalExpansion TRUE 65 166 5
415 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerInsolator Thermal Expansion ThermalExpansion:Machine:11 ThermalExpansion TRUE 65 166 5 2
416 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerPulverizer Thermal Expansion ThermalExpansion:Machine:1 ThermalExpansion TRUE 65 166 5
417 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerSawmill Thermal Expansion ThermalExpansion:Machine:2 ThermalExpansion TRUE 65 166 5
418 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerSmelter Thermal Expansion ThermalExpansion:Machine:3 ThermalExpansion TRUE 65 166 5
419 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerTransposer Thermal Expansion ThermalExpansion:Machine:5 ThermalExpansion TRUE 65 166 5 2
420 mekanism.client.nei.ChemicalCrystallizerRecipeHandler Mekanism Mekanism:MachineBlock2:8 Mekanism TRUE 79 4
421 mekanism.client.nei.ChemicalDissolutionChamberRecipeHandler Mekanism Mekanism:MachineBlock2:6 Mekanism TRUE 79 4
422 mekanism.client.nei.ChemicalInfuserRecipeHandler Mekanism Mekanism:MachineBlock2:2 Mekanism TRUE 80 4
437 mekanism.client.nei.SolarNeutronRecipeHandler Mekanism Mekanism:MachineBlock3:1 Mekanism TRUE 70 5
438 mekanism.client.nei.ThermalEvaporationRecipeHandler Mekanism Mekanism:BasicBlock:14 Mekanism TRUE 62 5
439 exnihilo.compatibility.nei.RecipeHandlerHammer Ex Nihilo exnihilo:hammer_iron exnihilo TRUE 58 5
440 exnihilo.compatibility.nei.RecipeHandlerSieve Ex Nihilo exnihilo:sifting_table exnihilo TRUE 130 2 1
441 gregtech.Alloy GregTech-Addon gregtech_addon:machine:56 gregtech_addon TRUE 15 145 166 2
442 gregtech.Assembler GregTech-Addon gregtech_addon:machine:60 gregtech_addon TRUE 15 145 166 2
443 gregtech.Bender GregTech-Addon gregtech_addon:machine:59 gregtech_addon TRUE 15 145 166 2
499 nc.crafting.nei.ElectrolyserRecipeHandler NuclearCraft NuclearCraft:electrolyserIdle NuclearCraft TRUE 65 4
500 nc.crafting.nei.CrusherRecipeHandler NuclearCraft NuclearCraft:crusherIdle NuclearCraft TRUE 65 4
501 nc.crafting.nei.ElectricCrusherRecipeHandler NuclearCraft NuclearCraft:electricCrusherIdle NuclearCraft TRUE 65 4
ganymedes01.etfuturum.NEI_EtFuturum_Config$NEI_Recipes_Smoker EtFuturum Requiem etfuturum:lit_smoker etfuturum TRUE 65 166 5
ganymedes01.etfuturum.NEI_EtFuturum_Config$NEI_Recipes_BlastFurnace EtFuturum Requiem etfuturum:lit_blast_furnace etfuturum TRUE 65 166 5
502 connor135246.campfirebackport.client.compat.nei.NEICampfireRecipeHandler Campfire Backport campfirebackport:campfire campfirebackport TRUE 65 166 5
503 connor135246.campfirebackport.client.compat.nei.NEICampfireStateChangerHandler Campfire Backport campfirebackport:campfire_base campfirebackport TRUE 65 166 5
504 net.blay09.mods.excompressum.compat.nei.RecipeHandlerHeavySieve Ex Compressum excompressum:heavySieve excompressum TRUE 130 166 5
@@ -44,12 +44,16 @@ nei.inventory.magnet.enable=Enable magnet mode
nei.inventory.magnet.1=Turn magnet mode on
nei.inventory.magnet.0=Turn magnet mode off
nei.inventory.dawn.enable=Enable dawn-noon
nei.inventory.dawn.disable=Right-click: Disable dawn-noon phase
nei.inventory.dawn.set=Set time to dawn
nei.inventory.noon.enable=Enable noon-dusk
nei.inventory.noon.disable=Right-click: Disable noon-dusk phase
nei.inventory.noon.set=Set time to noon
nei.inventory.dusk.enable=Enable dusk-midnight
nei.inventory.dusk.disable=Right-click: Disable dusk-midnight phase
nei.inventory.dusk.set=Set time to dusk
nei.inventory.midnight.enable=Enable midnight-dawn
nei.inventory.midnight.disable=Right-click: Disable midnight-dawn phase
nei.inventory.midnight.set=Set time to midnight
nei.inventory.heal=Heal the player
nei.inventory.current.gamemode.0=Current gamemode: survival
@@ -148,6 +152,9 @@ nei.options.inventory.saveCurrentRecipeInBookmarksEnabled.false=Disabled
nei.options.inventory.useNBTInBookmarks=Use NBT in Bookmarks
nei.options.inventory.useNBTInBookmarks.true=Yes
nei.options.inventory.useNBTInBookmarks.false=No
nei.options.inventory.recipeTooltipsEnabled=Show recipe tooltips in Bookmarks
nei.options.inventory.recipeTooltipsEnabled.true=Yes
nei.options.inventory.recipeTooltipsEnabled.false=No
nei.options.inventory.bookmarksAnimationEnabled=REI Style Animation in Bookmarks
nei.options.inventory.bookmarksAnimationEnabled.true=Yes
nei.options.inventory.bookmarksAnimationEnabled.false=No
@@ -338,4 +345,4 @@ nei.presets.whitelist.tooltip=Whitelist
nei.presets.textfield.tooltip.1=Enter - save
nei.presets.textfield.tooltip.2=Escape - cancel
nei.presets.label.tooltip=Double click to edit
nei.presets.label.selected=%s Presets
nei.presets.label.selected=%s Presets