mirror of
https://github.com/GTNewHorizons/NotEnoughItems.git
synced 2026-10-26 22:33:52 +00:00
Compare commits
45
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e3100df69 | ||
|
|
aa9da2e0a0 | ||
|
|
dbf93128a4 | ||
|
|
e9a3a494d5 | ||
|
|
ebe83f970f | ||
|
|
ad9beb7f90 | ||
|
|
68bdb51c6b | ||
|
|
e4e1964dec | ||
|
|
560618024f | ||
|
|
e2a2d2a9df | ||
|
|
7163630cb1 | ||
|
|
ab168ad6ba | ||
|
|
e13e3483f0 | ||
|
|
de26547b64 | ||
|
|
c49f8808fd | ||
|
|
1c6cc8b693 | ||
|
|
43ae1b613a | ||
|
|
402c4325a6 | ||
|
|
550e85c456 | ||
|
|
1673079cbb | ||
|
|
e6174c446a | ||
|
|
869b4571b0 | ||
|
|
35f5400ecb | ||
|
|
1e2801c891 | ||
|
|
1b3b495fec | ||
|
|
2844ea35bc | ||
|
|
c020ecbf1f | ||
|
|
a105a60a1a | ||
|
|
3a4a6734dc | ||
|
|
11f9194de9 | ||
|
|
a685efb3b7 | ||
|
|
9f3697bb67 | ||
|
|
18abb880f8 | ||
|
|
5868187410 | ||
|
|
f84c4ef2bd | ||
|
|
a54c414595 | ||
|
|
3c472a02cb | ||
|
|
382278bebb | ||
|
|
55c9811a2b | ||
|
|
0ec87a8b9e | ||
|
|
939845a9ed | ||
|
|
c9db437dd1 | ||
|
|
b1f20104a6 | ||
|
|
ab8d5f275f | ||
|
|
9e87f2b158 |
No files matched your search
@@ -33,12 +33,10 @@ body:
|
||||
description: What Java version are you using? It's worth mentioning that if you play on Java9+ you should try update to latest minor release (e.g. prefer Java 17.0.6 over 17.0.2) of that version.
|
||||
options:
|
||||
- Java 8
|
||||
- Java 9
|
||||
- Java 11
|
||||
- Java 17
|
||||
- Java 19
|
||||
- Java 20
|
||||
- Java 21
|
||||
- java 25
|
||||
- java 26
|
||||
- Other (Please Specify)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
+3
-1
@@ -28,6 +28,7 @@ whitelist.json
|
||||
*.iws
|
||||
src/main/resources/mixins.*([!.]).json
|
||||
*.bat
|
||||
*.sh
|
||||
*.DS_Store
|
||||
!gradlew.bat
|
||||
.factorypath
|
||||
@@ -35,4 +36,5 @@ addon.local.gradle
|
||||
addon.local.gradle.kts
|
||||
addon.late.local.gradle
|
||||
addon.late.local.gradle.kts
|
||||
layout.json
|
||||
layout.json
|
||||
|
||||
+10
-5
@@ -5,8 +5,8 @@ configurations.create('gtnhlibEmbed') {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api('com.github.GTNewHorizons:CodeChickenCore:1.4.19:dev')
|
||||
devOnlyNonPublishable('com.github.GTNewHorizons:GTNHLib:0.11.48:dev')
|
||||
api('com.github.GTNewHorizons:CodeChickenCore:1.4.22:dev')
|
||||
devOnlyNonPublishable('com.github.GTNewHorizons:GTNHLib:0.11.54:dev')
|
||||
|
||||
shadowImplementation('org.apache.commons:commons-csv:1.10.0')
|
||||
|
||||
@@ -23,13 +23,18 @@ dependencies {
|
||||
testRuntimeOnly('org.junit.platform:junit-platform-launcher')
|
||||
testRuntimeOnly("org.lwjgl.lwjgl:lwjgl:2.9.3");
|
||||
|
||||
compileOnly("com.github.GTNewHorizons:GTNHLib:0.11.48") { transitive = false }
|
||||
gtnhlibEmbed("com.github.GTNewHorizons:GTNHLib:0.11.48") { transitive = false }
|
||||
compileOnly("com.github.GTNewHorizons:GTNHLib:0.11.54") { transitive = false }
|
||||
gtnhlibEmbed("com.github.GTNewHorizons:GTNHLib:0.11.54") { transitive = false }
|
||||
}
|
||||
|
||||
def embedArchiveOperations = gtnhGradle.archiveOperations
|
||||
def gtnhlibEmbedContents = configurations.gtnhlibEmbed.elements.map { files ->
|
||||
files.collect { embedArchiveOperations.zipTree(it.asFile) }
|
||||
}
|
||||
|
||||
[tasks.jar, tasks.shadowJar].each {
|
||||
it.configure {
|
||||
from({ project.configurations.getByName('gtnhlibEmbed').collect { zipTree(it) } }) {
|
||||
from(gtnhlibEmbedContents) {
|
||||
include 'com/gtnewhorizon/gtnhlib/color/ColorResource.class'
|
||||
include 'com/gtnewhorizon/gtnhlib/color/ColorResource$*.class'
|
||||
}
|
||||
|
||||
@@ -186,6 +186,11 @@ modrinthRelations = required-project\:codechickencore-unofficial
|
||||
# Leave this empty if you don't want to publish on CurseForge.
|
||||
curseForgeProjectId = 358228
|
||||
|
||||
# Comma-separated supported CurseForge environments: client, server (case-insensitive).
|
||||
# Use client or server for mods that only support one environment. Defaults to client,server.
|
||||
# These tags describe where the mod can run, not whether installation is required on both sides.
|
||||
curseForgeEnvironments = client,server
|
||||
|
||||
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
|
||||
# Syntax: type1:name1;type2:name2;...
|
||||
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+3
-1
@@ -1,7 +1,9 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip
|
||||
networkTimeout=10000
|
||||
retries=0
|
||||
retryBackOffMs=500
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
# gradlew start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
@@ -29,7 +29,7 @@
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
# ksh gradlew
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
@@ -57,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
|
||||
Vendored
+12
-23
@@ -19,12 +19,12 @@
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem gradlew startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
@rem Set local scope for the variables, and ensure extensions are enabled
|
||||
setlocal EnableExtensions
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@@ -51,7 +51,7 @@ echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
"%COMSPEC%" /c exit 1
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
@@ -65,29 +65,18 @@ echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
"%COMSPEC%" /c exit 1
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
@rem Execute gradlew
|
||||
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
|
||||
@rem which allows us to clear the local environment before executing the java command
|
||||
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
:exitWithErrorLevel
|
||||
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
|
||||
"%COMSPEC%" /c exit %ERRORLEVEL%
|
||||
+1
-1
@@ -17,7 +17,7 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.29'
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.34'
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,8 +7,10 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiTextField;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.client.settings.GameSettings;
|
||||
import net.minecraft.util.ChatAllowedCharacters;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
@@ -30,6 +32,8 @@ public class AutoFocusWidget implements IContainerInputHandler {
|
||||
|
||||
protected boolean autofocus = false;
|
||||
protected Point mouse;
|
||||
protected Point pendingMouse;
|
||||
protected GuiTextField textInputHolder;
|
||||
|
||||
public AutoFocusWidget() {
|
||||
GuiContainerManager.addInputHandler(this);
|
||||
@@ -38,32 +42,83 @@ public class AutoFocusWidget implements IContainerInputHandler {
|
||||
public void load(GuiContainer gui) {
|
||||
this.autofocus = LayoutManager.searchField.isVisible() && NEIClientConfig.searchWidgetAutofocus() != 0
|
||||
&& isAllowedGuiAutoSearchFocus(gui);
|
||||
this.mouse = getMousePosition();
|
||||
this.mouse = null;
|
||||
this.pendingMouse = null;
|
||||
|
||||
if (this.autofocus) {
|
||||
beginTextInput();
|
||||
}
|
||||
}
|
||||
|
||||
protected void beginTextInput() {
|
||||
if (this.textInputHolder == null) {
|
||||
this.textInputHolder = new GuiTextField(Minecraft.getMinecraft().fontRenderer, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
this.textInputHolder.setFocused(true);
|
||||
}
|
||||
|
||||
protected void endTextInput() {
|
||||
if (this.textInputHolder != null) {
|
||||
this.textInputHolder.setFocused(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void guiTick() {
|
||||
if (!this.autofocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Point current = getMousePosition();
|
||||
|
||||
if (this.mouse == null) {
|
||||
if (current.equals(this.pendingMouse)) {
|
||||
this.mouse = current;
|
||||
}
|
||||
|
||||
this.pendingMouse = current;
|
||||
} else if (!this.mouse.equals(current)) {
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
|
||||
protected void cancel() {
|
||||
if (this.autofocus) {
|
||||
this.autofocus = false;
|
||||
endTextInput();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyTyped(GuiContainer gui, char keyChar, int keyCode) {
|
||||
|
||||
if (this.autofocus) {
|
||||
this.autofocus = false;
|
||||
|
||||
if (!this.mouse.equals(getMousePosition())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.searchWidgetAutofocus() == 2
|
||||
&& GameSettings.isKeyDown(Minecraft.getMinecraft().gameSettings.keyBindInventory)) {
|
||||
cancel();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (keyCode == Keyboard.KEY_RETURN || keyCode == Keyboard.KEY_NUMPADENTER
|
||||
|| keyCode == Keyboard.KEY_ESCAPE) {
|
||||
cancel();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ChatAllowedCharacters.isAllowedCharacter(keyChar)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.autofocus = false;
|
||||
|
||||
LayoutManager.searchField.setFocus(true);
|
||||
endTextInput();
|
||||
|
||||
final String oldText = LayoutManager.searchField.text();
|
||||
LayoutManager.searchField.handleKeyPress(keyCode, keyChar);
|
||||
return true;
|
||||
|
||||
return !LayoutManager.searchField.text().equals(oldText);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -76,13 +131,13 @@ public class AutoFocusWidget implements IContainerInputHandler {
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
|
||||
this.autofocus = false;
|
||||
cancel();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
|
||||
this.autofocus = false;
|
||||
cancel();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -91,22 +146,22 @@ public class AutoFocusWidget implements IContainerInputHandler {
|
||||
|
||||
@Override
|
||||
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
|
||||
this.autofocus = false;
|
||||
cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseDragged(GuiContainer gui, int mousex, int mousey, int button, long heldTime) {
|
||||
this.autofocus = false;
|
||||
cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
|
||||
this.autofocus = false;
|
||||
cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) {
|
||||
this.autofocus = false;
|
||||
cancel();
|
||||
}
|
||||
|
||||
protected boolean isAllowedGuiAutoSearchFocus(GuiContainer gui) {
|
||||
|
||||
@@ -572,9 +572,10 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
|
||||
|
||||
return;
|
||||
} else if (this.sortableGroup != null) {
|
||||
final int overRowIndex = grid.getRowIndex(mousey);
|
||||
final int overRowIndex = Math.min(grid.getRowIndex(mousey), grid.getRows() - 1);
|
||||
|
||||
if (overRowIndex >= 0 && this.sortableGroup.groupId != this.grid.getRowGroupId(overRowIndex)) {
|
||||
if (overRowIndex >= 0 && !isOverNamespaceControls(mousex, mousey)
|
||||
&& !this.sortableGroup.matches(this.grid, this.grid.getRowGroupId(overRowIndex))) {
|
||||
this.grid.moveGroup(this.sortableGroup, overRowIndex);
|
||||
}
|
||||
|
||||
@@ -1022,14 +1023,18 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
|
||||
this.mouseDownSlot = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMouseWheel(int shift, int mousex, int mousey) {
|
||||
|
||||
if ((!inEditingState() || this.sortableGroup != null) && new Rectangle4i(
|
||||
private boolean isOverNamespaceControls(int mousex, int mousey) {
|
||||
return new Rectangle4i(
|
||||
namespacePrev.x,
|
||||
namespacePrev.y,
|
||||
namespaceNext.x + namespaceNext.w - namespacePrev.x,
|
||||
namespacePrev.h).contains(mousex, mousey)) {
|
||||
namespacePrev.h).contains(mousex, mousey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMouseWheel(int shift, int mousex, int mousey) {
|
||||
|
||||
if ((!inEditingState() || this.sortableGroup != null) && isOverNamespaceControls(mousex, mousey)) {
|
||||
|
||||
if (shift > 0) {
|
||||
this.storage.prevNamespace();
|
||||
@@ -1105,10 +1110,10 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
|
||||
}
|
||||
|
||||
if (super.onMouseWheel(shift, mousex, mousey)) {
|
||||
final int overRowIndex = grid.getRowIndex(mousey);
|
||||
final int overRowIndex = Math.min(grid.getRowIndex(mousey), grid.getRows() - 1);
|
||||
|
||||
if (this.sortableGroup != null && overRowIndex >= 0
|
||||
&& this.sortableGroup.groupId != this.grid.getRowGroupId(overRowIndex)) {
|
||||
&& !this.sortableGroup.matches(this.grid, this.grid.getRowGroupId(overRowIndex))) {
|
||||
this.grid.moveGroup(this.sortableGroup, overRowIndex);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTBase.NBTPrimitive;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.StatCollector;
|
||||
@@ -227,17 +228,17 @@ public class CollapsibleItems {
|
||||
|
||||
if (NEIClientConfig.world.nbt.hasKey(STATE_KEY)) {
|
||||
NBTTagCompound states = NEIClientConfig.world.nbt.getCompoundTag(STATE_KEY);
|
||||
@SuppressWarnings("unchecked")
|
||||
final Map<String, NBTPrimitive> list = (Map<String, NBTPrimitive>) states.tagMap;
|
||||
final Map<String, NBTBase> list = states.tagMap;
|
||||
final Map<String, GroupItem> mapping = new HashMap<>();
|
||||
|
||||
for (GroupItem group : CollapsibleItems.groups) {
|
||||
mapping.put(group.guid, group);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, NBTPrimitive> nbtEntry : list.entrySet()) {
|
||||
for (Map.Entry<String, NBTBase> nbtEntry : list.entrySet()) {
|
||||
if (mapping.containsKey(nbtEntry.getKey())) {
|
||||
mapping.get(nbtEntry.getKey()).expanded = nbtEntry.getValue().func_150290_f() == 1;
|
||||
mapping.get(nbtEntry.getKey()).expanded = ((NBTPrimitive) nbtEntry.getValue()).func_150290_f()
|
||||
== 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.lib.gui.GuiDraw.ITooltipLineHandler;
|
||||
|
||||
public abstract class CompositeTooltipLineHandler implements ITooltipLineHandler {
|
||||
|
||||
protected static final int SCREEN_MARGIN = 8 * 2 + 10;
|
||||
protected static final int RESERVED_HEIGHT = 40;
|
||||
|
||||
protected final List<ItemsTooltipLineHandler> lines = new ArrayList<>();
|
||||
protected final Dimension size = new Dimension();
|
||||
|
||||
protected boolean created = false;
|
||||
protected int screenHeight = 0;
|
||||
|
||||
protected abstract void createLines();
|
||||
|
||||
protected boolean needsUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getSize() {
|
||||
ensureCreated();
|
||||
return this.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int x, int y) {
|
||||
if (this.size.height == 0) return;
|
||||
|
||||
for (ItemsTooltipLineHandler line : this.lines) {
|
||||
line.draw(x, y);
|
||||
y += line.getSize().height;
|
||||
}
|
||||
}
|
||||
|
||||
protected void ensureCreated() {
|
||||
boolean update = needsUpdate();
|
||||
update = this.screenHeight != (this.screenHeight = GuiDraw.displaySize().height) || update;
|
||||
|
||||
if (this.created && !update) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.created = true;
|
||||
this.lines.clear();
|
||||
this.size.setSize(0, 0);
|
||||
|
||||
createLines();
|
||||
fitToScreen();
|
||||
|
||||
for (ItemsTooltipLineHandler line : this.lines) {
|
||||
this.size.width = Math.max(this.size.width, line.getSize().width);
|
||||
this.size.height += line.getSize().height;
|
||||
}
|
||||
}
|
||||
|
||||
protected void fitToScreen() {
|
||||
if (this.lines.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<ItemsTooltipLineHandler> ordered = new ArrayList<>(this.lines);
|
||||
ordered.sort(Comparator.comparingInt(ItemsTooltipLineHandler::getRows));
|
||||
|
||||
int budget = availableHeight() / ItemsTooltipLineHandler.SLOT_SIZE;
|
||||
int rest = ordered.size();
|
||||
|
||||
for (ItemsTooltipLineHandler line : ordered) {
|
||||
final int fair = Math.max(1, budget / rest);
|
||||
|
||||
if (line.getRows() > fair) {
|
||||
line.setMaxRows(fair);
|
||||
}
|
||||
|
||||
budget -= line.getRows();
|
||||
rest--;
|
||||
}
|
||||
}
|
||||
|
||||
protected int availableHeight() {
|
||||
return GuiDraw.displaySize().height - SCREEN_MARGIN
|
||||
- RESERVED_HEIGHT
|
||||
- this.lines.size() * ItemsTooltipLineHandler.headerHeight();
|
||||
}
|
||||
|
||||
protected static int maxLineRows() {
|
||||
final int height = GuiDraw.displaySize().height - SCREEN_MARGIN
|
||||
- RESERVED_HEIGHT
|
||||
- ItemsTooltipLineHandler.headerHeight();
|
||||
return Math.max(1, height / ItemsTooltipLineHandler.SLOT_SIZE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -16,6 +17,7 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
@@ -314,6 +316,10 @@ public class FavoriteRecipes {
|
||||
load();
|
||||
}
|
||||
|
||||
public static boolean hasManual() {
|
||||
return manualFavorites.size() > 0;
|
||||
}
|
||||
|
||||
public static boolean containsManual(ItemStack stack) {
|
||||
return getManualFavorite(stack) != null;
|
||||
}
|
||||
@@ -322,6 +328,21 @@ public class FavoriteRecipes {
|
||||
return getFavorite(stack) != null;
|
||||
}
|
||||
|
||||
public static void toggleFavoriteItem(ItemStack stack) {
|
||||
if (stack == null) return;
|
||||
|
||||
if (containsManual(stack)) {
|
||||
setFavorite(stack, null);
|
||||
} else {
|
||||
setFavorite(
|
||||
stack,
|
||||
RecipeId.of(
|
||||
stack,
|
||||
FavoriteRecipes.FAVORITE_ITEM,
|
||||
Arrays.asList(new ItemStack(Blocks.fire, 1), stack)));
|
||||
}
|
||||
}
|
||||
|
||||
public static void setFavorite(ItemStack stack, RecipeId recipeId) {
|
||||
if (stack == null) return;
|
||||
|
||||
|
||||
@@ -7,40 +7,36 @@ import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.nei.drawable.DrawableBuilder;
|
||||
import codechicken.nei.drawable.DrawableResource;
|
||||
|
||||
public class GuiNEIButton extends GuiButton {
|
||||
|
||||
protected static final ResourceLocation guiTex = new ResourceLocation("textures/gui/widgets.png");
|
||||
private static final DrawableResource[] BACKGROUNDS = new DrawableResource[3];
|
||||
|
||||
static {
|
||||
for (int state = 0; state < BACKGROUNDS.length; state++) {
|
||||
BACKGROUNDS[state] = new DrawableBuilder(guiTex, 0, 46 + state * 20, 200, 20).setSlices(2, 2, 2, 2).build();
|
||||
}
|
||||
}
|
||||
|
||||
public GuiNEIButton(int i, int j, int k, int l, int i1, String s) {
|
||||
super(i, j, k, l, i1, s);
|
||||
}
|
||||
|
||||
protected DrawableResource getBackground(int mouseX, int mouseY, boolean mouseOver) {
|
||||
return BACKGROUNDS[getHoverState(mouseOver)];
|
||||
}
|
||||
|
||||
public void drawButton(Minecraft minecraft, int x, int y) {
|
||||
if (!visible) return;
|
||||
|
||||
minecraft.renderEngine.bindTexture(guiTex);
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
boolean mouseOver = x >= xPosition && y >= yPosition && x < xPosition + width && y < yPosition + height;
|
||||
int k = getHoverState(mouseOver);
|
||||
drawTexturedModalRect(xPosition, yPosition, 0, 46 + k * 20, width / 2, height / 2); // top left
|
||||
drawTexturedModalRect(xPosition + width / 2, yPosition, 200 - width / 2, 46 + k * 20, width / 2, height / 2); // top
|
||||
// right
|
||||
drawTexturedModalRect(
|
||||
xPosition,
|
||||
yPosition + height / 2,
|
||||
0,
|
||||
46 + k * 20 + 20 - height / 2,
|
||||
width / 2,
|
||||
height / 2); // bottom left
|
||||
drawTexturedModalRect(
|
||||
xPosition + width / 2,
|
||||
yPosition + height / 2,
|
||||
200 - width / 2,
|
||||
46 + k * 20 + 20 - height / 2,
|
||||
width / 2,
|
||||
height / 2); // bottom right
|
||||
mouseDragged(minecraft, x, y);
|
||||
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
getBackground(x, y, mouseOver).draw(xPosition, yPosition, width, height);
|
||||
mouseDragged(minecraft, x, y);
|
||||
drawContent(minecraft, x, y, mouseOver);
|
||||
}
|
||||
|
||||
@@ -55,7 +51,7 @@ public class GuiNEIButton extends GuiButton {
|
||||
return ColorUtils.buttonLabelNormal.getColor();
|
||||
}
|
||||
|
||||
protected void drawContent(Minecraft minecraft, int y, int x, boolean mouseOver) {
|
||||
protected void drawContent(Minecraft minecraft, int x, int y, boolean mouseOver) {
|
||||
FontRenderer fontrenderer = minecraft.fontRenderer;
|
||||
int color = getTextColour(mouseOver);
|
||||
|
||||
|
||||
@@ -6,11 +6,14 @@ import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.fluids.FluidContainerRegistry;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
@@ -21,7 +24,6 @@ import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.ICraftingHandler;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
import codechicken.nei.recipe.Recipe;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.RecipeInfo;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
@@ -82,6 +84,42 @@ public class ItemCraftablesPanel
|
||||
|
||||
}
|
||||
|
||||
private static class CraftablesSnapshot {
|
||||
|
||||
final GuiContainer guiContainer;
|
||||
final ItemStackAmount inventory;
|
||||
final boolean showOnlyFavorites;
|
||||
final int maxCandidates;
|
||||
|
||||
CraftablesSnapshot(GuiContainer guiContainer, ItemStackAmount inventory, boolean showOnlyFavorites,
|
||||
int maxCandidates) {
|
||||
this.guiContainer = guiContainer;
|
||||
this.inventory = inventory;
|
||||
this.showOnlyFavorites = showOnlyFavorites;
|
||||
this.maxCandidates = maxCandidates;
|
||||
}
|
||||
}
|
||||
|
||||
private static class RecipeCandidate {
|
||||
|
||||
final IRecipeHandler handler;
|
||||
final int recipeIndex;
|
||||
final List<PositionedStack> ingredientStacks;
|
||||
final ItemStack sortKeyItem;
|
||||
|
||||
RecipeCandidate(IRecipeHandler handler, int recipeIndex, List<PositionedStack> ingredientStacks,
|
||||
ItemStack sortKeyItem) {
|
||||
this.handler = handler;
|
||||
this.recipeIndex = recipeIndex;
|
||||
this.ingredientStacks = ingredientStacks;
|
||||
this.sortKeyItem = sortKeyItem;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Comparator<ItemStack> ITEM_SORT_COMPARATOR = Comparator
|
||||
.comparing(FavoriteRecipes::containsManual).thenComparing(FavoriteRecipes::contains).reversed()
|
||||
.thenComparing(ItemSorter.instance);
|
||||
|
||||
public static List<String> guiBlacklist = new ArrayList<>();
|
||||
private final int MIN_DELAY = 600;
|
||||
|
||||
@@ -93,6 +131,16 @@ public class ItemCraftablesPanel
|
||||
private long lastPlayerInventorySync = 0;
|
||||
private int lastFavoritesCount = 0;
|
||||
|
||||
private volatile CraftablesSnapshot pendingSnapshot;
|
||||
private final AtomicReference<Map<ItemStack, RecipeId>> pendingResult = new AtomicReference<>();
|
||||
private final RestartableTask task = new RestartableTask("NEI Craftables Panel") {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
pendingResult.set(generateCraftables(ItemCraftablesPanel.this.pendingSnapshot));
|
||||
}
|
||||
};
|
||||
|
||||
public ItemCraftablesPanel() {
|
||||
this.grid = new ItemsGrid<>() {
|
||||
|
||||
@@ -114,12 +162,7 @@ public class ItemCraftablesPanel
|
||||
|
||||
if (!ItemCraftablesPanel.this.availableRecipes.isEmpty()) {
|
||||
final List<Map.Entry<ItemStack, RecipeId>> entries = ItemCraftablesPanel.this.availableRecipes
|
||||
.entrySet().stream()
|
||||
.sorted(
|
||||
Map.Entry.comparingByKey(
|
||||
Comparator.comparing(FavoriteRecipes::containsManual)
|
||||
.thenComparing(FavoriteRecipes::contains).reversed()
|
||||
.thenComparing(ItemSorter.instance)))
|
||||
.entrySet().stream().sorted(Map.Entry.comparingByKey(ITEM_SORT_COMPARATOR))
|
||||
.limit(maxSlotIndex).collect(Collectors.toList());
|
||||
int slotIndex = 0;
|
||||
int itemIndex = 0;
|
||||
@@ -195,10 +238,20 @@ public class ItemCraftablesPanel
|
||||
|
||||
public void update() {
|
||||
this.splittingLineColor = NEIClientConfig.getSetting("inventory.craftables.color").getHexValue();
|
||||
applyPendingResult();
|
||||
updateCraftables();
|
||||
super.update();
|
||||
}
|
||||
|
||||
private void applyPendingResult() {
|
||||
final Map<ItemStack, RecipeId> result = this.pendingResult.getAndSet(null);
|
||||
|
||||
if (result != null && NEIClientConfig.showCraftablesPanelWidget()) {
|
||||
this.availableRecipes = result;
|
||||
this.grid.onGridChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCraftables() {
|
||||
|
||||
if (!NEIClientConfig.showCraftablesPanelWidget()) {
|
||||
@@ -219,8 +272,14 @@ public class ItemCraftablesPanel
|
||||
this.lastPlayerInventory = inv;
|
||||
this.lastGuiContainer = firstGui;
|
||||
this.lastFavoritesCount = FavoriteRecipes.size();
|
||||
this.availableRecipes = generateCraftables(firstGui);
|
||||
this.grid.onGridChanged();
|
||||
final int maxRows = NEIClientConfig.getIntSetting("inventory.craftables.useRows") + 2;
|
||||
final int maxCandidates = Math.max(this.grid.columns, 1) * maxRows;
|
||||
this.pendingSnapshot = new CraftablesSnapshot(
|
||||
firstGui,
|
||||
inv,
|
||||
showOnlyFavorites,
|
||||
maxCandidates);
|
||||
this.task.restart();
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -244,17 +303,28 @@ public class ItemCraftablesPanel
|
||||
return (firstGui instanceof GuiRecipe<?>gui) ? gui.firstGui : firstGui;
|
||||
}
|
||||
|
||||
private Map<ItemStack, RecipeId> generateCraftables(GuiContainer firstGui) {
|
||||
final List<IRecipeHandler> availableHandlers = getAvailableHandlers(firstGui);
|
||||
private Map<ItemStack, RecipeId> generateCraftables(CraftablesSnapshot snapshot) {
|
||||
final List<IRecipeHandler> availableHandlers = getAvailableHandlers(snapshot.guiContainer);
|
||||
final Map<ItemStack, RecipeId> availableRecipes = new HashMap<>();
|
||||
|
||||
if (!availableHandlers.isEmpty()) {
|
||||
final List<ItemStack> invStacks = ItemCraftablesPanel.this.lastPlayerInventory.values();
|
||||
final Map<Item, List<ItemStack>> invByItem = indexInventoryByItem(snapshot.inventory.values());
|
||||
|
||||
for (IRecipeHandler handler : availableHandlers) {
|
||||
availableRecipes.putAll(filterHandlerRecipes(handler, firstGui, invStacks));
|
||||
if (snapshot.showOnlyFavorites) {
|
||||
for (IRecipeHandler handler : availableHandlers) {
|
||||
availableRecipes.putAll(filterHandlerRecipes(handler, invByItem, true));
|
||||
}
|
||||
} else {
|
||||
final List<RecipeCandidate> candidates = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
for (IRecipeHandler handler : availableHandlers) {
|
||||
collectHandlerCandidates(handler, invByItem, candidates);
|
||||
}
|
||||
|
||||
candidates.sort(Comparator.comparing(c -> c.sortKeyItem, ITEM_SORT_COMPARATOR));
|
||||
candidates.subList(0, Math.min(candidates.size(), snapshot.maxCandidates)).parallelStream()
|
||||
.forEach(candidate -> buildCandidate(candidate, availableRecipes));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return availableRecipes;
|
||||
@@ -270,19 +340,126 @@ public class ItemCraftablesPanel
|
||||
return availableHandlers;
|
||||
}
|
||||
|
||||
private Map<ItemStack, RecipeId> filterHandlerRecipes(IRecipeHandler handler, GuiContainer firstGui,
|
||||
List<ItemStack> invStacks) {
|
||||
private static Map<Item, List<ItemStack>> indexInventoryByItem(List<ItemStack> invStacks) {
|
||||
final Map<Item, List<ItemStack>> index = new HashMap<>();
|
||||
|
||||
for (ItemStack stack : invStacks) {
|
||||
index.computeIfAbsent(stack.getItem(), i -> new ArrayList<>()).add(stack);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
private void collectHandlerCandidates(IRecipeHandler handler, Map<Item, List<ItemStack>> invByItem,
|
||||
List<RecipeCandidate> candidates) {
|
||||
IntStream.range(0, handler.numRecipes()).parallel().forEach(recipeIndex -> {
|
||||
final List<PositionedStack> ingredientStacks = handler.getIngredientStacks(recipeIndex);
|
||||
|
||||
if (existsIngredients(ingredientStacks, invByItem)) {
|
||||
final ItemStack sortKeyItem = getCheapResultItem(handler, recipeIndex);
|
||||
|
||||
if (sortKeyItem != null) {
|
||||
candidates.add(new RecipeCandidate(handler, recipeIndex, ingredientStacks, sortKeyItem));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void buildCandidate(RecipeCandidate candidate, Map<ItemStack, RecipeId> availableRecipes) {
|
||||
final ItemStack result = getCheapResult(candidate.handler, candidate.recipeIndex);
|
||||
|
||||
if (result != null) {
|
||||
final RecipeId recipeId = RecipeId.of(candidate.handler, candidate.recipeIndex, candidate.ingredientStacks);
|
||||
|
||||
synchronized (availableRecipes) {
|
||||
availableRecipes.put(result, recipeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ItemStack getCheapResultItem(IRecipeHandler handler, int recipeIndex) {
|
||||
final PositionedStack resultStack = handler.getResultStack(recipeIndex);
|
||||
|
||||
if (resultStack != null) {
|
||||
return resultStack.item;
|
||||
}
|
||||
|
||||
final List<PositionedStack> otherStacks = handler.getOtherStacks(recipeIndex);
|
||||
|
||||
for (PositionedStack otherStack : otherStacks) {
|
||||
if (!FluidContainerRegistry.isContainer(otherStack.items[0])
|
||||
|| StackInfo.getFluid(otherStack.items[0]) != null) {
|
||||
return otherStack.item;
|
||||
}
|
||||
}
|
||||
|
||||
return otherStacks.isEmpty() ? null : otherStacks.get(0).item;
|
||||
}
|
||||
|
||||
private static ItemStack getCheapResult(IRecipeHandler handler, int recipeIndex) {
|
||||
final PositionedStack resultStack = handler.getResultStack(recipeIndex);
|
||||
final List<PositionedStack> results = resultStack != null ? Collections.singletonList(resultStack)
|
||||
: handler.getOtherStacks(recipeIndex);
|
||||
|
||||
if (results.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ItemStack stack = null;
|
||||
|
||||
if (results.size() > 1) {
|
||||
for (PositionedStack result : results) {
|
||||
if (!FluidContainerRegistry.isContainer(result.item) || StackInfo.getFluid(result.item) != null) {
|
||||
stack = result.item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stack == null) {
|
||||
stack = results.get(0).item;
|
||||
}
|
||||
|
||||
int stackSize = 0;
|
||||
|
||||
for (PositionedStack result : results) {
|
||||
if (containsSameType(result, stack)) {
|
||||
stackSize += StackInfo.getAmount(result.item);
|
||||
}
|
||||
}
|
||||
|
||||
return StackInfo.withAmount(stack, stackSize);
|
||||
}
|
||||
|
||||
private static boolean containsSameType(PositionedStack pStack, ItemStack stack) {
|
||||
final ItemStack normalized = StackInfo.withAmount(stack, 0);
|
||||
|
||||
for (ItemStack permutation : pStack.items) {
|
||||
if (NEIServerUtils.areStacksSameTypeWithNBT(StackInfo.withAmount(permutation, 0), normalized)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Map<ItemStack, RecipeId> filterHandlerRecipes(IRecipeHandler handler, Map<Item, List<ItemStack>> invByItem,
|
||||
boolean showOnlyFavorites) {
|
||||
final Map<ItemStack, RecipeId> availableRecipes = new HashMap<>();
|
||||
final boolean showOnlyFavorites = NEIClientConfig.getBooleanSetting("inventory.craftables.favoritesOnly");
|
||||
|
||||
IntStream.range(0, handler.numRecipes()).parallel().forEach(recipeIndex -> {
|
||||
if (existsIngredients(firstGui, handler.getIngredientStacks(recipeIndex), invStacks)) {
|
||||
final Recipe recipe = Recipe.of(handler, recipeIndex);
|
||||
final List<PositionedStack> ingredientStacks = handler.getIngredientStacks(recipeIndex);
|
||||
|
||||
if (!recipe.getResults().isEmpty()
|
||||
&& (!showOnlyFavorites || FavoriteRecipes.getFavorite(recipe.getRecipeId()) != null)) {
|
||||
synchronized (availableRecipes) {
|
||||
availableRecipes.put(recipe.getResult(), recipe.getRecipeId());
|
||||
if (existsIngredients(ingredientStacks, invByItem)) {
|
||||
final ItemStack result = getCheapResult(handler, recipeIndex);
|
||||
|
||||
if (result != null) {
|
||||
final RecipeId recipeId = RecipeId.of(handler, recipeIndex, ingredientStacks);
|
||||
|
||||
if (!showOnlyFavorites || FavoriteRecipes.getFavorite(recipeId) != null) {
|
||||
synchronized (availableRecipes) {
|
||||
availableRecipes.put(result, recipeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -291,14 +468,27 @@ public class ItemCraftablesPanel
|
||||
return availableRecipes;
|
||||
}
|
||||
|
||||
private boolean existsIngredients(GuiContainer firstGui, List<PositionedStack> ingredients,
|
||||
List<ItemStack> invStacks) {
|
||||
private boolean existsIngredients(List<PositionedStack> ingredients, Map<Item, List<ItemStack>> invByItem) {
|
||||
final Map<ItemStack, Integer> usedItems = new HashMap<>();
|
||||
|
||||
for (PositionedStack pStack : ingredients) {
|
||||
final ItemStack used = invStacks.stream().filter(
|
||||
is -> usedItems.getOrDefault(is, is.stackSize) >= pStack.item.stackSize && pStack.contains(is))
|
||||
.findAny().orElse(null);
|
||||
ItemStack used = null;
|
||||
|
||||
for (ItemStack permutation : pStack.items) {
|
||||
final List<ItemStack> candidates = invByItem.get(permutation.getItem());
|
||||
|
||||
if (candidates == null) continue;
|
||||
|
||||
for (ItemStack is : candidates) {
|
||||
if (usedItems.getOrDefault(is, is.stackSize) >= pStack.item.stackSize
|
||||
&& NEIServerUtils.areStacksSameTypeCrafting(permutation, is)) {
|
||||
used = is;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (used != null) break;
|
||||
}
|
||||
|
||||
if (used != null) {
|
||||
usedItems.put(used, usedItems.getOrDefault(used, used.stackSize) - pStack.item.stackSize);
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.util.regex.Pattern;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.StatCollector;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
@@ -103,7 +104,7 @@ public class ItemList {
|
||||
}
|
||||
|
||||
for (String alias : ItemInfo.getAliases(item)) {
|
||||
if (this.pattern.matcher(alias).find()) {
|
||||
if (this.pattern.matcher(StatCollector.translateToLocal(alias)).find()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,13 +75,7 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
|
||||
}
|
||||
|
||||
public static void updateItemList(ArrayList<ItemStack> newItems) {
|
||||
final ItemsPanelGrid grid = ItemPanels.itemPanel.getGrid();
|
||||
|
||||
if (grid.rawItems.size() != newItems.size()) {
|
||||
grid.setPage(0);
|
||||
}
|
||||
|
||||
grid.setItems(newItems);
|
||||
ItemPanels.itemPanel.getGrid().setItems(newItems);
|
||||
ItemPanels.itemPanel.realItems = newItems;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,14 +118,7 @@ public class ItemSorter implements Comparator<ItemStack> {
|
||||
return name1.compareTo(name2);
|
||||
});
|
||||
tag.getTag("inventory.itemsort").setDefaultValue(getSaveString(list));
|
||||
API.addOption(new OptionOpenGui("inventory.itemsort", GuiItemSorter.class) {
|
||||
|
||||
@Override
|
||||
public void useGlobals() {
|
||||
super.useGlobals();
|
||||
list = fromSaveString(activeTag().getValue());
|
||||
}
|
||||
});
|
||||
API.addOption(new OptionOpenGui("inventory.itemsort", GuiItemSorter.class));
|
||||
}
|
||||
|
||||
public static String getSaveString(List<SortEntry> list) {
|
||||
|
||||
@@ -111,8 +111,14 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
|
||||
this.xPosition = (availableAreaWidth - this.scale * SLOT_SIZE) / 2;
|
||||
this.availableAreaWidth = (int) (availableAreaWidth / screenScale);
|
||||
|
||||
if (availableAreaWidth / screenScale >= mouse.x) {
|
||||
this.xPosition += gui.width * screenScale - availableAreaWidth;
|
||||
final float rightSideShift = gui.width * screenScale - availableAreaWidth;
|
||||
final boolean leftSideFree = availableAreaWidth / screenScale < mouse.x;
|
||||
final boolean rightSideFree = mouse.x < gui.width - availableAreaWidth / screenScale;
|
||||
|
||||
final boolean showOnRight = leftSideFree && rightSideFree ? !preferLeftSide() : !leftSideFree;
|
||||
|
||||
if (showOnRight) {
|
||||
this.xPosition += rightSideShift;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -128,6 +134,22 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean preferLeftSide() {
|
||||
switch (NEIClientConfig.getIntSetting("inventory.itemzoom.preferredSide")) {
|
||||
case 1:
|
||||
return true;
|
||||
case 2:
|
||||
return false;
|
||||
}
|
||||
|
||||
final int leftCount = NEIClientConfig.isBookmarkPanelHidden()
|
||||
|| ItemPanels.bookmarkPanel.getGrid().getPerPage() == 0 ? 0 : ItemPanels.bookmarkPanel.getGrid().size();
|
||||
final int rightCount = ItemPanels.itemPanel.getGrid().getPerPage() == 0 ? 0
|
||||
: ItemPanels.itemPanel.getGrid().size();
|
||||
|
||||
return leftCount <= rightCount;
|
||||
}
|
||||
|
||||
private float getPointSize(GuiContainer gui) {
|
||||
final float screenScale = 1.0f / getScreenScale();
|
||||
final float availableAreaWidth = (gui.width - (gui.xSize + gui.width) / 2) * screenScale;
|
||||
@@ -197,6 +219,11 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
|
||||
|
||||
@Override
|
||||
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHotkeyPressed(GuiContainer gui) {
|
||||
|
||||
if (KeyManager.isHashDown("itemzoom.toggle", NEIClientUtils.SHIFT_HASH)) {
|
||||
NEIClientConfig.getSetting("inventory.itemzoom.enabled")
|
||||
|
||||
@@ -89,6 +89,10 @@ public class ItemsPanelGrid extends ItemsGrid<ItemsPanelGrid.ItemsPanelGridSlot,
|
||||
public void refresh(GuiContainer gui) {
|
||||
|
||||
if (this.newItems != null) {
|
||||
if (this.rawItems.size() != this.newItems.size()) {
|
||||
this.page = 0;
|
||||
}
|
||||
|
||||
this.groupItems.clear();
|
||||
this.itemToGroup.clear();
|
||||
this.forceExpand = false;
|
||||
|
||||
@@ -4,6 +4,7 @@ import static codechicken.lib.gui.GuiDraw.fontRenderer;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.util.ArrayList;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -17,56 +18,265 @@ import org.lwjgl.opengl.GL12;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.lib.gui.GuiDraw.ITooltipLineHandler;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.NEIClientUtils.Alignment;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.ReadableNumberConverter;
|
||||
|
||||
public class ItemsTooltipLineHandler implements ITooltipLineHandler {
|
||||
|
||||
protected static final int SLOT_SIZE = 18;
|
||||
protected static final int MAX_COLUMNS = 11;
|
||||
protected static final int MARGIN_TOP = 2;
|
||||
@FunctionalInterface
|
||||
public interface AmountRenderer {
|
||||
|
||||
protected String label;
|
||||
protected EnumChatFormatting labelColor = EnumChatFormatting.GRAY;
|
||||
protected List<ItemStack> items;
|
||||
protected int activeStackIndex = -1;
|
||||
protected Dimension size = new Dimension();
|
||||
protected boolean saveStackSize = false;
|
||||
protected int columns = 0;
|
||||
protected int count = 0;
|
||||
protected int rows = 0;
|
||||
protected int length = 0;
|
||||
|
||||
public ItemsTooltipLineHandler(String label, List<ItemStack> items) {
|
||||
this(label, items, true, 5);
|
||||
void draw(int x, int y, ItemStack stack, long amount);
|
||||
}
|
||||
|
||||
public ItemsTooltipLineHandler(String label, List<ItemStack> items, boolean saveStackSize, int maxRows) {
|
||||
this.label = label;
|
||||
this.items = groupingItemStacks(items);
|
||||
this.saveStackSize = saveStackSize;
|
||||
this.length = this.items.size();
|
||||
public static class NoAmountRenderer implements AmountRenderer {
|
||||
|
||||
if (this.length > 0) {
|
||||
this.columns = Math.min(MAX_COLUMNS, this.length);
|
||||
this.rows = Math.min(maxRows, (int) Math.ceil((float) this.length / this.columns));
|
||||
@Override
|
||||
public void draw(int x, int y, ItemStack stack, long amount) {
|
||||
GuiContainerManager.drawItem(x, y, stack, true, "");
|
||||
}
|
||||
|
||||
this.size.width = Math.max(this.columns * SLOT_SIZE, fontRenderer.getStringWidth(this.label) + 15);
|
||||
this.size.height = this.rows * SLOT_SIZE + fontRenderer.FONT_HEIGHT + 2 + MARGIN_TOP;
|
||||
protected static void drawAmountText(String text, Rectangle4i rect, int color, Alignment alignment) {
|
||||
NEIClientUtils.drawNEIOverlayText(text, rect, 1, color, true, alignment);
|
||||
}
|
||||
}
|
||||
|
||||
this.count = Math.min(
|
||||
this.length,
|
||||
Math.min(
|
||||
this.columns * this.rows,
|
||||
this.length > MAX_COLUMNS * maxRows ? (MAX_COLUMNS * maxRows) : Integer.MAX_VALUE));
|
||||
public static class TotalAmountRenderer extends NoAmountRenderer {
|
||||
|
||||
if (this.items.size() > this.count) {
|
||||
String text = "+" + (this.items.size() - this.count);
|
||||
this.count -= (int) Math.ceil((float) (fontRenderer.getStringWidth(text) - 2) / SLOT_SIZE);
|
||||
private static class AmountText {
|
||||
|
||||
public final String text;
|
||||
public final Alignment alignment;
|
||||
|
||||
public AmountText(String text, Alignment alignment) {
|
||||
this.text = text;
|
||||
this.alignment = alignment;
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<ItemStack, AmountText> cache = new IdentityHashMap<>();
|
||||
|
||||
@Override
|
||||
public void draw(int x, int y, ItemStack stack, long amount) {
|
||||
super.draw(x, y, stack, amount);
|
||||
drawAmount(new Rectangle4i(x, y, SLOT_SIZE - 2, SLOT_SIZE - 2), stack, amount);
|
||||
}
|
||||
|
||||
protected void drawAmount(Rectangle4i rect, ItemStack stack, long amount) {
|
||||
final AmountText amountText = this.cache.computeIfAbsent(stack, key -> {
|
||||
final boolean isFluidDisplay = StackInfo.isFluidDisplayItem(key);
|
||||
final String text = formatAmount(key, amount);
|
||||
|
||||
return new AmountText(
|
||||
isFluidDisplay && !text.isEmpty() ? text + "L" : text,
|
||||
isFluidDisplay ? Alignment.BottomLeft : Alignment.BottomRight);
|
||||
});
|
||||
|
||||
if (!amountText.text.isEmpty()) {
|
||||
drawAmountText(amountText.text, rect, 0xFFFFFF, amountText.alignment);
|
||||
}
|
||||
}
|
||||
|
||||
protected String formatAmount(ItemStack stack, long amount) {
|
||||
return amount == 0 ? "" : ReadableNumberConverter.INSTANCE.toWideReadableForm(amount);
|
||||
}
|
||||
}
|
||||
|
||||
public static class StacksAmountRenderer extends NoAmountRenderer {
|
||||
|
||||
private static class StacksText {
|
||||
|
||||
public final String stacks;
|
||||
public final String remainder;
|
||||
public final int color;
|
||||
|
||||
public StacksText(String stacks, String remainder, int color) {
|
||||
this.stacks = stacks;
|
||||
this.remainder = remainder;
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<ItemStack, StacksText> cache = new IdentityHashMap<>();
|
||||
|
||||
@Override
|
||||
public void draw(int x, int y, ItemStack stack, long amount) {
|
||||
super.draw(x, y, stack, amount);
|
||||
drawAmount(new Rectangle4i(x, y, SLOT_SIZE - 2, SLOT_SIZE - 2), stack, amount);
|
||||
}
|
||||
|
||||
protected void drawAmount(Rectangle4i rect, ItemStack stack, long amount) {
|
||||
final StacksText stacksText = this.cache.computeIfAbsent(stack, key -> formatAmount(key, amount));
|
||||
|
||||
if (!stacksText.stacks.isEmpty()) {
|
||||
drawAmountText(stacksText.stacks, rect, stacksText.color, Alignment.TopLeft);
|
||||
}
|
||||
|
||||
if (!stacksText.remainder.isEmpty()) {
|
||||
drawAmountText(stacksText.remainder, rect, stacksText.color, Alignment.BottomRight);
|
||||
}
|
||||
}
|
||||
|
||||
private StacksText formatAmount(ItemStack stack, long amount) {
|
||||
final long stackSize = StackInfo.isFluidDisplayItem(stack) ? FLUID_STACK_SIZE
|
||||
: Math.max(1, stack.getMaxStackSize());
|
||||
final long stacks = amount / stackSize;
|
||||
final long remainder = amount % stackSize;
|
||||
final String prefix = getPrefix(stack);
|
||||
|
||||
return new StacksText(
|
||||
stacks > 0 ? prefix + "x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(stacks) : "",
|
||||
remainder > 0
|
||||
? (stacks > 0 ? "+" : prefix)
|
||||
+ ReadableNumberConverter.INSTANCE.toWideReadableForm(remainder)
|
||||
: "",
|
||||
getColor(stack));
|
||||
}
|
||||
|
||||
protected String getPrefix(ItemStack stack) {
|
||||
return "";
|
||||
}
|
||||
|
||||
protected int getColor(ItemStack stack) {
|
||||
return 0xFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
protected static final int SLOT_SIZE = 18;
|
||||
protected static final int ICON_SIZE = 16;
|
||||
protected static final int ICON_OFFSET = 1;
|
||||
protected static final int MAX_COLUMNS = 11;
|
||||
protected static final int MARGIN_TOP = 2;
|
||||
protected static final int LABEL_MARGIN = 15;
|
||||
protected static final int NAME_MARGIN = 2;
|
||||
protected static final int DEFAULT_MAX_ROWS = 5;
|
||||
protected static final int FLUID_STACK_SIZE = 144;
|
||||
|
||||
protected final List<ItemStack> items;
|
||||
protected final List<Long> amounts = new ArrayList<>();
|
||||
protected final List<String> names = new ArrayList<>();
|
||||
|
||||
protected AmountRenderer amountRenderer;
|
||||
|
||||
protected String label;
|
||||
protected EnumChatFormatting labelColor = EnumChatFormatting.GRAY;
|
||||
|
||||
protected int activeStackIndex = -1;
|
||||
protected Dimension size = new Dimension();
|
||||
|
||||
protected int maxNamedRows = Integer.MAX_VALUE;
|
||||
|
||||
protected int length = 0;
|
||||
protected int rows = 0;
|
||||
protected int nameRows = 0;
|
||||
protected int gridColumns = 0;
|
||||
protected int gridCount = 0;
|
||||
|
||||
public static ItemsTooltipLineHandler of(String label, List<ItemStack> items, int maxRows, int maxNamedRows) {
|
||||
return new ItemsTooltipLineHandler(label, items, true, maxRows, maxNamedRows);
|
||||
}
|
||||
|
||||
public ItemsTooltipLineHandler(String label, List<ItemStack> items) {
|
||||
this(label, items, true, DEFAULT_MAX_ROWS, 0);
|
||||
}
|
||||
|
||||
public ItemsTooltipLineHandler(String label, List<ItemStack> items, boolean saveStackSize, int maxRows) {
|
||||
this(label, items, saveStackSize, maxRows, 0);
|
||||
}
|
||||
|
||||
protected ItemsTooltipLineHandler(String label, List<ItemStack> items, boolean saveStackSize, int maxRows,
|
||||
int maxNamedRows) {
|
||||
this.label = label;
|
||||
this.items = groupingItemStacks(items);
|
||||
this.amountRenderer = saveStackSize ? new TotalAmountRenderer() : new NoAmountRenderer();
|
||||
this.length = this.items.size();
|
||||
this.maxNamedRows = maxNamedRows;
|
||||
|
||||
setMaxRows(maxRows);
|
||||
}
|
||||
|
||||
protected static int headerHeight() {
|
||||
return fontRenderer.FONT_HEIGHT + 2 + MARGIN_TOP;
|
||||
}
|
||||
|
||||
public ItemsTooltipLineHandler setMaxRows(int maxRows) {
|
||||
if (this.length == 0) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.names.clear();
|
||||
this.nameRows = 0;
|
||||
|
||||
if (!layoutWithNames(maxRows)) {
|
||||
layoutAsGrid(maxRows);
|
||||
}
|
||||
|
||||
this.size.height = this.rows * SLOT_SIZE + headerHeight();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getRows() {
|
||||
return this.rows;
|
||||
}
|
||||
|
||||
protected boolean layoutWithNames(int maxRows) {
|
||||
final int maxNames = Math.min(this.maxNamedRows, this.length <= maxRows ? this.length : maxRows - 1);
|
||||
final int[] lineWidth = new int[maxNames + 1];
|
||||
lineWidth[0] = labelWidth();
|
||||
|
||||
for (int index = 0; index < maxNames; index++) {
|
||||
final String name = this.items.get(index).getDisplayName();
|
||||
this.names.add(name);
|
||||
lineWidth[index + 1] = Math
|
||||
.max(lineWidth[index], SLOT_SIZE + NAME_MARGIN + fontRenderer.getStringWidth(name));
|
||||
}
|
||||
|
||||
for (int named = maxNames; named >= 0; named--) {
|
||||
final int rest = this.length - named;
|
||||
final int width = Math.max(lineWidth[named], Math.min(rest, MAX_COLUMNS) * SLOT_SIZE);
|
||||
final int columns = Math.max(1, width / SLOT_SIZE);
|
||||
final int restRows = (int) Math.ceil((float) rest / columns);
|
||||
|
||||
if (named + restRows <= maxRows) {
|
||||
this.nameRows = named;
|
||||
this.gridColumns = columns;
|
||||
this.gridCount = rest;
|
||||
this.rows = named + restRows;
|
||||
this.size.width = width;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
this.names.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void layoutAsGrid(int maxRows) {
|
||||
this.gridColumns = Math.min(MAX_COLUMNS, this.length);
|
||||
this.rows = Math.min(maxRows, (int) Math.ceil((float) this.length / this.gridColumns));
|
||||
this.gridCount = Math.min(this.length, this.gridColumns * this.rows);
|
||||
this.size.width = Math.max(this.gridColumns * SLOT_SIZE, labelWidth());
|
||||
|
||||
if (this.gridCount < this.length) {
|
||||
this.gridCount -= reservedColumns(this.length - this.gridCount);
|
||||
}
|
||||
}
|
||||
|
||||
protected int labelWidth() {
|
||||
return fontRenderer.getStringWidth(this.label) + LABEL_MARGIN;
|
||||
}
|
||||
|
||||
protected int reservedColumns(int hidden) {
|
||||
return (int) Math.ceil((float) (fontRenderer.getStringWidth("+" + hidden) - 2) / SLOT_SIZE);
|
||||
}
|
||||
|
||||
public ItemsTooltipLineHandler setAmountRenderer(AmountRenderer amountRenderer) {
|
||||
this.amountRenderer = amountRenderer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setActiveStack(ItemStack activeStack) {
|
||||
@@ -98,7 +308,7 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
this.size.width = Math.max(this.columns * SLOT_SIZE, fontRenderer.getStringWidth(this.label) + 15);
|
||||
this.size.width = Math.max(this.size.width, labelWidth());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,63 +329,79 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
|
||||
final int zTranslation = GuiContainerManager.TOOLTIP_Z_OFFSET;
|
||||
GL11.glTranslatef(xTranslation, yTranslation, zTranslation);
|
||||
|
||||
int indexShift = 0;
|
||||
final int gridShift = gridIndexShift();
|
||||
|
||||
if (this.activeStackIndex != -1) {
|
||||
indexShift = Math.max(0, Math.min(this.items.size() - this.count, this.activeStackIndex - this.count + 2));
|
||||
for (int index = 0; index < this.nameRows; index++) {
|
||||
drawSlot(0, index * SLOT_SIZE, index);
|
||||
}
|
||||
|
||||
for (int index = 0; index < this.count && index + indexShift < this.items.size(); index++) {
|
||||
ItemStack drawStack = this.items.get(index + indexShift);
|
||||
int col = index % this.columns;
|
||||
int row = index / this.columns;
|
||||
for (int index = 0; index < this.gridCount; index++) {
|
||||
drawSlot(
|
||||
(index % this.gridColumns) * SLOT_SIZE,
|
||||
(this.nameRows + index / this.gridColumns) * SLOT_SIZE,
|
||||
this.nameRows + gridShift + index);
|
||||
}
|
||||
|
||||
String stackSize = !this.saveStackSize || drawStack.stackSize == 0 ? ""
|
||||
: ReadableNumberConverter.INSTANCE.toWideReadableForm(drawStack.stackSize);
|
||||
NEIClientUtils.gl2DRenderContext(() -> {
|
||||
final int textShift = ICON_OFFSET + Math.round((ICON_SIZE - fontRenderer.FONT_HEIGHT) / 2f);
|
||||
|
||||
if (this.activeStackIndex == index + indexShift) {
|
||||
NEIClientUtils.gl2DRenderContext(
|
||||
() -> GuiDraw.drawRect(col * SLOT_SIZE - 1, row * SLOT_SIZE - 1, 18, 18, 0x66555555));
|
||||
for (int index = 0; index < this.nameRows; index++) {
|
||||
fontRenderer.drawStringWithShadow(
|
||||
EnumChatFormatting.GRAY + this.names.get(index),
|
||||
SLOT_SIZE + NAME_MARGIN,
|
||||
index * SLOT_SIZE + textShift,
|
||||
0xFFFFFF);
|
||||
}
|
||||
|
||||
drawItem(col * SLOT_SIZE, row * SLOT_SIZE, drawStack, stackSize);
|
||||
}
|
||||
final int hidden = this.length - this.nameRows - this.gridCount;
|
||||
|
||||
if (this.count < this.items.size()) {
|
||||
final String text = "+" + (this.items.size() - this.count);
|
||||
|
||||
NEIClientUtils.gl2DRenderContext(() -> {
|
||||
if (hidden > 0) {
|
||||
final String text = "+" + hidden;
|
||||
fontRenderer.drawStringWithShadow(
|
||||
text,
|
||||
MAX_COLUMNS * SLOT_SIZE - fontRenderer.getStringWidth(text) - 2,
|
||||
(this.rows - 1) * SLOT_SIZE + (SLOT_SIZE - fontRenderer.FONT_HEIGHT) / 2,
|
||||
0xee555555);
|
||||
});
|
||||
}
|
||||
EnumChatFormatting.GRAY + text,
|
||||
this.size.width - fontRenderer.getStringWidth(text) - 2,
|
||||
(this.rows - 1) * SLOT_SIZE + textShift,
|
||||
0xFFFFFF);
|
||||
}
|
||||
});
|
||||
|
||||
GL11.glTranslatef(-xTranslation, -yTranslation, -zTranslation);
|
||||
GL11.glPopAttrib();
|
||||
}
|
||||
|
||||
protected void drawItem(int x, int y, ItemStack drawStack, String stackSize) {
|
||||
GuiContainerManager.drawItem(x, y, drawStack, true, stackSize);
|
||||
protected int gridIndexShift() {
|
||||
if (this.nameRows > 0 || this.activeStackIndex == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Math.max(0, Math.min(this.length - this.gridCount, this.activeStackIndex - this.gridCount + 2));
|
||||
}
|
||||
|
||||
protected void drawSlot(int x, int y, int index) {
|
||||
if (this.activeStackIndex == index) {
|
||||
NEIClientUtils.gl2DRenderContext(() -> GuiDraw.drawRect(x, y, SLOT_SIZE, SLOT_SIZE, 0x66555555));
|
||||
}
|
||||
|
||||
drawStackWithAmount(x, y, index);
|
||||
}
|
||||
|
||||
protected void drawStackWithAmount(int x, int y, int index) {
|
||||
this.amountRenderer.draw(x + ICON_OFFSET, y + ICON_OFFSET, this.items.get(index), this.amounts.get(index));
|
||||
}
|
||||
|
||||
private List<ItemStack> groupingItemStacks(List<ItemStack> items) {
|
||||
final List<ItemStack> result = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<NBTTagCompound, Long> entry : ItemStackAmount.of(items).entrySet()) {
|
||||
final ItemStack stack = StackInfo.loadFromNBT(entry.getKey(), Math.max(0, entry.getValue()));
|
||||
|
||||
if (stack != null && StackInfo.isFluidDisplayItem(stack)) {
|
||||
stack.stackSize = 0;
|
||||
}
|
||||
|
||||
result.add(stack);
|
||||
result.add(StackInfo.loadFromNBT(entry.getKey(), 0));
|
||||
this.amounts.add(Math.max(0, entry.getValue()));
|
||||
}
|
||||
|
||||
if (result.isEmpty()) {
|
||||
result.addAll(items);
|
||||
for (ItemStack stack : items) {
|
||||
result.add(stack);
|
||||
this.amounts.add(0L);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
@@ -29,6 +30,7 @@ public class KeyManager {
|
||||
private static final Map<String, KeyBinding> keyBindings = new HashMap<>();
|
||||
private static final Map<String, String> keyAliases = new HashMap<>();
|
||||
private static volatile boolean pendingOptionsReload = false;
|
||||
private static int clickedButton = -1;
|
||||
|
||||
static {
|
||||
// Aliases for legacy keybinds
|
||||
@@ -73,7 +75,8 @@ public class KeyManager {
|
||||
final int keyCode = binding.getKeyCode();
|
||||
|
||||
if (keyCode < 0) {
|
||||
return Mouse.isButtonDown(keyCode + 100);
|
||||
final int button = keyCode + 100;
|
||||
return Mouse.isButtonDown(button) || button == clickedButton;
|
||||
} else if (keyCode > Keyboard.KEY_NONE && keyCode < Keyboard.KEYBOARD_SIZE) {
|
||||
return Keyboard.isKeyDown(keyCode);
|
||||
}
|
||||
@@ -82,6 +85,40 @@ public class KeyManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether any NEI key binding is assigned to the given mouse button.
|
||||
*/
|
||||
public static boolean isMouseBound(int button) {
|
||||
for (KeyBinding binding : keyBindings.values()) {
|
||||
if (binding.getKeyCode() == button - 100) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a hotkey handler for a click of the given mouse button if the button is bound to any NEI key binding. The
|
||||
* button is reported as down by {@link #isKeyDown} for the duration of the call, because the LWJGL button state can
|
||||
* already be released when a quick click is processed.
|
||||
*
|
||||
* @return true if the click was consumed by the handler
|
||||
*/
|
||||
public static boolean handleMouseHotkey(int button, BooleanSupplier handler) {
|
||||
if (!isMouseBound(button)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int previous = clickedButton;
|
||||
clickedButton = button;
|
||||
|
||||
try {
|
||||
return handler.getAsBoolean();
|
||||
} finally {
|
||||
clickedButton = previous;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isHashDown(String ident) {
|
||||
return isHashDown(ident, 0);
|
||||
}
|
||||
@@ -107,18 +144,23 @@ public class KeyManager {
|
||||
|
||||
public static String getKeyName(String ident, int meta) {
|
||||
final int keyCode = getKeyCode(ident);
|
||||
return keyCode == Keyboard.KEY_NONE ? null : NEIKeyboardUtils.getKeyName(keyCode + meta);
|
||||
return keyCode == Keyboard.KEY_NONE ? null : NEIKeyboardUtils.getKeyName(keyCode, meta);
|
||||
}
|
||||
|
||||
public static String getKeyName(String ident, int meta, int mouseBind) {
|
||||
final int keyCode = getKeyCode(ident);
|
||||
return keyCode == Keyboard.KEY_NONE && mouseBind == NEIMouseUtils.MOUSE_BTN_NONE ? null
|
||||
: getKeyName(keyCode + meta, mouseBind);
|
||||
: getKeyName(keyCode, meta, mouseBind);
|
||||
}
|
||||
|
||||
public static String getKeyName(int keyBind, int mouseBind) {
|
||||
final int keyCode = NEIKeyboardUtils.unhash(keyBind);
|
||||
return getKeyName(keyCode, keyBind - keyCode, mouseBind);
|
||||
}
|
||||
|
||||
private static String getKeyName(int keyCode, int hash, int mouseBind) {
|
||||
StringJoiner keyText = new StringJoiner(" + ");
|
||||
String keyHash = keyBind == Keyboard.KEY_NONE ? "" : NEIKeyboardUtils.getKeyName(keyBind);
|
||||
String keyHash = keyCode == Keyboard.KEY_NONE && hash == 0 ? "" : NEIKeyboardUtils.getKeyName(keyCode, hash);
|
||||
String mouseHash = mouseBind == NEIMouseUtils.MOUSE_BTN_NONE ? "" : NEIMouseUtils.getKeyName(mouseBind);
|
||||
|
||||
if (!keyHash.isEmpty()) {
|
||||
|
||||
@@ -220,6 +220,20 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
@Override
|
||||
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
|
||||
|
||||
if (isEnabled() && !isHidden()) {
|
||||
for (Widget widget : controlWidgets) {
|
||||
if (inputFocused == null) {
|
||||
widget.lastKeyTyped(keyID, keyChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHotkeyPressed(GuiContainer gui) {
|
||||
|
||||
if (KeyManager.isKeyDown("gui.hide")) {
|
||||
toggleBooleanSetting("inventory.hidden");
|
||||
return true;
|
||||
@@ -234,8 +248,12 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isEnabled() && !isHidden()) {
|
||||
for (Widget widget : controlWidgets) if (inputFocused == null) widget.lastKeyTyped(keyID, keyChar);
|
||||
if (isEnabled() && !isHidden() && inputFocused == null) {
|
||||
for (Widget widget : controlWidgets) {
|
||||
if (widget.onHotkeyPressed()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -427,14 +445,14 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
if (!rightclick) {
|
||||
if (Keyboard.getEventKeyState() && getIsAccessibleControlEventKey()
|
||||
&& NEIClientConfig.canChangeCheatMode()) {
|
||||
NEIClientConfig.cycleSetting("inventory.cheatmode", 3);
|
||||
NEIClientConfig.setCheatMode((NEIClientConfig.getCheatMode() + 1) % 3);
|
||||
} else {
|
||||
if (Keyboard.getEventKeyState() && (Keyboard.getEventKey() == Keyboard.KEY_LSHIFT
|
||||
|| Keyboard.getEventKey() == Keyboard.KEY_RSHIFT)) {
|
||||
GuiRecipeTab.loadHandlerInfo();
|
||||
RecipeCatalysts.loadCatalystInfo();
|
||||
}
|
||||
getOptionList().openGui(getGuiContainer(), false);
|
||||
getOptionList().openGui(getGuiContainer());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -803,6 +821,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
|
||||
if (!isEnabled()) return;
|
||||
|
||||
AutoFocusWidget.instance.guiTick();
|
||||
|
||||
for (Widget widget : drawWidgets) widget.update();
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,9 @@ public class NEICPH implements IClientPacketHandler {
|
||||
case S2C.CACHE_BOOKMARK_DATA:
|
||||
handleCacheBookmarkData(packet);
|
||||
break;
|
||||
case S2C.SYNC:
|
||||
ServerSync.onReply(packet.readInt());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ import codechicken.lib.config.ConfigTag;
|
||||
import codechicken.lib.config.ConfigTagParent;
|
||||
import codechicken.nei.api.API;
|
||||
import codechicken.nei.api.GuiInfo;
|
||||
import codechicken.nei.api.IConfigureNEI;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.api.NEIInfo;
|
||||
import codechicken.nei.config.ConfigSet;
|
||||
@@ -69,6 +68,7 @@ public class NEIClientConfig {
|
||||
private static boolean pluginNEIConfigLoaded;
|
||||
private static boolean enabledOverride;
|
||||
private static String worldPath;
|
||||
private static final String CHEAT_MODE_KEY = "cheatmode";
|
||||
|
||||
public static Logger logger = LogManager.getLogger("NotEnoughItems");
|
||||
public static File configDir = new File(CommonUtils.getMinecraftDir(), "config/NEI/");
|
||||
@@ -157,6 +157,16 @@ public class NEIClientConfig {
|
||||
.getIntValue(-1);
|
||||
API.addOption(new OptionCycled("inventory.cheatmode", 3) {
|
||||
|
||||
@Override
|
||||
public int value() {
|
||||
return getCheatMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(int value) {
|
||||
setCheatMode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean optionValid(int index) {
|
||||
return getLockedMode() == -1 || getLockedMode() == index && NEIInfo.isValidMode(index);
|
||||
@@ -200,6 +210,11 @@ public class NEIClientConfig {
|
||||
tag.getTag("inventory.bookmarks.showRecipeMarkerMode").setComment("Show Recipe Marker").getIntValue(0);
|
||||
API.addOption(new OptionCycled("inventory.bookmarks.showRecipeMarkerMode", 3, true));
|
||||
|
||||
tag.getTag("inventory.bookmarks.maxVerticalTooltipRows")
|
||||
.setComment("Max rows in vertical crafting chain tooltip lists (0 - disable, always use grid)")
|
||||
.getIntValue(12);
|
||||
API.addOption(new OptionIntegerField("inventory.bookmarks.maxVerticalTooltipRows", 0, 50));
|
||||
|
||||
tag.getTag("inventory.bookmarks.recipeMarkerColor").setComment("Color of the icon marker")
|
||||
.getHexValue(0xADADAD);
|
||||
API.addOption(
|
||||
@@ -212,9 +227,6 @@ public class NEIClientConfig {
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.bookmarks.showRecipeHandlerIcon", true));
|
||||
|
||||
tag.getTag("inventory.bookmarks.recipeChainDir").getIntValue(1);
|
||||
API.addOption(new OptionCycled("inventory.bookmarks.recipeChainDir", 2, true));
|
||||
|
||||
tag.getTag("inventory.bookmarks.ignorePotionOverlap").setComment("Ignore overlap with potion effect HUD")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.bookmarks.ignorePotionOverlap", true));
|
||||
@@ -227,6 +239,10 @@ public class NEIClientConfig {
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.bookmarks.bookmarkRecipeWithCount", true));
|
||||
|
||||
tag.getTag("inventory.bookmarks.craftingTreeZoomWithoutModifier")
|
||||
.setComment("Zoom Crafting Tree with mouse wheel without holding Ctrl").getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.bookmarks.craftingTreeZoomWithoutModifier", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.jeiStyleTabs").setComment("Enable/disable JEI Style Tabs")
|
||||
.getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButtonBoubs("inventory.guirecipe.jeiStyleTabs", true));
|
||||
@@ -266,6 +282,11 @@ public class NEIClientConfig {
|
||||
.getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.scrollPages", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.freezeCycleOnHover")
|
||||
.setComment("Stop cycling the recipe while hovering over an ingredient or a button")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.freezeCycleOnHover", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.profile").getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.profile", true));
|
||||
|
||||
@@ -371,6 +392,11 @@ public class NEIClientConfig {
|
||||
tag.getTag("inventory.itemzoom.onlySolid").getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.itemzoom.onlySolid", true));
|
||||
|
||||
tag.getTag("inventory.itemzoom.preferredSide")
|
||||
.setComment("Which side to prefer showing the zoomed item on, when both sides are free.")
|
||||
.getIntValue(0);
|
||||
API.addOption(new OptionCycled("inventory.itemzoom.preferredSide", 3, true));
|
||||
|
||||
tag.getTag("inventory.itemzoom.helpText")
|
||||
.setComment("Display name \"Item Zoom\" and the hotkey to toggle this mod below the zoomed item.")
|
||||
.getBooleanValue(true);
|
||||
@@ -531,23 +557,18 @@ public class NEIClientConfig {
|
||||
OptionList.setOptionList(new OptionList("nei.options") {
|
||||
|
||||
@Override
|
||||
public ConfigSet globalConfigSet() {
|
||||
public ConfigSet configSet() {
|
||||
return global;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigSet worldConfigSet() {
|
||||
return world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionList configBase() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuiOptionList getGui(GuiScreen parent, OptionList list, boolean world) {
|
||||
return new GuiNEIOptionList(parent, list, world);
|
||||
public GuiOptionList getGui(GuiScreen parent, OptionList list) {
|
||||
return new GuiNEIOptionList(parent, list);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -914,15 +935,15 @@ public class NEIClientConfig {
|
||||
specificDir.mkdirs();
|
||||
}
|
||||
|
||||
world = new ConfigSet(new File(specificDir, "NEI.dat"), new ConfigFile(new File(specificDir, "NEI.cfg")));
|
||||
world = new ConfigSet(new File(specificDir, "NEI.dat"));
|
||||
|
||||
if (newWorld && Minecraft.getMinecraft().isSingleplayer() && getLockedMode() == -1) {
|
||||
final int globalMode = global.config.getTag("inventory.cheatmode").getIntValue();
|
||||
final int globalMode = getCheatMode();
|
||||
final int worldMode = Math
|
||||
.min(globalMode, NEIClientUtils.mc().playerController.isInCreativeMode() ? 2 : 0);
|
||||
|
||||
if (worldMode != globalMode) {
|
||||
world.config.getTag("inventory.cheatmode").setIntValue(worldMode);
|
||||
setCheatMode(worldMode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -936,9 +957,6 @@ public class NEIClientConfig {
|
||||
}
|
||||
|
||||
private static void onWorldLoad() {
|
||||
world.config.setComment(
|
||||
"World based configuration of NEI.\nMost of these options can be changed ingame.\nDeleting any element will restore it to it's default value");
|
||||
|
||||
setWorldDefaults();
|
||||
creativeInv = new ItemStack[54];
|
||||
LayoutManager.searchField.setText(getSearchExpression());
|
||||
@@ -1014,16 +1032,7 @@ public class NEIClientConfig {
|
||||
? NEIClientConfig.pluginsList.parallelStream()
|
||||
: NEIClientConfig.pluginsList.stream();
|
||||
|
||||
stream.forEach(clazz -> {
|
||||
try {
|
||||
IConfigureNEI config = (IConfigureNEI) clazz.getConstructor().newInstance();
|
||||
config.loadConfig();
|
||||
NEIModContainer.plugins.add(config);
|
||||
logger.debug("Loaded {}", clazz.getName());
|
||||
} catch (Throwable e) {
|
||||
logger.error("Failed to Load {}", clazz.getName(), e);
|
||||
}
|
||||
});
|
||||
PluginLoader.load(stream, NEIModContainer.plugins, logger);
|
||||
|
||||
KeyManager.requestOptionsReload();
|
||||
RecipeCatalysts.loadCatalystInfo();
|
||||
@@ -1053,14 +1062,8 @@ public class NEIClientConfig {
|
||||
|
||||
}
|
||||
|
||||
public static boolean isWorldSpecific(String setting) {
|
||||
if (world == null) return false;
|
||||
ConfigTag tag = world.config.getTag(setting, false);
|
||||
return tag != null && tag.value != null;
|
||||
}
|
||||
|
||||
public static ConfigTag getSetting(String s) {
|
||||
return isWorldSpecific(s) ? world.config.getTag(s) : global.config.getTag(s);
|
||||
return global.config.getTag(s);
|
||||
}
|
||||
|
||||
public static boolean getBooleanSetting(String s) {
|
||||
@@ -1105,6 +1108,10 @@ public class NEIClientConfig {
|
||||
return getIntSetting("inventory.bookmarks.showRecipeMarkerMode");
|
||||
}
|
||||
|
||||
public static int getMaxVerticalTooltipRows() {
|
||||
return getIntSetting("inventory.bookmarks.maxVerticalTooltipRows");
|
||||
}
|
||||
|
||||
public static boolean showItemQuantityWidget() {
|
||||
return getBooleanSetting("inventory.showItemQuantityWidget");
|
||||
}
|
||||
@@ -1153,8 +1160,8 @@ public class NEIClientConfig {
|
||||
return getBooleanSetting("inventory.bookmarks.ignorePotionOverlap");
|
||||
}
|
||||
|
||||
public static int recipeChainDir() {
|
||||
return getIntSetting("inventory.bookmarks.recipeChainDir");
|
||||
public static boolean craftingTreeZoomWithoutModifier() {
|
||||
return getBooleanSetting("inventory.bookmarks.craftingTreeZoomWithoutModifier");
|
||||
}
|
||||
|
||||
public static boolean optimizeGuiOverlapComputation() {
|
||||
@@ -1165,6 +1172,10 @@ public class NEIClientConfig {
|
||||
return getBooleanSetting("inventory.guirecipe.cycledIngredientsTooltip");
|
||||
}
|
||||
|
||||
public static boolean freezeCycleOnHover() {
|
||||
return getBooleanSetting("inventory.guirecipe.freezeCycleOnHover");
|
||||
}
|
||||
|
||||
public static boolean requireShiftForOverlayRecipe() {
|
||||
return getBooleanSetting("inventory.guirecipe.shiftOverlayRecipe");
|
||||
}
|
||||
@@ -1198,12 +1209,18 @@ public class NEIClientConfig {
|
||||
}
|
||||
|
||||
public static int getCheatMode() {
|
||||
if (world != null && world.nbt.hasKey(CHEAT_MODE_KEY)) return world.nbt.getInteger(CHEAT_MODE_KEY);
|
||||
return getIntSetting("inventory.cheatmode");
|
||||
}
|
||||
|
||||
public static void setCheatMode(int mode) {
|
||||
if (world != null) world.nbt.setInteger(CHEAT_MODE_KEY, mode);
|
||||
else setIntSetting("inventory.cheatmode", mode);
|
||||
}
|
||||
|
||||
public static boolean canChangeCheatMode() {
|
||||
if (getLockedMode() != -1) {
|
||||
setIntSetting("inventory.cheatmode", getLockedMode());
|
||||
setCheatMode(getLockedMode());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
|
||||
|
||||
if (GuiInfo.hasCustomSlots(gui)) return false;
|
||||
|
||||
if (NEIClientUtils.shiftKey()) {
|
||||
if (NEIClientUtils.shiftKey() && button != 2) { // MMB is used by other mods when an itemstack is picked.
|
||||
// fix small mouse movement while clicking causing slotIndex to be -999
|
||||
if (slotIndex == -999) {
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
|
||||
@@ -92,9 +92,17 @@ public class NEISPH implements IServerPacketHandler {
|
||||
case C2S.SEND_CHAT_ITEM_LINK:
|
||||
handleSendChatItemLink(sender, packet);
|
||||
break;
|
||||
case C2S.SYNC:
|
||||
handleSync(sender, packet.readInt());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSync(EntityPlayerMP sender, int id) {
|
||||
sender.sendContainerAndContentsToPlayer(sender.openContainer, sender.openContainer.getInventory());
|
||||
new PacketCustom(channel, S2C.SYNC).writeInt(id).sendToPlayer(sender);
|
||||
}
|
||||
|
||||
private void handleSendChatItemLink(EntityPlayerMP sender, PacketCustom packet) {
|
||||
final NBTTagCompound payloadTag = packet.readNBTTagCompound();
|
||||
NEIServerUtils.sendChatItemLink(sender, payloadTag);
|
||||
|
||||
@@ -24,6 +24,7 @@ public final class PacketIDs {
|
||||
public static final int REQUEST_POTION_GUI = 24;
|
||||
public static final int SET_DUMMY_SLOT = 25;
|
||||
public static final int SEND_CHAT_ITEM_LINK = 26;
|
||||
public static final int SYNC = 27;
|
||||
}
|
||||
|
||||
public static final class S2C {
|
||||
@@ -38,5 +39,6 @@ public final class PacketIDs {
|
||||
public static final int SET_CREATIVE_PLUS_MODE = 23;
|
||||
public static final int OPEN_POTION_GUI = 24;
|
||||
public static final int CACHE_BOOKMARK_DATA = 25;
|
||||
public static final int SYNC = 26;
|
||||
}
|
||||
}
|
||||
@@ -305,7 +305,7 @@ public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ?
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyPress(int keyID, char keyChar) {
|
||||
public boolean onHotkeyPressed() {
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
if (!contains(mouse.x, mouse.y)) return false;
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import codechicken.nei.api.IConfigureNEI;
|
||||
|
||||
final class PluginLoader {
|
||||
|
||||
private PluginLoader() {}
|
||||
|
||||
static void load(Stream<Class<?>> plugins, Collection<IConfigureNEI> loadedPlugins, Logger logger) {
|
||||
final ClassLoader classLoader = IConfigureNEI.class.getClassLoader();
|
||||
|
||||
plugins.forEach(clazz -> {
|
||||
final Thread thread = Thread.currentThread();
|
||||
final ClassLoader previousClassLoader = thread.getContextClassLoader();
|
||||
|
||||
// Common-pool workers may use the system loader, which cannot see FML-only classes. Keep FML's loader
|
||||
// through error logging too: old Log4j can otherwise throw while resolving a plugin's stack frames.
|
||||
try {
|
||||
thread.setContextClassLoader(classLoader);
|
||||
try {
|
||||
IConfigureNEI config = (IConfigureNEI) clazz.getConstructor().newInstance();
|
||||
config.loadConfig();
|
||||
loadedPlugins.add(config);
|
||||
logger.debug("Loaded {}", clazz.getName());
|
||||
} catch (Throwable e) {
|
||||
logger.error("Failed to Load {}", clazz.getName(), e);
|
||||
}
|
||||
} finally {
|
||||
thread.setContextClassLoader(previousClassLoader);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,11 @@ public class PopupInputHandler implements IContainerInputHandler {
|
||||
|
||||
@Override
|
||||
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHotkeyPressed(GuiContainer gui) {
|
||||
|
||||
if (KeyManager.isHashDown("gui.enchant") && canPerformAction("enchant")) {
|
||||
NEICPH.sendOpenEnchantmentWindow();
|
||||
|
||||
@@ -4,16 +4,13 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
@@ -21,7 +18,11 @@ import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.drawable.DrawableBuilder;
|
||||
import codechicken.nei.drawable.DrawableResource;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.item.FluidDrawer;
|
||||
import codechicken.nei.item.FluidDrawer.FillDirection;
|
||||
import codechicken.nei.recipe.Badge;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
@@ -46,7 +47,8 @@ public class PositionedStack implements Cloneable {
|
||||
protected boolean permutated = false;
|
||||
|
||||
protected String acceptsLabel;
|
||||
protected List<String> tooltip;
|
||||
|
||||
protected Function<ItemStack, List<String>> tooltip;
|
||||
protected List<Badge> badges;
|
||||
|
||||
public PositionedStack(Object object, int x, int y, boolean genPerms) {
|
||||
@@ -119,11 +121,15 @@ public class PositionedStack implements Cloneable {
|
||||
}
|
||||
|
||||
public void setTooltip(List<String> tooltip) {
|
||||
this.tooltip = tooltip;
|
||||
this.tooltip = tooltip == null ? null : item -> tooltip;
|
||||
}
|
||||
|
||||
public void setTooltipProvider(Function<ItemStack, List<String>> provider) {
|
||||
this.tooltip = provider;
|
||||
}
|
||||
|
||||
public List<String> getTooltip() {
|
||||
return this.tooltip;
|
||||
return this.tooltip == null ? null : this.tooltip.apply(this.item);
|
||||
}
|
||||
|
||||
public int getChance() {
|
||||
@@ -139,7 +145,6 @@ public class PositionedStack implements Cloneable {
|
||||
PositionedStack pStack = (PositionedStack) super.clone();
|
||||
pStack.items = Arrays.stream(this.items).map(ItemStack::copy).toArray(ItemStack[]::new);
|
||||
pStack.item = this.item == null ? null : this.item.copy();
|
||||
pStack.tooltip = this.tooltip == null ? null : new ArrayList<>(this.tooltip);
|
||||
pStack.badges = this.badges == null ? null : new ArrayList<>(this.badges);
|
||||
return pStack;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
@@ -158,7 +163,7 @@ public class PositionedStack implements Cloneable {
|
||||
}
|
||||
|
||||
public List<ItemStack> getFilteredPermutations(ItemFilter additionalFilter) {
|
||||
List<ItemStack> items = Arrays.asList(this.items);
|
||||
List<ItemStack> items = new ArrayList<>(Arrays.asList(this.items));
|
||||
|
||||
items = filteringPermutations(items, item -> !ItemInfo.isHidden(item));
|
||||
items = filteringPermutations(items, PresetsList.getItemFilter());
|
||||
@@ -252,27 +257,70 @@ public class PositionedStack implements Cloneable {
|
||||
public void draw(int mousex, int mousey) {}
|
||||
}
|
||||
|
||||
public static class Fluid extends PositionedStack {
|
||||
public static class Tank extends PositionedStack {
|
||||
|
||||
/** The tank size the fill level is measured against, in mB. 0 means "always render full". */
|
||||
public int capacity = 0;
|
||||
protected int capacity = 0;
|
||||
protected boolean flowingTexture = false;
|
||||
protected FillDirection fillDirection = FillDirection.AUTO;
|
||||
protected DrawableResource overlay;
|
||||
|
||||
private ItemStack cachedFluidItem;
|
||||
private FluidStack cachedFluidStack;
|
||||
|
||||
public Fluid(Object object, int x, int y, boolean genPerms) {
|
||||
public Tank(Object object, int x, int y, boolean genPerms) {
|
||||
super(object, x, y, genPerms);
|
||||
}
|
||||
|
||||
public Fluid(Object object, int x, int y) {
|
||||
public Tank(Object object, int x, int y) {
|
||||
this(object, x, y, true);
|
||||
}
|
||||
|
||||
public Fluid(Object object, int x, int y, int width, int height, int capacity) {
|
||||
public Tank(Object object, int x, int y, int width, int height, int capacity) {
|
||||
super(object, x, y, false);
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.capacity = capacity;
|
||||
setCapacity(capacity);
|
||||
}
|
||||
|
||||
public int getCapacity() {
|
||||
return this.capacity;
|
||||
}
|
||||
|
||||
public Tank setCapacity(int capacity) {
|
||||
this.capacity = Math.max(capacity, 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean hasFlowingTexture() {
|
||||
return this.flowingTexture;
|
||||
}
|
||||
|
||||
public Tank setFlowingTexture(boolean flowingTexture) {
|
||||
this.flowingTexture = flowingTexture;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FillDirection getFillDirection() {
|
||||
return this.fillDirection;
|
||||
}
|
||||
|
||||
public Tank setFillDirection(FillDirection fillDirection) {
|
||||
this.fillDirection = fillDirection == null ? FillDirection.AUTO : fillDirection;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DrawableResource getOverlay() {
|
||||
return this.overlay;
|
||||
}
|
||||
|
||||
public Tank setOverlay(String resourceLocation, int u, int v, int width, int height) {
|
||||
return setOverlay(new DrawableBuilder(resourceLocation, u, v, width, height).build());
|
||||
}
|
||||
|
||||
public Tank setOverlay(DrawableResource overlay) {
|
||||
this.overlay = overlay;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected FluidStack getFluidStack() {
|
||||
@@ -313,62 +361,24 @@ public class PositionedStack implements Cloneable {
|
||||
return;
|
||||
}
|
||||
|
||||
final int tankCapacity = this.capacity > 0 ? this.capacity : fluidStack.amount;
|
||||
int fillHeight = tankCapacity > 0
|
||||
? (int) ((long) this.height * Math.min(fluidStack.amount, tankCapacity) / tankCapacity)
|
||||
: 0;
|
||||
FluidDrawer.drawTank(
|
||||
this.relx,
|
||||
this.rely,
|
||||
this.width,
|
||||
this.height,
|
||||
this.capacity,
|
||||
fluidStack,
|
||||
this.flowingTexture,
|
||||
this.fillDirection);
|
||||
|
||||
if (fluidStack.amount > 0 && fillHeight <= 0) {
|
||||
fillHeight = 1;
|
||||
if (this.overlay != null) {
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
this.overlay.draw(this.relx, this.rely);
|
||||
GL11.glEnable(GL11.GL_LIGHTING);
|
||||
GL11.glDisable(GL11.GL_BLEND);
|
||||
}
|
||||
|
||||
if (fillHeight > 0) {
|
||||
drawFluid(this.relx, this.rely, this.width, this.height, fillHeight, fluidStack);
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawFluid(int x, int y, int width, int height, int fillHeight, FluidStack fluidStack) {
|
||||
final IIcon icon = fluidStack.getFluid().getIcon(fluidStack);
|
||||
|
||||
if (icon == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int color = fluidStack.getFluid().getColor(fluidStack);
|
||||
final float red = (color >> 16 & 0xFF) / 255F;
|
||||
final float green = (color >> 8 & 0xFF) / 255F;
|
||||
final float blue = (color & 0xFF) / 255F;
|
||||
|
||||
Minecraft.getMinecraft().getTextureManager().bindTexture(TextureMap.locationBlocksTexture);
|
||||
GL11.glColor4f(red, green, blue, 1F);
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
|
||||
final Tessellator tessellator = Tessellator.instance;
|
||||
|
||||
tessellator.startDrawingQuads();
|
||||
for (int tx = 0; tx < width; tx += 16) {
|
||||
final int tileWidth = Math.min(16, width - tx);
|
||||
final double u2 = icon.getMinU() + (icon.getMaxU() - icon.getMinU()) * tileWidth / 16D;
|
||||
|
||||
for (int ty = 0; ty < fillHeight; ty += 16) {
|
||||
final int tileHeight = Math.min(16, fillHeight - ty);
|
||||
final double v2 = icon.getMinV() + (icon.getMaxV() - icon.getMinV()) * tileHeight / 16D;
|
||||
final int bottomY = y + height - ty;
|
||||
final int topY = bottomY - tileHeight;
|
||||
|
||||
tessellator.addVertexWithUV(x + tx, bottomY, 0, icon.getMinU(), v2);
|
||||
tessellator.addVertexWithUV(x + tx + tileWidth, bottomY, 0, u2, v2);
|
||||
tessellator.addVertexWithUV(x + tx + tileWidth, topY, 0, u2, icon.getMinV());
|
||||
tessellator.addVertexWithUV(x + tx, topY, 0, icon.getMinU(), icon.getMinV());
|
||||
}
|
||||
}
|
||||
tessellator.draw();
|
||||
|
||||
GL11.glDisable(GL11.GL_BLEND);
|
||||
GL11.glEnable(GL11.GL_LIGHTING);
|
||||
GL11.glColor4f(1F, 1F, 1F, 1F);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,15 +48,19 @@ public abstract class RecipeSearchField extends TextField implements ItemFilterP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lastKeyTyped(int keyID, char keyChar) {
|
||||
public boolean onHotkeyPressed() {
|
||||
|
||||
if (focused() && KeyManager.isKeyDown("gui.getprevioussearch")) {
|
||||
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (focused() && KeyManager.isKeyDown("gui.getnextsearch")) {
|
||||
handleNavigateHistory(TextHistory.Direction.NEXT);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -227,18 +227,24 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lastKeyTyped(int keyID, char keyChar) {
|
||||
public boolean onHotkeyPressed() {
|
||||
|
||||
if (isVisible() && KeyManager.isHashDown("gui.search")) {
|
||||
setFocus(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (focused() && KeyManager.isKeyDown("gui.getprevioussearch")) {
|
||||
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (focused() && KeyManager.isKeyDown("gui.getnextsearch")) {
|
||||
handleNavigateHistory(TextHistory.Direction.NEXT);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -445,7 +445,7 @@ public class SearchTokenParser {
|
||||
final char ch = input.charAt(index);
|
||||
|
||||
if (!insideQuotes && delimiters.indexOf(ch) >= 0
|
||||
&& (!space || index == 0 || input.charAt(index - 1) == ' ')) {
|
||||
&& (!space || index == 0 || input.charAt(index - 1) == ' ' || lastEnd == index)) {
|
||||
|
||||
if (lastEnd == index) {
|
||||
token += String.valueOf(ch);
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import codechicken.lib.packet.PacketCustom;
|
||||
import codechicken.nei.PacketIDs.C2S;
|
||||
|
||||
/**
|
||||
* Waits until the server has processed everything the client sent before. The server handles slot clicks and NEI
|
||||
* packets in the order they came and answers after it has sent the slot updates, so once the answer is here the client
|
||||
* container holds what the server computed.
|
||||
*/
|
||||
public final class ServerSync {
|
||||
|
||||
private static int lastId;
|
||||
private static volatile int awaiting;
|
||||
|
||||
private ServerSync() {}
|
||||
|
||||
public static void request() {
|
||||
|
||||
if (!NEIClientConfig.hasSMPCounterPart()) {
|
||||
awaiting = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
awaiting = ++lastId;
|
||||
new PacketCustom(NEICPH.channel, C2S.SYNC).writeInt(awaiting).sendToServer();
|
||||
}
|
||||
|
||||
public static boolean pending() {
|
||||
return awaiting != 0;
|
||||
}
|
||||
|
||||
static void onReply(int id) {
|
||||
if (id == awaiting) awaiting = 0;
|
||||
}
|
||||
}
|
||||
@@ -160,7 +160,7 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
|
||||
// 1 - partitial hidden
|
||||
// 2 - enabled
|
||||
public int state = 2;
|
||||
public int calculatedWidth;
|
||||
public volatile int calculatedWidth = -1;
|
||||
public final List<ItemStack> items;
|
||||
public final List<SubsetTag> children = new ArrayList<>();
|
||||
protected final SubsetSlot slot = new SubsetSlot();
|
||||
@@ -206,7 +206,7 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
|
||||
this.state = 2;
|
||||
this.items.clear();
|
||||
this.children.clear();
|
||||
this.calculatedWidth = 0;
|
||||
this.calculatedWidth = -1;
|
||||
}
|
||||
|
||||
public void updateVisiblity(int mx, int my) {
|
||||
@@ -261,6 +261,10 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
|
||||
}
|
||||
|
||||
public void resize(Rectangle4i screen, Rectangle4i parent, boolean dropRight) {
|
||||
if (calculatedWidth < 0) {
|
||||
calculatedWidth = this.children.stream().mapToInt(SubsetTag::nameWidth).max().orElse(0);
|
||||
}
|
||||
|
||||
int height = Math.min(slot.contentHeight(), screen.h);
|
||||
int width = Math.max(calculatedWidth + 2, this.items.isEmpty() ? 0 : 16 + MARGIN * 2);
|
||||
int scrollbarWidth = slot.scrollbarDim().width;
|
||||
@@ -686,12 +690,12 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
|
||||
|
||||
for (SubsetTag tag : list) {
|
||||
tag.children.sort(Comparator.comparing(SubsetTag::displayName));
|
||||
tag.calculatedWidth = tag.children.stream().mapToInt(SubsetTag::nameWidth).max().orElse(0);
|
||||
tag.calculatedWidth = -1;
|
||||
}
|
||||
|
||||
root.children.removeIf(child -> child.children.isEmpty() && child.items.isEmpty());
|
||||
root.children.sort(Comparator.comparing(SubsetTag::displayName));
|
||||
root.calculatedWidth = root.children.stream().mapToInt(SubsetTag::nameWidth).max().orElse(0);
|
||||
root.calculatedWidth = -1;
|
||||
|
||||
calculateVisibility(root);
|
||||
} catch (Throwable e) {
|
||||
|
||||
@@ -29,6 +29,10 @@ public abstract class Widget {
|
||||
|
||||
public void lastKeyTyped(int keyID, char keyChar) {}
|
||||
|
||||
public boolean onHotkeyPressed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean handleClickExt(int mx, int my, int button) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -162,6 +162,19 @@ public class WidgetContainer extends Widget {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHotkeyPressed() {
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
if (widget.onHotkeyPressed()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFocused() {
|
||||
return this.isFocused;
|
||||
|
||||
@@ -12,6 +12,7 @@ import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.fluids.Fluid;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
@@ -33,6 +34,7 @@ import codechicken.nei.SubsetWidget.SubsetTag;
|
||||
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
|
||||
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
|
||||
import codechicken.nei.config.Option;
|
||||
import codechicken.nei.item.FluidDrawer;
|
||||
import codechicken.nei.recipe.CatalystInfo;
|
||||
import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
@@ -178,6 +180,8 @@ public class API {
|
||||
|
||||
/**
|
||||
* Add an alias name that this item can be found by in the search field, in addition to its display name.
|
||||
*
|
||||
* @param aliases translation keys, localized at search time
|
||||
*/
|
||||
public static void setAliases(ItemStack item, String... aliases) {
|
||||
final List<String> list = Arrays.asList(aliases).stream().filter(Objects::nonNull).map(String::trim)
|
||||
@@ -375,6 +379,16 @@ public class API {
|
||||
StackInfo.stackStringifyHandlers.add(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the default rendering of a fluid in NEI fluid display slots and fluid tanks.
|
||||
*
|
||||
* @param fluid the fluid to render
|
||||
* @param renderer the renderer, or null to restore the default rendering
|
||||
*/
|
||||
public static void registerFluidRenderer(Fluid fluid, IFluidRenderer renderer) {
|
||||
FluidDrawer.registerFluidRenderer(fluid, renderer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an association between an ingredient and what it can craft. (i.e. Furnace ItemStack -> Smelting and Fuel
|
||||
* Recipes) Allows players to see what ingredient they need to craft in order to make recipes from a recipe
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package codechicken.nei.api;
|
||||
|
||||
import net.minecraftforge.fluids.Fluid;
|
||||
|
||||
/**
|
||||
* Custom renderer for a fluid, used by NEI fluid display slots and fluid tanks in recipes.
|
||||
* <p>
|
||||
* Register with {@link API#registerFluidRenderer(Fluid, IFluidRenderer)}.
|
||||
*/
|
||||
public interface IFluidRenderer {
|
||||
|
||||
/**
|
||||
* Renders one 16x16 tile of the fluid. Partial tiles of a tank are clipped by NEI. The amount overlay is drawn by
|
||||
* NEI.
|
||||
*/
|
||||
void renderFluid(Fluid fluid, int x, int y);
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import java.util.LinkedList;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.config.GuiOptionList;
|
||||
import codechicken.nei.config.OptionCycled;
|
||||
|
||||
public class NEIInfo {
|
||||
@@ -14,11 +13,7 @@ public class NEIInfo {
|
||||
|
||||
public static void load(World world) {
|
||||
OptionCycled modeOption = (OptionCycled) NEIClientConfig.getOptionList().getOption("inventory.cheatmode");
|
||||
final boolean worldConfig = NEIClientConfig.isWorldSpecific("inventory.cheatmode");
|
||||
// kept alive so the WeakReference in Option.slotRef isn't GC'd before copyGlobals/cycle use it
|
||||
GuiOptionList env = modeOption.parent.synthesizeEnvironment(worldConfig);
|
||||
if (!modeOption.optionValid(modeOption.value())) {
|
||||
modeOption.copyGlobals();
|
||||
modeOption.cycle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import codechicken.nei.BookmarkContainerInfo;
|
||||
import codechicken.nei.FavoriteRecipes;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemQuantityField;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.KeyManager;
|
||||
import codechicken.nei.LayoutManager;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
@@ -38,6 +37,7 @@ import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiFavoriteButton;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.GuiUsageRecipe;
|
||||
import codechicken.nei.recipe.HoveredRecipe;
|
||||
import codechicken.nei.recipe.Recipe;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.RecipeHandlerRef;
|
||||
@@ -415,41 +415,37 @@ public abstract class ShortcutInputHandler {
|
||||
|
||||
private static Recipe getFocusedRecipe(ItemStack stackover, int mousex, int mousey, boolean useFavorites) {
|
||||
final GuiContainer gui = NEIClientUtils.getGuiContainer();
|
||||
Recipe recipe = null;
|
||||
|
||||
if (useFavorites) {
|
||||
ItemsGridSlot itemSlot = ItemPanels.itemPanel.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.historyPanel.getSlotMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.craftablesPanel.getSlotMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
if (itemSlot != null) {
|
||||
final RecipeId recipeId = itemSlot.getRecipeId();
|
||||
|
||||
if (recipeId != null && (recipe = Recipe.of(recipeId)) != null) {
|
||||
|
||||
recipe.getIngredients().stream().forEach(ingr -> {
|
||||
final List<ItemStack> permutations = ingr.getPermutations();
|
||||
for (int index = 0; index < permutations.size(); index++) {
|
||||
if (FavoriteRecipes.contains(permutations.get(index))) {
|
||||
ingr.setActiveIndex(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
if (gui instanceof GuiRecipe<?>guiRecipe) {
|
||||
final Recipe focusedRecipe = guiRecipe.getFocusedRecipe();
|
||||
|
||||
if (focusedRecipe != null) {
|
||||
return focusedRecipe;
|
||||
}
|
||||
}
|
||||
|
||||
if (gui instanceof GuiRecipe<?>guiRecipe) {
|
||||
recipe = guiRecipe.getFocusedRecipe();
|
||||
if (!useFavorites) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final HoveredRecipe hovered = HoveredRecipe.of(gui, stackover);
|
||||
|
||||
if (hovered == null || hovered.source != HoveredRecipe.Source.ITEM_PANEL) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Recipe recipe = Recipe.of(hovered.recipeId);
|
||||
|
||||
if (recipe != null) {
|
||||
recipe.getIngredients().stream().forEach(ingr -> {
|
||||
final List<ItemStack> permutations = ingr.getPermutations();
|
||||
for (int index = 0; index < permutations.size(); index++) {
|
||||
if (FavoriteRecipes.contains(permutations.get(index))) {
|
||||
ingr.setActiveIndex(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return recipe;
|
||||
@@ -529,7 +525,9 @@ public abstract class ShortcutInputHandler {
|
||||
}
|
||||
|
||||
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mousex, mousey);
|
||||
final RecipeId recipeId = getHotkeyRecipeId(gui, mousex, mousey, stack, slot);
|
||||
final HoveredRecipe hovered = HoveredRecipe.of(gui, stack);
|
||||
final RecipeId recipeId = hovered == null || hovered.source == HoveredRecipe.Source.OTHER
|
||||
|| hovered.source == HoveredRecipe.Source.BOOKMARK && hovered.favorite ? null : hovered.recipeId;
|
||||
|
||||
if (slot != null) {
|
||||
final BookmarkGroup group = slot.getGroup();
|
||||
@@ -729,36 +727,4 @@ public abstract class ShortcutInputHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private static RecipeId getHotkeyRecipeId(GuiContainer gui, int mousex, int mousey, ItemStack stack,
|
||||
BookmarksGridSlot slot) {
|
||||
|
||||
if (slot != null) {
|
||||
return slot.getType() == BookmarkItemType.INGREDIENT ? null : slot.getRecipeId();
|
||||
}
|
||||
|
||||
ItemsGridSlot itemSlot = ItemPanels.itemPanel.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.historyPanel.getSlotMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.craftablesPanel.getSlotMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
if (itemSlot != null) {
|
||||
return itemSlot.getRecipeId();
|
||||
}
|
||||
|
||||
if (gui instanceof GuiRecipe<?>guiRecipe) {
|
||||
final Recipe focusedRecipe = guiRecipe.getFocusedRecipe();
|
||||
|
||||
if (focusedRecipe != null) {
|
||||
return focusedRecipe.getRecipeId();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import static org.objectweb.asm.Opcodes.ILOAD;
|
||||
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
|
||||
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
|
||||
import static org.objectweb.asm.Opcodes.IRETURN;
|
||||
import static org.objectweb.asm.Opcodes.NEW;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -22,11 +23,14 @@ import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.TypeInsnNode;
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
|
||||
import codechicken.lib.asm.ASMBlock;
|
||||
@@ -98,6 +102,48 @@ public class NEITransformer implements IClassTransformer {
|
||||
}
|
||||
});
|
||||
|
||||
if (Boolean.getBoolean("nei.recipeOrigins")) {
|
||||
// Replace the plain ArrayList CraftingManager's constructor builds its recipe list with, so every recipe
|
||||
// added anywhere (including vanilla's own, added in that same constructor) is observed for
|
||||
// codechicken.nei.recipe.debug.RecipeOrigins. Must be done at classload time, since by the time any mod
|
||||
// code runs vanilla has already populated the list. Capturing a stack trace per recipe is slow, so this is
|
||||
// opt-in via -Dnei.recipeOrigins=true.
|
||||
transformer.add(
|
||||
new MethodTransformer(
|
||||
new ObfMapping("net/minecraft/item/crafting/CraftingManager", "<init>", "()V")) {
|
||||
|
||||
@Override
|
||||
public void transform(MethodNode mv) {
|
||||
ASMHelper.logger.debug("NEI: Hooking CraftingManager recipe list for origin tracking");
|
||||
|
||||
TypeInsnNode newInsn = null;
|
||||
MethodInsnNode initInsn = null;
|
||||
|
||||
// only the first ArrayList construction, the recipe list field
|
||||
for (AbstractInsnNode insn : mv.instructions.toArray()) {
|
||||
if (newInsn == null) {
|
||||
if (insn.getOpcode() == NEW
|
||||
&& "java/util/ArrayList".equals(((TypeInsnNode) insn).desc)) {
|
||||
newInsn = (TypeInsnNode) insn;
|
||||
}
|
||||
} else if (insn.getOpcode() == INVOKESPECIAL
|
||||
&& "java/util/ArrayList".equals(((MethodInsnNode) insn).owner)
|
||||
&& "<init>".equals(((MethodInsnNode) insn).name)) {
|
||||
initInsn = (MethodInsnNode) insn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newInsn == null || initInsn == null) {
|
||||
ASMHelper.logger.warn("NEI: CraftingManager recipe list not found, origins disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
newInsn.desc = initInsn.owner = "codechicken/nei/recipe/debug/RecipeOrigins$TrackingList";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// put glint alpha into the buffer correctly for exporting
|
||||
transformer.add(
|
||||
new MethodReplacer(
|
||||
|
||||
@@ -452,8 +452,9 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
|
||||
if (!this.isEmpty() && this.gridGenerator.maxAbsoluteSlotIndex > 0) {
|
||||
final GroupingItem groupingItem = ItemPanels.bookmarkPanel.groupingItem;
|
||||
final int sortableGroupId = ItemPanels.bookmarkPanel.sortableGroup != null
|
||||
? ItemPanels.bookmarkPanel.sortableGroup.groupId
|
||||
: -3;
|
||||
&& ItemPanels.bookmarkPanel.sortableGroup.grid == this
|
||||
? ItemPanels.bookmarkPanel.sortableGroup.groupId
|
||||
: -3;
|
||||
final int rowShift = this.page * this.rows;
|
||||
Map<Integer, Integer> groups = this.gridGenerator.rowToGroupId;
|
||||
|
||||
@@ -795,10 +796,10 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
|
||||
this.bookmarkItems.add(item);
|
||||
}
|
||||
|
||||
sortableGroup.grid = this;
|
||||
sortableGroup.groupId = groupId;
|
||||
sortableGroup.update(this, groupId);
|
||||
this.onItemsChanged();
|
||||
this.getMask();// force generate grid
|
||||
overGroupId = getRowGroupId(overRowIndex);
|
||||
}
|
||||
|
||||
if (sortableGroup.groupId == overGroupId) {
|
||||
@@ -1284,7 +1285,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
|
||||
for (BookmarksGridSlot slot : getMask()) {
|
||||
Rectangle4i rect = getSlotRect(slot.slotIndex);
|
||||
|
||||
if (sortableGroup != null && slot.getGroupId() == sortableGroup.groupId) {
|
||||
if (sortableGroup != null && sortableGroup.matches(this, slot.getGroupId())) {
|
||||
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, DRAG_COLOR);
|
||||
} else if (sortableItem != null && sortableItem.items.contains(slot.itemIndex)) {
|
||||
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, DRAG_COLOR);
|
||||
@@ -1313,7 +1314,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
|
||||
final SortableItem sortableItem = LayoutManager.bookmarkPanel.sortableItem;
|
||||
|
||||
for (BookmarksGridSlot slot : getMask()) {
|
||||
if ((sortableGroup == null || slot.getGroupId() != sortableGroup.groupId)
|
||||
if ((sortableGroup == null || !sortableGroup.matches(this, slot.getGroupId()))
|
||||
&& (sortableItem == null || !sortableItem.items.contains(slot.itemIndex))) {
|
||||
slot.afterDraw(getSlotRect(slot.slotIndex), mouseContext);
|
||||
}
|
||||
@@ -1330,7 +1331,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
|
||||
|
||||
for (BookmarksGridSlot slot : getMask()) {
|
||||
|
||||
if ((sortableGroup == null || slot.getGroupId() != sortableGroup.groupId)
|
||||
if ((sortableGroup == null || !sortableGroup.matches(this, slot.getGroupId()))
|
||||
&& (sortableItem == null || !sortableItem.items.contains(slot.itemIndex))) {
|
||||
final BookmarkItem item = slot.getBookmarkItem();
|
||||
|
||||
|
||||
@@ -340,7 +340,8 @@ public class BookmarkGridGenerator {
|
||||
0,
|
||||
chainItem.getItem(),
|
||||
null,
|
||||
group);
|
||||
group,
|
||||
this.grid);
|
||||
} else {
|
||||
return new BookmarksGridSlot(
|
||||
slotIndex,
|
||||
@@ -350,7 +351,8 @@ public class BookmarkGridGenerator {
|
||||
chainItem.getCalculatedMultiplier(),
|
||||
chainItem.getItem(),
|
||||
chainItem.calculatedType,
|
||||
group);
|
||||
group,
|
||||
this.grid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ public class BookmarkItem {
|
||||
private static synchronized String getItemGUID(ItemStack stack) {
|
||||
final FluidStack fluidStack = StackInfo.getFluid(stack);
|
||||
|
||||
if (fluidStack != null) {
|
||||
if (fluidStack != null && (fluidStack.amount > 0 || !StackInfo.isFluidContainer(stack))) {
|
||||
return fluidStack.getFluid().getName() + ":" + fluidStack.tag;
|
||||
} else {
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.util.NBTJson;
|
||||
@@ -79,10 +80,21 @@ public class BookmarkStorage {
|
||||
|
||||
public int getNamespaceSize() {
|
||||
|
||||
if (this.namespaces.get(this.namespaces.size() - 1).size() > 0) {
|
||||
this.namespaces.add(new BookmarkGrid());
|
||||
} else if (this.activeNamespaceIndex == this.namespaces.size() - 2 && getActiveGrid().size() == 0) {
|
||||
this.namespaces.remove(this.namespaces.size() - 1);
|
||||
final int lastIndex = this.namespaces.size() - 1;
|
||||
final BookmarkGrid lastGrid = this.namespaces.get(lastIndex);
|
||||
final SortableGroup sortableGroup = ItemPanels.bookmarkPanel.sortableGroup;
|
||||
|
||||
if (lastGrid.size() > 0) {
|
||||
if (sortableGroup == null || sortableGroup.grid != lastGrid || !sortableGroup.aloneInGrid) {
|
||||
this.namespaces.add(new BookmarkGrid());
|
||||
}
|
||||
} else if (lastIndex > 0 && this.activeNamespaceIndex != lastIndex) {
|
||||
final BookmarkGrid prevGrid = this.namespaces.get(lastIndex - 1);
|
||||
|
||||
if (sortableGroup != null && sortableGroup.grid == prevGrid && sortableGroup.aloneInGrid
|
||||
|| prevGrid == getActiveGrid() && prevGrid.size() == 0) {
|
||||
this.namespaces.remove(lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return this.namespaces.size();
|
||||
@@ -198,6 +210,11 @@ public class BookmarkStorage {
|
||||
final BookmarkItem item = BookmarkItem.of(parser.parse(itemStr).getAsJsonObject());
|
||||
|
||||
if (item != null) {
|
||||
|
||||
if (!grid.groups.containsKey(item.groupId)) {
|
||||
item.groupId = BookmarkGrid.DEFAULT_GROUP_ID;
|
||||
}
|
||||
|
||||
grid.addItem(item, false);
|
||||
} else {
|
||||
wasError = true;
|
||||
|
||||
@@ -8,7 +8,6 @@ import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.ItemsGrid.MouseContext;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
@@ -65,7 +64,8 @@ public class BookmarksGridSlot extends ItemsGridSlot {
|
||||
protected final int rowIndex;
|
||||
|
||||
public BookmarksGridSlot(int slotIndex, int itemIndex, long realMultiplier, long shiftAmount,
|
||||
long calculatedMultiplier, BookmarkItem bookmarkItem, CalculatedType calculatedType, BookmarkGroup group) {
|
||||
long calculatedMultiplier, BookmarkItem bookmarkItem, CalculatedType calculatedType, BookmarkGroup group,
|
||||
BookmarkGrid grid) {
|
||||
super(
|
||||
slotIndex,
|
||||
itemIndex,
|
||||
@@ -96,7 +96,6 @@ public class BookmarksGridSlot extends ItemsGridSlot {
|
||||
: CalculatedType.RESULT;
|
||||
}
|
||||
|
||||
final BookmarkGrid grid = ItemPanels.bookmarkPanel.getGrid();
|
||||
final BookmarkItem prevItem = grid.getCalculatedItem(
|
||||
grid.gridGenerator.slotToItem.getOrDefault(grid.gridGenerator.itemToSlot.get(this.itemIndex) - 1, -1));
|
||||
this.isFirstOutput = this.itemIndex >= 0 && this.bookmarkItem.type == BookmarkItemType.RESULT
|
||||
|
||||
@@ -13,13 +13,23 @@ public class SortableGroup {
|
||||
|
||||
public int groupId;
|
||||
public BookmarkGrid grid;
|
||||
public boolean aloneInGrid;
|
||||
|
||||
public int shiftX = 0;
|
||||
public int shiftY = 0;
|
||||
|
||||
public SortableGroup(BookmarkGrid grid, int groupId) {
|
||||
update(grid, groupId);
|
||||
}
|
||||
|
||||
public void update(BookmarkGrid grid, int groupId) {
|
||||
this.grid = grid;
|
||||
this.groupId = groupId;
|
||||
this.aloneInGrid = grid.bookmarkItems.stream().allMatch(item -> item.groupId == groupId);
|
||||
}
|
||||
|
||||
public boolean matches(BookmarkGrid grid, int groupId) {
|
||||
return this.grid == grid && this.groupId == groupId;
|
||||
}
|
||||
|
||||
public void postDraw(int mousex, int mousey) {
|
||||
|
||||
@@ -2,6 +2,8 @@ package codechicken.nei.bookmark.tree;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
class Camera {
|
||||
|
||||
private static final float ZOOM_MIN = 0.1f;
|
||||
@@ -39,23 +41,34 @@ class Camera {
|
||||
&& y < this.widgetY + this.widgetH;
|
||||
}
|
||||
|
||||
public void startDrag(int mouseX, int mouseY) {
|
||||
public void startDrag(Point2D mouse) {
|
||||
this.dragging = true;
|
||||
this.lastDragX = mouseX;
|
||||
this.lastDragY = mouseY;
|
||||
this.lastDragX = (float) mouse.getX();
|
||||
this.lastDragY = (float) mouse.getY();
|
||||
}
|
||||
|
||||
public void drag(int mouseX, int mouseY) {
|
||||
public void drag(Point2D mouse) {
|
||||
if (!this.dragging) {
|
||||
return;
|
||||
}
|
||||
|
||||
final float mouseX = (float) mouse.getX();
|
||||
final float mouseY = (float) mouse.getY();
|
||||
|
||||
this.scrollX -= (mouseX - this.lastDragX) / this.zoomLevel;
|
||||
this.scrollY -= (mouseY - this.lastDragY) / this.zoomLevel;
|
||||
this.lastDragX = mouseX;
|
||||
this.lastDragY = mouseY;
|
||||
}
|
||||
|
||||
public void update(Point2D mouse, int treeWidth, int treeHeight) {
|
||||
if (this.dragging && Mouse.isButtonDown(0)) {
|
||||
drag(mouse);
|
||||
}
|
||||
|
||||
clampToBounds(treeWidth, treeHeight);
|
||||
}
|
||||
|
||||
public void endDrag() {
|
||||
this.dragging = false;
|
||||
}
|
||||
@@ -79,7 +92,6 @@ class Camera {
|
||||
} else {
|
||||
this.scrollY -= direction * this.widgetH / (SCROLL_STEP_DIVISOR * this.zoomLevel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void centerOn(float worldX, float worldY) {
|
||||
|
||||
@@ -142,7 +142,11 @@ class CraftingTreeCanvas {
|
||||
public int treeWidth = 0;
|
||||
public int treeHeight = 0;
|
||||
|
||||
private final Camera camera = new Camera();
|
||||
private final Camera camera;
|
||||
|
||||
public CraftingTreeCanvas(Camera camera) {
|
||||
this.camera = camera;
|
||||
}
|
||||
|
||||
public void setViewport(int x, int y, int w, int h) {
|
||||
this.camera.setViewport(x, y, w, h);
|
||||
@@ -165,12 +169,12 @@ class CraftingTreeCanvas {
|
||||
: -FIT_MARGIN;
|
||||
}
|
||||
|
||||
public void startDrag(int mouseX, int mouseY) {
|
||||
this.camera.startDrag(mouseX, mouseY);
|
||||
public void startDrag(Point2D mouse) {
|
||||
this.camera.startDrag(mouse);
|
||||
}
|
||||
|
||||
public void drag(int mouseX, int mouseY) {
|
||||
this.camera.drag(mouseX, mouseY);
|
||||
public void drag(Point2D mouse) {
|
||||
this.camera.drag(mouse);
|
||||
}
|
||||
|
||||
public void endDrag() {
|
||||
@@ -255,7 +259,7 @@ class CraftingTreeCanvas {
|
||||
|
||||
public void draw(Point2D mouse, Set<BookmarkItem> collapsedItems, SearchResult searchResult,
|
||||
boolean useInventorySnapshot, ItemTreeSlot hoveredNode, ItemTreeSlot deleteHoverNode) {
|
||||
this.camera.clampToBounds(this.treeWidth, this.treeHeight);
|
||||
this.camera.update(mouse, this.treeWidth, this.treeHeight);
|
||||
|
||||
final float zScrollX = this.camera.scrollX * this.camera.zoomLevel;
|
||||
final float zScrollY = this.camera.scrollY * this.camera.zoomLevel;
|
||||
|
||||
@@ -2,9 +2,12 @@ package codechicken.nei.bookmark.tree;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.bookmark.BookmarkGroup;
|
||||
import codechicken.nei.bookmark.BookmarkItem;
|
||||
|
||||
class CraftingTreeState {
|
||||
@@ -25,6 +28,8 @@ class CraftingTreeState {
|
||||
HANDLERS
|
||||
}
|
||||
|
||||
private static final Map<BookmarkGroup, CraftingTreeState> GROUP_STATES = new WeakHashMap<>();
|
||||
|
||||
private static final String KEY_STATS_VISIBLE = "craftingTree.statsVisible";
|
||||
private static final String KEY_STATS_SECTIONS = "craftingTree.statsSections";
|
||||
private static final String KEY_USE_INVENTORY_SNAPSHOT = "craftingTree.useInventorySnapshot";
|
||||
@@ -35,6 +40,8 @@ class CraftingTreeState {
|
||||
public boolean useInventorySnapshot = false;
|
||||
public CollapseMode collapseMode = CollapseMode.EXPANDED;
|
||||
|
||||
public boolean initialized;
|
||||
public final Camera camera = new Camera();
|
||||
public final Set<BookmarkItem> collapsedItems = new HashSet<>();
|
||||
public ItemTreeSlot replaceRecipeNode;
|
||||
|
||||
@@ -65,6 +72,9 @@ class CraftingTreeState {
|
||||
? collapseModes[savedCollapseMode]
|
||||
: CollapseMode.EXPANDED;
|
||||
this.replaceRecipeNode = null;
|
||||
this.searchItemResult = null;
|
||||
this.searchStatsResult = null;
|
||||
this.camera.endDrag();
|
||||
}
|
||||
|
||||
public void toggleStatsPanelVisible() {
|
||||
@@ -98,6 +108,10 @@ class CraftingTreeState {
|
||||
NEIClientConfig.world.nbt.setInteger(KEY_COLLAPSE_MODE, this.collapseMode.ordinal());
|
||||
}
|
||||
|
||||
public static CraftingTreeState of(BookmarkGroup group) {
|
||||
return GROUP_STATES.computeIfAbsent(group, g -> new CraftingTreeState());
|
||||
}
|
||||
|
||||
public SearchResult activeSearchResult() {
|
||||
return this.searchItemResult != null ? this.searchItemResult : this.searchStatsResult;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
@@ -40,6 +39,7 @@ import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.KeyManager;
|
||||
import codechicken.nei.LRUCache;
|
||||
import codechicken.nei.NEICPH;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.SearchField.GuiSearchField;
|
||||
@@ -58,6 +58,7 @@ import codechicken.nei.drawable.DrawableResource;
|
||||
import codechicken.nei.guihook.IContainerTooltipHandler;
|
||||
import codechicken.nei.guihook.IGuiClientSide;
|
||||
import codechicken.nei.guihook.IGuiHandleMouseWheel;
|
||||
import codechicken.nei.guihook.IGuiHotkeyListener;
|
||||
import codechicken.nei.recipe.AcceptsFollowingTooltipLineHandler;
|
||||
import codechicken.nei.recipe.AutoCraftingManager;
|
||||
import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
@@ -67,6 +68,7 @@ import codechicken.nei.recipe.GuiRecipeButton.UpdateRecipeButtonsEvent;
|
||||
import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import codechicken.nei.recipe.Recipe;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.RecipeItemsTooltipLineHandler;
|
||||
import codechicken.nei.recipe.RecipeTooltipLineHandler;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.EmptyContainer;
|
||||
@@ -76,7 +78,7 @@ import codechicken.nei.util.SlotInaccessible;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGuiClientSide, IGuiHandleMouseWheel,
|
||||
IContainerTooltipHandler, IGuiContainerOverlay {
|
||||
IGuiHotkeyListener, IContainerTooltipHandler, IGuiContainerOverlay {
|
||||
|
||||
public static class EventHandler {
|
||||
|
||||
@@ -101,24 +103,23 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
}
|
||||
}
|
||||
|
||||
private static final int MARGIN = 4;
|
||||
private static final int PADDING = 9;
|
||||
private static final int PADDING_TOP = 22;
|
||||
|
||||
private static final DrawableResource BG_TEXTURE = new DrawableBuilder(
|
||||
"nei:textures/gui/craftingtree.png",
|
||||
0,
|
||||
0,
|
||||
64,
|
||||
64).build();
|
||||
64).setSlices(PADDING, PADDING, PADDING_TOP, PADDING).build();
|
||||
|
||||
private static final DateTimeFormatter SCREENSHOT_DATE_FORMAT = DateTimeFormatter
|
||||
.ofPattern("yyyy-MM-dd_HH.mm.ss", Locale.ROOT);
|
||||
|
||||
private static final int MARGIN = 4;
|
||||
private static final int PADDING = 9;
|
||||
private static final int PADDING_TOP = 22;
|
||||
|
||||
private static LRUCache<String, String> handlerTitleCache = new LRUCache<>(100);
|
||||
private final LRUCache<String, String> handlerTitleCache = new LRUCache<>(100);
|
||||
|
||||
private GuiScreen prevGui;
|
||||
private boolean isFirstScreen = true;
|
||||
|
||||
private final BookmarkGrid grid;
|
||||
private final int groupId;
|
||||
@@ -127,15 +128,16 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
|
||||
private final StatsPanel statsPanel = new StatsPanel();
|
||||
private final StatsSectionsMenu statsSectionsMenu = new StatsSectionsMenu();
|
||||
private final CraftingTreeCanvas canvas = new CraftingTreeCanvas();
|
||||
private final CraftingTreeCanvas canvas;
|
||||
private boolean statsPanelVisible;
|
||||
|
||||
private GuiSearchField searchField;
|
||||
|
||||
private RecipeTooltipLineHandler recipeTooltipLineHandler;
|
||||
private AcceptsFollowingTooltipLineHandler acceptsFollowingTooltipLineHandler;
|
||||
private RecipeItemsTooltipLineHandler recipeItemsTooltipLineHandler;
|
||||
|
||||
private final CraftingTreeState uiState = new CraftingTreeState();
|
||||
private final CraftingTreeState uiState;
|
||||
private final CraftingTreeToolbar toolbar;
|
||||
|
||||
private ItemTreeSlot hoveredNode;
|
||||
@@ -147,6 +149,8 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
this.grid = grid;
|
||||
this.groupId = groupId;
|
||||
|
||||
this.uiState = CraftingTreeState.of(grid.getGroup(groupId));
|
||||
this.canvas = new CraftingTreeCanvas(this.uiState.camera);
|
||||
this.toolbar = new CraftingTreeToolbar(this.uiState);
|
||||
}
|
||||
|
||||
@@ -159,7 +163,7 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
final ItemTreeSlot replaceNode = this.uiState.replaceRecipeNode;
|
||||
this.uiState.replaceRecipeNode = null;
|
||||
|
||||
if (recipe != null) {
|
||||
if (recipe != null && this.grid.getGroup(this.groupId) != null) {
|
||||
final RecipeId recipeId = recipe.getRecipeId();
|
||||
boolean changed = false;
|
||||
|
||||
@@ -187,6 +191,13 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
|
||||
// the group can be removed from the bookmark panel while a recipe screen opened from this tree is shown
|
||||
if (this.grid.getGroup(this.groupId) == null) {
|
||||
this.mc.displayGuiScreen(this.prevGui);
|
||||
return;
|
||||
}
|
||||
|
||||
this.xSize = this.width;
|
||||
this.ySize = this.height;
|
||||
|
||||
@@ -283,7 +294,7 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
|
||||
this.canvas.graph.rebuild(this.math);
|
||||
|
||||
if (this.isFirstScreen) {
|
||||
if (!this.uiState.initialized) {
|
||||
updateCollapsedItems();
|
||||
} else {
|
||||
this.canvas.recalculateCoordinates(this.collapsedRecipes, this.uiState.collapsedItems, anchor);
|
||||
@@ -291,8 +302,8 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
|
||||
rebuildStatsPanel();
|
||||
|
||||
if (this.isFirstScreen) {
|
||||
this.isFirstScreen = false;
|
||||
if (!this.uiState.initialized) {
|
||||
this.uiState.initialized = true;
|
||||
this.canvas.fitToView();
|
||||
}
|
||||
}
|
||||
@@ -328,15 +339,7 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
this.hoveredNode = canHover && hoveredBadgeHandler == null ? this.canvas.getNodeMouseOver(getMousePosition())
|
||||
: null;
|
||||
|
||||
BG_TEXTURE.draw(
|
||||
MARGIN,
|
||||
MARGIN,
|
||||
this.width - MARGIN * 2,
|
||||
this.height - MARGIN * 2,
|
||||
PADDING,
|
||||
PADDING,
|
||||
PADDING_TOP,
|
||||
PADDING);
|
||||
BG_TEXTURE.draw(MARGIN, MARGIN, this.width - MARGIN * 2, this.height - MARGIN * 2);
|
||||
|
||||
if (this.math.outputRecipes.isEmpty()) {
|
||||
drawCenteredString(
|
||||
@@ -755,7 +758,7 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
return true;
|
||||
}
|
||||
|
||||
this.canvas.startDrag(mouseX, mouseY);
|
||||
this.canvas.startDrag(getMousePosition());
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -776,7 +779,7 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
|
||||
}
|
||||
|
||||
this.canvas.drag(mouseX, mouseY);
|
||||
this.canvas.drag(getMousePosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -841,7 +844,7 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
(int) mouse.getY(),
|
||||
direction,
|
||||
NEIClientUtils.shiftKey(),
|
||||
NEIClientUtils.controlKey());
|
||||
NEIClientUtils.controlKey() || NEIClientConfig.craftingTreeZoomWithoutModifier());
|
||||
}
|
||||
|
||||
private boolean handleItemWheel(int wheel, Point2D mouse) {
|
||||
@@ -903,6 +906,18 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
}
|
||||
}
|
||||
|
||||
if (keyCode == this.mc.gameSettings.keyBindInventory.getKeyCode()) {
|
||||
this.mc.displayGuiScreen(this.prevGui);
|
||||
NEICPH.sendRequestContainer();
|
||||
return;
|
||||
}
|
||||
|
||||
super.keyTyped(typedChar, keyCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHotkeyPressed() {
|
||||
|
||||
if (this.statsPanelVisible && KeyManager.isKeyDown("recipe.recipe")) {
|
||||
final Point2D mouse = getMousePosition();
|
||||
final Widget widget = this.statsPanel.getWidgetUnderMouse((int) mouse.getX(), (int) mouse.getY());
|
||||
@@ -910,22 +925,15 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
if (widget != null && widget instanceof StatsPanel.ItemStatsSlot itemStatsSlot
|
||||
&& itemStatsSlot.recipeId != null) {
|
||||
GuiCraftingRecipe.openRecipeGui("recipeId", itemStatsSlot.recipeId.getResult(), itemStatsSlot.recipeId);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
super.keyTyped(typedChar, keyCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String getHandlerTitle(String handlerName) {
|
||||
return handlerTitleCache.computeIfAbsent(
|
||||
handlerName,
|
||||
hname -> Stream
|
||||
.concat(
|
||||
GuiCraftingRecipe.craftinghandlers.stream(),
|
||||
GuiCraftingRecipe.serialCraftingHandlers.stream())
|
||||
.filter(handler -> hname.equals(GuiRecipeTab.getHandlerInfo(handler).getHandlerName()))
|
||||
.findFirst().map(handler -> handler.getRecipeName().trim()).orElse(hname));
|
||||
private String getHandlerTitle(String handlerName) {
|
||||
return this.handlerTitleCache.computeIfAbsent(handlerName, GuiRecipeTab::getHandlerTitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -939,12 +947,15 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
if (toolbarTooltip != null) {
|
||||
currenttip.add(toolbarTooltip);
|
||||
} else if (this.hoveredBadgeHandler != null) {
|
||||
final RecipeId recipeId = this.hoveredBadgeHandler.prefItem != null
|
||||
? this.hoveredBadgeHandler.prefItem.recipeId
|
||||
: null;
|
||||
final long multiplier = this.hoveredBadgeHandler.multiplier;
|
||||
final ItemTreeSlot node = this.hoveredBadgeHandler;
|
||||
final RecipeId recipeId = node.prefItem != null ? node.prefItem.recipeId : null;
|
||||
|
||||
if (recipeId != null && NEIClientUtils.shiftKey()) {
|
||||
addRecipeItemsTooltipLine(recipeId, node.multiplier, currenttip);
|
||||
} else {
|
||||
addRecipeTooltipLine(recipeId, node.multiplier, currenttip);
|
||||
}
|
||||
|
||||
addRecipeTooltipLine(recipeId, multiplier, currenttip);
|
||||
} else {
|
||||
|
||||
if (this.statsPanelVisible) {
|
||||
@@ -960,6 +971,14 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
EnumChatFormatting.GRAY + NEIClientUtils.translate(
|
||||
"bookmark.tree.stats.handler_iterations",
|
||||
handlerStatsSlot.stats.iterations));
|
||||
} else if (widget instanceof StatsPanel.ItemStatsSlot itemStatsSlot && itemStatsSlot.recipeId != null) {
|
||||
if (NEIClientUtils.shiftKey()) {
|
||||
addRecipeItemsTooltipLine(itemStatsSlot.recipeId, itemStatsSlot.multiplier, currenttip);
|
||||
} else {
|
||||
currenttip.add(itemStatsSlot.stack.getDisplayName() + GuiDraw.TOOLTIP_LINESPACE);
|
||||
|
||||
addRecipeTooltipLine(itemStatsSlot.recipeId, itemStatsSlot.multiplier, currenttip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,6 +987,19 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
private void addRecipeItemsTooltipLine(RecipeId recipeId, long multiplier, List<String> currenttip) {
|
||||
|
||||
if (this.recipeItemsTooltipLineHandler == null
|
||||
|| this.recipeItemsTooltipLineHandler.getMultiplier() != multiplier
|
||||
|| !this.recipeItemsTooltipLineHandler.getRecipeId().equals(recipeId)) {
|
||||
this.recipeItemsTooltipLineHandler = new RecipeItemsTooltipLineHandler(recipeId, multiplier)
|
||||
.setUseInventory(true);
|
||||
}
|
||||
|
||||
currenttip.add(this.recipeItemsTooltipLineHandler.getTitle() + GuiDraw.TOOLTIP_LINESPACE);
|
||||
currenttip.add(GuiDraw.TOOLTIP_HANDLER + GuiDraw.getTipLineId(this.recipeItemsTooltipLineHandler));
|
||||
}
|
||||
|
||||
private void addRecipeTooltipLine(RecipeId recipeId, long multiplier, List<String> currenttip) {
|
||||
|
||||
if (recipeId == null) {
|
||||
@@ -1078,14 +1110,6 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
|
||||
} else {
|
||||
this.acceptsFollowingTooltipLineHandler = null;
|
||||
|
||||
if (this.statsPanelVisible) {
|
||||
final Widget widget = this.statsPanel.getWidgetUnderMouse(mousex, mousey);
|
||||
if (widget instanceof StatsPanel.ItemStatsSlot itemStatsSlot) {
|
||||
addRecipeTooltipLine(itemStatsSlot.recipeId, itemStatsSlot.multiplier, currenttip);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return currenttip;
|
||||
|
||||
@@ -3,6 +3,7 @@ package codechicken.nei.bookmark.tree;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -88,6 +89,10 @@ class StatsPanel extends ScrollContainer {
|
||||
this(stack, stackSize, icon, null, 1);
|
||||
}
|
||||
|
||||
public ItemStack getStack() {
|
||||
return StackInfo.withAmount(this.stack, stackSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mx, int my) {
|
||||
|
||||
@@ -118,7 +123,7 @@ class StatsPanel extends ScrollContainer {
|
||||
|
||||
GL11.glPushMatrix();
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
GL11.glTranslatef(badgeX, y - 6 * scale, 3.0f);
|
||||
GL11.glTranslatef(badgeX, y - 6 * scale, 10.0f);
|
||||
GL11.glScalef(scale, scale, 1.0f);
|
||||
|
||||
if (this.info.hasImageOrItem()) {
|
||||
@@ -237,7 +242,7 @@ class StatsPanel extends ScrollContainer {
|
||||
26,
|
||||
84,
|
||||
46,
|
||||
16).build();
|
||||
16).setSlices(0, 0, 2, 0).build();
|
||||
|
||||
private static final DrawableResource SLOT_DEFAULT = new DrawableBuilder(
|
||||
"nei:textures/gui/craftingtree.png",
|
||||
@@ -285,8 +290,8 @@ class StatsPanel extends ScrollContainer {
|
||||
|
||||
public StatsPanel() {
|
||||
final ScrollBar scrollbar = new ScrollBar().setTrackWidth(4)
|
||||
.setThumbTexture(new DrawableBuilder("nei:textures/gui/craftingtree.png", 26, 100, 24, 4).build(), 0, 0)
|
||||
.setTrackTexture(new DrawableBuilder("nei:textures/gui/craftingtree.png", 26, 104, 24, 4).build(), 0, 0)
|
||||
.setThumbTexture(new DrawableBuilder("nei:textures/gui/craftingtree.png", 26, 100, 24, 4).build())
|
||||
.setTrackTexture(new DrawableBuilder("nei:textures/gui/craftingtree.png", 26, 104, 24, 4).build())
|
||||
.setTrackPadding(1, -5, 1, 0).setOverflowType(ScrollBar.OverflowType.AUTO);
|
||||
|
||||
setHorizontalScroll(scrollbar);
|
||||
@@ -519,7 +524,7 @@ class StatsPanel extends ScrollContainer {
|
||||
|
||||
public ItemStack getStackMouseOver(int mouseX, int mouseY) {
|
||||
final Widget widget = getWidgetUnderMouse(mouseX, mouseY);
|
||||
return widget instanceof ItemStatsSlot slot ? slot.stack : null;
|
||||
return widget instanceof ItemStatsSlot slot && slot.recipeId == null ? slot.getStack() : null;
|
||||
}
|
||||
|
||||
public void setHighlight(SearchResult searchResult) {
|
||||
@@ -584,7 +589,7 @@ class StatsPanel extends ScrollContainer {
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
|
||||
BG_TEXTURE.draw(this.x, this.y, this.w, this.h, 0, 0, 2, 0);
|
||||
BG_TEXTURE.draw(this.x, this.y, this.w, this.h);
|
||||
|
||||
super.draw(mouseX, mouseY);
|
||||
|
||||
@@ -711,8 +716,14 @@ class StatsPanel extends ScrollContainer {
|
||||
private List<Widget> collectHandlers(RecipeChainMath math) {
|
||||
final Map<String, HandlerStats> handlerStats = new HashMap<>();
|
||||
final List<Widget> widgets = new ArrayList<>();
|
||||
final Set<RecipeId> countedRecipes = new HashSet<>();
|
||||
|
||||
for (BookmarkItem item : math.recipeResults) {
|
||||
// a recipe adds one result item per output, count it only once
|
||||
if (!countedRecipes.add(item.recipeId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final HandlerStats stats = handlerStats
|
||||
.computeIfAbsent(item.recipeId.getHandlerName(), k -> new HandlerStats());
|
||||
stats.iterations += item.getMultiplier();
|
||||
|
||||
@@ -13,6 +13,10 @@ public class ConfigSet {
|
||||
public NBTTagCompound nbt;
|
||||
public final ConfigTagParent config;
|
||||
|
||||
public ConfigSet(File nbtFile) {
|
||||
this(nbtFile, null);
|
||||
}
|
||||
|
||||
public ConfigSet(File nbtFile, ConfigTagParent config) {
|
||||
this.nbtFile = nbtFile;
|
||||
this.config = config;
|
||||
|
||||
@@ -110,7 +110,7 @@ public abstract class DataDumper extends Option {
|
||||
}
|
||||
|
||||
public int getMode() {
|
||||
return renderTag().getIntValue(0);
|
||||
return getTag().getIntValue(0);
|
||||
}
|
||||
|
||||
public void drawButton(int mousex, int mousey, Rectangle4i b, String text) {
|
||||
|
||||
@@ -29,7 +29,6 @@ public class GuiHighlightTips extends GuiScreenWidget {
|
||||
private GuiCCButton toggleButton;
|
||||
private final Option opt;
|
||||
private final GuiOptionList parentGui;
|
||||
private final boolean world;
|
||||
private Point dragDown;
|
||||
|
||||
public GuiHighlightTips(Option opt) {
|
||||
@@ -37,7 +36,6 @@ public class GuiHighlightTips extends GuiScreenWidget {
|
||||
this.opt = opt;
|
||||
name = opt.name;
|
||||
this.parentGui = (GuiOptionList) Minecraft.getMinecraft().currentScreen;
|
||||
this.world = parentGui.worldConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,15 +61,11 @@ public class GuiHighlightTips extends GuiScreenWidget {
|
||||
}
|
||||
|
||||
private boolean show() {
|
||||
return renderTag(name).getBooleanValue();
|
||||
return getTag(name).getBooleanValue();
|
||||
}
|
||||
|
||||
private ConfigTag getTag(String s) {
|
||||
return (world ? opt.worldConfigSet() : opt.globalConfigSet()).config.getTag(s);
|
||||
}
|
||||
|
||||
private ConfigTag renderTag(String s) {
|
||||
return (world && opt.worldSpecific(s) ? opt.worldConfigSet() : opt.globalConfigSet()).config.getTag(s);
|
||||
return opt.configSet().config.getTag(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -95,7 +89,7 @@ public class GuiHighlightTips extends GuiScreenWidget {
|
||||
}
|
||||
|
||||
public Point getPos() {
|
||||
return new Point(renderTag(name + ".x").getIntValue(), renderTag(name + ".y").getIntValue());
|
||||
return new Point(getTag(name + ".x").getIntValue(), getTag(name + ".y").getIntValue());
|
||||
}
|
||||
|
||||
public Dimension sampleSize() // copied from HUDManager when running with the sample for this gui
|
||||
@@ -161,7 +155,6 @@ public class GuiHighlightTips extends GuiScreenWidget {
|
||||
}
|
||||
|
||||
private void setPos(Point p) {
|
||||
getTag(name).setBooleanValue(show()); // duplicates global tag for the option gui if in world mode
|
||||
getTag(name + ".x").setIntValue(p.x);
|
||||
getTag(name + ".y").setIntValue(p.y);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ public class GuiItemSorter extends GuiOptionPane {
|
||||
public final List<SortItem> slots = new ArrayList<>();
|
||||
public final List<SortEntry> list;
|
||||
private final GuiOptionList parentGui;
|
||||
private final boolean world;
|
||||
|
||||
boolean dragging;
|
||||
public SortItem dragged;
|
||||
@@ -62,8 +61,7 @@ public class GuiItemSorter extends GuiOptionPane {
|
||||
public GuiItemSorter(Option opt) {
|
||||
this.opt = opt;
|
||||
this.parentGui = (GuiOptionList) Minecraft.getMinecraft().currentScreen;
|
||||
this.world = parentGui.worldConfig();
|
||||
list = ItemSorter.fromSaveString(renderTag(opt.configName()).getValue());
|
||||
list = ItemSorter.fromSaveString(getTag(opt.configName()).getValue());
|
||||
for (SortEntry e : list) slots.add(new SortItem(e));
|
||||
}
|
||||
|
||||
@@ -122,10 +120,7 @@ public class GuiItemSorter extends GuiOptionPane {
|
||||
list.add(nslot, dragged.e);
|
||||
|
||||
getTag(opt.configName()).setValue(ItemSorter.getSaveString(list));
|
||||
|
||||
if (opt.activeTag() == getTag(opt.configName())) {
|
||||
ItemSorter.list = new ArrayList<>(list);
|
||||
}
|
||||
ItemSorter.list = new ArrayList<>(list);
|
||||
|
||||
ItemList.refreshItems.restart();
|
||||
}
|
||||
@@ -133,11 +128,7 @@ public class GuiItemSorter extends GuiOptionPane {
|
||||
}
|
||||
|
||||
private ConfigTag getTag(String s) {
|
||||
return (world ? opt.worldConfigSet() : opt.globalConfigSet()).config.getTag(s);
|
||||
}
|
||||
|
||||
private ConfigTag renderTag(String s) {
|
||||
return (world && opt.worldSpecific(s) ? opt.worldConfigSet() : opt.globalConfigSet()).config.getTag(s);
|
||||
return opt.configSet().config.getTag(s);
|
||||
}
|
||||
|
||||
public SortItem itemAt(int mx, int my) {
|
||||
|
||||
@@ -5,8 +5,8 @@ import net.minecraft.client.gui.GuiYesNoCallback;
|
||||
|
||||
public class GuiNEIOptionList extends GuiOptionList implements GuiYesNoCallback {
|
||||
|
||||
public GuiNEIOptionList(GuiScreen parent, OptionList optionList, boolean world) {
|
||||
super(parent, optionList, world);
|
||||
public GuiNEIOptionList(GuiScreen parent, OptionList optionList) {
|
||||
super(parent, optionList);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package codechicken.nei.config;
|
||||
|
||||
import static codechicken.lib.gui.GuiDraw.drawMultilineTip;
|
||||
import static codechicken.lib.gui.GuiDraw.drawStringC;
|
||||
import static codechicken.lib.gui.GuiDraw.fontRenderer;
|
||||
import static codechicken.lib.gui.GuiDraw.getMousePosition;
|
||||
import static net.minecraft.util.StatCollector.translateToLocal;
|
||||
@@ -10,7 +9,6 @@ import java.awt.Dimension;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -23,8 +21,6 @@ import org.lwjgl.opengl.GL11;
|
||||
import codechicken.core.gui.GuiCCButton;
|
||||
import codechicken.core.gui.GuiScreenWidget;
|
||||
import codechicken.core.gui.GuiScrollSlot;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.LayoutManager;
|
||||
|
||||
public class GuiOptionList extends GuiScreenWidget {
|
||||
|
||||
@@ -66,25 +62,11 @@ public class GuiOptionList extends GuiScreenWidget {
|
||||
protected void drawSlot(int slot, int x, int y, int mx, int my, float frame) {
|
||||
Option o = options.get(slot);
|
||||
GL11.glTranslatef(x, y, 0);
|
||||
if (o.showWorldSelector() && world) drawWorldSelector(o, mx, my);
|
||||
GL11.glTranslatef(24, 2, 0);
|
||||
o.draw(mx - 24, my - 2, frame);
|
||||
GL11.glTranslatef(-x - 24, -y - 2, 0);
|
||||
}
|
||||
|
||||
public Rectangle4i worldButtonSize() {
|
||||
return new Rectangle4i(0, 2, 20, 20);
|
||||
}
|
||||
|
||||
private void drawWorldSelector(Option o, int mousex, int mousey) {
|
||||
Rectangle4i b = worldButtonSize();
|
||||
boolean set = o.hasWorldOverride();
|
||||
boolean mouseover = b.contains(mousex, mousey);
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
LayoutManager.drawButtonBackground(b.x, b.y, b.w, b.h, true, !set ? 0 : mouseover ? 2 : 1);
|
||||
drawStringC("W", b.x, b.y, b.w, b.h, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawBackground(float frame) {
|
||||
Rectangle sbar = scrollbarBounds();
|
||||
@@ -116,16 +98,7 @@ public class GuiOptionList extends GuiScreenWidget {
|
||||
|
||||
@Override
|
||||
protected void slotClicked(int slot, int button, int mx, int my, int count) {
|
||||
Option o = options.get(slot);
|
||||
if (world && o.showWorldSelector() && worldButtonSize().contains(mx, my)) {
|
||||
if (button == 1 && o.hasWorldOverride()) {
|
||||
o.useGlobals();
|
||||
Option.playClickSound();
|
||||
} else if (button == 0 && !o.hasWorldOverride()) {
|
||||
o.copyGlobals();
|
||||
Option.playClickSound();
|
||||
}
|
||||
} else if (slotBounds(slot).contains(mx, my)) {
|
||||
if (slotBounds(slot).contains(mx, my)) {
|
||||
options.get(slot).mouseClicked(mx - 24, my - 2, button);
|
||||
}
|
||||
}
|
||||
@@ -167,26 +140,20 @@ public class GuiOptionList extends GuiScreenWidget {
|
||||
}
|
||||
|
||||
private List<String> handleTooltip(int slot, int mx, int my, List<String> tooltip) {
|
||||
Option o = options.get(slot);
|
||||
if (world && o.showWorldSelector() && worldButtonSize().contains(mx, my))
|
||||
tooltip.add(translateToLocal("nei.options.wbutton.tip." + (o.hasWorldOverride() ? "1" : "0")));
|
||||
if (slotBounds(slot).contains(mx, my)) return o.handleTooltip(mx - 24, my - 2, tooltip);
|
||||
if (slotBounds(slot).contains(mx, my)) return options.get(slot).handleTooltip(mx - 24, my - 2, tooltip);
|
||||
return tooltip;
|
||||
}
|
||||
}
|
||||
|
||||
protected final GuiScreen parent;
|
||||
protected final OptionList optionList;
|
||||
protected boolean world;
|
||||
|
||||
protected OptionScrollSlot slot;
|
||||
protected GuiCCButton backButton;
|
||||
protected GuiCCButton worldButton;
|
||||
|
||||
public GuiOptionList(GuiScreen parent, OptionList optionList, boolean world) {
|
||||
public GuiOptionList(GuiScreen parent, OptionList optionList) {
|
||||
this.parent = parent;
|
||||
this.optionList = optionList;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -202,29 +169,18 @@ public class GuiOptionList extends GuiScreenWidget {
|
||||
backButton.width = Math.min(200, width - 40);
|
||||
backButton.x = (width - backButton.width) / 2;
|
||||
backButton.y = height - 25;
|
||||
worldButton.width = 60;
|
||||
worldButton.x = width - worldButton.width - 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addWidgets() {
|
||||
add(slot = new OptionScrollSlot());
|
||||
add(backButton = new GuiCCButton(0, 0, 0, 20, translateToLocal("nei.options.back")).setActionCommand("back"));
|
||||
add(worldButton = new GuiCCButton(0, 2, 0, 16, worldButtonName()).setActionCommand("world"));
|
||||
}
|
||||
|
||||
private String worldButtonName() {
|
||||
return translateToLocal("nei.options." + (world ? "world" : "global"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(String ident, Object... params) {
|
||||
if (ident.equals("back")) {
|
||||
if (parent instanceof GuiOptionList) ((GuiOptionList) parent).world = world;
|
||||
Minecraft.getMinecraft().displayGuiScreen(parent);
|
||||
} else if (ident.equals("world")) {
|
||||
world = !world;
|
||||
worldButton.text = worldButtonName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,9 +198,6 @@ public class GuiOptionList extends GuiScreenWidget {
|
||||
private void drawTooltip() {
|
||||
List<String> tooltip = new LinkedList<>();
|
||||
Point mouse = getMousePosition();
|
||||
if (worldButton.pointInside(mouse.x, mouse.y))
|
||||
tooltip.addAll(Arrays.asList(translateToLocal("nei.options.global.tip." + (world ? "1" : "0")).split(":")));
|
||||
|
||||
tooltip = slot.handleTooltip(mouse.x, mouse.y, tooltip);
|
||||
drawMultilineTip(mouse.x + 12, mouse.y - 12, tooltip);
|
||||
}
|
||||
@@ -265,8 +218,4 @@ public class GuiOptionList extends GuiScreenWidget {
|
||||
super.keyTyped(c, keycode);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean worldConfig() {
|
||||
return world;
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,6 @@ public class GuiPanelSettings extends GuiScreenWidget {
|
||||
|
||||
private final Option opt;
|
||||
private final String name;
|
||||
private final boolean world;
|
||||
private Rectangle4i margin;
|
||||
private Point dragDown;
|
||||
private String dragDir;
|
||||
@@ -69,10 +68,9 @@ public class GuiPanelSettings extends GuiScreenWidget {
|
||||
private PanelResizeButton rightButton = new PanelResizeButton(PANEL_SIZE, PANEL_SIZE * 2);
|
||||
private PanelResizeButton bottomButton = new PanelResizeButton(PANEL_SIZE * 2, PANEL_SIZE);
|
||||
|
||||
public PanelPlaceholder(Option opt, String name, boolean world) {
|
||||
public PanelPlaceholder(Option opt, String name) {
|
||||
this.opt = opt;
|
||||
this.name = name;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public void resize(Rectangle4i margin) {
|
||||
@@ -163,7 +161,7 @@ public class GuiPanelSettings extends GuiScreenWidget {
|
||||
}
|
||||
|
||||
private ConfigTag getTag(String s) {
|
||||
return (world ? opt.worldConfigSet() : opt.globalConfigSet()).config.getTag(s);
|
||||
return opt.configSet().config.getTag(s);
|
||||
}
|
||||
|
||||
protected void drawItems() {
|
||||
@@ -241,9 +239,8 @@ public class GuiPanelSettings extends GuiScreenWidget {
|
||||
super(176, 198);
|
||||
this.parentGui = (GuiOptionList) Minecraft.getMinecraft().currentScreen;
|
||||
|
||||
boolean world = parentGui.worldConfig();
|
||||
bookmarksPanel = new PanelPlaceholder(opt, opt.name + ".bookmarks", world);
|
||||
itemsPanel = new PanelPlaceholder(opt, opt.name + ".items", world);
|
||||
bookmarksPanel = new PanelPlaceholder(opt, opt.name + ".bookmarks");
|
||||
itemsPanel = new PanelPlaceholder(opt, opt.name + ".items");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -74,7 +74,11 @@ public class IMCHandler {
|
||||
tag.getInteger("imageX"),
|
||||
tag.getInteger("imageY"),
|
||||
tag.getInteger("imageWidth"),
|
||||
tag.getInteger("imageHeight"));
|
||||
tag.getInteger("imageHeight"),
|
||||
tag.hasKey("imageTextureWidth") ? tag.getInteger("imageTextureWidth")
|
||||
: HandlerInfo.DEFAULT_IMAGE_TEXTURE_SIZE,
|
||||
tag.hasKey("imageTextureHeight") ? tag.getInteger("imageTextureHeight")
|
||||
: HandlerInfo.DEFAULT_IMAGE_TEXTURE_SIZE);
|
||||
}
|
||||
if (!info.hasImageOrItem()) {
|
||||
final String itemName = tag.getString("itemName");
|
||||
|
||||
@@ -58,7 +58,7 @@ public class ItemPanelDumper extends DataDumper {
|
||||
}
|
||||
|
||||
public int getRes() {
|
||||
int i = renderTag(name + ".res").getIntValue(0);
|
||||
int i = getTag(name + ".res").getIntValue(0);
|
||||
int size = 16 << i;
|
||||
if (size >= getSmallerScreenAxisSize() || i < 0) {
|
||||
getTag(name + ".res").setIntValue(0);
|
||||
@@ -95,7 +95,7 @@ public class ItemPanelDumper extends DataDumper {
|
||||
}
|
||||
if (resButtonSize().contains(mousex, mousey)) {
|
||||
NEIClientUtils.playClickSound();
|
||||
int current = renderTag(name + ".res").getIntValue(0);
|
||||
int current = getTag(name + ".res").getIntValue(0);
|
||||
int next;
|
||||
// 31 - numberOfLeadingZeros(x) = floor(log2(x))
|
||||
int max = 31 - Integer.numberOfLeadingZeros(getSmallerScreenAxisSize()) - 3;
|
||||
|
||||
@@ -59,12 +59,8 @@ public abstract class Option {
|
||||
return elem;
|
||||
}
|
||||
|
||||
public ConfigSet globalConfigSet() {
|
||||
return assertParentOverride(parent.globalConfigSet());
|
||||
}
|
||||
|
||||
public ConfigSet worldConfigSet() {
|
||||
return assertParentOverride(parent.worldConfigSet());
|
||||
public ConfigSet configSet() {
|
||||
return assertParentOverride(parent.configSet());
|
||||
}
|
||||
|
||||
public OptionList configBase() {
|
||||
@@ -72,127 +68,19 @@ public abstract class Option {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the world config contains a tag with this name
|
||||
*/
|
||||
public boolean worldSpecific() {
|
||||
return worldSpecific(configName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the world config contains a tag with this name
|
||||
*/
|
||||
public boolean worldSpecific(String s) {
|
||||
ConfigTag tag = worldConfigSet().config.getTag(s, false);
|
||||
return tag != null && tag.value != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The currently config set for the gui based on the world/global button
|
||||
*/
|
||||
public ConfigSet configSet() {
|
||||
return worldConfig() ? worldConfigSet() : globalConfigSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The tag to render, world if world override, otherwise global
|
||||
*/
|
||||
public ConfigTag renderTag() {
|
||||
return renderTag(configName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The tag to render, world if world override, otherwise global
|
||||
*/
|
||||
public ConfigTag renderTag(String s) {
|
||||
return (worldConfig() && worldSpecific(s) ? worldConfigSet() : globalConfigSet()).config.getTag(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The tag with this name from the current configSet
|
||||
* @return The tag with this name from the config set
|
||||
*/
|
||||
public ConfigTag getTag() {
|
||||
return getTag(configName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The tag with this name from the current configSet
|
||||
* @return The tag with this name from the config set
|
||||
*/
|
||||
public ConfigTag getTag(String s) {
|
||||
return configSet().config.getTag(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The tag currently being used ingame, world if a world override exists, otherwise global
|
||||
*/
|
||||
public ConfigTag activeTag() {
|
||||
return activeTag(configName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The tag currently being used ingame, world if a world override exists, otherwise global
|
||||
*/
|
||||
public ConfigTag activeTag(String s) {
|
||||
return (worldSpecific() ? worldConfigSet() : globalConfigSet()).config.getTag(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the gui is in world config mode
|
||||
*/
|
||||
public boolean worldConfig() {
|
||||
return getSlot().getGui().worldConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if in world mode, but this tag has no world override. Changes should not be made in this mode
|
||||
*/
|
||||
public boolean defaulting() {
|
||||
return defaulting(configName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if in world mode, but this tag has no world override. Changes should not be made in this mode
|
||||
*/
|
||||
public boolean defaulting(String s) {
|
||||
return worldConfig() && !worldSpecific(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when world specific is disabled for this option. Should delete all world specific overrides
|
||||
*/
|
||||
public void useGlobals() {
|
||||
useGlobal(configName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a specific named tag from the worldConfig
|
||||
*/
|
||||
public void useGlobal(String s) {
|
||||
if (worldConfig()) worldConfigSet().config.removeTag(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when world specific is activated for this option. Should copy the global value into a world specific
|
||||
* override
|
||||
*/
|
||||
public void copyGlobals() {
|
||||
copyGlobal(configName(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the global value into a world specific override
|
||||
*/
|
||||
public void copyGlobal(String s) {
|
||||
copyGlobal(s, false);
|
||||
}
|
||||
|
||||
public void copyGlobal(String s, boolean recursive) {
|
||||
if (!worldConfig()) return;
|
||||
|
||||
ConfigTag tag = globalConfigSet().config.getTag(s);
|
||||
worldConfigSet().config.getTag(s).setValue(tag.getValue());
|
||||
if (recursive) for (String s2 : tag.childTagMap().keySet()) copyGlobal(s + "." + s2);
|
||||
}
|
||||
|
||||
public void onAdded(OptionScrollSlot slot) {
|
||||
this.slotRef = new WeakReference<>(slot);
|
||||
}
|
||||
@@ -217,12 +105,4 @@ public abstract class Option {
|
||||
public List<String> handleTooltip(int mx, int my, List<String> currenttip) {
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
public boolean showWorldSelector() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean hasWorldOverride() {
|
||||
return worldSpecific();
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,11 @@ public class OptionCycled extends OptionButton {
|
||||
}
|
||||
|
||||
public int value() {
|
||||
return renderTag().getIntValue();
|
||||
return getTag().getIntValue();
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
getTag().setIntValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,7 +56,7 @@ public class OptionCycled extends OptionButton {
|
||||
|
||||
if (next == value()) return false;
|
||||
|
||||
getTag().setIntValue(next);
|
||||
setValue(next);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ public class OptionIntegerField extends OptionTextField {
|
||||
@Override
|
||||
protected int getMaxInputWidth() {
|
||||
|
||||
if (renderTag().getValue().startsWith("0x")) {
|
||||
if (getTag().getValue().startsWith("0x")) {
|
||||
return GuiDraw.getStringWidth("0x" + Long.toHexString(this.max).toUpperCase()) + 32;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,12 +20,7 @@ public class OptionList extends OptionButton {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigSet globalConfigSet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigSet worldConfigSet() {
|
||||
public ConfigSet configSet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -35,8 +30,8 @@ public class OptionList extends OptionButton {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuiOptionList getGui(GuiScreen parent, OptionList list, boolean world) {
|
||||
return new GuiOptionList(parent, list, world);
|
||||
public GuiOptionList getGui(GuiScreen parent, OptionList list) {
|
||||
return new GuiOptionList(parent, list);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,41 +113,25 @@ public class OptionList extends OptionButton {
|
||||
*
|
||||
* @param parent The parent screen for the back button
|
||||
* @param list The option list to be displayed in the gui
|
||||
* @param world true if in world config mode, false for global
|
||||
*/
|
||||
public GuiOptionList getGui(GuiScreen parent, OptionList list, boolean world) {
|
||||
return this.parent.getGui(parent, list, world);
|
||||
public GuiOptionList getGui(GuiScreen parent, OptionList list) {
|
||||
return this.parent.getGui(parent, list);
|
||||
}
|
||||
|
||||
public void openGui(GuiScreen parent, boolean world) {
|
||||
Minecraft.getMinecraft().displayGuiScreen(getGui(parent, this, world));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds this option to a temporary slot and gui for internal setting manipulation.
|
||||
*/
|
||||
public GuiOptionList synthesizeEnvironment(boolean world) {
|
||||
GuiOptionList gui = getGui(null, this, world);
|
||||
gui.addWidgets();
|
||||
return gui;
|
||||
public void openGui(GuiScreen parent) {
|
||||
Minecraft.getMinecraft().displayGuiScreen(getGui(parent, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
openGui(getSlot().getGui(), getSlot().getGui().worldConfig());
|
||||
openGui(getSlot().getGui());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showWorldSelector() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdded(OptionScrollSlot slot) {
|
||||
super.onAdded(slot);
|
||||
|
||||
globalConfigSet().config.getTag(configName()).useBraces();
|
||||
worldConfigSet().config.getTag(configName()).useBraces();
|
||||
configSet().config.getTag(configName()).useBraces();
|
||||
}
|
||||
}
|
||||
@@ -127,7 +127,7 @@ public abstract class OptionStringSet extends Option {
|
||||
}
|
||||
|
||||
public List<String> values() {
|
||||
return Arrays.asList(renderTag().getValue().replace(" ", "").split(","));
|
||||
return Arrays.asList(getTag().getValue().replace(" ", "").split(","));
|
||||
}
|
||||
|
||||
public int buttonX() {
|
||||
|
||||
@@ -16,8 +16,7 @@ public class OptionTextField extends Option {
|
||||
|
||||
@Override
|
||||
public void onTextChange(String oldText) {
|
||||
// don't override global if text hasn't changed
|
||||
if (focused() && isValidValue(text()) && (!defaulting() || !text().equals(getTag().getValue()))) {
|
||||
if (focused() && isValidValue(text())) {
|
||||
getTag().setValue(text());
|
||||
OptionTextField.this.onTextChange(text());
|
||||
}
|
||||
@@ -25,7 +24,7 @@ public class OptionTextField extends Option {
|
||||
|
||||
@Override
|
||||
public void setFocus(boolean focus) {
|
||||
if (!focus && !isValidValue(text())) setText(renderTag().getValue());
|
||||
if (!focus && !isValidValue(text())) setText(getTag().getValue());
|
||||
super.setFocus(focus);
|
||||
}
|
||||
|
||||
@@ -45,7 +44,7 @@ public class OptionTextField extends Option {
|
||||
@Override
|
||||
public void update() {
|
||||
textField.update();
|
||||
if (!textField.focused()) textField.setText(renderTag().getValue());
|
||||
if (!textField.focused()) textField.setText(getTag().getValue());
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
|
||||
@@ -14,7 +14,7 @@ public class OptionToggleButton extends OptionButton {
|
||||
}
|
||||
|
||||
public boolean state() {
|
||||
return renderTag().getBooleanValue();
|
||||
return getTag().getBooleanValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -34,7 +34,7 @@ public class OptionToggleButtonBoubs extends OptionButton {
|
||||
}
|
||||
|
||||
public boolean state() {
|
||||
return renderTag().getBooleanValue();
|
||||
return getTag().getBooleanValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -79,19 +79,24 @@ public class RightPanel extends GuiWidget {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lastKeyTyped(int keyID, char keyChar) {
|
||||
public boolean onHotkeyPressed() {
|
||||
|
||||
if (!focused() && KeyManager.isHashDown("gui.search")) {
|
||||
setFocus(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (focused() && KeyManager.isKeyDown("gui.getprevioussearch")) {
|
||||
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (focused() && KeyManager.isKeyDown("gui.getnextsearch")) {
|
||||
handleNavigateHistory(TextHistory.Direction.NEXT);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,13 +15,21 @@ public class DrawableBuilder {
|
||||
private int paddingBottom = 0;
|
||||
private int paddingLeft = 0;
|
||||
private int paddingRight = 0;
|
||||
private int sliceLeft = 0;
|
||||
private int sliceRight = 0;
|
||||
private int sliceTop = 0;
|
||||
private int sliceBottom = 0;
|
||||
|
||||
public DrawableBuilder(String resourceLocation, int u, int v, int width, int height) {
|
||||
this(new ResourceLocation(resourceLocation), u, v, width, height);
|
||||
}
|
||||
|
||||
public DrawableBuilder(ResourceLocation resource, int u, int v, int width, int height) {
|
||||
this.u = u;
|
||||
this.v = v;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.resourceLocation = new ResourceLocation(resourceLocation);
|
||||
this.resourceLocation = resource;
|
||||
}
|
||||
|
||||
public DrawableBuilder setTextureSize(int width, int height) {
|
||||
@@ -38,6 +46,14 @@ public class DrawableBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public DrawableBuilder setSlices(int sliceLeft, int sliceRight, int sliceTop, int sliceBottom) {
|
||||
this.sliceLeft = sliceLeft;
|
||||
this.sliceRight = sliceRight;
|
||||
this.sliceTop = sliceTop;
|
||||
this.sliceBottom = sliceBottom;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DrawableBuilder trim(int trimTop, int trimBottom, int trimLeft, int trimRight) {
|
||||
this.u += trimLeft;
|
||||
this.v += trimTop;
|
||||
@@ -58,6 +74,10 @@ public class DrawableBuilder {
|
||||
paddingLeft,
|
||||
paddingRight,
|
||||
textureWidth,
|
||||
textureHeight);
|
||||
textureHeight,
|
||||
sliceLeft,
|
||||
sliceRight,
|
||||
sliceTop,
|
||||
sliceBottom);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package codechicken.nei.drawable;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
@@ -19,9 +19,42 @@ public class DrawableResource extends Image {
|
||||
private final int paddingLeft;
|
||||
private final int paddingRight;
|
||||
|
||||
private final int sliceLeft;
|
||||
private final int sliceRight;
|
||||
private final int sliceTop;
|
||||
private final int sliceBottom;
|
||||
|
||||
public DrawableResource(ResourceLocation resourceLocation, int u, int v, int width, int height, int paddingTop,
|
||||
int paddingBottom, int paddingLeft, int paddingRight, int textureWidth, int textureHeight) {
|
||||
this(
|
||||
resourceLocation,
|
||||
u,
|
||||
v,
|
||||
width,
|
||||
height,
|
||||
paddingTop,
|
||||
paddingBottom,
|
||||
paddingLeft,
|
||||
paddingRight,
|
||||
textureWidth,
|
||||
textureHeight,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
|
||||
// negative padding lets the texture overflow the box it is drawn into
|
||||
public DrawableResource(ResourceLocation resourceLocation, int u, int v, int width, int height, int paddingTop,
|
||||
int paddingBottom, int paddingLeft, int paddingRight, int textureWidth, int textureHeight, int sliceLeft,
|
||||
int sliceRight, int sliceTop, int sliceBottom) {
|
||||
super(u, v, width, height);
|
||||
|
||||
this.sliceLeft = sliceLeft;
|
||||
this.sliceRight = sliceRight;
|
||||
this.sliceTop = sliceTop;
|
||||
this.sliceBottom = sliceBottom;
|
||||
|
||||
this.resourceLocation = resourceLocation;
|
||||
this.textureWidth = textureWidth;
|
||||
this.textureHeight = textureHeight;
|
||||
@@ -40,6 +73,14 @@ public class DrawableResource extends Image {
|
||||
return height + paddingTop + paddingBottom;
|
||||
}
|
||||
|
||||
public int getTextureWidth() {
|
||||
return this.textureWidth;
|
||||
}
|
||||
|
||||
public int getTextureHeight() {
|
||||
return this.textureHeight;
|
||||
}
|
||||
|
||||
public void bindTexture() {
|
||||
Minecraft.getMinecraft().getTextureManager().bindTexture(this.resourceLocation);
|
||||
}
|
||||
@@ -55,18 +96,28 @@ public class DrawableResource extends Image {
|
||||
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
bindTexture();
|
||||
drawModalRectWithCustomSizedTexture(xOffset + maskLeft, yOffset + maskTop, maskLeft, maskTop, width, height);
|
||||
final Tessellator tessellator = Tessellator.instance;
|
||||
tessellator.startDrawingQuads();
|
||||
addQuad(tessellator, xOffset + maskLeft, yOffset + maskTop, maskLeft, maskTop, width, height);
|
||||
tessellator.draw();
|
||||
if (!is2DTexture) GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
public void draw(int xOffset, int yOffset, int width, int height, int sliceLeft, int sliceRight, int sliceTop,
|
||||
int sliceBottom) {
|
||||
final int textureWidth = getWidth();
|
||||
final int textureHeight = getHeight();
|
||||
final int middleWidth = textureWidth - sliceLeft - sliceRight;
|
||||
final int middleHeight = textureHeight - sliceTop - sliceBottom;
|
||||
final int tileWidth = width - sliceLeft - sliceRight;
|
||||
final int tileHeight = height - sliceTop - sliceBottom;
|
||||
public void draw(int xOffset, int yOffset, int width, int height) {
|
||||
|
||||
if (width == getWidth() && height == getHeight()) {
|
||||
draw(xOffset, yOffset);
|
||||
return;
|
||||
}
|
||||
|
||||
final int sliceLeft = this.sliceLeft;
|
||||
final int sliceRight = this.sliceRight;
|
||||
final int sliceTop = this.sliceTop;
|
||||
final int sliceBottom = this.sliceBottom;
|
||||
final int middleWidth = this.width - sliceLeft - sliceRight;
|
||||
final int middleHeight = this.height - sliceTop - sliceBottom;
|
||||
final int tileWidth = width - this.paddingLeft - this.paddingRight - sliceLeft - sliceRight;
|
||||
final int tileHeight = height - this.paddingTop - this.paddingBottom - sliceTop - sliceBottom;
|
||||
|
||||
if (middleWidth > 0 && middleHeight > 0 && tileWidth > 0 && tileHeight > 0) {
|
||||
final boolean is2DTexture = GL11.glGetBoolean(GL11.GL_TEXTURE_2D);
|
||||
@@ -78,14 +129,30 @@ public class DrawableResource extends Image {
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
bindTexture();
|
||||
|
||||
// middle parts
|
||||
final Tessellator tessellator = Tessellator.instance;
|
||||
tessellator.startDrawingQuads();
|
||||
|
||||
for (int tileW = 0; tileW <= tileWidthCount; tileW++) {
|
||||
final int tileWidthSize = (tileW == tileWidthCount) ? remainderWidth : middleWidth;
|
||||
final int x = xOffset + sliceLeft + tileW * middleWidth;
|
||||
|
||||
// border top
|
||||
addQuad(tessellator, x, yOffset, sliceLeft, 0, tileWidthSize, sliceTop);
|
||||
// border bottom
|
||||
addQuad(
|
||||
tessellator,
|
||||
x,
|
||||
yOffset + sliceTop + tileHeight,
|
||||
sliceLeft,
|
||||
sliceTop + middleHeight,
|
||||
tileWidthSize,
|
||||
sliceBottom);
|
||||
|
||||
// middle parts
|
||||
for (int tileH = 0; tileH <= tileHeightCount; tileH++) {
|
||||
final int tileHeightSize = (tileH == tileHeightCount) ? remainderHeight : middleHeight;
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
addQuad(
|
||||
tessellator,
|
||||
x,
|
||||
yOffset + sliceTop + tileH * middleHeight,
|
||||
sliceLeft,
|
||||
@@ -95,114 +162,75 @@ public class DrawableResource extends Image {
|
||||
}
|
||||
}
|
||||
|
||||
// border top
|
||||
if (sliceTop > 0) {
|
||||
for (int tileW = 0; tileW <= tileWidthCount; tileW++) {
|
||||
final int tileWidthSize = (tileW == tileWidthCount) ? remainderWidth : middleWidth;
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
xOffset + sliceLeft + tileW * middleWidth,
|
||||
yOffset,
|
||||
sliceLeft,
|
||||
0,
|
||||
tileWidthSize,
|
||||
sliceTop);
|
||||
}
|
||||
}
|
||||
for (int tileH = 0; tileH <= tileHeightCount; tileH++) {
|
||||
final int tileHeightSize = (tileH == tileHeightCount) ? remainderHeight : middleHeight;
|
||||
final int y = yOffset + sliceTop + tileH * middleHeight;
|
||||
|
||||
// border bottom
|
||||
if (sliceBottom > 0) {
|
||||
for (int tileW = 0; tileW <= tileWidthCount; tileW++) {
|
||||
final int tileWidthSize = (tileW == tileWidthCount) ? remainderWidth : middleWidth;
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
xOffset + sliceLeft + tileW * middleWidth,
|
||||
yOffset + sliceTop + tileHeight,
|
||||
sliceLeft,
|
||||
sliceTop + middleHeight,
|
||||
tileWidthSize,
|
||||
sliceBottom);
|
||||
}
|
||||
}
|
||||
|
||||
// border left
|
||||
if (sliceLeft > 0) {
|
||||
for (int tileH = 0; tileH <= tileHeightCount; tileH++) {
|
||||
final int tileHeightSize = (tileH == tileHeightCount) ? remainderHeight : middleHeight;
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
xOffset,
|
||||
yOffset + sliceTop + tileH * middleHeight,
|
||||
0,
|
||||
sliceTop,
|
||||
sliceLeft,
|
||||
tileHeightSize);
|
||||
}
|
||||
}
|
||||
|
||||
// border right
|
||||
if (sliceRight > 0) {
|
||||
for (int tileH = 0; tileH <= tileHeightCount; tileH++) {
|
||||
final int tileHeightSize = (tileH == tileHeightCount) ? remainderHeight : middleHeight;
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
xOffset + sliceLeft + tileWidth,
|
||||
yOffset + sliceTop + tileH * middleHeight,
|
||||
sliceLeft + middleWidth,
|
||||
sliceTop,
|
||||
sliceRight,
|
||||
tileHeightSize);
|
||||
}
|
||||
// border left
|
||||
addQuad(tessellator, xOffset, y, 0, sliceTop, sliceLeft, tileHeightSize);
|
||||
// border right
|
||||
addQuad(
|
||||
tessellator,
|
||||
xOffset + sliceLeft + tileWidth,
|
||||
y,
|
||||
sliceLeft + middleWidth,
|
||||
sliceTop,
|
||||
sliceRight,
|
||||
tileHeightSize);
|
||||
}
|
||||
|
||||
// angle left-top
|
||||
if (sliceLeft > 0 && sliceTop > 0) {
|
||||
drawModalRectWithCustomSizedTexture(xOffset, yOffset, 0, 0, sliceLeft, sliceTop);
|
||||
}
|
||||
|
||||
addQuad(tessellator, xOffset, yOffset, 0, 0, sliceLeft, sliceTop);
|
||||
// angle right-top
|
||||
if (sliceRight > 0 && sliceTop > 0) {
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
xOffset + sliceLeft + tileWidth,
|
||||
yOffset,
|
||||
sliceLeft + middleWidth,
|
||||
0,
|
||||
sliceRight,
|
||||
sliceTop);
|
||||
}
|
||||
|
||||
addQuad(
|
||||
tessellator,
|
||||
xOffset + sliceLeft + tileWidth,
|
||||
yOffset,
|
||||
sliceLeft + middleWidth,
|
||||
0,
|
||||
sliceRight,
|
||||
sliceTop);
|
||||
// angle left-bottom
|
||||
if (sliceLeft > 0 && sliceBottom > 0) {
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
xOffset,
|
||||
yOffset + sliceTop + tileHeight,
|
||||
0,
|
||||
sliceTop + middleHeight,
|
||||
sliceLeft,
|
||||
sliceBottom);
|
||||
}
|
||||
|
||||
addQuad(
|
||||
tessellator,
|
||||
xOffset,
|
||||
yOffset + sliceTop + tileHeight,
|
||||
0,
|
||||
sliceTop + middleHeight,
|
||||
sliceLeft,
|
||||
sliceBottom);
|
||||
// angle right-bottom
|
||||
if (sliceRight > 0 && sliceBottom > 0) {
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
xOffset + sliceLeft + tileWidth,
|
||||
yOffset + sliceTop + tileHeight,
|
||||
sliceLeft + middleWidth,
|
||||
sliceTop + middleHeight,
|
||||
sliceRight,
|
||||
sliceBottom);
|
||||
}
|
||||
addQuad(
|
||||
tessellator,
|
||||
xOffset + sliceLeft + tileWidth,
|
||||
yOffset + sliceTop + tileHeight,
|
||||
sliceLeft + middleWidth,
|
||||
sliceTop + middleHeight,
|
||||
sliceRight,
|
||||
sliceBottom);
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
if (!is2DTexture) GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawModalRectWithCustomSizedTexture(int xOffset, int yOffset, int u, int v, int width, int height) {
|
||||
Gui.func_146110_a(
|
||||
xOffset + this.paddingLeft,
|
||||
yOffset + this.paddingTop,
|
||||
this.x + u,
|
||||
this.y + v,
|
||||
width,
|
||||
height,
|
||||
this.textureWidth,
|
||||
this.textureHeight);
|
||||
private void addQuad(Tessellator tessellator, int xOffset, int yOffset, int u, int v, int width, int height) {
|
||||
if (width <= 0 || height <= 0) return;
|
||||
|
||||
final float scaleU = 1.0F / this.textureWidth;
|
||||
final float scaleV = 1.0F / this.textureHeight;
|
||||
final int x = xOffset + this.paddingLeft;
|
||||
final int y = yOffset + this.paddingTop;
|
||||
final float u0 = (this.x + u) * scaleU;
|
||||
final float u1 = (this.x + u + width) * scaleU;
|
||||
final float v0 = (this.y + v) * scaleV;
|
||||
final float v1 = (this.y + v + height) * scaleV;
|
||||
|
||||
tessellator.addVertexWithUV(x, y + height, 0.0D, u0, v1);
|
||||
tessellator.addVertexWithUV(x + width, y + height, 0.0D, u1, v1);
|
||||
tessellator.addVertexWithUV(x + width, y, 0.0D, u1, v0);
|
||||
tessellator.addVertexWithUV(x, y, 0.0D, u0, v0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -449,6 +449,7 @@ public class GuiContainerManager {
|
||||
}
|
||||
|
||||
private int clickHandled = 0;
|
||||
private int hotkeyHandled = 0;
|
||||
public final List<IContainerTooltipHandler> instanceTooltipHandlers;
|
||||
|
||||
public GuiContainerManager(GuiContainer screen) {
|
||||
@@ -483,6 +484,7 @@ public class GuiContainerManager {
|
||||
|
||||
public void load() {
|
||||
clickHandled = 0;
|
||||
hotkeyHandled = 0;
|
||||
for (IContainerObjectHandler objectHandler : objectHandlers) objectHandler.load(window);
|
||||
}
|
||||
|
||||
@@ -502,6 +504,46 @@ public class GuiContainerManager {
|
||||
for (IContainerInputHandler inputhander : inputHandlers)
|
||||
if (inputhander.lastKeyTyped(window, keyChar, keyID)) return true;
|
||||
|
||||
return onHotkeyPressed();
|
||||
}
|
||||
|
||||
public boolean onHotkeyPressed() {
|
||||
|
||||
if (window instanceof IGuiHotkeyListener && ((IGuiHotkeyListener) window).onHotkeyPressed()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (IContainerInputHandler inputhander : inputHandlers) {
|
||||
if (inputhander.onHotkeyPressed(window)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return window instanceof IGuiHotkeyListener && ((IGuiHotkeyListener) window).onScreenHotkeyPressed();
|
||||
}
|
||||
|
||||
public boolean handleMouseHotkey() {
|
||||
final int button = Mouse.getEventButton();
|
||||
|
||||
if (button < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Mouse.getEventButtonState()) {
|
||||
// the press has been consumed, so the release must not reach the screen either
|
||||
if ((hotkeyHandled & 1 << button) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hotkeyHandled &= ~(1 << button);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (KeyManager.handleMouseHotkey(button, this::onHotkeyPressed)) {
|
||||
hotkeyHandled |= 1 << button;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,18 @@ public interface IContainerInputHandler {
|
||||
*/
|
||||
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID);
|
||||
|
||||
/**
|
||||
* Called when a key or a mouse button is pressed and the event has not been handled by the first pass. Use this for
|
||||
* key bindings that work globally and check them with {@link codechicken.nei.KeyManager#isKeyDown}, so they work
|
||||
* the same for keyboard keys and mouse buttons.
|
||||
*
|
||||
* @param gui An instance of the currentscreen
|
||||
* @return true to terminate further processing of this event.
|
||||
*/
|
||||
default boolean onHotkeyPressed(GuiContainer gui) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the mouse is clicked in the gui
|
||||
*
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package codechicken.nei.guihook;
|
||||
|
||||
/**
|
||||
* Interface for GuiContainers to receive NEI compatible hotkey events from both keyboard keys and mouse buttons
|
||||
*/
|
||||
public interface IGuiHotkeyListener {
|
||||
|
||||
/**
|
||||
* Called before the input handlers when a key or a mouse button is pressed, check key bindings with
|
||||
* {@link codechicken.nei.KeyManager#isKeyDown}
|
||||
*
|
||||
* @return true to terminate further processing of this event.
|
||||
*/
|
||||
default boolean onHotkeyPressed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the input handlers for screen-wide hotkeys that do not depend on the hovered object, so they never
|
||||
* take priority over more specific actions
|
||||
*
|
||||
* @return true to terminate further processing of this event.
|
||||
*/
|
||||
default boolean onScreenHotkeyPressed() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,14 @@ package codechicken.nei.item;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraftforge.client.IItemRenderer;
|
||||
import net.minecraftforge.fluids.Fluid;
|
||||
import net.minecraftforge.fluids.FluidRegistry;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.nei.item.FluidDrawer.FillDirection;
|
||||
import codechicken.nei.util.ReadableNumberConverter;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
@@ -34,37 +33,13 @@ public class FluidDisplayRenderer implements IItemRenderer {
|
||||
return;
|
||||
}
|
||||
|
||||
renderIcon(item, fluidDisplay);
|
||||
renderIcon(item);
|
||||
renderAmountOverlay(item, fluidDisplay);
|
||||
}
|
||||
|
||||
private void renderIcon(ItemStack item, ItemFluidDisplay fluidDisplay) {
|
||||
final IIcon icon = fluidDisplay.getIconIndex(item);
|
||||
if (icon == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int color = fluidDisplay.getColorFromItemStack(item, 0);
|
||||
final float red = (color >> 16 & 0xFF) / 255F;
|
||||
final float green = (color >> 8 & 0xFF) / 255F;
|
||||
final float blue = (color & 0xFF) / 255F;
|
||||
|
||||
Minecraft.getMinecraft().getTextureManager().bindTexture(TextureMap.locationBlocksTexture);
|
||||
GL11.glColor4f(red, green, blue, 1F);
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
OpenGlHelper
|
||||
.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
final Tessellator tessellator = Tessellator.instance;
|
||||
tessellator.startDrawingQuads();
|
||||
tessellator.addVertexWithUV(0, 16, 0, icon.getMinU(), icon.getMaxV());
|
||||
tessellator.addVertexWithUV(16, 16, 0, icon.getMaxU(), icon.getMaxV());
|
||||
tessellator.addVertexWithUV(16, 0, 0, icon.getMaxU(), icon.getMinV());
|
||||
tessellator.addVertexWithUV(0, 0, 0, icon.getMinU(), icon.getMinV());
|
||||
tessellator.draw();
|
||||
|
||||
GL11.glColor4f(1F, 1F, 1F, 1F);
|
||||
GL11.glDisable(GL11.GL_BLEND);
|
||||
private void renderIcon(ItemStack item) {
|
||||
final Fluid fluid = FluidRegistry.getFluid(item.getItemDamage());
|
||||
FluidDrawer.drawFluidArea(fluid != null ? fluid : FluidRegistry.WATER, 0, 0, 16, 16, false, FillDirection.UP);
|
||||
}
|
||||
|
||||
private void renderAmountOverlay(ItemStack item, ItemFluidDisplay fluidDisplay) {
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
package codechicken.nei.item;
|
||||
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraftforge.fluids.Fluid;
|
||||
import net.minecraftforge.fluids.FluidRegistry;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.nei.api.IFluidRenderer;
|
||||
import codechicken.nei.scroll.GuiHelper;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class FluidDrawer {
|
||||
|
||||
public enum FillDirection {
|
||||
|
||||
AUTO,
|
||||
UP,
|
||||
DOWN,
|
||||
LEFT,
|
||||
RIGHT;
|
||||
|
||||
public boolean isHorizontal() {
|
||||
return this == LEFT || this == RIGHT;
|
||||
}
|
||||
|
||||
public FillDirection resolve(Fluid fluid) {
|
||||
if (this != AUTO) return this;
|
||||
return fluid.isGaseous() ? DOWN : UP;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<Fluid, IFluidRenderer> fluidRenderers = new IdentityHashMap<>();
|
||||
|
||||
private FluidDrawer() {}
|
||||
|
||||
public static void registerFluidRenderer(Fluid fluid, IFluidRenderer renderer) {
|
||||
if (renderer == null) {
|
||||
fluidRenderers.remove(fluid);
|
||||
} else {
|
||||
fluidRenderers.put(fluid, renderer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawTank(int x, int y, int width, int height, int capacity, FluidStack fluidStack,
|
||||
boolean flowing, FillDirection direction) {
|
||||
if (fluidStack.amount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Fluid fluid = fluidStack.getFluid();
|
||||
direction = direction.resolve(fluid);
|
||||
|
||||
final int tankSize = direction.isHorizontal() ? width : height;
|
||||
final int tankCapacity = capacity > 0 ? capacity : fluidStack.amount;
|
||||
final int fillSize = Math
|
||||
.max(1, (int) ((long) tankSize * Math.min(fluidStack.amount, tankCapacity) / tankCapacity));
|
||||
|
||||
final int fillWidth = direction.isHorizontal() ? Math.min(fillSize, width) : width;
|
||||
final int fillHeight = direction.isHorizontal() ? height : Math.min(fillSize, height);
|
||||
final int fillX = direction == FillDirection.LEFT ? x + width - fillWidth : x;
|
||||
final int fillY = direction == FillDirection.DOWN ? y : y + height - fillHeight;
|
||||
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
drawFluidArea(fluid, fillX, fillY, fillWidth, fillHeight, flowing, direction);
|
||||
GL11.glEnable(GL11.GL_LIGHTING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the area with fluid tiles. The tiles start from the side the fluid fills from, so a partial tile ends up at
|
||||
* the fluid surface.
|
||||
*/
|
||||
public static void drawFluidArea(Fluid fluid, int x, int y, int width, int height, boolean flowing,
|
||||
FillDirection direction) {
|
||||
direction = direction.resolve(fluid);
|
||||
final boolean anchorRight = direction == FillDirection.LEFT;
|
||||
final boolean anchorBottom = direction != FillDirection.DOWN;
|
||||
final IFluidRenderer renderer = fluidRenderers.get(fluid);
|
||||
|
||||
if (renderer == null) {
|
||||
drawDefaultFluid(fluid, x, y, width, height, flowing, anchorRight, anchorBottom);
|
||||
} else {
|
||||
drawCustomFluid(renderer, fluid, x, y, width, height, anchorRight, anchorBottom);
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawCustomFluid(IFluidRenderer renderer, Fluid fluid, int x, int y, int width, int height,
|
||||
boolean anchorRight, boolean anchorBottom) {
|
||||
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
|
||||
final boolean clip = width % 16 != 0 || height % 16 != 0;
|
||||
|
||||
if (clip) {
|
||||
GuiHelper.pushScissorFrame(x, y, width, height);
|
||||
}
|
||||
|
||||
try {
|
||||
for (int tx = 0; tx < width; tx += 16) {
|
||||
final int tileX = anchorRight ? x + width - tx - 16 : x + tx;
|
||||
|
||||
for (int ty = 0; ty < height; ty += 16) {
|
||||
final int tileY = anchorBottom ? y + height - ty - 16 : y + ty;
|
||||
renderer.renderFluid(fluid, tileX, tileY);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (clip) {
|
||||
GuiHelper.popScissorFrame();
|
||||
}
|
||||
|
||||
GL11.glPopAttrib();
|
||||
GL11.glColor4f(1F, 1F, 1F, 1F);
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawDefaultFluid(Fluid fluid, int x, int y, int width, int height, boolean flowing,
|
||||
boolean anchorRight, boolean anchorBottom) {
|
||||
IIcon icon = flowing ? fluid.getFlowingIcon() : null;
|
||||
|
||||
if (icon == null) {
|
||||
icon = fluid.getStillIcon();
|
||||
}
|
||||
|
||||
if (icon == null) {
|
||||
icon = FluidRegistry.WATER.getStillIcon();
|
||||
}
|
||||
|
||||
if (icon == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int color = fluid.getColor();
|
||||
final float red = (color >> 16 & 0xFF) / 255F;
|
||||
final float green = (color >> 8 & 0xFF) / 255F;
|
||||
final float blue = (color & 0xFF) / 255F;
|
||||
|
||||
Minecraft.getMinecraft().getTextureManager().bindTexture(TextureMap.locationBlocksTexture);
|
||||
GL11.glColor4f(red, green, blue, 1F);
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
OpenGlHelper
|
||||
.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
final double iconMinU = icon.getMinU();
|
||||
final double iconMaxU = icon.getMaxU();
|
||||
final double iconMinV = icon.getMinV();
|
||||
final double iconMaxV = icon.getMaxV();
|
||||
final Tessellator tessellator = Tessellator.instance;
|
||||
|
||||
tessellator.startDrawingQuads();
|
||||
for (int tx = 0; tx < width; tx += 16) {
|
||||
final int tileWidth = Math.min(16, width - tx);
|
||||
// a cropped tile keeps the texture edge that stays seamless against the neighbouring tile
|
||||
final double uSize = (iconMaxU - iconMinU) * tileWidth / 16D;
|
||||
final double uMin = anchorRight ? iconMaxU - uSize : iconMinU;
|
||||
final double uMax = anchorRight ? iconMaxU : iconMinU + uSize;
|
||||
final int leftX = anchorRight ? x + width - tx - tileWidth : x + tx;
|
||||
final int rightX = leftX + tileWidth;
|
||||
|
||||
for (int ty = 0; ty < height; ty += 16) {
|
||||
final int tileHeight = Math.min(16, height - ty);
|
||||
final double vSize = (iconMaxV - iconMinV) * tileHeight / 16D;
|
||||
final double vMin = anchorBottom ? iconMaxV - vSize : iconMinV;
|
||||
final double vMax = anchorBottom ? iconMaxV : iconMinV + vSize;
|
||||
final int bottomY = anchorBottom ? y + height - ty : y + ty + tileHeight;
|
||||
final int topY = bottomY - tileHeight;
|
||||
|
||||
tessellator.addVertexWithUV(leftX, bottomY, 0, uMin, vMax);
|
||||
tessellator.addVertexWithUV(rightX, bottomY, 0, uMax, vMax);
|
||||
tessellator.addVertexWithUV(rightX, topY, 0, uMax, vMin);
|
||||
tessellator.addVertexWithUV(leftX, topY, 0, uMin, vMin);
|
||||
}
|
||||
}
|
||||
tessellator.draw();
|
||||
|
||||
GL11.glDisable(GL11.GL_BLEND);
|
||||
GL11.glColor4f(1F, 1F, 1F, 1F);
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ public class ItemFluidDisplay extends Item implements IFluidContainerItem {
|
||||
public ItemFluidDisplay() {
|
||||
setUnlocalizedName("nei.fluidDisplay");
|
||||
setMaxStackSize(1);
|
||||
setHasSubtypes(true);
|
||||
INSTANCE = this;
|
||||
}
|
||||
|
||||
@@ -72,7 +73,7 @@ public class ItemFluidDisplay extends Item implements IFluidContainerItem {
|
||||
@Override
|
||||
public FluidStack getFluid(ItemStack stack) {
|
||||
|
||||
if (stack == null || !(stack.getItem() instanceof ItemFluidDisplay) || !stack.hasTagCompound()) {
|
||||
if (stack == null || !(stack.getItem() instanceof ItemFluidDisplay)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -85,7 +86,7 @@ public class ItemFluidDisplay extends Item implements IFluidContainerItem {
|
||||
final NBTTagCompound nbTag = stack.getTagCompound();
|
||||
final FluidStack fluidStack = new FluidStack(
|
||||
fluid,
|
||||
(int) Math.min(nbTag.getLong("neiFluidDisplayAmount"), Integer.MAX_VALUE));
|
||||
(int) Math.min(nbTag != null ? nbTag.getLong("neiFluidDisplayAmount") : 0, Integer.MAX_VALUE));
|
||||
|
||||
return fluidStack;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ public class AcceptsFollowingTooltipLineHandler extends ItemsTooltipLineHandler
|
||||
super(NEIClientUtils.translate("recipe.accepts"), items, false, maxRows);
|
||||
this.tooltipGUID = tooltipGUID;
|
||||
setActiveStack(activeStack);
|
||||
setAmountRenderer(new FavoriteAmountRenderer());
|
||||
}
|
||||
|
||||
public static AcceptsFollowingTooltipLineHandler of(Object tooltipGUID, List<ItemStack> items,
|
||||
@@ -38,12 +39,15 @@ public class AcceptsFollowingTooltipLineHandler extends ItemsTooltipLineHandler
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawItem(int x, int y, ItemStack drawStack, String stackSize) {
|
||||
super.drawItem(x, y, drawStack, stackSize);
|
||||
protected static class FavoriteAmountRenderer extends NoAmountRenderer {
|
||||
|
||||
if (FavoriteRecipes.containsManual(drawStack)) {
|
||||
NEIClientUtils.drawNEIOverlayText("F", x, y);
|
||||
@Override
|
||||
public void draw(int x, int y, ItemStack stack, long amount) {
|
||||
super.draw(x, y, stack, amount);
|
||||
|
||||
if (FavoriteRecipes.containsManual(stack)) {
|
||||
NEIClientUtils.drawNEIOverlayText("F", x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,13 +5,18 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.inventory.SlotCrafting;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.nei.FastTransferManager;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemStackAmount;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.NEIServerUtils;
|
||||
import codechicken.nei.RestartableTask;
|
||||
import codechicken.nei.ServerSync;
|
||||
import codechicken.nei.bookmark.BookmarkItem;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.chain.RecipeChainIterator;
|
||||
@@ -26,6 +31,7 @@ public class AutoCraftingManager {
|
||||
@Override
|
||||
public void execute() {
|
||||
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
|
||||
final ItemStack[] layout = snapshotLayout(guiContainer);
|
||||
final List<BookmarkItem> initialItems = prepareInitialItems(math, getInventoryItems(guiContainer));
|
||||
boolean processed = false;
|
||||
boolean changed = false;
|
||||
@@ -69,6 +75,11 @@ public class AutoCraftingManager {
|
||||
|
||||
} while (changed && !interrupted(guiContainer));
|
||||
|
||||
if (!interrupted(guiContainer)) {
|
||||
restoreLayout(guiContainer, layout);
|
||||
ServerSync.request();
|
||||
}
|
||||
|
||||
} finally {
|
||||
StackInfo.pauseItemDamageSound(false);
|
||||
}
|
||||
@@ -134,4 +145,70 @@ public class AutoCraftingManager {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
private static ItemStack[] snapshotLayout(GuiContainer guiContainer) {
|
||||
final List<Slot> slots = guiContainer.inventorySlots.inventorySlots;
|
||||
final ItemStack[] layout = new ItemStack[slots.size()];
|
||||
|
||||
for (int index = 0; index < slots.size(); index++) {
|
||||
final Slot slot = slots.get(index);
|
||||
|
||||
if (slot.getHasStack() && !(slot instanceof SlotCrafting)) {
|
||||
layout[index] = slot.getStack().copy();
|
||||
}
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
private static void restoreLayout(GuiContainer guiContainer, ItemStack[] layout) {
|
||||
final List<Slot> slots = guiContainer.inventorySlots.inventorySlots;
|
||||
final EntityPlayer player = guiContainer.mc.thePlayer;
|
||||
|
||||
for (int index = 0; index < slots.size() && player.inventory.getItemStack() == null
|
||||
&& guiContainer.mc.currentScreen == guiContainer; index++) {
|
||||
final ItemStack expected = layout[index];
|
||||
final Slot target = slots.get(index);
|
||||
|
||||
if (expected == null || inPlace(slots, layout, index)
|
||||
|| !target.isItemValid(expected)
|
||||
|| target.getHasStack() && !target.canTakeStack(player)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Slot source = findMisplaced(slots, layout, expected, player);
|
||||
if (source == null) continue;
|
||||
|
||||
FastTransferManager.clickSlot(guiContainer, source.slotNumber);
|
||||
FastTransferManager.clickSlot(guiContainer, target.slotNumber);
|
||||
|
||||
if (player.inventory.getItemStack() != null) {
|
||||
FastTransferManager.clickSlot(guiContainer, source.slotNumber);
|
||||
}
|
||||
}
|
||||
|
||||
FastTransferManager.dropHeldItem(guiContainer);
|
||||
}
|
||||
|
||||
private static boolean inPlace(List<Slot> slots, ItemStack[] layout, int index) {
|
||||
final ItemStack stack = slots.get(index).getStack();
|
||||
return stack != null && layout[index] != null
|
||||
&& NEIServerUtils.areStacksSameTypeCraftingWithNBT(layout[index], stack);
|
||||
}
|
||||
|
||||
private static Slot findMisplaced(List<Slot> slots, ItemStack[] layout, ItemStack expected, EntityPlayer player) {
|
||||
|
||||
for (int index = 0; index < slots.size(); index++) {
|
||||
final Slot slot = slots.get(index);
|
||||
|
||||
if (slot.getHasStack() && !(slot instanceof SlotCrafting)
|
||||
&& !inPlace(slots, layout, index)
|
||||
&& slot.canTakeStack(player)
|
||||
&& NEIServerUtils.areStacksSameTypeCraftingWithNBT(expected, slot.getStack())) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -20,10 +21,13 @@ import codechicken.lib.inventory.InventoryUtils;
|
||||
import codechicken.nei.FastTransferManager;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.ServerSync;
|
||||
import codechicken.nei.api.IOverlayHandler;
|
||||
|
||||
public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
|
||||
private static final long SYNC_TIMEOUT_MILLIS = 5000;
|
||||
|
||||
public static class DistributedIngred {
|
||||
|
||||
public DistributedIngred(ItemStack item) {
|
||||
@@ -113,7 +117,8 @@ public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
}
|
||||
|
||||
boolean craft = false;
|
||||
while (multiplier > 0) {
|
||||
while (multiplier > 0 && firstGui.mc.currentScreen == firstGui
|
||||
&& presenceOverlay(firstGui, handler, recipeIndex).stream().allMatch(s -> s.isPresent())) {
|
||||
final int transfer = transferRecipe(firstGui, handler, recipeIndex, multiplier);
|
||||
|
||||
if (transfer <= 0) {
|
||||
@@ -122,6 +127,10 @@ public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
|
||||
multiplier -= transfer;
|
||||
|
||||
if (!craftingSlot.getHasStack() && !awaitServer(firstGui)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (craftingSlot.getHasStack() && craftingSlot.canTakeStack(firstGui.mc.thePlayer)) {
|
||||
FastTransferManager.clickSlot(firstGui, craftingSlot.slotNumber, 0, 1);
|
||||
|
||||
@@ -139,9 +148,30 @@ public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
return craft;
|
||||
}
|
||||
|
||||
private boolean awaitServer(GuiContainer gui) {
|
||||
final long deadline = System.currentTimeMillis() + SYNC_TIMEOUT_MILLIS;
|
||||
ServerSync.request();
|
||||
|
||||
while (ServerSync.pending()) {
|
||||
if (gui.mc.currentScreen != gui || System.currentTimeMillis() > deadline) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean clearIngredients(GuiContainer gui, IRecipeHandler handler) {
|
||||
|
||||
for (Slot slot : getCraftMatrixSlots(gui, handler)) {
|
||||
if (gui.mc.currentScreen != gui) return false;
|
||||
|
||||
if (slot.canTakeStack(gui.mc.thePlayer)) {
|
||||
FastTransferManager.clickSlot(gui, slot.slotNumber, 0, 1);
|
||||
if (slot.getHasStack()) return false;
|
||||
@@ -206,7 +236,9 @@ public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
protected void moveIngredients(GuiContainer gui, List<IngredientDistribution> assignedIngredients, int multiplier) {
|
||||
final Slot craftingSlot = getCraftingResultSlot(gui);
|
||||
|
||||
for (Slot slot : gui.inventorySlots.inventorySlots) {
|
||||
for (Slot slot : getSourceSlots(gui)) {
|
||||
if (gui.mc.currentScreen != gui) return;
|
||||
|
||||
if (slot == craftingSlot || !slot.getHasStack()
|
||||
|| !canMoveFrom(slot, gui)
|
||||
|| !slot.canTakeStack(gui.mc.thePlayer))
|
||||
@@ -240,6 +272,10 @@ public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
FastTransferManager.clickSlot(gui, slot.slotNumber);
|
||||
}
|
||||
|
||||
// A right click with an empty or foreign cursor would take half of the dest stack
|
||||
final ItemStack held = gui.mc.thePlayer.inventory.getItemStack();
|
||||
if (held == null || !canStack(distrib.permutation, held)) break;
|
||||
|
||||
FastTransferManager.clickSlot(gui, dest.slotNumber, 1);
|
||||
stackSize--;
|
||||
}
|
||||
@@ -370,7 +406,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
}
|
||||
|
||||
protected void findInventoryQuantities(GuiContainer gui, List<DistributedIngred> ingredStacks) {
|
||||
for (Slot slot : gui.inventorySlots.inventorySlots) /* work out how much we have to go round */ {
|
||||
for (Slot slot : getSourceSlots(gui)) /* work out how much we have to go round */ {
|
||||
if (slot.getHasStack() && canMoveFrom(slot, gui)) {
|
||||
final ItemStack pstack = slot.getStack();
|
||||
final DistributedIngred istack = findIngred(ingredStacks, pstack);
|
||||
@@ -408,6 +444,25 @@ public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
}
|
||||
}
|
||||
|
||||
protected List<Slot> getSourceSlots(GuiContainer gui) {
|
||||
final List<Slot> slots = new ArrayList<>(gui.inventorySlots.inventorySlots);
|
||||
slots.sort(Comparator.comparingLong(slot -> getRemainingDurability(slot.getStack())));
|
||||
return slots;
|
||||
}
|
||||
|
||||
private static long getRemainingDurability(ItemStack stack) {
|
||||
if (stack == null || stack.getMaxStackSize() != 1) return Long.MAX_VALUE;
|
||||
|
||||
final NBTTagCompound tagCompound = stack.getTagCompound();
|
||||
|
||||
if (tagCompound != null && tagCompound.hasKey("GT.ToolStats")) {
|
||||
final NBTTagCompound toolStats = tagCompound.getCompoundTag("GT.ToolStats");
|
||||
return toolStats.getLong("MaxDamage") - toolStats.getLong("Damage");
|
||||
}
|
||||
|
||||
return stack.isItemStackDamageable() ? stack.getMaxDamage() - stack.getItemDamage() : Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
private int getGTToolDamagePerContainerCraft(ItemStack aStack) {
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,121 +1,242 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.inventory.InventoryCrafting;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemDye;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.RecipeFireworks;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.InventoryCraftingDummy;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
|
||||
public class FireworkRecipeHandler extends ShapelessRecipeHandler {
|
||||
|
||||
public class CachedFireworkRecipe extends CachedShapelessRecipe {
|
||||
|
||||
final LinkedList<Object> itemList = new LinkedList<>();
|
||||
|
||||
public final Object[] baseIngredients;
|
||||
public final Object extraIngred;
|
||||
public final int recipeType;
|
||||
public final Object groupId;
|
||||
|
||||
public CachedFireworkRecipe(Object[] base, Object extra, int type) {
|
||||
super(new ItemStack(Items.fireworks));
|
||||
this.baseIngredients = base;
|
||||
this.extraIngred = extra;
|
||||
public CachedFireworkRecipe(List<ItemStack> ingredients, ItemStack result, int type, Object groupId) {
|
||||
super(ingredients, result);
|
||||
this.recipeType = type;
|
||||
|
||||
cycle();
|
||||
}
|
||||
|
||||
public void cycle() {
|
||||
itemList.clear();
|
||||
itemList.addAll(Arrays.asList(baseIngredients));
|
||||
int extras = (cycleticks / 40) % (10 - itemList.size());
|
||||
for (int i = 0; i < extras; i++) itemList.add(extraIngred);
|
||||
setIngredients(itemList);
|
||||
|
||||
List<PositionedStack> ingreds = getIngredients();
|
||||
for (int i = 0; i < 9; i++)
|
||||
inventoryCrafting.setInventorySlotContents(i, i < ingreds.size() ? ingreds.get(i).item : null);
|
||||
|
||||
if (!recipeFireworks.matches(inventoryCrafting, null)) throw new RuntimeException("Invalid Recipe?");
|
||||
setResult(recipeFireworks.getCraftingResult(null));
|
||||
this.groupId = groupId;
|
||||
}
|
||||
}
|
||||
|
||||
// indexed by the "Type" explosion tag
|
||||
private static final ItemStack[] SHAPES = { null, new ItemStack(Items.fire_charge),
|
||||
new ItemStack(Items.gold_nugget), new ItemStack(Items.skull, 1, Short.MAX_VALUE),
|
||||
new ItemStack(Items.feather) };
|
||||
|
||||
private final InventoryCrafting inventoryCrafting = new InventoryCraftingDummy();
|
||||
private final RecipeFireworks recipeFireworks = new RecipeFireworks();
|
||||
|
||||
public final ArrayList<CachedFireworkRecipe> mfireworks = new ArrayList<>();
|
||||
private ItemStack usageIngredient = null;
|
||||
|
||||
public FireworkRecipeHandler() {
|
||||
super();
|
||||
stackorder = new int[][] { { 0, 0 }, { 1, 0 }, { 2, 0 }, { 0, 1 }, { 1, 1 }, { 2, 1 }, { 0, 2 }, { 1, 2 },
|
||||
{ 2, 2 } };
|
||||
loadAllFireworks();
|
||||
}
|
||||
|
||||
private void loadAllFireworks() {
|
||||
// charges
|
||||
Item[] shapes = new Item[] { null, Items.fire_charge, Items.gold_nugget, Items.feather, Items.skull };
|
||||
Item[] effects = new Item[] { null, Items.diamond, Items.glowstone_dust };
|
||||
for (Item shape : shapes)
|
||||
for (Item effect : effects) genRecipe(Items.gunpowder, shape, effect, Items.dye, Items.dye, 0);
|
||||
|
||||
// fireworks
|
||||
genRecipe(Items.gunpowder, Items.paper, Items.firework_charge, 2);
|
||||
genRecipe(Items.gunpowder, Items.gunpowder, Items.paper, Items.firework_charge, 2);
|
||||
genRecipe(Items.gunpowder, Items.gunpowder, Items.gunpowder, Items.paper, Items.firework_charge, 2);
|
||||
|
||||
// setup a valid charge to use for the recolour recipe
|
||||
for (int i = 0; i < 9; i++) inventoryCrafting.setInventorySlotContents(i, null);
|
||||
inventoryCrafting.setInventorySlotContents(0, new ItemStack(Items.gunpowder));
|
||||
inventoryCrafting.setInventorySlotContents(1, new ItemStack(Items.dye));
|
||||
recipeFireworks.matches(inventoryCrafting, null);
|
||||
ItemStack charge = recipeFireworks.getCraftingResult(null);
|
||||
genRecipe(charge, Items.dye, Items.dye, 1);
|
||||
@Override
|
||||
public Object getRecipeGroupId(int recipe) {
|
||||
return this.arecipes.get(recipe) instanceof CachedFireworkRecipe firework ? firework.groupId : null;
|
||||
}
|
||||
|
||||
private void genRecipe(Object... params) {
|
||||
int numIngreds = 0;
|
||||
for (int i = 0; i < params.length - 2; i++) if (params[i] != null) numIngreds++;
|
||||
private void loadChargeRecipes() {
|
||||
final List<List<ItemStack>> dyeSets = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < params.length - 1; i++)
|
||||
if (params[i] instanceof Item) params[i] = new ItemStack((Item) params[i], 1, Short.MAX_VALUE);
|
||||
for (int dye = 0; dye < ItemDye.field_150922_c.length; dye++) {
|
||||
dyeSets.add(Collections.singletonList(new ItemStack(Items.dye, 1, dye)));
|
||||
}
|
||||
|
||||
Object[] ingreds = new Object[numIngreds];
|
||||
for (int i = 0, j = 0; i < params.length - 2; i++) if (params[i] != null) ingreds[j++] = params[i];
|
||||
for (ItemStack shape : SHAPES) {
|
||||
for (int effect = 0; effect < 4; effect++) {
|
||||
addRecipes(getChargeBase(shape, (effect & 1) != 0, (effect & 2) != 0), dyeSets, 0);
|
||||
}
|
||||
}
|
||||
|
||||
mfireworks
|
||||
.add(new CachedFireworkRecipe(ingreds, params[params.length - 2], (Integer) params[params.length - 1]));
|
||||
final ItemStack charge = craft(Arrays.asList(new ItemStack(Items.gunpowder), new ItemStack(Items.dye)));
|
||||
addRecipes(Collections.singletonList(charge), dyeSets, 1);
|
||||
}
|
||||
|
||||
private void loadRocketRecipes() {
|
||||
final ItemStack charge = craft(Arrays.asList(new ItemStack(Items.gunpowder), new ItemStack(Items.dye)));
|
||||
final List<List<ItemStack>> chargeSets = new ArrayList<>();
|
||||
|
||||
for (int count = 0; count < 9; count++) {
|
||||
chargeSets.add(Collections.nCopies(count, charge));
|
||||
}
|
||||
|
||||
for (int flight = 1; flight <= 3; flight++) {
|
||||
addRecipes(getRocketBase(flight), chargeSets, 2);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadExactChargeRecipes(NBTTagCompound explosion) {
|
||||
final byte type = explosion.getByte("Type");
|
||||
|
||||
if (explosion.hasKey("FadeColors")) {
|
||||
final NBTTagCompound baseTag = new NBTTagCompound();
|
||||
final ItemStack charge = new ItemStack(Items.firework_charge);
|
||||
|
||||
baseTag.setTag("Explosion", explosion.copy());
|
||||
baseTag.getCompoundTag("Explosion").removeTag("FadeColors");
|
||||
charge.setTagCompound(baseTag);
|
||||
|
||||
addRecipes(Collections.singletonList(charge), getDyeSets(explosion.getIntArray("FadeColors")), 1);
|
||||
} else if (type >= 0 && type < SHAPES.length) {
|
||||
addRecipes(
|
||||
getChargeBase(SHAPES[type], explosion.getBoolean("Flicker"), explosion.getBoolean("Trail")),
|
||||
getDyeSets(explosion.getIntArray("Colors")),
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadExactRocketRecipes(NBTTagCompound fireworks) {
|
||||
final NBTTagList explosions = fireworks.getTagList("Explosions", 10);
|
||||
final List<ItemStack> charges = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < explosions.tagCount(); i++) {
|
||||
final ItemStack charge = new ItemStack(Items.firework_charge);
|
||||
charge.setTagCompound(new NBTTagCompound());
|
||||
charge.getTagCompound().setTag("Explosion", explosions.getCompoundTagAt(i));
|
||||
charges.add(charge);
|
||||
}
|
||||
|
||||
addRecipes(getRocketBase(fireworks.getByte("Flight")), Collections.singletonList(charges), 2);
|
||||
}
|
||||
|
||||
private static List<ItemStack> getChargeBase(ItemStack shape, boolean flicker, boolean trail) {
|
||||
final List<ItemStack> base = new ArrayList<>();
|
||||
base.add(new ItemStack(Items.gunpowder));
|
||||
|
||||
if (shape != null) {
|
||||
base.add(shape);
|
||||
}
|
||||
|
||||
if (flicker) {
|
||||
base.add(new ItemStack(Items.glowstone_dust));
|
||||
}
|
||||
|
||||
if (trail) {
|
||||
base.add(new ItemStack(Items.diamond));
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
private static List<ItemStack> getRocketBase(int flight) {
|
||||
final List<ItemStack> base = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < flight; i++) {
|
||||
base.add(new ItemStack(Items.gunpowder));
|
||||
}
|
||||
|
||||
base.add(new ItemStack(Items.paper));
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
private static List<List<ItemStack>> getDyeSets(int[] colors) {
|
||||
final List<ItemStack> dyes = new ArrayList<>();
|
||||
|
||||
for (int color : colors) {
|
||||
for (int dye = 0; dye < ItemDye.field_150922_c.length; dye++) {
|
||||
if (ItemDye.field_150922_c[dye] == color) {
|
||||
dyes.add(new ItemStack(Items.dye, 1, dye));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dyes.isEmpty() || dyes.size() != colors.length) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if (Arrays.stream(colors).distinct().count() > 1) {
|
||||
return Collections.singletonList(dyes);
|
||||
}
|
||||
|
||||
final List<List<ItemStack>> dyeSets = new ArrayList<>();
|
||||
|
||||
for (int count = 1; count < 9; count++) {
|
||||
dyeSets.add(Collections.nCopies(count, dyes.get(0)));
|
||||
}
|
||||
|
||||
return dyeSets;
|
||||
}
|
||||
|
||||
private void addRecipes(List<ItemStack> base, List<List<ItemStack>> extraSets, int type) {
|
||||
final Object groupId = new Object();
|
||||
|
||||
for (List<ItemStack> extras : extraSets) {
|
||||
final List<ItemStack> ingredients = new ArrayList<>(base);
|
||||
ingredients.addAll(extras);
|
||||
|
||||
final ItemStack result = craft(ingredients);
|
||||
|
||||
if (result != null) {
|
||||
final CachedFireworkRecipe recipe = new CachedFireworkRecipe(ingredients, result, type, groupId);
|
||||
|
||||
if (usageIngredient == null || recipe.contains(recipe.ingredients, usageIngredient)) {
|
||||
arecipes.add(recipe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStack craft(List<ItemStack> ingredients) {
|
||||
|
||||
if (ingredients.size() > 9) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 9; i++) {
|
||||
inventoryCrafting.setInventorySlotContents(i, i < ingredients.size() ? ingredients.get(i) : null);
|
||||
}
|
||||
|
||||
return recipeFireworks.matches(inventoryCrafting, null) ? recipeFireworks.getCraftingResult(inventoryCrafting)
|
||||
: null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCraftingRecipes(ItemStack result) {
|
||||
for (CachedFireworkRecipe recipe : mfireworks) {
|
||||
if (recipe.result.item.getItem() == result.getItem()) {
|
||||
recipe.cycle();
|
||||
arecipes.add(recipe);
|
||||
final NBTTagCompound tag = result.getTagCompound();
|
||||
|
||||
if (result.getItem() == Items.firework_charge) {
|
||||
if (tag != null) {
|
||||
loadExactChargeRecipes(tag.getCompoundTag("Explosion"));
|
||||
}
|
||||
|
||||
if (arecipes.isEmpty()) {
|
||||
loadChargeRecipes();
|
||||
}
|
||||
} else if (result.getItem() == Items.fireworks) {
|
||||
if (tag != null) {
|
||||
loadExactRocketRecipes(tag.getCompoundTag("Fireworks"));
|
||||
}
|
||||
|
||||
if (arecipes.isEmpty()) {
|
||||
loadRocketRecipes();
|
||||
}
|
||||
}
|
||||
// show random recolouring recipes as well
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCraftingRecipes(String outputId, Object... results) {
|
||||
if (outputId.equals("crafting") && getClass() == FireworkRecipeHandler.class) {
|
||||
arecipes.addAll(mfireworks);
|
||||
loadChargeRecipes();
|
||||
loadRocketRecipes();
|
||||
} else {
|
||||
super.loadCraftingRecipes(outputId, results);
|
||||
}
|
||||
@@ -123,20 +244,9 @@ public class FireworkRecipeHandler extends ShapelessRecipeHandler {
|
||||
|
||||
@Override
|
||||
public void loadUsageRecipes(ItemStack ingredient) {
|
||||
for (CachedFireworkRecipe recipe : mfireworks) {
|
||||
if (recipe.contains(recipe.ingredients, ingredient)) {
|
||||
recipe.cycle();
|
||||
arecipes.add(recipe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate() {
|
||||
if (!NEIClientUtils.shiftKey()) {
|
||||
cycleticks++;
|
||||
if (cycleticks % 20 == 0) for (CachedRecipe crecipe : arecipes) ((CachedFireworkRecipe) crecipe).cycle();
|
||||
}
|
||||
usageIngredient = ingredient;
|
||||
loadChargeRecipes();
|
||||
loadRocketRecipes();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,11 +257,8 @@ public class FireworkRecipeHandler extends ShapelessRecipeHandler {
|
||||
@Override
|
||||
public List<String> handleTooltip(GuiRecipe<?> gui, List<String> currenttip, int recipe) {
|
||||
currenttip = super.handleTooltip(gui, currenttip, recipe);
|
||||
Point mousepos = GuiDraw.getMousePosition();
|
||||
Point relMouse = new Point(mousepos.x - gui.guiLeft, mousepos.y - gui.guiTop);
|
||||
Point recipepos = gui.getRecipePosition(recipe);
|
||||
if (currenttip.isEmpty() && GuiContainerManager.getStackMouseOver(gui) == null
|
||||
&& new Rectangle(recipepos.x, recipepos.y, 166, 55).contains(relMouse))
|
||||
&& new Rectangle(0, 0, 166, 55).contains(gui.getRecipeMousePosition(recipe)))
|
||||
currenttip.add(
|
||||
NEIClientUtils.translate(
|
||||
"recipe.firework.tooltip" + ((CachedFireworkRecipe) arecipes.get(recipe)).recipeType));
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -12,14 +12,9 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.FavoriteRecipes;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
|
||||
import codechicken.nei.bookmark.BookmarksGridSlot;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
|
||||
public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
|
||||
@@ -35,6 +30,7 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
|
||||
public static GuiRecipe<?> createRecipeGui(String outputId, boolean open, Object... results) {
|
||||
final Minecraft mc = NEIClientUtils.mc();
|
||||
final RecipeId recipeId;
|
||||
List<ItemStack> pinnedIngredients = null;
|
||||
|
||||
for (int i = 0; i < results.length; i++) {
|
||||
if (results[i] instanceof ItemStack stack) {
|
||||
@@ -46,6 +42,12 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
|
||||
recipeId = getRecipeId(mc.currentScreen, (ItemStack) results[0]);
|
||||
} else if ("recipeId".equals(outputId)) {
|
||||
recipeId = (RecipeId) results[1];
|
||||
|
||||
// optional third argument: ingredients to pin the found recipe with
|
||||
if (results.length > 2 && results[2] instanceof List<?>list) {
|
||||
pinnedIngredients = extractIngredients(list);
|
||||
}
|
||||
|
||||
} else {
|
||||
recipeId = getCurrentRecipeId(mc.currentScreen);
|
||||
}
|
||||
@@ -65,13 +67,25 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
|
||||
mc.displayGuiScreen(gui);
|
||||
}
|
||||
|
||||
gui.openTargetRecipe(recipeId);
|
||||
gui.openTargetRecipe(recipeId, pinnedIngredients);
|
||||
return gui;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<ItemStack> extractIngredients(List<?> list) {
|
||||
final List<ItemStack> ingredients = new ArrayList<>(list.size());
|
||||
|
||||
for (Object item : list) {
|
||||
if (item instanceof ItemStack stack) {
|
||||
ingredients.add(stack);
|
||||
}
|
||||
}
|
||||
|
||||
return ingredients;
|
||||
}
|
||||
|
||||
public static ArrayList<ICraftingHandler> getCraftingHandlers(String outputId, Object... results) {
|
||||
ArrayList<ICraftingHandler> craftinghandlers = GuiCraftingRecipe.craftinghandlers;
|
||||
ArrayList<ICraftingHandler> serialCraftingHandlers = GuiCraftingRecipe.serialCraftingHandlers;
|
||||
@@ -118,39 +132,8 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
|
||||
}
|
||||
|
||||
public static RecipeId getRecipeId(GuiScreen gui, ItemStack stackover) {
|
||||
|
||||
if (gui instanceof GuiRecipe<?>guiRecipe) {
|
||||
final Recipe focusedRecipe = guiRecipe.getFocusedRecipe();
|
||||
|
||||
if (focusedRecipe != null) {
|
||||
return focusedRecipe.getRecipeId();
|
||||
}
|
||||
}
|
||||
|
||||
final Point mouseover = GuiDraw.getMousePosition();
|
||||
final BookmarksGridSlot panelSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
|
||||
if (panelSlot != null) {
|
||||
return panelSlot.getType() == BookmarkItemType.INGREDIENT || panelSlot.getRecipeId() == null
|
||||
? FavoriteRecipes.getFavorite(stackover)
|
||||
: panelSlot.getRecipeId();
|
||||
}
|
||||
|
||||
ItemsGridSlot itemSlot = ItemPanels.itemPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.historyPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
}
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.craftablesPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
}
|
||||
|
||||
if (itemSlot != null) {
|
||||
return itemSlot.getRecipeId();
|
||||
}
|
||||
|
||||
return null;
|
||||
final HoveredRecipe hovered = HoveredRecipe.of(gui, stackover);
|
||||
return hovered != null ? hovered.recipeId : null;
|
||||
}
|
||||
|
||||
private GuiCraftingRecipe(ArrayList<ICraftingHandler> handlers) {
|
||||
|
||||
@@ -122,18 +122,25 @@ public class GuiFavoriteButton extends GuiRecipeButton {
|
||||
return Recipe.of(this.handlerRef);
|
||||
}
|
||||
|
||||
public void lastKeyTyped(char keyChar, int keyID) {
|
||||
@Override
|
||||
public void lastKeyTyped(char keyChar, int keyID) {}
|
||||
|
||||
@Override
|
||||
public boolean onHotkeyPressed() {
|
||||
|
||||
if (KeyManager.isKeyDown("bookmark.add") && NEIClientUtils.shiftKey()) {
|
||||
saveRecipeInBookmark();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (KeyManager.isKeyDown("bookmark.open_crafting_tree") && NEIClientUtils.shiftKey()
|
||||
&& saveRecipeInBookmark()) {
|
||||
final int groupId = ItemPanels.bookmarkPanel.getGrid().getNextGroupId() - 1;
|
||||
GuiCraftingTree.openCraftingTreeGui(ItemPanels.bookmarkPanel.getGrid(), groupId);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -177,12 +177,20 @@ public class GuiOverlayButton extends GuiRecipeButton {
|
||||
hotkeys.put(
|
||||
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("recipe.overlay.fillCraftingGrid"));
|
||||
hotkeys.put(
|
||||
NEIClientUtils.getKeyName(
|
||||
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH,
|
||||
NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("recipe.overlay.fillCraftingGridOnce"));
|
||||
}
|
||||
|
||||
} else if (canFillCraftingGrid()) {
|
||||
hotkeys.put(
|
||||
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("recipe.overlay.fillCraftingGrid"));
|
||||
hotkeys.put(
|
||||
NEIClientUtils.getKeyName(NEIClientUtils.CTRL_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("recipe.overlay.fillCraftingGridOnce"));
|
||||
}
|
||||
|
||||
hotkeys.put(
|
||||
@@ -262,11 +270,8 @@ public class GuiOverlayButton extends GuiRecipeButton {
|
||||
.map(state -> state.getSlot().item).collect(Collectors.toList());
|
||||
|
||||
if (!items.isEmpty()) {
|
||||
this.missedMaterialsTooltipLineHandler = new ItemsTooltipLineHandler(
|
||||
NEIClientUtils.translate("recipe.overlay.missing"),
|
||||
items,
|
||||
true,
|
||||
Integer.MAX_VALUE);
|
||||
this.missedMaterialsTooltipLineHandler = ItemsTooltipLineHandler
|
||||
.of(NEIClientUtils.translate("recipe.overlay.missing"), items, Integer.MAX_VALUE, 0);
|
||||
} else {
|
||||
this.missedMaterialsTooltipLineHandler = null;
|
||||
}
|
||||
@@ -332,7 +337,7 @@ public class GuiOverlayButton extends GuiRecipeButton {
|
||||
|
||||
if (!requireShiftForOverlayRecipe() || shift) {
|
||||
if (this.canFillCraftingGrid) {
|
||||
this.handlerRef.fillCraftingGrid(this.firstGui, 0);
|
||||
this.handlerRef.fillCraftingGrid(this.firstGui, NEIClientUtils.controlKey() ? 1 : 0);
|
||||
}
|
||||
} else if (hasOverlay() && useOverlayRenderer()) {
|
||||
this.handlerRef.useOverlayRenderer(this.firstGui);
|
||||
@@ -341,14 +346,21 @@ public class GuiOverlayButton extends GuiRecipeButton {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lastKeyTyped(char keyChar, int keyID) {
|
||||
public void lastKeyTyped(char keyChar, int keyID) {}
|
||||
|
||||
@Override
|
||||
public boolean onHotkeyPressed() {
|
||||
if (KeyManager.isKeyDown("bookmark.add") && NEIClientUtils.shiftKey()) {
|
||||
saveRecipeInBookmark();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (KeyManager.isKeyDown("bookmark.chat_link") && NEIClientUtils.controlKey() && NEIClientUtils.shiftKey()) {
|
||||
sendRecipeChatLink();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void saveRecipeInBookmark() {
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
@@ -51,7 +51,9 @@ import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerTooltipHandler;
|
||||
import codechicken.nei.guihook.IGuiClientSide;
|
||||
import codechicken.nei.guihook.IGuiHandleMouseWheel;
|
||||
import codechicken.nei.guihook.IGuiHotkeyListener;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.widget.RecipeWidget;
|
||||
import codechicken.nei.scroll.ScrollBar;
|
||||
import codechicken.nei.scroll.ScrollBar.OverflowType;
|
||||
import codechicken.nei.scroll.ScrollBar.ScrollPlace;
|
||||
@@ -61,7 +63,7 @@ import codechicken.nei.util.EmptyContainer;
|
||||
import codechicken.nei.util.SlotInaccessible;
|
||||
|
||||
public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer implements IGuiContainerOverlay,
|
||||
IGuiClientSide, IGuiHandleMouseWheel, IContainerTooltipHandler, INEIGuiHandler {
|
||||
IGuiClientSide, IGuiHandleMouseWheel, IGuiHotkeyListener, IContainerTooltipHandler, INEIGuiHandler {
|
||||
|
||||
private static final int BORDER_PADDING = 5;
|
||||
private static final int TRANSPARENCY_BORDER = 4;
|
||||
@@ -70,15 +72,23 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
0,
|
||||
0,
|
||||
176 + TRANSPARENCY_BORDER * 2,
|
||||
166 + TRANSPARENCY_BORDER * 2).build();
|
||||
166 + TRANSPARENCY_BORDER * 2)
|
||||
.setSlices(
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER)
|
||||
.build();
|
||||
|
||||
private static final int BUTTON_WIDTH = 13;
|
||||
private static final int BUTTON_HEIGHT = 12;
|
||||
|
||||
protected static final ScrollBar VERTICAL_SCROLLBAR = new ScrollBar().setTrackWidth(14)
|
||||
.setOverflowType(OverflowType.AUTO).setScrollPlace(ScrollPlace.END)
|
||||
.setTrackTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 42, 90, 13, 21).build(), 9, 9)
|
||||
.setThumbTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 22, 96, 6, 9).build(), 3, 2)
|
||||
.setTrackTexture(
|
||||
new DrawableBuilder("nei:textures/nei_sprites.png", 42, 90, 13, 21).setSlices(0, 0, 9, 9).build())
|
||||
.setThumbTexture(
|
||||
new DrawableBuilder("nei:textures/nei_sprites.png", 22, 96, 6, 9).setSlices(0, 0, 3, 2).build())
|
||||
.setThumbPadding(1, 6, 0, 6);
|
||||
|
||||
public static final List<IRecipeFilterProvider> recipeFilterers = new LinkedList<>();
|
||||
@@ -294,73 +304,118 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
}
|
||||
|
||||
/**
|
||||
* Many old mods assumed a fixed NEI window height of {@code 166} pixels. Now that this is no longer the case, their
|
||||
* 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.
|
||||
* Many old mods assumed a fixed NEI window size of {@code 176x166} pixels, with exactly one recipe shown at a time,
|
||||
* flush against the top-left corner of the window. Now that none of these assumptions hold (the window has a
|
||||
* flexible size, several recipes can be stacked in the same scrollable list, and the recipe area is inset from the
|
||||
* window's edges), these old mods' tooltip and click zone handling is broken. This helper class fixes these old
|
||||
* mods by hacking the {@link #width}, {@link #height}, {@link #guiLeft} and {@link #guiTop} properties' values so
|
||||
* that these old mods' calculations return the correct value for whichever recipe they are currently being asked
|
||||
* about.
|
||||
*
|
||||
* <p>
|
||||
* New and old mods often assume that the handler is only drawn when {@link GuiRecipe} is the currently active
|
||||
* screen in {@link net.minecraft.client.Minecraft}. This is no longer true since the addition of recipe tooltips
|
||||
* which need to render the recipe in other containers on mouse hover, this class temporarily switches the active
|
||||
* screen to {@code this} while rendering them to avoid ClassCastExceptions and other similar crashes.
|
||||
* Since each recipe handled by a {@link RecipeWidget} can sit at a different real position, this must be
|
||||
* constructed with that widget's top-left edge every time a legacy entry point ({@code mouseClicked},
|
||||
* {@code handleTooltip}, ...) is invoked for it, rather than once per {@link GuiRecipe}.
|
||||
*
|
||||
* <p>
|
||||
* This class is an {@link AutoCloseable} so that it can be used with try-with-resources, which will ensure that
|
||||
* {@link #height} and {@link net.minecraft.client.Minecraft#currentScreen} is returned to the correct value
|
||||
* {@link #width}, {@link #height}, {@link #guiLeft} and {@link #guiTop} are returned to the correct value
|
||||
* afterwards.
|
||||
*/
|
||||
private class CompatibilityHacks implements AutoCloseable {
|
||||
public static final class CompatibilityHacks implements AutoCloseable {
|
||||
|
||||
// The historical NEI recipe screen's fixed size: a single top paging widget 16px tall, no horizontal inset,
|
||||
// and a 176x166 box. Legacy handlers either read guiLeft/guiTop directly (expecting them to point 16px above
|
||||
// their recipe, flush on the left) or recompute them from width/height with these same two constants.
|
||||
private static final int LEGACY_TOP_GAP = 16;
|
||||
private static final int LEGACY_BOX_WIDTH = 176;
|
||||
private static final int LEGACY_BOX_HEIGHT = 166;
|
||||
|
||||
// layoutWindow() places the recipe container at (guiLeft + 3, guiTop + 32); RecipePageManager then places
|
||||
// each left-aligned recipe widget another 2px to the right of that. This is the inverse of both, undoing the
|
||||
// container's own inset so a legacy handler sees its recipe flush with guiLeft as it expects.
|
||||
private static final int CONTAINER_LEFT_INSET = 3 + 2;
|
||||
|
||||
private final GuiRecipe<?> gui;
|
||||
private final int trueWidth;
|
||||
private final int trueHeight;
|
||||
private final int trueGuiLeft;
|
||||
private final int trueGuiTop;
|
||||
|
||||
private CompatibilityHacks() {
|
||||
trueHeight = height;
|
||||
trueGuiTop = guiTop;
|
||||
/**
|
||||
* @param widget The recipe widget a legacy entry point ({@code mouseClicked}, {@code handleTooltip}, ...) is
|
||||
* about to be invoked for.
|
||||
*/
|
||||
public CompatibilityHacks(GuiRecipe<?> gui, RecipeWidget widget) {
|
||||
this.gui = gui;
|
||||
this.trueWidth = gui.width;
|
||||
this.trueHeight = gui.height;
|
||||
this.trueGuiLeft = gui.guiLeft;
|
||||
this.trueGuiTop = gui.guiTop;
|
||||
|
||||
isHeightHackApplied = NEIClientConfig.heightHackHandlerRegex.stream()
|
||||
.map(pattern -> pattern.matcher(handler.original.getHandlerId())).anyMatch(Matcher::matches);
|
||||
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;
|
||||
final String handlerId = gui.handler.original.getHandlerId();
|
||||
gui.isHeightHackApplied = NEIClientConfig.heightHackHandlerRegex.stream()
|
||||
.anyMatch(pattern -> pattern.matcher(handlerId).matches());
|
||||
|
||||
// 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 recipe screen). So if we
|
||||
// wanted to override width
|
||||
// as well, we'd do this:
|
||||
// width = (2 * guiWidth) + 176;
|
||||
if (gui.isHeightHackApplied) {
|
||||
gui.guiTop = recipeTop(widget) - LEGACY_TOP_GAP;
|
||||
gui.guiLeft = widget.x - CONTAINER_LEFT_INSET;
|
||||
gui.height = (2 * gui.guiTop) + LEGACY_BOX_HEIGHT;
|
||||
gui.width = (2 * gui.guiLeft) + LEGACY_BOX_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
// recipiesPerPage() == 2 is the IRecipeHandler default: a handler only ends up with this value if it never
|
||||
// overrode the method, or if it overrode it and chose 2 on purpose. We only care about the latter case, so
|
||||
// we require the override to actually come from the handler's own class rather than being inherited as-is.
|
||||
private static final Map<Class<?>, Boolean> overridesRecipiesPerPage = new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* The real top edge of this widget's recipe, as a legacy handler following the {@link #LEGACY_TOP_GAP}
|
||||
* convention would expect to find it at guiTop. A few handlers (e.g. ImmersiveEngineering) are left over from
|
||||
* the old {@code recipiesPerPage() == 2} convention, where two recipes shared one physical page: their own
|
||||
* {@code mouseClicked}/{@code handleTooltip} still add a hardcoded "recipe height * (recipe % 2)" on top of
|
||||
* guiTop to find the odd one of the pair. Since every recipe is its own independent widget now, we pre-subtract
|
||||
* that same offset here so their own addition cancels out and lands back on this widget's real top.
|
||||
*
|
||||
* <p>
|
||||
* This only applies when the handler itself overrides {@link IRecipeHandler#recipiesPerPage()} to return
|
||||
* {@code 2}: that method defaults to {@code 2} on the interface, so most height-hacked handlers return it
|
||||
* without ever having implemented this pairing (e.g. BuildCraftCompat never overrides it at all, and only reads
|
||||
* it elsewhere to pick a cosmetic sub-name), and applying this compensation to them would break them. A handler
|
||||
* that went out of its way to declare {@code return 2;} itself is making a deliberate statement about this
|
||||
* legacy convention that a handler which simply never mentions the method isn't.
|
||||
*/
|
||||
private static int recipeTop(RecipeWidget widget) {
|
||||
final RecipeHandlerRef ref = widget.getRecipeHandlerRef();
|
||||
final HandlerInfo handlerInfo = widget.getHandlerInfo();
|
||||
final int top = widget.y + handlerInfo.getYShift();
|
||||
|
||||
if (ref.handler.recipiesPerPage() == 2 && declaresRecipiesPerPage(ref.handler)) {
|
||||
return top - handlerInfo.getHeight() * (ref.recipeIndex % 2);
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
private static boolean declaresRecipiesPerPage(IRecipeHandler handler) {
|
||||
return overridesRecipiesPerPage.computeIfAbsent(handler.getClass(), clazz -> {
|
||||
try {
|
||||
return clazz.getMethod("recipiesPerPage").getDeclaringClass() != IRecipeHandler.class;
|
||||
} catch (NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
guiTop = trueGuiTop;
|
||||
height = trueHeight;
|
||||
this.gui.guiLeft = this.trueGuiLeft;
|
||||
this.gui.guiTop = this.trueGuiTop;
|
||||
this.gui.width = this.trueWidth;
|
||||
this.gui.height = this.trueHeight;
|
||||
|
||||
isHeightHackApplied = false;
|
||||
this.gui.isHeightHackApplied = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,7 +578,14 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
}
|
||||
|
||||
public int openTargetRecipe(RecipeId recipeId) {
|
||||
int refIndex = -1;
|
||||
return openTargetRecipe(recipeId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pinnedIngredients when not null, the found recipe is paused with these ingredients shown
|
||||
*/
|
||||
public int openTargetRecipe(RecipeId recipeId, List<ItemStack> pinnedIngredients) {
|
||||
int recipeIndex = -1;
|
||||
int recipetype = 0;
|
||||
|
||||
this.recipeId = recipeId;
|
||||
@@ -537,10 +599,9 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
recipetype = j;
|
||||
|
||||
if (!this.recipeId.getIngredients().isEmpty()) {
|
||||
refIndex = SearchRecipeHandler.findFirst(
|
||||
recipeIndex = SearchRecipeHandler.findFirst(
|
||||
localHandler,
|
||||
recipeIndex -> this.recipeId
|
||||
.equalsIngredients(localHandler.getIngredientStacks(recipeIndex)));
|
||||
ri -> this.recipeId.equalsIngredients(localHandler.getIngredientStacks(ri)));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -549,17 +610,21 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
}
|
||||
|
||||
setRecipePage(recipetype);
|
||||
this.handlerPages.gotoRefIndex(Math.max(0, refIndex));
|
||||
this.handlerPages.gotoRecipeIndex(Math.max(0, recipeIndex));
|
||||
|
||||
return refIndex;
|
||||
if (pinnedIngredients != null && recipeIndex >= 0) {
|
||||
this.handlerPages.pinRecipe(recipeIndex, pinnedIngredients);
|
||||
}
|
||||
|
||||
return recipeIndex;
|
||||
}
|
||||
|
||||
public Recipe getFocusedRecipe() {
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
final Widget activeWidget = this.container.getWidgetUnderMouse(mouse.x, mouse.y);
|
||||
|
||||
if (activeWidget instanceof NEIRecipeWidget recipeWidget && recipeWidget.isFocusedRecipe(mouse.x, mouse.y)) {
|
||||
return recipeWidget.getRecipe();
|
||||
if (activeWidget instanceof RecipeWidget recipeWidget && recipeWidget.isFocusedRecipe(mouse.x, mouse.y)) {
|
||||
return Recipe.of(recipeWidget.getRecipeHandlerRef());
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -569,7 +634,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
final Widget activeWidget = this.container.getWidgetUnderMouse(mouse.x, mouse.y);
|
||||
|
||||
if (activeWidget instanceof NEIRecipeWidget recipeWidget) {
|
||||
if (activeWidget instanceof RecipeWidget recipeWidget) {
|
||||
final PositionedStack hovered = recipeWidget.getPositionedStackMouseOver(mouse.x, mouse.y);
|
||||
|
||||
if (hovered != null) {
|
||||
@@ -586,7 +651,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
final EmptyContainer slotcontainer = (EmptyContainer) inventorySlots;
|
||||
slotcontainer.setActiveStack(null);
|
||||
|
||||
if (activeWidget instanceof NEIRecipeWidget recipeWidget) {
|
||||
if (activeWidget instanceof RecipeWidget recipeWidget) {
|
||||
final PositionedStack hovered = recipeWidget.getPositionedStackMouseOver(mousex, mousey);
|
||||
|
||||
if (hovered != null) {
|
||||
@@ -633,6 +698,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
|
||||
if (GuiRecipe.searchField.isVisible() && GuiRecipe.searchField.focused()) {
|
||||
GuiRecipe.searchField.lastKeyTyped(i, c);
|
||||
GuiRecipe.searchField.onHotkeyPressed();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -657,7 +723,24 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
if (i == mc.gameSettings.keyBindInventory.getKeyCode()) {
|
||||
this.mc.displayGuiScreen(getFirstScreenGeneral());
|
||||
NEICPH.sendRequestContainer();
|
||||
} else if (KeyManager.isKeyDown("recipe.back")) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHotkeyPressed() {
|
||||
if (GuiRecipe.searchField.isVisible() && GuiRecipe.searchField.onHotkeyPressed()
|
||||
|| this.recipeCatalyst.isShowWidget() && this.recipeCatalyst.onHotkeyPressed()
|
||||
|| this.container.onHotkeyPressed()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScreenHotkeyPressed() {
|
||||
|
||||
if (KeyManager.isKeyDown("recipe.back")) {
|
||||
this.mc.displayGuiScreen(this.prevGui);
|
||||
} else if (KeyManager.isKeyDown("recipe.prev_machine")) {
|
||||
prevType();
|
||||
@@ -667,7 +750,11 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
prevPage();
|
||||
} else if (KeyManager.isKeyDown("recipe.next_recipe")) {
|
||||
nextPage();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -687,10 +774,8 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
return;
|
||||
}
|
||||
|
||||
try (CompatibilityHacks compatibilityHacks = new CompatibilityHacks()) {
|
||||
if (this.container.handleClick(mousex, mousey, button)) {
|
||||
return;
|
||||
}
|
||||
if (this.container.handleClick(mousex, mousey, button)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.recipeTabs.mouseClicked(mousex, mousey, button)) {
|
||||
@@ -738,11 +823,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
public void mouseScrolled(int scroll) {
|
||||
// Height hacking is not necessary here since mouse scrolling is a new feature,
|
||||
// added in
|
||||
// GTNH NEI. So no old mods will use this. Though not hacking the height here
|
||||
// does mean that
|
||||
// the value of the height field will be different from in other mouseover
|
||||
// methods, which
|
||||
// could be confusing...
|
||||
// GTNH NEI. So no old mods will use this.
|
||||
|
||||
// First, invoke scroll handling over recipe handler tabbar. Makes sure it is
|
||||
// not overwritten by recipe
|
||||
@@ -755,10 +836,8 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
return;
|
||||
}
|
||||
|
||||
try (CompatibilityHacks compatibilityHacks = new CompatibilityHacks()) {
|
||||
if (this.container.onMouseWheel(scroll, mouse.x, mouse.y)) {
|
||||
return;
|
||||
}
|
||||
if (this.container.onMouseWheel(scroll, mouse.x, mouse.y)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If shift is held, try switching to the next recipe handler. Replicates the
|
||||
@@ -810,9 +889,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
currenttip = this.recipeCatalyst.handleTooltip(mousex, mousey, currenttip);
|
||||
}
|
||||
|
||||
try (CompatibilityHacks compatibilityHacks = new CompatibilityHacks()) {
|
||||
currenttip = this.container.handleTooltip(mousex, mousey, currenttip);
|
||||
}
|
||||
currenttip = this.container.handleTooltip(mousex, mousey, currenttip);
|
||||
|
||||
this.recipeTabs.handleTooltip(mousex, mousey, currenttip);
|
||||
|
||||
@@ -844,7 +921,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
List<String> currenttip) {
|
||||
final Widget activeWidget = this.container.getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
if (activeWidget instanceof NEIRecipeWidget recipeWidget) {
|
||||
if (activeWidget instanceof RecipeWidget recipeWidget) {
|
||||
currenttip = recipeWidget.handleItemTooltip(itemstack, mousex, mousey, currenttip);
|
||||
}
|
||||
|
||||
@@ -858,9 +935,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
hotkeys = this.recipeCatalyst.handleHotkeys(mousex, mousey, hotkeys);
|
||||
}
|
||||
|
||||
try (CompatibilityHacks compatibilityHacks = new CompatibilityHacks()) {
|
||||
hotkeys = this.container.handleHotkeys(mousex, mousey, hotkeys);
|
||||
}
|
||||
hotkeys = this.container.handleHotkeys(mousex, mousey, hotkeys);
|
||||
|
||||
return hotkeys;
|
||||
}
|
||||
@@ -891,7 +966,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
this.recipetype = this.currenthandlers.indexOf(this.handler.original);
|
||||
|
||||
setRecipePage(this.recipetype);
|
||||
this.handlerPages.changePage(currentPage);
|
||||
this.handlerPages.changePage(currentPage - this.handlerPages.getCurrentPageIndex());
|
||||
|
||||
refreshContainer();
|
||||
}
|
||||
@@ -914,11 +989,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
this.guiLeft - TRANSPARENCY_BORDER,
|
||||
this.guiTop - TRANSPARENCY_BORDER,
|
||||
this.xSize + TRANSPARENCY_BORDER * 2,
|
||||
this.ySize + TRANSPARENCY_BORDER * 2,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER);
|
||||
this.ySize + TRANSPARENCY_BORDER * 2);
|
||||
|
||||
drawJEITabs(mouseX, mouseY);
|
||||
}
|
||||
@@ -1014,8 +1085,23 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
return this.firstGuiGeneral;
|
||||
}
|
||||
|
||||
public Point getRecipePosition(int recipe) {
|
||||
return getRefIndexPosition(getRecipeIndices().indexOf(recipe));
|
||||
public Point getRecipePosition(int recipeIndex) {
|
||||
|
||||
for (Widget widget : this.container.getWidgets()) {
|
||||
if (widget instanceof RecipeWidget recipeWidget && recipeWidget.containsRecipeIndex(recipeIndex)) {
|
||||
return new Point(
|
||||
recipeWidget.x - this.guiLeft,
|
||||
recipeWidget.y - this.guiTop + recipeWidget.getHandlerInfo().getYShift());
|
||||
}
|
||||
}
|
||||
|
||||
return new Point(0, 0);
|
||||
}
|
||||
|
||||
public Point getRecipeMousePosition(int recipeIndex) {
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
final Point recipePosition = getRecipePosition(recipeIndex);
|
||||
return new Point(mouse.x - this.guiLeft - recipePosition.x, mouse.y - this.guiTop - recipePosition.y);
|
||||
}
|
||||
|
||||
protected Point getRefIndexPosition(int refIndex) {
|
||||
@@ -1027,7 +1113,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
final List<Widget> children = this.container.getWidgets();
|
||||
|
||||
if (refIndex >= 0 && refIndex < children.size()
|
||||
&& children.get(refIndex) instanceof NEIRecipeWidget recipeWidget) {
|
||||
&& children.get(refIndex) instanceof RecipeWidget recipeWidget) {
|
||||
return new Point(
|
||||
recipeWidget.x - this.guiLeft,
|
||||
recipeWidget.y - this.guiTop + recipeWidget.getHandlerInfo().getYShift());
|
||||
|
||||
@@ -15,12 +15,16 @@ public abstract class GuiRecipeButton extends GuiNEIButton {
|
||||
public static class UpdateRecipeButtonsEvent extends GuiScreenEvent {
|
||||
|
||||
public List<GuiRecipeButton> buttonList;
|
||||
public NEIRecipeWidget recipeWidget;
|
||||
public RecipeHandlerRef handlerRef;
|
||||
public int width;
|
||||
public int height;
|
||||
|
||||
public UpdateRecipeButtonsEvent(GuiRecipe<?> gui, NEIRecipeWidget recipeWidget,
|
||||
public UpdateRecipeButtonsEvent(GuiRecipe<?> gui, RecipeHandlerRef handlerRef, int width, int height,
|
||||
List<GuiRecipeButton> buttonList) {
|
||||
super(gui);
|
||||
this.recipeWidget = recipeWidget;
|
||||
this.handlerRef = handlerRef;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.buttonList = new ArrayList<>(buttonList);
|
||||
}
|
||||
|
||||
@@ -29,16 +33,17 @@ public abstract class GuiRecipeButton extends GuiNEIButton {
|
||||
|
||||
public HandlerInfo handlerInfo;
|
||||
|
||||
public Pre(GuiRecipe<?> gui, NEIRecipeWidget recipeWidget, HandlerInfo handlerInfo) {
|
||||
super(gui, recipeWidget, new ArrayList<>());
|
||||
public Pre(GuiRecipe<?> gui, RecipeHandlerRef handlerRef, int width, int height, HandlerInfo handlerInfo) {
|
||||
super(gui, handlerRef, width, height, new ArrayList<>());
|
||||
this.handlerInfo = handlerInfo;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Post extends UpdateRecipeButtonsEvent {
|
||||
|
||||
public Post(GuiRecipe<?> gui, NEIRecipeWidget recipeWidget, List<GuiRecipeButton> buttonList) {
|
||||
super(gui, recipeWidget, buttonList);
|
||||
public Post(GuiRecipe<?> gui, RecipeHandlerRef handlerRef, int width, int height,
|
||||
List<GuiRecipeButton> buttonList) {
|
||||
super(gui, handlerRef, width, height, buttonList);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,6 +64,10 @@ public abstract class GuiRecipeButton extends GuiNEIButton {
|
||||
|
||||
public abstract void lastKeyTyped(char keyChar, int keyID);
|
||||
|
||||
public boolean onHotkeyPressed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract void drawItemOverlay();
|
||||
|
||||
public void update() {
|
||||
|
||||
@@ -55,11 +55,17 @@ public class GuiRecipeCatalyst extends ScrollContainer {
|
||||
0,
|
||||
0,
|
||||
28 + TRANSPARENCY_BORDER * 2,
|
||||
28 + TRANSPARENCY_BORDER * 2).setTextureSize(28 + TRANSPARENCY_BORDER * 2, 28 + TRANSPARENCY_BORDER * 2)
|
||||
28 + TRANSPARENCY_BORDER * 2)
|
||||
.setTextureSize(28 + TRANSPARENCY_BORDER * 2, 28 + TRANSPARENCY_BORDER * 2)
|
||||
.setSlices(
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER)
|
||||
.build();
|
||||
|
||||
private static final DrawableResource FG_TEXTURE = new DrawableBuilder("nei:textures/slot.png", 0, 0, 18, 18)
|
||||
.setTextureSize(18, 18).build();
|
||||
.setTextureSize(18, 18).setSlices(1, 1, 1, 1).build();
|
||||
|
||||
private static final ScrollBar VERTICAL_SCROLLBAR = ScrollBar.defaultVerticalBar()
|
||||
.setOverflowType(ScrollBar.OverflowType.AUTO).setTrackPadding(0, BORDER_PADDING, -13, BORDER_PADDING)
|
||||
@@ -155,20 +161,12 @@ public class GuiRecipeCatalyst extends ScrollContainer {
|
||||
this.x - TRANSPARENCY_BORDER,
|
||||
this.y - TRANSPARENCY_BORDER,
|
||||
this.w + TRANSPARENCY_BORDER * 2,
|
||||
this.h + TRANSPARENCY_BORDER * 2,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER);
|
||||
this.h + TRANSPARENCY_BORDER * 2);
|
||||
FG_TEXTURE.draw(
|
||||
this.x + this.paddingInlineStart - 1,
|
||||
this.y + this.paddingBlockStart - 1,
|
||||
this.w - this.paddingInlineStart - this.paddingInlineEnd + 2,
|
||||
this.h - this.paddingBlockStart - this.paddingBlockEnd + 2,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1);
|
||||
this.h - this.paddingBlockStart - this.paddingBlockEnd + 2);
|
||||
|
||||
super.draw(mx, my);
|
||||
}
|
||||
|
||||
@@ -181,6 +181,24 @@ public abstract class GuiRecipeTab extends Widget {
|
||||
return res;
|
||||
}
|
||||
|
||||
public static String getHandlerTitle(String handlerName) {
|
||||
String title = findRecipeName(GuiCraftingRecipe.craftinghandlers, handlerName);
|
||||
if (title == null) title = findRecipeName(GuiCraftingRecipe.serialCraftingHandlers, handlerName);
|
||||
if (title == null) title = findRecipeName(GuiUsageRecipe.usagehandlers, handlerName);
|
||||
if (title == null) title = findRecipeName(GuiUsageRecipe.serialUsageHandlers, handlerName);
|
||||
|
||||
return title != null ? title : handlerName;
|
||||
}
|
||||
|
||||
private static String findRecipeName(List<? extends IRecipeHandler> handlers, String handlerName) {
|
||||
for (int index = 0; index < handlers.size(); index++) {
|
||||
final IRecipeHandler handler = handlers.get(index);
|
||||
if (handlerName.equals(getHandlerInfo(handler).getHandlerName())) return handler.getRecipeName().trim();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getHandlerMod(String name, String name2) {
|
||||
HandlerInfo info = getHandlerInfo(name, name2);
|
||||
if (info == null) return "Unknown";
|
||||
|
||||
@@ -12,6 +12,7 @@ public class HandlerInfo {
|
||||
|
||||
public static int DEFAULT_HEIGHT = 65;
|
||||
public static int DEFAULT_WIDTH = 166;
|
||||
public static final int DEFAULT_IMAGE_TEXTURE_SIZE = 256;
|
||||
|
||||
@Deprecated
|
||||
public static int DEFAULT_MAX_PER_PAGE = 1;
|
||||
@@ -70,9 +71,22 @@ public class HandlerInfo {
|
||||
}
|
||||
|
||||
public boolean setImage(String resourceLocation, int imageX, int imageY, int imageWidth, int imageHeight) {
|
||||
return setImage(
|
||||
resourceLocation,
|
||||
imageX,
|
||||
imageY,
|
||||
imageWidth,
|
||||
imageHeight,
|
||||
DEFAULT_IMAGE_TEXTURE_SIZE,
|
||||
DEFAULT_IMAGE_TEXTURE_SIZE);
|
||||
}
|
||||
|
||||
public boolean setImage(String resourceLocation, int imageX, int imageY, int imageWidth, int imageHeight,
|
||||
int textureWidth, int textureHeight) {
|
||||
if (hasImageOrItem()) return false;
|
||||
|
||||
this.image = new DrawableBuilder(resourceLocation, imageX, imageY, imageWidth, imageHeight).build();
|
||||
this.image = new DrawableBuilder(resourceLocation, imageX, imageY, imageWidth, imageHeight)
|
||||
.setTextureSize(textureWidth, textureHeight).build();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -211,6 +225,20 @@ public class HandlerInfo {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDisplayImage(ResourceLocation location, int imageX, int imageY, int imageWidth,
|
||||
int imageHeight, int textureWidth, int textureHeight) {
|
||||
this.info.itemStack = null;
|
||||
this.info.setImage(
|
||||
location.toString(),
|
||||
imageX,
|
||||
imageY,
|
||||
imageWidth,
|
||||
imageHeight,
|
||||
textureWidth,
|
||||
textureHeight);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Builder setUseCustomScroll(boolean useCustomScroll) {
|
||||
this.info.setUseCustomScroll(useCustomScroll);
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import java.awt.Point;
|
||||
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.FavoriteRecipes;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
|
||||
import codechicken.nei.bookmark.BookmarksGridSlot;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
|
||||
public final class HoveredRecipe {
|
||||
|
||||
public enum Source {
|
||||
RECIPE_GUI,
|
||||
BOOKMARK,
|
||||
ITEM_PANEL,
|
||||
OTHER
|
||||
}
|
||||
|
||||
public final RecipeId recipeId;
|
||||
public final Source source;
|
||||
public final boolean favorite;
|
||||
|
||||
private HoveredRecipe(RecipeId recipeId, Source source, boolean favorite) {
|
||||
this.recipeId = recipeId;
|
||||
this.source = source;
|
||||
this.favorite = favorite;
|
||||
}
|
||||
|
||||
public static HoveredRecipe of(GuiScreen gui, ItemStack stackover) {
|
||||
|
||||
if (gui instanceof GuiRecipe<?>guiRecipe) {
|
||||
final Recipe focusedRecipe = guiRecipe.getFocusedRecipe();
|
||||
|
||||
if (focusedRecipe != null) {
|
||||
return new HoveredRecipe(focusedRecipe.getRecipeId(), Source.RECIPE_GUI, false);
|
||||
}
|
||||
}
|
||||
|
||||
final Point mouseover = GuiDraw.getMousePosition();
|
||||
final BookmarksGridSlot bookmarkSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
|
||||
if (bookmarkSlot != null) {
|
||||
|
||||
if (bookmarkSlot.getType() != BookmarkItemType.INGREDIENT && bookmarkSlot.getRecipeId() != null) {
|
||||
return new HoveredRecipe(bookmarkSlot.getRecipeId(), Source.BOOKMARK, false);
|
||||
}
|
||||
|
||||
return favorite(stackover, Source.BOOKMARK);
|
||||
}
|
||||
|
||||
ItemsGridSlot itemSlot = ItemPanels.itemPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.historyPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
}
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.craftablesPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
}
|
||||
|
||||
if (itemSlot != null) {
|
||||
|
||||
if (itemSlot.getRecipeId() != null) {
|
||||
return new HoveredRecipe(itemSlot.getRecipeId(), Source.ITEM_PANEL, false);
|
||||
}
|
||||
|
||||
return favorite(stackover, Source.ITEM_PANEL);
|
||||
}
|
||||
|
||||
if (gui instanceof GuiRecipe<?>guiRecipe && guiRecipe.getSlotAtPosition(mouseover.x, mouseover.y) != null) {
|
||||
return favorite(stackover, Source.RECIPE_GUI);
|
||||
}
|
||||
|
||||
return favorite(stackover, Source.OTHER);
|
||||
}
|
||||
|
||||
private static HoveredRecipe favorite(ItemStack stackover, Source source) {
|
||||
final RecipeId recipeId = FavoriteRecipes.getFavorite(stackover);
|
||||
return recipeId != null ? new HoveredRecipe(recipeId, source, true) : null;
|
||||
}
|
||||
}
|
||||
@@ -91,6 +91,14 @@ public interface IRecipeHandler {
|
||||
*/
|
||||
PositionedStack getResultStack(int recipe);
|
||||
|
||||
/**
|
||||
* @param recipe The recipe index to get the group id for.
|
||||
* @return An id shared by every recipe in this recipe's group, or {@code null} if this recipe isn't grouped.
|
||||
*/
|
||||
default Object getRecipeGroupId(int recipe) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A tick function called for updating progress bars and cycling damage items.
|
||||
*/
|
||||
|
||||
@@ -1,688 +0,0 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.FavoriteRecipes;
|
||||
import codechicken.nei.KeyManager;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.NEIServerUtils;
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.Widget;
|
||||
import codechicken.nei.api.IGuiContainerOverlay;
|
||||
import codechicken.nei.api.ShortcutInputHandler;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.recipe.GuiRecipeButton.UpdateRecipeButtonsEvent;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.debug.DebugHandlerWidget;
|
||||
import codechicken.nei.util.NEIMouseUtils;
|
||||
|
||||
public class NEIRecipeWidget extends Widget {
|
||||
|
||||
protected AcceptsFollowingTooltipLineHandler acceptsFollowingTooltipLineHandler;
|
||||
protected final Map<PositionedStack, Integer> favoriteIndexes = new WeakHashMap<>();
|
||||
protected final Map<PositionedStack, List<ItemStack>> permutations = new WeakHashMap<>();
|
||||
protected final Map<PositionedStack, List<Badge>> badgeCache = new WeakHashMap<>();
|
||||
protected int favoriteRevision = -1;
|
||||
protected boolean update = true;
|
||||
protected int cycleticks = 0;
|
||||
protected int lastcycle = -1;
|
||||
|
||||
protected final RecipeHandlerRef handlerRef;
|
||||
protected final HandlerInfo handlerInfo;
|
||||
|
||||
protected boolean showAsWidget = false;
|
||||
protected List<GuiRecipeButton> recipeButtons = null;
|
||||
|
||||
public NEIRecipeWidget(RecipeHandlerRef handlerRef) {
|
||||
this.handlerRef = handlerRef;
|
||||
this.handlerInfo = GuiRecipeTab.getHandlerInfo(this.handlerRef.handler);
|
||||
update();
|
||||
}
|
||||
|
||||
public void setLocation(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
|
||||
if (this.showAsWidget || !this.handlerInfo.isAllowOverflowY()) {
|
||||
final int recipeHeight = this.handlerRef.handler.getRecipeHeight(this.handlerRef.recipeIndex);
|
||||
this.w = Math.max(166, this.handlerInfo.getWidth());
|
||||
this.h = recipeHeight > 0 ? recipeHeight : this.handlerInfo.getHeight();
|
||||
this.h += this.handlerInfo.getYShift();
|
||||
}
|
||||
|
||||
this.update = true;
|
||||
}
|
||||
|
||||
public List<GuiRecipeButton> getRecipeButtons() {
|
||||
|
||||
if (this.recipeButtons == null) {
|
||||
if (!getOutputs().isEmpty()) {
|
||||
this.recipeButtons = initButtons();
|
||||
} else {
|
||||
this.recipeButtons = Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(this.recipeButtons);
|
||||
}
|
||||
|
||||
protected List<GuiRecipeButton> getRecipeButtonsIfInit() {
|
||||
|
||||
if (this.recipeButtons == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(this.recipeButtons);
|
||||
}
|
||||
|
||||
public RecipeHandlerRef getRecipeHandlerRef() {
|
||||
return this.handlerRef;
|
||||
}
|
||||
|
||||
public Recipe getRecipe() {
|
||||
return Recipe.of(this.handlerRef);
|
||||
}
|
||||
|
||||
public HandlerInfo getHandlerInfo() {
|
||||
return this.handlerInfo;
|
||||
}
|
||||
|
||||
public void showAsWidget(boolean show) {
|
||||
this.showAsWidget = show;
|
||||
}
|
||||
|
||||
protected List<GuiRecipeButton> initButtons() {
|
||||
final GuiRecipe<?> guiRecipe = getGuiRecipe();
|
||||
|
||||
if (guiRecipe != null) {
|
||||
final UpdateRecipeButtonsEvent.Pre preEvent = new UpdateRecipeButtonsEvent.Pre(
|
||||
guiRecipe,
|
||||
this,
|
||||
this.handlerInfo);
|
||||
|
||||
if (MinecraftForge.EVENT_BUS.post(preEvent)) {
|
||||
return preEvent.buttonList;
|
||||
} else {
|
||||
final UpdateRecipeButtonsEvent.Post postEvent = new UpdateRecipeButtonsEvent.Post(
|
||||
guiRecipe,
|
||||
this,
|
||||
getDefaultButtons());
|
||||
MinecraftForge.EVENT_BUS.post(postEvent);
|
||||
return postEvent.buttonList;
|
||||
}
|
||||
|
||||
} else {
|
||||
return getDefaultButtons();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected List<GuiRecipeButton> getDefaultButtons() {
|
||||
GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
|
||||
final List<GuiRecipeButton> buttons = new ArrayList<>();
|
||||
final boolean showFavorites = NEIClientConfig.favoritesEnabled() && handlerInfo.getShowFavoritesButton();
|
||||
final boolean showOverlay = handlerInfo.getShowOverlayButton();
|
||||
final int x = Math.min(166, this.w) - GuiRecipeButton.BUTTON_WIDTH;
|
||||
int y = this.h - GuiRecipeButton.BUTTON_HEIGHT - 6;
|
||||
|
||||
if (guiContainer instanceof IGuiContainerOverlay overlay) {
|
||||
guiContainer = overlay.getFirstScreen();
|
||||
}
|
||||
|
||||
if (showOverlay) {
|
||||
buttons.add(new GuiOverlayButton(guiContainer, this.handlerRef, x, y));
|
||||
y -= GuiRecipeButton.BUTTON_HEIGHT + 1;
|
||||
}
|
||||
|
||||
if (showFavorites) {
|
||||
buttons.add(new GuiFavoriteButton(handlerRef, x, y));
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mouseX, int mouseY) {
|
||||
final int yShift = this.handlerInfo.getYShift();
|
||||
|
||||
if (this.update) {
|
||||
this.update = false;
|
||||
|
||||
if (!NEIClientUtils.shiftKey() && ((this.cycleticks++) / 20) != this.lastcycle || this.lastcycle == -1) {
|
||||
this.lastcycle = this.cycleticks / 20;
|
||||
updatePermutations();
|
||||
|
||||
for (GuiRecipeButton button : getRecipeButtonsIfInit()) {
|
||||
button.onPermutationsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
for (GuiRecipeButton button : getRecipeButtons()) {
|
||||
button.update();
|
||||
}
|
||||
}
|
||||
|
||||
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
|
||||
GL11.glTranslatef(this.x, this.y + yShift, 0);
|
||||
|
||||
this.handlerRef.handler.drawBackground(this.handlerRef.recipeIndex);
|
||||
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
|
||||
GuiContainerManager.enableMatrixStackLogging();
|
||||
|
||||
for (PositionedStack pStack : getInputs()) {
|
||||
|
||||
if (!this.permutations.containsKey(pStack)) {
|
||||
updatePermutationsFor(pStack);
|
||||
}
|
||||
|
||||
drawItem(pStack, mouseX, mouseY, yShift, true);
|
||||
}
|
||||
|
||||
for (PositionedStack pStack : getCatalysts()) {
|
||||
|
||||
if (!this.permutations.containsKey(pStack)) {
|
||||
updatePermutationsFor(pStack);
|
||||
}
|
||||
|
||||
drawItem(pStack, mouseX, mouseY, yShift, true);
|
||||
}
|
||||
|
||||
for (PositionedStack pStack : getOutputs()) {
|
||||
drawItem(pStack, mouseX, mouseY, yShift, false);
|
||||
}
|
||||
|
||||
GuiContainerManager.disableMatrixStackLogging();
|
||||
|
||||
this.handlerRef.handler.drawForeground(this.handlerRef.recipeIndex);
|
||||
|
||||
final GuiRecipeButton overlayButton = forEachButtons(
|
||||
button -> (this.showAsWidget ? button instanceof GuiOverlayButton : button.contains(mouseX, mouseY))
|
||||
? button
|
||||
: null,
|
||||
null);
|
||||
|
||||
if (overlayButton != null) {
|
||||
NEIClientUtils.gl2DRenderContext(() -> overlayButton.drawItemOverlay());
|
||||
}
|
||||
|
||||
GL11.glTranslatef(-this.x, -this.y - yShift, 0);
|
||||
GL11.glPopAttrib();
|
||||
|
||||
if (!this.showAsWidget) {
|
||||
final Minecraft mc = NEIClientUtils.mc();
|
||||
for (GuiRecipeButton button : getRecipeButtons()) {
|
||||
button.xPosition += this.x;
|
||||
button.yPosition += this.y;
|
||||
button.drawButton(mc, mouseX, mouseY);
|
||||
button.xPosition -= this.x;
|
||||
button.yPosition -= this.y;
|
||||
}
|
||||
}
|
||||
|
||||
DebugHandlerWidget.instance.drawGuiPlaceholder(this);
|
||||
}
|
||||
|
||||
protected void drawItem(PositionedStack pStack, int mouseX, int mouseY, int yShift, boolean input) {
|
||||
pStack.draw(mouseX - this.x, mouseY - this.y - yShift);
|
||||
|
||||
if (this.handlerInfo.getShowBadge()) {
|
||||
drawBadge(pStack, input);
|
||||
}
|
||||
|
||||
if (pStack.contains(mouseX - this.x, mouseY - this.y - yShift)) {
|
||||
NEIClientUtils.gl2DRenderContext(
|
||||
() -> GuiDraw.drawRect(pStack.relx, pStack.rely, pStack.width, pStack.height, 0x80FFFFFF));
|
||||
}
|
||||
}
|
||||
|
||||
protected List<Badge> getBadges(PositionedStack pStack, boolean input) {
|
||||
|
||||
return this.badgeCache.computeIfAbsent(pStack, k -> {
|
||||
final List<Badge> badges = k.getBadges();
|
||||
|
||||
if (badges == null) {
|
||||
|
||||
if (input) {
|
||||
if (StackInfo.getAmount(pStack.item) == 0) {
|
||||
return Collections.singletonList(Badge.notConsumed());
|
||||
} else if (pStack.getChance() == 0) {
|
||||
return Collections.singletonList(Badge.notConsumedParallel());
|
||||
} else if (pStack.getChance() != PositionedStack.CHANCE_FULL) {
|
||||
return Collections.singletonList(
|
||||
Badge.consumeChance(pStack.getChance() / (float) PositionedStack.CHANCE_FULL));
|
||||
}
|
||||
} else if (pStack.getChance() != PositionedStack.CHANCE_FULL) {
|
||||
return Collections.singletonList(
|
||||
Badge.outputChance(pStack.getChance() / (float) PositionedStack.CHANCE_FULL));
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return badges;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
protected void drawBadge(PositionedStack pStack, boolean input) {
|
||||
final List<Badge> badges = getBadges(pStack, input);
|
||||
|
||||
for (Badge badge : badges) {
|
||||
badge.draw(new Rectangle4i(pStack.relx, pStack.rely, pStack.width, pStack.height));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyPress(int keyID, char keyChar) {
|
||||
|
||||
if (NEIClientConfig.favoritesEnabled()
|
||||
&& KeyManager.isHashDown("bookmark.favorite_item", NEIClientUtils.SHIFT_HASH)) {
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
final int yShift = this.handlerInfo.getYShift();
|
||||
PositionedStack pStackOver = null;
|
||||
|
||||
for (PositionedStack pStack : getInputs()) {
|
||||
if (pStack.contains(mouse.x - this.x, mouse.y - this.y - yShift)) {
|
||||
pStackOver = pStack;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pStackOver != null) {
|
||||
|
||||
if (FavoriteRecipes.containsManual(pStackOver.item)) {
|
||||
FavoriteRecipes.setFavorite(pStackOver.item, null);
|
||||
} else {
|
||||
FavoriteRecipes.setFavorite(
|
||||
pStackOver.item,
|
||||
RecipeId.of(
|
||||
pStackOver.item,
|
||||
FavoriteRecipes.FAVORITE_ITEM,
|
||||
Arrays.asList(new ItemStack(Blocks.fire, 1), pStackOver.item)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lastKeyTyped(int keyID, char keyChar) {
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
|
||||
forEachButtons(button -> {
|
||||
|
||||
if (button.contains(mouse.x, mouse.y)) {
|
||||
button.lastKeyTyped(keyChar, keyID);
|
||||
}
|
||||
|
||||
return null;
|
||||
}, null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleClick(int mouseX, int mouseY, int button) {
|
||||
|
||||
if (ShortcutInputHandler.handleMouseClick(getStackMouseOver(mouseX, mouseY))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (button == 0) {
|
||||
final Minecraft mc = NEIClientUtils.mc();
|
||||
|
||||
if (forEachButtons(guibutton -> {
|
||||
|
||||
if (guibutton.mousePressed(mc, mouseX, mouseY)) {
|
||||
NEIClientUtils.playClickSound();
|
||||
guibutton.mouseReleased(mouseX, mouseY);
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}, false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final GuiRecipe<?> guiRecipe = getGuiRecipe();
|
||||
if (guiRecipe == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.handlerRef.handler.mouseClicked(guiRecipe, button, this.handlerRef.recipeIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(int mouseX, int mouseY, List<String> tooltip) {
|
||||
final GuiRecipe<?> guiRecipe = getGuiRecipe();
|
||||
|
||||
if (guiRecipe == null) {
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
final List<String> localTooltip = this.handlerRef.handler
|
||||
.handleTooltip(guiRecipe, tooltip, this.handlerRef.recipeIndex);
|
||||
|
||||
return forEachButtons(
|
||||
button -> button.contains(mouseX, mouseY) ? button.handleTooltip(localTooltip) : null,
|
||||
localTooltip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleItemTooltip(ItemStack itemstack, int mousex, int mousey, List<String> tooltip) {
|
||||
final GuiRecipe<?> guiRecipe = getGuiRecipe();
|
||||
|
||||
if (guiRecipe == null) {
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
tooltip = this.handlerRef.handler.handleItemTooltip(guiRecipe, itemstack, tooltip, this.handlerRef.recipeIndex);
|
||||
|
||||
if (itemstack != null) {
|
||||
final PositionedStack hovered = getPositionedStackMouseOver(mousex, mousey);
|
||||
|
||||
if (hovered != null) {
|
||||
if (this.handlerInfo.getShowBadge()) {
|
||||
final List<Badge> badges = getBadges(hovered, getOutputs().indexOf(hovered) == -1);
|
||||
|
||||
for (Badge badge : badges) {
|
||||
if (badge.getTooltip() != null && !badge.getTooltip().isEmpty()) {
|
||||
tooltip.addAll(badge.getTooltip());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final List<String> customTooltip = hovered.getTooltip();
|
||||
|
||||
if (customTooltip != null && !customTooltip.isEmpty()) {
|
||||
tooltip.addAll(customTooltip);
|
||||
}
|
||||
}
|
||||
|
||||
if (hovered == null || !NEIClientConfig.showCycledIngredientsTooltip()
|
||||
|| this.permutations.getOrDefault(hovered, Collections.emptyList()).size() <= 1
|
||||
|| getOutputs().indexOf(hovered) != -1) {
|
||||
this.acceptsFollowingTooltipLineHandler = null;
|
||||
} else if (this.acceptsFollowingTooltipLineHandler == null
|
||||
|| this.acceptsFollowingTooltipLineHandler.tooltipGUID != hovered) {
|
||||
this.acceptsFollowingTooltipLineHandler = AcceptsFollowingTooltipLineHandler
|
||||
.of(hovered, this.permutations.get(hovered), hovered.item);
|
||||
|
||||
if (this.acceptsFollowingTooltipLineHandler != null && hovered.getAcceptsLabel() != null) {
|
||||
this.acceptsFollowingTooltipLineHandler.setLabel(hovered.getAcceptsLabel());
|
||||
}
|
||||
}
|
||||
} else if (this.acceptsFollowingTooltipLineHandler != null) {
|
||||
this.acceptsFollowingTooltipLineHandler = null;
|
||||
}
|
||||
|
||||
if (this.acceptsFollowingTooltipLineHandler != null) {
|
||||
tooltip.add(GuiDraw.TOOLTIP_HANDLER + GuiDraw.getTipLineId(this.acceptsFollowingTooltipLineHandler));
|
||||
}
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> handleHotkeys(int mouseX, int mouseY, Map<String, String> hotkeys) {
|
||||
final int yShift = this.handlerInfo.getYShift();
|
||||
final Map<String, String> buttonHotkeys = forEachButtons(
|
||||
button -> button.contains(mouseX, mouseY) ? button.handleHotkeys(mouseX, mouseY, hotkeys) : null,
|
||||
hotkeys);
|
||||
|
||||
if (this.acceptsFollowingTooltipLineHandler != null) {
|
||||
buttonHotkeys.put(
|
||||
NEIClientUtils.getKeyName(
|
||||
NEIClientUtils.SHIFT_HASH,
|
||||
NEIMouseUtils.MOUSE_BTN_NONE + NEIMouseUtils.MOUSE_SCROLL),
|
||||
NEIClientUtils.translate("recipe.accepts.scroll"));
|
||||
}
|
||||
|
||||
if (getInputs().stream().anyMatch(
|
||||
pStack -> this.permutations.getOrDefault(pStack, Collections.emptyList()).size() > 1
|
||||
&& pStack.contains(mouseX - this.x, mouseY - this.y - yShift))) {
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.favorite_item", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("recipe.favorite.toggle"));
|
||||
}
|
||||
|
||||
return buttonHotkeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMouseWheel(int scroll, int mx, int my) {
|
||||
|
||||
if (forEachButtons(button -> button.contains(mx, my) ? button.mouseScrolled(scroll) : null, false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (scrollPermutations(scroll, mx, my)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final GuiRecipe<?> guiRecipe = getGuiRecipe();
|
||||
|
||||
return guiRecipe != null
|
||||
&& this.handlerRef.handler.mouseScrolled(guiRecipe, scroll, this.handlerRef.recipeIndex);
|
||||
}
|
||||
|
||||
protected boolean scrollPermutations(int scroll, int mx, int my) {
|
||||
if (!NEIClientUtils.shiftKey()) return false;
|
||||
final PositionedStack overStack = getPositionedStackMouseOver(mx, my);
|
||||
|
||||
if (overStack != null && this.permutations.getOrDefault(overStack, Collections.emptyList()).size() > 1) {
|
||||
final List<ItemStack> items = this.permutations.get(overStack);
|
||||
final int stackIndex = indexOf(items, overStack.item);
|
||||
final ItemStack stack = items.get((items.size() - scroll + stackIndex) % items.size());
|
||||
|
||||
Stream.concat(getInputs().stream(), getCatalysts().stream()).filter(pStack -> pStack.containsWithNBT(stack))
|
||||
.forEach(pStack -> pStack.setPermutationToRender(stack));
|
||||
|
||||
if (this.acceptsFollowingTooltipLineHandler != null) {
|
||||
this.acceptsFollowingTooltipLineHandler
|
||||
.setActiveStack(((PositionedStack) this.acceptsFollowingTooltipLineHandler.tooltipGUID).item);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected int indexOf(List<ItemStack> list, ItemStack stack) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(list.get(i), stack)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected <R> R forEachButtons(Function<GuiRecipeButton, R> callback, R defaultValue) {
|
||||
|
||||
for (GuiRecipeButton button : getRecipeButtonsIfInit()) {
|
||||
button.xPosition += this.x;
|
||||
button.yPosition += this.y;
|
||||
|
||||
final R result = callback.apply(button);
|
||||
|
||||
button.xPosition -= this.x;
|
||||
button.yPosition -= this.y;
|
||||
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public boolean isFocusedRecipe(int mx, int my) {
|
||||
final int yShift = this.handlerInfo.getYShift();
|
||||
|
||||
for (PositionedStack pStackOver : getOutputs()) {
|
||||
if (pStackOver.contains(mx - this.x, my - this.y - yShift)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public PositionedStack getPositionedStackMouseOver(int mx, int my) {
|
||||
final int yShift = this.handlerInfo.getYShift();
|
||||
|
||||
for (PositionedStack pStack : getInputs()) {
|
||||
if (pStack.contains(mx - this.x, my - this.y - yShift)) {
|
||||
return pStack;
|
||||
}
|
||||
}
|
||||
|
||||
for (PositionedStack pStack : getCatalysts()) {
|
||||
if (pStack.contains(mx - this.x, my - this.y - yShift)) {
|
||||
return pStack;
|
||||
}
|
||||
}
|
||||
|
||||
for (PositionedStack pStack : getOutputs()) {
|
||||
if (pStack.contains(mx - this.x, my - this.y - yShift)) {
|
||||
return pStack;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackMouseOver(int mx, int my) {
|
||||
final PositionedStack pStack = getPositionedStackMouseOver(mx, my);
|
||||
return pStack != null ? pStack.item : null;
|
||||
}
|
||||
|
||||
protected GuiRecipe<?> getGuiRecipe() {
|
||||
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
|
||||
|
||||
if (guiContainer instanceof GuiRecipe<?>guiRecipe) {
|
||||
return guiRecipe;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected GuiContainer getFirstGui() {
|
||||
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
|
||||
|
||||
if (guiContainer instanceof GuiRecipe<?>guiRecipe) {
|
||||
return guiRecipe.firstGui;
|
||||
}
|
||||
|
||||
return guiContainer;
|
||||
}
|
||||
|
||||
protected void updatePermutations() {
|
||||
final int rev = FavoriteRecipes.getRevision();
|
||||
|
||||
if (this.favoriteRevision != rev) {
|
||||
this.favoriteRevision = rev;
|
||||
this.acceptsFollowingTooltipLineHandler = null;
|
||||
this.favoriteIndexes.clear();
|
||||
this.permutations.clear();
|
||||
this.badgeCache.clear();
|
||||
}
|
||||
|
||||
for (PositionedStack pStack : getInputs()) {
|
||||
updatePermutationsFor(pStack);
|
||||
}
|
||||
|
||||
for (PositionedStack pStack : getCatalysts()) {
|
||||
updatePermutationsFor(pStack);
|
||||
}
|
||||
|
||||
if (this.acceptsFollowingTooltipLineHandler != null) {
|
||||
this.acceptsFollowingTooltipLineHandler
|
||||
.setActiveStack(((PositionedStack) this.acceptsFollowingTooltipLineHandler.tooltipGUID).item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void updatePermutationsFor(PositionedStack pStack) {
|
||||
List<ItemStack> perms = this.permutations.get(pStack);
|
||||
int favoriteIndex = this.favoriteIndexes.getOrDefault(pStack, -1);
|
||||
boolean needsUpdate = false;
|
||||
|
||||
if (perms == null) {
|
||||
perms = pStack.getFilteredPermutations();
|
||||
favoriteIndex = -1;
|
||||
|
||||
if (perms.size() > 1) {
|
||||
for (ItemStack item : perms) {
|
||||
if (!FavoriteRecipes.containsManual(item)) break;
|
||||
favoriteIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
this.permutations.put(pStack, perms);
|
||||
this.favoriteIndexes.put(pStack, favoriteIndex);
|
||||
needsUpdate = true;
|
||||
}
|
||||
|
||||
if (perms.size() > 1 || needsUpdate) {
|
||||
final int size = favoriteIndex != -1 ? favoriteIndex + 1 : perms.size();
|
||||
|
||||
if (size > 0) {
|
||||
pStack.setPermutationToRender(perms.get(this.lastcycle % size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected List<PositionedStack> getInputs() {
|
||||
return this.handlerRef.handler.getIngredientStacks(this.handlerRef.recipeIndex);
|
||||
}
|
||||
|
||||
protected List<PositionedStack> getOutputs() {
|
||||
final PositionedStack pStackResult = this.handlerRef.handler.getResultStack(this.handlerRef.recipeIndex);
|
||||
return pStackResult != null ? Arrays.asList(pStackResult)
|
||||
: this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex);
|
||||
}
|
||||
|
||||
protected List<PositionedStack> getCatalysts() {
|
||||
if (this.handlerRef.handler.getResultStack(this.handlerRef.recipeIndex) == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,9 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
@@ -43,7 +45,13 @@ public class Recipe {
|
||||
|
||||
if (!isShapedRecipe()) {
|
||||
// sort to ignore ingredients position in shapeless recipes
|
||||
this.ingredients.sort(Comparator.comparing(StackInfo::getItemStackGUID));
|
||||
final Map<ItemStack, String> guids = new IdentityHashMap<>();
|
||||
|
||||
for (ItemStack ingredient : this.ingredients) {
|
||||
guids.put(ingredient, StackInfo.getItemStackGUID(ingredient));
|
||||
}
|
||||
|
||||
this.ingredients.sort(Comparator.comparing(guids::get));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +60,10 @@ public class Recipe {
|
||||
}
|
||||
|
||||
public static RecipeId of(IRecipeHandler handler, int recipeIndex) {
|
||||
final List<PositionedStack> ingredients = handler.getIngredientStacks(recipeIndex);
|
||||
return of(handler, recipeIndex, handler.getIngredientStacks(recipeIndex));
|
||||
}
|
||||
|
||||
public static RecipeId of(IRecipeHandler handler, int recipeIndex, List<PositionedStack> ingredients) {
|
||||
final String handlerName = GuiRecipeTab.getHandlerInfo(handler).getHandlerName();
|
||||
PositionedStack pStackResult = handler.getResultStack(recipeIndex);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -36,12 +37,12 @@ public class RecipeHandlerRef {
|
||||
.getCraftingHandlers("recipeId", recipeId.getResult(), recipeId);
|
||||
|
||||
for (ICraftingHandler handler : handlers) {
|
||||
int refIndex = SearchRecipeHandler.findFirst(
|
||||
int recipeIndex = SearchRecipeHandler.findFirst(
|
||||
handler,
|
||||
recipeIndex -> recipeId.equalsIngredients(handler.getIngredientStacks(recipeIndex)));
|
||||
index -> recipeId.equalsIngredients(handler.getIngredientStacks(index)));
|
||||
|
||||
if (refIndex >= 0) {
|
||||
return new RecipeHandlerRef(handler, refIndex);
|
||||
if (recipeIndex >= 0) {
|
||||
return new RecipeHandlerRef(handler, recipeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,10 +67,6 @@ public class RecipeHandlerRef {
|
||||
return firstGui != null && firstGui.inventorySlots != null ? firstGui : null;
|
||||
}
|
||||
|
||||
public NEIRecipeWidget getRecipeWidget() {
|
||||
return new NEIRecipeWidget(this);
|
||||
}
|
||||
|
||||
public IOverlayHandler getOverlayHandler(GuiContainer gui) {
|
||||
final GuiContainer firstGui = prepareGui(gui);
|
||||
|
||||
@@ -171,6 +168,8 @@ public class RecipeHandlerRef {
|
||||
return transferAlghoritmCache.computeIfAbsent(overlayHandler.getClass(), clazz -> {
|
||||
|
||||
try {
|
||||
final Method transferRecipe = overlayHandler.getClass()
|
||||
.getMethod("transferRecipe", GuiContainer.class, IRecipeHandler.class, int.class, int.class);
|
||||
|
||||
if (overlayHandler instanceof DefaultOverlayHandler) {
|
||||
final Class<?> overlayRecipeClazz = overlayHandler.getClass()
|
||||
@@ -182,14 +181,11 @@ public class RecipeHandlerRef {
|
||||
boolean.class)
|
||||
.getDeclaringClass();
|
||||
|
||||
if (overlayRecipeClazz.equals(DefaultOverlayHandler.class)) {
|
||||
return true;
|
||||
}
|
||||
return overlayRecipeClazz.equals(DefaultOverlayHandler.class)
|
||||
|| !transferRecipe.getDeclaringClass().equals(DefaultOverlayHandler.class);
|
||||
}
|
||||
|
||||
return !overlayHandler.getClass()
|
||||
.getMethod("transferRecipe", GuiContainer.class, IRecipeHandler.class, int.class, int.class)
|
||||
.isDefault();
|
||||
return !transferRecipe.isDefault();
|
||||
} catch (NoSuchMethodException e) {}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -7,14 +7,10 @@ import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.FavoriteRecipes;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.api.ShortcutInputHandler;
|
||||
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
|
||||
import codechicken.nei.bookmark.BookmarksGridSlot;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerInputHandler;
|
||||
@@ -33,6 +29,11 @@ public class RecipeItemInputHandler implements IContainerInputHandler, IContaine
|
||||
|
||||
@Override
|
||||
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyCode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHotkeyPressed(GuiContainer gui) {
|
||||
return ShortcutInputHandler.handleKeyEvent(GuiContainerManager.getStackMouseOver(gui));
|
||||
}
|
||||
|
||||
@@ -58,7 +59,9 @@ public class RecipeItemInputHandler implements IContainerInputHandler, IContaine
|
||||
List<String> currenttip) {
|
||||
|
||||
if (itemstack != null) {
|
||||
final RecipeId recipeId = getHoveredRecipeId(gui, itemstack, mousex, mousey);
|
||||
final HoveredRecipe hovered = HoveredRecipe.of(gui, itemstack);
|
||||
final RecipeId recipeId = hovered != null && showRecipeTooltip(hovered, mousex, mousey) ? hovered.recipeId
|
||||
: null;
|
||||
|
||||
if (recipeId == null) {
|
||||
recipeTooltipLineHandler = null;
|
||||
@@ -76,49 +79,21 @@ public class RecipeItemInputHandler implements IContainerInputHandler, IContaine
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
private RecipeId getHoveredRecipeId(GuiContainer gui, ItemStack itemstack, int mousex, int mousey) {
|
||||
private boolean showRecipeTooltip(HoveredRecipe hovered, int mousex, int mousey) {
|
||||
return switch (hovered.source) {
|
||||
case BOOKMARK -> !hovered.favorite && showRecipeTooltipInBookmarks(mousex, mousey);
|
||||
case ITEM_PANEL -> NEIClientConfig.showRecipeTooltipInPanel();
|
||||
case RECIPE_GUI -> hovered.favorite && NEIClientConfig.showRecipeTooltipInGui();
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
if (ItemPanels.bookmarkPanel.contains(mousex, mousey)) {
|
||||
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (slot != null && slot.getRecipeId() != null
|
||||
&& slot.getType() != BookmarkItemType.INGREDIENT
|
||||
&& NEIClientConfig.getRecipeTooltipsMode() != 0) {
|
||||
final int tooltipMode = NEIClientConfig.getRecipeTooltipsMode();
|
||||
final BookmarkViewMode viewMode = slot.getGroup().viewMode;
|
||||
if (tooltipMode == 3 || viewMode == BookmarkViewMode.DEFAULT && tooltipMode == 1
|
||||
|| viewMode == BookmarkViewMode.TODO_LIST && tooltipMode == 2) {
|
||||
return slot.getRecipeId();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.showRecipeTooltipInPanel()) {
|
||||
ItemsGridSlot panelSlot = ItemPanels.itemPanel.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (panelSlot == null) {
|
||||
panelSlot = ItemPanels.itemPanel.historyPanel.getSlotMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
if (panelSlot == null) {
|
||||
panelSlot = ItemPanels.itemPanel.craftablesPanel.getSlotMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
if (panelSlot != null) {
|
||||
return panelSlot.getRecipeId();
|
||||
}
|
||||
}
|
||||
|
||||
if (gui instanceof GuiRecipe<?>guiRecipe
|
||||
&& new Rectangle4i(gui.guiLeft, gui.guiTop, gui.xSize, gui.ySize).contains(mousex, mousey)
|
||||
&& NEIClientConfig.showRecipeTooltipInGui()
|
||||
&& guiRecipe.getFocusedRecipe() == null) {
|
||||
return FavoriteRecipes.getFavorite(itemstack);
|
||||
}
|
||||
|
||||
return null;
|
||||
private boolean showRecipeTooltipInBookmarks(int mousex, int mousey) {
|
||||
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mousex, mousey);
|
||||
final int tooltipMode = NEIClientConfig.getRecipeTooltipsMode();
|
||||
final BookmarkViewMode viewMode = slot.getGroup().viewMode;
|
||||
return tooltipMode == 3 || viewMode == BookmarkViewMode.DEFAULT && tooltipMode == 1
|
||||
|| viewMode == BookmarkViewMode.TODO_LIST && tooltipMode == 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Loaded 100 of 139 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user