UNFINISHED
Add Crafting, improve autosuck //TODO: - add into SettingsScreen all containers with taking out, autosuck and putting in - add block to store hard drives, because chests are too expensive to index - fix crafting
This commit is contained in:
parent
5473358a75
commit
48479c9a88
@ -8,7 +8,7 @@ yarn_mappings=1.20.6+build.3
|
|||||||
loader_version=0.15.11
|
loader_version=0.15.11
|
||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=2.3
|
mod_version=2.4
|
||||||
maven_group=systems.brn
|
maven_group=systems.brn
|
||||||
archives_base_name=Server_storage
|
archives_base_name=Server_storage
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ public class StorageBlockEntity extends BlockEntity implements Inventory, SidedI
|
|||||||
|
|
||||||
public Boolean sortAlphabetically = false;
|
public Boolean sortAlphabetically = false;
|
||||||
public Boolean allInventories = false;
|
public Boolean allInventories = false;
|
||||||
|
public Boolean autoSuck = false;
|
||||||
public String searchString = "";
|
public String searchString = "";
|
||||||
public int page = 0;
|
public int page = 0;
|
||||||
public ConnectedChests chests;
|
public ConnectedChests chests;
|
||||||
@ -37,6 +38,9 @@ public class StorageBlockEntity extends BlockEntity implements Inventory, SidedI
|
|||||||
|
|
||||||
public void rescanChests() {
|
public void rescanChests() {
|
||||||
this.chests = new ConnectedChests(world, this.pos, sortAlphabetically, searchString, allInventories);
|
this.chests = new ConnectedChests(world, this.pos, sortAlphabetically, searchString, allInventories);
|
||||||
|
if(autoSuck){
|
||||||
|
this.chests.autoSuck();
|
||||||
|
}
|
||||||
this.updateDisplays();
|
this.updateDisplays();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,6 +162,7 @@ public class StorageBlockEntity extends BlockEntity implements Inventory, SidedI
|
|||||||
nbt.putBoolean("sortAlphabetically", sortAlphabetically);
|
nbt.putBoolean("sortAlphabetically", sortAlphabetically);
|
||||||
nbt.putString("searchString", searchString);
|
nbt.putString("searchString", searchString);
|
||||||
nbt.putBoolean("allInventories", allInventories);
|
nbt.putBoolean("allInventories", allInventories);
|
||||||
|
nbt.putBoolean("autoSuck", autoSuck);
|
||||||
|
|
||||||
super.writeNbt(nbt, wrapperLookup);
|
super.writeNbt(nbt, wrapperLookup);
|
||||||
}
|
}
|
||||||
@ -171,5 +176,6 @@ public class StorageBlockEntity extends BlockEntity implements Inventory, SidedI
|
|||||||
sortAlphabetically = nbt.getBoolean("sortAlphabetically");
|
sortAlphabetically = nbt.getBoolean("sortAlphabetically");
|
||||||
searchString = nbt.getString("searchString");
|
searchString = nbt.getString("searchString");
|
||||||
allInventories = nbt.getBoolean("allInventories");
|
allInventories = nbt.getBoolean("allInventories");
|
||||||
|
autoSuck = nbt.getBoolean("autoSuck");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import static systems.brn.server_storage.lib.StorageOperations.*;
|
|||||||
|
|
||||||
public class ConnectedChests {
|
public class ConnectedChests {
|
||||||
public final List<Inventory> inventories;
|
public final List<Inventory> inventories;
|
||||||
|
public final List<Inventory> hoppers;
|
||||||
public final Inventory inventory;
|
public final Inventory inventory;
|
||||||
|
|
||||||
public final int containerCount;
|
public final int containerCount;
|
||||||
@ -24,11 +25,13 @@ public class ConnectedChests {
|
|||||||
|
|
||||||
public ConnectedChests(World world, BlockPos startPos, boolean sortAlphabetically, String searchString, boolean allInventories) {
|
public ConnectedChests(World world, BlockPos startPos, boolean sortAlphabetically, String searchString, boolean allInventories) {
|
||||||
List<Inventory> inventories = new ArrayList<>();
|
List<Inventory> inventories = new ArrayList<>();
|
||||||
|
List<Inventory> hoppers = new ArrayList<>();
|
||||||
Set<BlockPos> visited = new HashSet<>();
|
Set<BlockPos> visited = new HashSet<>();
|
||||||
|
|
||||||
getConnectedChestsHelper(world, startPos, inventories, visited, allInventories);
|
getConnectedChestsHelper(world, startPos, inventories, hoppers, visited, allInventories);
|
||||||
|
|
||||||
this.inventories = inventories;
|
this.inventories = inventories;
|
||||||
|
this.hoppers = hoppers;
|
||||||
this.containerCount = inventories.size();
|
this.containerCount = inventories.size();
|
||||||
this.inventory = getCombinedInventory(sortAlphabetically, searchString);
|
this.inventory = getCombinedInventory(sortAlphabetically, searchString);
|
||||||
|
|
||||||
@ -58,13 +61,18 @@ public class ConnectedChests {
|
|||||||
blockEntity instanceof ShulkerBoxBlockEntity;
|
blockEntity instanceof ShulkerBoxBlockEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void getConnectedChestsHelper(World world, BlockPos pos, List<Inventory> inventories, Set<BlockPos> visited, Boolean allContainers) {
|
private static void getConnectedChestsHelper(World world, BlockPos pos, List<Inventory> inventories, List<Inventory> hoppers, Set<BlockPos> visited, Boolean allContainers) {
|
||||||
if (visited.contains(pos)) {
|
if (visited.contains(pos)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
visited.add(pos);
|
visited.add(pos);
|
||||||
|
|
||||||
BlockEntity blockEntity = world.getBlockEntity(pos);
|
BlockEntity blockEntity = world.getBlockEntity(pos);
|
||||||
|
|
||||||
|
if (isEnabledHopper(blockEntity)) {
|
||||||
|
hoppers.add((Inventory) blockEntity);
|
||||||
|
}
|
||||||
|
|
||||||
if (isEnabledContainer(blockEntity, allContainers) || blockEntity instanceof StorageBlockEntity) {
|
if (isEnabledContainer(blockEntity, allContainers) || blockEntity instanceof StorageBlockEntity) {
|
||||||
if (isEnabledContainer(blockEntity, allContainers) && !(blockEntity instanceof StorageBlockEntity)) {
|
if (isEnabledContainer(blockEntity, allContainers) && !(blockEntity instanceof StorageBlockEntity)) {
|
||||||
inventories.add((Inventory) blockEntity);
|
inventories.add((Inventory) blockEntity);
|
||||||
@ -72,7 +80,7 @@ public class ConnectedChests {
|
|||||||
|
|
||||||
for (Direction direction : Direction.values()) {
|
for (Direction direction : Direction.values()) {
|
||||||
BlockPos nextPos = pos.offset(direction);
|
BlockPos nextPos = pos.offset(direction);
|
||||||
getConnectedChestsHelper(world, nextPos, inventories, visited, allContainers);
|
getConnectedChestsHelper(world, nextPos, inventories, hoppers, visited, allContainers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,27 +89,7 @@ public class ConnectedChests {
|
|||||||
private SimpleInventory getCombinedInventory(boolean sortAlphabetically, String query) {
|
private SimpleInventory getCombinedInventory(boolean sortAlphabetically, String query) {
|
||||||
Map<ItemStack, Integer> itemStackMap = new HashMap<>();
|
Map<ItemStack, Integer> itemStackMap = new HashMap<>();
|
||||||
for (Inventory inventory : inventories) {
|
for (Inventory inventory : inventories) {
|
||||||
for (int i = 0; i < inventory.size(); i++) {
|
addInventoryToMap(inventory, itemStackMap);
|
||||||
ItemStack stack = inventory.getStack(i);
|
|
||||||
if (!stack.isEmpty()) {
|
|
||||||
// Check if there's an existing ItemStack with the same item and metadata
|
|
||||||
boolean found = false;
|
|
||||||
for (Map.Entry<ItemStack, Integer> entry : itemStackMap.entrySet()) {
|
|
||||||
ItemStack existingStack = entry.getKey();
|
|
||||||
if (ItemStack.areItemsAndComponentsEqual(stack, existingStack)) {
|
|
||||||
int count = entry.getValue() + stack.getCount();
|
|
||||||
itemStackMap.put(existingStack.copy(), count);
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If no existing stack with the same item and metadata, add a new entry
|
|
||||||
if (!found) {
|
|
||||||
ItemStack copiedStack = stack.copy();
|
|
||||||
itemStackMap.put(copiedStack, stack.getCount());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return filterInventory(getSimpleInventory(itemStackMap.size(), itemStackMap, sortAlphabetically), query, sortAlphabetically);
|
return filterInventory(getSimpleInventory(itemStackMap.size(), itemStackMap, sortAlphabetically), query, sortAlphabetically);
|
||||||
}
|
}
|
||||||
@ -119,7 +107,7 @@ public class ConnectedChests {
|
|||||||
if (!filteredStack.isEmpty()) {
|
if (!filteredStack.isEmpty()) {
|
||||||
itemCount++;
|
itemCount++;
|
||||||
int count = itemStackMap.getOrDefault(filteredStack, 0) + filteredStack.getCount();
|
int count = itemStackMap.getOrDefault(filteredStack, 0) + filteredStack.getCount();
|
||||||
itemStackMap.put(filteredStack.copy(), count);
|
itemStackMap.put(filteredStack, count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getSimpleInventory(itemCount, itemStackMap, sortAlphabetically);
|
return getSimpleInventory(itemCount, itemStackMap, sortAlphabetically);
|
||||||
@ -141,6 +129,15 @@ public class ConnectedChests {
|
|||||||
return stack.isEmpty();
|
return stack.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isEnabledHopper(BlockEntity blockEntity) {
|
||||||
|
return blockEntity instanceof HopperBlockEntity ||
|
||||||
|
blockEntity instanceof TrappedChestBlockEntity ||
|
||||||
|
blockEntity instanceof FurnaceBlockEntity ||
|
||||||
|
blockEntity instanceof BlastFurnaceBlockEntity ||
|
||||||
|
blockEntity instanceof SmokerBlockEntity ||
|
||||||
|
blockEntity instanceof BrewingStandBlockEntity;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean canAddItemStack(ItemStack stack) {
|
public boolean canAddItemStack(ItemStack stack) {
|
||||||
// Iterate over each chest to check if it's possible to insert the ItemStack
|
// Iterate over each chest to check if it's possible to insert the ItemStack
|
||||||
for (Inventory chest : inventories) {
|
for (Inventory chest : inventories) {
|
||||||
@ -155,29 +152,30 @@ public class ConnectedChests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's not possible to insert into any chest, return false
|
// If it's not possible to insert into any chest, return false
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canRemove(ItemStack stackToRemove) {
|
public void autoSuck() {
|
||||||
int remainingToRemove = stackToRemove.getCount();
|
for (Inventory chest : hoppers) {
|
||||||
|
for (int i = 0; i < chest.size(); i++) {
|
||||||
for (int i = 0; i < inventory.size(); i++) {
|
ItemStack slotStack = chest.getStack(i);
|
||||||
ItemStack slotStack = inventory.getStack(i);
|
if (!slotStack.isEmpty()) {
|
||||||
if (canCombine(slotStack, stackToRemove)) {
|
if (this.canAddItemStack(slotStack)) {
|
||||||
// If the slot contains the same item type
|
if (this.tryPutItemStack(slotStack)) {
|
||||||
if (slotStack.getCount() >= remainingToRemove) {
|
removeFromInventory(chest, slotStack, slotStack.getCount());
|
||||||
// If the count in the slot is sufficient to remove the requested amount
|
}
|
||||||
return true;
|
;
|
||||||
} else {
|
} else {
|
||||||
// If the count in the slot is not sufficient, update remainingToRemove
|
return;
|
||||||
remainingToRemove -= slotStack.getCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If no matching stack with sufficient count is found, return false
|
}
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
public boolean canRemove(ItemStack stackToRemove) {
|
||||||
|
return canRemoveCount(stackToRemove, inventory) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemStack removeItemStack(ItemStack stackToRemove) {
|
public ItemStack removeItemStack(ItemStack stackToRemove) {
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
package systems.brn.server_storage.lib;
|
||||||
|
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.recipe.CraftingRecipe;
|
||||||
|
import net.minecraft.recipe.RecipeEntry;
|
||||||
|
|
||||||
|
public class CraftingEntry {
|
||||||
|
public final ItemStack itemStack;
|
||||||
|
public final RecipeEntry<CraftingRecipe> recipeEntry;
|
||||||
|
public CraftingEntry(ItemStack itemStack, RecipeEntry<CraftingRecipe> recipeEntry) {
|
||||||
|
this.itemStack = itemStack;
|
||||||
|
this.recipeEntry = recipeEntry;
|
||||||
|
}
|
||||||
|
}
|
@ -31,7 +31,11 @@ public abstract class PagedGui extends SimpleGui {
|
|||||||
public static final String GUI_A = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGU0MTc0ODEyMTYyNmYyMmFlMTZhNGM2NjRjNzMwMWE5ZjhlYTU5MWJmNGQyOTg4ODk1NzY4MmE5ZmRhZiJ9fX0=";
|
public static final String GUI_A = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGU0MTc0ODEyMTYyNmYyMmFlMTZhNGM2NjRjNzMwMWE5ZjhlYTU5MWJmNGQyOTg4ODk1NzY4MmE5ZmRhZiJ9fX0=";
|
||||||
public static final String GUI_1 = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2E1MTZmYmFlMTYwNThmMjUxYWVmOWE2OGQzMDc4NTQ5ZjQ4ZjZkNWI2ODNmMTljZjVhMTc0NTIxN2Q3MmNjIn19fQ==";
|
public static final String GUI_1 = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2E1MTZmYmFlMTYwNThmMjUxYWVmOWE2OGQzMDc4NTQ5ZjQ4ZjZkNWI2ODNmMTljZjVhMTc0NTIxN2Q3MmNjIn19fQ==";
|
||||||
public static final String GUI_STORE_ALL = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWFkNmM4MWY4OTlhNzg1ZWNmMjZiZTFkYzQ4ZWFlMmJjZmU3NzdhODYyMzkwZjU3ODVlOTViZDgzYmQxNGQifX19";
|
public static final String GUI_STORE_ALL = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWFkNmM4MWY4OTlhNzg1ZWNmMjZiZTFkYzQ4ZWFlMmJjZmU3NzdhODYyMzkwZjU3ODVlOTViZDgzYmQxNGQifX19";
|
||||||
public static final String GUI_SETTINGS = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2EzYzhjNmQzYWFhOTYzNjNkNGJlZjI1NzhmMTAyNDc4MWVhMTRlOWQ4NWE5ZGNmYzA5MzU4NDdhNmZiNWM4ZCJ9fX0=";
|
public static final String GUI_CONTAINERS = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2EzYzhjNmQzYWFhOTYzNjNkNGJlZjI1NzhmMTAyNDc4MWVhMTRlOWQ4NWE5ZGNmYzA5MzU4NDdhNmZiNWM4ZCJ9fX0=";
|
||||||
|
public static final String GUI_SETTINGS = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTRkNDliYWU5NWM3OTBjM2IxZmY1YjJmMDEwNTJhNzE0ZDYxODU0ODFkNWIxYzg1OTMwYjNmOTlkMjMyMTY3NCJ9fX0=";
|
||||||
|
public static final String GUI_CRAFTING = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWQyYzBjZWRmYzMyZTNiZWVlOTU1Y2FiZDY2ZmQ0ZDc2NWVlZGEzYWRjYzg0YmM0NTFjOWZkYmVjZjNjYjdjMiJ9fX0=";
|
||||||
|
public static final String GUI_AUTOSUCK_OFF = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGViODFlZjg5MDIzNzk2NTBiYTc5ZjQ1NzIzZDZiOWM4ODgzODhhMDBmYzRlMTkyZjM0NTRmZTE5Mzg4MmVlMSJ9fX0=";
|
||||||
|
public static final String GUI_AUTOSUCK_ON = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMThjNDQzYWRhNmUzOWZjYTgzN2EwMzgzYjBhNWUzZTU1NDc3M2I5NjYwYzQ4NzNmNTkxMDMyZGJlOWFkY2RmOCJ9fX0=";
|
||||||
|
|
||||||
public static final int PAGE_SIZE = 9 * 5;
|
public static final int PAGE_SIZE = 9 * 5;
|
||||||
protected final Runnable closeCallback;
|
protected final Runnable closeCallback;
|
||||||
@ -112,17 +116,18 @@ public abstract class PagedGui extends SimpleGui {
|
|||||||
protected DisplayElement getNavElement(int id) {
|
protected DisplayElement getNavElement(int id) {
|
||||||
return switch (id) {
|
return switch (id) {
|
||||||
case 0 -> DisplayElement.previousPage(this);
|
case 0 -> DisplayElement.previousPage(this);
|
||||||
case 2 -> this.search();
|
case 1 -> this.search();
|
||||||
case 3 -> this.sorting();
|
case 2 -> this.sorting();
|
||||||
case 4 -> this.refresh();
|
case 3 -> this.refresh();
|
||||||
case 5 -> this.storeAll();
|
case 4 -> this.storeAll();
|
||||||
case 6 -> this.settings();
|
case 5 -> this.settings();
|
||||||
|
case 6 -> this.crafting();
|
||||||
case 7 -> DisplayElement.nextPage(this);
|
case 7 -> DisplayElement.nextPage(this);
|
||||||
case 8 -> DisplayElement.of(
|
case 8 -> DisplayElement.of(
|
||||||
new GuiElementBuilder(Items.STRUCTURE_VOID)
|
new GuiElementBuilder(Items.STRUCTURE_VOID)
|
||||||
.setName(Text.translatable(this.closeCallback != null ? "gui.back" : "mco.selectServer.close").formatted(Formatting.RED))
|
.setName(Text.translatable(this.closeCallback != null ? "gui.back" : "mco.selectServer.close").formatted(Formatting.RED))
|
||||||
.hideDefaultTooltip().noDefaults()
|
.hideDefaultTooltip().noDefaults()
|
||||||
.setCallback((x, y, z) -> {
|
.setCallback((i, clickType, slotActionType) -> {
|
||||||
playClickSound(this.player);
|
playClickSound(this.player);
|
||||||
this.close();
|
this.close();
|
||||||
})
|
})
|
||||||
@ -135,9 +140,14 @@ public abstract class PagedGui extends SimpleGui {
|
|||||||
return DisplayElement.filler();
|
return DisplayElement.filler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected DisplayElement crafting() {
|
||||||
|
return DisplayElement.filler();
|
||||||
|
}
|
||||||
|
|
||||||
protected DisplayElement search(){
|
protected DisplayElement search(){
|
||||||
return DisplayElement.filler();
|
return DisplayElement.filler();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DisplayElement sorting(){
|
protected DisplayElement sorting(){
|
||||||
return DisplayElement.filler();
|
return DisplayElement.filler();
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,48 @@ public class StorageOperations {
|
|||||||
return remainingToRemove;
|
return remainingToRemove;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int canRemoveCount(ItemStack stackToRemove, Inventory inventory) {
|
||||||
|
int remainingToRemove = stackToRemove.getCount();
|
||||||
|
|
||||||
|
for (int i = 0; i < inventory.size(); i++) {
|
||||||
|
ItemStack slotStack = inventory.getStack(i);
|
||||||
|
if (canCombine(slotStack, stackToRemove)) {
|
||||||
|
// If the slot contains the same item type
|
||||||
|
if (slotStack.getCount() >= remainingToRemove) {
|
||||||
|
// If the count in the slot is sufficient to remove the requested amount
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
// If the count in the slot is not sufficient, update remainingToRemove
|
||||||
|
remainingToRemove -= slotStack.getCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If no matching stack with sufficient count is found, return false
|
||||||
|
return remainingToRemove;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean canCombine(ItemStack stack1, ItemStack stack2) {
|
public static boolean canCombine(ItemStack stack1, ItemStack stack2) {
|
||||||
return !stack1.isEmpty() && stack1.getItem() == stack2.getItem() && ItemStack.areItemsAndComponentsEqual(stack1, stack2);
|
return !stack1.isEmpty() && stack1.getItem() == stack2.getItem() && ItemStack.areItemsAndComponentsEqual(stack1, stack2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void addInventoryToMap(Inventory inventory, Map<ItemStack, Integer> itemStackMap) {
|
||||||
|
for (int i = 0; i < inventory.size(); i++) {
|
||||||
|
ItemStack stack = inventory.getStack(i);
|
||||||
|
if (!stack.isEmpty()) {
|
||||||
|
addToMap(itemStackMap, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addToMap(Map<ItemStack, Integer> itemStackMap, ItemStack stack) {
|
||||||
|
for (Map.Entry<ItemStack, Integer> entry : itemStackMap.entrySet()) {
|
||||||
|
ItemStack existingStack = entry.getKey();
|
||||||
|
if (ItemStack.areItemsAndComponentsEqual(stack, existingStack)) {
|
||||||
|
int newCount = entry.getValue() + stack.getCount();
|
||||||
|
itemStackMap.put(existingStack, newCount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itemStackMap.put(stack.copy(), stack.getCount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ import net.minecraft.component.type.LoreComponent;
|
|||||||
import net.minecraft.inventory.Inventory;
|
import net.minecraft.inventory.Inventory;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.recipe.*;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.text.RawFilteredPair;
|
import net.minecraft.text.RawFilteredPair;
|
||||||
import net.minecraft.text.Style;
|
import net.minecraft.text.Style;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
@ -99,4 +101,60 @@ public class Util {
|
|||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ArrayList<CraftingEntry> getCraftableRecipes(Inventory inventory, MinecraftServer server) {
|
||||||
|
RecipeManager recipeManager = server.getRecipeManager();
|
||||||
|
List<RecipeEntry<CraftingRecipe>> allRecipes = recipeManager.listAllOfType(RecipeType.CRAFTING);
|
||||||
|
|
||||||
|
ArrayList<CraftingEntry> craftingEntries = new ArrayList<>();
|
||||||
|
|
||||||
|
for (RecipeEntry<CraftingRecipe> recipe : allRecipes) {
|
||||||
|
int maxAmount = -1;
|
||||||
|
boolean canMake = true;
|
||||||
|
for (Ingredient ingredient : recipe.value().getIngredients()) {
|
||||||
|
for (ItemStack stack : ingredient.getMatchingStacks()) {
|
||||||
|
if (stack.isEmpty()) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
//if inventory contains stack
|
||||||
|
boolean foundUsableStack = false;
|
||||||
|
for (int i = 0; i < inventory.size(); i++) {
|
||||||
|
if (inventory.getStack(i).getItem().equals(stack.getItem())) {
|
||||||
|
if (maxAmount == -1) {
|
||||||
|
maxAmount = inventory.getStack(i).getCount();
|
||||||
|
} else {
|
||||||
|
maxAmount = Math.min(maxAmount, inventory.getStack(i).getCount());
|
||||||
|
}
|
||||||
|
foundUsableStack = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundUsableStack) {
|
||||||
|
canMake = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (maxAmount > 1 && canMake) {
|
||||||
|
Item outputItem = recipe.value().getResult(server.getRegistryManager()).getItem();
|
||||||
|
CraftingEntry entry = new CraftingEntry(new ItemStack(outputItem, maxAmount), recipe);
|
||||||
|
boolean needToAdd = true;
|
||||||
|
for (int i = 0; i < craftingEntries.size(); i++) {
|
||||||
|
CraftingEntry entryLoop = craftingEntries.get(i);
|
||||||
|
if (entryLoop.itemStack.getItem().equals(outputItem)) {
|
||||||
|
needToAdd = false;
|
||||||
|
if (maxAmount > entryLoop.itemStack.getCount()) {
|
||||||
|
craftingEntries.set(i, entry);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needToAdd) {
|
||||||
|
craftingEntries.add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return craftingEntries;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,199 @@
|
|||||||
|
package systems.brn.server_storage.screens;
|
||||||
|
|
||||||
|
import eu.pb4.sgui.api.elements.GuiElementBuilder;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.inventory.Inventory;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.recipe.CraftingRecipe;
|
||||||
|
import net.minecraft.recipe.Ingredient;
|
||||||
|
import net.minecraft.recipe.RecipeEntry;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import systems.brn.server_storage.lib.CraftingEntry;
|
||||||
|
import systems.brn.server_storage.lib.PagedGui;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static systems.brn.server_storage.lib.StorageOperations.*;
|
||||||
|
import static systems.brn.server_storage.lib.Util.addCountToLore;
|
||||||
|
import static systems.brn.server_storage.lib.Util.getCraftableRecipes;
|
||||||
|
|
||||||
|
public class CraftingScreen extends PagedGui {
|
||||||
|
private final StorageScreen storageScreen;
|
||||||
|
|
||||||
|
private ArrayList<CraftingEntry> craftingEntries;
|
||||||
|
|
||||||
|
private ArrayList<DisplayElement> recipesList;
|
||||||
|
|
||||||
|
public CraftingScreen(StorageScreen storageScreen) {
|
||||||
|
super(storageScreen.getPlayer(), null);
|
||||||
|
this.storageScreen = storageScreen;
|
||||||
|
this.setTitle(Text.translatable("container.crafting"));
|
||||||
|
this.updateDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateDisplay(){
|
||||||
|
storageScreen.blockEntity.rescanChests();
|
||||||
|
Map<ItemStack, Integer> itemStackMap = new HashMap<>();
|
||||||
|
addInventoryToMap(storageScreen.getPlayer().getInventory(), itemStackMap);
|
||||||
|
addInventoryToMap(storageScreen.blockEntity.chests.inventory, itemStackMap);
|
||||||
|
Inventory inventory = getSimpleInventory(itemStackMap.size(), itemStackMap, false);
|
||||||
|
this.craftingEntries = getCraftableRecipes(inventory, Objects.requireNonNull(player.getServer()));
|
||||||
|
this.recipesList = getAvailableRecipes();
|
||||||
|
super.updateDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<DisplayElement> getAvailableRecipes() {
|
||||||
|
ArrayList<DisplayElement> recipes = new ArrayList<>();
|
||||||
|
|
||||||
|
for (CraftingEntry craftingEntry : craftingEntries) {
|
||||||
|
ItemStack stackWithCount = addCountToLore(craftingEntry.itemStack.getCount(), craftingEntry.itemStack);
|
||||||
|
if (stackWithCount.getCount() > stackWithCount.getMaxCount()) {
|
||||||
|
stackWithCount.setCount(stackWithCount.getMaxCount());
|
||||||
|
}
|
||||||
|
recipes.add(
|
||||||
|
DisplayElement.of(new GuiElementBuilder(stackWithCount)
|
||||||
|
.setCallback((i, clickType, slotActionType) -> {
|
||||||
|
playClickSound(player);
|
||||||
|
RecipeEntry<CraftingRecipe> recipeEntry = craftingEntry.recipeEntry;
|
||||||
|
|
||||||
|
// Crafting logic based on click type
|
||||||
|
if (clickType.isLeft) { // put into player inventory
|
||||||
|
if (clickType.shift) { // craft all
|
||||||
|
craftAll(player, recipeEntry, true);
|
||||||
|
} else { // craft one stack
|
||||||
|
craftOneStack(player, recipeEntry, true);
|
||||||
|
}
|
||||||
|
} else if (clickType.isRight) { // put back into storage
|
||||||
|
if (clickType.shift) { // craft all
|
||||||
|
craftAll(player, recipeEntry, false);
|
||||||
|
} else { // craft one stack
|
||||||
|
craftOneStack(player, recipeEntry, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateDisplay();
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return recipes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void craftAll(PlayerEntity player, RecipeEntry<CraftingRecipe> recipeEntry, boolean toPlayerInventory) {
|
||||||
|
while (canCraft(recipeEntry)) {
|
||||||
|
if (craftOneStack(player, recipeEntry, toPlayerInventory)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean craftOneStack(PlayerEntity player, RecipeEntry<CraftingRecipe> recipeEntry, boolean toPlayerInventory) {
|
||||||
|
if (!canCraft(recipeEntry)) {
|
||||||
|
return true; //stop
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check and remove ingredients
|
||||||
|
for (Ingredient ingredient : recipeEntry.value().getIngredients()) {
|
||||||
|
ItemStack stackToRemove = findMatchingStack(ingredient);
|
||||||
|
if (stackToRemove == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int requiredCount = canRemoveCount(stackToRemove, this.storageScreen.blockEntity.chests.inventory);
|
||||||
|
|
||||||
|
if (requiredCount > 0 && canRemoveCount(stackToRemove, this.storageScreen.getPlayer().getInventory()) < requiredCount) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
removeItems(stackToRemove, requiredCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the result to the appropriate inventory
|
||||||
|
ItemStack outputStack = recipeEntry.value().getResult(storageScreen.getPlayer().getRegistryManager());
|
||||||
|
if (toPlayerInventory) {
|
||||||
|
if (canInsertItemIntoPlayerInventory(player, outputStack) == outputStack.getCount()) {
|
||||||
|
player.getInventory().insertStack(outputStack);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.storageScreen.blockEntity.chests.canAddItemStack(outputStack)) {
|
||||||
|
this.storageScreen.blockEntity.chests.tryPutItemStack(outputStack);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove ingredients
|
||||||
|
for (Ingredient ingredient : recipeEntry.value().getIngredients()) {
|
||||||
|
ItemStack stackToRemove = findMatchingStack(ingredient);
|
||||||
|
if (stackToRemove == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
removeItems(stackToRemove, stackToRemove.getCount());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canCraft(RecipeEntry<CraftingRecipe> recipeEntry) {
|
||||||
|
for (Ingredient ingredient : recipeEntry.value().getIngredients()) {
|
||||||
|
ItemStack stackToRemove = findMatchingStack(ingredient);
|
||||||
|
if (stackToRemove == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int requiredCount = canRemoveCount(stackToRemove, this.storageScreen.blockEntity.chests.inventory);
|
||||||
|
|
||||||
|
if (requiredCount > 0 && canRemoveCount(stackToRemove, this.storageScreen.getPlayer().getInventory()) < requiredCount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemStack findMatchingStack(Ingredient ingredient) {
|
||||||
|
for (ItemStack stack : ingredient.getMatchingStacks()) {
|
||||||
|
if (this.storageScreen.blockEntity.chests.canRemove(stack)) {
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeItems(ItemStack stack, int count) {
|
||||||
|
// Logic to remove items from the storage
|
||||||
|
ItemStack stackRemove = stack.copy();
|
||||||
|
stackRemove.setCount(count);
|
||||||
|
ItemStack fromPlayer = this.storageScreen.blockEntity.chests.removeItemStack(stackRemove);
|
||||||
|
if (fromPlayer != null && fromPlayer.getCount() > 0) {
|
||||||
|
Inventory playerInventory = player.getInventory();
|
||||||
|
for (int i = 0; i < playerInventory.size(); i++) {
|
||||||
|
if (playerInventory.getStack(i).equals(fromPlayer)) {
|
||||||
|
playerInventory.removeStack(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose() {
|
||||||
|
super.onClose();
|
||||||
|
storageScreen.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getPageAmount() {
|
||||||
|
return Math.ceilDivExact(recipesList.size(), 9 * 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DisplayElement getElement(int id) {
|
||||||
|
if (id >=0 && id < recipesList.size()) {
|
||||||
|
return recipesList.get(id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return DisplayElement.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package systems.brn.server_storage.screens;
|
||||||
|
|
||||||
|
import eu.pb4.sgui.api.elements.GuiElementBuilder;
|
||||||
|
import net.minecraft.item.Items;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Formatting;
|
||||||
|
import systems.brn.server_storage.lib.PagedGui;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class SettingsScreen extends PagedGui {
|
||||||
|
|
||||||
|
private final StorageScreen storageScreen;
|
||||||
|
|
||||||
|
private ArrayList<DisplayElement> settingsList;
|
||||||
|
|
||||||
|
public SettingsScreen(StorageScreen storageScreen) {
|
||||||
|
super(storageScreen.getPlayer(), null);
|
||||||
|
this.storageScreen = storageScreen;
|
||||||
|
this.setTitle(Text.translatable("mco.configure.world.buttons.settings"));
|
||||||
|
this.updateDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose() {
|
||||||
|
super.onClose();
|
||||||
|
storageScreen.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateDisplay() {
|
||||||
|
this.settingsList = new ArrayList<>();
|
||||||
|
this.settingsList.add(containers());
|
||||||
|
this.settingsList.add(autoSuck());
|
||||||
|
super.updateDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PagedGui.DisplayElement containers() {
|
||||||
|
return PagedGui.DisplayElement.of(
|
||||||
|
new GuiElementBuilder(Items.PLAYER_HEAD)
|
||||||
|
.setName(Text.translatable(storageScreen.blockEntity.allInventories ? "gui.all" : "options.fov.min").formatted(Formatting.WHITE))
|
||||||
|
.hideDefaultTooltip().noDefaults()
|
||||||
|
.setSkullOwner(GUI_CONTAINERS)
|
||||||
|
.setCallback((x, y, z) -> {
|
||||||
|
storageScreen.blockEntity.allInventories ^= true;
|
||||||
|
storageScreen.blockEntity.markDirty();
|
||||||
|
storageScreen.blockEntity.rescanChests();
|
||||||
|
playClickSound(getPlayer());
|
||||||
|
updateDisplay();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getPageAmount() {
|
||||||
|
return Math.ceilDivExact(settingsList.size(), 9*6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DisplayElement getElement(int id) {
|
||||||
|
if (id >= 0 && id < settingsList.size()) {
|
||||||
|
return settingsList.get(id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return DisplayElement.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PagedGui.DisplayElement autoSuck() {
|
||||||
|
return PagedGui.DisplayElement.of(
|
||||||
|
new GuiElementBuilder(Items.PLAYER_HEAD)
|
||||||
|
.setName(Text.translatable(storageScreen.blockEntity.autoSuck ? "gui.yes" : "gui.no").formatted(Formatting.WHITE))
|
||||||
|
.hideDefaultTooltip().noDefaults()
|
||||||
|
.setSkullOwner(storageScreen.blockEntity.autoSuck ? GUI_AUTOSUCK_ON : GUI_AUTOSUCK_OFF)
|
||||||
|
.setCallback((x, y, z) -> {
|
||||||
|
storageScreen.blockEntity.autoSuck ^= true;
|
||||||
|
storageScreen.blockEntity.rescanChests();
|
||||||
|
playClickSound(getPlayer());
|
||||||
|
updateDisplay();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,7 @@ import static systems.brn.server_storage.lib.Util.removeCountFromLore;
|
|||||||
|
|
||||||
public class StorageScreen extends PagedGui {
|
public class StorageScreen extends PagedGui {
|
||||||
private final ServerPlayerEntity player;
|
private final ServerPlayerEntity player;
|
||||||
private final StorageBlockEntity blockEntity;
|
public final StorageBlockEntity blockEntity;
|
||||||
|
|
||||||
public StorageScreen(ServerPlayerEntity player, BlockPos pos, @Nullable Runnable closeCallback) {
|
public StorageScreen(ServerPlayerEntity player, BlockPos pos, @Nullable Runnable closeCallback) {
|
||||||
super(player, closeCallback);
|
super(player, closeCallback);
|
||||||
@ -118,22 +118,6 @@ public class StorageScreen extends PagedGui {
|
|||||||
return super.insertItem(stack, startIndex, endIndex, fromLast);
|
return super.insertItem(stack, startIndex, endIndex, fromLast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected DisplayElement settings() {
|
|
||||||
return DisplayElement.of(
|
|
||||||
new GuiElementBuilder(Items.PLAYER_HEAD)
|
|
||||||
.setName(Text.translatable(this.blockEntity.allInventories ? "gui.all" : "options.fov.min").formatted(Formatting.WHITE))
|
|
||||||
.hideDefaultTooltip().noDefaults()
|
|
||||||
.setSkullOwner(GUI_SETTINGS)
|
|
||||||
.setCallback((x, y, z) -> {
|
|
||||||
this.blockEntity.allInventories ^= true;
|
|
||||||
this.blockEntity.markDirty();
|
|
||||||
this.blockEntity.rescanChests();
|
|
||||||
playClickSound(getPlayer());
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DisplayElement search() {
|
protected DisplayElement search() {
|
||||||
return DisplayElement.of(
|
return DisplayElement.of(
|
||||||
@ -149,6 +133,21 @@ public class StorageScreen extends PagedGui {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DisplayElement settings() {
|
||||||
|
return DisplayElement.of(
|
||||||
|
new GuiElementBuilder(Items.PLAYER_HEAD)
|
||||||
|
.setName(Text.translatable("mco.configure.world.settings.title").formatted(Formatting.WHITE))
|
||||||
|
.hideDefaultTooltip().noDefaults()
|
||||||
|
.setSkullOwner(GUI_SETTINGS)
|
||||||
|
.setCallback((x, y, z) -> {
|
||||||
|
SettingsScreen settingsScreen = new SettingsScreen(this);
|
||||||
|
playClickSound(getPlayer());
|
||||||
|
settingsScreen.open();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DisplayElement sorting() {
|
protected DisplayElement sorting() {
|
||||||
return DisplayElement.of(
|
return DisplayElement.of(
|
||||||
@ -164,6 +163,7 @@ public class StorageScreen extends PagedGui {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DisplayElement storeAll() {
|
protected DisplayElement storeAll() {
|
||||||
return DisplayElement.of(
|
return DisplayElement.of(
|
||||||
@ -181,6 +181,22 @@ public class StorageScreen extends PagedGui {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DisplayElement crafting() {
|
||||||
|
return DisplayElement.of(
|
||||||
|
new GuiElementBuilder(Items.PLAYER_HEAD)
|
||||||
|
.setName(Text.translatable("container.crafting").formatted(Formatting.WHITE))
|
||||||
|
.hideDefaultTooltip().noDefaults()
|
||||||
|
.setSkullOwner(GUI_CRAFTING)
|
||||||
|
.setCallback((x, y, z) -> {
|
||||||
|
playClickSound(player);
|
||||||
|
CraftingScreen craftingScreen = new CraftingScreen(this);
|
||||||
|
playClickSound(getPlayer());
|
||||||
|
craftingScreen.open();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public void doSearch(String query) {
|
public void doSearch(String query) {
|
||||||
this.blockEntity.searchString = query;
|
this.blockEntity.searchString = query;
|
||||||
this.blockEntity.rescanChests();
|
this.blockEntity.rescanChests();
|
||||||
|
Loading…
Reference in New Issue
Block a user