Compare commits

...
Author SHA1 Message Date
sbancuz 2169ba03d0 Merge remote-tracking branch 'origin/multi-result' into multi-result 2026-08-02 21:16:56 +02:00
sbancuz 7f182757c3 De-dupe draw calls 2026-08-02 21:16:43 +02:00
sbancuz 83ee2e0d53 FurnaceHandler 2026-08-02 21:01:08 +02:00
Luca Bancale ff518c81b3 Merge branch 'master' into multi-result 2026-08-02 20:50:13 +02:00
slprime 5fb5ab6698 Added Bookmark Chain Visitor (#991) 2026-08-01 20:35:19 +03:00
slprime f47a8766a9 Create EmptyContainer (#990) 2026-08-01 20:19:54 +03:00
slprime 4cc72444d9 Fix Tooltip with Component in first line (#989) 2026-08-01 20:00:17 +03:00
slprime b48956ef94 Bookmarks Chain: fix container item multiplier limit (#988) 2026-07-29 00:57:12 +03:00
Algentandslprime 583d28ed12 Fix GL reset (#984)
Co-authored-by: slprime <31038811+slprime@users.noreply.github.com>
2026-07-26 23:36:37 +03:00
koolkrafter5 384813347c Overlay Button moves one item if the recipe stack is size zero (#985) 2026-07-26 23:28:39 +03:00
slprime 2660460c87 Merge branch 'master' into multi-result 2026-07-25 02:14:33 +03:00
slprime 2b28068382 Simplify the keybinding (#982) 2026-07-25 02:14:12 +03:00
sbancuz 1767d4be63 Fix isEmpty conditions, and add catalysts for not breaking old APIs 2026-07-17 12:33:04 +02:00
sbancuz e6684ddebb Fix isEmpty conditions, and add extraInputs for not breaking old APIs 2026-07-17 11:54:34 +02:00
sbancuz 89110ccb7e Check if new behavior is supported (no fallbacks for now) 2026-07-16 16:47:56 +02:00
sbancuz 434b4ac879 Review 2026-07-16 16:05:32 +02:00
sbancuz 24e6f7c57d Allow proper representation of recipes with multiple results 2026-07-16 12:06:40 +02:00
slprime 2c204c25aa Rework chat item link to support bookmarking recipes and groups (#971) 2026-07-11 20:38:01 +03:00
Jordan Rey 5e6ff1d63b fix: spawner placement logic (#973) 2026-07-11 20:33:51 +03:00
Algent 53ce50b35a oregenPattern this time for sure (#974) 2026-07-11 19:53:43 +03:00
slprime 835c4f7e01 Fix Dynamic Keybinding (#972) 2026-07-11 14:20:03 +03:00
RecursivePineapple f8c1f39faf Add Cubic Chunks cube overlay & fix chunk grid above y=256, below y=0. (#970) 2026-07-10 11:02:43 +03:00
slprime 4c4716e64f Fix duplicate keybinding handling by patching KeyBinding static handlers (#968) 2026-07-08 09:19:48 +03:00
LunaandMartin Robertz c84ac27a18 Add offset for snow block to mob spawn overlay (#965)
Co-authored-by: Martin Robertz <dream-master@gmx.net>
2026-07-07 11:44:58 +02:00
mllfjn 47baee272c Remove redundant simplewasher recipe (#967) 2026-07-07 11:08:44 +02:00
Martin Robertz f55dc716e3 update deps 2026-07-04 19:50:07 +02:00
slprimeandMartin Robertz 26beb079f0 [Feature] Keybinding Refactoring (#957)
Co-authored-by: Martin Robertz <dream-master@gmx.net>
2026-07-04 14:38:02 +03:00
Algent 841b73c6fe Update way of getting oregen pattern for GT overlay (#964) 2026-06-30 18:18:32 +03:00
slprime 0c7eeebb1f Fix Debug Handler (#963) 2026-06-29 20:24:36 +03:00
slprime 65b56735a7 Add item name aliases for search (#961) 2026-06-29 18:08:59 +02:00
slprime ff428bf538 Allow plugins to force fill mode for overlay button (#960) 2026-06-28 13:11:27 -04:00
Martin Robertz a406021f26 deps 2026-06-27 15:15:43 +02:00
slprime 8500ac57eb Persist hidden items by GUID across reloads (#959) 2026-06-27 00:48:39 +03:00
slprime d97123ec13 ItemLoader Refactoring/Optimization (#958) 2026-06-26 21:25:07 +03:00
slprime 434931bfac Fix Loading Items error log (#956) 2026-06-21 00:57:41 +03:00
RanzuandMartin Robertz 860011036b Convert color class (#947)
Co-authored-by: Martin Robertz <dream-master@gmx.net>
2026-06-16 10:21:20 +02:00
slprime 937c1858a4 Fix Config Option NPE (#951) 2026-06-14 21:14:44 +03:00
slprime 4562ecf087 Fix Broken DisplayName in Untranslator (#949) 2026-06-13 17:46:46 +03:00
slprime d621d5d5bd Fix Autocrefing Permission (#948) 2026-06-13 17:25:07 +03:00
Martin Robertz 3175b316af update+gradle+deps+bs 2026-06-12 23:32:41 +02:00
slprime 61930ac7a8 Add server-controlled autocraft permission (#942) 2026-06-10 18:58:23 +03:00
slprime fcbf1dcade Fix Single Item In Bookmarks With Amount (#941) 2026-06-07 20:22:42 +03:00
slprime 3fa69e826c Guard loadTransferRects against plugin init errors (#939) 2026-05-27 08:26:29 +03:00
31fff21a55 Smart-Fallback & Alchemic Chemistry Set Fix (#935)
Co-authored-by: FFS <FFS@OhFuckOff>
Co-authored-by: slprime <31038811+slprime@users.noreply.github.com>
2026-05-27 02:29:59 +03:00
slprime 2e9ab88692 Fix ItemStack load from NBT with short overflow (#938) 2026-05-27 02:22:47 +03:00
slprime a02d293d44 Fix Recipe Page Area (#932) 2026-05-11 18:47:36 +03:00
sisyphussy 1265113390 Fix mui2 screen capture (#930) 2026-05-07 20:30:52 +03:00
slprime 4ffd614017 GuiRecipe: Add scrollPages Option (#929) 2026-05-07 18:57:15 +03:00
slprime 41554f4c5b Options: fix memory leaks (#928) 2026-05-06 22:36:07 +02:00
slprime 2104184077 GuiInfo: fix memory leaks (#927) 2026-05-06 20:18:35 +02:00
slprime d5f25a4be8 Prevent ConcurrentModificationException while searching for fuels in ItemList (#926) 2026-05-06 19:43:50 +03:00
slprime ccbf94790a Add Horizontal Scroll to Recipe GUI (#924) 2026-05-06 19:31:00 +03:00
slprime 2f4f72a2d6 Fix Filter Loading (#925) 2026-05-06 07:55:49 +03:00
danyadevandslprime f8cec9a78c Much faster recipe dumper (#920)
Co-authored-by: slprime <31038811+slprime@users.noreply.github.com>
2026-04-25 14:58:50 +03:00
Lucaandslprime fb43a662eb Fix StringIndexOutOfBoundsException in FormattedTextField (#922)
Co-authored-by: slprime <31038811+slprime@users.noreply.github.com>
2026-04-25 10:30:32 +00:00
Luca b2e0b8878a Fix bookmark recipe item order being inconsistent (#921) 2026-04-25 13:21:46 +03:00
slprime 374f019103 Fix Autocrafting NPE (#917) 2026-04-14 01:29:26 +03:00
slprime 5dfcff6f30 Rollback PR#913 (#916) 2026-04-13 20:39:15 +03:00
slprime bd17301cb9 Fix Collapsed Recipes in Bookmarks (#915) 2026-04-13 15:41:30 +03:00
lc-1337 96ccd4e109 fix client -> server sync in creative gui (#913) 2026-04-12 14:47:27 +03:00
Kogepan229 b30ca57e68 Don't block slot click if canCheatItem is false (#912) 2026-04-08 18:35:08 +03:00
slprime 8f949bc1d1 Refactor recipe profiler (#911) 2026-04-07 13:10:39 +03:00
slprime d25365942a Fix Repair Handler with broken ItemStack (#910) 2026-04-06 21:35:47 +03:00
slprime eb58e1dabc Improve Recipe Badge (#909) 2026-04-06 20:39:41 +03:00
slprime f4601e7eed Disable badge by default (#907) 2026-04-04 21:12:05 +03:00
slprime ba48806667 Chance tooltip (#906) 2026-04-04 00:03:15 +03:00
Martin Robertz 70c332796a update+deps 2026-04-03 16:34:57 +02:00
slprime bcc25d4369 Fix Collapsed Recipes in Bookmarks (#905) 2026-03-31 20:47:23 +03:00
slprime 10a3109714 Add recipe chance to bookmarks (#903) 2026-03-30 20:36:55 +03:00
koolkrafter5 b60769864f Improve image exporter data dumper (#902) 2026-03-30 08:19:34 +03:00
slprime 6bc899769f Add Reset to Debug Handler (#901) 2026-03-26 22:22:13 +02:00
slprime 0ba14091fb Refactor DebugHandlerWidget (#900) 2026-03-22 14:10:10 +02:00
slprimeandUltraProdigy 6ed0be7961 Add Repair Handler (#899)
Co-authored-by: UltraProdigy <187078471+UltraProdigy@users.noreply.github.com>
2026-03-21 15:04:09 +02:00
slprime d40b951cce Fix areStacksSameTypeWithNBT damage check (#896) 2026-03-19 14:43:45 +02:00
slprime ecdf7892ce updateBuildScript (#895) 2026-03-19 09:39:59 +02:00
slprime 1eaaac94bc Fix filtered permutations (#893) 2026-03-18 01:25:27 +02:00
136 changed files with 5237 additions and 2416 deletions

No files matched your search

+18 -2
View File
@@ -1,8 +1,12 @@
// Add your dependencies here
configurations.create('gtnhlibEmbed') {
canBeConsumed = false
canBeResolved = true
}
dependencies {
api('com.github.GTNewHorizons:CodeChickenCore:1.4.10:dev')
devOnlyNonPublishable('com.github.GTNewHorizons:GTNHLib:0.9.13:dev')
api('com.github.GTNewHorizons:CodeChickenCore:1.4.16:dev')
devOnlyNonPublishable('com.github.GTNewHorizons:GTNHLib:0.11.23:dev')
shadowImplementation('org.apache.commons:commons-csv:1.10.0')
@@ -17,4 +21,16 @@ dependencies {
testRuntimeOnly('org.junit.platform:junit-platform-launcher')
testRuntimeOnly("org.lwjgl.lwjgl:lwjgl:2.9.3");
compileOnly("com.github.GTNewHorizons:GTNHLib:0.11.23") { transitive = false }
gtnhlibEmbed("com.github.GTNewHorizons:GTNHLib:0.11.23") { transitive = false }
}
[tasks.jar, tasks.shadowJar].each {
it.configure {
from({ project.configurations.getByName('gtnhlibEmbed').collect { zipTree(it) } }) {
include 'com/gtnewhorizon/gtnhlib/color/ColorResource.class'
include 'com/gtnewhorizon/gtnhlib/color/ColorResource$*.class'
}
}
}
+10 -10
View File
@@ -1,12 +1,12 @@
#This file is generated by updateDaemonJvm
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/df211d3c3eefdc408b462041881bc575/redirect
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/b41931cf1e70bc8e08d7dd19c343ef00/redirect
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/4945f00643ec68e7c7a6b66f90124f89/redirect
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/93aeea858331bd6bb00ba94759830234/redirect
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/3426ffcaa54c3f62406beb1f1ab8b179/redirect
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/f636c800fdb3f9ae33f019dfa048ba72/redirect
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/df211d3c3eefdc408b462041881bc575/redirect
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/93aeea858331bd6bb00ba94759830234/redirect
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/3cd7045fca9a72cd9bc7d14a385e594c/redirect
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/552c7bffe0370c66410a51c55985b511/redirect
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/cf726b4a1c84b50457225f9bba6d7650/redirect
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/fa1e318c287360478e3c83a9a3ef1007/redirect
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/cf726b4a1c84b50457225f9bba6d7650/redirect
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/fa1e318c287360478e3c83a9a3ef1007/redirect
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c2dd35c9d0aaf0ba6ad0791320f99dfc/redirect
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/e5810bd7fd1f8a586644409d395a7e55/redirect
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/cf726b4a1c84b50457225f9bba6d7650/redirect
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/fa1e318c287360478e3c83a9a3ef1007/redirect
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/7b3c4877c0749019e6805bb61e421497/redirect
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/d76df094a9cbbabd3b08251f9e61444a/redirect
toolchainVersion=25
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+1 -1
View File
@@ -57,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/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/.
+1 -1
View File
@@ -17,7 +17,7 @@ pluginManagement {
}
plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.21'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.26'
}
@@ -19,6 +19,7 @@ import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumChatFormatting;
import org.apache.commons.io.IOUtils;
@@ -184,27 +185,33 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
if (itemStack != null && this.grid.indexOf(groupId, itemStack, recipeId, false) == -1) {
final boolean existsRecipe = recipeId != null
&& this.grid.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID);
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(itemStack);
long count = nbTag.getInteger("Count");
long factor = existsRecipe ? Math.max(count, 1) : 1;
final Recipe recipe = Recipe.of(recipeId);
final BookmarkItem.Builder builder;
if (recipe != null) {
builder = BookmarkItem.builder(groupId, itemStack, recipe, BookmarkItemType.RESULT).multiplier(1);
} else if (recipeId != null) {
builder = BookmarkItem.builder(groupId, itemStack).recipeId(recipeId)
.factor(StackInfo.getAmount(itemStack)).multiplier(1);
} else {
builder = BookmarkItem.builder(groupId, itemStack).factor(1).multiplier(StackInfo.getAmount(itemStack));
}
if (existsRecipe) {
builder.type(BookmarkItemType.RESULT);
for (int i = 0; i < this.grid.size(); i++) {
if (this.grid.getBookmarkItem(i).equalsRecipe(recipeId, groupId)) {
count *= this.grid.getBookmarkItem(i).getMultiplier();
builder.multiplier(this.grid.getBookmarkItem(i).getMultiplier());
break;
}
}
} else {
builder.type(BookmarkItemType.ITEM);
}
this.grid.addItem(
BookmarkItem.of(
groupId,
StackInfo.withAmount(itemStack, count),
factor,
recipeId,
existsRecipe ? BookmarkItemType.RESULT : BookmarkItemType.ITEM),
true);
this.grid.addItem(builder.build(), true);
return true;
}
@@ -212,9 +219,11 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
public boolean addRecipe(Recipe recipe, int multiplier, int groupId) {
if (recipe == null) return false;
final RecipeId recipeId = recipe.getRecipeId();
if (recipe != null && this.grid.getGroup(groupId) != null && !this.grid.existsRecipe(recipeId, groupId)) {
if (this.grid.getGroup(groupId) != null && !this.grid.existsRecipe(recipeId, groupId)) {
this.grid.addRecipe(recipe, multiplier, groupId);
return true;
}
@@ -245,15 +254,22 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
ItemStack stack = recipeId.getResult();
if (stack != null && uniqueRecipe.add(recipeId)) {
this.grid.addItem(
BookmarkItem
.of(groupId, stack, StackInfo.getAmount(stack), recipeId, BookmarkItemType.ITEM),
true);
final Recipe recipe = Recipe.of(recipeId);
final BookmarkItem.Builder builder;
if (recipe != null) {
builder = BookmarkItem.builder(groupId, stack, recipe, BookmarkItemType.RESULT);
} else {
builder = BookmarkItem.builder(groupId, stack).recipeId(recipeId)
.factor(StackInfo.getAmount(stack));
}
this.grid.addItem(builder.multiplier(1).type(BookmarkItemType.ITEM).build(), true);
uniqueStack.add(stack);
}
} else {
ItemStack stack = extractItem(item);
final ItemStack stack = extractItem(item);
if (stack != null && !uniqueStack.contains(stack)) {
this.grid.addItem(BookmarkItem.of(groupId, stack), true);
@@ -783,15 +799,15 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_RMB),
NEIClientUtils.translate("bookmark.group.toggle_crafting_chain"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.remove_recipe"),
KeyManager.getKeyName("bookmark.remove_recipe", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.remove_recipe"));
if (BookmarkContainerInfo.getBookmarkContainerHandler(NEIClientUtils.getGuiContainer()) != null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items"),
KeyManager.getKeyName("bookmark.pull_items"),
NEIClientUtils.translate("bookmark.group.pull_items"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("bookmark.pull_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.pull_items_shift"));
}
@@ -925,6 +941,17 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
if (slot != null) {
if (slot.getBookmarkItem().chance != PositionedStack.CHANCE_FULL) {
final String chanceText = NEIClientUtils
.formatChance(slot.getBookmarkItem().chance / (float) PositionedStack.CHANCE_FULL);
currenttip.add(
1,
EnumChatFormatting.GRAY + NEIClientUtils.translate(
slot.getType() == BookmarkItemType.INGREDIENT ? "recipe.badge.chance.consume"
: "recipe.badge.chance.output",
chanceText));
}
if (slot.getType() == BookmarkItemType.INGREDIENT && slot.getRecipeId() != null
&& slot.getBookmarkItem().permutations.size() > 1) {
RecipeId recipeId = slot.getRecipeId();
@@ -1119,7 +1146,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
for (BookmarkItem item : math.initialItems) {
final long invStackSize = inventory.getOrDefault(item.itemStack, 0L);
final long amount = item.amount - invStackSize * item.fluidCellAmount;
final long amount = item.getAmount() - invStackSize * item.fluidCellAmount;
if (amount > 0) {
pullItemStacks.add(item.getItemStack(amount));
}
@@ -1133,7 +1160,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
for (BookmarkItem item : math.initialItems) {
final long invStackSize = inventory.getOrDefault(item.itemStack, 0L);
final long strStackSize = containerStorage.getOrDefault(item.itemStack, 0L);
final long amount = item.amount - invStackSize * item.fluidCellAmount
final long amount = item.getAmount() - invStackSize * item.fluidCellAmount
- strStackSize * item.fluidCellAmount;
if (amount > 0) {
@@ -1267,7 +1294,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
public BookmarkRecipeId getBookmarkRecipeId(int itemIndex) {
BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
return item == null || item.type == BookmarkItemType.INGREDIENT || item.recipeId == null ? null
: new BookmarkRecipeId(item.recipeId.getHandleName(), item.recipeId.getIngredients());
: new BookmarkRecipeId(item.recipeId.getHandlerName(), item.recipeId.getIngredients());
}
@Deprecated
@@ -57,6 +57,10 @@ public abstract class Button extends Widget {
return label;
}
public int getRenderLabelColor() {
return 0;
}
public final String label;
public Image icon;
@@ -45,6 +45,7 @@ import codechicken.core.ClassDiscoverer;
import codechicken.core.ClientUtils;
import codechicken.lib.packet.PacketCustom;
import codechicken.nei.api.API;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.IConfigureNEI;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.guihook.GuiContainerManager;
@@ -374,6 +375,7 @@ public class ClientHandler {
} else if (event.gui == null) {
/* prevent WorldClient reference being held in the Gui */
NEIController.manager = null;
GuiInfo.clearGuiHandlers();
}
}
@@ -0,0 +1,22 @@
package codechicken.nei;
import com.gtnewhorizon.gtnhlib.color.ColorResource;
public class ColorUtils {
private static final ColorResource.Factory color = new ColorResource.Factory("nei");
public static final ColorResource
// spotless:off
textGray = color.rgb("textGray", "0x404040"),
textLightGray = color.rgb("textLightGray", "0x606060"),
recipeTitle = color.rgb("recipeTitle", "0xFFFFFF"),
recipeTitleHover = color.rgb("recipeTitleHover", "0xFFFF55"),
subsetWidget = color.rgb("subsetWidget", "0xAA00AA"),
recipeBadge = color.rgb("recipeBadge", "0xFDD835"),
buttonLabelNormal = color.rgb("buttonLabelNormal", "0xE0E0E0"),
buttonLabelHover = color.rgb("buttonLabelHover", "0xFFFFA0"),
buttonLabelDisabled = color.rgb("buttonLabelDisabled", "0x601010"),
buttonLabelInactive = color.rgb("buttonLabelInactive", "0xA0A0A0");
// spotless:on
}
@@ -8,7 +8,6 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -129,8 +128,8 @@ public class FavoriteRecipes {
}
protected List<PositionedStack> getOutputs(IRecipeHandler handler, int recipeIndex) {
final PositionedStack pStackResult = handler.getResultStack(recipeIndex);
return pStackResult != null ? Collections.singletonList(pStackResult) : handler.getOtherStacks(recipeIndex);
final List<PositionedStack> pStackResults = handler.getResultStacks(recipeIndex);
return !pStackResults.isEmpty() ? pStackResults : handler.getOtherStacks(recipeIndex);
}
};
@@ -225,7 +224,7 @@ public class FavoriteRecipes {
continue;
}
if (FAVORITE_ITEM.equals(recipeId.getHandleName()) || RecipeHandlerRef.of(recipeId) != null) {
if (FAVORITE_ITEM.equals(recipeId.getHandlerName()) || RecipeHandlerRef.of(recipeId) != null) {
manualFavorites.add(stack, recipeId);
} else {
hasErrors = true;
@@ -296,15 +296,26 @@ public class FormattedTextField extends GuiTextField {
int shift = 0;
for (int i = 0; i < position; i++) {
while (this.formattedText.length() > i + shift && this.formattedText.charAt(i + shift) == '\u00a7') {
while (this.formattedText.length() > i + shift + 1 && this.formattedText.charAt(i + shift) == '\u00a7'
&& isFormattingCode(this.formattedText.charAt(i + shift + 1))) {
shift += 2;
}
}
return position + shift;
return Math.min(position + shift, this.formattedText.length());
}
private static boolean isFormattingCode(char c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')
|| (c >= 'k' && c <= 'o')
|| c == 'r'
|| (c >= 'A' && c <= 'F')
|| (c >= 'K' && c <= 'O')
|| c == 'R';
}
private String getPreviousColor(int position) {
position = Math.min(position, this.formattedText.length() - 1);
while (position >= 0) {
if (this.formattedText.charAt(position) == '\u00a7') {
return this.formattedText.substring(position, position + 2);
@@ -24,8 +24,8 @@ public class GuiEnchantmentModifier extends GuiContainer {
@Override
protected void drawGuiContainerForegroundLayer(int par1, int par2) {
fontRendererObj.drawString(translate("enchant"), 12, 6, 0x404040);
fontRendererObj.drawString(translate("enchant.level"), 19, 20, 0x404040);
fontRendererObj.drawString(translate("enchant"), 12, 6, ColorUtils.textGray.getColor());
fontRendererObj.drawString(translate("enchant.level"), 19, 20, ColorUtils.textGray.getColor());
}
protected void drawGuiContainerBackgroundLayer(float f, int i, int j) {
@@ -39,7 +39,11 @@ public class GuiEnchantmentModifier extends GuiContainer {
container.drawScrollBar(this);
String levelstring = "" + container.level;
fontRendererObj.drawString(levelstring, 33 - fontRendererObj.getStringWidth(levelstring) / 2, 34, 0xFF606060);
fontRendererObj.drawString(
levelstring,
33 - fontRendererObj.getStringWidth(levelstring) / 2,
34,
ColorUtils.textLightGray.getColor());
GL11.glTranslatef(-guiLeft, -guiTop, 0);
}
@@ -45,15 +45,14 @@ public class GuiNEIButton extends GuiButton {
}
protected int getTextColour(boolean mouseOver) {
int color = 0xe0e0e0;
if (!enabled) {
color = 0xffa0a0a0;
return ColorUtils.buttonLabelInactive.getColor();
} else if (mouseOver) {
color = 0xffffa0;
return ColorUtils.buttonLabelHover.getColor();
}
return color;
return ColorUtils.buttonLabelNormal.getColor();
}
protected void drawContent(Minecraft minecraft, int y, int x, boolean mouseOver) {
@@ -289,10 +289,10 @@ public class GuiPotionCreator extends GuiContainerWidget {
CCRenderState.changeTexture("nei:textures/gui/potion.png");
drawTexturedModalRect(0, 0, 0, 0, xSize, ySize);
FontUtils.drawCenteredString(translate("potion.favourite"), xSize / 2, 4, 0x404040);
fontRendererObj.drawString(translate("potion.duration"), 12, 40, 0x404040);
fontRendererObj.drawString(translate("potion.level"), 19, 73, 0x404040);
FontUtils.drawCenteredString(translateAmplifier(amplifier), 33, 86, 0xFF606060);
FontUtils.drawCenteredString(translate("potion.favourite"), xSize / 2, 4, ColorUtils.textGray.getColor());
fontRendererObj.drawString(translate("potion.duration"), 12, 40, ColorUtils.textGray.getColor());
fontRendererObj.drawString(translate("potion.level"), 19, 73, ColorUtils.textGray.getColor());
FontUtils.drawCenteredString(translateAmplifier(amplifier), 33, 86, ColorUtils.textGray.getColor());
}
@Override
@@ -28,7 +28,7 @@ public class HUDRenderer implements IKeyStateTracker {
@Override
public void tickKeyStates() {
if (KeyManager.keyStates.get("world.highlight_tips").down) {
if (KeyManager.isPressed("world.highlight_tips")) {
ConfigTag tag = NEIClientConfig.getSetting("world.highlight_tips");
tag.setBooleanValue(!tag.getBooleanValue());
}
@@ -0,0 +1,161 @@
package codechicken.nei;
import net.minecraft.client.gui.GuiRepair;
import net.minecraft.client.gui.inventory.GuiBrewingStand;
import net.minecraft.client.gui.inventory.GuiCrafting;
import net.minecraft.client.gui.inventory.GuiFurnace;
import net.minecraft.client.gui.inventory.GuiInventory;
import net.minecraft.nbt.NBTTagCompound;
import codechicken.nei.api.API;
import codechicken.nei.recipe.BrewingOverlayHandler;
import codechicken.nei.recipe.BrewingRecipeHandler;
import codechicken.nei.recipe.DefaultOverlayHandler;
import codechicken.nei.recipe.FireworkRecipeHandler;
import codechicken.nei.recipe.FuelRecipeHandler;
import codechicken.nei.recipe.FurnaceRecipeHandler;
import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.ProfilerRecipeHandler;
import codechicken.nei.recipe.RepairOverlayHandler;
import codechicken.nei.recipe.RepairRecipeHandler;
import codechicken.nei.recipe.ShapedRecipeHandler;
import codechicken.nei.recipe.ShapelessRecipeHandler;
import cpw.mods.fml.common.event.FMLInterModComms;
public class IMCForNEI {
public static void IMCSender() {
API.registerRecipeHandler(new ShapedRecipeHandler());
API.registerUsageHandler(new ShapedRecipeHandler());
sendHandler("codechicken.nei.recipe.ShapedRecipeHandler", "minecraft:crafting_table");
API.registerRecipeHandler(new ShapelessRecipeHandler());
API.registerUsageHandler(new ShapelessRecipeHandler());
sendHandler("codechicken.nei.recipe.ShapelessRecipeHandler", "minecraft:crafting_table");
API.registerRecipeHandler(new FireworkRecipeHandler());
API.registerUsageHandler(new FireworkRecipeHandler());
sendHandler("codechicken.nei.recipe.FireworkRecipeHandler", "minecraft:fireworks");
API.registerRecipeHandler(new FurnaceRecipeHandler());
API.registerUsageHandler(new FurnaceRecipeHandler());
sendHandler("codechicken.nei.recipe.FurnaceRecipeHandler", "minecraft:furnace");
API.registerRecipeHandler(new BrewingRecipeHandler());
API.registerUsageHandler(new BrewingRecipeHandler());
sendHandler("codechicken.nei.recipe.BrewingRecipeHandler", "minecraft:brewing_stand");
API.registerRecipeHandler(new FuelRecipeHandler());
API.registerUsageHandler(new FuelRecipeHandler());
sendFuelRecipeHandler();
API.registerRecipeHandler(new InformationHandler());
API.registerUsageHandler(new InformationHandler());
sendInformationHandler();
API.registerRecipeHandler(new RepairRecipeHandler());
API.registerUsageHandler(new RepairRecipeHandler());
sendRepairHandler();
sendCatalyst("repair", "minecraft:anvil");
API.registerGuiOverlay(GuiCrafting.class, "crafting");
API.registerGuiOverlay(GuiInventory.class, "crafting2x2", 63, 20);
API.registerGuiOverlay(GuiFurnace.class, "smelting");
API.registerGuiOverlay(GuiFurnace.class, "fuel");
API.registerGuiOverlay(GuiBrewingStand.class, "brewing");
API.registerGuiOverlay(GuiRepair.class, "repair", 2, 37);
API.registerGuiOverlayHandler(GuiCrafting.class, new DefaultOverlayHandler(), "crafting");
API.registerGuiOverlayHandler(GuiInventory.class, new DefaultOverlayHandler(63, 20), "crafting2x2");
API.registerGuiOverlayHandler(GuiBrewingStand.class, new BrewingOverlayHandler(), "brewing");
API.registerGuiOverlayHandler(GuiRepair.class, new RepairOverlayHandler(), "repair");
API.registerRecipeHandler(new ProfilerRecipeHandler(true));
API.registerUsageHandler(new ProfilerRecipeHandler(false));
sendProfilerRecipeHandler();
}
private static void sendHandler(String aName, String aBlock) {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handler", aName);
aNBT.setString("modName", "Minecraft");
aNBT.setString("modId", "minecraft");
aNBT.setString("itemName", aBlock);
aNBT.setInteger("handlerWidth", 166);
aNBT.setInteger("handlerHeight", 65);
aNBT.setBoolean("multipleWidgetsAllowed", true);
aNBT.setInteger("yShift", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
}
private static void sendRepairHandler() {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handler", "codechicken.nei.recipe.RepairRecipeHandler");
aNBT.setString("modName", "Minecraft");
aNBT.setString("modId", "minecraft");
aNBT.setString("itemName", "minecraft:anvil");
aNBT.setInteger("handlerHeight", 39);
aNBT.setInteger("handlerWidth", 166);
aNBT.setBoolean("multipleWidgetsAllowed", true);
aNBT.setBoolean("showFavoritesButton", false);
aNBT.setInteger("yShift", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
}
private static void sendFuelRecipeHandler() {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handler", "codechicken.nei.recipe.FuelRecipeHandler");
aNBT.setString("modName", "Minecraft");
aNBT.setString("modId", "minecraft");
aNBT.setString("imageResource", "nei:textures/nei_tabbed_sprites.png");
aNBT.setInteger("imageX", 80);
aNBT.setInteger("imageY", 0);
aNBT.setInteger("imageWidth", 14);
aNBT.setInteger("imageHeight", 14);
aNBT.setInteger("handlerHeight", 65);
aNBT.setInteger("handlerWidth", 166);
aNBT.setBoolean("multipleWidgetsAllowed", true);
aNBT.setInteger("yShift", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
}
private static void sendInformationHandler() {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handler", "codechicken.nei.recipe.InformationHandler");
aNBT.setString("modName", "Not Enough Items");
aNBT.setString("modId", "nei");
aNBT.setString("imageResource", "nei:textures/nei_tabbed_sprites.png");
aNBT.setInteger("imageX", 96);
aNBT.setInteger("imageY", 0);
aNBT.setInteger("imageWidth", 16);
aNBT.setInteger("imageHeight", 16);
aNBT.setInteger("handlerHeight", 65);
aNBT.setInteger("handlerWidth", 166);
aNBT.setBoolean("multipleWidgetsAllowed", true);
aNBT.setInteger("yShift", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
}
private static void sendProfilerRecipeHandler() {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handler", "codechicken.nei.recipe.ProfilerRecipeHandler");
aNBT.setString("modName", "Not Enough Items");
aNBT.setString("modId", "nei");
aNBT.setString("itemName", "minecraft:clock");
aNBT.setInteger("handlerHeight", 16);
aNBT.setInteger("handlerWidth", 166);
aNBT.setBoolean("multipleWidgetsAllowed", true);
aNBT.setInteger("yShift", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
}
private static void sendCatalyst(String aName, String aStack) {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handlerID", aName);
aNBT.setString("itemName", aStack);
aNBT.setInteger("priority", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerCatalystInfo", aNBT);
}
}
+13 -271
View File
@@ -2,39 +2,23 @@ package codechicken.nei;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import net.minecraft.client.Minecraft;
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.IFluidContainerItem;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import codechicken.nei.ThreadOperationTimer.TimeoutException;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.RecipeHandlerRef;
import codechicken.nei.search.TooltipFilter;
import codechicken.nei.util.ItemUntranslator;
import cpw.mods.fml.common.FMLLog;
public class ItemList {
@@ -52,9 +36,6 @@ public class ItemList {
public static final List<ItemFilterProvider> itemFilterers = new LinkedList<>();
public static final List<ItemsLoadedCallback> loadCallbacks = new LinkedList<>();
private static final HashSet<Item> erroredItems = new HashSet<>();
private static final HashSet<String> stackTraces = new HashSet<>();
private static Map<ItemStack, Integer> ordering = new HashMap<>();
/**
* Unlike {@link LayoutManager#itemsLoaded}, this indicates whether item loading is actually finished or not.
*/
@@ -116,7 +97,15 @@ public class ItemList {
displayName = EnumChatFormatting
.getTextWithoutFormattingCodes(item.getItem().getItemStackDisplayName(item));
return displayName != null && !displayName.isEmpty() && this.pattern.matcher(displayName).find();
if (displayName != null && !displayName.isEmpty() && this.pattern.matcher(displayName).find()) {
return true;
}
}
for (String alias : ItemInfo.getAliases(item)) {
if (this.pattern.matcher(alias).find()) {
return true;
}
}
return false;
@@ -217,230 +206,6 @@ public class ItemList {
return filters;
}
public static final RestartableTask loadItems = new RestartableTask("NEI Item Loading") {
private void damageSearch(Item item, List<ItemStack> permutations) {
HashSet<String> damageIconSet = new HashSet<>();
for (int damage = 0; damage < 16; damage++) try {
ItemStack itemstack = new ItemStack(item, 1, damage);
IIcon icon = item.getIconIndex(itemstack);
String name = getTooltip(itemstack);
String s = name + "@" + (icon == null ? 0 : icon.hashCode());
if (damageIconSet.add(s)) {
permutations.add(itemstack);
}
} catch (TimeoutException t) {
throw t;
} catch (Throwable t) {
NEIServerUtils.logOnce(
t,
stackTraces,
"Ommiting " + item + ":" + damage + " " + item.getClass().getSimpleName(),
item.toString());
}
}
private String getTooltip(ItemStack stack) {
try {
return String.join("\n", stack.getTooltip(Minecraft.getMinecraft().thePlayer, false));
} catch (Throwable ignored) {}
return "";
}
private void updateOrdering(List<ItemStack> items) {
final Map<ItemStack, Integer> newOrdering = new HashMap<>();
ItemSorter.sort(items);
if (!CollapsibleItems.isEmpty()) {
final HashMap<Integer, Integer> groups = new HashMap<>();
int orderIndex = 0;
for (ItemStack stack : items) {
final int groupIndex = CollapsibleItems.getGroupIndex(stack);
if (groupIndex == -1) {
newOrdering.put(stack, orderIndex++);
} else {
if (!groups.containsKey(groupIndex)) {
groups.put(groupIndex, orderIndex++);
}
newOrdering.put(stack, groups.get(groupIndex));
}
}
} else {
int orderIndex = 0;
for (ItemStack stack : items) {
newOrdering.put(stack, orderIndex++);
}
}
ItemList.ordering = newOrdering;
}
private List<ItemStack> getPermutations(Item item) {
final List<ItemStack> permutations = new LinkedList<>(ItemInfo.itemOverrides.get(item));
if (permutations.isEmpty()) {
item.getSubItems(item, null, permutations);
}
if (permutations.isEmpty()) {
damageSearch(item, permutations);
}
permutations.addAll(ItemInfo.itemVariants.get(item));
return permutations.stream()
.filter(
stack -> stack.getItem() != null && stack.getItem().delegate.name() != null
&& !ItemInfo.isHidden(stack))
.collect(Collectors.toList());
}
private void runChecked(ItemStack stack, Runnable action, String reason) {
int hashOld = 0;
if (stack.hasTagCompound()) {
hashOld = stack.stackTagCompound.hashCode();
}
action.run();
if (stack.hasTagCompound() && hashOld != stack.stackTagCompound.hashCode()) {
FMLLog.warning(
"NEI: Forced tag update with reason (" + reason
+ ") for "
+ stack
+ "("
+ stack.getItem()
+ ")");
}
}
private void forceTagCompoundInitialization(ItemStack stack) {
Item item = stack.getItem();
if (item == null) {
return;
}
if (item instanceof IFluidContainerItem) {
IFluidContainerItem fluidItem = (IFluidContainerItem) item;
runChecked(stack, () -> fluidItem.getFluid(stack), "getFluid");
}
runChecked(stack, () -> item.isDamaged(stack), "isDamaged");
runChecked(stack, () -> item.getDamage(stack), "getDamage");
runChecked(stack, () -> item.showDurabilityBar(stack), "showDurabilityBar");
runChecked(stack, () -> item.getAttributeModifiers(stack), "getAttributeModifiers");
runChecked(stack, () -> item.getDurabilityForDisplay(stack), "getDurabilityForDisplay");
runChecked(stack, () -> item.getItemStackLimit(stack), "getItemStackLimit");
runChecked(stack, () -> item.getToolClasses(stack), "getToolClasses");
runChecked(stack, () -> item.getUnlocalizedNameInefficiently(stack), "getUnlocalizedNameInefficiently");
runChecked(stack, () -> item.hasEffect(stack), "hasEffect");
runChecked(stack, () -> item.getDigSpeed(stack, Blocks.stone, 0), "getDigSpeed");
/*
* unused... for now runChecked(stack, () -> GameRegistry.getFuelValue(stack), "getFuelValue");
* runChecked(stack, () -> item.getUnlocalizedName(stack), "getUnlocalizedName"); runChecked(stack, () ->
* item.doesContainerItemLeaveCraftingGrid(stack), "doesContainerItemLeaveCraftingGrid"); runChecked(stack,
* () -> item.getItemUseAction(stack), "getItemUseAction"); runChecked(stack, () ->
* item.getMaxItemUseDuration(stack), "getMaxItemUseDuration"); runChecked(stack, () ->
* item.getPotionEffect(stack), "getPotionEffect"); runChecked(stack, () -> item.isPotionIngredient(stack),
* "isPotionIngredient"); runChecked(stack, () -> item.getRarity(stack), "getRarity"); runChecked(stack, ()
* -> item.hasCustomEntity(stack), "hasCustomEntity"); runChecked(stack, () ->
* item.getSmeltingExperience(stack), "getSmeltingExperience"); runChecked(stack, () ->
* item.getMaxDamage(stack), "getMaxDamage"); runChecked(stack, () -> item.getDamage(stack), "getDamage");
* runChecked(stack, stack::isItemDamaged, "isItemDamaged"); runChecked(stack, () -> item.hasEffect(stack,
* 0), "hasEffect"); runChecked(stack, () -> item.getItemEnchantability(stack), "getItemEnchantability");
* runChecked(stack, () -> item.isBeaconPayment(stack), "isBeaconPayment"); runChecked(stack, () ->
* item.getDamage(stack), "getDamage"); runChecked(stack, () -> item.getDamage(stack), "getDamage");
* runChecked(stack, () -> item.getDamage(stack), "getDamage");
*/
}
// Generate itemlist, permutations, orders, collapsibleitems, and informationhandler stacks
@Override
@SuppressWarnings("unchecked")
public void execute() {
if (!NEIClientConfig.isEnabled() || NEIClientUtils.mc().thePlayer == null) return;
ThreadOperationTimer timer = getTimer(NEIClientConfig.getItemLoadingTimeout());
LayoutManager.itemsLoaded = true;
loadFinished = false;
SearchField.searchParser.clearCache();
ItemSorter.instance.ordering.clear();
CollapsibleItems.clearCache();
TooltipFilter.clearCache();
InformationHandler.clearCache();
List<ItemStack> items = new ArrayList<>();
ListMultimap<Item, ItemStack> itemMap = ArrayListMultimap.create();
ItemStackSet unique = new ItemStackSet();
StreamSupport.stream(((Iterable<Item>) Item.itemRegistry).spliterator(), true).forEach(item -> {
if (item == null || item.delegate.name() == null || erroredItems.contains(item)) return;
try {
timer.reset(item);
List<ItemStack> permutations = getPermutations(item);
timer.reset();
for (ItemStack stack : permutations) {
if (!unique.contains(stack)) {
synchronized (unique) {
unique.add(stack);
}
synchronized (items) {
items.add(stack);
}
forceTagCompoundInitialization(stack);
CollapsibleItems.putItem(stack);
TooltipFilter.getSearchTooltip(stack);
InformationHandler.populateStacks(stack);
}
}
synchronized (itemMap) {
itemMap.putAll(item, permutations);
}
} catch (Throwable t) {
NEIServerConfig.logger.error("Removing item: {} from list.", item, t);
erroredItems.add(item);
}
});
int index = 0;
for (Item item : (Iterable<Item>) Item.itemRegistry) {
for (ItemStack stack : itemMap.get(item)) {
ItemSorter.instance.ordering.put(stack, index++);
}
}
if (interrupted()) return;
ItemList.items = items;
ItemList.itemMap = itemMap;
for (ItemsLoadedCallback callback : loadCallbacks) callback.itemsLoaded();
if (interrupted()) return;
updateOrdering(ItemList.items);
loadFinished = true;
RecipeHandlerRef.clearCache();
FavoriteRecipes.reload();
SubsetWidget.updateHiddenItems();
ItemPanels.bookmarkPanel.load();
updateFilter.restart();
}
};
public static ForkJoinPool forkJoinPool;
static {
@@ -460,35 +225,12 @@ public class ItemList {
forkJoinPool = new ForkJoinPool(poolSize, factory, null, false);
}
public static final RestartableTask updateFilter = new RestartableTask("NEI Item Filtering") {
// The item list pipeline lives in ItemListLoader; these references are kept for backward compatibility.
public static final RestartableTask loadItems = ItemListLoader.loadItems;
@Override
public void execute() {
public static final RestartableTask refreshItems = ItemListLoader.refreshItems;
if (!loadFinished) return;
ItemFilter filter = getItemListFilter();
ArrayList<ItemStack> filtered;
try {
filtered = ItemList.forkJoinPool.submit(
() -> items.parallelStream().filter(filter::matches)
.collect(Collectors.toCollection(ArrayList::new)))
.get();
} catch (InterruptedException | ExecutionException e) {
filtered = new ArrayList<>();
e.printStackTrace();
stop();
}
if (interrupted()) return;
filtered.sort(Comparator.comparingInt(ItemList.ordering::get));
if (interrupted()) return;
ItemPanel.updateItemList(filtered);
}
};
public static final RestartableTask updateFilter = ItemListLoader.updateFilter;
/**
* @deprecated Use updateFilter.restart()
@@ -0,0 +1,376 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IIcon;
import net.minecraftforge.fluids.IFluidContainerItem;
import com.google.common.base.Throwables;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import codechicken.nei.ItemList.ItemsLoadedCallback;
import codechicken.nei.ThreadOperationTimer.TimeoutException;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.RecipeHandlerRef;
import codechicken.nei.recipe.RepairRecipeHandler;
import codechicken.nei.search.TooltipFilter;
import cpw.mods.fml.common.FMLLog;
public class ItemListLoader {
private static final HashSet<Item> erroredItems = new HashSet<>();
private static final HashSet<String> stackTraces = new HashSet<>();
private static Map<ItemStack, Integer> ordering = new HashMap<>();
private ItemListLoader() {}
private static void damageSearch(Item item, List<ItemStack> permutations) {
final Set<String> damageIconSet = new HashSet<>();
final EntityPlayer player = Minecraft.getMinecraft().thePlayer;
for (int damage = 0; damage < 16; damage++) {
try {
final ItemStack itemstack = new ItemStack(item, 1, damage);
final IIcon icon = item.getIconIndex(itemstack);
final String key = itemstack.getDisplayName() + "@"
+ (icon == null ? 0 : icon.hashCode())
+ "@"
+ getInformation(itemstack, player);
if (damageIconSet.add(key)) {
permutations.add(itemstack);
}
} catch (TimeoutException t) {
throw t;
} catch (Throwable t) {
NEIServerUtils.logOnce(
t,
stackTraces,
"Ommiting " + item + ":" + damage + " " + item.getClass().getSimpleName(),
item.toString());
}
}
}
private static String getInformation(ItemStack stack, EntityPlayer player) {
try {
final List<String> tooltip = new ArrayList<>();
stack.getItem().addInformation(stack, player, tooltip, false);
return String.join("\n", tooltip);
} catch (Throwable ignored) {}
return "";
}
private static void updateOrdering(List<ItemStack> items) {
final Map<ItemStack, Integer> newOrdering = new HashMap<>();
if (!CollapsibleItems.isEmpty()) {
final HashMap<Integer, Integer> groups = new HashMap<>();
int orderIndex = 0;
for (ItemStack stack : items) {
final int groupIndex = CollapsibleItems.getGroupIndex(stack);
if (groupIndex == -1) {
newOrdering.put(stack, orderIndex++);
} else {
if (!groups.containsKey(groupIndex)) {
groups.put(groupIndex, orderIndex++);
}
newOrdering.put(stack, groups.get(groupIndex));
}
}
} else {
int orderIndex = 0;
for (ItemStack stack : items) {
newOrdering.put(stack, orderIndex++);
}
}
ordering = newOrdering;
}
private static List<ItemStack> getPermutations(Item item) {
final List<ItemStack> permutations = new LinkedList<>(ItemInfo.itemOverrides.get(item));
if (permutations.isEmpty()) {
item.getSubItems(item, null, permutations);
}
if (permutations.isEmpty()) {
damageSearch(item, permutations);
}
permutations.addAll(ItemInfo.itemVariants.get(item));
return permutations.stream()
.filter(
stack -> stack.getItem() != null && stack.getItem().delegate.name() != null
&& !ItemInfo.isHidden(stack))
.collect(Collectors.toList());
}
private static void runChecked(ItemStack stack, Runnable action, String reason) {
int hashOld = 0;
if (stack.hasTagCompound()) {
hashOld = stack.stackTagCompound.hashCode();
}
action.run();
if (stack.hasTagCompound() && hashOld != stack.stackTagCompound.hashCode()) {
FMLLog.warning(
"NEI: Forced tag update with reason (" + reason + ") for " + stack + "(" + stack.getItem() + ")");
}
}
private static void forceTagCompoundInitialization(ItemStack stack) {
Item item = stack.getItem();
if (item == null) {
return;
}
if (item instanceof IFluidContainerItem) {
IFluidContainerItem fluidItem = (IFluidContainerItem) item;
runChecked(stack, () -> fluidItem.getFluid(stack), "getFluid");
}
runChecked(stack, () -> item.isDamaged(stack), "isDamaged");
runChecked(stack, () -> item.getDamage(stack), "getDamage");
runChecked(stack, () -> item.showDurabilityBar(stack), "showDurabilityBar");
runChecked(stack, () -> item.getAttributeModifiers(stack), "getAttributeModifiers");
runChecked(stack, () -> item.getDurabilityForDisplay(stack), "getDurabilityForDisplay");
runChecked(stack, () -> item.getItemStackLimit(stack), "getItemStackLimit");
runChecked(stack, () -> item.getToolClasses(stack), "getToolClasses");
runChecked(stack, () -> item.getUnlocalizedNameInefficiently(stack), "getUnlocalizedNameInefficiently");
runChecked(stack, () -> item.hasEffect(stack), "hasEffect");
runChecked(stack, () -> item.getDigSpeed(stack, Blocks.stone, 0), "getDigSpeed");
/*
* unused... for now runChecked(stack, () -> GameRegistry.getFuelValue(stack), "getFuelValue");
* runChecked(stack, () -> item.getUnlocalizedName(stack), "getUnlocalizedName"); runChecked(stack, () ->
* item.doesContainerItemLeaveCraftingGrid(stack), "doesContainerItemLeaveCraftingGrid"); runChecked(stack, ()
* -> item.getItemUseAction(stack), "getItemUseAction"); runChecked(stack, () ->
* item.getMaxItemUseDuration(stack), "getMaxItemUseDuration"); runChecked(stack, () ->
* item.getPotionEffect(stack), "getPotionEffect"); runChecked(stack, () -> item.isPotionIngredient(stack),
* "isPotionIngredient"); runChecked(stack, () -> item.getRarity(stack), "getRarity"); runChecked(stack, () ->
* item.hasCustomEntity(stack), "hasCustomEntity"); runChecked(stack, () -> item.getSmeltingExperience(stack),
* "getSmeltingExperience"); runChecked(stack, () -> item.getMaxDamage(stack), "getMaxDamage");
* runChecked(stack, () -> item.getDamage(stack), "getDamage"); runChecked(stack, stack::isItemDamaged,
* "isItemDamaged"); runChecked(stack, () -> item.hasEffect(stack, 0), "hasEffect"); runChecked(stack, () ->
* item.getItemEnchantability(stack), "getItemEnchantability"); runChecked(stack, () ->
* item.isBeaconPayment(stack), "isBeaconPayment"); runChecked(stack, () -> item.getDamage(stack), "getDamage");
* runChecked(stack, () -> item.getDamage(stack), "getDamage"); runChecked(stack, () -> item.getDamage(stack),
* "getDamage");
*/
}
@SuppressWarnings("unchecked")
private static List<ItemStack> gatherItems(ThreadOperationTimer timer) {
ItemSorter.instance.ordering.clear();
List<ItemStack> items = new ArrayList<>();
ListMultimap<Item, ItemStack> itemMap = ArrayListMultimap.create();
ItemStackSet unique = new ItemStackSet();
final List<Item> registryItems = new ArrayList<>();
for (Item item : (Iterable<Item>) Item.itemRegistry) registryItems.add(item);
registryItems.parallelStream().forEach(item -> {
if (item == null || item.delegate.name() == null || erroredItems.contains(item)) return;
try {
timer.reset(item);
List<ItemStack> permutations = getPermutations(item);
timer.reset();
synchronized (itemMap) {
itemMap.putAll(item, permutations);
}
} catch (Throwable t) {
NEIServerConfig.logger.error(
"Removing item: {} from list.\n{}: {}",
item,
t.getMessage(),
Throwables.getStackTraceAsString(t));
erroredItems.add(item);
}
});
int index = 0;
for (Item item : (Iterable<Item>) Item.itemRegistry) {
for (ItemStack stack : itemMap.get(item)) {
ItemSorter.instance.ordering.put(stack, index++);
if (!unique.contains(stack)) {
unique.add(stack);
items.add(stack);
}
}
}
ItemList.itemMap = itemMap;
return items;
}
private static void buildItemCaches(List<ItemStack> items) {
SearchField.searchParser.clearCache();
TooltipFilter.clearCache();
InformationHandler.clearCache();
items.parallelStream().forEach(stack -> {
try {
forceTagCompoundInitialization(stack);
InformationHandler.populateStacks(stack);
} catch (Throwable t) {
NEIServerConfig.logger.error(
"Failed to build caches for: {}\n{}: {}",
stack,
t.getMessage(),
Throwables.getStackTraceAsString(t));
}
});
}
private static void indexCollapsibleItems(List<ItemStack> items) {
CollapsibleItems.clearCache();
items.parallelStream().forEach(CollapsibleItems::putItem);
}
public static final RestartableTask loadItems = new RestartableTask("NEI Item Loading") {
@Override
public void execute() {
if (!NEIClientConfig.isEnabled() || NEIClientUtils.mc().thePlayer == null) return;
final ThreadOperationTimer timer = getTimer(NEIClientConfig.getItemLoadingTimeout());
LayoutManager.itemsLoaded = true;
ItemList.loadFinished = false;
warmTooltips.stop();
List<ItemStack> items = gatherItems(timer);
if (interrupted()) return;
buildItemCaches(items);
indexCollapsibleItems(items);
if (interrupted()) return;
ItemSorter.sort(items);
if (interrupted()) return;
ItemList.items = items;
for (ItemsLoadedCallback callback : ItemList.loadCallbacks) callback.itemsLoaded();
if (interrupted()) return;
updateOrdering(ItemList.items);
ItemList.loadFinished = true;
RepairRecipeHandler.findRepairRecipesOnceParallel();
RecipeHandlerRef.clearCache();
FavoriteRecipes.reload();
SubsetWidget.updateHiddenItems();
updateFilter.restart();
warmTooltips.restart();
loadBookmarks.restart();
}
};
public static final RestartableTask warmTooltips = new RestartableTask("NEI Tooltip Caching") {
@Override
public void execute() {
if (!ItemList.loadFinished) return;
// Use the common pool, not ItemList.forkJoinPool, so it does not queue behind updateFilter.
ItemList.items.parallelStream().forEach(stack -> {
if (interrupted()) return;
try {
TooltipFilter.getSearchTooltip(stack);
} catch (Throwable ignored) {}
});
}
};
public static final RestartableTask loadBookmarks = new RestartableTask("NEI Bookmark Loading") {
@Override
public void execute() {
ItemPanels.bookmarkPanel.load();
}
};
public static final RestartableTask refreshItems = new RestartableTask("NEI Item Reordering") {
@Override
public void execute() {
if (!ItemList.loadFinished) return;
final List<ItemStack> items = new ArrayList<>(ItemList.items);
indexCollapsibleItems(items);
if (interrupted()) return;
ItemSorter.sort(items);
if (interrupted()) return;
ItemList.items = items;
updateOrdering(ItemList.items);
FavoriteRecipes.reload();
SubsetWidget.updateHiddenItems();
updateFilter.restart();
loadBookmarks.restart();
}
};
public static final RestartableTask updateFilter = new RestartableTask("NEI Item Filtering") {
@Override
public void execute() {
if (!ItemList.loadFinished) return;
ItemFilter filter = ItemList.getItemListFilter();
ArrayList<ItemStack> filtered;
try {
filtered = ItemList.forkJoinPool.submit(
() -> ItemList.items.parallelStream().filter(filter::matches)
.collect(Collectors.toCollection(ArrayList::new)))
.get();
} catch (InterruptedException | ExecutionException e) {
filtered = new ArrayList<>();
e.printStackTrace();
stop();
}
if (interrupted()) return;
filtered.sort(Comparator.comparingInt(ordering::get));
if (interrupted()) return;
ItemPanel.updateItemList(filtered);
}
};
}
@@ -23,6 +23,7 @@ import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IIcon;
import net.minecraft.world.World;
import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.common.util.ForgeDirection;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@@ -65,26 +66,40 @@ public class ItemMobSpawner extends ItemBlock {
@Override
public boolean onItemUse(ItemStack itemstack, EntityPlayer entityplayer, World world, int x, int y, int z, int side,
float hitX, float hitY, float hitZ) {
int targetX = x;
int targetY = y;
int targetZ = z;
placedX = x;
placedY = y;
placedZ = z;
if (!world.getBlock(x, y, z).isReplaceable(world, x, y, z)) {
ForgeDirection direction = ForgeDirection.getOrientation(side);
targetX += direction.offsetX;
targetY += direction.offsetY;
targetZ += direction.offsetZ;
}
placedX = targetX;
placedY = targetY;
placedZ = targetZ;
String mobType = getMobTypeFromItemStack(itemstack);
boolean placed = super.onItemUse(itemstack, entityplayer, world, x, y, z, side, hitX, hitY, hitZ);
if (placed && !world.isRemote) {
TileEntity tileEntity = world.getTileEntity(x, y, z);
if (tileEntity instanceof TileEntityMobSpawner) {
TileEntityMobSpawner spawner = (TileEntityMobSpawner) tileEntity;
String mobType = getMobTypeFromItemStack(itemstack);
if (mobType != null) {
spawner.func_145881_a().setEntityName(mobType);
world.markBlockForUpdate(x, y, z);
NEICPH.sendMobSpawnerID(x, y, z, mobType);
if (placed) {
TileEntity tileEntity = world.getTileEntity(targetX, targetY, targetZ);
if (tileEntity instanceof TileEntityMobSpawner spawner && mobType != null) {
spawner.func_145881_a().setEntityName(mobType);
if (!world.isRemote) {
world.markBlockForUpdate(targetX, targetY, targetZ);
NEICPH.sendMobSpawnerID(targetX, targetY, targetZ, mobType);
}
}
return true;
}
return placed;
}
+6 -6
View File
@@ -42,7 +42,7 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
if (this.stack != null && this.availableAreaWidth >= SLOT_SIZE * 2
&& (NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled")
|| NEIClientConfig.isKeyHashDown("gui.itemzoom_hold"))
|| KeyManager.isKeyDown("itemzoom.hold"))
&& GuiContainerManager.shouldShowTooltip(NEIClientUtils.getGuiContainer())) {
final float inverseScaleFactor = 1.0f / this.scale;
final float screenScale = getScreenScale();
@@ -74,7 +74,7 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
if (NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled")
&& NEIClientConfig.getBooleanSetting("inventory.itemzoom.helpText")) {
String keyName = NEIClientConfig.getKeyName("gui.itemzoom_toggle");
String keyName = KeyManager.getKeyName("itemzoom.toggle", NEIClientUtils.SHIFT_HASH);
if (keyName != null) {
String helpText = NEIClientUtils.translate("itemzoom.toggle", keyName);
@@ -198,24 +198,24 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
@Override
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
if (NEIClientConfig.isKeyHashDown("gui.itemzoom_toggle")) {
if (KeyManager.isHashDown("itemzoom.toggle", NEIClientUtils.SHIFT_HASH)) {
NEIClientConfig.getSetting("inventory.itemzoom.enabled")
.setBooleanValue(!NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled"));
return true;
}
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_hold")) {
if (this.stack != null && KeyManager.isKeyDown("itemzoom.hold")) {
return true;
}
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_zoom_in")) {
if (this.stack != null && KeyManager.isKeyDown("itemzoom.zoom_in")) {
increaseZoom(gui);
previousKeyboardRepeatEnabled = Keyboard.areRepeatEventsEnabled();
Keyboard.enableRepeatEvents(true);
return true;
}
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_zoom_out")) {
if (this.stack != null && KeyManager.isKeyDown("itemzoom.zoom_out")) {
decreaseZoom(gui);
previousKeyboardRepeatEnabled = Keyboard.areRepeatEventsEnabled();
Keyboard.enableRepeatEvents(true);
+18 -2
View File
@@ -15,6 +15,7 @@ import net.minecraft.client.shader.Framebuffer;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL30;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.api.GuiInfo;
@@ -27,7 +28,7 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
protected static class ScreenCapture {
private long nextCacheRefresh = 0;
private Framebuffer framebuffer;
private final Framebuffer framebuffer;
public ScreenCapture() {
this.framebuffer = new Framebuffer(1, 1, true);
@@ -51,7 +52,7 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
}
public void captureScreen(Runnable callback, int mode) {
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
resetFramebuffer();
this.framebuffer.bindFramebuffer(false);
@@ -84,6 +85,21 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
} else {
this.framebuffer.framebufferClear();
}
// Copy stencil values (required by mui2)
OpenGlHelper.func_153171_g(GL30.GL_READ_FRAMEBUFFER, minecraft.getFramebuffer().framebufferObject);
OpenGlHelper.func_153171_g(GL30.GL_DRAW_FRAMEBUFFER, this.framebuffer.framebufferObject);
GL30.glBlitFramebuffer(
0,
0,
minecraft.displayWidth,
minecraft.displayHeight,
0,
0,
minecraft.displayWidth,
minecraft.displayHeight,
GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT,
GL11.GL_NEAREST);
}
public void renderCapturedScreen() {
+129 -21
View File
@@ -2,14 +2,21 @@ package codechicken.nei;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.Map;
import java.util.StringJoiner;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.KeyBinding;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import codechicken.nei.util.NEIKeyboardUtils;
import codechicken.nei.util.NEIMouseUtils;
import cpw.mods.fml.client.registry.ClientRegistry;
/**
* Good old down/held/up keystate tracker
* Registers NEI key bindings as vanilla {@link KeyBinding}s and exposes their state to the rest of NEI.
*/
public class KeyManager {
@@ -18,31 +25,132 @@ public class KeyManager {
public void tickKeyStates();
}
public static class KeyState {
public static LinkedList<IKeyStateTracker> trackers = new LinkedList<>();
private static final Map<String, KeyBinding> keyBindings = new HashMap<>();
private static final Map<String, String> keyAliases = new HashMap<>();
private static volatile boolean pendingOptionsReload = false;
public boolean down;
public boolean held;
public boolean up;
static {
// Aliases for legacy keybinds
keyAliases.put("gui.recipe", "recipe.recipe");
keyAliases.put("gui.usage", "recipe.usage");
keyAliases.put("gui.hide_bookmarks", "bookmark.hide");
}
public static HashMap<String, KeyState> keyStates = new HashMap<>();
public static LinkedList<IKeyStateTracker> trackers = new LinkedList<>();
public static KeyBinding registerKeyBinding(String ident, int defaultKey) {
return keyBindings.computeIfAbsent(ident, id -> {
final KeyBinding binding = new KeyBinding(
"nei.options.keys." + id,
NEIKeyboardUtils.unhash(defaultKey),
categoryFor(id));
ClientRegistry.registerKeyBinding(binding);
return binding;
});
}
public static KeyBinding getKeyBinding(String ident) {
return keyBindings.get(keyAliases.getOrDefault(ident, ident));
}
public static boolean isRegistered(String description) {
for (KeyBinding binding : keyBindings.values()) {
if (binding.getKeyDescription().equals(description)) {
return true;
}
}
return false;
}
public static int getKeyCode(String ident) {
final KeyBinding binding = getKeyBinding(ident);
return binding == null ? Keyboard.KEY_NONE : binding.getKeyCode();
}
public static boolean isKeyDown(String ident) {
final KeyBinding binding = getKeyBinding(ident);
if (binding != null) {
final int keyCode = binding.getKeyCode();
if (keyCode < 0) {
return Mouse.isButtonDown(keyCode + 100);
} else if (keyCode > Keyboard.KEY_NONE && keyCode < Keyboard.KEYBOARD_SIZE) {
return Keyboard.isKeyDown(keyCode);
}
}
return false;
}
public static boolean isHashDown(String ident) {
return isHashDown(ident, 0);
}
public static boolean isHashDown(String ident, int modifierMask) {
if (!isKeyDown(ident)) {
return false;
}
if (NEIKeyboardUtils.isHashKey(getKeyCode(ident))) {
return true;
}
return ((modifierMask & NEIKeyboardUtils.CTRL_HASH) != 0) == NEIClientUtils.controlKey()
&& ((modifierMask & NEIKeyboardUtils.SHIFT_HASH) != 0) == NEIClientUtils.shiftKey()
&& ((modifierMask & NEIKeyboardUtils.ALT_HASH) != 0) == NEIClientUtils.altKey();
}
public static String getKeyName(String ident) {
return getKeyName(ident, 0);
}
public static String getKeyName(String ident, int meta) {
final int keyCode = getKeyCode(ident);
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);
}
public static String getKeyName(int keyBind, int mouseBind) {
StringJoiner keyText = new StringJoiner(" + ");
String keyHash = keyBind == Keyboard.KEY_NONE ? "" : NEIKeyboardUtils.getKeyName(keyBind);
String mouseHash = mouseBind == NEIMouseUtils.MOUSE_BTN_NONE ? "" : NEIMouseUtils.getKeyName(mouseBind);
if (!keyHash.isEmpty()) {
keyText.add(keyHash);
}
if (!mouseHash.isEmpty()) {
keyText.add(mouseHash);
}
return keyText.toString();
}
public static boolean isPressed(String ident) {
final KeyBinding binding = getKeyBinding(ident);
return binding != null && binding.isPressed();
}
private static String categoryFor(String ident) {
final int dot = ident.indexOf('.');
return dot < 0 ? "nei.options.keys" : "nei.options.keys." + ident.substring(0, dot);
}
public static void requestOptionsReload() {
pendingOptionsReload = true;
}
public static void tickKeyStates() {
for (Entry<String, KeyState> entry : keyStates.entrySet()) {
final int keyCode = NEIKeyboardUtils.unhash(NEIClientConfig.getKeyBinding(entry.getKey()));
final boolean down = keyCode > 0 && keyCode < Keyboard.KEYBOARD_SIZE && Keyboard.isKeyDown(keyCode);
final KeyState state = entry.getValue();
if (down) {
state.down = !state.held;
state.up = false;
} else {
state.up = state.held;
state.down = false;
}
state.held = down;
if (pendingOptionsReload) {
pendingOptionsReload = false;
Minecraft.getMinecraft().gameSettings.loadOptions();
}
for (IKeyStateTracker tracker : trackers) tracker.tickKeyStates();
@@ -66,9 +66,9 @@ import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.guihook.IContainerObjectHandler;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.recipe.AutoCraftingManager;
import codechicken.nei.recipe.DebugHandlerWidget;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.RecipeCatalysts;
import codechicken.nei.recipe.debug.DebugHandlerWidget;
public class LayoutManager implements IContainerInputHandler, IContainerTooltipHandler, IContainerDrawHandler,
IContainerObjectHandler, IKeyStateTracker {
@@ -92,7 +92,6 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public static SubsetWidget dropDown;
public static SearchField searchField;
public static ItemZoom itemZoom;
public static DebugHandlerWidget recipeHandlerWidget;
public static ButtonCycled options;
public static ButtonCycled bookmarksButton;
@@ -225,17 +224,17 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
if (NEIClientConfig.isKeyHashDown("gui.hide")) {
if (KeyManager.isKeyDown("gui.hide")) {
toggleBooleanSetting("inventory.hidden");
return true;
}
if (NEIClientConfig.isKeyHashDown("gui.hide_bookmarks")) {
if (KeyManager.isKeyDown("bookmark.hide")) {
toggleBooleanSetting("inventory.bookmarks.enabled");
return true;
}
if (NEIClientConfig.isKeyHashDown("gui.next_tooltip") && GuiContainerManager.incrementTooltipPage()) {
if (KeyManager.isKeyDown("gui.next_tooltip") && GuiContainerManager.incrementTooltipPage()) {
return true;
}
@@ -406,8 +405,6 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
itemZoom = new ItemZoom();
recipeHandlerWidget = new DebugHandlerWidget();
dropDown = new SubsetWidget();
searchField = new SearchField("search");
API.addItemFilter(searchField);
@@ -786,8 +783,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
addWidget(dropDown);
}
addWidget(recipeHandlerWidget);
recipeHandlerWidget.setVisible();
addWidget(DebugHandlerWidget.instance);
}
public static LayoutStyle getLayoutStyle(int id) {
@@ -945,12 +941,12 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public void tickKeyStates() {
if (Minecraft.getMinecraft().currentScreen != null) return;
if (KeyManager.keyStates.get("world.dawn").down) timeButtons[0].onButtonPress(false);
if (KeyManager.keyStates.get("world.noon").down) timeButtons[1].onButtonPress(false);
if (KeyManager.keyStates.get("world.dusk").down) timeButtons[2].onButtonPress(false);
if (KeyManager.keyStates.get("world.midnight").down) timeButtons[3].onButtonPress(false);
if (KeyManager.keyStates.get("world.rain").down) rain.onButtonPress(false);
if (KeyManager.keyStates.get("world.heal").down) heal.onButtonPress(false);
if (KeyManager.keyStates.get("world.creative").down) gamemode.onButtonPress(false);
if (KeyManager.isPressed("world.dawn")) timeButtons[0].onButtonPress(false);
if (KeyManager.isPressed("world.noon")) timeButtons[1].onButtonPress(false);
if (KeyManager.isPressed("world.dusk")) timeButtons[2].onButtonPress(false);
if (KeyManager.isPressed("world.midnight")) timeButtons[3].onButtonPress(false);
if (KeyManager.isPressed("world.rain")) rain.onButtonPress(false);
if (KeyManager.isPressed("world.heal")) heal.onButtonPress(false);
if (KeyManager.isPressed("world.creative")) gamemode.onButtonPress(false);
}
}
@@ -244,7 +244,11 @@ public class LayoutStyleMinecraft extends LayoutStyle {
Image icon = b.getRenderIcon();
if (icon == null) {
int colour = tex == 2 ? 0xffffa0 : tex == 0 ? 0x601010 : 0xe0e0e0;
int labelColor = b.getRenderLabelColor();
int colour = labelColor != 0 ? labelColor
: tex == 2 ? ColorUtils.buttonLabelHover.getColor()
: tex == 0 ? ColorUtils.buttonLabelDisabled.getColor()
: ColorUtils.buttonLabelNormal.getColor();
drawStringC(b.getRenderLabel(), b.x + b.w / 2, b.y + (b.h - 8) / 2, colour);
} else {
@@ -54,6 +54,7 @@ public class NEIActions {
addAction("magnet", true);
addAction("enchant", true);
addAction("potion", true);
addAction("autocraft");
canDisable.add("dawn");
canDisable.add("noon");
+16 -2
View File
@@ -6,6 +6,7 @@ import static codechicken.nei.PacketIDs.S2C;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.play.INetHandlerPlayClient;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.world.World;
@@ -14,6 +15,7 @@ import codechicken.core.ClientUtils;
import codechicken.lib.inventory.InventoryUtils;
import codechicken.lib.packet.PacketCustom;
import codechicken.lib.packet.PacketCustom.IClientPacketHandler;
import codechicken.nei.commands.CommandBookmarkAdd;
import cpw.mods.fml.relauncher.Side;
public class NEICPH implements IClientPacketHandler {
@@ -56,6 +58,18 @@ public class NEICPH implements IClientPacketHandler {
case S2C.OPEN_POTION_GUI:
ClientUtils.openSMPGui(packet.readUByte(), new GuiPotionCreator(mc.thePlayer.inventory));
break;
case S2C.CACHE_BOOKMARK_DATA:
handleCacheBookmarkData(packet);
break;
}
}
private void handleCacheBookmarkData(PacketCustom packet) {
final String payloadId = packet.readString();
final NBTTagCompound payloadTag = packet.readNBTTagCompound();
if (payloadTag != null) {
CommandBookmarkAdd.cachePayload(payloadId, payloadTag);
}
}
@@ -186,9 +200,9 @@ public class NEICPH implements IClientPacketHandler {
packet.sendToServer();
}
public static void sendChatLink(ItemStack stackover) {
public static void sendChatLink(NBTTagCompound payloadTag) {
PacketCustom packet = new PacketCustom(channel, C2S.SEND_CHAT_ITEM_LINK);
packet.writeItemStack(stackover);
packet.writeNBTTagCompound(payloadTag);
packet.sendToServer();
}
@@ -56,14 +56,11 @@ import codechicken.nei.config.OptionToggleButtonBoubs;
import codechicken.nei.config.OptionUtilities;
import codechicken.nei.config.preset.GuiPresetList;
import codechicken.nei.event.NEIConfigsLoadedEvent;
import codechicken.nei.recipe.DebugHandlerWidget;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.IRecipeHandler;
import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.RecipeCatalysts;
import codechicken.nei.recipe.RecipeInfo;
import codechicken.nei.util.ItemUntranslator;
import codechicken.nei.util.NEIKeyboardUtils;
import codechicken.obfuscator.ObfuscationRun;
public class NEIClientConfig {
@@ -149,6 +146,7 @@ public class NEIClientConfig {
API.addOption(new OptionToggleButton("inventory.widgetsenabled"));
tag.getTag("findFuelsParallel").getBooleanValue(true);
tag.getTag("showRepairOnlyForDamageableItems").getBooleanValue(true);
tag.getTag("inventory.autocrafting").getBooleanValue(true);
tag.getTag("inventory.dynamicFontSize").getBooleanValue(true);
@@ -264,6 +262,10 @@ public class NEIClientConfig {
.setComment("Require holding shift to move items when overlaying recipe").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.guirecipe.shiftOverlayRecipe", true));
tag.getTag("inventory.guirecipe.scrollPages").setComment("Disable page scroll when overlaying recipe")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.guirecipe.scrollPages", true));
tag.getTag("inventory.guirecipe.profile").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.guirecipe.profile", true));
@@ -308,7 +310,7 @@ public class NEIClientConfig {
super.onClick(button);
CollapsibleItems.saveStates();
CollapsibleItems.load();
LayoutManager.markItemsDirty();
ItemList.refreshItems.restart();
return true;
}
});
@@ -812,35 +814,38 @@ public class NEIClientConfig {
}
private static void setDefaultKeyBindings() {
API.addHashBind("gui.recipe", Keyboard.KEY_R);
API.addHashBind("gui.usage", Keyboard.KEY_U);
API.addKeyBind("gui.back", Keyboard.KEY_BACK);
API.addHashBind("gui.enchant", Keyboard.KEY_X);
API.addHashBind("gui.potion", Keyboard.KEY_P);
API.addKeyBind("gui.enchant", Keyboard.KEY_X);
API.addKeyBind("gui.potion", Keyboard.KEY_P);
API.addKeyBind("gui.prev", Keyboard.KEY_PRIOR);
API.addKeyBind("gui.next", Keyboard.KEY_NEXT);
API.addKeyBind("gui.prev_machine", Keyboard.KEY_UP);
API.addKeyBind("gui.next_machine", Keyboard.KEY_DOWN);
API.addKeyBind("gui.prev_recipe", Keyboard.KEY_LEFT);
API.addKeyBind("gui.next_recipe", Keyboard.KEY_RIGHT);
API.addHashBind("gui.hide", Keyboard.KEY_O);
API.addHashBind("gui.search", Keyboard.KEY_F);
API.addKeyBind("gui.bookmark", Keyboard.KEY_A);
API.addHashBind("gui.favorite", Keyboard.KEY_F + NEIClientUtils.SHIFT_HASH);
API.addKeyBind("gui.favorite_item", Keyboard.KEY_F);
API.addHashBind("gui.remove_recipe", Keyboard.KEY_A + NEIClientUtils.SHIFT_HASH);
API.addKeyBind("gui.bookmark_pull_items", Keyboard.KEY_V);
API.addKeyBind("gui.hide", Keyboard.KEY_O);
API.addKeyBind("gui.search", Keyboard.KEY_F);
API.addKeyBind("gui.overlay", Keyboard.KEY_S);
API.addKeyBind("gui.craft_items", Keyboard.KEY_C);
API.addHashBind("gui.hide_bookmarks", Keyboard.KEY_B);
API.addKeyBind("gui.getprevioussearch", Keyboard.KEY_UP);
API.addKeyBind("gui.getnextsearch", Keyboard.KEY_DOWN);
API.addKeyBind("gui.next_tooltip", Keyboard.KEY_Z);
API.addHashBind("gui.itemzoom_toggle", Keyboard.KEY_Z + NEIClientUtils.SHIFT_HASH);
API.addHashBind("gui.itemzoom_hold", 0);
API.addHashBind("gui.itemzoom_zoom_in", 0);
API.addHashBind("gui.itemzoom_zoom_out", 0);
API.addKeyBind("recipe.recipe", Keyboard.KEY_R);
API.addKeyBind("recipe.usage", Keyboard.KEY_U);
API.addKeyBind("recipe.back", Keyboard.KEY_BACK);
API.addKeyBind("recipe.prev_machine", Keyboard.KEY_UP);
API.addKeyBind("recipe.next_machine", Keyboard.KEY_DOWN);
API.addKeyBind("recipe.prev_recipe", Keyboard.KEY_LEFT);
API.addKeyBind("recipe.next_recipe", Keyboard.KEY_RIGHT);
API.addKeyBind("bookmark.add", Keyboard.KEY_A);
API.addKeyBind("bookmark.favorite", Keyboard.KEY_F);
API.addKeyBind("bookmark.favorite_item", Keyboard.KEY_F);
API.addKeyBind("bookmark.remove_recipe", Keyboard.KEY_A);
API.addKeyBind("bookmark.pull_items", Keyboard.KEY_V);
API.addKeyBind("bookmark.chat_link", Keyboard.KEY_L);
API.addKeyBind("bookmark.hide", Keyboard.KEY_B);
API.addKeyBind("itemzoom.toggle", Keyboard.KEY_Z);
API.addKeyBind("itemzoom.hold", 0);
API.addKeyBind("itemzoom.zoom_in", 0);
API.addKeyBind("itemzoom.zoom_out", 0);
API.addKeyBind("world.chunkoverlay", Keyboard.KEY_F9);
API.addKeyBind("world.moboverlay", Keyboard.KEY_F7);
@@ -852,10 +857,10 @@ public class NEIClientConfig {
API.addKeyBind("world.rain", 0);
API.addKeyBind("world.heal", 0);
API.addKeyBind("world.creative", 0);
API.addHashBind("gui.copy_name", Keyboard.KEY_C + NEIClientUtils.CTRL_HASH);
API.addHashBind("gui.copy_oredict", Keyboard.KEY_D + NEIClientUtils.CTRL_HASH);
API.addHashBind("gui.copy_id", Keyboard.KEY_X + NEIClientUtils.CTRL_HASH);
API.addHashBind("gui.chat_link_item", Keyboard.KEY_L + NEIClientUtils.CTRL_HASH);
API.addKeyBind("copy.name", Keyboard.KEY_C);
API.addKeyBind("copy.oredict", Keyboard.KEY_D);
API.addKeyBind("copy.identifier", Keyboard.KEY_X);
}
public static OptionList getOptionList() {
@@ -926,50 +931,28 @@ public class NEIClientConfig {
world.saveNBT();
}
private static final Map<String, String> keySettings = new HashMap<>();
public static int getKeyBinding(String string) {
final String key = keySettings.computeIfAbsent(string, s -> "keys." + s);
return getSetting(key).getIntValue(Keyboard.KEY_NONE);
return KeyManager.getKeyCode(string);
}
public static void setDefaultKeyBinding(String string, int key) {
getSetting("keys." + string).getIntValue(key);
KeyManager.registerKeyBinding(string, key);
}
public static boolean isKeyHashDown(String string) {
final int hash = getKeyBinding(string);
if (hash != Keyboard.CHAR_NONE && Keyboard.getEventKeyState()) {
return KeyManager.keyStates.containsKey(string) ? Keyboard.isKeyDown(NEIKeyboardUtils.unhash(hash))
: hash == NEIClientUtils.getKeyHash();
}
return false;
return KeyManager.isHashDown(string);
}
public static String getKeyName(String keyBind) {
return getKeyName(keyBind, 0);
return KeyManager.getKeyName(keyBind);
}
public static String getKeyName(String keyBind, int meta, int mouseBind) {
final int hash = getKeyBinding(keyBind);
if (hash == Keyboard.CHAR_NONE) {
return null;
}
return NEIClientUtils.getKeyName(hash + meta, mouseBind);
return KeyManager.getKeyName(keyBind, meta, mouseBind);
}
public static String getKeyName(String keyBind, int meta) {
final int hash = getKeyBinding(keyBind);
if (hash == Keyboard.CHAR_NONE) {
return null;
}
return NEIKeyboardUtils.getKeyName(hash + meta);
return KeyManager.getKeyName(keyBind, meta);
}
public static void bootNEI() {
@@ -978,7 +961,6 @@ public class NEIClientConfig {
// main NEI config loading
ItemInfo.load();
GuiInfo.load();
RecipeInfo.load();
HeldItemHandler.load();
LayoutManager.load();
NEIController.load();
@@ -1005,6 +987,7 @@ public class NEIClientConfig {
}
});
KeyManager.requestOptionsReload();
RecipeCatalysts.loadCatalystInfo();
SubsetWidget.loadCustomSubsets();
SubsetWidget.loadHidden();
@@ -1018,14 +1001,16 @@ public class NEIClientConfig {
// API. I don't expect any handler to do this, but who knows what modders have come up with...
pluginNEIConfigLoaded = true;
MinecraftForge.EVENT_BUS.post(new NEIConfigsLoadedEvent());
DebugHandlerWidget.loadHandlerInfoPatch();
ItemList.loadItems.restart();
}
}.start();
} else {
SubsetWidget.loadHidden();
ItemList.loadItems.restart();
if (ItemList.loadFinished) {
ItemList.refreshItems.restart();
} else {
ItemList.loadItems.restart();
}
}
}
@@ -1049,7 +1034,9 @@ public class NEIClientConfig {
}
public static boolean autocraftingEnabled() {
return getBooleanSetting("inventory.autocrafting");
if (!getBooleanSetting("inventory.autocrafting")) return false;
if (hasSMPCounterpart) return permissableActions.contains("autocraft");
return true;
}
public static boolean favoritesEnabled() {
@@ -25,7 +25,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
import java.util.stream.Collectors;
import net.minecraft.client.Minecraft;
@@ -39,6 +38,7 @@ import net.minecraft.inventory.Container;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.IChatComponent;
import net.minecraft.util.ResourceLocation;
@@ -57,7 +57,6 @@ import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.IInfiniteItemHandler;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.util.NEIKeyboardUtils;
import codechicken.nei.util.NEIMouseUtils;
public class NEIClientUtils extends NEIServerUtils {
@@ -95,6 +94,7 @@ public class NEIClientUtils extends NEIServerUtils {
/** Formats a number with group separator and at most 2 fraction digits. */
private static final Map<Locale, DecimalFormat> decimalFormatters = new HashMap<>();
private static final DecimalFormat CHANCE_FORMAT = new DecimalFormat("##0.##%");
public static final int ALT_HASH = NEIKeyboardUtils.ALT_HASH;
public static final int SHIFT_HASH = NEIKeyboardUtils.SHIFT_HASH;
@@ -126,7 +126,7 @@ public class NEIClientUtils extends NEIServerUtils {
});
}
public static String formatNumber(long aNumber) {
public static String formatNumber(Number aNumber) {
if (NEIModContainer.isGTNHLibLoaded()) {
return NumberFormatUtil.formatNumber(aNumber);
@@ -135,7 +135,7 @@ public class NEIClientUtils extends NEIServerUtils {
return getDecimalFormat().format(aNumber);
}
public static String formatFluid(long aNumber) {
public static String formatFluid(Number aNumber) {
if (NEIModContainer.isGTNHLibLoaded()) {
return NumberFormatUtil.formatFluid(aNumber);
@@ -144,6 +144,10 @@ public class NEIClientUtils extends NEIServerUtils {
return getDecimalFormat().format(aNumber) + " L";
}
public static String formatChance(float chance) {
return CHANCE_FORMAT.format(chance);
}
public static void deleteHeldItem() {
deleteSlotStack(-999);
}
@@ -376,8 +380,8 @@ public class NEIClientUtils extends NEIServerUtils {
else sendCommand(getStringSetting("command.heal"), mc().thePlayer.getCommandSenderName());
}
public static void sendChatItemLink(ItemStack stackover) {
if (hasSMPCounterPart()) NEICPH.sendChatLink(stackover);
public static void sendChatItemLink(NBTTagCompound payload) {
if (hasSMPCounterPart()) NEICPH.sendChatLink(payload);
}
public static void toggleMagnetMode() {
@@ -451,55 +455,8 @@ public class NEIClientUtils extends NEIServerUtils {
return Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU);
}
public static int getMetaHash() {
if (Keyboard.getEventKeyState()) {
int hash = 0;
if (altKey()) {
hash = hash | ALT_HASH;
}
if (shiftKey()) {
hash = hash | SHIFT_HASH;
}
if (controlKey()) {
hash = hash | CTRL_HASH;
}
return hash;
}
return 0;
}
public static int getKeyHash() {
if (Keyboard.getEventKeyState()) {
final int keycode = Keyboard.getEventKey();
if (!NEIKeyboardUtils.isHashKey(keycode)) {
return getMetaHash() + keycode;
}
}
return Keyboard.CHAR_NONE;
}
public static String getKeyName(int keyBind, int mouseBind) {
StringJoiner keyText = new StringJoiner(" + ");
String keyHash = keyBind == Keyboard.KEY_NONE ? "" : NEIKeyboardUtils.getKeyName(keyBind);
String mouseHash = mouseBind == NEIMouseUtils.MOUSE_BTN_NONE ? "" : NEIMouseUtils.getKeyName(mouseBind);
if (!keyHash.isEmpty()) {
keyText.add(keyHash);
}
if (!mouseHash.isEmpty()) {
keyText.add(mouseHash);
}
return keyText.toString();
return KeyManager.getKeyName(keyBind, mouseBind);
}
public static void playClickSound() {
@@ -1,6 +1,7 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.getMousePosition;
import static codechicken.nei.NEIClientConfig.canCheatItem;
import java.awt.Point;
import java.util.LinkedList;
@@ -26,7 +27,7 @@ import codechicken.nei.commands.CommandUntranslator;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.guihook.IContainerSlotClickHandler;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.util.EmptyContainer;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@@ -151,6 +152,8 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
&& slot != null
&& slot.getStack() != null
&& slot.isItemValid(slot.getStack())) {
if (!canCheatItem(slot.getStack())) return false;
NEIClientUtils.cheatItem(slot.getStack(), button, 1);
return true;
}
@@ -249,7 +252,7 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
// slot in GuiRecipe does not contain actual stack
// and scroll should be handled by GuiRecipe, not here
if (gui instanceof GuiRecipe) return false;
if (gui.inventorySlots instanceof EmptyContainer) return false;
Point mousePos = getMousePosition();
Slot mouseover = manager.window.getSlotAtPosition(mousePos.x, mousePos.y);
@@ -43,6 +43,7 @@ public class NEIModContainer extends DummyModContainer {
private static boolean gregTech5Loaded;
private static boolean gtnhLibLoaded;
private static boolean cubicChunksLoaded;
private static ASMDataTable asmDataTable;
@@ -69,6 +70,10 @@ public class NEIModContainer extends DummyModContainer {
return gtnhLibLoaded;
}
public static boolean isCCLoaded() {
return cubicChunksLoaded;
}
@Override
public Set<ArtifactVersion> getRequirements() {
Set<ArtifactVersion> deps = new HashSet<>();
@@ -96,6 +101,7 @@ public class NEIModContainer extends DummyModContainer {
public void preInit(FMLPreInitializationEvent event) {
gregTech5Loaded = Loader.isModLoaded("gregtech") && !Loader.isModLoaded("gregapi_post");
gtnhLibLoaded = Loader.isModLoaded("gtnhlib");
cubicChunksLoaded = Loader.isModLoaded("cubicchunks");
if (CommonUtils.isClient()) ClientHandler.preInit();
asmDataTable = event.getAsmData();
}
@@ -104,6 +110,7 @@ public class NEIModContainer extends DummyModContainer {
public void init(FMLInitializationEvent event) {
if (CommonUtils.isClient()) {
ClientHandler.load();
IMCForNEI.IMCSender();
}
ServerHandler.load();
}
+3 -1
View File
@@ -11,6 +11,7 @@ import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.InventoryBasic;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.play.INetHandlerPlayServer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityMobSpawner;
@@ -95,7 +96,8 @@ public class NEISPH implements IServerPacketHandler {
}
private void handleSendChatItemLink(EntityPlayerMP sender, PacketCustom packet) {
NEIServerUtils.sendChatItemLink(sender, packet.readItemStack());
final NBTTagCompound payloadTag = packet.readNBTTagCompound();
NEIServerUtils.sendChatItemLink(sender, payloadTag);
}
private void handleDummySlotSet(EntityPlayerMP sender, PacketCustom packet) {
@@ -108,6 +108,7 @@ public class NEIServerConfig {
setDefaultFeature("save-state");
setDefaultFeature("item");
setDefaultFeature("delete");
setDefaultFeature("autocraft", "ALL");
setDefaultFeature("notify-item", "CONSOLE, OP");
}
@@ -10,6 +10,7 @@ import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.zip.ZipException;
import net.minecraft.command.ICommandSender;
@@ -28,6 +29,7 @@ import net.minecraft.nbt.NBTException;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IChatComponent;
@@ -44,6 +46,7 @@ import codechicken.lib.inventory.InventoryRange;
import codechicken.lib.inventory.InventoryUtils;
import codechicken.lib.packet.PacketCustom;
import codechicken.nei.PacketIDs.S2C;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTHelper;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.registry.GameRegistry;
@@ -86,16 +89,46 @@ public class NEIServerUtils {
player.extinguish();
}
public static void sendChatItemLink(EntityPlayerMP sender, ItemStack stackover) {
ServerUtils.sendChatToAll(
new ChatComponentTranslation(
"nei.chat.item_link.text",
sender.getDisplayName(),
stackover.func_151000_E().setChatStyle(
stackover.func_151000_E().getChatStyle().setChatClickEvent(
new ClickEvent(
ClickEvent.Action.RUN_COMMAND,
"/nei_bookmark " + stackover.writeToNBT(new NBTTagCompound()))))));
public static void sendChatItemLink(EntityPlayerMP sender, NBTTagCompound payload) {
if (payload == null) {
sender.addChatMessage(new ChatComponentText("Invalid bookmark payload"));
return;
}
final String linkType = payload.getString("linkType");
final String payloadId = UUID.randomUUID().toString().substring(0, 8);
final PacketCustom packet = new PacketCustom(NEISPH.channel, S2C.CACHE_BOOKMARK_DATA).writeString(payloadId)
.writeNBTTagCompound((NBTTagCompound) payload.copy());
for (EntityPlayer player : ServerUtils.getPlayers()) {
if (player instanceof EntityPlayerMP playerMP) {
packet.sendToPlayer(playerMP);
}
}
try {
final IChatComponent clickable;
if (payload.hasKey("item")) {
clickable = StackInfo.loadFromNBT(payload.getCompoundTag("item")).func_151000_E();
} else {
clickable = new ChatComponentText("[")
.appendSibling(new ChatComponentTranslation("nei.chat.item_link." + linkType + ".text"))
.appendText("]");
}
if (clickable == null) {
throw new Exception("Invalid ItemStack NBT");
}
clickable.getChatStyle()
.setChatClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/nei_bookmark " + payloadId));
ServerUtils.sendChatToAll(
new ChatComponentTranslation("nei.chat.item_link.text", sender.getDisplayName(), clickable));
} catch (Exception e) {
sender.addChatMessage(new ChatComponentText(e.toString()));
}
}
public static long getTime(World world) {
@@ -183,7 +216,7 @@ public class NEIServerUtils {
public static boolean areStacksSameTypeWithNBT(ItemStack stack1, ItemStack stack2) {
return stack1 != null && stack2 != null
&& stack1.getItem() == stack2.getItem()
&& (!stack2.getHasSubtypes() || stack2.getItemDamage() == stack1.getItemDamage())
&& (stack2.isItemStackDamageable() || stack2.getItemDamage() == stack1.getItemDamage())
&& NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound());
}
@@ -37,5 +37,6 @@ public final class PacketIDs {
public static final int OPEN_ENCHANTMENT_GUI = 21;
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;
}
}
@@ -309,12 +309,12 @@ public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ?
final Point mouse = GuiDraw.getMousePosition();
if (!contains(mouse.x, mouse.y)) return false;
if (NEIClientConfig.isKeyHashDown("gui.next")) {
if (KeyManager.isKeyDown("gui.next")) {
this.grid.shiftPage(1);
return true;
}
if (NEIClientConfig.isKeyHashDown("gui.prev")) {
if (KeyManager.isKeyDown("gui.prev")) {
this.grid.shiftPage(-1);
return true;
}
@@ -24,12 +24,12 @@ public class PopupInputHandler implements IContainerInputHandler {
@Override
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
if (NEIClientConfig.isKeyHashDown("gui.enchant") && canPerformAction("enchant")) {
if (KeyManager.isHashDown("gui.enchant") && canPerformAction("enchant")) {
NEICPH.sendOpenEnchantmentWindow();
return true;
}
if (NEIClientConfig.isKeyHashDown("gui.potion") && canPerformAction("potion")) {
if (KeyManager.isHashDown("gui.potion") && canPerformAction("potion")) {
NEICPH.sendOpenPotionWindow();
return true;
}
@@ -13,6 +13,7 @@ import net.minecraftforge.oredict.OreDictionary;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.recipe.Badge;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.StackInfo;
@@ -21,12 +22,16 @@ import codechicken.nei.recipe.StackInfo;
*/
public class PositionedStack {
/** Maximum chance value representing 100% probability (1 unit = 0.01%). */
public static final int CHANCE_FULL = 10_000;
public int relx;
public int rely;
public ItemStack[] items;
// compatibility dummy
public ItemStack item;
protected int chance = CHANCE_FULL;
private boolean permutated = false;
public PositionedStack(Object object, int x, int y, boolean genPerms) {
@@ -82,6 +87,18 @@ public class PositionedStack {
for (ItemStack item : items) if (item.stackSize > i) item.stackSize = i;
}
public List<Badge> getBadges() {
return null;
}
public int getChance() {
return this.chance;
}
public void setChance(int chance) {
this.chance = chance;
}
public PositionedStack copy() {
PositionedStack pStack = new PositionedStack(
Arrays.stream(this.items).map(ItemStack::copy).toArray(ItemStack[]::new),
@@ -89,6 +106,7 @@ public class PositionedStack {
rely,
false);
pStack.permutated = this.permutated;
pStack.chance = this.chance;
return pStack;
}
+10 -4
View File
@@ -89,9 +89,9 @@ public class PresetsList {
return false;
}
final PositionedStack result = handler.getResultStack(recipeIndex);
final List<PositionedStack> results = handler.getResultStacks(recipeIndex);
if (result != null && matchPositionedStack(result)) {
if (!results.isEmpty() && matchPositionedStack(results, true)) {
return true;
}
@@ -101,7 +101,13 @@ public class PresetsList {
return true;
}
return result == null && others.isEmpty();
final List<PositionedStack> extraInputs = handler.getCatalystStacks(recipeIndex);
if (!extraInputs.isEmpty() && matchPositionedStack(extraInputs, true)) {
return true;
}
return results.isEmpty() && others.isEmpty();
}
private boolean matchPositionedStack(List<PositionedStack> items, boolean dir) {
@@ -251,7 +257,7 @@ public class PresetsList {
updateSubsets();
CollapsibleItems.saveStates();
CollapsibleItems.load();
LayoutManager.markItemsDirty();
ItemList.refreshItems.restart();
}
private static void updateSubsets() {
@@ -50,11 +50,11 @@ public abstract class RecipeSearchField extends TextField implements ItemFilterP
@Override
public void lastKeyTyped(int keyID, char keyChar) {
if (focused() && NEIClientConfig.isKeyHashDown("gui.getprevioussearch")) {
if (focused() && KeyManager.isKeyDown("gui.getprevioussearch")) {
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
}
if (focused() && NEIClientConfig.isKeyHashDown("gui.getnextsearch")) {
if (focused() && KeyManager.isKeyDown("gui.getnextsearch")) {
handleNavigateHistory(TextHistory.Direction.NEXT);
}
}
@@ -230,14 +230,14 @@ public class SearchField extends TextField implements ItemFilterProvider {
@Override
public void lastKeyTyped(int keyID, char keyChar) {
if (isVisible() && NEIClientConfig.isKeyHashDown("gui.search")) {
if (isVisible() && KeyManager.isHashDown("gui.search")) {
setFocus(true);
}
if (focused() && NEIClientConfig.isKeyHashDown("gui.getprevioussearch")) {
if (focused() && KeyManager.isKeyDown("gui.getprevioussearch")) {
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
}
if (focused() && NEIClientConfig.isKeyHashDown("gui.getnextsearch")) {
if (focused() && KeyManager.isKeyDown("gui.getnextsearch")) {
handleNavigateHistory(TextHistory.Direction.NEXT);
}
}
@@ -111,7 +111,7 @@ public class SearchTokenParser {
clearCache();
}
public void clearCache() {
public synchronized void clearCache() {
this.providersCache.clear();
this.filtersCache.clear();
this.recipesCache.clear();
+42 -24
View File
@@ -6,7 +6,6 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -19,6 +18,7 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTTagString;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
@@ -413,9 +413,10 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
}
/**
* All operations on this variable should be synchronised.
* Canonical {@link StackInfo#getItemStackGUID(ItemStack)} of every hidden item, stored by GUID so the state
* survives world reloads. All operations should be synchronised.
*/
private static final ItemStackSet hiddenItems = new ItemStackSet();
private static final Set<String> hiddenItems = new HashSet<>();
private static final Map<String, SubsetTag> tags = new HashMap<>();
private static final SubsetTag root = new SubsetTag("");
@@ -456,11 +457,16 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
}
public static boolean isHidden(ItemStack item) {
final String guid = StackInfo.getItemStackGUID(item);
synchronized (hiddenLock) {
return hiddenItems.contains(item);
return hiddenItems.contains(guid);
}
}
private static List<String> toGUIDs(List<ItemStack> items) {
return items.stream().map(StackInfo::getItemStackGUID).collect(Collectors.toList());
}
private static List<ItemStack> getItems(SubsetTag tag, List<ItemStack> items) {
items.addAll(tag.items);
@@ -472,19 +478,22 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
}
public static void showOnly(SubsetTag tag) {
final List<String> allItems = toGUIDs(getItems(root, new ArrayList<>()));
final List<String> tagItems = toGUIDs(getItems(tag, new ArrayList<>()));
synchronized (hiddenLock) {
hiddenItems.clear();
hiddenItems.addAll(getItems(root, new ArrayList<>()));
hiddenItems.removeAll(getItems(tag, new ArrayList<>()));
hiddenItems.addAll(allItems);
hiddenItems.removeAll(tagItems);
}
calculateVisibility();
}
public static void setHidden(SubsetTag tag, boolean hidden) {
synchronized (hiddenLock) {
final List<ItemStack> tagItems = getItems(tag, new ArrayList<>());
final List<String> tagItems = toGUIDs(getItems(tag, new ArrayList<>()));
synchronized (hiddenLock) {
if (hidden) {
hiddenItems.addAll(tagItems);
} else {
@@ -496,11 +505,13 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
}
public static void setHidden(ItemStack item, boolean hidden) {
final String guid = StackInfo.getItemStackGUID(item);
synchronized (hiddenLock) {
if (hidden) {
hiddenItems.add(item);
hiddenItems.add(guid);
} else {
hiddenItems.remove(item);
hiddenItems.remove(guid);
}
}
calculateVisibility();
@@ -582,13 +593,23 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
}
public static void loadHidden() {
final List<ItemStack> itemList = new LinkedList<>();
final Set<String> guids = new HashSet<>();
try {
final NBTTagList guidList = NEIClientConfig.world.nbt.getTagList("hiddenItems", 8);
for (int i = 0; i < guidList.tagCount(); i++) {
guids.add(guidList.getStringTagAt(i));
}
final NBTTagList list = NEIClientConfig.world.nbt.getTagList("hiddenItems", 10);
for (int i = 0; i < list.tagCount(); i++) {
itemList.add(ItemStack.loadItemStackFromNBT(list.getCompoundTagAt(i)));
final ItemStack stack = ItemStack.loadItemStackFromNBT(list.getCompoundTagAt(i));
if (stack != null) {
guids.add(StackInfo.getItemStackGUID(stack));
}
}
} catch (Exception e) {
NEIClientConfig.logger.error("Error loading hiddenItems", e);
@@ -597,7 +618,7 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
synchronized (hiddenLock) {
hiddenItems.clear();
hiddenItems.addAll(itemList);
hiddenItems.addAll(guids);
}
}
@@ -606,8 +627,8 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
final NBTTagList list = new NBTTagList();
synchronized (hiddenLock) {
for (ItemStack stack : hiddenItems.values()) {
list.appendTag(stack.writeToNBT(new NBTTagCompound()));
for (String guid : hiddenItems) {
list.appendTag(new NBTTagString(guid));
}
}
@@ -689,20 +710,17 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
}
@Override
public String getRenderLabel() {
public int getRenderLabelColor() {
return NEIClientConfig.subsetWidgetOnTop() ? 0 : ColorUtils.subsetWidget.getColor();
}
@Override
public String getRenderLabel() {
if (NEIClientConfig.subsetWidgetOnTop()) {
return NEIClientUtils.translate("inventory.item_subsets");
} else {
final String translated = NEIClientUtils.translate("gui.button.label.subset");
if (!translated.startsWith("nei.")) { // Optional localization string for resource packs
return translated;
}
return EnumChatFormatting.DARK_PURPLE + String.valueOf(SearchField.searchParser.getRedefinedPrefix(PREFIX))
+ EnumChatFormatting.RESET;
return String.valueOf(SearchField.searchParser.getRedefinedPrefix(PREFIX));
}
}
@Override
@@ -1,5 +1,13 @@
package codechicken.nei;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import net.minecraft.block.Block;
import net.minecraft.block.BlockSnow;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.entity.Entity;
@@ -26,24 +34,23 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
public static int mobOverlay = 0;
private static byte[] mobSpawnCache;
private static long mobOverlayUpdateTime;
private static String oregenPatternName;
public static void reset() {
mobOverlay = 0;
chunkOverlay = 0;
oregenPatternName = null;
}
@Override
public void tickKeyStates() {
if (Minecraft.getMinecraft().currentScreen != null) return;
if (KeyManager.keyStates.get("world.moboverlay").down) {
if (KeyManager.isPressed("world.moboverlay")) {
mobOverlay = (mobOverlay + 1) % 2;
NEIClientUtils
.printChatMessage(new ChatComponentText(NEIClientUtils.translate("chat.moboverlay." + mobOverlay)));
}
if (KeyManager.keyStates.get("world.chunkoverlay").down) {
if (KeyManager.isPressed("world.chunkoverlay")) {
chunkOverlay = (chunkOverlay + 1) % (NEIModContainer.isGT5Loaded() ? 4 : 3);
// 0-2 (or 3 with gt)
NEIClientUtils.printChatMessage(
@@ -53,6 +60,7 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
}
public static void render(float frame) {
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_LINE_BIT);
GL11.glPushMatrix();
Entity entity = Minecraft.getMinecraft().renderViewEntity;
@@ -66,9 +74,12 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
GL11.glTranslated(-interpPosX + intOffsetX, -interpPosY + intOffsetY, -interpPosZ + intOffsetZ);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glDepthFunc(GL11.GL_LEQUAL);
renderChunkBounds(entity, intOffsetX, intOffsetY, intOffsetZ);
renderMobSpawnOverlay(entity, intOffsetX, intOffsetY, intOffsetZ);
GL11.glPopMatrix();
GL11.glPopAttrib();
}
private static void buildMobSpawnOverlay(Entity entity) {
@@ -116,6 +127,15 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
}
}
private static double getOverlayYOffset(World world, int x, int y, int z) {
Block block = world.getBlock(x, y, z);
if (block instanceof BlockSnow) {
int meta = world.getBlockMetadata(x, y, z) & 7;
return (1 + meta) / 8.0 + 0.02;
}
return 0.02;
}
private static void renderMobSpawnOverlay(Entity entity, int intOffsetX, int intOffsetY, int intOffsetZ) {
if (mobOverlay == 0) {
if (mobSpawnCache != null) {
@@ -171,10 +191,12 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
curSpawnMode = spawnMode;
}
tess.addVertex(x, y + 0.02, z);
tess.addVertex(x + 1, y + 0.02, z + 1);
tess.addVertex(x + 1, y + 0.02, z);
tess.addVertex(x, y + 0.02, z + 1);
double yOff = getOverlayYOffset(world, x + intOffsetX, y + intOffsetY, z + intOffsetZ);
tess.addVertex(x, y + yOff, z);
tess.addVertex(x + 1, y + yOff, z + 1);
tess.addVertex(x + 1, y + yOff, z);
tess.addVertex(x, y + yOff, z + 1);
}
}
}
@@ -215,6 +237,9 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
private static void renderChunkBounds(Entity entity, int intOffsetX, int intOffsetY, int intOffsetZ) {
if (chunkOverlay == 0) return;
int worldMinY = worldMinHeight(entity.worldObj);
int worldMaxY = worldMaxHeight(entity.worldObj);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
@@ -233,14 +258,13 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
double dy = 128;
double y1 = Math.floor(entity.posY - dy / 2);
double y2 = y1 + dy;
if (y1 < 0) {
y1 = 0;
y2 = dy;
if (y1 < worldMinY) {
y1 = worldMinY;
y2 = worldMinY + dy;
}
if (y1 > entity.worldObj.getHeight()) {
y2 = entity.worldObj.getHeight();
y1 = y2 - dy;
if (y2 > worldMaxY) {
y2 = worldMaxY;
y1 = Math.max(worldMaxY - dy, worldMinY);
}
y1 -= intOffsetY;
@@ -266,19 +290,34 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
tess.addVertex(x1, y2, z1);
}
if (NEIModContainer.isCCLoaded()) {
tess.setColorRGBA_F(0, 0.5F, 0.9F, (float) dist * 0.5F);
int cubeBase = (int) Math.floor((y1 + intOffsetY) / 16.0) * 16;
for (int cubeY = cubeBase; cubeY <= y2 + intOffsetY; cubeY += 16) {
double ry = cubeY - intOffsetY;
tess.addVertex(x1, ry, z1);
tess.addVertex(x2, ry, z1);
tess.addVertex(x1, ry, z2);
tess.addVertex(x2, ry, z2);
tess.addVertex(x1, ry, z1);
tess.addVertex(x1, ry, z2);
tess.addVertex(x2, ry, z1);
tess.addVertex(x2, ry, z2);
}
}
if (cx == 0 && cz == 0) {
if (chunkOverlay == 2) {
dy = 32;
y1 = Math.floor(entity.posY - dy / 2);
y2 = y1 + dy;
if (y1 < 0) {
y1 = 0;
y2 = dy;
if (y1 < worldMinY) {
y1 = worldMinY;
y2 = worldMinY + dy;
}
if (y1 > entity.worldObj.getHeight()) {
y2 = entity.worldObj.getHeight();
y1 = y2 - dy;
if (y2 > worldMaxY) {
y2 = worldMaxY;
y1 = Math.max(worldMaxY - dy, worldMinY);
}
y1 -= intOffsetY;
@@ -377,20 +416,75 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
GL11.glDisable(GL11.GL_BLEND);
}
private static String getOregenPatternName() {
/** Holder defers class loading until Cubic Chunks is confirmed present. */
private static final class CCWorldBounds {
if (oregenPatternName == null) {
static final MethodHandle GET_MIN_HEIGHT;
static final MethodHandle GET_MAX_HEIGHT;
static {
try {
final ClassLoader loader = WorldOverlayRenderer.class.getClassLoader();
final Class<?> gtWorldGenerator = ReflectionHelper
.getClass(loader, "gregtech.common.GTWorldgenerator", "gregtech.common.GT_Worldgenerator");
oregenPatternName = ((Enum<?>) gtWorldGenerator.getDeclaredField("oregenPattern").get(null)).name();
} catch (Exception ignored) {
oregenPatternName = "AXISSYMMETRICAL";
MethodHandles.Lookup lookup = MethodHandles.lookup();
// Mixined into World by CC, use reflection + MethodHandles to call these
GET_MIN_HEIGHT = lookup.unreflect(World.class.getMethod("getMinHeight"));
GET_MAX_HEIGHT = lookup.unreflect(World.class.getMethod("getMaxHeight"));
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
}
return oregenPatternName;
private static int worldMinHeight(World world) {
if (!NEIModContainer.isCCLoaded()) return 0;
try {
return (int) CCWorldBounds.GET_MIN_HEIGHT.invoke(world);
} catch (Throwable ignored) {
return 0;
}
}
private static int worldMaxHeight(World world) {
if (!NEIModContainer.isCCLoaded()) return world.getHeight();
try {
return (int) CCWorldBounds.GET_MAX_HEIGHT.invoke(world);
} catch (Throwable ignored) {
return world.getHeight();
}
}
private static Callable<String> oregenPatternReader;
private static String getOregenPatternName() {
if (oregenPatternReader == null) {
oregenPatternReader = resolveOregenPatternReader();
}
try {
return oregenPatternReader.call();
} catch (Exception ignored) {
return "AXISSYMMETRICAL";
}
}
private static Callable<String> resolveOregenPatternReader() {
try {
final Class<?> gtWorldGenerator = ReflectionHelper.getClass(
WorldOverlayRenderer.class.getClassLoader(),
"gregtech.common.GTWorldgenerator",
"gregtech.common.GT_Worldgenerator");
try {
// GT5-Unofficial >= 5.09.54.29 support
final Method accessor = gtWorldGenerator.getMethod("getOregenPattern");
return () -> ((Enum<?>) accessor.invoke(null)).name();
} catch (NoSuchMethodException legacy) {
// Older GT
final Field oregenPattern = gtWorldGenerator.getDeclaredField("oregenPattern");
oregenPattern.setAccessible(true);
return () -> ((Enum<?>) oregenPattern.get(null)).name();
}
} catch (Exception ignored) {
return () -> "AXISSYMMETRICAL";
}
}
public static void load() {
+20 -13
View File
@@ -1,9 +1,11 @@
package codechicken.nei.api;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import net.minecraft.block.Block;
import net.minecraft.client.gui.inventory.GuiContainer;
@@ -20,7 +22,6 @@ import codechicken.nei.ItemList;
import codechicken.nei.ItemSorter;
import codechicken.nei.ItemStackSet;
import codechicken.nei.KeyManager;
import codechicken.nei.KeyManager.KeyState;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.OffsetPositioner;
@@ -32,7 +33,6 @@ 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.config.OptionKeyBind;
import codechicken.nei.recipe.CatalystInfo;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipe;
@@ -176,6 +176,21 @@ public class API {
}
}
/**
* Add an alias name that this item can be found by in the search field, in addition to its display name.
*/
public static void setAliases(ItemStack item, String... aliases) {
final List<String> list = Arrays.asList(aliases).stream().filter(Objects::nonNull).map(String::trim)
.filter(s -> !s.isEmpty()).collect(Collectors.toList());
if (list.isEmpty()) {
ItemInfo.itemAliases.remove(item);
} else {
ItemInfo.itemAliases.put(item, list);
}
}
/**
* Adds an item to the item panel. Any items added using this function will override the default search pattern.
*
@@ -206,20 +221,12 @@ public class API {
* @param defaultKey The default value, commonly obtained from {@link Keyboard}
*/
public static void addKeyBind(String ident, int defaultKey) {
NEIClientConfig.setDefaultKeyBinding(ident, defaultKey);
KeyManager.keyStates.put(ident, new KeyState());
addOption(new OptionKeyBind(ident));
KeyManager.registerKeyBinding(ident, defaultKey);
}
/**
* Add a custom KeyBinding to be configured in the Controls menu.
*
* @param ident An identifier for your key, eg "shoot"
* @param defaultKey The default value, commonly obtained from {@link Keyboard}
*/
@Deprecated
public static void addHashBind(String ident, int defaultKey) {
NEIClientConfig.setDefaultKeyBinding(ident, defaultKey);
addOption(new OptionKeyBind(ident, true));
KeyManager.registerKeyBinding(ident, defaultKey);
}
public static void addOption(Option option) {
@@ -8,6 +8,7 @@ import java.util.stream.Collectors;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.PositionedStack;
import codechicken.nei.recipe.GuiOverlayButton.ItemOverlayState;
import codechicken.nei.recipe.IRecipeHandler;
@@ -32,6 +33,10 @@ public interface IOverlayHandler {
return false;
}
default boolean requireShiftForOverlayRecipe() {
return NEIClientConfig.requireShiftForOverlayRecipe();
}
default List<ItemOverlayState> presenceOverlay(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex) {
final List<ItemOverlayState> itemPresenceSlots = new ArrayList<>();
final List<PositionedStack> ingredients = recipe.getIngredientStacks(recipeIndex);
@@ -1,6 +1,7 @@
package codechicken.nei.api;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
@@ -84,6 +85,7 @@ public class ItemInfo {
public static final ArrayListMultimap<Layout, IHighlightHandler> highlightHandlers = ArrayListMultimap.create();
public static final ItemStackMap<String> nameOverrides = new ItemStackMap<>();
public static final ItemStackMap<List<String>> itemAliases = new ItemStackMap<>();
public static final ItemStackSet hiddenItems = new ItemStackSet();
public static final AnyMultiItemFilter hiddenItemsRules = new AnyMultiItemFilter();
public static final ItemStackSet finiteItems = new ItemStackSet();
@@ -109,6 +111,11 @@ public class ItemInfo {
return nameOverrides.get(stack);
}
public static List<String> getAliases(ItemStack stack) {
final List<String> aliases = itemAliases.get(stack);
return aliases != null ? aliases : Collections.emptyList();
}
public static boolean canBeInfinite(ItemStack stack) {
return !finiteItems.contains(stack);
}
@@ -5,6 +5,7 @@ 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 {
@@ -13,7 +14,8 @@ public class NEIInfo {
public static void load(World world) {
OptionCycled modeOption = (OptionCycled) NEIClientConfig.getOptionList().getOption("inventory.cheatmode");
modeOption.parent.synthesizeEnvironment(false);
// kept alive so the WeakReference in Option.slotRef isn't GC'd before copyGlobals/cycle use it
GuiOptionList env = modeOption.parent.synthesizeEnvironment(false);
if (!modeOption.optionValid(modeOption.value())) {
modeOption.copyGlobals();
modeOption.cycle();
@@ -20,14 +20,17 @@ 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;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.SearchField;
import codechicken.nei.bookmark.BookmarkGrid;
import codechicken.nei.bookmark.BookmarkGroup;
import codechicken.nei.bookmark.BookmarkItem;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.BookmarkPayload;
import codechicken.nei.bookmark.BookmarksGridSlot;
import codechicken.nei.recipe.AutoCraftingManager;
import codechicken.nei.recipe.GuiCraftingRecipe;
@@ -74,8 +77,7 @@ public abstract class ShortcutInputHandler {
return false;
}
if (NEIClientConfig.isKeyHashDown("gui.overlay") && stackover == null
&& LayoutManager.overlayRenderer != null) {
if (KeyManager.isKeyDown("gui.overlay") && stackover == null && LayoutManager.overlayRenderer != null) {
LayoutManager.overlayRenderer = null;
return true;
}
@@ -85,16 +87,21 @@ public abstract class ShortcutInputHandler {
if (groupId != -1) {
if (NEIClientConfig.isKeyHashDown("gui.remove_recipe")) {
if (KeyManager.isHashDown("bookmark.remove_recipe", NEIClientUtils.SHIFT_HASH)) {
ItemPanels.bookmarkPanel.removeGroup(groupId);
return true;
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark_pull_items")) {
if (KeyManager.isKeyDown("bookmark.pull_items")) {
return ItemPanels.bookmarkPanel.pullBookmarkItems(groupId, NEIClientUtils.shiftKey());
}
if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft_items")
if (KeyManager.isKeyDown("bookmark.chat_link") && NEIClientUtils.controlKey()) {
NEIClientUtils.sendChatItemLink(BookmarkPayload.of(groupId).toNBT());
return true;
}
if (NEIClientConfig.autocraftingEnabled() && KeyManager.isKeyDown("gui.craft_items")
&& NEIClientUtils.shiftKey()
&& ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)) {
final RecipeChainMath math = ItemPanels.bookmarkPanel.getGrid().createRecipeChainMath(groupId);
@@ -117,46 +124,47 @@ public abstract class ShortcutInputHandler {
stackover = stackover.copy();
if (NEIClientConfig.isKeyHashDown("gui.overlay")) {
if (KeyManager.isKeyDown("gui.overlay")) {
return openOverlayRecipe(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.copy_name")) {
if (KeyManager.isHashDown("copy.name", NEIClientUtils.CTRL_HASH)) {
return copyItemStackName(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.copy_id")) {
if (KeyManager.isHashDown("copy.identifier", NEIClientUtils.CTRL_HASH)) {
return copyItemStackID(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.copy_oredict")) {
if (KeyManager.isHashDown("copy.oredict", NEIClientUtils.CTRL_HASH)) {
return copyItemStackOreDictionary(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.chat_link_item")) {
return sendItemStackChatLink(stackover);
if (KeyManager.isKeyDown("bookmark.chat_link") && NEIClientUtils.controlKey()) {
return sendRecipeInChatLink(stackover, NEIClientUtils.shiftKey());
}
if (NEIClientConfig.isKeyHashDown("gui.recipe")) {
if (KeyManager.isKeyDown("recipe.recipe")) {
return GuiCraftingRecipe.openRecipeGui("item", stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.usage")) {
if (KeyManager.isKeyDown("recipe.usage")) {
return GuiUsageRecipe.openRecipeGui("item", stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.favorite")) {
if (KeyManager.isHashDown("bookmark.favorite", NEIClientUtils.SHIFT_HASH)) {
return saveFavoriteTree(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark")) {
if (KeyManager.isKeyDown("bookmark.add")) {
return saveRecipeInBookmark(stackover, NEIClientUtils.shiftKey(), NEIClientUtils.controlKey());
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark_pull_items")) {
if (KeyManager.isKeyDown("bookmark.pull_items")) {
return pullRecipeItems(stackover, NEIClientUtils.shiftKey());
}
if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft_items")
if (NEIClientConfig.autocraftingEnabled() && KeyManager.isKeyDown("gui.craft_items")
&& NEIClientUtils.shiftKey()) {
return runAutoCrafting(stackover, !NEIClientUtils.controlKey());
}
@@ -196,10 +204,37 @@ public abstract class ShortcutInputHandler {
return true;
}
private static boolean sendItemStackChatLink(ItemStack stackover) {
if (stackover == null) return false;
private static boolean sendRecipeInChatLink(ItemStack stackover, boolean saveIngredients) {
final Point mousePos = GuiDraw.getMousePosition();
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mousePos.x, mousePos.y);
NEIClientUtils.sendChatItemLink(stackover); // I wish clients could just send formatted messages
if (slot != null && saveIngredients && slot.getType() == BookmarkItemType.RESULT) {
NEIClientUtils.sendChatItemLink(BookmarkPayload.of(slot.getBookmarkItem()).toNBT());
return true;
}
final Recipe recipe = getFocusedRecipe(stackover, mousePos.x, mousePos.y, saveIngredients);
if (recipe != null && saveIngredients) {
NEIClientUtils.sendChatItemLink(BookmarkPayload.of(recipe).toNBT());
return true;
}
final RecipeId recipeId;
if (slot != null) {
recipeId = slot.getType() == BookmarkItemType.INGREDIENT ? null : slot.getRecipeId();
} else {
recipeId = recipe != null ? recipe.getRecipeId() : null;
}
final boolean existsRecipe = NEIClientConfig.getBooleanSetting("inventory.bookmarks.bookmarkItemsWithRecipe");
if (ItemPanels.itemPanel.containsWithSubpanels(mousePos.x, mousePos.y)) {
stackover = ItemQuantityField.prepareStackWithQuantity(stackover, 0);
}
NEIClientUtils.sendChatItemLink(BookmarkPayload.of(stackover, existsRecipe ? recipeId : null).toNBT());
return true;
}
@@ -444,15 +479,19 @@ public abstract class ShortcutInputHandler {
if (groupId != -1) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.remove_recipe"),
KeyManager.getKeyName("bookmark.remove_recipe", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.remove_recipe"));
hotkeys.put(
KeyManager.getKeyName("bookmark.chat_link", NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("bookmark.group.chat_link"));
if (BookmarkContainerInfo.getBookmarkContainerHandler(gui) != null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items"),
KeyManager.getKeyName("bookmark.pull_items"),
NEIClientUtils.translate("bookmark.group.pull_items"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("bookmark.pull_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.pull_items_shift"));
}
@@ -462,7 +501,7 @@ public abstract class ShortcutInputHandler {
.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("bookmark.group.craft_missing"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.craft_all"));
}
@@ -483,30 +522,28 @@ public abstract class ShortcutInputHandler {
if (group.crafting != null && group.collapsed) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.remove_recipe"));
} else if (slot.getRecipeId() == null || slot.getType() == BookmarkItemType.ITEM) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate("bookmark.remove_item"));
hotkeys.put(KeyManager.getKeyName("bookmark.add"), NEIClientUtils.translate("bookmark.remove_item"));
} else if (group.crafting != null && group.crafting.recipeRelations.entrySet().stream().anyMatch(
entry -> entry.getKey().equals(slot.getRecipeId())
|| entry.getValue().contains(slot.getRecipeId()))) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
} else {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
if (slot.getType() == BookmarkItemType.INGREDIENT) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
KeyManager.getKeyName("bookmark.add"),
NEIClientUtils.translate("bookmark.remove_item"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
} else {
final BookmarkItem item = slot.getBookmarkItem();
@@ -516,14 +553,14 @@ public abstract class ShortcutInputHandler {
m -> m.type == BookmarkItemType.RESULT && !m.equals(item)
&& item.equalsRecipe(m))) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
KeyManager.getKeyName("bookmark.add"),
NEIClientUtils.translate("bookmark.remove_recipe"));
} else {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
KeyManager.getKeyName("bookmark.add"),
NEIClientUtils.translate("bookmark.remove_item"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
}
@@ -533,60 +570,66 @@ public abstract class ShortcutInputHandler {
if (BookmarkContainerInfo.getBookmarkContainerHandler(gui) != null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items"),
KeyManager.getKeyName("bookmark.pull_items"),
NEIClientUtils.translate("bookmark.group.pull_items"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("bookmark.pull_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.pull_items_shift"));
}
} else {
hotkeys.put(NEIClientConfig.getKeyName("gui.bookmark"), NEIClientUtils.translate("bookmark.add_item"));
hotkeys.put(KeyManager.getKeyName("bookmark.add"), NEIClientUtils.translate("bookmark.add_item"));
if (StackInfo.getAmount(stack) > 0) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.CTRL_HASH),
KeyManager.getKeyName("bookmark.add", NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("bookmark.add_item_with_count"));
}
if (recipeId != null) {
hotkeys.put(
NEIClientConfig
.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("bookmark.add_item_with_recipe_and_count"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.add_item_with_recipe"));
}
if ((ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey)) && FavoriteRecipes.contains(stack)) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.favorite"),
KeyManager.getKeyName("bookmark.favorite", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("recipe.favorite.bookmark_recipe"));
}
}
hotkeys.put(NEIClientConfig.getKeyName("gui.recipe"), NEIClientUtils.translate("itempanel.open_crafting"));
hotkeys.put(NEIClientConfig.getKeyName("gui.usage"), NEIClientUtils.translate("itempanel.open_usage"));
hotkeys.put(KeyManager.getKeyName("recipe.recipe"), NEIClientUtils.translate("itempanel.open_crafting"));
hotkeys.put(KeyManager.getKeyName("recipe.usage"), NEIClientUtils.translate("itempanel.open_usage"));
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_name"), NEIClientUtils.translate("itempanel.copy_name"));
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_oredict"), NEIClientUtils.translate("itempanel.copy_oredict"));
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_id"), NEIClientUtils.translate("itempanel.copy_id"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.chat_link_item"),
NEIClientUtils.translate("itempanel.chat_link_item"));
KeyManager.getKeyName("copy.name", NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("itempanel.copy_name"));
hotkeys.put(
KeyManager.getKeyName("copy.oredict", NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("itempanel.copy_oredict"));
hotkeys.put(
KeyManager.getKeyName("copy.identifier", NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("itempanel.copy_id"));
hotkeys.put(
KeyManager.getKeyName("bookmark.chat_link", NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("bookmark.item.chat_link"));
if (!(gui instanceof GuiRecipe) && NEIClientConfig.canCheatItem(stack)) {
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
KeyManager.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("itempanel.open_crafting"));
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_RMB),
KeyManager.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_RMB),
NEIClientUtils.translate("itempanel.open_usage"));
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.CTRL_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
KeyManager.getKeyName(NEIClientUtils.CTRL_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("itempanel.infinite_item"));
} else {
hotkeys.put(
@@ -604,18 +647,18 @@ public abstract class ShortcutInputHandler {
if (handlerRef.canUseOverlayRenderer(gui)) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.overlay"),
KeyManager.getKeyName("gui.overlay"),
NEIClientUtils.translate("itempanel.overlay_recipe"));
}
if (handlerRef.canFillCraftingGrid(gui)) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.overlay", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("gui.overlay", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("itempanel.fill_crafting_grid"));
if (handlerRef.allowedTransferAlghoritm(gui)) {
hotkeys.put(
NEIClientConfig.getKeyName(
KeyManager.getKeyName(
"gui.overlay",
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("itempanel.fill_crafting_grid_quantity"));
@@ -624,16 +667,19 @@ public abstract class ShortcutInputHandler {
if (NEIClientConfig.autocraftingEnabled()) {
hotkeys.put(
NEIClientConfig.getKeyName(
KeyManager.getKeyName(
"gui.craft_items",
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("itempanel.craft_missing"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("itempanel.craft_all"));
}
}
hotkeys.put(
KeyManager.getKeyName("bookmark.chat_link", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("bookmark.recipe.chat_link"));
}
hotkeysCache.update(mousex, mousey, stack, groupId, hotkeys);
@@ -646,8 +692,10 @@ public abstract class ShortcutInputHandler {
final List<ItemStack> playerInventory = AutoCraftingManager.getInventoryItems(guiContainer).values();
final RecipeId rootRecipeId = math.createMasterRoot();
for (BookmarkItem item : math.recipeIngredients) {
if (item.amount > 0 && rootRecipeId.equals(item.recipeId)) {
for (int i = 0; i < math.recipeIngredients.size(); i++) {
final BookmarkItem item = math.recipeIngredients.get(i);
if (item.getAmount() > 0 && rootRecipeId.equals(item.recipeId)) {
long amount = 0;
for (ItemStack stack : playerInventory) {
@@ -656,8 +704,12 @@ public abstract class ShortcutInputHandler {
}
}
if (amount >= item.amount) {
item.factor = item.amount = amount + item.amount - (amount % item.amount);
if (amount >= item.getAmount()) {
math.recipeIngredients.set(
i,
BookmarkItem.builder(item).multiplier(1)
.factor(amount + item.getAmount() - (amount % item.getAmount()))
.chance(PositionedStack.CHANCE_FULL).build());
}
}
}
@@ -0,0 +1,76 @@
package codechicken.nei.asm;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;
import net.minecraft.client.settings.KeyBinding;
import cpw.mods.fml.relauncher.ReflectionHelper;
public final class KeyBindingFixHooks {
private static volatile boolean initialized;
private static Field keybindArrayField;
private static Field pressedField;
private static Field pressTimeField;
private KeyBindingFixHooks() {}
public static void onTickAll(int keyCode) {
if (keyCode == 0) {
return;
}
for (KeyBinding binding : getBindings()) {
if (binding.getKeyCode() == keyCode) {
try {
pressTimeField.setInt(binding, pressTimeField.getInt(binding) + 1);
} catch (Exception ignored) {}
}
}
}
public static void setKeyBindStateAll(int keyCode, boolean pressed) {
if (keyCode == 0) {
return;
}
for (KeyBinding binding : getBindings()) {
if (binding.getKeyCode() == keyCode) {
try {
pressedField.setBoolean(binding, pressed);
} catch (Exception ignored) {}
}
}
}
@SuppressWarnings("unchecked")
private static List<KeyBinding> getBindings() {
init();
try {
return (List<KeyBinding>) keybindArrayField.get(null);
} catch (Exception ignored) {}
return Collections.emptyList();
}
private static synchronized void init() {
if (initialized) {
return;
}
keybindArrayField = ReflectionHelper.findField(KeyBinding.class, "keybindArray", "field_74516_a");
pressedField = ReflectionHelper.findField(KeyBinding.class, "pressed", "field_74513_e");
pressTimeField = ReflectionHelper.findField(KeyBinding.class, "pressTime", "field_151474_i");
initialized = true;
}
}
@@ -56,7 +56,8 @@ public class NEITransformer implements IClassTransformer {
public NEITransformer() {
if (FMLLaunchHandler.side().isClient()) {
// Generates method to set the placed position of a mob spawner for the item callback. More portable than
// Generates method to set the placed position of a mob spawner for the item
// callback. More portable than
// copying vanilla placement code
transformer.add(
new MethodWriter(
@@ -82,7 +83,6 @@ public class NEITransformer implements IClassTransformer {
asmblocks.get("commaFix"),
true));
// fix workbench container losing items on shift click output without room for the full stack
transformer.add(
new MethodTransformer(
new ObfMapping(
@@ -105,6 +105,33 @@ public class NEITransformer implements IClassTransformer {
asmblocks.get("d_glintAlphaFix"),
asmblocks.get("glintAlphaFix")));
if (FMLLaunchHandler.side().isClient()) {
transformer.add(
new MethodWriter(
ACC_PUBLIC | ACC_STATIC,
new ObfMapping("net/minecraft/client/settings/KeyBinding", "func_74507_a", "(I)V"),
asmblocks.get("m_keyBindingOnTickAll")));
transformer.add(
new MethodWriter(
ACC_PUBLIC | ACC_STATIC,
new ObfMapping("net/minecraft/client/settings/KeyBinding", "func_74510_a", "(IZ)V"),
asmblocks.get("m_keyBindingSetStateAll")));
transformer.add(
new MethodInjector(
new ObfMapping("net/minecraft/client/settings/GameSettings", "func_74303_b", "()V"),
asmblocks.get("saveOptionsHook"),
true));
transformer.add(
new MethodInjector(
new ObfMapping("net/minecraft/client/settings/GameSettings", "func_74303_b", "()V"),
asmblocks.get("n_saveOptionsSendSettings"),
asmblocks.get("saveOptionsRestoreHook"),
false));
}
String GuiContainer = "net/minecraft/client/gui/inventory/GuiContainer";
// add manager field
transformer.add(
@@ -0,0 +1,78 @@
package codechicken.nei.asm;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import codechicken.core.CommonUtils;
import codechicken.nei.KeyManager;
import codechicken.nei.NEIClientConfig;
public final class SaveOptionsFixHooks {
private static final String KEY_PREFIX = "key_nei.options.keys.";
private static List<String> pendingRestoreLines;
private SaveOptionsFixHooks() {}
public static void onBeforeSaveOptions() {
pendingRestoreLines = null;
if (NEIClientConfig.isLoaded()) {
return;
}
final File optionsFile = new File(CommonUtils.getMinecraftDir(), "options.txt");
if (!optionsFile.exists()) {
return;
}
final List<String> missing = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(optionsFile))) {
String line;
while ((line = reader.readLine()) != null) {
if (!line.startsWith(KEY_PREFIX)) continue;
final int colon = line.indexOf(':');
if (colon <= 0) continue;
final String description = line.substring(4, colon);
if (!KeyManager.isRegistered(description)) {
missing.add(line);
}
}
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to read key bindings before options save", e);
return;
}
if (!missing.isEmpty()) {
pendingRestoreLines = missing;
}
}
public static void onAfterSaveOptions() {
final List<String> restore = pendingRestoreLines;
pendingRestoreLines = null;
if (restore == null) {
return;
}
final File optionsFile = new File(CommonUtils.getMinecraftDir(), "options.txt");
try (FileWriter writer = new FileWriter(optionsFile, true)) {
for (String line : restore) {
writer.write(line);
writer.write(System.lineSeparator());
}
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to restore NEI key bindings after options save", e);
}
}
}
@@ -24,7 +24,7 @@ import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.ItemPanels;
import codechicken.nei.ItemStackAmount;
import codechicken.nei.ItemStackSet;
import codechicken.nei.ItemsGrid;
import codechicken.nei.ItemsGrid.MouseContext;
import codechicken.nei.LayoutManager;
@@ -33,6 +33,7 @@ import codechicken.nei.NEIClientUtils;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.Recipe.RecipeIngredient;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.recipe.chain.RecipeChainMath;
@@ -139,17 +140,16 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
if (group.collapsedRecipes.contains(collapsedRecipeId)) {
for (BookmarkItem item : this.bookmarkItems) {
if (item.groupId == groupId && collapsedRecipeId.equals(item.recipeId)
&& item.amount == item.factor) {
item.amount = 0;
if (item.groupId == groupId && collapsedRecipeId.equals(item.recipeId) && item.multiplier == 1) {
item.multiplier = 0;
}
}
} else {
for (BookmarkItem item : this.bookmarkItems) {
if (item.groupId == groupId && collapsedRecipeId.equals(item.recipeId) && item.amount == 0) {
item.amount = item.factor;
if (item.groupId == groupId && collapsedRecipeId.equals(item.recipeId) && item.multiplier == 0) {
item.multiplier = 1;
}
}
@@ -627,15 +627,17 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
for (int itemIndex = 0; itemIndex < this.bookmarkItems.size(); itemIndex++) {
final BookmarkItem item = this.bookmarkItems.get(itemIndex);
if (item.groupId == groupId && (recipeRelations == null || recipeRelations.contains(item.recipeId))) {
long amount = item.amount;
if (recipeId != null && group.crafting != null
&& group.crafting.calculatedItems.containsKey(itemIndex)
&& recipeId.equals(item.recipeId)) {
amount = group.crafting.calculatedItems.get(itemIndex).getCalculatedAmount();
chainItems.add(
item.copyWithMultiplier(
group.crafting.calculatedItems.get(itemIndex).getCalculatedMultiplier()));
} else {
chainItems.add(item.copy());
}
chainItems.add(item.copyWithAmount(amount));
}
}
@@ -896,34 +898,38 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
}
public void addRecipe(Recipe recipe, int multiplier, int groupId) {
final RecipeId recipeId = recipe.getRecipeId();
final List<ItemStack> results = recipe.getResults().stream().map(res -> res.getItemStack())
.collect(Collectors.toList());
final List<ItemStack> ingredients = recipe.getIngredients().stream().map(ingr -> ingr.getItemStack())
.collect(Collectors.toList());
final ItemStackSet seenResults = new ItemStackSet();
final ItemStackSet seenIngredients = new ItemStackSet();
final List<ItemStack> results = new ArrayList<>();
final List<ItemStack> ingredients = new ArrayList<>();
for (ItemStack stack : ItemStackAmount.of(results).values()) {
long factor = StackInfo.getAmount(stack);
for (RecipeIngredient result : recipe.getResults()) {
ItemStack stack = result.getItemStack();
if (!seenResults.contains(stack)) {
seenResults.add(stack);
results.add(stack);
}
}
for (RecipeIngredient ingr : recipe.getIngredients()) {
ItemStack stack = ingr.getItemStack();
if (!seenIngredients.contains(stack)) {
seenIngredients.add(stack);
ingredients.add(stack);
}
}
for (ItemStack stack : results) {
this.addItem(
BookmarkItem.of(
groupId,
StackInfo.withAmount(stack, factor * multiplier),
factor,
recipeId,
BookmarkItemType.RESULT),
BookmarkItem.builder(groupId, stack, recipe, BookmarkItemType.RESULT).multiplier(multiplier)
.build(),
true);
}
for (ItemStack stack : ItemStackAmount.of(ingredients).values()) {
long factor = StackInfo.getAmount(stack);
for (ItemStack stack : ingredients) {
this.addItem(
BookmarkItem.of(
groupId,
StackInfo.withAmount(stack, factor * multiplier),
factor,
recipeId,
BookmarkItemType.INGREDIENT,
BookmarkItem.generatePermutations(stack, recipe)),
BookmarkItem.builder(groupId, stack, recipe, BookmarkItemType.INGREDIENT).multiplier(multiplier)
.build(),
true);
}
}
@@ -1133,8 +1139,8 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
final Set<Long> sizes = new HashSet<>();
for (BookmarkItem item : this.bookmarkItems) {
if (item.groupId == targetGroupId && item.amount > 0) {
sizes.add(Math.max(item.getStackSize(), item.factor / item.fluidCellAmount));
if (item.groupId == targetGroupId && item.getAmount() > 0) {
sizes.add(Math.max(item.getStackSize(), item.getStackSize(item.getAmount(1))));
items.add(item);
}
}
@@ -1143,14 +1149,16 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
long multiplier = Integer.MAX_VALUE;
for (BookmarkItem item : items) {
long customFactor = (long) Math.ceil(item.amount / (double) gcd);
long customMultiplier = (long) (customFactor > 0 ? Math.ceil(item.amount / (double) customFactor) : 0);
final long amount = item.getAmount();
final long customFactor = (amount + gcd - 1) / gcd;
final long customMultiplier = customFactor > 0 ? ((amount + customFactor - 1) / customFactor) : 0;
multiplier = Math.min(shiftMultiplier(customMultiplier, shift, 1), multiplier);
}
for (BookmarkItem item : items) {
long customFactor = (long) Math.ceil(item.amount / (double) gcd);
item.amount = customFactor * multiplier;
final long amount = item.getAmount();
final long customFactor = (amount + gcd - 1) / gcd;
item.multiplier = item.getMultiplierFromAmount(customFactor * multiplier);
}
} else {
final Map<RecipeId, Long> recipeMultipliers = new HashMap<>();
@@ -1158,7 +1166,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
final List<BookmarkItem> items = new ArrayList<>();
for (BookmarkItem item : this.bookmarkItems) {
if (item.factor > 0
if (!item.emptyFactor()
&& outputRecipes.stream().anyMatch(recipeId -> item.equalsRecipe(recipeId, targetGroupId))) {
final long multiplier = recipeMultipliers.getOrDefault(item.recipeId, (long) Integer.MAX_VALUE);
final boolean recipeInMiddle = group.crafting != null
@@ -1168,7 +1176,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
item.recipeId,
Math.min(
shiftMultiplier(
Math.max(recipeInMiddle ? 1 : 0, item.getMultiplier()),
Math.max(recipeInMiddle ? 1 : 0, item.multiplier),
shift,
recipeInMiddle ? 1 : 0),
multiplier));
@@ -1177,7 +1185,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
}
for (BookmarkItem item : items) {
item.amount = item.factor * recipeMultipliers.getOrDefault(item.recipeId, 0L);
item.multiplier = recipeMultipliers.getOrDefault(item.recipeId, 0L);
}
}
@@ -1197,10 +1205,10 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
long multiplier = Integer.MAX_VALUE;
for (BookmarkItem item : this.bookmarkItems) {
if (item.equalsRecipe(recipeId, targetItem.groupId) && item.factor > 0) {
if (item.equalsRecipe(recipeId, targetItem.groupId) && !item.emptyFactor()) {
multiplier = Math.min(
shiftMultiplier(
Math.max(recipeInMiddle ? 1 : 0, item.getMultiplier()),
Math.max(recipeInMiddle ? 1 : 0, item.multiplier),
shift,
recipeInMiddle ? 1 : 0),
multiplier);
@@ -1208,8 +1216,8 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
}
for (BookmarkItem item : this.bookmarkItems) {
if (item.equalsRecipe(recipeId, targetItem.groupId) && item.factor > 0) {
item.amount = item.factor * multiplier;
if (item.equalsRecipe(recipeId, targetItem.groupId) && !item.emptyFactor()) {
item.multiplier = multiplier;
}
}
@@ -1217,7 +1225,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
for (BookmarkItem item : this.bookmarkItems) {
if (targetItem.equals(item)) {
item.amount = item.factor * shiftMultiplier(item.getMultiplier(), shift, 0);
item.multiplier = shiftMultiplier(item.multiplier, shift, 0);
break;
}
}
@@ -66,10 +66,14 @@ public class BookmarkGridGenerator {
while (itemIndex < size && absoluteSlotIndex != -1) {
final BookmarkItem bookmarkItem = this.grid.getBookmarkItem(itemIndex);
final BookmarkGroup group = this.grid.getGroup(bookmarkItem.groupId);
final boolean isCollapsedRecipeAnchor = group.crafting != null && bookmarkItem.recipeId != null
&& bookmarkItem.type != BookmarkItemType.INGREDIENT
&& group.collapsedRecipes.contains(bookmarkItem.recipeId);
if (group.crafting != null && (!group.crafting.calculatedItems.containsKey(itemIndex)
|| bookmarkItem.recipeId != null && !bookmarkItem.recipeId
.equals(group.crafting.itemToRecipe.getOrDefault(itemIndex, bookmarkItem.recipeId)))) {
if (group.crafting != null && !isCollapsedRecipeAnchor
&& (!group.crafting.calculatedItems.containsKey(itemIndex)
|| bookmarkItem.recipeId != null && !bookmarkItem.recipeId.equals(
group.crafting.itemToRecipe.getOrDefault(itemIndex, bookmarkItem.recipeId)))) {
itemIndex++;
} else if (group.collapsed) {
final List<Integer> results = getGroupResults(bookmarkItem.groupId, itemIndex, size);
@@ -189,13 +193,11 @@ public class BookmarkGridGenerator {
for (int shadowIndex : shadows) {
final boolean isIngredient = shadows.get(0) != shadowIndex
|| group.crafting.calculatedItems.get(shadowIndex).calculatedType == CalculatedType.INGREDIENT;
final BookmarkItem shadowBookmarkItem = BookmarkItem.of(
bookmarkItem.groupId,
bookmarkItem.itemStack,
1,
bookmarkItem.recipeId,
isIngredient ? BookmarkItemType.INGREDIENT : BookmarkItemType.RESULT,
Collections.emptyMap());
final BookmarkItem shadowBookmarkItem = BookmarkItem.builder(bookmarkItem.groupId, bookmarkItem.itemStack)
.multiplier(1).factor(StackInfo.getAmount(bookmarkItem.itemStack)).recipeId(bookmarkItem.recipeId)
.type(isIngredient ? BookmarkItemType.INGREDIENT : BookmarkItemType.RESULT)
.permutations(Collections.emptyMap()).build();
if ((absoluteSlotIndex = nextSlotIndex(
absoluteSlotIndex + 1,
@@ -320,7 +322,7 @@ public class BookmarkGridGenerator {
return group.crafting.calculatedItems.get(itemIndex);
} else {
BookmarkChainItem item = BookmarkChainItem.of(this.grid.getBookmarkItem(itemIndex));
item.setRealAmount(item.getShiftAmount());
item.setRealMultiplier(item.getCalculatedMultiplier());
return item;
}
}
@@ -333,7 +335,7 @@ public class BookmarkGridGenerator {
return new BookmarksGridSlot(
slotIndex,
itemIndex,
chainItem.getRealAmount(),
chainItem.getRealMultiplier(),
0,
0,
chainItem.getItem(),
@@ -343,9 +345,9 @@ public class BookmarkGridGenerator {
return new BookmarksGridSlot(
slotIndex,
itemIndex,
chainItem.getRealAmount(),
chainItem.getRealMultiplier(),
chainItem.getShiftAmount(),
chainItem.getCalculatedAmount(),
chainItem.getCalculatedMultiplier(),
chainItem.getItem(),
chainItem.calculatedType,
group);
@@ -2,6 +2,7 @@ package codechicken.nei.bookmark;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -9,14 +10,160 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fluids.FluidStack;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.Recipe.RecipeIngredient;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
public class BookmarkItem {
public static class Builder {
private static Map<ItemStack, String> fuzzyPermutations = new HashMap<>();
private final int groupId;
private final ItemStack stack;
private long factor;
private long multiplier = -1;
private long chance = PositionedStack.CHANCE_FULL;
private RecipeId recipeId = null;
private Recipe recipe = null;
private BookmarkItemType type = BookmarkItemType.ITEM;
private Map<String, ItemStack> permutations = null;
private Builder(int groupId, ItemStack stack) {
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stack);
this.groupId = groupId;
this.stack = stack;
this.factor = nbTag.hasKey("gtFluidName") ? Math.min(144, nbTag.getInteger("Count")) : 1;
}
public Builder factor(long factor) {
this.factor = factor;
return this;
}
public Builder multiplier(long multiplier) {
this.multiplier = multiplier;
return this;
}
public Builder chance(long chance) {
this.chance = chance;
return this;
}
public Builder recipe(Recipe recipe) {
this.recipe = recipe;
this.recipeId = null;
return this;
}
public Builder recipeId(RecipeId recipeId) {
this.recipeId = recipeId;
this.recipe = null;
return this;
}
public Builder type(BookmarkItemType type) {
this.type = type;
return this;
}
public Builder permutations(Map<String, ItemStack> permutations) {
this.permutations = permutations;
return this;
}
public BookmarkItem build() {
final Map<String, ItemStack> perms;
long multiplier = 0;
if (this.permutations != null) {
perms = this.permutations;
} else if (this.type == BookmarkItemType.INGREDIENT) {
if (this.recipe != null) {
perms = Builder.generatePermutations(this.stack, this.recipe);
} else if (this.recipeId != null) {
perms = Builder.generatePermutations(this.stack, Recipe.of(this.recipeId));
} else {
perms = Builder.generatePermutations(this.stack);
}
} else {
perms = Builder.generatePermutations(this.stack);
}
if (this.multiplier >= 0) {
multiplier = this.multiplier;
} else if (this.factor > 0) {
multiplier = StackInfo.getAmount(this.stack) / this.factor;
}
return new BookmarkItem(
this.groupId,
multiplier,
this.factor,
this.chance,
this.stack,
perms,
this.recipeId != null ? this.recipeId : this.recipe != null ? this.recipe.getRecipeId() : null,
this.type);
}
public static Map<String, ItemStack> generatePermutations(ItemStack stack) {
return Collections.singletonMap(getItemGUID(stack), stack);
}
public static Map<String, ItemStack> generatePermutations(ItemStack stack, Recipe recipe) {
if (recipe != null) {
final RecipeIngredient ingr = recipe.getIngredients().stream()
.filter(ingredient -> ingredient.contains(stack)).findAny().orElse(null);
if (ingr != null) {
final Map<String, ItemStack> permutations = new HashMap<>();
for (ItemStack ingrStack : ingr.getPermutations()) {
permutations.put(getItemGUID(ingrStack), ingrStack);
}
return permutations;
}
}
return generatePermutations(stack);
}
private static synchronized String getItemGUID(ItemStack stack) {
final FluidStack fluidStack = StackInfo.getFluid(stack);
if (fluidStack != null) {
return fluidStack.getFluid().getName() + ":" + fluidStack.tag;
} else {
for (Map.Entry<ItemStack, String> entry : Builder.fuzzyPermutations.entrySet()) {
if (NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, entry.getKey())) {
Builder.fuzzyPermutations.put(stack, entry.getValue());
return entry.getValue();
}
}
final String stackGUID = StackInfo.getItemStackGUID(stack);
Builder.fuzzyPermutations.put(stack, stackGUID);
return stackGUID;
}
}
}
public enum BookmarkItemType {
INGREDIENT,
@@ -32,150 +179,167 @@ public class BookmarkItem {
}
}
private static Map<ItemStack, String> fuzzyPermutations = new HashMap<>();
public int groupId;
public long amount = 0L;
public final int fluidCellAmount;
public ItemStack itemStack;
public Map<String, ItemStack> permutations;
public long factor;
public RecipeId recipeId;
public BookmarkItemType type = BookmarkItemType.ITEM;
protected BookmarkItem(int groupId, long amount, int fluidCellAmount, ItemStack itemStack,
Map<String, ItemStack> permutations, long factor, RecipeId recipeId, BookmarkItemType type) {
public long multiplier = 1L;
public final long factor;
public final int fluidCellAmount;
public final long chance;
protected BookmarkItem(int groupId, long multiplier, long factor, long chance, ItemStack itemStack,
Map<String, ItemStack> permutations, RecipeId recipeId, BookmarkItemType type) {
final FluidStack fluidStack = StackInfo.getFluid(itemStack);
if (fluidStack != null) {
this.fluidCellAmount = Math.max(1, StackInfo.isFluidContainer(itemStack) ? fluidStack.amount : 1);
} else {
this.fluidCellAmount = 1;
}
this.groupId = groupId;
this.amount = amount;
this.fluidCellAmount = fluidCellAmount;
this.itemStack = itemStack;
this.permutations = permutations;
this.factor = factor;
this.recipeId = recipeId;
this.type = type == null ? BookmarkItemType.ITEM : type;
this.multiplier = multiplier;
this.factor = factor;
this.chance = chance;
}
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, BookmarkItemType type,
Map<String, ItemStack> permutations) {
final FluidStack fluidStack = StackInfo.getFluid(stack);
int fluidCellAmount = 1;
long amount;
public static Builder builder(int groupId, ItemStack stack) {
return new Builder(groupId, stack);
}
if (fluidStack != null) {
amount = fluidStack.amount * (long) Math.max(0, stack.stackSize);
fluidCellAmount = Math.max(1, StackInfo.isFluidContainer(stack) ? fluidStack.amount : 1);
} else {
amount = StackInfo.getAmount(stack);
public static Builder builder(BookmarkItem item) {
return new Builder(item.groupId, item.itemStack).factor(item.factor).multiplier(item.multiplier)
.chance(item.chance).recipeId(item.recipeId).type(item.type).permutations(item.permutations);
}
public static Builder builder(int groupId, ItemStack stack, Recipe recipe, BookmarkItemType type) {
final List<RecipeIngredient> items = type == BookmarkItemType.RESULT ? recipe.getResults()
: recipe.getIngredients();
final Builder builder = builder(groupId, stack).type(type).recipe(recipe);
long amount = 0;
for (RecipeIngredient res : items) {
if (res.contains(stack)) {
amount += 1L * res.getAmount() * res.getChance();
}
}
return new BookmarkItem(
groupId,
amount,
fluidCellAmount,
stack,
permutations,
factor * fluidCellAmount,
recipeId,
type);
}
if ((amount % PositionedStack.CHANCE_FULL) == 0) {
builder.factor(amount / PositionedStack.CHANCE_FULL);
} else {
builder.factor(1).chance(amount);
}
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, BookmarkItemType type) {
return of(
groupId,
stack,
factor,
recipeId,
type,
generatePermutations(stack, recipeId, type == BookmarkItemType.INGREDIENT));
return builder;
}
public static BookmarkItem of(int groupId, ItemStack stack) {
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stack);
final long factor = nbTag.hasKey("gtFluidName") ? Math.min(144, nbTag.getInteger("Count")) : 1;
return BookmarkItem.of(
groupId,
stack,
factor,
null,
BookmarkItemType.ITEM,
Collections.singletonMap(getItemGUID(stack), stack));
return builder(groupId, stack).build();
}
public BookmarkItem copyWithAmount(long amount) {
public static BookmarkItem of(JsonObject jsonObject) {
final NBTTagCompound itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject.get("item"));
final ItemStack itemStack = StackInfo.loadFromNBT(itemStackNBT);
if (itemStack != null) {
final int groupId = jsonObject.has("groupId") ? jsonObject.get("groupId").getAsInt()
: BookmarkGrid.DEFAULT_GROUP_ID;
final BookmarkItem.Builder builder = BookmarkItem.builder(groupId, itemStack);
if (jsonObject.has("type")) {
builder.type(BookmarkItemType.fromInt(jsonObject.get("type").getAsInt()));
} else if (jsonObject.has("ingredient") && jsonObject.get("ingredient").getAsBoolean()) {
builder.type(BookmarkItemType.INGREDIENT);
} else {
builder.type(BookmarkItemType.RESULT);
}
if (jsonObject.has("multiplier")) {
builder.multiplier(jsonObject.get("multiplier").getAsInt());
}
if (jsonObject.has("factor")) {
builder.factor(jsonObject.get("factor").getAsInt());
}
if (jsonObject.has("chance")) {
builder.chance(jsonObject.get("chance").getAsInt());
}
if (jsonObject.get("recipeId") instanceof JsonObject recipeJson) {
builder.recipeId(RecipeId.of(recipeJson));
}
return builder.build();
}
return null;
}
public BookmarkItem copyWithMultiplier(long multiplier) {
return new BookmarkItem(
this.groupId,
amount,
this.fluidCellAmount,
multiplier,
this.factor,
this.chance,
this.itemStack,
this.permutations,
this.factor,
this.recipeId,
this.type);
}
public BookmarkItem copyWithAmount(long amount) {
return copyWithMultiplier(getMultiplierFromAmount(amount));
}
public BookmarkItem copy() {
return copyWithAmount(this.amount);
}
public static Map<String, ItemStack> generatePermutations(ItemStack stack, RecipeId recipeId,
boolean isIngredient) {
if (isIngredient && recipeId != null) {
return generatePermutations(stack, Recipe.of(recipeId));
}
return Collections.singletonMap(getItemGUID(stack), stack);
}
public static Map<String, ItemStack> generatePermutations(ItemStack stack, Recipe recipe) {
if (recipe != null) {
final RecipeIngredient ingr = recipe.getIngredients().stream()
.filter(ingredient -> ingredient.contains(stack)).findAny().orElse(null);
if (ingr != null) {
final Map<String, ItemStack> permutations = new HashMap<>();
for (ItemStack ingrStack : ingr.getPermutations()) {
permutations.put(getItemGUID(ingrStack), ingrStack);
}
return permutations;
}
}
return Collections.singletonMap(getItemGUID(stack), stack);
}
private static synchronized String getItemGUID(ItemStack stack) {
final FluidStack fluidStack = StackInfo.getFluid(stack);
if (fluidStack != null) {
return fluidStack.getFluid().getName() + ":" + fluidStack.tag;
} else {
for (Map.Entry<ItemStack, String> entry : BookmarkItem.fuzzyPermutations.entrySet()) {
if (NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, entry.getKey())) {
BookmarkItem.fuzzyPermutations.put(stack, entry.getValue());
return entry.getValue();
}
}
final String stackGUID = StackInfo.getItemStackGUID(stack);
BookmarkItem.fuzzyPermutations.put(stack, stackGUID);
return stackGUID;
}
return copyWithMultiplier(this.multiplier);
}
public boolean containsItems(BookmarkItem item) {
return this.permutations.keySet().stream().anyMatch(item.permutations::containsKey);
}
public long getAmount() {
return getAmount(this.multiplier);
}
public long getAmount(long multiplier) {
long amount = this.factor * multiplier;
if (this.fluidCellAmount > 1) {
amount = amount * this.fluidCellAmount;
}
if (this.chance != PositionedStack.CHANCE_FULL) {
if (this.type == BookmarkItemType.INGREDIENT) {
// For ingredients, round up the expected amount to be conservative.
amount = (amount * this.chance + PositionedStack.CHANCE_FULL - 1) / PositionedStack.CHANCE_FULL;
} else {
// For results, round down the expected amount to be conservative.
amount = (amount * this.chance) / PositionedStack.CHANCE_FULL;
}
}
return amount;
}
public ItemStack getItemStack() {
return getItemStack(this.amount);
return getItemStack(getAmount());
}
public ItemStack getItemStack(long amount) {
@@ -183,23 +347,34 @@ public class BookmarkItem {
}
public long getStackSize() {
return getStackSize(this.amount);
return getStackSize(getAmount());
}
public long getStackSize(long amount) {
return (long) (this.factor > 0 ? Math.ceil(amount / (double) this.fluidCellAmount) : 0);
if (this.fluidCellAmount > 1) {
amount = (amount + this.fluidCellAmount - 1) / this.fluidCellAmount;
}
return amount;
}
public long getMultiplierFromAmount(long amount) {
if (this.factor <= 0 || this.chance <= 0) return 0;
if (this.fluidCellAmount > 1) {
amount = (amount + this.fluidCellAmount - 1) / this.fluidCellAmount;
}
if (this.chance == PositionedStack.CHANCE_FULL) {
return (amount + this.factor - 1) / this.factor;
}
return (amount * PositionedStack.CHANCE_FULL + this.factor * this.chance - 1) / (this.factor * this.chance);
}
public long getMultiplier() {
return getMultiplier(this.amount);
}
public long getMultiplier(long amount) {
return (long) (this.factor > 0 ? Math.ceil(amount / (double) this.factor) : 0);
}
public long getFactor() {
return this.factor / this.fluidCellAmount;
return this.multiplier;
}
public boolean equalsRecipe(BookmarkItem meta) {
@@ -210,6 +385,10 @@ public class BookmarkItem {
return groupId == this.groupId && recipeId != null && recipeId.equals(this.recipeId);
}
public boolean emptyFactor() {
return this.factor <= 0 || this.chance <= 0;
}
@Override
public int hashCode() {
return Objects.hash(this.groupId, this.fluidCellAmount, this.type.toInt(), this.recipeId);
@@ -228,4 +407,27 @@ public class BookmarkItem {
return false;
}
public JsonObject toJsonObject() {
final JsonObject jsonObject = new JsonObject();
jsonObject.add("item", NBTJson.toJsonObject(StackInfo.itemStackToNBT(getItemStack())));
jsonObject.add("multiplier", new JsonPrimitive(this.multiplier));
jsonObject.add("factor", new JsonPrimitive(this.factor));
jsonObject.add("type", new JsonPrimitive(this.type.toInt()));
if (this.groupId != BookmarkGrid.DEFAULT_GROUP_ID) {
jsonObject.add("groupId", new JsonPrimitive(this.groupId));
}
if (this.recipeId != null) {
jsonObject.add("recipeId", this.recipeId.toJsonObject());
}
if (this.chance != PositionedStack.CHANCE_FULL) {
jsonObject.add("chance", new JsonPrimitive(this.chance));
}
return jsonObject;
}
}
@@ -0,0 +1,283 @@
package codechicken.nei.bookmark;
import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import com.google.gson.JsonObject;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.ItemPanels;
import codechicken.nei.ItemQuantityField;
import codechicken.nei.ItemStackSet;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.Recipe.RecipeIngredient;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
public class BookmarkPayload {
private String linkType;
private NBTTagCompound target;
private NBTTagCompound group;
private NBTTagList items = new NBTTagList();
private NBTTagList recipes = new NBTTagList();
private BookmarkPayload(String linkType, ItemStack stack) {
this.linkType = linkType;
this.target = stack != null ? StackInfo.itemStackToNBT(stack) : null;
}
public static BookmarkPayload of(NBTTagCompound nbt) {
final BookmarkPayload payload = new BookmarkPayload(nbt.getString("linkType"), null);
if (nbt.hasKey("item")) {
payload.target = nbt.getCompoundTag("item");
}
if (nbt.hasKey("group")) {
payload.group = nbt.getCompoundTag("group");
}
payload.items = nbt.getTagList("items", 10);
payload.recipes = nbt.getTagList("recipes", 10);
return payload;
}
public static BookmarkPayload of(BookmarkItem item) {
final BookmarkPayload payload = new BookmarkPayload("recipe", item.getItemStack());
final BookmarkGrid grid = ItemPanels.bookmarkPanel.getGrid();
final Map<RecipeId, Integer> recipesIndexes = new HashMap<>();
final RecipeId recipeId = item.recipeId;
final int groupId = item.groupId;
payload.items = new NBTTagList();
payload.recipes = new NBTTagList();
if (recipeId != null) {
for (int itemIndex = 0; itemIndex < grid.size(); itemIndex++) {
final BookmarkItem currentItem = grid.getBookmarkItem(itemIndex);
if (currentItem != null && currentItem.groupId == groupId && recipeId.equals(currentItem.recipeId)) {
addBookmarkItemToPayload(payload, currentItem, recipesIndexes);
}
}
} else {
addBookmarkItemToPayload(payload, item, recipesIndexes);
}
return payload;
}
public static BookmarkPayload of(Recipe recipe) {
final BookmarkPayload payload = new BookmarkPayload("recipe", recipe.getResult());
final Map<RecipeId, Integer> recipesIndexes = new HashMap<>();
final ItemStackSet seenIngredients = new ItemStackSet();
final ItemStackSet seenResults = new ItemStackSet();
for (RecipeIngredient result : recipe.getResults()) {
ItemStack stack = result.getItemStack();
if (!seenResults.contains(stack)) {
final BookmarkItem item = BookmarkItem.builder(-1, stack, recipe, BookmarkItemType.RESULT).build();
addBookmarkItemToPayload(payload, item, recipesIndexes);
seenResults.add(stack);
}
}
for (RecipeIngredient ingr : recipe.getIngredients()) {
ItemStack stack = ingr.getItemStack();
if (!seenIngredients.contains(stack)) {
final BookmarkItem item = BookmarkItem.builder(-1, stack, recipe, BookmarkItemType.INGREDIENT).build();
addBookmarkItemToPayload(payload, item, recipesIndexes);
seenIngredients.add(stack);
}
}
return payload;
}
public static BookmarkPayload of(int groupId) {
final BookmarkPayload payload = new BookmarkPayload("group", null);
final Map<RecipeId, Integer> recipesIndexes = new HashMap<>();
final BookmarkGrid grid = ItemPanels.bookmarkPanel.getGrid();
for (int itemIndex = 0; itemIndex < grid.size(); itemIndex++) {
final BookmarkItem item = grid.getBookmarkItem(itemIndex);
if (item != null && item.groupId == groupId) {
addBookmarkItemToPayload(payload, item, recipesIndexes);
}
}
payload.group = generateGroup(grid.getGroup(groupId));
return payload;
}
public static BookmarkPayload of(ItemStack stackover, RecipeId recipeId) {
final BookmarkPayload payload = new BookmarkPayload("item", stackover);
final Map<RecipeId, Integer> recipesIndexes = new HashMap<>();
final Point mousePos = GuiDraw.getMousePosition();
if (ItemPanels.itemPanel.containsWithSubpanels(mousePos.x, mousePos.y)) {
stackover = ItemQuantityField.prepareStackWithQuantity(stackover, 0);
}
final BookmarkItem item = BookmarkItem.builder(-1, stackover).recipeId(recipeId).type(BookmarkItemType.ITEM)
.build();
addBookmarkItemToPayload(payload, item, recipesIndexes);
return payload;
}
private static NBTTagCompound generateGroup(BookmarkGroup group) {
final NBTTagCompound groupTag = new NBTTagCompound();
final NBTTagList collapsedRecipes = new NBTTagList();
groupTag.setString("viewmode", group.viewMode.toString());
groupTag.setBoolean("crafting", group.crafting != null);
groupTag.setBoolean("collapsed", group.collapsed);
for (RecipeId recipeId : group.collapsedRecipes) {
collapsedRecipes.appendTag(NBTJson.toNbt(recipeId.toJsonObject()));
}
groupTag.setTag("collapsedRecipes", collapsedRecipes);
return groupTag;
}
private static void addBookmarkItemToPayload(BookmarkPayload payload, BookmarkItem item,
Map<RecipeId, Integer> recipesIndexes) {
final JsonObject itemTag = item.toJsonObject();
itemTag.remove("groupId");
if (item.recipeId != null) {
final int recipeIndex = recipesIndexes
.computeIfAbsent(item.recipeId, recipeId -> addRecipeToPayload(payload, recipeId, recipesIndexes));
itemTag.addProperty("recipeId", recipeIndex);
}
payload.items.appendTag(NBTJson.toNbt(itemTag));
}
private static int addRecipeToPayload(BookmarkPayload payload, RecipeId recipeId,
Map<RecipeId, Integer> recipesIndexes) {
final NBTTagCompound recipeTag = new NBTTagCompound();
final int recipeIndex = payload.recipes.tagCount();
recipeTag.setTag("recipeId", NBTJson.toNbt(recipeId.toJsonObject()));
recipeTag.setInteger("recipeIndex", recipeIndex);
payload.recipes.appendTag(recipeTag);
return recipeIndex;
}
public NBTTagCompound toNBT() {
final NBTTagCompound payloadTag = new NBTTagCompound();
payloadTag.setString("linkType", linkType);
if (target != null) {
payloadTag.setTag("item", target);
}
if (group != null) {
payloadTag.setTag("group", group);
}
payloadTag.setTag("items", items);
payloadTag.setTag("recipes", recipes);
return payloadTag;
}
public String getLinkType() {
return this.linkType;
}
public ItemStack getTargetStack() {
return this.target != null ? StackInfo.loadFromNBT(this.target) : null;
}
public BookmarkGroup getGroup() {
if (this.group == null) {
return null;
}
final boolean crafting = this.group.hasKey("crafting") && this.group.getBoolean("crafting");
final BookmarkViewMode viewMode;
if (this.group.hasKey("viewmode")) {
viewMode = BookmarkViewMode.valueOf(this.group.getString("viewmode"));
} else {
viewMode = BookmarkViewMode.TODO_LIST;
}
final BookmarkGroup group = new BookmarkGroup(viewMode, crafting);
if (this.group.hasKey("collapsed")) {
group.collapsed = this.group.getBoolean("collapsed");
}
if (this.group.hasKey("collapsedRecipes")) {
final NBTTagList collapsedRecipes = this.group.getTagList("collapsedRecipes", 10);
for (int i = 0; i < collapsedRecipes.tagCount(); i++) {
final NBTTagCompound recipeTag = collapsedRecipes.getCompoundTagAt(i);
final RecipeId recipeId = RecipeId.of((JsonObject) NBTJson.toJsonObject(recipeTag));
group.collapsedRecipes.add(recipeId);
}
}
return group;
}
public List<BookmarkItem> getBookmarkItems(int groupId) {
final List<BookmarkItem> bookmarkItems = new ArrayList<>();
final Map<Integer, RecipeId> recipesMap = new HashMap<>();
for (int i = 0; i < recipes.tagCount(); i++) {
final NBTTagCompound recipeTag = recipes.getCompoundTagAt(i);
final RecipeId recipeId = RecipeId
.of((JsonObject) NBTJson.toJsonObject(recipeTag.getCompoundTag("recipeId")));
recipesMap.put(recipeTag.getInteger("recipeIndex"), recipeId);
}
for (int i = 0; i < items.tagCount(); i++) {
final NBTTagCompound itemTag = items.getCompoundTagAt(i);
RecipeId recipeId = null;
if (itemTag.hasKey("recipeId")) {
recipeId = recipesMap.get(itemTag.getInteger("recipeId"));
itemTag.removeTag("recipeId");
}
final BookmarkItem item = BookmarkItem.of((JsonObject) NBTJson.toJsonObject(itemTag));
if (item != null) {
item.groupId = groupId;
item.recipeId = recipeId;
bookmarkItems.add(item);
}
}
return bookmarkItems;
}
}
@@ -10,7 +10,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import org.apache.commons.io.IOUtils;
@@ -25,9 +24,7 @@ import com.google.gson.JsonSyntaxException;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
public class BookmarkStorage {
@@ -198,7 +195,11 @@ public class BookmarkStorage {
continue;
}
if (!addItemToGrid(grid, parser.parse(itemStr).getAsJsonObject())) {
final BookmarkItem item = BookmarkItem.of(parser.parse(itemStr).getAsJsonObject());
if (item != null) {
grid.addItem(item, false);
} else {
wasError = true;
NEIClientConfig.logger.warn(
"Failed to load bookmarked ItemStack from json string, the item no longer exists:\n{}",
@@ -237,47 +238,6 @@ public class BookmarkStorage {
this.bookmarkFile = bookmarkFile;
}
private boolean addItemToGrid(BookmarkGrid grid, JsonObject jsonObject) {
NBTTagCompound itemStackNBT;
if (jsonObject.get("item") != null) {
itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject.get("item"));
} else { // old format
itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject);
}
ItemStack itemStack = StackInfo.loadFromNBT(itemStackNBT);
if (itemStack != null) {
RecipeId recipeId = null;
boolean isFluid = itemStackNBT.hasKey("gtFluidName");
int groupId = jsonObject.has("groupId") ? jsonObject.get("groupId").getAsInt()
: BookmarkGrid.DEFAULT_GROUP_ID;
int factor = jsonObject.has("factor") ? Math.abs(jsonObject.get("factor").getAsInt()) : (isFluid ? 144 : 1);
BookmarkItemType type = jsonObject.has("type") ? BookmarkItemType.fromInt(jsonObject.get("type").getAsInt())
: null;
if (type == null) {
// old format
type = jsonObject.has("ingredient") && jsonObject.get("ingredient").getAsBoolean()
? BookmarkItemType.INGREDIENT
: BookmarkItemType.RESULT;
}
if (jsonObject.get("recipeId") instanceof JsonObject recipeJson) {
recipeId = RecipeId.of(recipeJson);
}
if (!grid.groups.containsKey(groupId)) {
groupId = BookmarkGrid.DEFAULT_GROUP_ID;
}
grid.addItem(BookmarkItem.of(groupId, itemStack, factor, recipeId, type), false);
}
return itemStack != null;
}
public void save() {
if (this.bookmarkFile == null) {
@@ -318,21 +278,7 @@ public class BookmarkStorage {
for (BookmarkItem item : grid.bookmarkItems) {
try {
JsonObject row = new JsonObject();
row.add("item", NBTJson.toJsonObject(StackInfo.itemStackToNBT(item.getItemStack())));
row.add("factor", new JsonPrimitive(item.getFactor()));
row.add("type", new JsonPrimitive(item.type.toInt()));
if (item.groupId != BookmarkGrid.DEFAULT_GROUP_ID) {
row.add("groupId", new JsonPrimitive(item.groupId));
}
if (item.recipeId != null) {
row.add("recipeId", item.recipeId.toJsonObject());
}
strings.add(NBTJson.toJson(row));
strings.add(NBTJson.toJson(item.toJsonObject()));
} catch (JsonSyntaxException e) {
NEIClientConfig.logger.error("Failed to stringify bookmarked ItemStack to json string");
}
@@ -14,6 +14,7 @@ import codechicken.nei.ItemsGrid.MouseContext;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIClientUtils.Alignment;
import codechicken.nei.PositionedStack;
import codechicken.nei.bookmark.BookmarkGrid.BookmarkMouseContext;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.RecipeChainDetails.CalculatedType;
@@ -63,18 +64,18 @@ public class BookmarksGridSlot extends ItemsGridSlot {
protected final boolean isFirstOutput;
protected final int rowIndex;
public BookmarksGridSlot(int slotIndex, int itemIndex, long realAmount, long shiftAmount, long calculatedAmount,
BookmarkItem bookmarkItem, CalculatedType calculatedType, BookmarkGroup group) {
public BookmarksGridSlot(int slotIndex, int itemIndex, long realMultiplier, long shiftAmount,
long calculatedMultiplier, BookmarkItem bookmarkItem, CalculatedType calculatedType, BookmarkGroup group) {
super(
slotIndex,
itemIndex,
calculatedType != null ? bookmarkItem.getItemStack(calculatedAmount)
: bookmarkItem.getItemStack(realAmount));
calculatedType != null ? bookmarkItem.getItemStack(bookmarkItem.getAmount(calculatedMultiplier))
: bookmarkItem.getItemStack(bookmarkItem.getAmount(realMultiplier)));
this.emptyItemStack = bookmarkItem.getItemStack(0);
this.realAmount = realAmount;
this.realAmount = bookmarkItem.getAmount(realMultiplier);
this.shiftAmount = shiftAmount;
this.calculatedAmount = calculatedAmount;
this.calculatedAmount = calculatedType != null ? bookmarkItem.getAmount(calculatedMultiplier) : this.realAmount;
this.group = group;
this.calculatedType = calculatedType;
@@ -83,8 +84,8 @@ public class BookmarksGridSlot extends ItemsGridSlot {
this.isOutputRecipe = group.crafting != null && group.crafting.outputRecipes.contains(bookmarkItem.recipeId);
this.isFluidDisplay = StackInfo.itemStackToNBT(bookmarkItem.itemStack).hasKey("gtFluidName");
this.realMultiplier = bookmarkItem.getMultiplier(realAmount);
this.calculatedMultiplier = bookmarkItem.getMultiplier(calculatedAmount);
this.realMultiplier = realMultiplier;
this.calculatedMultiplier = calculatedMultiplier;
if (this.group.crafting != null && this.group.crafting.calculatedItems.containsKey(this.itemIndex)) {
this.realType = this.group.crafting.calculatedItems.get(this.itemIndex).calculatedType
@@ -192,7 +193,7 @@ public class BookmarksGridSlot extends ItemsGridSlot {
protected HandlerInfo getHandlerInfo() {
if (this.bookmarkItem.recipeId != null && this.handlerInfo == null) {
this.handlerInfo = GuiRecipeTab.getHandlerInfo(this.bookmarkItem.recipeId.getHandleName(), null);
this.handlerInfo = GuiRecipeTab.getHandlerInfo(this.bookmarkItem.recipeId.getHandlerName(), null);
}
return this.handlerInfo;
}
@@ -347,17 +348,22 @@ public class BookmarksGridSlot extends ItemsGridSlot {
}
protected void drawStackSize(Rectangle4i rect, ShownItemType shownItemType) {
boolean drawChance = this.calculatedMultiplier > 0;
long amount = this.calculatedAmount;
if (shownItemType == null || shownItemType == ShownItemType.REAL || this.calculatedType == null) {
amount = this.realAmount;
drawChance = this.realMultiplier > 0;
} else if (shownItemType == ShownItemType.SHIFT) {
amount = this.shiftAmount;
drawChance = false;
}
if (amount > 0 || shownItemType == ShownItemType.REAL && this.bookmarkItem.factor > 0) {
if (amount > 0 || this.bookmarkItem.chance != PositionedStack.CHANCE_FULL && drawChance
|| shownItemType == ShownItemType.REAL && !this.bookmarkItem.emptyFactor()) {
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
final long stackSize = this.bookmarkItem.getStackSize(amount);
int color = 0xFFFFFF;
String amountString = "";
if (stackSize < 10_000) {
@@ -370,11 +376,16 @@ public class BookmarksGridSlot extends ItemsGridSlot {
amountString += "L";
}
if (this.bookmarkItem.chance != PositionedStack.CHANCE_FULL) {
amountString = "~" + amountString;
color = 0xFFAA00;
}
NEIClientUtils.drawNEIOverlayText(
amountString,
new Rectangle4i(rect.x + 1, rect.y + 1, rect.w - 2, rect.h - 2),
panelFactor,
0xFFFFFF,
color,
true,
this.isFluidDisplay ? Alignment.BottomLeft : Alignment.BottomRight);
}
@@ -42,34 +42,35 @@ public class RecipeChainDetails {
private final BookmarkItem item;
private long realAmount = 0L;
private long realMultiplier = 0L;
private long shiftAmount = 0L;
private long calculatedAmount = 0L;
private long calculatedMultiplier = 0L;
public CalculatedType calculatedType;
protected BookmarkChainItem(BookmarkItem item, long shiftItem, long calculatedItem,
protected BookmarkChainItem(BookmarkItem item, long shiftItem, long calculatedMultiplier,
CalculatedType calculatedType) {
this.item = item.copy();
this.shiftAmount = shiftItem;
this.calculatedAmount = calculatedItem;
this.calculatedMultiplier = calculatedMultiplier;
this.calculatedType = calculatedType;
}
public static BookmarkChainItem of(BookmarkItem item, long shiftItem, long calculatedAmount,
public static BookmarkChainItem of(BookmarkItem item, long shiftItem, long calculatedMultiplier,
CalculatedType calculatedType) {
return new BookmarkChainItem(item, shiftItem, calculatedAmount, calculatedType);
return new BookmarkChainItem(item, shiftItem, calculatedMultiplier, calculatedType);
}
public static BookmarkChainItem of(BookmarkItem item, long shiftItem, CalculatedType calculatedType) {
return new BookmarkChainItem(item, shiftItem, item.amount, calculatedType);
return new BookmarkChainItem(item, shiftItem, item.getMultiplier(), calculatedType);
}
public static BookmarkChainItem of(BookmarkItem item) {
final long amount = item.getAmount();
return new BookmarkChainItem(
item,
item.amount,
item.amount,
amount,
item.getMultiplier(),
item.type == BookmarkItemType.INGREDIENT ? CalculatedType.INGREDIENT : CalculatedType.RESULT);
}
@@ -77,30 +78,34 @@ public class RecipeChainDetails {
return this.item.getItemStack(amount);
}
public void setRealAmount(long amount) {
this.realAmount = amount;
public void setRealMultiplier(long multiplier) {
this.realMultiplier = multiplier;
}
public long getRealAmount() {
return this.realAmount;
public long getRealMultiplier() {
return this.realMultiplier;
}
public void setCalculatedMultiplier(long multiplier) {
this.calculatedMultiplier = multiplier;
}
public long getCalculatedMultiplier() {
return this.calculatedMultiplier;
}
public long getShiftAmount() {
return this.shiftAmount;
}
public long getCalculatedAmount() {
return this.calculatedAmount;
}
public BookmarkItem getItem() {
return this.item;
}
public void append(long amount, long calculatedAmount) {
this.shiftAmount += amount;
this.calculatedAmount += calculatedAmount;
this.item.amount = this.calculatedAmount;
this.calculatedMultiplier += this.item.getMultiplierFromAmount(calculatedAmount);
this.item.multiplier = this.calculatedMultiplier;
}
}
@@ -180,10 +185,9 @@ public class RecipeChainDetails {
if (itemIndex >= 0 && this.calculatedItems.containsKey(itemIndex)) {
final BookmarkItem item = entry.getValue();
if (this.recipeInMiddle.contains(item.recipeId)) {
this.calculatedItems.get(itemIndex)
.setRealAmount(Math.max(0, item.factor * (item.getMultiplier() - 1)));
this.calculatedItems.get(itemIndex).setRealMultiplier(Math.max(0, item.getMultiplier() - 1));
} else {
this.calculatedItems.get(itemIndex).setRealAmount(item.amount);
this.calculatedItems.get(itemIndex).setRealMultiplier(item.getMultiplier());
}
}
}
@@ -239,7 +243,7 @@ public class RecipeChainDetails {
for (BookmarkItem item : chainItems) {
if (recipeRelations.contains(item.recipeId)) {
subChainItems.add(item.copyWithAmount(recipeId.equals(item.recipeId) ? item.amount : 0));
subChainItems.add(item.copyWithMultiplier(recipeId.equals(item.recipeId) ? item.multiplier : 0));
}
}
@@ -258,7 +262,8 @@ public class RecipeChainDetails {
}
if (this.calculatedItems.containsKey(itemIndex)) {
this.calculatedItems.get(itemIndex).setRealAmount(value.getShiftAmount());
this.calculatedItems.get(itemIndex)
.setRealMultiplier(value.getItem().getMultiplierFromAmount(value.getShiftAmount()));
}
}
@@ -272,18 +277,19 @@ public class RecipeChainDetails {
for (RecipeId relRecipeId : recipeRelations) {
for (BookmarkItem item : math.recipeResults) {
if (item.recipeId.equals(relRecipeId)) {
final long amount = item.amount - math.requiredAmount.getOrDefault(item, 0L);
final long amount = item.getAmount() - math.requiredAmount.getOrDefault(item, 0L);
if (item.recipeId.equals(recipeId)) {
multiplier.put(item.recipeId, item.getMultiplier());
items.computeIfAbsent(
StackInfo.getItemStackGUID(item.itemStack),
is -> BookmarkChainItem.of(item, 0, 0, CalculatedType.RESULT))
.append(amount, item.amount);
.append(amount, item.getAmount());
} else if (amount > 0) {
items.computeIfAbsent(
StackInfo.getItemStackGUID(item.itemStack),
is -> BookmarkChainItem.of(item, 0, 0, CalculatedType.RESULT)).append(amount, amount);
is -> BookmarkChainItem.of(item, 0, 0, CalculatedType.RESULT))
.append(amount, item.getAmount());
}
}
}
@@ -292,17 +298,17 @@ public class RecipeChainDetails {
if (item.recipeId.equals(relRecipeId)) {
final BookmarkItem prefItem = math.preferredItems.get(item);
final long amount = math.requiredAmount.containsKey(prefItem) ? 0
: math.requiredAmount.getOrDefault(item, item.amount);
: math.requiredAmount.getOrDefault(item, item.getAmount());
final long refAmount = prefItem != null && !topLevelRecipes.contains(prefItem.recipeId)
? math.requiredAmount.getOrDefault(prefItem, 0L)
: 0;
if (amount != 0 || item.amount > refAmount && math.requiredAmount.containsKey(prefItem)
if (amount != 0 || item.getAmount() > refAmount && math.requiredAmount.containsKey(prefItem)
|| recipeId.equals(item.recipeId) && multiplier.get(recipeId) == 0) {
items.computeIfAbsent(
StackInfo.getItemStackGUID(item.itemStack),
is -> BookmarkChainItem.of(item, 0, 0, CalculatedType.INGREDIENT))
.append(amount, item.amount - refAmount);
.append(amount, item.getAmount() - refAmount);
}
}
}
@@ -312,7 +318,7 @@ public class RecipeChainDetails {
}
private void generateResult(RecipeChainMath math, BookmarkItem item, int itemIndex) {
final long amount = item.amount - math.requiredAmount.getOrDefault(item, 0L);
final long amount = item.getAmount() - math.requiredAmount.getOrDefault(item, 0L);
final CalculatedType calculatedType = math.outputRecipes.containsKey(item.recipeId) ? CalculatedType.RESULT
: CalculatedType.REMAINDER;
@@ -322,7 +328,7 @@ public class RecipeChainDetails {
private void generateIngredient(RecipeChainMath math, BookmarkItem item, int itemIndex) {
final BookmarkItem prefItem = math.preferredItems.get(item);
final long amount = math.requiredAmount.containsKey(prefItem) ? 0
: math.requiredAmount.getOrDefault(item, item.amount);
: math.requiredAmount.getOrDefault(item, item.getAmount());
this.calculatedItems.put(itemIndex, BookmarkChainItem.of(item, amount, CalculatedType.INGREDIENT));
}
@@ -1,18 +1,39 @@
package codechicken.nei.commands;
import java.util.Arrays;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommandSender;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTException;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.ChatComponentTranslation;
import codechicken.nei.ItemPanels;
import codechicken.nei.LRUCache;
import codechicken.nei.bookmark.BookmarkGrid;
import codechicken.nei.bookmark.BookmarkGroup;
import codechicken.nei.bookmark.BookmarkPayload;
public class CommandBookmarkAdd extends CommandBase {
private static final LRUCache<String, NBTTagCompound> PAYLOAD_CACHE = new LRUCache<>(64);
public static void cachePayload(String payloadId, NBTTagCompound payload) {
if (payloadId == null || payloadId.isEmpty() || payload == null) {
return;
}
synchronized (PAYLOAD_CACHE) {
PAYLOAD_CACHE.put(payloadId, (NBTTagCompound) payload.copy());
}
}
private static NBTTagCompound getCachedPayload(String payloadId) {
synchronized (PAYLOAD_CACHE) {
return PAYLOAD_CACHE.get(payloadId);
}
}
@Override
public String getCommandName() {
return "nei_bookmark";
@@ -20,7 +41,7 @@ public class CommandBookmarkAdd extends CommandBase {
@Override
public String getCommandUsage(ICommandSender sender) {
return "/nei_bookmark <nbt>";
return "/nei_bookmark <payloadId>";
}
@Override
@@ -30,19 +51,37 @@ public class CommandBookmarkAdd extends CommandBase {
@Override
public void processCommand(ICommandSender sender, String[] args) {
if (args.length < 1 || args[0].length() < 3) {
sender.addChatMessage(new ChatComponentText("§c/nei_bookmark <nbt>"));
if (args.length < 1) {
sender.addChatMessage(new ChatComponentText("§c/nei_bookmark <payloadId>"));
return;
}
try {
ItemPanels.bookmarkPanel.addItem(
ItemStack.loadItemStackFromNBT((NBTTagCompound) JsonToNBT.func_150315_a(String.join(" ", args))));
final String payloadId = String.join(" ", Arrays.copyOfRange(args, 0, args.length));
final NBTTagCompound payload = getCachedPayload(payloadId);
if (payload == null) {
throw new IllegalArgumentException("Missing cached payload");
}
addBookmarkFromPayload((NBTTagCompound) payload.copy());
sender.addChatMessage(new ChatComponentTranslation("nei.chat.bookmark_added.text"));
} catch (NBTException e) {
} catch (Exception e) {
sender.addChatMessage(new ChatComponentText(e.toString()));
}
}
private static void addBookmarkFromPayload(NBTTagCompound nbt) {
final BookmarkPayload payload = BookmarkPayload.of(nbt);
final BookmarkGrid grid = ItemPanels.bookmarkPanel.getGrid();
final BookmarkGroup group = payload.getGroup();
int groupId = BookmarkGrid.DEFAULT_GROUP_ID;
if (group != null) {
groupId = grid.addGroup(group);
}
payload.getBookmarkItems(groupId).forEach(item -> grid.addItem(item, true));
}
}
@@ -8,13 +8,15 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import net.minecraft.command.CommandBase;
@@ -39,6 +41,7 @@ import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.ICraftingHandler;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.RecipeHandlerQuery;
import codechicken.nei.recipe.TemplateRecipeHandler;
import codechicken.nei.util.NBTJson;
public class CommandRecipeId extends CommandBase {
@@ -125,12 +128,16 @@ public class CommandRecipeId extends CommandBase {
private ArrayList<ICraftingHandler> craftinghandlers = new ArrayList<>();
private ArrayList<ICraftingHandler> serialCraftingHandlers = new ArrayList<>();
protected final ICommandSender sender;
protected final File currFile;
protected final boolean fastDump;
public ProcessDumpThread(ICommandSender sender, File currFile) {
public ProcessDumpThread(ICommandSender sender, File currFile, boolean fastDump) {
this.sender = sender;
this.currFile = currFile;
this.fastDump = fastDump;
ClientHandler.loadSettingsFile("recipeidblacklist.cfg", lines -> {
final Set<String> names = lines.collect(Collectors.toSet());
@@ -150,38 +157,10 @@ public class CommandRecipeId extends CommandBase {
sendChatInfoMessage(sender, "nei.chat.recipeid.dump.start");
try (BufferedWriter writer = Files.newBufferedWriter(currFile.toPath(), StandardCharsets.UTF_8)) {
int total = ItemList.items.size();
int count = 0;
for (ItemStack stack : ItemList.items) {
if (count % 1000 == 0) {
NEIClientConfig.logger.info(
"({}/{}). Processing {} crafting recipes...",
count,
total,
stack.getDisplayName());
}
count++;
for (ICraftingHandler handler : getCraftingHandlers(stack)) {
for (int index = 0, num = handler.numRecipes(); index < num; index++) {
try {
final Recipe recipe = Recipe.of(handler, index);
if (!recipe.getIngredients().isEmpty() && !recipe.getResults().isEmpty()) {
writer.write(NBTJson.toJson(recipe.getRecipeId().toJsonObject()));
writer.newLine();
}
} catch (Exception ex) {
NEIClientConfig.logger.error(
"Found Broken RecipeId {}:{}",
GuiRecipeTab.getHandlerInfo(handler).getHandlerName(),
stack,
ex);
}
}
}
if (fastDump) {
processFastDump(writer);
} else {
processDump(writer);
}
} catch (Exception e) {
@@ -192,15 +171,118 @@ public class CommandRecipeId extends CommandBase {
sendChatInfoMessage(sender, "nei.chat.recipeid.dump.finish");
}
/**
* + technically more reliable and supports some weird handlers
* <p>
* - very very very slow, took 1 hour to get a dump in GTNH on M1 in background
* <p>
* - generates a lot of duplicates, up to 75% of file size is duplicates (and it's 300mb out of 400mb...)
*/
private void processDump(BufferedWriter writer) throws IOException {
final int total = ItemList.items.size();
int count = 0;
for (ItemStack stack : ItemList.items) {
if (count % 1000 == 0) {
NEIClientConfig.logger
.info("({}/{}). Processing {} crafting recipes...", count, total, stack.getDisplayName());
}
count++;
for (ICraftingHandler handler : getCraftingHandlers(stack)) {
writeLines(writer, collectRecipeLines(handler, stack.toString()));
}
}
}
/**
* - may skip some handlers if they're not TemplateRecipeHandler / just weird ones (like gendustry handlers)
* <p>
* + but in terms of GT recipes everything is dumped, and surprisingly it catches even more GT recipes than the
* regular dumper (in particular, it has a lot of new hammer, extruder, blast furnace, etc. recipes)
* <p>
* + way faster, took like 2.5 minutes
* <p>
* + doesn't have nearly as many duplicates, but something can still slip in, for example from
* FuelRecipeHandler. The dump has a size of only 100 MB instead of 400 MB from the regular dumper
*/
private void processFastDump(BufferedWriter writer) throws IOException {
final ArrayList<ICraftingHandler> handlers = getCraftingHandlers();
final int total = handlers.size();
final AtomicInteger count = new AtomicInteger();
try {
final List<List<String>> linesByHandler = ItemList.forkJoinPool.submit(() -> {
return handlers.parallelStream().map(handler -> {
final String handlerName = GuiRecipeTab.getHandlerInfo(handler).getHandlerName();
final List<String> lines = collectRecipeLines(handler, handlerName);
final int current = count.incrementAndGet();
NEIClientConfig.logger
.info("({}/{}). Processed {} handler recipes.", current, total, handlerName);
return lines;
}).collect(Collectors.toList());
}).get();
for (List<String> lines : linesByHandler) {
writeLines(writer, lines);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException("Interrupted while dumping RecipeId", e);
} catch (ExecutionException e) {
throw new IOException("Error while dumping RecipeId", e);
}
}
private List<String> collectRecipeLines(ICraftingHandler handler, String context) {
final List<String> lines = new ArrayList<>(handler.numRecipes());
for (int index = 0, num = handler.numRecipes(); index < num; index++) {
try {
final Recipe recipe = Recipe.of(handler, index);
if (!recipe.getIngredients().isEmpty() && !recipe.getResults().isEmpty()) {
lines.add(NBTJson.toJson(recipe.getRecipeId().toJsonObject()));
}
} catch (Exception ex) {
NEIClientConfig.logger.error(
"Found Broken RecipeId {}:{}",
GuiRecipeTab.getHandlerInfo(handler).getHandlerName(),
context,
ex);
}
}
return lines;
}
private void writeLines(BufferedWriter writer, List<String> lines) throws IOException {
for (String line : lines) {
writer.write(line);
writer.newLine();
}
}
private ArrayList<ICraftingHandler> getCraftingHandlers(Object... results) {
return new RecipeHandlerQuery<>(
h -> h.getRecipeHandler("item", results),
handler -> handler.getRecipeHandler("item", results),
this.craftinghandlers,
this.serialCraftingHandlers,
"Error while looking up crafting recipe",
"outputId: item",
"results: " + Arrays.toString(results))
.runWithProfiling(NEIClientUtils.translate("recipe.concurrent.crafting"));
"outputId: item").runWithProfiling(NEIClientUtils.translate("recipe.concurrent.crafting"));
}
private ArrayList<ICraftingHandler> getCraftingHandlers() {
return new RecipeHandlerQuery<>(handler -> {
if (handler instanceof TemplateRecipeHandler templateHandler) {
return templateHandler.getAllRecipeHandler();
}
return handler.getRecipeHandler("all");
},
this.craftinghandlers,
this.serialCraftingHandlers,
"Error while looking up crafting recipe",
"outputId: all").runWithProfiling(NEIClientUtils.translate("recipe.concurrent.crafting"));
}
}
@@ -212,7 +294,7 @@ public class CommandRecipeId extends CommandBase {
@Override
public String getCommandUsage(ICommandSender sender) {
return "/recipeid dump <filename> OR /recipeid diff <prev-filename> <curr-filename> [subset name]";
return "/recipeid [dump|fast-dump] <filename> OR /recipeid diff <prev-filename> <curr-filename> <subset name>";
}
@Override
@@ -220,12 +302,27 @@ public class CommandRecipeId extends CommandBase {
return 0;
}
@Override
public List<String> addTabCompletionOptions(ICommandSender sender, String[] args) {
if (args.length == 1) {
return getListOfStringsMatchingLastWord(args, "dump", "fast-dump", "diff");
}
if ("diff".equals(args[0]) && (args.length == 2 || args.length == 3)) {
return getListOfStringsMatchingLastWord(args, getRecipeIdFilenames());
}
return Collections.emptyList();
}
@Override
public void processCommand(ICommandSender sender, String[] args) {
final String command = args.length == 0 ? null : args[0];
if ("dump".equals(command)) {
processDumpCommand(sender, args);
processDumpCommand(sender, args, false);
} else if ("fast-dump".equals(command)) {
processDumpCommand(sender, args, true);
} else if ("diff".equals(command)) {
processDiffCommand(sender, args);
} else {
@@ -263,7 +360,7 @@ public class CommandRecipeId extends CommandBase {
(new ProcessDiffThread(sender, prevFilename, currFilename, diffFilename)).start();
}
protected void processDumpCommand(ICommandSender sender, String[] args) {
protected void processDumpCommand(ICommandSender sender, String[] args, boolean fastDump) {
if (args.length > 2) {
sendChatErrorMessage(sender, "nei.chat.recipeid.many_params", getCommandUsage(sender));
@@ -274,13 +371,30 @@ public class CommandRecipeId extends CommandBase {
final String currFilename = args.length == 2 ? args[1] : "recipeId";
if (!dir.exists()) dir.mkdirs();
(new ProcessDumpThread(sender, getFile(currFilename))).start();
(new ProcessDumpThread(sender, getFile(currFilename), fastDump)).start();
}
private static File getFile(String filename) {
return new File(CommonUtils.getMinecraftDir(), "recipeid/" + filename + ".json");
}
private static String[] getRecipeIdFilenames() {
final File dir = new File(CommonUtils.getMinecraftDir(), "recipeid");
final File[] files = dir.listFiles((currentDir, name) -> name.endsWith(".json"));
if (files == null || files.length == 0) {
return new String[] {};
}
final String[] names = new String[files.length];
for (int i = 0; i < files.length; i++) {
final String name = files[i].getName();
names[i] = name.substring(0, name.length() - ".json".length());
}
return names;
}
private static void sendChatInfoMessage(ICommandSender sender, String translationKey, Object... args) {
sender.addChatMessage(
new ChatComponentTranslation(translationKey, args)
@@ -92,8 +92,8 @@ public abstract class DataDumper extends Option {
}
public Rectangle4i dumpButtonSize() {
int width = 80;
return new Rectangle4i(slot.slotWidth() - width, 0, width, 20);
int width = 50;
return new Rectangle4i(getSlot().slotWidth() - width, 0, width, 20);
}
public Rectangle4i modeButtonSize() {
@@ -18,6 +18,7 @@ import org.lwjgl.input.Keyboard;
import codechicken.core.gui.GuiCCButton;
import codechicken.core.gui.GuiScreenWidget;
import codechicken.lib.config.ConfigTag;
import codechicken.lib.math.MathHelper;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.HUDRenderer;
@@ -27,12 +28,16 @@ public class GuiHighlightTips extends GuiScreenWidget {
private final String name;
private GuiCCButton toggleButton;
private final Option opt;
private final GuiOptionList parentGui;
private final boolean world;
private Point dragDown;
public GuiHighlightTips(Option opt) {
super(80, 20);
this.opt = opt;
name = opt.name;
this.parentGui = (GuiOptionList) Minecraft.getMinecraft().currentScreen;
this.world = parentGui.worldConfig();
}
@Override
@@ -48,7 +53,7 @@ public class GuiHighlightTips extends GuiScreenWidget {
@Override
public void actionPerformed(String ident, Object... params) {
if (ident.equals("show")) {
opt.getTag(name).setBooleanValue(!show());
getTag(name).setBooleanValue(!show());
updateNames();
}
}
@@ -58,13 +63,21 @@ public class GuiHighlightTips extends GuiScreenWidget {
}
private boolean show() {
return opt.renderTag(name).getBooleanValue();
return renderTag(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);
}
@Override
public void keyTyped(char c, int keycode) {
if (keycode == Keyboard.KEY_ESCAPE || keycode == Keyboard.KEY_BACK) {
Minecraft.getMinecraft().displayGuiScreen(opt.slot.getGui());
Minecraft.getMinecraft().displayGuiScreen(parentGui);
return;
}
super.keyTyped(c, keycode);
@@ -82,7 +95,7 @@ public class GuiHighlightTips extends GuiScreenWidget {
}
public Point getPos() {
return new Point(opt.renderTag(name + ".x").getIntValue(), opt.renderTag(name + ".y").getIntValue());
return new Point(renderTag(name + ".x").getIntValue(), renderTag(name + ".y").getIntValue());
}
public Dimension sampleSize() // copied from HUDManager when running with the sample for this gui
@@ -148,8 +161,8 @@ public class GuiHighlightTips extends GuiScreenWidget {
}
private void setPos(Point p) {
opt.getTag(name).setBooleanValue(show()); // duplicates global tag for the option gui if in world mode
opt.getTag(name + ".x").setIntValue(p.x);
opt.getTag(name + ".y").setIntValue(p.y);
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);
}
}
@@ -43,6 +43,7 @@ public class GuiItemIconDumper extends GuiScreen {
}
private Option opt;
private final GuiOptionList parentGui;
private int drawIndex;
private int parseIndex;
private final File dir = new File(CommonUtils.getMinecraftDir(), "dumps/itempanel_icons");
@@ -52,6 +53,7 @@ public class GuiItemIconDumper extends GuiScreen {
public GuiItemIconDumper(Option opt, int iconSize) {
this.opt = opt;
this.parentGui = (GuiOptionList) Minecraft.getMinecraft().currentScreen;
this.iconSize = iconSize;
borderSize = iconSize / 16;
boxSize = iconSize + borderSize * 2;
@@ -62,7 +64,7 @@ public class GuiItemIconDumper extends GuiScreen {
}
private void returnScreen(IChatComponent msg) {
Minecraft.getMinecraft().displayGuiScreen(opt.slot.getGui());
Minecraft.getMinecraft().displayGuiScreen(parentGui);
NEIClientUtils.printChatMessage(msg);
}
@@ -7,11 +7,14 @@ import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import org.lwjgl.opengl.GL11;
import codechicken.lib.config.ConfigTag;
import codechicken.lib.math.MathHelper;
import codechicken.nei.ItemList;
import codechicken.nei.ItemSorter;
import codechicken.nei.ItemSorter.SortEntry;
import codechicken.nei.LayoutManager;
@@ -48,6 +51,8 @@ public class GuiItemSorter extends GuiOptionPane {
public final Option opt;
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;
@@ -56,7 +61,9 @@ public class GuiItemSorter extends GuiOptionPane {
public GuiItemSorter(Option opt) {
this.opt = opt;
list = ItemSorter.fromSaveString(opt.renderTag().getValue());
this.parentGui = (GuiOptionList) Minecraft.getMinecraft().currentScreen;
this.world = parentGui.worldConfig();
list = ItemSorter.fromSaveString(renderTag(opt.configName()).getValue());
for (SortEntry e : list) slots.add(new SortItem(e));
}
@@ -98,7 +105,7 @@ public class GuiItemSorter extends GuiOptionPane {
@Override
public GuiScreen getParentScreen() {
return opt.slot.getGui();
return parentGui;
}
@Override
@@ -114,16 +121,25 @@ public class GuiItemSorter extends GuiOptionPane {
list.remove(dragged.e);
list.add(nslot, dragged.e);
opt.getTag().setValue(ItemSorter.getSaveString(list));
LayoutManager.markItemsDirty();
getTag(opt.configName()).setValue(ItemSorter.getSaveString(list));
if (opt.activeTag() == opt.getTag()) {
if (opt.activeTag() == getTag(opt.configName())) {
ItemSorter.list = new ArrayList<>(list);
}
ItemList.refreshItems.restart();
}
}
}
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);
}
public SortItem itemAt(int mx, int my) {
if (!pane.windowBounds().contains(mx, my)) return null;
@@ -12,6 +12,7 @@ import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.core.gui.GuiScreenWidget;
import codechicken.lib.config.ConfigTag;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.render.CCRenderState;
import codechicken.lib.vec.Rectangle4i;
@@ -21,7 +22,7 @@ import codechicken.nei.guihook.GuiContainerManager;
public class GuiPanelSettings extends GuiScreenWidget {
private final Option opt;
private final GuiOptionList parentGui;
private PanelPlaceholder bookmarksPanel;
private PanelPlaceholder itemsPanel;
@@ -54,6 +55,7 @@ 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;
@@ -67,9 +69,10 @@ 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) {
public PanelPlaceholder(Option opt, String name, boolean world) {
this.opt = opt;
this.name = name;
this.world = world;
}
public void resize(Rectangle4i margin) {
@@ -116,10 +119,10 @@ public class GuiPanelSettings extends GuiScreenWidget {
final int minWidth = ItemsGrid.SLOT_SIZE;
final int minHeight = ItemsGrid.SLOT_SIZE;
int paddingLeft = (int) Math.ceil(margin.w * opt.renderTag(name + ".left").getIntValue() / 100000.0);
int paddingTop = (int) Math.ceil(margin.h * opt.renderTag(name + ".top").getIntValue() / 100000.0);
int paddingRight = (int) Math.ceil(margin.w * opt.renderTag(name + ".right").getIntValue() / 100000.0);
int paddingBottom = (int) Math.ceil(margin.h * opt.renderTag(name + ".bottom").getIntValue() / 100000.0);
int paddingLeft = (int) Math.ceil(margin.w * getTag(name + ".left").getIntValue() / 100000.0);
int paddingTop = (int) Math.ceil(margin.h * getTag(name + ".top").getIntValue() / 100000.0);
int paddingRight = (int) Math.ceil(margin.w * getTag(name + ".right").getIntValue() / 100000.0);
int paddingBottom = (int) Math.ceil(margin.h * getTag(name + ".bottom").getIntValue() / 100000.0);
if (dragDir != null) {
final Point mouse = GuiDraw.getMousePosition();
@@ -159,6 +162,10 @@ public class GuiPanelSettings extends GuiScreenWidget {
return new int[] { paddingLeft, paddingTop, paddingRight, paddingBottom };
}
private ConfigTag getTag(String s) {
return (world ? opt.worldConfigSet() : opt.globalConfigSet()).config.getTag(s);
}
protected void drawItems() {
final int columns = (w - 2) / ItemsGrid.SLOT_SIZE;
final int rows = (h - (PANEL_SIZE + 2) * 2 - 2) / ItemsGrid.SLOT_SIZE;
@@ -219,10 +226,10 @@ public class GuiPanelSettings extends GuiScreenWidget {
if (button == 0 && dragDown != null) {
int[] padding = getPaddings();
opt.renderTag(name + ".left").setIntValue(padding[0] * 100000 / margin.w);
opt.renderTag(name + ".top").setIntValue(padding[1] * 100000 / margin.h);
opt.renderTag(name + ".right").setIntValue(padding[2] * 100000 / margin.w);
opt.renderTag(name + ".bottom").setIntValue(padding[3] * 100000 / margin.h);
getTag(name + ".left").setIntValue(padding[0] * 100000 / margin.w);
getTag(name + ".top").setIntValue(padding[1] * 100000 / margin.h);
getTag(name + ".right").setIntValue(padding[2] * 100000 / margin.w);
getTag(name + ".bottom").setIntValue(padding[3] * 100000 / margin.h);
dragDir = null;
dragDown = null;
@@ -232,10 +239,11 @@ public class GuiPanelSettings extends GuiScreenWidget {
public GuiPanelSettings(Option opt) {
super(176, 198);
this.opt = opt;
this.parentGui = (GuiOptionList) Minecraft.getMinecraft().currentScreen;
bookmarksPanel = new PanelPlaceholder(opt, opt.name + ".bookmarks");
itemsPanel = new PanelPlaceholder(opt, opt.name + ".items");
boolean world = parentGui.worldConfig();
bookmarksPanel = new PanelPlaceholder(opt, opt.name + ".bookmarks", world);
itemsPanel = new PanelPlaceholder(opt, opt.name + ".items", world);
}
@Override
@@ -247,7 +255,7 @@ public class GuiPanelSettings extends GuiScreenWidget {
public void keyTyped(char c, int keycode) {
if (keycode == Keyboard.KEY_ESCAPE || keycode == Keyboard.KEY_BACK) {
Minecraft.getMinecraft().displayGuiScreen(opt.slot.getGui());
Minecraft.getMinecraft().displayGuiScreen(parentGui);
return;
}
@@ -93,15 +93,18 @@ public class IMCHandler {
final boolean multipleWidgetsAllowed = tag.hasKey("multipleWidgetsAllowed")
? tag.getBoolean("multipleWidgetsAllowed")
: tag.hasKey("maxRecipesPerPage") && tag.getInteger("maxRecipesPerPage") > 1;
info.setHandlerDimensions(handlerWidth, handlerHeight, multipleWidgetsAllowed);
info.setHandlerDimensions(handlerWidth, handlerHeight);
info.setMultipleWidgetsAllowed(multipleWidgetsAllowed);
} catch (NumberFormatException ignored) {
NEIClientConfig.logger.info("Error setting handler dimensions for {}", handler);
}
// true if not set to false
info.setUseCustomScroll(tag.hasKey("useCustomScroll") && tag.getBoolean("useCustomScroll"));
final boolean allowOverflow = tag.hasKey("useCustomScroll") && tag.getBoolean("useCustomScroll");
info.setAllowOverflowX(tag.hasKey("allowOverflowX") ? tag.getBoolean("allowOverflowX") : true);
info.setAllowOverflowY(tag.hasKey("allowOverflowY") ? tag.getBoolean("allowOverflowY") : allowOverflow);
info.setShowFavoritesButton(!tag.hasKey("showFavoritesButton") || tag.getBoolean("showFavoritesButton"));
info.setShowOverlayButton(!tag.hasKey("showOverlayButton") || tag.getBoolean("showOverlayButton"));
info.setShowBadge(tag.hasKey("showBadge") && tag.getBoolean("showBadge"));
GuiRecipeTab.handlerAdderFromIMC.remove(handler);
GuiRecipeTab.handlerAdderFromIMC.put(handler, info);
@@ -5,6 +5,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.item.Item;
@@ -23,7 +24,11 @@ import codechicken.nei.guihook.GuiContainerManager;
public class ItemPanelDumper extends DataDumper {
private static final int[] resolutions = new int[] { 16, 32, 48, 64, 128, 256 };
public static final int CSV = 0;
public static final int NBT = 1;
public static final int JSON = 2;
public static final int PNG = 3;
private static final Minecraft mc = Minecraft.getMinecraft();
public ItemPanelDumper(String name) {
super(name);
@@ -54,19 +59,29 @@ public class ItemPanelDumper extends DataDumper {
public int getRes() {
int i = renderTag(name + ".res").getIntValue(0);
if (i >= resolutions.length || i < 0) renderTag().setIntValue(i = 0);
return resolutions[i];
int size = 16 << i;
if (size >= getSmallerScreenAxisSize() || i < 0) {
getTag(name + ".res").setIntValue(0);
size = 16;
}
return size;
}
private int getSmallerScreenAxisSize() {
int width = mc.displayWidth;
int height = mc.displayHeight;
return Math.min(width, height);
}
public Rectangle4i resButtonSize() {
int width = 50;
int width = 60;
return new Rectangle4i(modeButtonSize().x - width - 6, 0, width, 20);
}
@Override
public void draw(int mousex, int mousey, float frame) {
super.draw(mousex, mousey, frame);
if (getMode() == 3) {
if (getMode() == PNG) {
int res = getRes();
drawButton(mousex, mousey, resButtonSize(), res + "x" + res);
}
@@ -74,23 +89,35 @@ public class ItemPanelDumper extends DataDumper {
@Override
public void mouseClicked(int mousex, int mousey, int button) {
if (getMode() == 3 && resButtonSize().contains(mousex, mousey)) {
if (getMode() != PNG) {
super.mouseClicked(mousex, mousey, button);
return;
}
if (resButtonSize().contains(mousex, mousey)) {
NEIClientUtils.playClickSound();
getTag(name + ".res").setIntValue((renderTag(name + ".res").getIntValue(0) + 1) % resolutions.length);
} else super.mouseClicked(mousex, mousey, button);
int current = renderTag(name + ".res").getIntValue(0);
int next;
// 31 - numberOfLeadingZeros(x) = floor(log2(x))
int max = 31 - Integer.numberOfLeadingZeros(getSmallerScreenAxisSize()) - 3;
if (button == 1) { // Right click to cycle backward
next = (current - 1 + max) % max;
} else { // Left click to cycle forward
next = (current + 1) % max;
}
getTag(name + ".res").setIntValue(next);
} else if (!dumpButtonSize().contains(mousex, mousey) || acknowledgedItemSizeWarning()) {
super.mouseClicked(mousex, mousey, button);
}
}
@Override
public String getFileExtension() {
switch (getMode()) {
case 0:
return ".csv";
case 1:
return ".nbt";
case 2:
return ".json";
}
return null;
return switch (getMode()) {
case CSV -> ".csv";
case NBT -> ".nbt";
case JSON -> ".json";
default -> null;
};
}
@Override
@@ -105,15 +132,29 @@ public class ItemPanelDumper extends DataDumper {
@Override
public void dumpFile() {
if (getMode() == 3) Minecraft.getMinecraft().displayGuiScreen(new GuiItemIconDumper(this, getRes()));
if (getMode() == PNG && acknowledgedItemSizeWarning())
mc.displayGuiScreen(new GuiItemIconDumper(this, getRes()));
else super.dumpFile();
}
private boolean acknowledgedItemSizeWarning() {
return !showItemSizeWarning() || NEIClientUtils.shiftKey();
}
private boolean showItemSizeWarning() {
int res = getRes();
// More than 4 items at 2048x2048, 16 items at 1024x1024, 64 at 512x512, etc.
int WARNING_SIZE = 16_777_216;
return ItemPanels.itemPanel.getItems().size() * res * res > WARNING_SIZE;
}
@Override
public void dumpTo(File file) throws IOException {
if (getMode() == 0) super.dumpTo(file);
else if (getMode() == 1) dumpNBT(file);
else dumpJson(file);
switch (getMode()) {
case CSV -> super.dumpTo(file);
case NBT -> dumpNBT(file);
default -> dumpJson(file);
}
}
public void dumpNBT(File file) throws IOException {
@@ -141,4 +182,22 @@ public class ItemPanelDumper extends DataDumper {
public int modeCount() {
return 4;
}
@Override
public List<String> handleTooltip(int mousex, int mousey, List<String> currenttip) {
if (getMode() == PNG && dumpButtonSize().contains(mousex, mousey) && showItemSizeWarning()) {
int res = getRes();
currenttip.add(
NEIClientUtils.translate(
"options.tools.dump.itempanel.icon.warning.1",
ItemPanels.itemPanel.getItems().size(),
res,
res));
currenttip.add(
NEIClientUtils.translate(
"options.tools.dump.itempanel.icon.warning.2",
NEIClientUtils.translate("key.shift")));
}
return currenttip;
}
}
@@ -1,5 +1,6 @@
package codechicken.nei.config;
import java.lang.ref.WeakReference;
import java.util.List;
import net.minecraft.client.Minecraft;
@@ -17,7 +18,11 @@ public abstract class Option {
.playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F));
}
public OptionScrollSlot slot;
private WeakReference<OptionScrollSlot> slotRef;
public OptionScrollSlot getSlot() {
return slotRef != null ? slotRef.get() : null;
}
public String namespace = null;
public final String name;
@@ -134,7 +139,7 @@ public abstract class Option {
* @return true if the gui is in world config mode
*/
public boolean worldConfig() {
return slot.getGui().worldConfig();
return getSlot().getGui().worldConfig();
}
/**
@@ -189,7 +194,7 @@ public abstract class Option {
}
public void onAdded(OptionScrollSlot slot) {
this.slot = slot;
this.slotRef = new WeakReference<>(slot);
}
public void onAdded(OptionList list) {
@@ -57,10 +57,10 @@ public abstract class OptionButton extends Option {
}
public Rectangle buttonSize() {
if (getPrefix() == null) return new Rectangle(0, 0, slot.slotWidth(), 20);
if (getPrefix() == null) return new Rectangle(0, 0, getSlot().slotWidth(), 20);
int width = Math.max(60, getStringWidth(getButtonText()) + 8);
return new Rectangle(slot.slotWidth() - width, 0, width, 20);
return new Rectangle(getSlot().slotWidth() - width, 0, width, 20);
}
public String getPrefix() {
@@ -1,137 +0,0 @@
package codechicken.nei.config;
import static codechicken.lib.gui.GuiDraw.drawRect;
import static codechicken.lib.gui.GuiDraw.drawStringC;
import java.awt.Rectangle;
import org.lwjgl.input.Keyboard;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.util.NEIKeyboardUtils;
public class OptionKeyBind extends OptionButton {
private boolean editing = false;
private boolean useHash = false;
private int keyboard = Keyboard.CHAR_NONE;
public OptionKeyBind(String name) {
this(name, false);
}
public OptionKeyBind(final String name, final boolean useHash) {
super("keys." + name);
this.useHash = useHash;
}
@Override
public void onMouseClicked(int mousex, int mousey, int button) {
if (editing) {
resetChanges();
}
}
@Override
public void keyTyped(char c, int keycode) {
if (!editing) {
return;
}
if (keycode == Keyboard.KEY_RETURN) {
applyChanges();
return;
}
keyboard = useHash ? NEIClientUtils.getKeyHash() : keycode;
if (keyboard != Keyboard.CHAR_NONE) {
applyChanges();
}
}
@Override
public boolean onClick(int btn) {
if (editing) {
return true;
} else if (btn == 0) {
editing = true;
return true;
} else if (btn == 1) {
keyboard = Keyboard.CHAR_NONE;
applyChanges();
return true;
}
return false;
}
protected void applyChanges() {
setValue(keyboard);
resetChanges();
}
protected void resetChanges() {
editing = false;
keyboard = Keyboard.CHAR_NONE;
}
public boolean conflicted() {
final int keyboard = getValue();
if (keyboard <= 0) {
return false;
}
for (Option o : slot.options) {
if (o instanceof OptionKeyBind && o != this && ((OptionKeyBind) o).getValue() == keyboard) {
return true;
}
}
return false;
}
public void setValue(int keycode) {
getTag().setIntValue(keycode);
}
public int getValue() {
return renderTag().getIntValue();
}
@Override
public String getPrefix() {
return translateN(name);
}
@Override
public void drawButton(int mx, int my) {
if (editing) {
Rectangle b = buttonSize();
drawRect(b.x, b.y, b.width, b.height, -6250336);
drawRect(b.x + 1, b.y + 1, b.width - 2, b.height - 2, -16777216);
drawStringC(getButtonText(), b.x, b.y, b.width, b.height, getTextColour(mx, my));
} else {
super.drawButton(mx, my);
}
}
@Override
public String getButtonText() {
if (editing) {
return NEIKeyboardUtils.getHashName(NEIClientUtils.getMetaHash());
}
return NEIKeyboardUtils.getKeyName(Math.max(getValue(), 0));
}
@Override
public int getTextColour(int mousex, int mousey) {
return !editing && conflicted() ? 0xFFFF6666 : -1;
}
}
@@ -131,13 +131,15 @@ public class OptionList extends OptionButton {
/**
* Adds this option to a temporary slot and gui for internal setting manipulation.
*/
public void synthesizeEnvironment(boolean world) {
getGui(null, this, world).addWidgets();
public GuiOptionList synthesizeEnvironment(boolean world) {
GuiOptionList gui = getGui(null, this, world);
gui.addWidgets();
return gui;
}
@Override
public boolean onClick(int button) {
openGui(slot.getGui(), slot.getGui().worldConfig());
openGui(getSlot().getGui(), getSlot().getGui().worldConfig());
return true;
}
@@ -131,6 +131,6 @@ public abstract class OptionStringSet extends Option {
}
public int buttonX() {
return slot.slotWidth() - (24 * options.size() - 4);
return getSlot().slotWidth() - (24 * options.size() - 4);
}
}
@@ -53,7 +53,7 @@ public class OptionTextField extends Option {
}
protected int getMaxInputWidth() {
return slot.slotWidth();
return getSlot().slotWidth();
}
public boolean isEnabled() {
@@ -64,9 +64,10 @@ public class OptionTextField extends Option {
public void draw(int mousex, int mousey, float frame) {
GuiDraw.drawString(getPrefix(), 10, 6, -1);
textField.w = Math
.max(60, Math.min(getMaxInputWidth(), slot.slotWidth() - GuiDraw.getStringWidth(getPrefix())) - 16);
textField.x = slot.slotWidth() - textField.w;
textField.w = Math.max(
60,
Math.min(getMaxInputWidth(), getSlot().slotWidth() - GuiDraw.getStringWidth(getPrefix())) - 16);
textField.x = getSlot().slotWidth() - textField.w;
textField.draw(mousex, mousey);
}
@@ -5,6 +5,7 @@ import static codechicken.lib.gui.GuiDraw.drawStringC;
import org.lwjgl.opengl.GL11;
import codechicken.nei.Button;
import codechicken.nei.ColorUtils;
import codechicken.nei.LayoutManager;
public abstract class CheckboxButton extends Button {
@@ -38,7 +39,8 @@ public abstract class CheckboxButton extends Button {
tex = 1;
}
int colour = tex == 2 ? 0xffffa0 : tex == 0 ? 0x601010 : 0xe0e0e0;
int colour = tex == 2 ? ColorUtils.buttonLabelHover.getColor()
: tex == 0 ? ColorUtils.buttonLabelDisabled.getColor() : ColorUtils.buttonLabelNormal.getColor();
LayoutManager.drawButtonBackground(x, y, w, h, true, isChecked() ? 0 : tex);
drawStringC(getRenderLabel(), x + w / 2, y + (h - 8) / 2, colour);
}
@@ -17,12 +17,14 @@ import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.config.GuiOptionList;
import codechicken.nei.config.GuiOptionPane;
import codechicken.nei.config.Option;
public class GuiPresetList extends GuiOptionPane {
private final Option opt;
private final GuiOptionList parentGui;
protected static final int SLOT_HEIGHT = 24;
protected static final int BUTTON_HEIGHT = 20;
protected GuiCCButton createButton;
@@ -31,6 +33,7 @@ public class GuiPresetList extends GuiOptionPane {
public GuiPresetList(Option opt) {
this.opt = opt;
this.parentGui = (GuiOptionList) Minecraft.getMinecraft().currentScreen;
this.createButton = new GuiCCButton(0, 2, 0, 16, NEIClientUtils.translate("presets.new"))
.setActionCommand("create");
this.toggleButton = new GuiCCButton(0, 2, 0, 16, NEIClientUtils.translate("presets.toggle"))
@@ -253,7 +256,7 @@ public class GuiPresetList extends GuiOptionPane {
@Override
public GuiScreen getParentScreen() {
return opt.slot.getGui();
return parentGui;
}
@Override
@@ -21,7 +21,7 @@ import codechicken.nei.ItemList.AnyMultiItemFilter;
import codechicken.nei.ItemList.NegatedItemFilter;
import codechicken.nei.ItemsGrid;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.KeyManager;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList;
import codechicken.nei.PresetsList.Preset;
@@ -81,15 +81,15 @@ public class RightPanel extends GuiWidget {
@Override
public void lastKeyTyped(int keyID, char keyChar) {
if (!focused() && NEIClientConfig.isKeyHashDown("gui.search")) {
if (!focused() && KeyManager.isHashDown("gui.search")) {
setFocus(true);
}
if (focused() && NEIClientConfig.isKeyHashDown("gui.getprevioussearch")) {
if (focused() && KeyManager.isKeyDown("gui.getprevioussearch")) {
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
}
if (focused() && NEIClientConfig.isKeyHashDown("gui.getnextsearch")) {
if (focused() && KeyManager.isKeyDown("gui.getnextsearch")) {
handleNavigateHistory(TextHistory.Direction.NEXT);
}
}
@@ -24,6 +24,12 @@ public class AllOthersRecipeFilter implements IRecipeFilter {
}
}
for (PositionedStack pStack : handler.getCatalystStacks(recipeIndex)) {
if (!match(pStack)) {
return false;
}
}
return true;
}
@@ -24,6 +24,12 @@ public class AnyOthersRecipeFilter implements IRecipeFilter {
}
}
for (PositionedStack pStack : handler.getCatalystStacks(recipeIndex)) {
if (match(pStack)) {
return true;
}
}
return false;
}
@@ -48,9 +48,7 @@ public class RecipeFilter implements IRecipeFilter {
}
if (this.context == FilterContext.ANY || this.context == FilterContext.OUTPUT) {
final PositionedStack result = handler.getResultStack(recipeIndex);
if (result != null && matchPositionedStack(result) == this.anyMatch) {
if (matchPositionedStack(handler.getResultStacks(recipeIndex), this.anyMatch)) {
return this.anyMatch;
}
@@ -58,6 +56,10 @@ public class RecipeFilter implements IRecipeFilter {
return this.anyMatch;
}
if (matchPositionedStack(handler.getCatalystStacks(recipeIndex), this.anyMatch)) {
return this.anyMatch;
}
}
return !this.anyMatch;
@@ -46,6 +46,7 @@ import org.lwjgl.opengl.GL12;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ItemList;
import codechicken.nei.ItemStackSet;
import codechicken.nei.KeyManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIModContainer;
@@ -624,7 +625,7 @@ public class GuiContainerManager {
tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE);
}
} else if (!tooltip.isEmpty()) {
} else if (!tooltip.isEmpty() && !tooltip.get(0).startsWith(GuiDraw.TOOLTIP_HANDLER)) {
tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE);
}
@@ -762,7 +763,7 @@ public class GuiContainerManager {
"inventory.tooltip.page",
tooltipPage + 1,
maxTooltipPage,
NEIClientConfig.getKeyName("gui.next_tooltip"));
KeyManager.getKeyName("gui.next_tooltip"));
if (lastLine.startsWith(GuiDraw.TOOLTIP_HANDLER)) {
currentTooltip.add(lastLine);
@@ -91,7 +91,7 @@ public class AutoCraftingManager {
for (BookmarkItem item : math.initialItems) {
final long invStackSize = inventory.getOrDefault(item.itemStack, 0L);
final long amount = Math.max(0, item.amount - invStackSize * item.fluidCellAmount);
final long amount = Math.max(0, item.getAmount() - invStackSize * item.fluidCellAmount);
if (amount > 0) {
initialItems.add(item.copyWithAmount(amount));
}
@@ -0,0 +1,89 @@
package codechicken.nei.recipe;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import net.minecraft.util.EnumChatFormatting;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ColorUtils;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIClientUtils.Alignment;
public class Badge {
protected final String text;
protected final List<String> tooltip;
protected int badgeTextColor;
protected boolean shadow = false;
protected Alignment alignment = Alignment.TopLeft;
public Badge(String text, String... tooltip) {
this.text = text;
this.tooltip = Arrays.stream(tooltip).map(t -> EnumChatFormatting.GRAY + t).collect(Collectors.toList());
this.badgeTextColor = ColorUtils.recipeBadge.getColor();
}
public String getText() {
return this.text;
}
public List<String> getTooltip() {
return this.tooltip;
}
public Badge setColor(int color) {
this.badgeTextColor = color;
return this;
}
public int getColor() {
return this.badgeTextColor;
}
public Badge setShadow(boolean shadow) {
this.shadow = shadow;
return this;
}
public boolean hasShadow() {
return this.shadow;
}
public Badge setAlignment(Alignment alignment) {
this.alignment = alignment;
return this;
}
public Alignment getAlignment() {
return this.alignment;
}
public void draw(Rectangle4i rect) {
NEIClientUtils.drawNEIOverlayText(getText(), rect, 0.5f, getColor(), hasShadow(), getAlignment());
}
public static Badge notConsumed() {
return new Badge(
NEIClientUtils.translate("recipe.badge.nc"),
NEIClientUtils.translate("recipe.badge.nc.tooltip"));
}
public static Badge notConsumedParallel() {
return new Badge(
NEIClientUtils.translate("recipe.badge.ncp"),
NEIClientUtils.translate("recipe.badge.ncp.tooltip"));
}
public static Badge consumeChance(float chance) {
final String chanceText = NEIClientUtils.formatChance(chance);
return new Badge(chanceText, NEIClientUtils.translate("recipe.badge.chance.consume", chanceText));
}
public static Badge outputChance(float chance) {
final String chanceText = NEIClientUtils.formatChance(chance);
return new Badge(chanceText, NEIClientUtils.translate("recipe.badge.chance.output", chanceText));
}
}
@@ -1,718 +0,0 @@
package codechicken.nei.recipe;
import java.awt.Point;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.stream.Collectors;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.util.EnumChatFormatting;
import org.apache.commons.io.IOUtils;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.Button;
import codechicken.nei.ClientHandler;
import codechicken.nei.FormattedTextField;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.TextField;
import codechicken.nei.Widget;
import codechicken.nei.drawable.DrawableBuilder;
import codechicken.nei.drawable.DrawableResource;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.recipe.TemplateRecipeHandler.RecipeTransferRect;
public class DebugHandlerWidget extends Widget implements IContainerInputHandler {
private static abstract class IntegerField extends TextField {
protected int defaultValue = 0;
public IntegerField(String ident, int defaultValue) {
super(ident);
this.defaultValue = defaultValue;
this.h = LINE_HEIGHT;
this.z = 2;
((FormattedTextField) field).setPlaceholder(Integer.toString(this.defaultValue));
}
@Override
protected void initInternalTextField() {
field = new FormattedTextField(Minecraft.getMinecraft().fontRenderer, 0, 0, 0, 0) {
@Override
public String getText() {
String text = super.getText();
return !isFocused() && this.placeholder.equals(text) ? "" : text;
}
@Override
protected boolean beforeWrite(String text) {
if (text == null || text.isEmpty()) return true;
try {
return Integer.parseInt(text) >= 0;
} catch (NumberFormatException e) {
return false;
}
}
@Override
public boolean textboxKeyTyped(char keyChar, int keyID) {
if (!isFocused()) return false;
if (super.textboxKeyTyped(keyChar, keyID)) {
return true;
} else if (keyID == Keyboard.KEY_DOWN) {
setText(Integer.toString(getInteger() - 1));
return true;
} else if (keyID == Keyboard.KEY_UP) {
setText(Integer.toString(getInteger() + 1));
return true;
}
return false;
}
};
field.setMaxStringLength(maxSearchLength);
field.setCursorPositionZero();
}
protected int getInteger() {
try {
return Integer.parseInt(text());
} catch (NumberFormatException nfe) {
return this.defaultValue;
}
}
@Override
public boolean onMouseWheel(int i, int mx, int my) {
if (!contains(mx, my)) return false;
setText(Integer.toString(getInteger() + i));
return true;
}
}
private final int[] COLORS = new int[] { 0x2200FF00, 0x22FF0000, 0x220000FF, 0x2200FFFF, 0x22FF00FF, 0x22FFFF00 };
private IRecipeHandler handler;
private HandlerInfo handlerInfo;
private static final int WINDOW_WIDTH = 176;
private static final int LINE_HEIGHT = 16;
private static final int INLINE_PADDING = 6;
private static final int LABEL_WIDTH = 50;
private IntegerField order;
private IntegerField yShift;
private IntegerField handlerHeight;
private IntegerField handlerWidth;
private Button multipleWidgetsAllowed;
private Button useCustomScroll;
private Point dragPoint = null;
public boolean showWidget = false;
private static final int BORDER_PADDING = 6;
private static final int TRANSPARENCY_BORDER = 4;
private static final String TOOLTIP_PREFIX = "debug.RecipeHandler.";
private static final Map<String, String> TOOLTIP_KEYS = new HashMap<>();
static {
TOOLTIP_KEYS.put("Name", TOOLTIP_PREFIX + "Name");
TOOLTIP_KEYS.put("ID", TOOLTIP_PREFIX + "Id");
TOOLTIP_KEYS.put("Key", TOOLTIP_PREFIX + "Key");
TOOLTIP_KEYS.put("H.Hack", TOOLTIP_PREFIX + "HHack");
TOOLTIP_KEYS.put("Mod Name", TOOLTIP_PREFIX + "ModName");
TOOLTIP_KEYS.put("Mod ID", TOOLTIP_PREFIX + "ModId");
TOOLTIP_KEYS.put("Order", TOOLTIP_PREFIX + "Order");
TOOLTIP_KEYS.put("yShift", TOOLTIP_PREFIX + "yShift");
TOOLTIP_KEYS.put("Multi Widgets", TOOLTIP_PREFIX + "MultiWidgets");
TOOLTIP_KEYS.put("Height", TOOLTIP_PREFIX + "Height");
TOOLTIP_KEYS.put("Width", TOOLTIP_PREFIX + "Width");
TOOLTIP_KEYS.put("Use Custom Scroll", TOOLTIP_PREFIX + "UseCustomScroll");
}
private final DrawableResource BG_TEXTURE = new DrawableBuilder(
"nei:textures/gui/recipebg.png",
0,
0,
176 + TRANSPARENCY_BORDER * 2,
166 + TRANSPARENCY_BORDER * 2).build();
public DebugHandlerWidget() {
GuiContainerManager.addInputHandler(this);
this.order = new IntegerField("order", 0) {
@Override
public void onTextChange(String oldText) {
if (NEIClientConfig.handlerOrdering.get(handler.getOverlayIdentifier()) != null) {
if (getInteger() != NEIClientConfig.handlerOrdering.get(handler.getOverlayIdentifier())) {
updatePatch(5, getInteger(), this.defaultValue);
}
} else if (NEIClientConfig.handlerOrdering.get(handler.getHandlerId()) != null) {
if (getInteger() != NEIClientConfig.handlerOrdering.get(handler.getHandlerId())) {
updatePatch(5, getInteger(), this.defaultValue);
}
}
}
};
this.yShift = new IntegerField("yShift", 0) {
@Override
public void onTextChange(String oldText) {
if (getInteger() != handlerInfo.getYShift()) {
handlerInfo.setYShift(getInteger());
updatePatch(1, getInteger(), this.defaultValue);
}
}
};
this.multipleWidgetsAllowed = new Button() {
{
this.h = LINE_HEIGHT;
this.z = 2;
}
public String getRenderLabel() {
return handlerInfo.isMultipleWidgetsAllowed() ? "On" : "Off";
}
@Override
public boolean onButtonPress(boolean rightclick) {
handlerInfo.setHandlerDimensions(
handlerInfo.getWidth(),
handlerInfo.getHeight(),
!handlerInfo.isMultipleWidgetsAllowed());
updatePatch(4, handlerInfo.isMultipleWidgetsAllowed() ? 1 : 0, 1);
return true;
}
};
this.handlerHeight = new IntegerField("handlerHeight", HandlerInfo.DEFAULT_HEIGHT) {
@Override
public void draw(int mx, int my) {
this.field.setEnabled(handler.getRecipeHeight(0) <= 0);
super.draw(mx, my);
}
@Override
public void onTextChange(String oldText) {
if (getInteger() != handlerInfo.getHeight()) {
handlerInfo.setHandlerDimensions(
handlerInfo.getWidth(),
getInteger(),
handlerInfo.isMultipleWidgetsAllowed());
updatePatch(2, getInteger(), this.defaultValue);
}
}
};
this.handlerWidth = new IntegerField("handlerWidth", HandlerInfo.DEFAULT_WIDTH) {
@Override
public void onTextChange(String oldText) {
if (getInteger() != handlerInfo.getWidth()) {
handlerInfo.setHandlerDimensions(
getInteger(),
handlerInfo.getHeight(),
handlerInfo.isMultipleWidgetsAllowed());
updatePatch(3, getInteger(), this.defaultValue);
}
}
};
this.useCustomScroll = new Button() {
{
this.h = LINE_HEIGHT;
this.z = 2;
}
public String getRenderLabel() {
return handlerInfo.getUseCustomScroll() ? "On" : "Off";
}
@Override
public boolean onButtonPress(boolean rightclick) {
handlerInfo.setUseCustomScroll(!handlerInfo.getUseCustomScroll());
updatePatch(6, handlerInfo.getUseCustomScroll() ? 1 : 0, 0);
return true;
}
};
this.w = WINDOW_WIDTH;
this.h = 10 + 13 * LINE_HEIGHT;
this.x = 10;
this.y = 50;
this.z = 1;
}
private void updatePatch(int key, int value, int defaultValue) {
final String handlerKey = getHandlerID(handler);
if (!patches.containsKey(handlerKey)) {
patches.put(handlerKey, new String[] { handlerKey, null, null, null, null, null, null });
}
if (value == defaultValue) {
patches.get(handlerKey)[key] = null;
} else {
patches.get(handlerKey)[key] = String.valueOf(value);
}
saveHandlerInfoPatch();
if (NEIClientUtils.getGuiContainer() instanceof GuiRecipe<?>recipe) {
recipe.forceRefreshPage();
}
}
private void drawKeyLabel(String keyLabel, int topShift) {
final String displayLabel = translateDisplayLabel(keyLabel);
GuiDraw.drawString(
NEIClientUtils.cropText(GuiDraw.fontRenderer, displayLabel, LABEL_WIDTH),
this.x + INLINE_PADDING,
topShift,
0x66555555,
false);
GuiDraw.drawString(":", this.x + INLINE_PADDING + LABEL_WIDTH, topShift, 0x66555555, false);
}
private void drawDetail(String keyLabel, String valueLabel, int topShift, int spaceWidth) {
drawKeyLabel(keyLabel, topShift);
GuiDraw.drawString(
NEIClientUtils.cropText(
GuiDraw.fontRenderer,
valueLabel,
this.w - INLINE_PADDING * 2 - LABEL_WIDTH - spaceWidth),
this.x + INLINE_PADDING + LABEL_WIDTH + spaceWidth,
topShift,
0xffffff);
}
private void drawControl(String keyLabel, Widget field, int topShift, int spaceWidth) {
drawKeyLabel(keyLabel, topShift);
field.x = this.x + INLINE_PADDING + LABEL_WIDTH + spaceWidth;
field.y = topShift - 4;
field.w = this.w - INLINE_PADDING * 2 - LABEL_WIDTH - spaceWidth;
}
private static String translateTooltipLabel(String label) {
String key = TOOLTIP_KEYS.get(label);
String text = label;
if (key == null) {
return EnumChatFormatting.WHITE + EnumChatFormatting.getTextWithoutFormattingCodes(text);
}
text = NEIClientUtils.translate(key);
return EnumChatFormatting.WHITE + EnumChatFormatting.getTextWithoutFormattingCodes(text);
}
private static String translateDisplayLabel(String label) {
String key = TOOLTIP_KEYS.get(label);
if (key == null) {
return label;
}
return NEIClientUtils.translate(key);
}
@Override
public void draw(int mx, int my) {
if (this.handler != null) {
final int spaceWidth = GuiDraw.fontRenderer.getStringWidth(": ");
int topShift = this.y + BORDER_PADDING + 12 + 6;
GL11.glColor4f(1F, 1F, 1F, 1F);
GL11.glScaled(1, 1, 2f);
GL11.glDisable(GL11.GL_DEPTH_TEST);
BG_TEXTURE.draw(
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);
GuiDraw.drawRect(
this.x + INLINE_PADDING,
this.y + BORDER_PADDING,
this.w - INLINE_PADDING * 2,
12,
0x30000000);
GuiDraw.drawStringC(
NEIClientUtils.translate("debug.RecipeHandler.title"),
this.x + this.w / 2,
this.y + BORDER_PADDING + 2,
0xffffff);
for (Map.Entry<String, String> entry : getDetailsInfo().entrySet()) {
drawDetail(entry.getKey(), entry.getValue(), topShift, spaceWidth);
topShift += LINE_HEIGHT;
}
drawControl("Order", this.order, topShift, spaceWidth);
topShift += LINE_HEIGHT;
drawControl("yShift", this.yShift, topShift, spaceWidth);
topShift += LINE_HEIGHT;
drawControl("Multi Widgets", this.multipleWidgetsAllowed, topShift, spaceWidth);
topShift += LINE_HEIGHT;
drawControl("Height", this.handlerHeight, topShift, spaceWidth);
topShift += LINE_HEIGHT;
drawControl("Width", this.handlerWidth, topShift, spaceWidth);
topShift += LINE_HEIGHT;
drawControl("Use Custom Scroll", this.useCustomScroll, topShift, spaceWidth);
topShift += LINE_HEIGHT;
GL11.glScaled(1, 1, 1 / 2f);
}
}
private Map<String, String> getDetailsInfo() {
final Map<String, String> lines = new LinkedHashMap<>();
final boolean isHeightHackApplied = NEIClientConfig.heightHackHandlerRegex.stream()
.map(pattern -> pattern.matcher(this.handler.getHandlerId())).anyMatch(Matcher::matches);
lines.put("Name", this.handler.getRecipeName());
lines.put("ID", this.handler.getOverlayIdentifier());
lines.put("Key", this.handler.getHandlerId());
lines.put("H.Hack", String.valueOf(isHeightHackApplied));
lines.put("Mod Name", this.handlerInfo.getModName());
lines.put("Mod ID", this.handlerInfo.getModId());
return lines;
}
public void setVisible() {
if (showWidget && this.handler != null) {
LayoutManager.addWidget(this.order);
LayoutManager.addWidget(this.yShift);
LayoutManager.addWidget(this.handlerHeight);
LayoutManager.addWidget(this.handlerWidth);
LayoutManager.addWidget(this.multipleWidgetsAllowed);
LayoutManager.addWidget(this.useCustomScroll);
}
}
@Override
public void update() {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
if (showWidget && gui instanceof GuiRecipe recipe) {
if (this.handler != recipe.getHandler()) {
this.handler = recipe.getHandler();
this.handlerInfo = GuiRecipeTab.getHandlerInfo(handler);
this.order.setText(String.valueOf(NEIClientConfig.getHandlerOrder(this.handler)));
this.yShift.setText(String.valueOf(this.handlerInfo.getYShift()));
this.handlerHeight.setText(String.valueOf(this.handlerInfo.getHeight()));
this.handlerWidth.setText(String.valueOf(this.handlerInfo.getWidth()));
}
} else {
this.handler = null;
this.handlerInfo = null;
showWidget = false;
}
}
@Override
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
if (this.handler != null) {
final int spaceWidth = GuiDraw.fontRenderer.getStringWidth(": ");
final int leftShift = this.x + INLINE_PADDING;
if (mx >= leftShift && mx < this.x + WINDOW_WIDTH - INLINE_PADDING) {
int topShift = this.y + BORDER_PADDING + 12 + 6;
for (Map.Entry<String, String> entry : getDetailsInfo().entrySet()) {
if (my >= topShift && my < topShift + LINE_HEIGHT) {
if (mx < leftShift + LABEL_WIDTH + spaceWidth) {
tooltip.add(translateTooltipLabel(entry.getKey()));
} else {
tooltip.add(String.valueOf(entry.getValue()));
}
return tooltip;
}
topShift += LINE_HEIGHT;
}
String[] controlLabels = new String[] { "Order", "yShift", "Multi Widgets", "Height", "Width",
"Use Custom Scroll" };
for (String label : controlLabels) {
if (my >= topShift && my < topShift + LINE_HEIGHT) {
tooltip.add(translateTooltipLabel(label));
return tooltip;
}
topShift += LINE_HEIGHT;
}
}
}
return tooltip;
}
@Override
public boolean keyTyped(GuiContainer gui, char keyChar, int keyCode) {
if (NEIClientConfig.getBooleanSetting("inventory.guirecipe.handlerInfo") && showWidget
&& keyCode == Keyboard.KEY_C
&& NEIClientUtils.controlKey()) {
final int spaceWidth = GuiDraw.fontRenderer.getStringWidth(": ");
final Point mouse = GuiDraw.getMousePosition();
if (mouse.x >= this.x + INLINE_PADDING + LABEL_WIDTH + spaceWidth
&& mouse.x < this.x + WINDOW_WIDTH - INLINE_PADDING) {
int topShift = this.y + BORDER_PADDING + 12 + 6;
for (Map.Entry<String, String> entry : getDetailsInfo().entrySet()) {
if (mouse.y >= topShift && mouse.y < topShift + LINE_HEIGHT) {
GuiScreen.setClipboardString(entry.getValue());
return true;
}
topShift += LINE_HEIGHT;
}
}
}
return false;
}
@Override
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
return false;
}
@Override
public void onKeyTyped(GuiContainer gui, char keyChar, int keyID) {}
@Override
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
if (NEIClientConfig.getBooleanSetting("inventory.guirecipe.handlerInfo") && keyID == Keyboard.KEY_D
&& NEIClientUtils.shiftKey()) {
showWidget = !showWidget;
return true;
} else if (this.handler != null) {
return this.order.focused() || this.yShift.focused()
|| this.handlerHeight.focused()
|| this.handlerWidth.focused();
}
return false;
}
@Override
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
if (this.handler != null
&& new Rectangle4i(this.x + INLINE_PADDING, this.y + BORDER_PADDING, this.w - INLINE_PADDING * 2, 12)
.contains(mousex, mousey)) {
this.dragPoint = new Point(mousex, mousey);
}
}
@Override
public boolean contains(int px, int py) {
return this.handler != null && super.contains(px, py);
}
@Override
public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) {
this.dragPoint = null;
}
@Override
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
return false;
}
@Override
public void onMouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {}
@Override
public boolean handleClickExt(int mx, int my, int button) {
return false;
}
@Override
public void onMouseDragged(GuiContainer gui, int mousex, int mousey, int button, long heldTime) {
if (this.dragPoint != null) {
this.x -= this.dragPoint.x - mousex;
this.y -= this.dragPoint.y - mousey;
this.dragPoint.move(mousex, mousey);
}
}
public void drawGuiPlaceholder(NEIRecipeWidget widget) {
if (!showWidget) return;
NEIClientUtils.gl2DRenderContext(() -> {
// background
GuiDraw.drawRect(
widget.x,
widget.y,
widget.w,
widget.h,
COLORS[widget.handlerRef.recipeIndex % COLORS.length]);
// center cross
GuiDraw.drawRect(widget.x + widget.w / 2 - 1, widget.y, 1, widget.h, 0x88ffffff);
GuiDraw.drawRect(widget.x, widget.y + widget.h / 2 - 1, widget.w, 1, 0x88ffffff);
// blue-line-top (grid-top)
GuiDraw.drawRect(widget.x + 14, widget.y + 5, widget.w - 38, 1, 0xff0000aa);
// blue-line-bottom {grid-bottom}
GuiDraw.drawRect(widget.x + 14, widget.y + widget.h - 7, widget.w - 38, 1, 0xff0000aa);
// blue-left (grid start)
GuiDraw.drawRect(widget.x + 24, widget.y + (widget.h - 16) / 2, 1, 16, 0xffaa00aa);
// purple (before favorite)
GuiDraw.drawRect(
widget.x + Math.min(168, widget.w) - 27,
widget.y + widget.h - 6 - GuiRecipeButton.BUTTON_HEIGHT * 2 - 4,
GuiRecipeButton.BUTTON_WIDTH,
1,
0xffaa00aa);
// green ()
GuiDraw.drawRect(
widget.x + Math.min(168, widget.w) - 35,
widget.y + widget.h - 6 - GuiRecipeButton.BUTTON_HEIGHT - 3,
20,
1,
0xff00aa00);
// purple space before bottom grid
GuiDraw.drawRect(
widget.x + 14,
widget.y + widget.h - 7 - GuiRecipeButton.BUTTON_WIDTH / 2,
38,
1,
0xffaa00aa);
if (widget.handlerRef.handler instanceof TemplateRecipeHandler handler) {
int yShift = widget.getHandlerInfo().getYShift();
for (RecipeTransferRect rect : handler.transferRects) {
GuiDraw.drawRect(
widget.x + rect.rect.x,
widget.y + yShift + rect.rect.y,
rect.rect.width,
rect.rect.height,
0x40ff0000);
}
}
});
}
private static Map<String, String[]> patches = new HashMap<>();
public static void loadHandlerInfoPatch() {
ClientHandler.loadSettingsFile("handlers.patch", lines -> {
for (String line : lines.collect(Collectors.toCollection(HashSet::new))) {
final String[] parts = line.split(",");
final String handler = parts[0];
if (GuiRecipeTab.handlerMap.containsKey(handler)) {
final HandlerInfo info = GuiRecipeTab.handlerMap.get(handler);
final int yShift = intOrDefault(parts[1], info.getYShift());
final int height = intOrDefault(parts[2], info.getHeight());
final int width = intOrDefault(parts[3], info.getWidth());
final boolean isMultipleWidgetsAllowed = intOrDefault(
parts[4],
info.isMultipleWidgetsAllowed() ? 1 : 0) == 1;
final int order = intOrDefault(parts[5], NEIClientConfig.handlerOrdering.getOrDefault(handler, 0));
final boolean useCustomScroll = intOrDefault(parts[6], info.getUseCustomScroll() ? 1 : 0) == 1;
info.setYShift(yShift);
info.setHandlerDimensions(width, height, isMultipleWidgetsAllowed);
info.setUseCustomScroll(useCustomScroll);
NEIClientConfig.handlerOrdering.put(handler, order);
}
patches.put(handler, parts);
}
});
}
private static void saveHandlerInfoPatch() {
final List<String> lines = new ArrayList<>();
for (String[] line : patches.values()) {
lines.add(String.join(",", line));
}
final File path = new File(NEIClientConfig.configDir, "handlers.patch");
try (FileOutputStream output = new FileOutputStream(path)) {
IOUtils.writeLines(lines, "\n", output, StandardCharsets.UTF_8);
} catch (IOException e) {}
}
private static int intOrDefault(String str, int defaultValue) {
if (str == null || str.equals("")) return defaultValue;
try {
return Integer.parseInt(str);
} catch (NumberFormatException e) {
return defaultValue;
}
}
private static String getHandlerID(IRecipeHandler handler) {
if (GuiRecipeTab.handlerMap.containsKey(handler.getHandlerId())) {
return handler.getHandlerId();
} else if (handler instanceof TemplateRecipeHandler) {
return handler.getOverlayIdentifier();
}
return null;
}
}
@@ -98,10 +98,14 @@ public class DefaultOverlayHandler implements IOverlayHandler {
&& presenceOverlay(firstGui, handler, recipeIndex).stream().allMatch(state -> state.isPresent());
}
protected Slot getCraftingResultSlot(GuiContainer gui) {
return gui.inventorySlots.inventorySlots.stream().filter(slot -> slot instanceof SlotCrafting).findFirst()
.orElse(null);
}
@Override
public boolean craft(GuiContainer firstGui, IRecipeHandler handler, int recipeIndex, int multiplier) {
final Slot craftingSlot = firstGui.inventorySlots.inventorySlots.stream()
.filter(slot -> slot instanceof SlotCrafting).findFirst().orElse(null);
final Slot craftingSlot = getCraftingResultSlot(firstGui);
if (craftingSlot == null) {
return false;
@@ -145,7 +149,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
/**
* Gets the slots in the crafting matrix for the given GUI and recipe handler.
*
*
* @param gui
* @param handler
* @return
@@ -193,10 +197,11 @@ public class DefaultOverlayHandler implements IOverlayHandler {
return ingredSlots;
}
private void moveIngredients(GuiContainer gui, List<IngredientDistribution> assignedIngredients, int multiplier) {
protected void moveIngredients(GuiContainer gui, List<IngredientDistribution> assignedIngredients, int multiplier) {
final Slot craftingSlot = getCraftingResultSlot(gui);
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (slot instanceof SlotCrafting || !slot.getHasStack()
if (slot == craftingSlot || !slot.getHasStack()
|| !canMoveFrom(slot, gui)
|| !slot.canTakeStack(gui.mc.thePlayer))
continue;
@@ -205,7 +210,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
for (IngredientDistribution distrib : assignedIngredients) {
if (distrib.slots.length == 0 || !slot.getHasStack() || !canStack(distrib.permutation, stack)) continue;
int transferCap = Math.min(slotTransferCap, multiplier * distrib.permutation.stackSize);
int transferCap = Math.min(slotTransferCap, Math.max(multiplier * distrib.permutation.stackSize, 1));
int stackSize = slot.getStack().stackSize;
boolean pickup = false;
@@ -244,7 +249,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
}
}
private int calculateRecipeQuantity(List<IngredientDistribution> assignedIngredients) {
protected int calculateRecipeQuantity(List<IngredientDistribution> assignedIngredients) {
int quantity = Integer.MAX_VALUE;
for (IngredientDistribution distrib : assignedIngredients) {
@@ -270,7 +275,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
return quantity;
}
private Slot[][] assignIngredSlots(GuiContainer gui, List<PositionedStack> ingredients,
protected Slot[][] assignIngredSlots(GuiContainer gui, List<PositionedStack> ingredients,
List<IngredientDistribution> assignedIngredients) {
Slot[][] recipeSlots = mapIngredSlots(gui, ingredients); // setup the slot map
@@ -315,7 +320,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
return recipeSlots;
}
private List<IngredientDistribution> assignIngredients(List<PositionedStack> ingredients,
protected List<IngredientDistribution> assignIngredients(List<PositionedStack> ingredients,
List<DistributedIngred> ingredStacks) {
ArrayList<IngredientDistribution> assignedIngredients = new ArrayList<>();
for (PositionedStack posstack : ingredients) // assign what we need and have
@@ -353,7 +358,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
return assignedIngredients;
}
private void findInventoryQuantities(GuiContainer gui, List<DistributedIngred> ingredStacks) {
protected void findInventoryQuantities(GuiContainer gui, List<DistributedIngred> ingredStacks) {
for (Slot slot : gui.inventorySlots.inventorySlots) /* work out how much we have to go round */ {
if (slot.getHasStack() && canMoveFrom(slot, gui)) {
final ItemStack pstack = slot.getStack();
@@ -385,7 +390,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
}
}
private List<DistributedIngred> getPermutationIngredients(List<PositionedStack> ingredients) {
protected List<DistributedIngred> getPermutationIngredients(List<PositionedStack> ingredients) {
ArrayList<DistributedIngred> ingredStacks = new ArrayList<>();
for (PositionedStack posstack : ingredients) /* work out what we need */ {
for (ItemStack pstack : posstack.items) {
@@ -422,8 +427,8 @@ public class DefaultOverlayHandler implements IOverlayHandler {
return null;
}
protected boolean canStack(ItemStack stack1, ItemStack stack2) {
if (stack1 == null || stack2 == null) return true;
return NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack1, stack2);
protected boolean canStack(ItemStack dst, ItemStack src) {
if (dst == null || src == null) return true;
return NEIClientUtils.areStacksSameTypeCraftingWithNBT(dst, src);
}
}
@@ -38,6 +38,11 @@ public class FuelRecipeHandler extends FurnaceRecipeHandler {
public PositionedStack getOtherStack() {
return fuel.stack;
}
@Override
public PositionedStack getCatalyst() {
return fuel.stack;
}
}
private final ArrayList<SmeltingPair> mfurnace = new ArrayList<>();
@@ -21,7 +21,6 @@ import codechicken.nei.NEIClientUtils;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.BookmarksGridSlot;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.TemplateRecipeHandler.RecipeTransferRect;
public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
@@ -83,8 +82,8 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
} else if ("recipeId".equals(outputId)) {
ItemStack stack = (ItemStack) results[0];
RecipeId recipeId = (RecipeId) results[1];
craftinghandlers = filterByHandlerName(craftinghandlers, recipeId.getHandleName());
serialCraftingHandlers = filterByHandlerName(serialCraftingHandlers, recipeId.getHandleName());
craftinghandlers = filterByHandlerName(craftinghandlers, recipeId.getHandlerName());
serialCraftingHandlers = filterByHandlerName(serialCraftingHandlers, recipeId.getHandlerName());
recipeHandlerFunction = h -> h.getRecipeHandler("item", stack);
} else {
recipeHandlerFunction = h -> h.getRecipeHandler(outputId, results);
@@ -103,18 +102,7 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
private static ICraftingHandler buildAllRecipesHandler(ICraftingHandler handler) {
if (handler instanceof TemplateRecipeHandler templateHandler) {
TemplateRecipeHandler allHandler = templateHandler.newInstance();
if (allHandler.transferRects.isEmpty()) {
allHandler.loadCraftingRecipes("all");
return allHandler;
}
for (RecipeTransferRect rect : allHandler.transferRects) {
if (allHandler.specifyTransferRect() == null
|| allHandler.specifyTransferRect().equals(rect.outputId)) {
allHandler.loadCraftingRecipes(rect.outputId, rect.results);
return allHandler;
}
}
return templateHandler.getAllRecipeHandler();
}
return handler.getRecipeHandler("all");
}
@@ -19,6 +19,7 @@ import codechicken.nei.FavoriteRecipes;
import codechicken.nei.Image;
import codechicken.nei.ItemPanels;
import codechicken.nei.ItemStackSet;
import codechicken.nei.KeyManager;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
@@ -122,7 +123,7 @@ public class GuiFavoriteButton extends GuiRecipeButton {
public void lastKeyTyped(char keyChar, int keyID) {
if (NEIClientConfig.isKeyHashDown("gui.bookmark") && NEIClientUtils.shiftKey()) {
if (KeyManager.isKeyDown("bookmark.add") && NEIClientUtils.shiftKey()) {
saveRecipeInBookmark();
}
@@ -131,7 +132,7 @@ public class GuiFavoriteButton extends GuiRecipeButton {
@Override
public Map<String, String> handleHotkeys(int mousex, int mousey, Map<String, String> hotkeys) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH),
translate("recipe.favorite.bookmark_recipe"));
if (this.recipe.getResults().size() > 1) {
@@ -229,7 +230,7 @@ public class GuiFavoriteButton extends GuiRecipeButton {
}
}
if (recipeId != null && FavoriteRecipes.FAVORITE_ITEM.contains(recipeId.getHandleName())) {
if (recipeId != null && FavoriteRecipes.FAVORITE_ITEM.contains(recipeId.getHandlerName())) {
items.add(stack);
} else {
Recipe recipe = Recipe.of(recipeId);
@@ -15,11 +15,14 @@ import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ItemPanels;
import codechicken.nei.ItemsTooltipLineHandler;
import codechicken.nei.KeyManager;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.api.IOverlayHandler;
import codechicken.nei.bookmark.BookmarkGrid;
import codechicken.nei.bookmark.BookmarkPayload;
import codechicken.nei.drawable.DrawableBuilder;
import codechicken.nei.drawable.DrawableResource;
import codechicken.nei.util.NEIMouseUtils;
@@ -96,12 +99,18 @@ public class GuiOverlayButton extends GuiRecipeButton {
super(handlerRef, x, y, handlerRef.recipeIndex + BUTTON_ID_SHIFT, "+");
this.firstGui = firstGui != null && firstGui.inventorySlots != null ? firstGui : null;
this.canUseOverlayRenderer = this.firstGui != null && handlerRef.getRecipeOverlayRenderer(firstGui) != null;
this.canFillCraftingGrid = this.firstGui != null && this.handlerRef.canFillCraftingGrid(this.firstGui);
this.hasOverlay = this.canUseOverlayRenderer
|| this.firstGui != null && handlerRef.getOverlayHandler(firstGui) != null;
IOverlayHandler overlayHandler = null;
setRequireShiftForOverlayRecipe(NEIClientConfig.requireShiftForOverlayRecipe());
if (this.firstGui != null) {
overlayHandler = this.handlerRef.getOverlayHandler(this.firstGui);
this.canUseOverlayRenderer = this.handlerRef.getRecipeOverlayRenderer(this.firstGui) != null;
this.canFillCraftingGrid = this.handlerRef.canFillCraftingGrid(this.firstGui);
this.hasOverlay = this.canUseOverlayRenderer || overlayHandler != null;
}
setRequireShiftForOverlayRecipe(
overlayHandler != null ? overlayHandler.requireShiftForOverlayRecipe()
: NEIClientConfig.requireShiftForOverlayRecipe());
ingredientsOverlay();
}
@@ -156,13 +165,17 @@ public class GuiOverlayButton extends GuiRecipeButton {
}
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("recipe.overlay.bookmarkRecipe"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("recipe.overlay.bookmarkRecipeAndCount"));
hotkeys.put(
KeyManager.getKeyName("bookmark.chat_link", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("recipe.overlay.sendRecipeToChat"));
return hotkeys;
}
@@ -318,9 +331,13 @@ public class GuiOverlayButton extends GuiRecipeButton {
@Override
public void lastKeyTyped(char keyChar, int keyID) {
if (NEIClientConfig.isKeyHashDown("gui.bookmark") && NEIClientUtils.shiftKey()) {
if (KeyManager.isKeyDown("bookmark.add") && NEIClientUtils.shiftKey()) {
saveRecipeInBookmark();
}
if (KeyManager.isKeyDown("bookmark.chat_link") && NEIClientUtils.controlKey() && NEIClientUtils.shiftKey()) {
sendRecipeChatLink();
}
}
public void saveRecipeInBookmark() {
@@ -335,4 +352,7 @@ public class GuiOverlayButton extends GuiRecipeButton {
}
}
private void sendRecipeChatLink() {
NEIClientUtils.sendChatItemLink(BookmarkPayload.of(getRecipe()).toNBT());
}
}
@@ -17,7 +17,6 @@ import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
@@ -25,7 +24,9 @@ import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.Button;
import codechicken.nei.ColorUtils;
import codechicken.nei.GuiNEIButton;
import codechicken.nei.KeyManager;
import codechicken.nei.NEICPH;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
@@ -53,6 +54,7 @@ import codechicken.nei.scroll.ScrollBar;
import codechicken.nei.scroll.ScrollBar.OverflowType;
import codechicken.nei.scroll.ScrollBar.ScrollPlace;
import codechicken.nei.scroll.ScrollContainer;
import codechicken.nei.util.EmptyContainer;
import codechicken.nei.util.SlotInaccessible;
public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer implements IGuiContainerOverlay,
@@ -92,6 +94,9 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private GuiButton prevtype;
private GuiButton nexttype;
private Rectangle typeArea = new Rectangle();
private Rectangle pageArea = new Rectangle();
private int lastPage = -1;
private final GuiRecipeTabs recipeTabs;
private final GuiRecipeCatalyst recipeCatalyst;
@@ -177,7 +182,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private boolean isHeightHackApplied = false;
protected GuiRecipe(GuiScreen prevgui) {
super(new ContainerRecipe());
super(new EmptyContainer());
this.recipeTabs = new GuiRecipeTabs() {
@Override
@@ -187,7 +192,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
};
this.recipeCatalyst = new GuiRecipeCatalyst();
this.slotcontainer = (ContainerRecipe) this.inventorySlots;
this.slotcontainer = (EmptyContainer) this.inventorySlots;
this.prevGui = prevgui;
this.firstGuiGeneral = prevgui;
@@ -308,7 +313,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
@Override
public Widget getWidgetUnderMouse(int mousex, int mousey) {
if (handlerInfo.getUseCustomScroll() && !this.widgets.isEmpty()) {
if (handlerInfo.isAllowOverflowY() && !this.widgets.isEmpty()) {
return this.widgets.get(0);
}
@@ -346,7 +351,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
this.container.x = this.guiLeft + 3;
this.container.y = this.guiTop + 32;
this.container.h = this.ySize - 32 - 5;
this.container.h = this.ySize - 32 - 4;
GuiRecipe.toggleSearch.icon = new DrawableBuilder("nei:textures/nei_sprites.png", 0, 76, 10, 10).build();
GuiRecipe.toggleSearch.w = GuiRecipe.toggleSearch.h = 12;
@@ -358,8 +363,18 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
GuiRecipe.searchField.w = this.xSize - (BORDER_PADDING + BUTTON_WIDTH) * 2 + 1 - GuiRecipe.toggleSearch.w - 45;
GuiRecipe.searchField.h = 14;
this.buttonList.addAll(Arrays.asList(this.prevtype, this.nexttype, this.prevpage, this.nextpage));
this.typeArea.setBounds(
this.prevtype.xPosition + BUTTON_WIDTH,
this.prevtype.yPosition,
this.nexttype.xPosition - this.prevtype.xPosition - BUTTON_WIDTH - 1,
BUTTON_HEIGHT);
this.pageArea.setBounds(
this.prevpage.xPosition + BUTTON_WIDTH,
this.prevpage.yPosition,
this.nextpage.xPosition - this.prevpage.xPosition - BUTTON_WIDTH - 1,
BUTTON_HEIGHT);
this.buttonList.addAll(Arrays.asList(this.prevtype, this.nexttype, this.prevpage, this.nextpage));
if (this.currenthandlers.size() == 1) {
this.prevtype.visible = false;
this.nexttype.visible = false;
@@ -372,9 +387,19 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
if (this.handlerPages.rebuildPages() || this.lastPage != this.handlerPages.getCurrentPageIndex()) {
this.lastPage = this.handlerPages.getCurrentPageIndex();
updateContainerSize();
this.container.setWidgets(this.handlerPages.getCurrentPageWidgets());
if (this.handlerInfo.getUseCustomScroll()) {
if (!this.handlerInfo.isAllowOverflowX() && this.handlerInfo.getWidth() > this.xSize - 6) {
this.container.setPaddingInline(0, 2);
this.container.setHorizontalScroll(ScrollBar.defaultHorizontalBar().setTrackPadding(1, 0, 1, 0));
} else {
this.container.setPaddingInline(0, 0);
this.container.setHorizontalScroll(null);
}
if (this.handlerInfo.isAllowOverflowY()) {
this.container.setVerticalScroll(null);
} else if (this.container.w == this.xSize - 6) {
this.container.setVerticalScroll(VERTICAL_SCROLLBAR);
@@ -416,7 +441,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
this.recipetype = (this.currenthandlers.size() + idx) % this.currenthandlers.size();
this.handler = new SearchRecipeHandler<>(this.currenthandlers.get(this.recipetype));
this.handlerInfo = GuiRecipeTab.getHandlerInfo(this.handler.original);
this.container.w = Math.max(this.xSize - 6, this.handlerInfo.getWidth());
updateContainerSize();
this.handlerPages = new RecipePageManager(this.handler, this.handlerInfo, this.container);
this.prevpage.enabled = this.nextpage.enabled = this.handlerPages.getNumPages() > 1;
this.lastPage = -1;
@@ -426,9 +451,21 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
GuiRecipe.toggleSearch.state = 0;
this.container.setVerticalScrollOffset(0);
this.container.setHorizontalScrollOffset(0);
this.recipeTabs.update(this);
}
private void updateContainerSize() {
final int width = this.xSize - 6;
this.container.w = Math.max(width, this.handlerInfo.getWidth());
this.container.h = this.ySize - 32 - 4;
if (!this.handlerInfo.isAllowOverflowX() && this.handlerInfo.getWidth() > width) {
this.container.w = width;
this.container.h -= 8;
}
}
public int openTargetRecipe(RecipeId recipeId) {
int refIndex = -1;
int recipetype = 0;
@@ -440,7 +477,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
final H localHandler = this.currenthandlers.get(j);
final HandlerInfo localHandlerInfo = GuiRecipeTab.getHandlerInfo(localHandler);
if (localHandlerInfo.getHandlerName().equals(this.recipeId.getHandleName())) {
if (localHandlerInfo.getHandlerName().equals(this.recipeId.getHandlerName())) {
recipetype = j;
if (!this.recipeId.getIngredients().isEmpty()) {
@@ -490,7 +527,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
@Override
public Slot getSlotAtPosition(int mousex, int mousey) {
final Widget activeWidget = this.container.getWidgetUnderMouse(mousex, mousey);
final ContainerRecipe slotcontainer = (ContainerRecipe) inventorySlots;
final EmptyContainer slotcontainer = (EmptyContainer) inventorySlots;
slotcontainer.setActiveStack(null);
if (activeWidget instanceof NEIRecipeWidget recipeWidget) {
@@ -564,15 +601,15 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
if (i == mc.gameSettings.keyBindInventory.getKeyCode()) {
this.mc.displayGuiScreen(getFirstScreenGeneral());
NEICPH.sendRequestContainer();
} else if (NEIClientConfig.isKeyHashDown("gui.back")) {
} else if (KeyManager.isKeyDown("recipe.back")) {
this.mc.displayGuiScreen(this.prevGui);
} else if (NEIClientConfig.isKeyHashDown("gui.prev_machine")) {
} else if (KeyManager.isKeyDown("recipe.prev_machine")) {
prevType();
} else if (NEIClientConfig.isKeyHashDown("gui.next_machine")) {
} else if (KeyManager.isKeyDown("recipe.next_machine")) {
nextType();
} else if (NEIClientConfig.isKeyHashDown("gui.prev_recipe")) {
} else if (KeyManager.isKeyDown("recipe.prev_recipe")) {
prevPage();
} else if (NEIClientConfig.isKeyHashDown("gui.next_recipe")) {
} else if (KeyManager.isKeyDown("recipe.next_recipe")) {
nextPage();
}
}
@@ -671,7 +708,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
// If shift is held, try switching to the next recipe handler. Replicates the
// GuiRecipeTabs.mouseScrolled()
// without the checking for the cursor being inside the tabbar.
if (NEIClientUtils.shiftKey()) {
if (NEIClientUtils.shiftKey() || this.typeArea.contains(mouse)) {
if (scroll < 0) {
nextType();
} else {
@@ -683,7 +720,12 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
// Finally, if nothing else has handled scrolling, try changing to the next
// recipe page.
if (new Rectangle(this.guiLeft, this.guiTop, this.xSize, this.ySize).contains(mouse)) {
if (NEIClientConfig.getBooleanSetting("inventory.guirecipe.scrollPages")
&& this.container.boundsInside().contains(mouse.x, mouse.y)
|| this.pageArea.contains(mouse)
&& (!this.handler.searchingAvailable() || !GuiRecipe.toggleSearch.contains(mouse.x, mouse.y))
&& (!GuiRecipe.searchField.isVisible() || !GuiRecipe.searchField.contains(mouse.x, mouse.y))) {
if (scroll > 0) {
prevPage();
} else {
@@ -783,10 +825,11 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
return this.recipeCatalyst;
}
protected void forceRefreshPage() {
this.currenthandlers.sort(NEIClientConfig.HANDLER_COMPARATOR);
public void forceRefreshPage() {
final int currentPage = this.handlerPages.getCurrentPageIndex();
this.currenthandlers.sort(NEIClientConfig.HANDLER_COMPARATOR);
this.recipetype = this.currenthandlers.indexOf(this.handler.original);
setRecipePage(this.recipetype);
this.handlerPages.changePage(currentPage);
@@ -824,26 +867,26 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
final int textMiddle = (BUTTON_WIDTH - this.fontRendererObj.FONT_HEIGHT) / 2;
drawRect(
this.prevtype.xPosition + BUTTON_WIDTH - 1,
this.prevtype.yPosition,
this.nexttype.xPosition,
this.prevtype.yPosition + BUTTON_HEIGHT,
this.typeArea.x,
this.typeArea.y,
this.typeArea.x + this.typeArea.width,
this.typeArea.y + this.typeArea.height,
0x30000000);
drawRect(
this.prevpage.xPosition + BUTTON_WIDTH - 1,
this.prevpage.yPosition,
this.nextpage.xPosition,
this.prevpage.yPosition + BUTTON_HEIGHT,
this.pageArea.x,
this.pageArea.y,
this.pageArea.x + this.pageArea.width,
this.pageArea.y + this.pageArea.height,
0x30000000);
final String handlerTitle = this.handler.original.getRecipeName().trim();
final String titleColorCode = getHandlerTitleColorCode(isHandlerTitleHovered(mouseX, mouseY));
final int titleColor = getHandlerTitleColor(isHandlerTitleHovered(mouseX, mouseY));
drawCenteredString(
this.fontRendererObj,
titleColorCode + handlerTitle + EnumChatFormatting.RESET,
handlerTitle,
this.guiLeft + this.xSize / 2,
this.prevtype.yPosition + textMiddle,
0xffffff);
this.typeArea.y + textMiddle,
titleColor);
if (this.handler.searchingAvailable()) {
GuiRecipe.toggleSearch.draw(mouseX, mouseY);
@@ -865,7 +908,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
this.fontRendererObj,
recipePage,
GuiRecipe.searchField.x + GuiRecipe.searchField.w + 22,
this.prevpage.yPosition + textMiddle,
this.pageArea.y + textMiddle,
0xffffff);
} else {
final String recipePage = NEIClientUtils.translate(
@@ -876,7 +919,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
this.fontRendererObj,
recipePage,
this.guiLeft + this.xSize / 2,
this.prevpage.yPosition + textMiddle,
this.pageArea.y + textMiddle,
0xffffff);
}
@@ -897,13 +940,8 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
return new Rectangle(titleX, titleY, titleWidth, this.fontRendererObj.FONT_HEIGHT).contains(mousex, mousey);
}
private String getHandlerTitleColorCode(boolean hovered) {
final String key = hovered ? "recipe.title.color.hover" : "recipe.title.color.normal";
final String translated = NEIClientUtils.translate(key);
if (!translated.startsWith("nei.")) { // Optional localization string for resource packs
return translated;
}
return hovered ? EnumChatFormatting.YELLOW.toString() : EnumChatFormatting.WHITE.toString();
private int getHandlerTitleColor(boolean hovered) {
return hovered ? ColorUtils.recipeTitleHover.getColor() : ColorUtils.recipeTitle.getColor();
}
@Override
@@ -996,7 +1034,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private GuiOverlayButton[] overlayButtons = new GuiOverlayButton[0];
@Deprecated
public ContainerRecipe slotcontainer;
public EmptyContainer slotcontainer;
@Deprecated
public List<GuiButton> getOverlayButtons() {
@@ -23,16 +23,18 @@ import net.minecraftforge.common.MinecraftForge;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ColorUtils;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.Widget;
import codechicken.nei.drawable.DrawableResource;
import codechicken.nei.event.NEIRegisterHandlerInfosEvent;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.debug.DebugHandlerWidget;
import cpw.mods.fml.common.Loader;
public abstract class GuiRecipeTab extends Widget {
@@ -126,7 +128,7 @@ public abstract class GuiRecipeTab extends Widget {
int textCenterX = x + (int) (getWidth() / 2f);
int textCenterY = y + (int) (getHeight() / 2f) - 3;
int color = selected ? 0xffffa0 : 0xe0e0e0;
int color = selected ? ColorUtils.buttonLabelHover.getColor() : ColorUtils.buttonLabelNormal.getColor();
fontRenderer.drawStringWithShadow(
text,
textCenterX - (int) (fontRenderer.getStringWidth(text) / 2f),
@@ -138,18 +140,16 @@ public abstract class GuiRecipeTab extends Widget {
public void addTooltips(List<String> tooltip) {
tooltip.add(handler.getRecipeTabName().trim());
String handlerMod = getHandlerMod(handlerName, handlerID);
tooltip.add(EnumChatFormatting.BLUE + handlerMod);
boolean shiftHeld = Keyboard.getEventKeyState()
&& (Keyboard.getEventKey() == Keyboard.KEY_LSHIFT || Keyboard.getEventKey() == Keyboard.KEY_RSHIFT);
if (handlerMod.equals("Unknown") || shiftHeld) {
if (handlerMod.equals("Unknown") || NEIClientUtils.shiftKey()) {
tooltip.add("");
tooltip.add("HandlerName: " + handlerName);
tooltip.add("HandlerID: " + handlerID);
tooltip.add("HandlerOrder: " + NEIClientConfig.getHandlerOrder(handler));
tooltip.add(EnumChatFormatting.GRAY + "HandlerName: " + handlerName);
tooltip.add(EnumChatFormatting.GRAY + "HandlerID: " + handlerID);
tooltip.add(EnumChatFormatting.GRAY + "HandlerOrder: " + NEIClientConfig.getHandlerOrder(handler));
}
tooltip.add(EnumChatFormatting.BLUE + handlerMod);
}
public abstract boolean onButtonPress(boolean rightclick);
@@ -258,13 +258,19 @@ public abstract class GuiRecipeTab extends Widget {
final int handlerHeight = intOrDefault(record.get("handlerHeight"), HandlerInfo.DEFAULT_HEIGHT);
final int handlerWidth = intOrDefault(record.get("handlerWidth"), HandlerInfo.DEFAULT_WIDTH);
final boolean multipleWidgetsAllowed = intOrDefault(record.get("maxRecipesPerPage"), 1) > 1;
info.setHandlerDimensions(handlerWidth, handlerHeight, multipleWidgetsAllowed);
info.setHandlerDimensions(handlerWidth, handlerHeight);
info.setMultipleWidgetsAllowed(multipleWidgetsAllowed);
} catch (NumberFormatException ignored) {
NEIClientConfig.logger.info("Error setting handler dimensions for " + handler);
}
info.setUseCustomScroll(
record.isSet("useCustomScroll") ? Boolean.parseBoolean(record.get("useCustomScroll")) : false);
final boolean allowOverflow = record.isSet("useCustomScroll")
&& Boolean.parseBoolean(record.get("useCustomScroll"));
info.setAllowOverflowX(
record.isSet("allowOverflowX") ? Boolean.parseBoolean(record.get("allowOverflowX")) : true);
info.setAllowOverflowY(
record.isSet("allowOverflowY") ? Boolean.parseBoolean(record.get("allowOverflowY"))
: allowOverflow);
handlerMap.put(handler, info);
NEIClientConfig.logger.info("Loaded " + handler);
}
@@ -292,11 +298,12 @@ public abstract class GuiRecipeTab extends Widget {
}
NEIClientConfig.logger.info("Sending {}", NEIRegisterHandlerInfosEvent.class.getSimpleName());
MinecraftForge.EVENT_BUS.post(new NEIRegisterHandlerInfosEvent());
DebugHandlerWidget.instance.loadHandlerInfoPatch();
}
private static HandlerInfo getDefaultHandlerInfo() {
final HandlerInfo info = new HandlerInfo("Unknown", "Unknown", "Unknown", false, "");
info.setHandlerDimensions(HandlerInfo.DEFAULT_WIDTH, HandlerInfo.DEFAULT_HEIGHT, false);
info.setHandlerDimensions(HandlerInfo.DEFAULT_WIDTH, HandlerInfo.DEFAULT_HEIGHT);
return info;
}
@@ -30,7 +30,10 @@ public class HandlerInfo {
private boolean multipleWidgetsAllowed = false;
private boolean showFavoritesButton = true;
private boolean showOverlayButton = true;
private boolean useCustomScroll = false;
private boolean showBadge = false;
private boolean allowOverflowX = true;
private boolean allowOverflowY = false;
private ItemStack itemStack = null;
private DrawableResource image = null;
@@ -45,13 +48,13 @@ public class HandlerInfo {
@Deprecated
public void setHandlerDimensions(int height, int width, int maxRecipesPerPage) {
setHandlerDimensions(width, height, maxRecipesPerPage > 1);
setHandlerDimensions(width, height);
setMultipleWidgetsAllowed(maxRecipesPerPage > 1);
}
public void setHandlerDimensions(int width, int height, boolean multipleWidgetsAllowed) {
public void setHandlerDimensions(int width, int height) {
this.height = height;
this.width = width;
this.multipleWidgetsAllowed = multipleWidgetsAllowed;
}
public boolean setItem(String itemId, String nbtString) {
@@ -102,6 +105,10 @@ public class HandlerInfo {
return this.multipleWidgetsAllowed ? Integer.MAX_VALUE : 1;
}
public void setMultipleWidgetsAllowed(boolean multipleWidgetsAllowed) {
this.multipleWidgetsAllowed = multipleWidgetsAllowed;
}
public boolean isMultipleWidgetsAllowed() {
return this.multipleWidgetsAllowed;
}
@@ -138,12 +145,34 @@ public class HandlerInfo {
this.showOverlayButton = showOverlayButton;
}
public boolean getUseCustomScroll() {
return this.useCustomScroll;
public boolean getShowBadge() {
return this.showBadge;
}
public void setShowBadge(boolean showBadge) {
this.showBadge = showBadge;
}
@Deprecated
public void setUseCustomScroll(boolean useCustomScroll) {
this.useCustomScroll = useCustomScroll;
this.allowOverflowX = useCustomScroll;
this.allowOverflowY = useCustomScroll;
}
public boolean isAllowOverflowX() {
return this.allowOverflowX;
}
public void setAllowOverflowX(boolean allowOverflowX) {
this.allowOverflowX = allowOverflowX;
}
public boolean isAllowOverflowY() {
return this.allowOverflowY;
}
public void setAllowOverflowY(boolean allowOverflowY) {
this.allowOverflowY = allowOverflowY;
}
public static class Builder {
@@ -182,6 +211,7 @@ public class HandlerInfo {
return this;
}
@Deprecated
public Builder setUseCustomScroll(boolean useCustomScroll) {
this.info.setUseCustomScroll(useCustomScroll);
return this;
@@ -212,6 +242,11 @@ public class HandlerInfo {
return this;
}
public Builder setShowBadge(boolean showBadge) {
this.info.showBadge = showBadge;
return this;
}
@Deprecated
public Builder setMaxRecipesPerPage(int maxRecipesPerPage) {
this.info.multipleWidgetsAllowed = maxRecipesPerPage > 1;
@@ -223,6 +258,16 @@ public class HandlerInfo {
return this;
}
public Builder setAllowOverflowX(boolean allowOverflowX) {
this.info.allowOverflowX = allowOverflowX;
return this;
}
public Builder setAllowOverflowY(boolean allowOverflowY) {
this.info.allowOverflowY = allowOverflowY;
return this;
}
public HandlerInfo build() {
return this.info;
}
@@ -1,5 +1,6 @@
package codechicken.nei.recipe;
import java.util.Collections;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
@@ -82,15 +83,38 @@ public interface IRecipeHandler {
* @return A list of the other {@link PositionedStack}s in this recipe relative to the top left corner of your
* recipe drawing space. For example fuel in furnaces.
*/
default List<PositionedStack> getCatalystStacks(int recipe) {
return Collections.emptyList();
}
/**
* Legacy API, define either {@link #getCatalystStacks(int)} or {@link #getResultStacks(int)}
*
* @param recipe The recipe index to get items for.
* @return A list of the other {@link PositionedStack}s in this recipe relative to the top left corner of your
* recipe drawing space. For example fuel in furnaces.
*/
List<PositionedStack> getOtherStacks(int recipe);
/**
* Legacy API, use {@link #getResultStacks(int) getResultStacks.get(0)} if you want the primary result
*
* @param recipe The recipe index to get the result for.
* @return The recipe result {@link PositionedStack} relative to the top left corner of your recipe drawing space.
*/
PositionedStack getResultStack(int recipe);
/**
*
* @param recipe The recipe index to get the result for.
* @return A list of the result {@link PositionedStack}s relative to the top left corner of your recipe drawing
* space.
*/
default List<PositionedStack> getResultStacks(int recipe) {
final PositionedStack result = getResultStack(recipe);
return result != null ? Collections.singletonList(result) : Collections.emptyList();
}
/**
* A tick function called for updating progress bars and cycling damage items.
*/
@@ -6,6 +6,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.function.Function;
import java.util.stream.Stream;
@@ -21,8 +22,9 @@ 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.LayoutManager;
import codechicken.nei.KeyManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIServerUtils;
@@ -33,13 +35,16 @@ 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;
import it.unimi.dsi.fastutil.longs.LongArraySet;
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;
@@ -51,6 +56,9 @@ public class NEIRecipeWidget extends Widget {
protected boolean showAsWidget = false;
protected List<GuiRecipeButton> recipeButtons = null;
// Handles re-draws for catalysts-outputs duplication to preserve full backward compatibility for otherStacks
private final Set<Long> drawnSlots = new LongArraySet();
public NEIRecipeWidget(RecipeHandlerRef handlerRef) {
this.handlerRef = handlerRef;
this.handlerInfo = GuiRecipeTab.getHandlerInfo(this.handlerRef.handler);
@@ -64,7 +72,7 @@ public class NEIRecipeWidget extends Widget {
public void update() {
if (this.showAsWidget || !this.handlerInfo.getUseCustomScroll()) {
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();
@@ -127,23 +135,23 @@ public class NEIRecipeWidget extends Widget {
final UpdateRecipeButtonsEvent.Post postEvent = new UpdateRecipeButtonsEvent.Post(
guiRecipe,
this,
getDefatulButtons());
getDefaultButtons());
MinecraftForge.EVENT_BUS.post(postEvent);
return postEvent.buttonList;
}
} else {
return getDefatulButtons();
return getDefaultButtons();
}
}
protected List<GuiRecipeButton> getDefatulButtons() {
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(168, this.w) - GuiRecipeButton.BUTTON_WIDTH;
final int x = Math.min(166, this.w) - GuiRecipeButton.BUTTON_WIDTH;
int y = this.h - GuiRecipeButton.BUTTON_HEIGHT - 6;
if (guiContainer instanceof IGuiContainerOverlay overlay) {
@@ -169,7 +177,7 @@ public class NEIRecipeWidget extends Widget {
if (this.update) {
this.update = false;
if (!NEIClientUtils.shiftKey() && (this.cycleticks++) / 20 != this.lastcycle || this.lastcycle == -1) {
if (!NEIClientUtils.shiftKey() && ((this.cycleticks++) / 20) != this.lastcycle || this.lastcycle == -1) {
this.lastcycle = this.cycleticks / 20;
updatePermutations();
}
@@ -190,38 +198,38 @@ public class NEIRecipeWidget extends Widget {
GuiContainerManager.enableMatrixStackLogging();
for (PositionedStack pStack : getInputs()) {
final List<PositionedStack> inputs = getInputs();
final List<PositionedStack> catalysts = getCatalysts();
final List<PositionedStack> outputs = getOutputs();
drawnSlots.clear();
for (PositionedStack pStack : inputs) {
drawnSlots.add(slotKey(pStack));
drawItem(pStack, mouseX, mouseY, yShift, false);
}
for (PositionedStack pStack : catalysts) {
if (!drawnSlots.add(slotKey(pStack))) {
continue;
}
if (!this.permutations.containsKey(pStack)) {
updatePermutationsFor(pStack);
}
GuiContainerManager.drawItem(pStack.relx, pStack.rely, pStack.item);
if (pStack.contains(mouseX - this.x, mouseY - this.y - yShift)) {
NEIClientUtils.gl2DRenderContext(() -> GuiDraw.drawRect(pStack.relx, pStack.rely, 16, 16, 0x80FFFFFF));
}
drawItem(pStack, mouseX, mouseY, yShift, true);
}
for (PositionedStack pStack : getCatalysts()) {
for (PositionedStack pStack : outputs) {
if (!drawnSlots.add(slotKey(pStack))) {
continue;
}
if (!this.permutations.containsKey(pStack)) {
updatePermutationsFor(pStack);
}
GuiContainerManager.drawItem(pStack.relx, pStack.rely, pStack.item);
if (pStack.contains(mouseX - this.x, mouseY - this.y - yShift)) {
NEIClientUtils.gl2DRenderContext(() -> GuiDraw.drawRect(pStack.relx, pStack.rely, 16, 16, 0x80FFFFFF));
}
}
for (PositionedStack pStack : getOutputs()) {
GuiContainerManager.drawItem(pStack.relx, pStack.rely, pStack.item);
if (pStack.contains(mouseX - this.x, mouseY - this.y - yShift)) {
NEIClientUtils.gl2DRenderContext(() -> GuiDraw.drawRect(pStack.relx, pStack.rely, 16, 16, 0x80FFFFFF));
}
drawItem(pStack, mouseX, mouseY, yShift, true);
}
GuiContainerManager.disableMatrixStackLogging();
@@ -252,14 +260,67 @@ public class NEIRecipeWidget extends Widget {
}
}
LayoutManager.recipeHandlerWidget.drawGuiPlaceholder(this);
DebugHandlerWidget.instance.drawGuiPlaceholder(this);
}
private static long slotKey(PositionedStack pStack) {
return ((long) pStack.relx << 32) ^ (pStack.rely & 0xFFFFFFFFL);
}
protected void drawItem(PositionedStack pStack, int mouseX, int mouseY, int yShift, boolean input) {
GuiContainerManager.drawItem(pStack.relx, pStack.rely, pStack.item);
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, 16, 16, 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, 16, 16));
}
}
@Override
public boolean handleKeyPress(int keyID, char keyChar) {
if (NEIClientConfig.favoritesEnabled() && NEIClientUtils.shiftKey()
&& NEIClientConfig.isKeyHashDown("gui.favorite_item")) {
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;
@@ -366,30 +427,25 @@ public class NEIRecipeWidget extends Widget {
tooltip = this.handlerRef.handler.handleItemTooltip(guiRecipe, itemstack, tooltip, this.handlerRef.recipeIndex);
if (NEIClientConfig.showCycledIngredientsTooltip() && itemstack != null) {
final int yShift = this.handlerInfo.getYShift();
PositionedStack hovered = null;
if (itemstack != null) {
final PositionedStack hovered = getPositionedStackMouseOver(mousex, mousey);
for (PositionedStack pStack : getInputs()) {
if (pStack.contains(mousex - this.x, mousey - this.y - yShift)) {
hovered = pStack;
break;
}
}
if (hovered != null && this.handlerInfo.getShowBadge()) {
final List<Badge> badges = getBadges(hovered, getOutputs().indexOf(hovered) == -1);
if (hovered == null) {
for (PositionedStack pStack : getCatalysts()) {
if (pStack.contains(mousex - this.x, mousey - this.y - yShift)) {
hovered = pStack;
for (Badge badge : badges) {
if (badge.getTooltip() != null && !badge.getTooltip().isEmpty()) {
tooltip.addAll(badge.getTooltip());
}
}
}
if (hovered == null || hovered.items.length <= 1) {
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.permutations.getOrDefault(hovered, Collections.emptyList()).size() > 1) {
} else if (this.acceptsFollowingTooltipLineHandler == null
|| this.acceptsFollowingTooltipLineHandler.tooltipGUID != hovered) {
this.acceptsFollowingTooltipLineHandler = AcceptsFollowingTooltipLineHandler
.of(hovered, this.permutations.get(hovered), hovered.item);
}
@@ -423,7 +479,7 @@ public class NEIRecipeWidget extends Widget {
pStack -> this.permutations.getOrDefault(pStack, Collections.emptyList()).size() > 1
&& pStack.contains(mouseX - this.x, mouseY - this.y - yShift))) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.favorite_item", NEIClientUtils.SHIFT_HASH),
KeyManager.getKeyName("bookmark.favorite_item", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("recipe.favorite.toggle"));
}
@@ -568,6 +624,7 @@ public class NEIRecipeWidget extends Widget {
this.acceptsFollowingTooltipLineHandler = null;
this.favoriteIndexes.clear();
this.permutations.clear();
this.badgeCache.clear();
}
for (PositionedStack pStack : getInputs()) {
@@ -588,6 +645,7 @@ public class NEIRecipeWidget extends Widget {
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();
@@ -602,9 +660,10 @@ public class NEIRecipeWidget extends Widget {
this.permutations.put(pStack, perms);
this.favoriteIndexes.put(pStack, favoriteIndex);
needsUpdate = true;
}
if (perms.size() > 1) {
if (perms.size() > 1 || needsUpdate) {
final int size = favoriteIndex != -1 ? favoriteIndex + 1 : perms.size();
if (size > 0) {
@@ -618,13 +677,19 @@ public class NEIRecipeWidget extends Widget {
}
protected List<PositionedStack> getOutputs() {
final PositionedStack pStackResult = this.handlerRef.handler.getResultStack(this.handlerRef.recipeIndex);
return pStackResult != null ? Arrays.asList(pStackResult)
final List<PositionedStack> pStackResults = this.handlerRef.handler
.getResultStacks(this.handlerRef.recipeIndex);
return !pStackResults.isEmpty() ? pStackResults
: this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex);
}
protected List<PositionedStack> getCatalysts() {
if (this.handlerRef.handler.getResultStack(this.handlerRef.recipeIndex) == null) {
List<PositionedStack> catalysts = this.handlerRef.handler.getCatalystStacks(this.handlerRef.recipeIndex);
if (!catalysts.isEmpty()) {
return catalysts;
}
if (this.handlerRef.handler.getResultStacks(this.handlerRef.recipeIndex).isEmpty()) {
return Collections.emptyList();
}
return this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex);
@@ -1,16 +1,25 @@
package codechicken.nei.recipe;
import static codechicken.lib.gui.GuiDraw.drawString;
import static codechicken.lib.gui.GuiDraw.getStringWidth;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.inventory.Container;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import codechicken.core.TaskProfiler.ProfilerResult;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ColorUtils;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PositionedStack;
@@ -20,12 +29,104 @@ import codechicken.nei.util.AsyncTaskProfiler;
public class ProfilerRecipeHandler implements ICraftingHandler, IUsageHandler {
private static final AsyncTaskProfiler profiler = new AsyncTaskProfiler();
public static class RecipeProfiler {
private final AsyncTaskProfiler profiler = new AsyncTaskProfiler();
private final Map<String, IRecipeHandler> handlerMap = new ConcurrentHashMap<>();
private final AtomicInteger idCounter = new AtomicInteger(0);
private boolean isProfiling = false;
public <T extends IRecipeHandler> ArrayList<T> start(String profilerSection, Supplier<ArrayList<T>> callback) {
profilerInfos.clear();
this.handlerMap.clear();
this.idCounter.set(0);
if (NEIClientConfig.isProfileRecipeEnabled()) {
this.profiler.clear();
this.profiler.start(EnumChatFormatting.getTextWithoutFormattingCodes(profilerSection));
this.isProfiling = true;
try {
return callback.get();
} finally {
this.profiler.end();
this.isProfiling = false;
final List<ProfilerResult> results = this.profiler.getResults();
results.sort(
Comparator.comparingLong((ProfilerResult profilerResult) -> profilerResult.time)
.reversed());
for (ProfilerResult profilerResult : results) {
profilerInfos.add(new ProfilerInfo(handlerMap.get(profilerResult.name), profilerResult));
}
}
} else {
return callback.get();
}
}
public <T extends IRecipeHandler> T profile(T handler, Supplier<T> callback) {
if (this.isProfiling && !(handler instanceof ProfilerRecipeHandler)) {
final String id = String.valueOf(idCounter.incrementAndGet());
this.handlerMap.put(id, handler);
this.profiler.clearCurrent();
this.profiler.start(id);
try {
T result = callback.get();
if (result != null) {
this.handlerMap.put(id, result);
}
return result;
} finally {
this.profiler.end();
}
} else {
return callback.get();
}
}
public static AsyncTaskProfiler getProfiler() {
return profiler;
}
protected static class ProfilerInfo {
public final String modName;
public final IRecipeHandler handler;
public final List<String> tooltip = new ArrayList<>();
public final String title;
public final String time;
public ProfilerInfo(IRecipeHandler handler, ProfilerResult result) {
this.handler = handler;
this.time = (result.time < 1_000_000 ? (result.time / 1_000) + "us" : (result.time / 1_000_000) + "ms");
if (handler == null) {
this.title = result.name;
this.modName = "Unknown";
} else {
final HandlerInfo handlerInfo = GuiRecipeTab.getHandlerInfo(handler);
final String handlerName = handlerInfo != null ? handlerInfo.getHandlerName() : "Unknown";
this.title = EnumChatFormatting.getTextWithoutFormattingCodes(handler.getRecipeName());
this.modName = handlerInfo != null ? handlerInfo.getModName() : "Unknown";
this.tooltip.add(EnumChatFormatting.GRAY + "HandlerName: " + handlerName);
this.tooltip.add(EnumChatFormatting.GRAY + "HandlerID: " + handler.getOverlayIdentifier());
this.tooltip.add(EnumChatFormatting.GRAY + "HandlerOrder: " + NEIClientConfig.getHandlerOrder(handler));
}
}
}
public static final RecipeProfiler recipeProfiler = new RecipeProfiler();
protected static final List<ProfilerInfo> profilerInfos = new ArrayList<>();
private static final int WIDTH = 166;
private final boolean crafting;
public ProfilerRecipeHandler(boolean crafting) {
@@ -39,11 +140,7 @@ public class ProfilerRecipeHandler implements ICraftingHandler, IUsageHandler {
@Override
public int numRecipes() {
if (!NEIClientConfig.isProfileRecipeEnabled()) return 0;
return (int) Math.ceil(
((crafting ? GuiCraftingRecipe.craftinghandlers.size() : GuiUsageRecipe.usagehandlers.size()) - 1)
/ 6D);
return NEIClientConfig.isProfileRecipeEnabled() ? Math.max(1, profilerInfos.size()) : 0;
}
@Override
@@ -51,21 +148,32 @@ public class ProfilerRecipeHandler implements ICraftingHandler, IUsageHandler {
@Override
public void drawForeground(int recipe) {
List<ProfilerResult> results = profiler.getResults();
results.removeIf(profilerResult -> getRecipeName().equals(profilerResult.name));
if (recipe >= profilerInfos.size()) return;
results.sort((o1, o2) -> o1.time < o2.time ? 1 : -1);
final ProfilerInfo info = profilerInfos.get(recipe);
final int valueWidth = getStringWidth(info.time);
final IRecipeHandler handler = info.handler;
final boolean hovered = handler != null && handler.numRecipes() > 0
&& isHandlerTitleHovered(recipe, GuiDraw.getMousePosition());
for (int i = recipe * 6; i < results.size() && i < (recipe + 1) * 6; i++) {
ProfilerResult r = results.get(i);
int y = (i % 6) * 20 + 6;
drawString(r.name, 8, y, 0xFF808080, false);
GuiDraw.drawString(
NEIClientUtils.cropText(GuiDraw.fontRenderer, info.title, WIDTH - valueWidth - 2),
0,
3,
hovered ? 0xFFFFDD00 : 0xFF808080,
false);
GuiDraw.drawString(info.time, WIDTH - valueWidth, 3, ColorUtils.textGray.getColor(), false);
}
String s;
if (r.time < 1000000L) s = (r.time / 1000) + "us";
else s = (r.time / 1000000) + "ms";
private boolean isHandlerTitleHovered(int recipe, Point mouse) {
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
drawString(s, 156 - getStringWidth(s), y + 10, 0xFF404040, false);
if (guiContainer instanceof GuiRecipe guiRecipe) {
final Point recipePosition = guiRecipe.getRecipePosition(recipe);
return new Rectangle(recipePosition.x, recipePosition.y, WIDTH, 16)
.contains(mouse.x - guiContainer.guiLeft, mouse.y - guiContainer.guiTop);
} else {
return false;
}
}
@@ -104,6 +212,22 @@ public class ProfilerRecipeHandler implements ICraftingHandler, IUsageHandler {
@Override
public List<String> handleTooltip(GuiRecipe<?> gui, List<String> currenttip, int recipe) {
if (recipe >= profilerInfos.size()) return currenttip;
final ProfilerInfo r = profilerInfos.get(recipe);
currenttip.add(r.title + ": " + r.time);
if (r.handler != null) {
currenttip.add(EnumChatFormatting.GRAY + "Recipes: " + r.handler.numRecipes() + GuiDraw.TOOLTIP_LINESPACE);
if (NEIClientUtils.shiftKey()) {
currenttip.addAll(r.tooltip);
}
currenttip.add(EnumChatFormatting.BLUE + r.modName);
}
return currenttip;
}
@@ -119,6 +243,23 @@ public class ProfilerRecipeHandler implements ICraftingHandler, IUsageHandler {
@Override
public boolean mouseClicked(GuiRecipe<?> gui, int button, int recipe) {
if (recipe >= profilerInfos.size()) return false;
final ProfilerInfo r = profilerInfos.get(recipe);
if (r.handler != null) {
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
if (guiContainer instanceof GuiRecipe guiRecipe) {
int index = guiRecipe.currenthandlers.indexOf(r.handler);
if (index != -1) {
guiRecipe.setRecipePage(index);
return true;
}
}
}
return false;
}
@@ -54,19 +54,26 @@ public class Recipe {
public static RecipeId of(IRecipeHandler handler, int recipeIndex) {
final List<PositionedStack> ingredients = handler.getIngredientStacks(recipeIndex);
final String handlerName = GuiRecipeTab.getHandlerInfo(handler).getHandlerName();
PositionedStack pStackResult = handler.getResultStack(recipeIndex);
// Use getResultStacks even though getResult could work because if a handler, like GT for example, doesn't
// return anything from getResult, but will define all the outputs in getResultStacks we can still pick up
// the results here. If a handler still doesn't define getResultStacks, then it will naturally fall back to
// getResult anyway
List<PositionedStack> pStackResults = handler.getResultStacks(recipeIndex);
if (pStackResult == null) {
if (pStackResults.isEmpty()) {
for (PositionedStack otherStack : handler.getOtherStacks(recipeIndex)) {
if (!FluidContainerRegistry.isContainer(otherStack.items[0])
|| StackInfo.getFluid(otherStack.items[0]) != null) {
pStackResult = otherStack;
pStackResults.add(otherStack);
break;
}
}
}
return new RecipeId(extractItem(pStackResult), handlerName, extractIngredients(ingredients));
return new RecipeId(
extractItem(!pStackResults.isEmpty() ? pStackResults.get(0) : null),
handlerName,
extractIngredients(ingredients));
}
public static RecipeId of(JsonObject json) {
@@ -89,7 +96,7 @@ public class Recipe {
return new RecipeId(result, handlerName, ingredients);
}
public String getHandleName() {
public String getHandlerName() {
return this.handlerName;
}
@@ -282,17 +289,20 @@ public class Recipe {
protected final ItemStack[] items;
protected int activeIndex = 0;
protected int amount = 0;
protected int chance = PositionedStack.CHANCE_FULL;
protected int relx;
protected int rely;
public RecipeIngredient(int relx, int rely, List<ItemStack> items, int activeIndex) {
public RecipeIngredient(int relx, int rely, List<ItemStack> items, int chance, int activeIndex) {
this.items = items.stream().map(ItemStack::copy).toArray(size -> new ItemStack[size]);
this.amount = StackInfo.getAmount(this.items[activeIndex]);
this.activeIndex = activeIndex;
this.relx = relx;
this.rely = rely;
this.chance = chance;
}
public static RecipeIngredient of(PositionedStack positionedStack) {
@@ -311,17 +321,21 @@ public class Recipe {
}
}
return of(positionedStack.relx, positionedStack.rely, stacks, activeIndex);
return of(positionedStack.relx, positionedStack.rely, stacks, positionedStack.getChance(), activeIndex);
}
public static RecipeIngredient of(int relx, int rely, List<ItemStack> stacks, int activeIndex) {
return new RecipeIngredient(relx, rely, stacks, activeIndex);
public static RecipeIngredient of(int relx, int rely, List<ItemStack> stacks, int chance, int activeIndex) {
return new RecipeIngredient(relx, rely, stacks, chance, activeIndex);
}
public int getAmount() {
return this.amount;
}
public int getChance() {
return this.chance;
}
public ItemStack getItemStack() {
return this.items[this.activeIndex];
}
@@ -348,11 +362,16 @@ public class Recipe {
return this;
}
public void setChance(int chance) {
this.chance = chance;
}
public RecipeIngredient copy() {
return new RecipeIngredient(
this.relx,
this.rely,
getPermutations().stream().map(ItemStack::copy).collect(Collectors.toList()),
this.chance,
this.activeIndex);
}
}
@@ -377,8 +396,12 @@ public class Recipe {
ingredients.add(RecipeIngredient.of(positionedStack));
}
if (handler.getResultStack(recipeIndex) != null) {
results.add(RecipeIngredient.of(handler.getResultStack(recipeIndex)));
final List<PositionedStack> resultStacks = handler.getResultStacks(recipeIndex);
if (!resultStacks.isEmpty()) {
for (PositionedStack positionedStack : resultStacks) {
results.add(RecipeIngredient.of(positionedStack));
}
} else {
for (PositionedStack positionedStack : handler.getOtherStacks(recipeIndex)) {
results.add(RecipeIngredient.of(positionedStack));
@@ -435,7 +458,7 @@ public class Recipe {
}
if (item instanceof ItemStack stack) {
return RecipeIngredient.of(0, 0, Arrays.asList(stack), 0);
return RecipeIngredient.of(0, 0, Arrays.asList(stack), PositionedStack.CHANCE_FULL, 0);
}
if (item instanceof RecipeIngredient ingr) {
@@ -12,10 +12,8 @@ import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IChatComponent;
import codechicken.core.TaskProfiler;
import codechicken.nei.ItemList;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.util.AsyncTaskProfiler;
public class RecipeHandlerQuery<T extends IRecipeHandler> {
@@ -34,30 +32,22 @@ public class RecipeHandlerQuery<T extends IRecipeHandler> {
}
public ArrayList<T> runWithProfiling(String profilerSection) {
TaskProfiler profiler = ProfilerRecipeHandler.getProfiler();
return ProfilerRecipeHandler.recipeProfiler.start(profilerSection, () -> {
// Save the current config state here, as it may be altered
// if getRecipeHandlesParallel took so long and player accidentally changed config.
boolean profileRecipes = NEIClientConfig.isProfileRecipeEnabled();
if (profileRecipes) {
profiler.clear();
profiler.start(profilerSection);
}
try {
ArrayList<T> handlers = getRecipeHandlersParallel();
try {
ArrayList<T> handlers = getRecipeHandlersParallel();
if (error) {
if (error) {
displayRecipeLookupError();
}
return handlers;
} catch (InterruptedException | ExecutionException e) {
printLog(e);
displayRecipeLookupError();
return new ArrayList<>(0);
}
return handlers;
} catch (InterruptedException | ExecutionException e) {
printLog(e);
displayRecipeLookupError();
return new ArrayList<>(0);
} finally {
if (profileRecipes) profiler.end();
}
});
}
private ArrayList<T> getRecipeHandlersParallel() throws InterruptedException, ExecutionException {
@@ -77,40 +67,42 @@ public class RecipeHandlerQuery<T extends IRecipeHandler> {
private ArrayList<T> getSerialHandlersWithRecipes() {
return serialRecipeHandlers.stream().map(handler -> {
AsyncTaskProfiler profiler = ProfilerRecipeHandler.getProfiler();
profiler.clearCurrent();
profiler.start(handler.getRecipeName());
try {
return isHidden(handler) ? null : recipeHandlerFunction.apply(handler);
} catch (Throwable t) {
printLog(t);
error = true;
return null;
} finally {
profiler.end();
}
}).filter(h -> h != null && h.numRecipes() > 0 && SearchRecipeHandler.findFirst(h, (recipeIndex) -> true) != -1)
return serialRecipeHandlers.stream()
.map(handler -> ProfilerRecipeHandler.recipeProfiler.profile(handler, () -> {
try {
return isHidden(handler) ? null : recipeHandlerFunction.apply(handler);
} catch (Throwable t) {
printLog(t);
error = true;
return null;
}
}))
.filter(
h -> h != null && h.numRecipes() > 0
&& SearchRecipeHandler.findFirst(h, (recipeIndex) -> true) != -1)
.collect(Collectors.toCollection(ArrayList::new));
}
private ArrayList<T> getHandlersWithRecipes() throws InterruptedException, ExecutionException {
return ItemList.forkJoinPool.submit(() -> recipeHandlers.parallelStream().map(handler -> {
AsyncTaskProfiler profiler = ProfilerRecipeHandler.getProfiler();
profiler.clearCurrent();
profiler.start(handler.getRecipeName());
try {
return isHidden(handler) ? null : recipeHandlerFunction.apply(handler);
} catch (Throwable t) {
printLog(t);
error = true;
return null;
} finally {
profiler.end();
}
}).filter(h -> h != null && h.numRecipes() > 0 && SearchRecipeHandler.findFirst(h, (recipeIndex) -> true) != -1)
.collect(Collectors.toCollection(ArrayList::new))).get();
return ItemList.forkJoinPool.submit(
() -> recipeHandlers.parallelStream()
.map(handler -> ProfilerRecipeHandler.recipeProfiler.profile(handler, () -> {
try {
return isHidden(handler) ? null : recipeHandlerFunction.apply(handler);
} catch (Throwable t) {
printLog(t);
error = true;
return null;
}
}))
.filter(
h -> h != null && h.numRecipes() > 0
&& SearchRecipeHandler.findFirst(h, (recipeIndex) -> true) != -1)
.collect(Collectors.toCollection(ArrayList::new)))
.get();
}
private boolean isHidden(T handler) {
@@ -77,9 +77,24 @@ public class RecipeHandlerRef {
return this.handler.getOverlayHandler(firstGui, this.recipeIndex);
}
if (firstGui != null && canUseSmartOverlay(firstGui)) {
return SmartOverlayHandler.INSTANCE;
}
return null;
}
private boolean canUseSmartOverlay(GuiContainer gui) {
if (!(this.handler instanceof TemplateRecipeHandler templateHandler)
|| templateHandler.getOverlayIdentifier() == null
|| templateHandler.getGuiClass() == null
|| !templateHandler.getGuiClass().isAssignableFrom(gui.getClass())) {
return false;
}
return SmartOverlayHandler.canHandle(gui, this.handler, this.recipeIndex);
}
public boolean canFillCraftingGrid(GuiContainer gui) {
final IOverlayHandler overlayHandler = getOverlayHandler(gui);
@@ -4,16 +4,11 @@ import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
import net.minecraft.client.gui.inventory.GuiBrewingStand;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.gui.inventory.GuiCrafting;
import net.minecraft.client.gui.inventory.GuiFurnace;
import net.minecraft.client.gui.inventory.GuiInventory;
import com.google.common.base.Objects;
import codechicken.nei.OffsetPositioner;
import codechicken.nei.api.API;
import codechicken.nei.api.IOverlayHandler;
import codechicken.nei.api.IStackPositioner;
@@ -96,33 +91,4 @@ public class RecipeInfo {
return offset == null ? new int[] { 5, 11 } : offset;
}
public static void load() {
API.registerRecipeHandler(new ShapedRecipeHandler());
API.registerUsageHandler(new ShapedRecipeHandler());
API.registerRecipeHandler(new ShapelessRecipeHandler());
API.registerUsageHandler(new ShapelessRecipeHandler());
API.registerRecipeHandler(new FireworkRecipeHandler());
API.registerUsageHandler(new FireworkRecipeHandler());
API.registerRecipeHandler(new FurnaceRecipeHandler());
API.registerUsageHandler(new FurnaceRecipeHandler());
API.registerRecipeHandler(new BrewingRecipeHandler());
API.registerUsageHandler(new BrewingRecipeHandler());
API.registerRecipeHandler(new FuelRecipeHandler());
API.registerUsageHandler(new FuelRecipeHandler());
API.registerRecipeHandler(new InformationHandler());
API.registerUsageHandler(new InformationHandler());
API.registerGuiOverlay(GuiCrafting.class, "crafting");
API.registerGuiOverlay(GuiInventory.class, "crafting2x2", 63, 20);
API.registerGuiOverlay(GuiFurnace.class, "smelting");
API.registerGuiOverlay(GuiFurnace.class, "fuel");
API.registerGuiOverlay(GuiBrewingStand.class, "brewing");
API.registerGuiOverlayHandler(GuiCrafting.class, new DefaultOverlayHandler(), "crafting");
API.registerGuiOverlayHandler(GuiInventory.class, new DefaultOverlayHandler(63, 20), "crafting2x2");
API.registerGuiOverlayHandler(GuiBrewingStand.class, new BrewingOverlayHandler(), "brewing");
API.registerRecipeHandler(new ProfilerRecipeHandler(true));
API.registerUsageHandler(new ProfilerRecipeHandler(false));
}
}
@@ -42,10 +42,10 @@ public class RecipePageManager {
this.cacheKey = cacheKey;
this.pageWidgets.clear();
final boolean useCustomScroll = this.handlerInfo.getUseCustomScroll();
final boolean allowOverflowY = this.handlerInfo.isAllowOverflowY();
final int handlerHeight = this.handlerInfo.getHeight() + this.handlerInfo.getYShift();
final boolean multipleWidgetsAllowed = !useCustomScroll && handlerInfo.isMultipleWidgetsAllowed();
final boolean infiniteScroll = !useCustomScroll
final boolean multipleWidgetsAllowed = !allowOverflowY && handlerInfo.isMultipleWidgetsAllowed();
final boolean infiniteScroll = !allowOverflowY
&& NEIClientConfig.getBooleanSetting("inventory.guirecipe.infiniteScroll");
final int heightAvailable = this.container.getVisibleHeight();
@@ -59,7 +59,7 @@ public class RecipePageManager {
final NEIRecipeWidget widget = RecipeHandlerRef.of(this.handler.original, recipeIndex).getRecipeWidget();
widget.w = width;
if (useCustomScroll) {
if (allowOverflowY) {
widget.h = Math.min(handlerHeight, heightAvailable);
}
@@ -84,7 +84,7 @@ public class RecipePageManager {
}
public boolean isMultipleWidgetsAllowed() {
return !this.handlerInfo.getUseCustomScroll() && this.handlerInfo.isMultipleWidgetsAllowed();
return !this.handlerInfo.isAllowOverflowY() && this.handlerInfo.isMultipleWidgetsAllowed();
}
public int getNumRecipes() {
Loaded 100 of 136 files, more files were not shown because too many files have changed in this diff. Show more