diff --git a/changelog.md b/changelog.md
index ebe24bbc..d7a075f7 100644
--- a/changelog.md
+++ b/changelog.md
@@ -16,7 +16,8 @@ Changes
- Redid Bank Terminal texture to match other Create textures
- You can now insert or extract items from all sides of a vendor
- The buying/selling item slot in the vendor gui now acts like a ghost item (does not require actual items).
- Backwards compatible with existing vendors, so the items will remain 'real' until you remove them
+ Backwards compatible with existing vendors, so the items will remain 'real' until you remove them.
+ Additionally, enchantments and dyes can be applied to some items by shift-dragging items when using EMI on fabric or JEI on forge
------------------------------------------------------
Numismatics 1.0.6
------------------------------------------------------
diff --git a/common/src/generated/resources/.cache/630af4bded938901e0e1fd57c58a2ac245292828 b/common/src/generated/resources/.cache/630af4bded938901e0e1fd57c58a2ac245292828
index 94b2507f..889e8118 100644
--- a/common/src/generated/resources/.cache/630af4bded938901e0e1fd57c58a2ac245292828
+++ b/common/src/generated/resources/.cache/630af4bded938901e0e1fd57c58a2ac245292828
@@ -1,4 +1,4 @@
-// 1.20.1 2024-07-21T20:22:37.447106096 Create: Numismatics/Numismatics' Advancements
+// 1.20.1 2024-07-24T07:41:10.619577249 Create: Numismatics/Numismatics' Advancements
4ab84595dc44460d6d89ff3608940dd8694b93d6 data/numismatics/advancements/is_this_legal.json
645c92e6e449889ed4cf617432fd6fa87ffe355b data/numismatics/advancements/questionable_investment.json
8f32fb49ef81058e2e660fac983dbef2f554db38 data/numismatics/advancements/root.json
diff --git a/common/src/generated/resources/.cache/6ba62358bf8e130d42215f5f9edbedd611809677 b/common/src/generated/resources/.cache/6ba62358bf8e130d42215f5f9edbedd611809677
index 22a184de..e18bfd25 100644
--- a/common/src/generated/resources/.cache/6ba62358bf8e130d42215f5f9edbedd611809677
+++ b/common/src/generated/resources/.cache/6ba62358bf8e130d42215f5f9edbedd611809677
@@ -1,4 +1,4 @@
-// 1.20.1 2024-07-21T20:22:37.445651836 Create: Numismatics/Numismatics Standard Recipes
+// 1.20.1 2024-07-24T07:41:10.617662486 Create: Numismatics/Numismatics Standard Recipes
0e1680b878cfa51c04809504b3542cb6312027a1 data/numismatics/recipes/crafting/gray_id_card.json
61954216f844eecdbee266da7e517a983993d2f8 data/numismatics/advancements/recipes/misc/crafting/brown_card.json
2c732f9c3bc02a29a4d86a0552f4dbbae986a34a data/numismatics/recipes/crafting/blue_authorized_card.json
@@ -21,8 +21,8 @@ a9acb103fdf3c06e561b7252083fae594074ba40 data/numismatics/advancements/recipes/m
da540ae92c84519149c1b37ad49290814f507a8a data/numismatics/advancements/recipes/misc/crafting/white_authorized_card.json
12014c6c5ac12fdddc45d61bdb3841e2f930125d data/numismatics/recipes/crafting/red_card.json
858305a3537cdcb5bb19b883e688ddb876f0473c data/numismatics/recipes/crafting/brown_id_card.json
-ce32a3a7c2a5564e84b30bb1b71007ca4adc985d data/numismatics/recipes/crafting/lime_authorized_card.json
35d3c0460a2ba41603bea8e1453b26d662a1f2d5 data/numismatics/advancements/recipes/misc/crafting/yellow_authorized_card.json
+ce32a3a7c2a5564e84b30bb1b71007ca4adc985d data/numismatics/recipes/crafting/lime_authorized_card.json
501f27ee03faeb675a05b63b0c8058f1473f02d5 data/numismatics/advancements/recipes/misc/crafting/purple_id_card.json
8d863132d01d516db98d228e9038425923b7354d data/numismatics/recipes/crafting/black_card.json
78af0a7f17e04133eae7172df3255aaa34034537 data/numismatics/advancements/recipes/misc/crafting/red_id_card.json
diff --git a/common/src/generated/resources/.cache/816056b233c115f7af92c9ed2c207f096721f5cf b/common/src/generated/resources/.cache/816056b233c115f7af92c9ed2c207f096721f5cf
new file mode 100644
index 00000000..7886b3ad
--- /dev/null
+++ b/common/src/generated/resources/.cache/816056b233c115f7af92c9ed2c207f096721f5cf
@@ -0,0 +1,2 @@
+// 1.20.1 2024-07-24T07:41:10.61410668 Create: Numismatics/Numismatics EMI excluded tags
+b57edab6f7e7a6e1b1211daa4c3b217ffd09ce62 assets/emi/tag/exclusions/numismatics.json
diff --git a/common/src/generated/resources/.cache/c6e4c19894bc5aece2976a0277ba8e1dbf023865 b/common/src/generated/resources/.cache/c6e4c19894bc5aece2976a0277ba8e1dbf023865
index aabd1706..2c994166 100644
--- a/common/src/generated/resources/.cache/c6e4c19894bc5aece2976a0277ba8e1dbf023865
+++ b/common/src/generated/resources/.cache/c6e4c19894bc5aece2976a0277ba8e1dbf023865
@@ -1 +1 @@
-// 1.20.1 2024-07-21T20:22:37.446740402 Create: Numismatics/Numismatics' Sequenced Assembly Recipes
+// 1.20.1 2024-07-24T07:41:10.619204352 Create: Numismatics/Numismatics' Sequenced Assembly Recipes
diff --git a/common/src/generated/resources/.cache/d6a1ec2d08c6d6d7facbde77dda6f0158c00bbd6 b/common/src/generated/resources/.cache/d6a1ec2d08c6d6d7facbde77dda6f0158c00bbd6
index 5b875dcc..d327fefb 100644
--- a/common/src/generated/resources/.cache/d6a1ec2d08c6d6d7facbde77dda6f0158c00bbd6
+++ b/common/src/generated/resources/.cache/d6a1ec2d08c6d6d7facbde77dda6f0158c00bbd6
@@ -1,4 +1,4 @@
-// 1.20.1 2024-07-21T20:22:37.442752776 Create: Numismatics/Registrate Provider for numismatics [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)]
+// 1.20.1 2024-07-24T07:41:10.615215734 Create: Numismatics/Registrate Provider for numismatics [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)]
2f1dad2a2e0086d54cf4b88378feacc04341d87f data/numismatics/tags/items/internal/ingots/iron_ingots.json
dc5c60bbbaf3a5d7bc1f9bc0c9377757dbd8de49 data/numismatics/loot_tables/blocks/bank_terminal.json
5b0244502972f49d063d98fa0cb3f6fc65af82b2 data/numismatics/tags/items/internal/string.json
@@ -8,7 +8,7 @@ a96d3d02794064cd9be1bca25a9ba6217675e6c5 assets/numismatics/models/item/white_id
bb2a77462e6213eddde134f3cc3e9a3f07f07f3f assets/numismatics/models/item/yellow_authorized_card.json
74a4c7ca7a48382782e5dba33018dfc8255192c5 assets/numismatics/models/block/brass_depositor_locked.json
3f0d912779200aaaf55bef102d9b96acead1a636 data/numismatics/tags/items/internal/dyes/purple_dyes.json
-60932ebc47cf9e9a14fc5bd8b4f8d30506a1d074 assets/numismatics/lang/en_us.json
+bf4853dab3c317eaaf2f1196def7cda67212b493 assets/numismatics/lang/en_us.json
377e460c0dcf6d7de1b7ae235959105a7c45e4c4 assets/numismatics/models/item/cyan_authorized_card.json
bde18ccd9c21484154597c6271750c0406082f61 data/forge/tags/blocks/relocation_not_supported.json
eca751589c40725750e2c2baa6607e83255fd5f4 assets/numismatics/models/item/brown_authorized_card.json
@@ -18,7 +18,7 @@ ad712dd2a2a7268dfa773f38a50d526952758d5c data/numismatics/tags/items/internal/dy
8550097149cebbfd50bdeac2003327b60a4aee9a assets/numismatics/models/item/light_gray_card.json
95b492bd9230dc90fca9395c823cef39e644d8f2 assets/numismatics/models/item/sprocket.json
70c481f36a9718ac48632e6939ac6ba785be4c9e assets/numismatics/models/item/black_id_card.json
-b6539c792df61fc097c1dc8f843f7c4e9999cb73 assets/numismatics/lang/en_ud.json
+64524e27a031690bba14cf8ea1f1d92e03f2ad54 assets/numismatics/lang/en_ud.json
1e78f650091a4a2c43e36fb815f23d0591e058a6 assets/numismatics/models/item/magenta_card.json
909f5d14f23199c064f6b91a421bb7b15e0f1a7d assets/numismatics/models/item/orange_authorized_card.json
d6f017479b3cc538f73d7fb0a1e65d1742bab266 assets/numismatics/models/item/light_blue_id_card.json
@@ -53,8 +53,8 @@ bde18ccd9c21484154597c6271750c0406082f61 data/c/tags/blocks/relocation_not_suppo
d048d04208faa63f0014d614d6026a66fe118c11 data/numismatics/loot_tables/blocks/brass_depositor.json
790ff3c5da6a67a5de1ceb7138fa3e1c0fe97f80 data/numismatics/tags/items/internal/dyes/lime_dyes.json
a8cb82f19034a0e724e12df45c883e9cd469c210 assets/numismatics/models/item/green_card.json
-e1087e56db7b4d8812ab4617344f0ac8b0f0e6c7 assets/numismatics/models/item/light_gray_authorized_card.json
390db78c5393fca4f90018df51d1a79d11a64f72 assets/numismatics/models/item/light_blue_authorized_card.json
+e1087e56db7b4d8812ab4617344f0ac8b0f0e6c7 assets/numismatics/models/item/light_gray_authorized_card.json
c09892d2d189f147997d77f4ce39b0570729f030 assets/numismatics/models/item/lime_authorized_card.json
06ecd28cd97f4e8200dc396858695cad57b871c8 assets/numismatics/blockstates/blaze_banker.json
95ef415a564eba1d212053195d25b199427b94e3 assets/numismatics/blockstates/creative_vendor.json
diff --git a/common/src/generated/resources/assets/emi/tag/exclusions/numismatics.json b/common/src/generated/resources/assets/emi/tag/exclusions/numismatics.json
new file mode 100644
index 00000000..a0b09462
--- /dev/null
+++ b/common/src/generated/resources/assets/emi/tag/exclusions/numismatics.json
@@ -0,0 +1,31 @@
+{
+ "block": [
+ "numismatics:internal/relocation_not_supported"
+ ],
+ "item": [
+ "numismatics:internal/string",
+ "numismatics:internal/nuggets/iron_nuggets",
+ "numismatics:internal/nuggets/zinc_nuggets",
+ "numismatics:internal/nuggets/brass_nuggets",
+ "numismatics:internal/plates/iron_plates",
+ "numismatics:internal/plates/gold_plates",
+ "numismatics:internal/ingots/copper_ingots",
+ "numismatics:internal/ingots/iron_ingots",
+ "numismatics:internal/dyes/white_dyes",
+ "numismatics:internal/dyes/orange_dyes",
+ "numismatics:internal/dyes/magenta_dyes",
+ "numismatics:internal/dyes/light_blue_dyes",
+ "numismatics:internal/dyes/yellow_dyes",
+ "numismatics:internal/dyes/lime_dyes",
+ "numismatics:internal/dyes/pink_dyes",
+ "numismatics:internal/dyes/gray_dyes",
+ "numismatics:internal/dyes/light_gray_dyes",
+ "numismatics:internal/dyes/cyan_dyes",
+ "numismatics:internal/dyes/purple_dyes",
+ "numismatics:internal/dyes/blue_dyes",
+ "numismatics:internal/dyes/brown_dyes",
+ "numismatics:internal/dyes/green_dyes",
+ "numismatics:internal/dyes/red_dyes",
+ "numismatics:internal/dyes/black_dyes"
+ ]
+}
\ No newline at end of file
diff --git a/common/src/generated/resources/assets/numismatics/lang/en_ud.json b/common/src/generated/resources/assets/numismatics/lang/en_ud.json
index f361ebfb..630b25c0 100644
--- a/common/src/generated/resources/assets/numismatics/lang/en_ud.json
+++ b/common/src/generated/resources/assets/numismatics/lang/en_ud.json
@@ -165,5 +165,12 @@
"numismatics.authorization_type.trusted_players": "ʎןuO sɹǝʎɐןԀ pǝʇsnɹ⟘",
"numismatics.authorization_type.trusted_players.description": "ʇsıן ʇsnɹʇ ǝɥʇ uo sɹǝʎɐןd ʎןuO",
"numismatics.special.ltr": "ǝnɹʇ",
- "numismatics.trust_list.configure": "ʇsıꞀ ʇsnɹ⟘ ǝɹnbıɟuoƆ"
+ "numismatics.trust_list.configure": "ʇsıꞀ ʇsnɹ⟘ ǝɹnbıɟuoƆ",
+ "tag.block.numismatics.numismatics_blocks": "sʞɔoןᗺ sɔıʇɐɯsıɯnN",
+ "tag.item.forge.string": "buıɹʇS",
+ "tag.item.numismatics.authorized_cards": "spɹɐƆ pǝzıɹoɥʇnⱯ",
+ "tag.item.numismatics.cards": "spɹɐƆ",
+ "tag.item.numismatics.coins": "suıoƆ",
+ "tag.item.numismatics.id_cards": "spɹɐƆ pI",
+ "tag.item.numismatics.numismatics_items": "sɯǝʇI sɔıʇɐɯsıɯnN"
}
\ No newline at end of file
diff --git a/common/src/generated/resources/assets/numismatics/lang/en_us.json b/common/src/generated/resources/assets/numismatics/lang/en_us.json
index b9a16b97..f88a38e2 100644
--- a/common/src/generated/resources/assets/numismatics/lang/en_us.json
+++ b/common/src/generated/resources/assets/numismatics/lang/en_us.json
@@ -165,5 +165,12 @@
"numismatics.authorization_type.trusted_players": "Trusted Players Only",
"numismatics.authorization_type.trusted_players.description": "Only players on the trust list",
"numismatics.special.ltr": "true",
- "numismatics.trust_list.configure": "Configure Trust List"
+ "numismatics.trust_list.configure": "Configure Trust List",
+ "tag.block.numismatics.numismatics_blocks": "Numismatics Blocks",
+ "tag.item.forge.string": "String",
+ "tag.item.numismatics.authorized_cards": "Authorized Cards",
+ "tag.item.numismatics.cards": "Cards",
+ "tag.item.numismatics.coins": "Coins",
+ "tag.item.numismatics.id_cards": "Id Cards",
+ "tag.item.numismatics.numismatics_items": "Numismatics Items"
}
\ No newline at end of file
diff --git a/common/src/main/java/dev/ithundxr/createnumismatics/Numismatics.java b/common/src/main/java/dev/ithundxr/createnumismatics/Numismatics.java
index 7f23a080..6128976d 100644
--- a/common/src/main/java/dev/ithundxr/createnumismatics/Numismatics.java
+++ b/common/src/main/java/dev/ithundxr/createnumismatics/Numismatics.java
@@ -29,6 +29,7 @@
import com.tterrag.registrate.providers.ProviderType;
import dev.architectury.injectables.annotations.ExpectPlatform;
import dev.ithundxr.createnumismatics.base.data.NumismaticsTagGen;
+import dev.ithundxr.createnumismatics.base.data.emi.EmiExcludedTagGen;
import dev.ithundxr.createnumismatics.base.data.lang.NumismaticsLangGen;
import dev.ithundxr.createnumismatics.base.data.recipe.NumismaticsSequencedAssemblyRecipeGen;
import dev.ithundxr.createnumismatics.base.data.recipe.NumismaticsStandardRecipeGen;
@@ -106,6 +107,7 @@ public static void gatherData(DataGenerator.PackGenerator gen) {
gen.addProvider(NumismaticsSequencedAssemblyRecipeGen::new);
gen.addProvider(NumismaticsStandardRecipeGen::new);
gen.addProvider(NumismaticsAdvancements::new);
+ gen.addProvider(EmiExcludedTagGen::new);
}
public static ResourceLocation asResource(String path) {
diff --git a/common/src/main/java/dev/ithundxr/createnumismatics/base/data/emi/EmiExcludedTagGen.java b/common/src/main/java/dev/ithundxr/createnumismatics/base/data/emi/EmiExcludedTagGen.java
new file mode 100644
index 00000000..d3998053
--- /dev/null
+++ b/common/src/main/java/dev/ithundxr/createnumismatics/base/data/emi/EmiExcludedTagGen.java
@@ -0,0 +1,77 @@
+/*
+ * Steam 'n' Rails
+ * Copyright (c) 2022-2024 The Railways Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package dev.ithundxr.createnumismatics.base.data.emi;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import dev.ithundxr.createnumismatics.multiloader.CommonTag;
+import dev.ithundxr.createnumismatics.multiloader.CommonTags;
+import net.minecraft.data.CachedOutput;
+import net.minecraft.data.DataProvider;
+import net.minecraft.data.PackOutput;
+import net.minecraft.world.item.Item;
+import net.minecraft.world.level.block.Block;
+import org.jetbrains.annotations.NotNull;
+
+import java.nio.file.Path;
+import java.util.concurrent.CompletableFuture;
+
+public class EmiExcludedTagGen implements DataProvider {
+ private static final String INDENT = " ";
+ private final PackOutput packOutput;
+
+ public EmiExcludedTagGen(PackOutput packOutput) {
+ this.packOutput = packOutput;
+ }
+
+ @Override
+ public @NotNull CompletableFuture> run(@NotNull CachedOutput output) {
+ Path path = this.packOutput.getOutputFolder()
+ .resolve("assets/emi/tag/exclusions/numismatics.json");
+
+ return DataProvider.saveStable(output, run(), path);
+ }
+
+ private JsonElement run() {
+ JsonObject object = new JsonObject();
+ {
+ JsonArray item = new JsonArray();
+ // fill in items
+ for (CommonTag- itemTag : CommonTags.ALL_ITEMS) {
+ item.add(itemTag.tag.location().toString());
+ }
+ object.add("item", item);
+ }
+ {
+ JsonArray block = new JsonArray();
+ // fill in blocks
+ for (CommonTag blockTag : CommonTags.ALL_BLOCKS) {
+ block.add(blockTag.tag.location().toString());
+ }
+ object.add("block", block);
+ }
+ return object;
+ }
+
+ @Override
+ public String getName() {
+ return "Numismatics EMI excluded tags";
+ }
+}
diff --git a/common/src/main/java/dev/ithundxr/createnumismatics/base/data/lang/NumismaticsLangGen.java b/common/src/main/java/dev/ithundxr/createnumismatics/base/data/lang/NumismaticsLangGen.java
index 2979308e..743e980c 100644
--- a/common/src/main/java/dev/ithundxr/createnumismatics/base/data/lang/NumismaticsLangGen.java
+++ b/common/src/main/java/dev/ithundxr/createnumismatics/base/data/lang/NumismaticsLangGen.java
@@ -25,6 +25,7 @@
import dev.ithundxr.createnumismatics.content.backend.Coin;
import dev.ithundxr.createnumismatics.content.backend.sub_authorization.AuthorizationType;
import dev.ithundxr.createnumismatics.registry.NumismaticsAdvancements;
+import dev.ithundxr.createnumismatics.registry.NumismaticsTags;
import java.util.Map;
import java.util.function.BiConsumer;
@@ -38,6 +39,7 @@ public static void generate(RegistrateLangProvider provider) {
NumismaticsAdvancements.provideLang(langConsumer);
AuthorizationType.provideLang(langConsumer);
Coin.provideLang(langConsumer);
+ NumismaticsTags.provideLang(langConsumer);
/* ================= */
/* Special data keys */
diff --git a/common/src/main/java/dev/ithundxr/createnumismatics/compat/Mods.java b/common/src/main/java/dev/ithundxr/createnumismatics/compat/Mods.java
index ce1c9ad4..83816e26 100644
--- a/common/src/main/java/dev/ithundxr/createnumismatics/compat/Mods.java
+++ b/common/src/main/java/dev/ithundxr/createnumismatics/compat/Mods.java
@@ -31,7 +31,9 @@
public enum Mods {
CARRYON("carryon"),
SODIUM("sodium"),
- COMPUTERCRAFT("computercraft")
+ COMPUTERCRAFT("computercraft"),
+ EMI("emi"),
+ JEI("jei")
;
public final boolean isLoaded;
diff --git a/common/src/main/java/dev/ithundxr/createnumismatics/content/backend/IGhostItemMenu.java b/common/src/main/java/dev/ithundxr/createnumismatics/content/backend/IGhostItemMenu.java
new file mode 100644
index 00000000..eb311e8c
--- /dev/null
+++ b/common/src/main/java/dev/ithundxr/createnumismatics/content/backend/IGhostItemMenu.java
@@ -0,0 +1,29 @@
+/*
+ * Numismatics
+ * Copyright (c) 2024 The Railways Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package dev.ithundxr.createnumismatics.content.backend;
+
+import net.minecraft.world.item.ItemStack;
+
+public interface IGhostItemMenu {
+ void setGhostStackInSlot(int slotID, ItemStack stack);
+ boolean isSlotGhost(int slotID);
+ default boolean shouldGhostApplyEnchantsAndDye(int slotID) {
+ return true;
+ }
+}
diff --git a/common/src/main/java/dev/ithundxr/createnumismatics/content/vendor/VendorMenu.java b/common/src/main/java/dev/ithundxr/createnumismatics/content/vendor/VendorMenu.java
index 8618e697..dfbb06db 100644
--- a/common/src/main/java/dev/ithundxr/createnumismatics/content/vendor/VendorMenu.java
+++ b/common/src/main/java/dev/ithundxr/createnumismatics/content/vendor/VendorMenu.java
@@ -21,6 +21,7 @@
import com.simibubi.create.foundation.gui.menu.MenuBase;
import dev.ithundxr.createnumismatics.content.backend.BigStackSizeContainerSynchronizer;
import dev.ithundxr.createnumismatics.content.backend.Coin;
+import dev.ithundxr.createnumismatics.content.backend.IGhostItemMenu;
import dev.ithundxr.createnumismatics.content.backend.IScrollableSlotMenu;
import dev.ithundxr.createnumismatics.content.bank.AnyCardSlot;
import dev.ithundxr.createnumismatics.content.coins.CoinDisplaySlot;
@@ -41,7 +42,7 @@
import net.minecraft.world.level.block.entity.BlockEntity;
import org.jetbrains.annotations.NotNull;
-public class VendorMenu extends MenuBase implements IScrollableSlotMenu {
+public class VendorMenu extends MenuBase implements IScrollableSlotMenu, IGhostItemMenu {
public static final int COIN_SLOTS = Coin.values().length;
public static final int CARD_SLOT_INDEX = COIN_SLOTS;
public static final int FILTER_SLOT_INDEX = CARD_SLOT_INDEX + 1;
@@ -225,7 +226,7 @@ public void setSynchronizer(@NotNull ContainerSynchronizer synchronizer) {
@Override
public void scrollSlot(int slotID, double delta, boolean shift) {
- if (slotID == FILTER_SLOT_INDEX && !contentHolder.isFilterSlotLegacy()) {
+ if (isSlotGhost(slotID)) {
Slot slot = getSlot(slotID);
if (!slot.hasItem())
return;
@@ -240,4 +241,16 @@ public void scrollSlot(int slotID, double delta, boolean shift) {
slot.set(count == 0 ? ItemStack.EMPTY : stack.copyWithCount(count));
}
}
+
+ @Override
+ public void setGhostStackInSlot(int slotID, ItemStack stack) {
+ if (isSlotGhost(slotID)) {
+ getSlot(slotID).set(stack);
+ }
+ }
+
+ @Override
+ public boolean isSlotGhost(int slotID) {
+ return slotID == FILTER_SLOT_INDEX && !contentHolder.isFilterSlotLegacy();
+ }
}
diff --git a/common/src/main/java/dev/ithundxr/createnumismatics/multiloader/CommonTags.java b/common/src/main/java/dev/ithundxr/createnumismatics/multiloader/CommonTags.java
index 64d62526..ac8e6f16 100644
--- a/common/src/main/java/dev/ithundxr/createnumismatics/multiloader/CommonTags.java
+++ b/common/src/main/java/dev/ithundxr/createnumismatics/multiloader/CommonTags.java
@@ -24,10 +24,15 @@
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
+import java.util.ArrayList;
import java.util.EnumMap;
+import java.util.List;
import java.util.Map;
public class CommonTags {
+ public static final List> ALL_ITEMS = new ArrayList<>();
+ public static final List> ALL_BLOCKS = new ArrayList<>();
+
public static final CommonTag
-
STRING = item("string"),
IRON_NUGGETS = item("nuggets/iron_nuggets", "iron_nuggets", "nuggets/iron"),
@@ -55,11 +60,15 @@ public class CommonTags {
RELOCATION_NOT_SUPPORTED = block("relocation_not_supported");
public static CommonTag block(String path) {
- return CommonTag.conventional(Registries.BLOCK, path);
+ CommonTag tag = CommonTag.conventional(Registries.BLOCK, path);
+ ALL_BLOCKS.add(tag);
+ return tag;
}
public static CommonTag
- item(String common, String fabric, String forge) {
- return CommonTag.conventional(Registries.ITEM, common, fabric, forge);
+ CommonTag
- tag = CommonTag.conventional(Registries.ITEM, common, fabric, forge);
+ ALL_ITEMS.add(tag);
+ return tag;
}
public static CommonTag
- item(String path) {
diff --git a/common/src/main/java/dev/ithundxr/createnumismatics/registry/NumismaticsPackets.java b/common/src/main/java/dev/ithundxr/createnumismatics/registry/NumismaticsPackets.java
index fc8d37b9..9f1ad3c0 100644
--- a/common/src/main/java/dev/ithundxr/createnumismatics/registry/NumismaticsPackets.java
+++ b/common/src/main/java/dev/ithundxr/createnumismatics/registry/NumismaticsPackets.java
@@ -40,6 +40,7 @@ public class NumismaticsPackets {
.c2s(ConfigureSubAccountPacket.class, ConfigureSubAccountPacket::new)
.c2s(AddSubAccountPacket.class, AddSubAccountPacket::new)
.c2s(ScrollSlotPacket.class, ScrollSlotPacket::new)
+ .c2s(GhostItemSubmitPacket.class, GhostItemSubmitPacket::new)
.s2c(BankAccountLabelPacket.class, BankAccountLabelPacket::new)
.s2c(VarIntContainerSetDataPacket.class, VarIntContainerSetDataPacket::new)
diff --git a/common/src/main/java/dev/ithundxr/createnumismatics/registry/NumismaticsTags.java b/common/src/main/java/dev/ithundxr/createnumismatics/registry/NumismaticsTags.java
index 1190eb5e..9d271b50 100644
--- a/common/src/main/java/dev/ithundxr/createnumismatics/registry/NumismaticsTags.java
+++ b/common/src/main/java/dev/ithundxr/createnumismatics/registry/NumismaticsTags.java
@@ -20,6 +20,7 @@
import com.simibubi.create.foundation.utility.Lang;
import dev.ithundxr.createnumismatics.Numismatics;
+import dev.ithundxr.createnumismatics.util.TextUtils;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
@@ -30,6 +31,8 @@
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
+import java.util.function.BiConsumer;
+
public class NumismaticsTags {
public enum NameSpace {
@@ -157,4 +160,19 @@ public static void register() {
AllBlockTags.register();
AllItemTags.register();
}
+
+ public static void provideLang(BiConsumer consumer) {
+ for (AllBlockTags blockTag : AllBlockTags.values()) {
+ ResourceLocation loc = blockTag.tag.location();
+ consumer.accept("tag.block." + loc.getNamespace() + "." + loc.getPath().replace('/', '.'),
+ TextUtils.titleCaseConversion(blockTag.name()).replace('_', ' '));
+ }
+
+ for (AllItemTags itemTag : AllItemTags.values()) {
+ ResourceLocation loc = itemTag.tag.location();
+ consumer.accept("tag.item." + loc.getNamespace() + "." + loc.getPath().replace('/', '.'),
+ TextUtils.titleCaseConversion(itemTag.name().replace('_', ' ')));
+ }
+ consumer.accept("tag.item.forge.string", "String");
+ }
}
diff --git a/common/src/main/java/dev/ithundxr/createnumismatics/registry/packets/GhostItemSubmitPacket.java b/common/src/main/java/dev/ithundxr/createnumismatics/registry/packets/GhostItemSubmitPacket.java
new file mode 100644
index 00000000..392b98bb
--- /dev/null
+++ b/common/src/main/java/dev/ithundxr/createnumismatics/registry/packets/GhostItemSubmitPacket.java
@@ -0,0 +1,47 @@
+/*
+ * Numismatics
+ * Copyright (c) 2024 The Railways Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package dev.ithundxr.createnumismatics.registry.packets;
+
+import dev.ithundxr.createnumismatics.content.backend.IGhostItemMenu;
+import dev.ithundxr.createnumismatics.multiloader.C2SPacket;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.item.ItemStack;
+
+public record GhostItemSubmitPacket(int slot, ItemStack stack) implements C2SPacket {
+
+ public GhostItemSubmitPacket(FriendlyByteBuf buf) {
+ this(buf.readVarInt(), buf.readItem());
+ }
+
+ @Override
+ public void write(FriendlyByteBuf buffer) {
+ buffer.writeVarInt(slot);
+ buffer.writeItem(stack);
+ }
+
+ @Override
+ public void handle(ServerPlayer sender) {
+ if (sender.containerMenu instanceof IGhostItemMenu ghostItemMenu) {
+ if (ghostItemMenu.isSlotGhost(slot)) {
+ ghostItemMenu.setGhostStackInSlot(slot, stack);
+ }
+ }
+ }
+}
diff --git a/common/src/main/java/dev/ithundxr/createnumismatics/util/ClientCraftingUtils.java b/common/src/main/java/dev/ithundxr/createnumismatics/util/ClientCraftingUtils.java
new file mode 100644
index 00000000..01d090dc
--- /dev/null
+++ b/common/src/main/java/dev/ithundxr/createnumismatics/util/ClientCraftingUtils.java
@@ -0,0 +1,224 @@
+/*
+ * Numismatics
+ * Copyright (c) 2024 The Railways Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package dev.ithundxr.createnumismatics.util;
+
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.Minecraft;
+import net.minecraft.world.SimpleContainer;
+import net.minecraft.world.inventory.CraftingContainer;
+import net.minecraft.world.item.EnchantedBookItem;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.Items;
+import net.minecraft.world.item.crafting.ArmorDyeRecipe;
+import net.minecraft.world.item.enchantment.Enchantment;
+import net.minecraft.world.item.enchantment.EnchantmentHelper;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Map;
+
+@Environment(EnvType.CLIENT)
+public class ClientCraftingUtils {
+ /**
+ * Apply stacking crafts to an item stack.
+ * @param targetStack The item stack to apply the stacking crafts to.
+ * @param droppedStack The item stack to apply the stacking crafts from.
+ * @return The item stack with the stacking crafts applied, or null if it couldn't be applied.
+ * Note: The stack may be identical, but it will never be the same instance.
+ */
+ public static @NotNull Result applyStackingCrafts(@NotNull ItemStack targetStack, @NotNull ItemStack droppedStack) {
+ Result dyeResult = applyDye(targetStack, droppedStack);
+ if (dyeResult.isOk())
+ return dyeResult;
+ return applyEnchant(targetStack, droppedStack);
+ }
+
+ /**
+ * Apply an enchantment from an enchanted book to an item stack.
+ * @param targetStack The item stack to apply the enchantment to.
+ * @param enchantedBook The enchanted book to apply the enchantment from.
+ * @return The item stack with the enchantment applied, or null if it couldn't be applied.
+ * Note: The stack may be identical, but it will never be the same instance.
+ */
+ public static @NotNull Result applyEnchant(@NotNull ItemStack targetStack, @NotNull ItemStack enchantedBook) {
+ if (targetStack.isEmpty() || enchantedBook.isEmpty())
+ return targetStack.isEmpty() ? Result.failureReplace(enchantedBook.copy()) : Result.failureKeep();
+
+ if (!enchantedBook.is(Items.ENCHANTED_BOOK))
+ return Result.failureReplace(enchantedBook.copy());
+
+ if (EnchantedBookItem.getEnchantments(enchantedBook).isEmpty())
+ return Result.failureKeep();
+
+ targetStack = targetStack.copy();
+
+ Map targetEnchants = EnchantmentHelper.getEnchantments(targetStack);
+ Map bookEnchants = EnchantmentHelper.getEnchantments(enchantedBook);
+ boolean someEnchantsSucceeded = false;
+ boolean someEnchantsFailed = false;
+
+ for (Enchantment bookEnchantment : bookEnchants.keySet()) {
+ if (bookEnchantment == null)
+ continue;
+
+ int existingLevel = targetEnchants.getOrDefault(bookEnchantment, 0);
+ int bookLevel = bookEnchants.get(bookEnchantment);
+
+ if (existingLevel == bookLevel)
+ bookLevel++;
+ else
+ bookLevel = Math.max(bookLevel, existingLevel);
+
+ boolean ok = bookEnchantment.canEnchant(targetStack) || targetStack.is(Items.ENCHANTED_BOOK);
+
+ for (Enchantment existingEnchantment : targetEnchants.keySet()) {
+ if (existingEnchantment != bookEnchantment && !bookEnchantment.isCompatibleWith(existingEnchantment)) {
+ ok = false;
+ }
+ }
+
+ if (!ok) {
+ someEnchantsFailed = true;
+ } else {
+ someEnchantsSucceeded = true;
+
+ if (bookLevel > bookEnchantment.getMaxLevel())
+ bookLevel = bookEnchantment.getMaxLevel();
+
+ targetEnchants.put(bookEnchantment, bookLevel);
+ }
+ }
+
+ if (someEnchantsFailed && !someEnchantsSucceeded)
+ return Result.failureKeep();
+
+ EnchantmentHelper.setEnchantments(targetEnchants, targetStack);
+ return Result.ok(targetStack);
+ }
+
+ /**
+ * Apply a dye to an item stack.
+ * @param targetStack The item stack to apply the dye to (leather armor etc.).
+ * @param dye The dye to apply.
+ * @return The item stack with the dye applied, or null if it couldn't be applied.
+ */
+ public static @NotNull Result applyDye(@NotNull ItemStack targetStack, @NotNull ItemStack dye) {
+ targetStack = targetStack.copy();
+ ItemStack dye$ = dye.copy();
+
+ Minecraft mc = Minecraft.getInstance();
+ if (mc.level == null)
+ return Result.failureKeep();
+
+ CraftingContainer craftingContainer = new SimpleCraftingContainer(2, 1);
+ craftingContainer.setItem(0, targetStack);
+ craftingContainer.setItem(1, dye$);
+
+ return mc.level.getRecipeManager()
+ .getRecipes()
+ .stream()
+ .filter(recipe -> recipe instanceof ArmorDyeRecipe)
+ .map(recipe -> (ArmorDyeRecipe) recipe)
+ .filter(recipe -> recipe.matches(craftingContainer, mc.level))
+ .findFirst()
+ .map(recipe -> recipe.assemble(craftingContainer, mc.level.registryAccess()))
+ .filter(result -> !result.isEmpty())
+ .map(Result::ok)
+ .orElseGet(() -> Result.failureReplace(dye$));
+ }
+
+ private static class SimpleCraftingContainer extends SimpleContainer implements CraftingContainer {
+
+ protected int width;
+ protected int height;
+
+ public SimpleCraftingContainer(int width, int height) {
+ super(width * height);
+
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ public int getWidth() {
+ return width;
+ }
+
+ @Override
+ public int getHeight() {
+ return height;
+ }
+
+ @Override
+ public @NotNull List getItems() {
+ return items;
+ }
+ }
+
+ public static class Result {
+ private final @Nullable ItemStack stack;
+ private final @NotNull ResultType type;
+
+ private static final Result FAILURE_KEEP = new Result(null, ResultType.FAILURE_KEEP);
+
+ private Result(@Nullable ItemStack stack, @NotNull ResultType type) {
+ this.stack = stack;
+ this.type = type;
+ }
+
+ public static Result ok(@NotNull ItemStack stack) {
+ return new Result(stack, ResultType.SUCCESS);
+ }
+
+ public static Result failureReplace(@NotNull ItemStack new_) {
+ return new Result(new_, ResultType.FAILURE_REPLACE);
+ }
+
+ public static Result failureKeep() {
+ return FAILURE_KEEP;
+ }
+
+ public boolean isOk() {
+ return type == ResultType.SUCCESS;
+ }
+
+ public @NotNull ItemStack getResult(@NotNull ItemStack existing, boolean inheritCount) {
+ return switch (type) {
+ case SUCCESS -> stack == null
+ ? existing :
+ (inheritCount
+ ? stack.copyWithCount(existing.getCount())
+ : stack
+ );
+ case FAILURE_REPLACE -> stack == null
+ ? existing
+ : stack;
+ case FAILURE_KEEP -> existing;
+ };
+ }
+ }
+
+ public enum ResultType {
+ SUCCESS,
+ FAILURE_REPLACE,
+ FAILURE_KEEP
+ }
+}
diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts
index 11fb4b12..b58312cd 100644
--- a/fabric/build.gradle.kts
+++ b/fabric/build.gradle.kts
@@ -82,6 +82,7 @@ dependencies {
modLocalRuntime("maven.modrinth:lazydfu:${"lazydfu_version"()}")
modLocalRuntime("com.terraformersmc:modmenu:${"modmenu_version"()}")
+ modCompileOnly("dev.emi:emi-fabric:${"emi_version"()}:api")
modLocalRuntime("dev.emi:emi-fabric:${"emi_version"()}")
modCompileOnly("cc.tweaked:cc-tweaked-${"minecraft_version"()}-fabric-api:${"cc_version"()}")
diff --git a/fabric/src/main/java/dev/ithundxr/createnumismatics/compat/emi/fabric/GhostIngredientHandler.java b/fabric/src/main/java/dev/ithundxr/createnumismatics/compat/emi/fabric/GhostIngredientHandler.java
new file mode 100644
index 00000000..a0a480f6
--- /dev/null
+++ b/fabric/src/main/java/dev/ithundxr/createnumismatics/compat/emi/fabric/GhostIngredientHandler.java
@@ -0,0 +1,81 @@
+/*
+ * Numismatics
+ * Copyright (c) 2024 The Railways Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package dev.ithundxr.createnumismatics.compat.emi.fabric;
+
+import com.simibubi.create.AllKeys;
+import com.simibubi.create.foundation.gui.menu.AbstractSimiContainerScreen;
+import com.simibubi.create.foundation.gui.menu.MenuBase;
+import dev.emi.emi.api.EmiDragDropHandler;
+import dev.emi.emi.api.stack.EmiIngredient;
+import dev.emi.emi.api.stack.EmiStack;
+import dev.ithundxr.createnumismatics.content.backend.IGhostItemMenu;
+import dev.ithundxr.createnumismatics.registry.NumismaticsPackets;
+import dev.ithundxr.createnumismatics.registry.packets.GhostItemSubmitPacket;
+import dev.ithundxr.createnumismatics.util.ClientCraftingUtils;
+import io.github.fabricators_of_create.porting_lib.mixin.accessors.client.accessor.AbstractContainerScreenAccessor;
+import io.github.fabricators_of_create.porting_lib.transfer.item.ItemHandlerHelper;
+import net.minecraft.MethodsReturnNonnullByDefault;
+import net.minecraft.client.renderer.Rect2i;
+import net.minecraft.world.inventory.Slot;
+import net.minecraft.world.item.ItemStack;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+import java.util.List;
+
+@MethodsReturnNonnullByDefault
+@ParametersAreNonnullByDefault
+public class GhostIngredientHandler & IGhostItemMenu>
+ implements EmiDragDropHandler> {
+
+ @Override
+ public boolean dropStack(AbstractSimiContainerScreen gui, EmiIngredient ingredient, int x, int y) {
+ List stacks = ingredient.getEmiStacks();
+ if (!(gui instanceof AbstractContainerScreenAccessor access) || stacks.size() != 1)
+ return false;
+ ItemStack stack = stacks.get(0).getItemStack();
+ if (stack.isEmpty())
+ return false;
+
+ for (int i = 0; i < gui.getMenu().slots.size(); i++) {
+ Slot slot = gui.getMenu().slots.get(i);
+ if (slot.isActive() && gui.getMenu().isSlotGhost(i)) {
+ Rect2i slotArea = new Rect2i(access.port_lib$getGuiLeft() + slot.x, access.port_lib$getGuiTop() + slot.y, 16, 16);
+ if (slotArea.contains(x, y)) {
+ acceptStack(gui, i, stack);
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private void acceptStack(AbstractSimiContainerScreen gui, int slotIndex, ItemStack stack) {
+ stack = ItemHandlerHelper.copyStackWithSize(stack, 1);
+ if (gui.getMenu().shouldGhostApplyEnchantsAndDye(slotIndex) && AllKeys.shiftDown()) {
+ ItemStack existing = gui.getMenu().getSlot(slotIndex).getItem();
+ ClientCraftingUtils.Result result = ClientCraftingUtils.applyStackingCrafts(existing, stack);
+ stack = result.getResult(existing, true);
+ }
+ gui.getMenu().setGhostStackInSlot(slotIndex, stack);
+
+ // sync new filter contents with server
+ NumismaticsPackets.PACKETS.send(new GhostItemSubmitPacket(slotIndex, stack));
+ }
+}
diff --git a/fabric/src/main/java/dev/ithundxr/createnumismatics/compat/emi/fabric/NumismaticsEmiPlugin.java b/fabric/src/main/java/dev/ithundxr/createnumismatics/compat/emi/fabric/NumismaticsEmiPlugin.java
new file mode 100644
index 00000000..df9cace4
--- /dev/null
+++ b/fabric/src/main/java/dev/ithundxr/createnumismatics/compat/emi/fabric/NumismaticsEmiPlugin.java
@@ -0,0 +1,31 @@
+/*
+ * Numismatics
+ * Copyright (c) 2024 The Railways Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package dev.ithundxr.createnumismatics.compat.emi.fabric;
+
+import dev.emi.emi.api.EmiPlugin;
+import dev.emi.emi.api.EmiRegistry;
+import dev.ithundxr.createnumismatics.content.vendor.VendorScreen;
+
+public class NumismaticsEmiPlugin implements EmiPlugin {
+ @Override
+ @SuppressWarnings({"rawtypes", "unchecked"}) // Java isn't clever enough to figure out GhostIngredientHandler
+ public void register(EmiRegistry registry) {
+ registry.addDragDropHandler(VendorScreen.class, new GhostIngredientHandler());
+ }
+}
diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json
index fc8fbcf8..c7c98b09 100644
--- a/fabric/src/main/resources/fabric.mod.json
+++ b/fabric/src/main/resources/fabric.mod.json
@@ -22,6 +22,9 @@
],
"fabric-datagen": [
"dev.ithundxr.createnumismatics.fabric.NumismaticsDataFabric"
+ ],
+ "emi": [
+ "dev.ithundxr.createnumismatics.compat.emi.fabric.NumismaticsEmiPlugin"
]
},
"mixins": [
diff --git a/forge/build.gradle.kts b/forge/build.gradle.kts
index 77dc4bec..c4898143 100644
--- a/forge/build.gradle.kts
+++ b/forge/build.gradle.kts
@@ -48,6 +48,20 @@ repositories {
includeGroup("cc.tweaked")
}
}
+ maven("https://maven.blamejared.com/") {
+ // location of the maven that hosts JEI files since January 2023
+ name = "Jared's maven"
+ content {
+ includeGroup("mezz.jei")
+ }
+ }
+ maven("https://modmaven.dev") {
+ // location of a maven mirror for JEI files, as a fallback
+ name = "ModMaven"
+ content {
+ includeGroup("mezz.jei")
+ }
+ }
}
dependencies {
@@ -71,6 +85,12 @@ dependencies {
forgeRuntimeLibrary("io.netty:netty-codec-socks:4.1.82.Final")
forgeRuntimeLibrary("io.netty:netty-handler-proxy:4.1.82.Final")
+ // compile against the JEI API but do not include it at runtime
+ modCompileOnly("mezz.jei:jei-${"minecraft_version"()}-common-api:${"jei_version"()}")
+ modCompileOnly("mezz.jei:jei-${"minecraft_version"()}-forge-api:${"jei_version"()}")
+ // at runtime, use the full JEI jar for Forge
+ modLocalRuntime("mezz.jei:jei-${"minecraft_version"()}-forge:${"jei_version"()}")
+
if ("enable_cc"().toBoolean()) {
modLocalRuntime("cc.tweaked:cc-tweaked-${"minecraft_version"()}-forge:${"cc_version"()}")
}
diff --git a/forge/src/main/java/dev/ithundxr/createnumismatics/compat/jei/forge/GhostIngredientHandler.java b/forge/src/main/java/dev/ithundxr/createnumismatics/compat/jei/forge/GhostIngredientHandler.java
new file mode 100644
index 00000000..23a39aac
--- /dev/null
+++ b/forge/src/main/java/dev/ithundxr/createnumismatics/compat/jei/forge/GhostIngredientHandler.java
@@ -0,0 +1,106 @@
+/*
+ * Numismatics
+ * Copyright (c) 2024 The Railways Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package dev.ithundxr.createnumismatics.compat.jei.forge;
+
+import com.simibubi.create.AllKeys;
+import com.simibubi.create.foundation.gui.menu.AbstractSimiContainerScreen;
+import com.simibubi.create.foundation.gui.menu.MenuBase;
+import dev.ithundxr.createnumismatics.content.backend.IGhostItemMenu;
+import dev.ithundxr.createnumismatics.registry.NumismaticsPackets;
+import dev.ithundxr.createnumismatics.registry.packets.GhostItemSubmitPacket;
+import dev.ithundxr.createnumismatics.util.ClientCraftingUtils;
+import mezz.jei.api.constants.VanillaTypes;
+import mezz.jei.api.gui.handlers.IGhostIngredientHandler;
+import mezz.jei.api.ingredients.ITypedIngredient;
+import net.minecraft.MethodsReturnNonnullByDefault;
+import net.minecraft.client.renderer.Rect2i;
+import net.minecraft.world.inventory.Slot;
+import net.minecraft.world.item.ItemStack;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+import java.util.LinkedList;
+import java.util.List;
+
+@MethodsReturnNonnullByDefault
+@ParametersAreNonnullByDefault
+public class GhostIngredientHandler & IGhostItemMenu>
+ implements IGhostIngredientHandler> {
+
+ @Override
+ public List> getTargetsTyped(AbstractSimiContainerScreen gui, ITypedIngredient ingredient,
+ boolean doStart) {
+ List> targets = new LinkedList<>();
+
+ if (ingredient.getType() == VanillaTypes.ITEM_STACK) {
+ for (int i = 0; i < gui.getMenu().slots.size(); i++) {
+ if (gui.getMenu().slots.get(i).isActive() && gui.getMenu().isSlotGhost(i))
+ targets.add(new GhostTarget<>(gui, i));
+ }
+ }
+
+ return targets;
+ }
+
+ @Override
+ public void onComplete() {}
+
+ @Override
+ public boolean shouldHighlightTargets() {
+ // TODO change to false and highlight the slots ourself in some better way
+ return true;
+ }
+
+ private static class GhostTarget & IGhostItemMenu> implements Target {
+
+ private final Rect2i area;
+ private final AbstractSimiContainerScreen gui;
+ private final int slotIndex;
+
+ public GhostTarget(AbstractSimiContainerScreen gui, int slotIndex) {
+ this.gui = gui;
+ this.slotIndex = slotIndex;
+ Slot slot = gui.getMenu().slots.get(slotIndex);
+ this.area = new Rect2i(gui.getGuiLeft() + slot.x, gui.getGuiTop() + slot.y, 16, 16);
+ }
+
+ @Override
+ public Rect2i getArea() {
+ return area;
+ }
+
+ @Override
+ public void accept(I ingredient) {
+ ItemStack stack = ((ItemStack) ingredient).copy();
+ stack.setCount(1);
+ if (!gui.getMenu().isSlotGhost(slotIndex))
+ return;
+
+ if (gui.getMenu().shouldGhostApplyEnchantsAndDye(slotIndex) && AllKeys.shiftDown()) {
+ ItemStack existing = gui.getMenu().getSlot(slotIndex).getItem();
+ ClientCraftingUtils.Result result = ClientCraftingUtils.applyStackingCrafts(existing, stack);
+ stack = result.getResult(existing, true);
+ }
+
+ gui.getMenu().setGhostStackInSlot(slotIndex, stack);
+
+ // sync new filter contents with server
+ NumismaticsPackets.PACKETS.send(new GhostItemSubmitPacket(slotIndex, stack));
+ }
+ }
+}
diff --git a/forge/src/main/java/dev/ithundxr/createnumismatics/compat/jei/forge/NumismaticsJEI.java b/forge/src/main/java/dev/ithundxr/createnumismatics/compat/jei/forge/NumismaticsJEI.java
new file mode 100644
index 00000000..ca106495
--- /dev/null
+++ b/forge/src/main/java/dev/ithundxr/createnumismatics/compat/jei/forge/NumismaticsJEI.java
@@ -0,0 +1,48 @@
+/*
+ * Numismatics
+ * Copyright (c) 2024 The Railways Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package dev.ithundxr.createnumismatics.compat.jei.forge;
+
+import dev.ithundxr.createnumismatics.Numismatics;
+import dev.ithundxr.createnumismatics.content.vendor.VendorScreen;
+import mezz.jei.api.IModPlugin;
+import mezz.jei.api.JeiPlugin;
+import mezz.jei.api.registration.IGuiHandlerRegistration;
+import net.minecraft.resources.ResourceLocation;
+import org.jetbrains.annotations.NotNull;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+@JeiPlugin
+@SuppressWarnings("unused")
+@ParametersAreNonnullByDefault
+public class NumismaticsJEI implements IModPlugin {
+
+ private static final ResourceLocation ID = Numismatics.asResource("jei_plugin");
+
+ @Override
+ public @NotNull ResourceLocation getPluginUid() {
+ return ID;
+ }
+
+ @Override
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void registerGuiHandlers(IGuiHandlerRegistration registration) {
+ registration.addGhostIngredientHandler(VendorScreen.class, new GhostIngredientHandler());
+ }
+}
diff --git a/gradle.properties b/gradle.properties
index dab0faff..925f8bc8 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -38,17 +38,12 @@ flywheel_forge_version = 0.6.10-8
# https://github.com/LlamaLad7/MixinExtras
mixin_extras_version = 0.3.5
-# Development QOL
-# Create Fabric supports all 3 recipe viewers: JEI, REI, and EMI. This decides which is enabled at runtime.
-# set to disabled to have none of them.
-recipe_viewer = emi
-# JEI - https://www.curseforge.com/minecraft/mc-mods/jei/files
-jei_version = 15.2.0.27
-# REI - https://modrinth.com/mod/rei/versions
-rei_version = 12.0.674
# EMI - https://modrinth.com/mod/emi/versions
emi_version = 1.0.28+1.20.1
+# JEI - https://modrinth.com/mod/jei/versions
+jei_version = 15.8.0.16
+
# Mod Menu - https://modrinth.com/mod/modmenu/versions
modmenu_version = 7.2.2
# LazyDFU - https://modrinth.com/mod/lazydfu/versions