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:
Bruno Rybársky 2024-06-04 23:48:49 +02:00
parent 5473358a75
commit 48479c9a88
10 changed files with 491 additions and 66 deletions

@ -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();