feat: add Stackable ShulkerBoxes support(#2)

This commit is contained in:
Helvetica Volubi
2025-06-09 19:30:41 +08:00
parent 983be775ff
commit 6f9f5eb4e2
7 changed files with 508 additions and 13 deletions
@@ -168,7 +168,7 @@ index fb63e2a3205ea9f7aaee0ff0f4dc0cc1a5268507..645f2f41de74f4461685c753dcd6cfc5
);
}
diff --git a/src/main/java/me/earthme/luminol/config/LuminolConfig.java b/src/main/java/me/earthme/luminol/config/LuminolConfig.java
index da945b930ed8ef24a907e9c397efa115d128a3d2..f9994cb3134accd2d43ae5de950fdb9700e7b466 100644
index 57b1f606d2f4197e1f68d367bf63e04ce2fe1534..01f109fc02590d22a42676f35f23ae72ed08ac36 100644
--- a/src/main/java/me/earthme/luminol/config/LuminolConfig.java
+++ b/src/main/java/me/earthme/luminol/config/LuminolConfig.java
@@ -29,22 +29,33 @@ import java.util.jar.JarEntry;
@@ -276,7 +276,7 @@ index da945b930ed8ef24a907e9c397efa115d128a3d2..f9994cb3134accd2d43ae5de950fdb97
final EnumConfigCategory category = singleConfigModule.getCategory();
Field[] fields = singleConfigModule.getClass().getDeclaredFields();
@@ -200,7 +211,7 @@ public class LuminolConfig {
@@ -203,7 +214,7 @@ public class LuminolConfig {
}
}
@@ -285,7 +285,7 @@ index da945b930ed8ef24a907e9c397efa115d128a3d2..f9994cb3134accd2d43ae5de950fdb97
configFileInstance.remove(name);
Object configAtPath = configFileInstance.get(String.join(".", keys));
if (configAtPath instanceof UnmodifiableConfig && ((UnmodifiableConfig) configAtPath).isEmpty()) {
@@ -208,7 +219,7 @@ public class LuminolConfig {
@@ -211,7 +222,7 @@ public class LuminolConfig {
}
}
@@ -294,7 +294,7 @@ index da945b930ed8ef24a907e9c397efa115d128a3d2..f9994cb3134accd2d43ae5de950fdb97
configFileInstance.remove(String.join(".", keys));
Object configAtPath = configFileInstance.get(String.join(".", Arrays.copyOfRange(keys, 1, keys.length)));
if (configAtPath instanceof UnmodifiableConfig && ((UnmodifiableConfig) configAtPath).isEmpty()) {
@@ -216,11 +227,11 @@ public class LuminolConfig {
@@ -219,11 +230,11 @@ public class LuminolConfig {
}
}
@@ -308,7 +308,7 @@ index da945b930ed8ef24a907e9c397efa115d128a3d2..f9994cb3134accd2d43ae5de950fdb97
if (configFileInstance.contains(key) && configFileInstance.get(key) != null) {
stagedConfigMap.put(key, value);
return true;
@@ -228,7 +239,7 @@ public class LuminolConfig {
@@ -231,7 +242,7 @@ public class LuminolConfig {
return false;
}
@@ -317,7 +317,7 @@ index da945b930ed8ef24a907e9c397efa115d128a3d2..f9994cb3134accd2d43ae5de950fdb97
if (!targetType.isAssignableFrom(value.getClass())) {
try {
if (targetType == Integer.class) {
@@ -252,27 +263,27 @@ public class LuminolConfig {
@@ -255,27 +266,27 @@ public class LuminolConfig {
return value;
}
@@ -351,7 +351,7 @@ index da945b930ed8ef24a907e9c397efa115d128a3d2..f9994cb3134accd2d43ae5de950fdb97
List<String> allPaths = getAllConfigPaths(partialPath);
List<String> result = new ArrayList<>();
@@ -292,13 +303,13 @@ public class LuminolConfig {
@@ -295,13 +306,13 @@ public class LuminolConfig {
return result;
}
@@ -367,7 +367,7 @@ index da945b930ed8ef24a907e9c397efa115d128a3d2..f9994cb3134accd2d43ae5de950fdb97
Set<Class<?>> classes = new LinkedHashSet<>();
String packageDirName = pack.replace('.', '/');
Enumeration<URL> dirs;
@@ -329,7 +340,7 @@ public class LuminolConfig {
@@ -332,7 +343,7 @@ public class LuminolConfig {
return classes;
}
@@ -376,7 +376,7 @@ index da945b930ed8ef24a907e9c397efa115d128a3d2..f9994cb3134accd2d43ae5de950fdb97
File dir = new File(packagePath);
if (!dir.exists() || !dir.isDirectory()) {
@@ -353,7 +364,7 @@ public class LuminolConfig {
@@ -356,7 +367,7 @@ public class LuminolConfig {
}
}
@@ -1,6 +1,6 @@
--- /dev/null
+++ b/src/main/java/me/earthme/lophine/config/modules/misc/ContainerExpansionConfig.java
@@ -1,0 +_,27 @@
@@ -1,0 +_,32 @@
+package me.earthme.lophine.config.modules.misc;
+
+import me.earthme.luminol.config.EnumConfigCategory;
@@ -10,14 +10,19 @@
+public class ContainerExpansionConfig implements IConfigModule {
+ @ConfigInfo(baseName = "barrel_rows", comments =
+ """
+ range: 1~6\s""")
+ range: 1~6""")
+ public static int barrelRows = 3;
+
+ @ConfigInfo(baseName = "enderchest_rows", comments =
+ """
+ range: 1~6\s""")
+ range: 1~6""")
+ public static int enderchestRows = 3;
+
+ @ConfigInfo(baseName = "shulker_stackable_count", comments =
+ """
+ range: 1~64""")
+ public static int shulkerCount = 1;
+
+ @Override
+ public EnumConfigCategory getCategory() {
+ return EnumConfigCategory.MISC;
@@ -0,0 +1,79 @@
--- /dev/null
+++ b/src/main/java/me/earthme/lophine/utils/ShulkerBoxesUtil.java
@@ -1,0 +_,76 @@
+package me.earthme.lophine.utils;
+
+import me.earthme.lophine.config.modules.misc.ContainerExpansionConfig;
+import net.minecraft.core.component.DataComponents;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.world.item.BlockItem;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.component.CustomData;
+import net.minecraft.world.item.component.ItemContainerContents;
+import net.minecraft.world.level.block.ShulkerBoxBlock;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Optional;
+
+public class ShulkerBoxesUtil {
+ // Lophine - Stackable ShulkerBoxes
+ public static boolean shouldCheck() {
+ return ContainerExpansionConfig.shulkerCount > 1 && ContainerExpansionConfig.shulkerCount <= 64;
+ }
+
+ public static boolean checkShulkerBox(ItemStack itemStack) {
+ return shouldCheck() && itemStack.getItem() instanceof BlockItem b
+ && b.getBlock() instanceof ShulkerBoxBlock;
+ }
+
+ public static int getItemMaxCount(ItemStack itemStack) {
+ if (checkShulkerBox(itemStack)) {
+ return Math.clamp(ContainerExpansionConfig.shulkerCount, 1, 64);
+ }
+ return itemStack.getMaxStackSize();
+ }
+
+ public static int getShulkerBoxesMaxCountUnsafe() {
+ return Math.clamp(ContainerExpansionConfig.shulkerCount, 1, 64);
+ }
+
+ public static boolean emptyShulkerBoxCheck(@NotNull ItemStack stack) {
+ return stack.getComponents().getOrDefault(DataComponents.CONTAINER, ItemContainerContents.EMPTY).stream().findAny().isEmpty();
+ }
+
+ public static boolean isStackable(ItemStack itemStack) {
+ return getItemMaxCount(itemStack) > 1 && (!itemStack.isDamageableItem() || !itemStack.isDamaged());
+ }
+
+ public static int getItemStackMaxCountReal(ItemStack stack) {
+ CompoundTag nbt = Optional.ofNullable(stack.get(DataComponents.CUSTOM_DATA)).orElse(CustomData.EMPTY).copyTag();
+ return nbt.getInt("Lophine.RealStackSize").orElse(stack.getMaxStackSize());
+ }
+
+ public static ItemStack encodeMaxStackSize(ItemStack itemStack) {
+ int realMaxStackSize = getItemStackMaxCountReal(itemStack);
+ int modifiedMaxStackSize = getItemMaxCount(itemStack);
+ if (itemStack.getMaxStackSize() != modifiedMaxStackSize) {
+ itemStack.set(DataComponents.MAX_STACK_SIZE, modifiedMaxStackSize);
+ CompoundTag nbt = itemStack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
+ nbt.putInt("Lophine.RealStackSize", realMaxStackSize);
+ itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(nbt));
+ }
+ return itemStack;
+ }
+
+ public static ItemStack decodeMaxStackSize(ItemStack itemStack) {
+ int realMaxStackSize = getItemStackMaxCountReal(itemStack);
+ if (itemStack.getMaxStackSize() != realMaxStackSize) {
+ itemStack.set(DataComponents.MAX_STACK_SIZE, realMaxStackSize);
+ CompoundTag nbt = itemStack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
+ nbt.remove("Lophine.RealStackSize");
+ if (nbt.isEmpty()) {
+ itemStack.remove(DataComponents.CUSTOM_DATA);
+ } else {
+ itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(nbt));
+ }
+ }
+ return itemStack;
+ }
+}