diff --git a/1.14/gradle.properties b/1.14/gradle.properties index d6e478b..38b2f12 100644 --- a/1.14/gradle.properties +++ b/1.14/gradle.properties @@ -5,4 +5,4 @@ version_minecraft=1.14.4 version_forge_minecraft=1.14.4-28.2.3 version_fml_mappings=20190719-1.14.3 version_jei=1.14.4:6.0.0.10 -version_engineersdecor=1.0.20-b2 +version_engineersdecor=1.0.20-b3 diff --git a/1.14/readme.md b/1.14/readme.md index 3e40423..d70f080 100644 --- a/1.14/readme.md +++ b/1.14/readme.md @@ -11,6 +11,8 @@ Mod sources for Minecraft version 1.14.4. ## Version history + ~ v1.0.20-b3 [M] + - v1.0.20-b2 [U] Forge version requirement set to >= 28.2.3. [A] Added Labeled Crate (storage crate with built-in item frame). diff --git a/1.15/meta/update.json b/1.15/meta/update.json index 53aa50c..93bac2c 100644 --- a/1.15/meta/update.json +++ b/1.15/meta/update.json @@ -1,6 +1,7 @@ { "homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/", "1.15.2": { + "1.0.20-b2": "[A] Added Labeled Crate (storage crate with built-in item frame).", "1.0.20-b1": "[A] Electrical Furnace: Added four-position speed switch (off, 100%, 150%, 200%), power consumption increases at higher rate (off, 100%, 200%, 400%).\n[A] Added Steel Mesh Fence Gate (single or double height gate fitting to the Steel Mesh Fence).\n[M] Waste Incinerator processing speed tweaked.\n[F] Fixed steel table visual glitch (thx Urbanxx001).\n[M] MCP/Forge mappings updated.", "1.0.19-b5": "[A] Added right-click display of power and progress information for Block Breaker, Solar Panel, and Tree Cutter.\n[A] Solar Panel power curve tuned.\n[A] Mod manual 1st edition release recipe added.\n[A] Factory Hopper: Resetting NBT when breaking with empty inventory (for stacking), enabled item cap for all sides.\n[M] Electrical Furnace model polished.", "1.0.19-b4": "[A] Ported primary Immersive Engineering dependent recipes (alternative recipes will still work if IE is not installed).\n[F] Blacklisted Treated Wood Crafting Table in inventorysorter mod (issue #88, thx Nachtflame).\n[M] Furni comparator output overrides reflect input slots and empty fuel state/power-cutoff.\n[M] Solar Panel config: Default value for internal battery capacity increased.\n[F] Block Placer: Shifted GUI player slots 1px to the right.\n[A] Added mod block tags for slabs, stairs, and walls (PR#89, thanks CrudeAustin for the data).\n[A] Added experimental Patchouli manual (creative only).", @@ -15,6 +16,6 @@ }, "promos": { "1.15.2-recommended": "", - "1.15.2-latest": "1.0.20-b1" + "1.15.2-latest": "1.0.20-b2" } } \ No newline at end of file diff --git a/1.15/readme.md b/1.15/readme.md index f2e791e..155c4d2 100644 --- a/1.15/readme.md +++ b/1.15/readme.md @@ -11,7 +11,7 @@ Mod sources for Minecraft version 1.15.1. ## Version history - ~ v1.0.20-b2 [A] Added Labeled Crate (storage crate with built-in item frame). + - v1.0.20-b2 [A] Added Labeled Crate (storage crate with built-in item frame). - v1.0.20-b1 [A] Electrical Furnace: Added four-position speed switch (off, 100%, 150%, 200%), power consumption increases at higher rate (off, 100%, 200%, 400%). diff --git a/1.15/src/main/java/wile/engineersdecor/ModContent.java b/1.15/src/main/java/wile/engineersdecor/ModContent.java index 0e3b41c..5d8a02c 100644 --- a/1.15/src/main/java/wile/engineersdecor/ModContent.java +++ b/1.15/src/main/java/wile/engineersdecor/ModContent.java @@ -891,7 +891,7 @@ public class ModContent public static final ContainerType CT_SMALL_LAB_FURNACE; public static final ContainerType CT_SMALL_ELECTRICAL_FURNACE; public static final ContainerType CT_WASTE_INCINERATOR; - public static final ContainerType CT_LABELED_CRATE; + public static final ContainerType CT_LABELED_CRATE; static { CT_TREATED_WOOD_CRAFTING_TABLE = (new ContainerType(BlockDecorCraftingTable.CraftingTableContainer::new)); @@ -908,7 +908,7 @@ public class ModContent CT_SMALL_ELECTRICAL_FURNACE.setRegistryName(ModEngineersDecor.MODID,"ct_small_electrical_furnace"); CT_WASTE_INCINERATOR = (new ContainerType(BlockDecorWasteIncinerator.BContainer::new)); CT_WASTE_INCINERATOR.setRegistryName(ModEngineersDecor.MODID,"ct_small_waste_incinerator"); - CT_LABELED_CRATE = (new ContainerType(BlockDecorLabeledCrate.BContainer::new)); + CT_LABELED_CRATE = (new ContainerType(BlockDecorLabeledCrate.LabeledCrateContainer::new)); CT_LABELED_CRATE.setRegistryName(ModEngineersDecor.MODID,"ct_labeled_crate"); } @@ -999,7 +999,7 @@ public class ModContent public static final void registerContainerGuis(final FMLClientSetupEvent event) { ScreenManager.registerFactory(CT_TREATED_WOOD_CRAFTING_TABLE, BlockDecorCraftingTable.CraftingTableGui::new); - ScreenManager.registerFactory(CT_LABELED_CRATE, BlockDecorLabeledCrate.BGui::new); + ScreenManager.registerFactory(CT_LABELED_CRATE, BlockDecorLabeledCrate.LabeledCrateGui::new); ScreenManager.registerFactory(CT_FACTORY_DROPPER, BlockDecorDropper.BGui::new); ScreenManager.registerFactory(CT_FACTORY_PLACER, BlockDecorPlacer.BGui::new); ScreenManager.registerFactory(CT_FACTORY_HOPPER, BlockDecorHopper.BGui::new); diff --git a/1.15/src/main/java/wile/engineersdecor/blocks/BlockDecorCraftingTable.java b/1.15/src/main/java/wile/engineersdecor/blocks/BlockDecorCraftingTable.java index e4bf4d8..56c95d1 100644 --- a/1.15/src/main/java/wile/engineersdecor/blocks/BlockDecorCraftingTable.java +++ b/1.15/src/main/java/wile/engineersdecor/blocks/BlockDecorCraftingTable.java @@ -12,6 +12,7 @@ import wile.engineersdecor.ModContent; import wile.engineersdecor.ModEngineersDecor; import wile.engineersdecor.libmc.detail.Auxiliaries; import wile.engineersdecor.libmc.detail.Inventories; +import wile.engineersdecor.libmc.detail.Inventories.SlotRange; import wile.engineersdecor.libmc.detail.Networking; import net.minecraft.inventory.container.*; import net.minecraft.network.play.server.SSetSlotPacket; @@ -467,7 +468,7 @@ public class BlockDecorCraftingTable final ItemStack stack = super.slotClick(slotId, button, clickType, player); if((with_outslot_defined_refab) && (slotId == 0) && (clickType == ClickType.PICKUP)) { if((!crafting_matrix_changed_now_) && (!player.world.isRemote()) && (crafting_grid_empty())) { - final ItemStack dragged = player.inventory.getItemStack(); // @todo: check, as far as seen this is actually `stack`. + final ItemStack dragged = player.inventory.getItemStack(); if((dragged != null) && (!dragged.isEmpty())) { try_result_stack_refab(dragged, player.world); } else if(!history().current().isEmpty()) { @@ -487,12 +488,14 @@ public class BlockDecorCraftingTable Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); } + @Override public void onServerPacketReceived(int windowId, CompoundNBT nbt) { if(nbt.contains("history")) history_.read(nbt.getCompound("history")); if(nbt.contains("hascollision")) has_recipe_collision_ = nbt.getBoolean("hascollision"); } + @Override public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt) { boolean changed = false; @@ -608,7 +611,7 @@ public class BlockDecorCraftingTable if(Inventories.areItemStacksDifferent(reference_stack, stack)) continue; ItemStack remaining = from_inventory.getStackInSlot(i); for(SlotRange range:to_ranges) { - remaining = move_stack_to_inventory(remaining, range, false, 0); + remaining = range.insert(remaining, false, 0); if(!remaining.isEmpty()) { abort = true; // no space left break; @@ -898,120 +901,13 @@ public class BlockDecorCraftingTable return stacks; } - /** - * Moves as much items from the stack to the slots in range [first_slot, last_slot] of the inventory, - * filling up existing stacks first, then (player inventory only) checks appropriate empty slots next - * to stacks that have that item already, and last uses any empty slot that can be found. - * Returns the stack that is still remaining in the referenced `stack`. - */ - private ItemStack move_stack_to_inventory(final ItemStack stack_to_move, SlotRange range, boolean only_fillup, int limit) - { - final IInventory inventory = range.inventory; - final int slot_begin = range.start_slot; - final int slot_end = range.end_slot; - final ItemStack mvstack = stack_to_move.copy(); - if((mvstack.isEmpty()) || (slot_begin < 0) || (slot_end > inventory.getSizeInventory())) return mvstack; - int limit_left = (limit>0) ? (Math.min(limit, mvstack.getMaxStackSize())) : (mvstack.getMaxStackSize()); - // first iteration: fillup existing stacks - for(int i = slot_begin; i < slot_end; ++i) { - final ItemStack stack = inventory.getStackInSlot(i); - if((stack.isEmpty()) || (!stack.isItemEqual(mvstack))) continue; - int nmax = Math.min(limit_left, stack.getMaxStackSize() - stack.getCount()); - if(mvstack.getCount() <= nmax) { - stack.setCount(stack.getCount()+mvstack.getCount()); - mvstack.setCount(0); - inventory.setInventorySlotContents(i, stack); - return mvstack; - } else { - stack.grow(nmax); - mvstack.shrink(nmax); - inventory.setInventorySlotContents(i, stack); - limit_left -= nmax; - } - } - if(only_fillup) return mvstack; - if(inventory instanceof PlayerInventory) { - // second iteration: use appropriate empty slots - for(int i = slot_begin+1; i < slot_end-1; ++i) { - final ItemStack stack = inventory.getStackInSlot(i); - if(!stack.isEmpty()) continue; - if((Inventories.areItemStacksDifferent(inventory.getStackInSlot(i+1), mvstack)) && (Inventories.areItemStacksDifferent(inventory.getStackInSlot(i-1), mvstack))) continue; - int nmax = Math.min(limit_left, mvstack.getCount()); - ItemStack placed = mvstack.copy(); - placed.setCount(nmax); - mvstack.shrink(nmax); - inventory.setInventorySlotContents(i, placed); - return mvstack; - } - } - // third iteration: use any empty slots - for(int i = slot_begin; i < slot_end; ++i) { - final ItemStack stack = inventory.getStackInSlot(i); - if(!stack.isEmpty()) continue; - int nmax = Math.min(limit_left, mvstack.getCount()); - ItemStack placed = mvstack.copy(); - placed.setCount(nmax); - mvstack.shrink(nmax); - inventory.setInventorySlotContents(i, placed); - return mvstack; - } - return mvstack; - } - - /** - * Moves as much items from the slots in range [first_slot, last_slot] of the inventory into a new stack. - * Implicitly shrinks the inventory stacks and the `request_stack`. - */ - private ItemStack move_stack_from_inventory(SlotRange range, final ItemStack request_stack) - { - final IInventory inventory = range.inventory; - final int slot_begin = range.start_slot; - final int slot_end = range.end_slot; - ItemStack fetched_stack = request_stack.copy(); - fetched_stack.setCount(0); - int n_left = request_stack.getCount(); - while(n_left > 0) { - int smallest_stack_size = 0; - int smallest_stack_index = -1; - for(int i = slot_begin; i < slot_end; ++i) { - final ItemStack stack = inventory.getStackInSlot(i); - if((!stack.isEmpty()) && (Inventories.areItemStacksIdentical(stack, request_stack))) { - if(stack.hasTag()) { - final CompoundNBT nbt = stack.getTag(); - int n = nbt.size(); - if((n > 0) && (nbt.contains("Damage"))) --n; - if(n > 0) continue; - } - fetched_stack = stack.copy(); - fetched_stack.setCount(0); - int n = stack.getCount(); - if((n < smallest_stack_size) || (smallest_stack_size <= 0)) { - smallest_stack_size = n; - smallest_stack_index = i; - } - } - } - if(smallest_stack_index < 0) { - break; // no more items available - } else { - int n = Math.min(n_left, smallest_stack_size); - n_left -= n; - fetched_stack.grow(n); - ItemStack st = inventory.getStackInSlot(smallest_stack_index); - st.shrink(n); - inventory.setInventorySlotContents(smallest_stack_index, st); - } - } - return fetched_stack; - } - private boolean clear_grid_to_storage(PlayerEntity player) { boolean changed = false; for(int grid_i = CRAFTING_SLOTS_BEGIN; grid_i < (CRAFTING_SLOTS_BEGIN+NUM_OF_CRAFTING_SLOTS); ++grid_i) { ItemStack stack = inventory_.getStackInSlot(grid_i); if(stack.isEmpty()) continue; - ItemStack remaining = move_stack_to_inventory(stack, new SlotRange(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS), false, 0); + ItemStack remaining = (new SlotRange(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)).insert(stack, false, 0); inventory_.setInventorySlotContents(grid_i, remaining); changed = true; } @@ -1024,10 +920,10 @@ public class BlockDecorCraftingTable for(int grid_i = CRAFTING_SLOTS_BEGIN; grid_i < (CRAFTING_SLOTS_BEGIN+NUM_OF_CRAFTING_SLOTS); ++grid_i) { ItemStack remaining = inventory_.getStackInSlot(grid_i); if(remaining.isEmpty()) continue; - remaining = move_stack_to_inventory(remaining, new SlotRange(player.inventory,9, 36), true, 0); // prefer filling up inventory stacks - remaining = move_stack_to_inventory(remaining, new SlotRange(player.inventory,0, 9), true, 0); // then fill up the hotbar stacks - remaining = move_stack_to_inventory(remaining, new SlotRange(player.inventory,9, 36), false, 0); // then allow empty stacks in inventory - remaining = move_stack_to_inventory(remaining, new SlotRange(player.inventory,0, 9), false, 0); // then new stacks in the hotbar + remaining = (new SlotRange(player.inventory,9, 36)).insert(remaining,true, 0); // prefer filling up inventory stacks + remaining = (new SlotRange(player.inventory,0, 9)).insert(remaining, true, 0); // then fill up the hotbar stacks + remaining = (new SlotRange(player.inventory,9, 36)).insert(remaining, false, 0); // then allow empty stacks in inventory + remaining = (new SlotRange(player.inventory,0, 9)).insert(remaining, false, 0); // then new stacks in the hotbar inventory_.setInventorySlotContents(grid_i, remaining); changed = true; } @@ -1048,7 +944,7 @@ public class BlockDecorCraftingTable if(grid_stack.getCount() >= grid_stack.getMaxStackSize()) continue; final ItemStack req_stack = to_fill.get(i).copy(); req_stack.setCount(1); - final ItemStack mv_stack = move_stack_from_inventory(slot_range, req_stack); + final ItemStack mv_stack = slot_range.extract(req_stack); if(mv_stack.isEmpty()) continue; to_fill.get(i).shrink(1); if(grid_stack.isEmpty()) { @@ -1157,7 +1053,7 @@ public class BlockDecorCraftingTable ItemStack stack = inventory_.getStackInSlot(i+CRAFTING_SLOTS_BEGIN).copy(); if(stack.isEmpty()) continue; for(SlotRange range:ranges) { - ItemStack remaining = move_stack_to_inventory(stack, range, false, limit); + ItemStack remaining = range.insert(stack, false, limit); if(remaining.getCount() < stack.getCount()) changed = true; boolean stop = (remaining.getCount() <= Math.max(0, (stack.getCount()-limit))); stack = remaining; @@ -1711,11 +1607,4 @@ public class BlockDecorCraftingTable } } - private static class SlotRange - { - public final IInventory inventory; - public int start_slot, end_slot; - public SlotRange(IInventory inv, int start, int end) { inventory=inv; start_slot=start; end_slot=end; } - } - } diff --git a/1.15/src/main/java/wile/engineersdecor/blocks/BlockDecorLabeledCrate.java b/1.15/src/main/java/wile/engineersdecor/blocks/BlockDecorLabeledCrate.java index b1c148b..45aa278 100644 --- a/1.15/src/main/java/wile/engineersdecor/blocks/BlockDecorLabeledCrate.java +++ b/1.15/src/main/java/wile/engineersdecor/blocks/BlockDecorLabeledCrate.java @@ -11,6 +11,9 @@ package wile.engineersdecor.blocks; import wile.engineersdecor.ModContent; import wile.engineersdecor.ModEngineersDecor; import wile.engineersdecor.libmc.blocks.StandardBlocks; +import wile.engineersdecor.libmc.detail.Auxiliaries; +import wile.engineersdecor.libmc.detail.Inventories.SlotRange; +import wile.engineersdecor.libmc.detail.Networking; import net.minecraft.world.IBlockReader; import net.minecraft.world.server.ServerWorld; import net.minecraft.world.World; @@ -29,6 +32,7 @@ import net.minecraft.inventory.*; import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.Slot; +import net.minecraft.inventory.container.ClickType; import net.minecraft.util.*; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.AxisAlignedBB; @@ -47,6 +51,7 @@ import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.ItemHandlerHelper; import com.mojang.blaze3d.platform.GlStateManager; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.ArrayList; @@ -55,8 +60,11 @@ import java.util.List; public class BlockDecorLabeledCrate { - public static void on_config(int stack_limit) + private static boolean with_gui_mouse_handling = true; + + public static void on_config(boolean without_gui_mouse_handling) { + with_gui_mouse_handling = !without_gui_mouse_handling; } //-------------------------------------------------------------------------------------------------------------------- @@ -220,6 +228,10 @@ public class BlockDecorLabeledCrate public void handleUpdateTag(CompoundNBT tag) // on client { read(tag); } + @OnlyIn(Dist.CLIENT) + public double getMaxRenderDistanceSquared() + { return 400; } + // INameable --------------------------------------------------------------------------- @Override @@ -242,7 +254,7 @@ public class BlockDecorLabeledCrate @Override public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player ) - { return new BContainer(id, inventory, this, IWorldPosCallable.of(world, pos), fields); } + { return new LabeledCrateContainer(id, inventory, this, IWorldPosCallable.of(world, pos), fields); } // IInventory ------------------------------------------------------------------------------ @@ -451,51 +463,11 @@ public class BlockDecorLabeledCrate } } - //-------------------------------------------------------------------------------------------------------------------- - // GUI - //-------------------------------------------------------------------------------------------------------------------- - - @OnlyIn(Dist.CLIENT) - public static class BGui extends ContainerScreen - { - protected final PlayerEntity player_; - - public BGui(BContainer container, PlayerInventory player_inventory, ITextComponent title) - { - super(container, player_inventory, title); - player_ = player_inventory.player; - xSize = 213; - ySize = 206; - } - - @Override - public void init() - { super.init(); } - - @Override - public void render(int mouseX, int mouseY, float partialTicks) - { - renderBackground(); - super.render(mouseX, mouseY, partialTicks); - renderHoveredToolTip(mouseX, mouseY); - } - - @Override - @SuppressWarnings("deprecation") - protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) - { - GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); - this.minecraft.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/labeled_crate_gui.png")); - final int x0=guiLeft, y0=this.guiTop, w=xSize, h=ySize; - blit(x0, y0, 0, 0, w, h); - } - } - //-------------------------------------------------------------------------------------------------------------------- // Container //-------------------------------------------------------------------------------------------------------------------- - public static class BContainer extends Container + public static class LabeledCrateContainer extends Container implements Networking.INetworkSynchronisableContainer { //------------------------------------------------------------------------------------------------------------------ protected static class StorageSlot extends Slot @@ -510,11 +482,13 @@ public class BlockDecorLabeledCrate //------------------------------------------------------------------------------------------------------------------ private static final int PLAYER_INV_START_SLOTNO = LabeledCrateTileEntity.NUM_OF_SLOTS; + private static final int NUM_OF_CONTAINER_SLOTS = LabeledCrateTileEntity.NUM_OF_SLOTS + 36; protected final PlayerEntity player_; protected final IInventory inventory_; protected final IWorldPosCallable wpc_; private final IIntArray fields_; - private int proc_time_needed_; + private final SlotRange player_inventory_slot_range; + private final SlotRange crate_slot_range; //------------------------------------------------------------------------------------------------------------------ public int field(int index) { return fields_.get(index); } public PlayerEntity player() { return player_ ; } @@ -522,16 +496,18 @@ public class BlockDecorLabeledCrate public World world() { return player_.world; } //------------------------------------------------------------------------------------------------------------------ - public BContainer(int cid, PlayerInventory player_inventory) + public LabeledCrateContainer(int cid, PlayerInventory player_inventory) { this(cid, player_inventory, new Inventory(LabeledCrateTileEntity.NUM_OF_SLOTS), IWorldPosCallable.DUMMY, new IntArray(LabeledCrateTileEntity.NUM_OF_FIELDS)); } - private BContainer(int cid, PlayerInventory player_inventory, IInventory block_inventory, IWorldPosCallable wpc, IIntArray fields) + private LabeledCrateContainer(int cid, PlayerInventory player_inventory, IInventory block_inventory, IWorldPosCallable wpc, IIntArray fields) { super(ModContent.CT_LABELED_CRATE, cid); player_ = player_inventory.player; inventory_ = block_inventory; wpc_ = wpc; fields_ = fields; + crate_slot_range = new SlotRange(inventory_, 0, LabeledCrateTileEntity.ITEMFRAME_SLOTNO); + player_inventory_slot_range = new SlotRange(player_inventory, 0, 36); int i=-1; // storage slots (stacks 0 to 53) for(int y=0; y<6; ++y) { @@ -581,7 +557,7 @@ public class BlockDecorLabeledCrate // Player slot if(!mergeItemStack(slot_stack, 0, PLAYER_INV_START_SLOTNO-1, false)) return ItemStack.EMPTY; } else { - // invalid slot + // Invalid slot return ItemStack.EMPTY; } if(slot_stack.isEmpty()) { @@ -593,5 +569,170 @@ public class BlockDecorLabeledCrate slot.onTake(player, slot_stack); return transferred; } + + + // Container client/server synchronisation -------------------------------------------------- + + @OnlyIn(Dist.CLIENT) + public void onGuiAction(String message, CompoundNBT nbt) + { + nbt.putString("action", message); + Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); + } + + @Override + public void onServerPacketReceived(int windowId, CompoundNBT nbt) + {} + + protected static final int STORAGE_SLOT_BEGIN = 0; + protected static final int STORAGE_SLOT_END = LabeledCrateTileEntity.ITEMFRAME_SLOTNO; + protected static final int PLAYER_SLOT_BEGIN = LabeledCrateTileEntity.NUM_OF_SLOTS; + protected static final int PLAYER_SLOT_END = LabeledCrateTileEntity.NUM_OF_SLOTS+36; + + @Override + public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt) + { + boolean changed = false; + if(!nbt.contains("action")) return; + final int slotId = nbt.contains("slot") ? nbt.getInt("slot") : -1; + switch(nbt.getString("action")) { + case LabeledCrateGui.QUICK_MOVE_ALL: { + if((slotId >= STORAGE_SLOT_BEGIN) && (slotId < STORAGE_SLOT_END) && (getSlot(slotId).getHasStack())) { + final Slot slot = getSlot(slotId); + ItemStack remaining = slot.getStack(); + slot.putStack(ItemStack.EMPTY); + final ItemStack ref_stack = remaining.copy(); + ref_stack.setCount(ref_stack.getMaxStackSize()); + for(int i=crate_slot_range.end_slot-crate_slot_range.start_slot; (i>0) && (!remaining.isEmpty()); --i) { + remaining = player_inventory_slot_range.insert(remaining, false, 0, true, true); + if(!remaining.isEmpty()) break; + remaining = crate_slot_range.extract(ref_stack); + } + if(!remaining.isEmpty()) { + slot.putStack(remaining); // put back + } + } else if((slotId >= PLAYER_SLOT_BEGIN) && (slotId < PLAYER_SLOT_END) && (getSlot(slotId).getHasStack())) { + final Slot slot = getSlot(slotId); + ItemStack remaining = slot.getStack(); + slot.putStack(ItemStack.EMPTY); + final ItemStack ref_stack = remaining.copy(); + ref_stack.setCount(ref_stack.getMaxStackSize()); + for(int i=player_inventory_slot_range.end_slot-player_inventory_slot_range.start_slot; (i>0) && (!remaining.isEmpty()); --i) { + remaining = crate_slot_range.insert(remaining, false, 0, false, true); + if(!remaining.isEmpty()) break; + remaining = player_inventory_slot_range.extract(ref_stack); + } + if(!remaining.isEmpty()) { + slot.putStack(remaining); // put back + } + } + changed = true; + } break; + case LabeledCrateGui.INCREASE_STACK: { + } break; + case LabeledCrateGui.DECREASE_STACK: { + } break; + } + if(changed) { + inventory_.markDirty(); + player.inventory.markDirty(); + detectAndSendChanges(); + } + } } + + //-------------------------------------------------------------------------------------------------------------------- + // GUI + //-------------------------------------------------------------------------------------------------------------------- + + @OnlyIn(Dist.CLIENT) + public static class LabeledCrateGui extends ContainerScreen + { + protected static final String QUICK_MOVE_ALL = "quick-move-all"; + protected static final String INCREASE_STACK = "increase-stack"; + protected static final String DECREASE_STACK = "decrease-stack"; + protected final PlayerEntity player_; + + public LabeledCrateGui(LabeledCrateContainer container, PlayerInventory player_inventory, ITextComponent title) + { + super(container, player_inventory, title); + player_ = player_inventory.player; + xSize = 213; + ySize = 206; + } + + @Override + public void init() + { super.init(); } + + @Override + public void render(int mouseX, int mouseY, float partialTicks) + { + renderBackground(); + super.render(mouseX, mouseY, partialTicks); + renderHoveredToolTip(mouseX, mouseY); + } + + @Override + @SuppressWarnings("deprecation") + protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) + { + GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); + this.minecraft.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/labeled_crate_gui.png")); + final int x0=guiLeft, y0=this.guiTop, w=xSize, h=ySize; + blit(x0, y0, 0, 0, w, h); + } + + + //------------------------------------------------------------------------------------------------------------------ + + protected void action(String message) + { action(message, new CompoundNBT()); } + + protected void action(String message, CompoundNBT nbt) + { getContainer().onGuiAction(message, nbt); } + + @Override + protected void handleMouseClick(Slot slot, int slotId, int button, ClickType type) + { + if(!with_gui_mouse_handling) { + super.handleMouseClick(slot, slotId, button, type); + } else if((type == ClickType.QUICK_MOVE) && slot.getHasStack() && Auxiliaries.isShiftDown() && Auxiliaries.isCtrlDown()) { + CompoundNBT nbt = new CompoundNBT(); + nbt.putInt("slot", slotId); + action(QUICK_MOVE_ALL, nbt); + } else { + super.handleMouseClick(slot, slotId, button, type); + } + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double wheel_inc) + { + if(!with_gui_mouse_handling) return super.mouseScrolled(mouseX, mouseY, wheel_inc); + final Slot slot = getSlotUnderMouse(); + if(!slot.getHasStack()) return true; + final int count = slot.getStack().getCount(); + int limit = (Auxiliaries.isShiftDown() ? 2 : 1) * (Auxiliaries.isCtrlDown() ? 4 : 1); + if(wheel_inc > 0.1) { + if(count > 0) { + if((count < slot.getStack().getMaxStackSize()) && (count < slot.getSlotStackLimit())) { + CompoundNBT nbt = new CompoundNBT(); + nbt.putInt("slot", slot.slotNumber); + if(limit > 1) nbt.putInt("limit", limit); + action(INCREASE_STACK, nbt); + } + } + } else if(wheel_inc < -0.1) { + if(count > 0) { + CompoundNBT nbt = new CompoundNBT(); + nbt.putInt("slot", slot.slotNumber); + if(limit > 1) nbt.putInt("limit", limit); + action(DECREASE_STACK, nbt); + } + } + return true; + } + } + } diff --git a/1.15/src/main/java/wile/engineersdecor/detail/ModConfig.java b/1.15/src/main/java/wile/engineersdecor/detail/ModConfig.java index 53a55e4..2a8c164 100644 --- a/1.15/src/main/java/wile/engineersdecor/detail/ModConfig.java +++ b/1.15/src/main/java/wile/engineersdecor/detail/ModConfig.java @@ -608,6 +608,12 @@ public class ModConfig public static final void apply() { + without_crafting_table = isOptedOut(ModContent.TREATED_WOOD_CRAFTING_TABLE); + immersiveengineering_installed = Auxiliaries.isModLoaded("immersiveengineering"); + with_experimental_features_ = COMMON.with_experimental.get(); + without_recipes_ = COMMON.without_recipes.get(); + without_direct_slab_pickup = COMMON.without_direct_slab_pickup.get(); + // ----------------------------------------------------------------------------------------------------------------- BlockDecorFurnace.BTileEntity.on_config(COMMON.furnace_smelting_speed_percent.get(), COMMON.furnace_fuel_efficiency_percent.get(), COMMON.furnace_boost_energy_consumption.get()); BlockDecorChair.on_config(COMMON.without_chair_sitting.get(), COMMON.without_mob_chair_sitting.get(), COMMON.chair_mob_sitting_probability_percent.get(), COMMON.chair_mob_standup_probability_percent.get()); BlockDecorLadder.on_config(COMMON.without_ladder_speed_boost.get()); @@ -620,11 +626,8 @@ public class ModConfig BlockDecorMilker.BTileEntity.on_config(COMMON.milking_machine_energy_consumption.get(), COMMON.milking_machine_milking_delay.get()); BlockDecorSlab.on_config(!COMMON.without_direct_slab_pickup.get()); BlockDecorHalfSlab.on_config(!COMMON.without_direct_slab_pickup.get()); - without_crafting_table = isOptedOut(ModContent.TREATED_WOOD_CRAFTING_TABLE); - immersiveengineering_installed = Auxiliaries.isModLoaded("immersiveengineering"); - with_experimental_features_ = COMMON.with_experimental.get(); - without_recipes_ = COMMON.without_recipes.get(); - without_direct_slab_pickup = COMMON.without_direct_slab_pickup.get(); + BlockDecorLabeledCrate.on_config(false); + // ----------------------------------------------------------------------------------------------------------------- if(with_experimental_features_) { ModEngineersDecor.logger().info("Config: EXPERIMENTAL FEATURES ENABLED."); } diff --git a/1.15/src/main/java/wile/engineersdecor/libmc/datagen/LootTableGen.java b/1.15/src/main/java/wile/engineersdecor/libmc/datagen/LootTableGen.java index 82f4561..addf4fb 100644 --- a/1.15/src/main/java/wile/engineersdecor/libmc/datagen/LootTableGen.java +++ b/1.15/src/main/java/wile/engineersdecor/libmc/datagen/LootTableGen.java @@ -57,11 +57,14 @@ public class LootTableGen extends LootTableProvider final HashMap tables = new HashMap(); final List blocks = block_listing.get(); blocks.forEach((block)->{ + LOGGER.info("Generating loot table for " + block.getRegistryName()); if((!(block instanceof StandardBlocks.IStandardBlock)) || (!(((StandardBlocks.IStandardBlock)block).hasDynamicDropList()))) { tables.put( block.getLootTable(), defaultBlockDrops(block.getRegistryName().getPath() + "_dlt", block) .setParameterSet(LootParameterSets.BLOCK).build()); + } else { + LOGGER.info("Dynamic drop list, skipping loot table for " + block.getRegistryName()); } }); return tables; diff --git a/1.15/src/main/java/wile/engineersdecor/libmc/detail/Inventories.java b/1.15/src/main/java/wile/engineersdecor/libmc/detail/Inventories.java index 34cf0ee..6407cee 100644 --- a/1.15/src/main/java/wile/engineersdecor/libmc/detail/Inventories.java +++ b/1.15/src/main/java/wile/engineersdecor/libmc/detail/Inventories.java @@ -8,7 +8,9 @@ */ package wile.engineersdecor.libmc.detail; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; @@ -21,6 +23,8 @@ import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.wrapper.InvWrapper; import net.minecraftforge.items.wrapper.SidedInvWrapper; import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; public class Inventories @@ -32,8 +36,6 @@ public class Inventories public static boolean areItemStacksDifferent(ItemStack a, ItemStack b) { return (a.getItem()!=b.getItem()) || (!ItemStack.areItemStackTagsEqual(a, b)); } - - public static IItemHandler itemhandler(World world, BlockPos pos, @Nullable Direction side) { TileEntity te = world.getTileEntity(pos); @@ -71,9 +73,9 @@ public class Inventories final ItemStack stack = inventory.getStackInSlot(i); if(stack.isEmpty()) continue; if(out_stack.isEmpty()) { - if((match!=null) && Inventories.areItemStacksDifferent(stack, match)) continue; + if((match!=null) && areItemStacksDifferent(stack, match)) continue; out_stack = inventory.extractItem(i, amount, simulate); - } else if(Inventories.areItemStacksIdentical(stack, out_stack)) { + } else if(areItemStacksIdentical(stack, out_stack)) { ItemStack es = inventory.extractItem(i, (amount-out_stack.getCount()), simulate); out_stack.grow(es.getCount()); } @@ -82,4 +84,112 @@ public class Inventories return out_stack; } -} \ No newline at end of file + private static ItemStack checked(ItemStack stack) + { return stack.isEmpty() ? ItemStack.EMPTY : stack; } // explicit EMPTY return + + public static class SlotRange + { + public final IInventory inventory; + public final int start_slot, end_slot; + + public SlotRange(IInventory inv, int start, int end) + { inventory=inv; start_slot=start; end_slot=end; } + + /** + * Moves as much items from the stack to the slots in range [start_slot, end_slot] of the inventory, + * filling up existing stacks first, then (player inventory only) checks appropriate empty slots next + * to stacks that have that item already, and last uses any empty slot that can be found. + * Returns the stack that is still remaining in the referenced `stack`. + */ + public ItemStack insert(final ItemStack stack_to_move, boolean only_fillup, int limit) + { return insert(stack_to_move, only_fillup, limit, false, false); } + + public ItemStack insert(final ItemStack stack_to_move, boolean only_fillup, int limit, boolean reverse, boolean force_group_stacks) + { + final ItemStack mvstack = stack_to_move.copy(); + if((mvstack.isEmpty()) || (start_slot < 0) || (end_slot > inventory.getSizeInventory())) return checked(mvstack); + int limit_left = (limit>0) ? (Math.min(limit, mvstack.getMaxStackSize())) : (mvstack.getMaxStackSize()); + // first iteration: fillup existing stacks + for(int i = start_slot; i < end_slot; ++i) { + final int sno = reverse ? (end_slot-1-i) : (i); + final ItemStack stack = inventory.getStackInSlot(sno); + if((stack.isEmpty()) || (areItemStacksDifferent(stack, mvstack))) continue; + int nmax = Math.min(limit_left, stack.getMaxStackSize() - stack.getCount()); + if(mvstack.getCount() <= nmax) { + stack.setCount(stack.getCount()+mvstack.getCount()); + inventory.setInventorySlotContents(sno, stack); + return ItemStack.EMPTY; + } else { + stack.grow(nmax); + mvstack.shrink(nmax); + inventory.setInventorySlotContents(sno, stack); + limit_left -= nmax; + } + } + if(only_fillup) return checked(mvstack); + if((force_group_stacks) || (inventory instanceof PlayerInventory)) { + // second iteration: use appropriate empty slots + for(int i = start_slot+1; i < end_slot-1; ++i) { + final int sno = reverse ? (end_slot-1-i) : (i); + final ItemStack stack = inventory.getStackInSlot(sno); + if(!stack.isEmpty()) continue; + if((areItemStacksDifferent(inventory.getStackInSlot(sno+1), mvstack)) && (areItemStacksDifferent(inventory.getStackInSlot(sno-1), mvstack))) continue; + int nmax = Math.min(limit_left, mvstack.getCount()); + ItemStack moved = mvstack.copy(); + moved.setCount(nmax); + mvstack.shrink(nmax); + inventory.setInventorySlotContents(sno, moved); + return checked(mvstack); + } + } + // third iteration: use any empty slots + for(int i = start_slot; i < end_slot; ++i) { + final int sno = reverse ? (end_slot-1-i) : (i); + final ItemStack stack = inventory.getStackInSlot(sno); + if(!stack.isEmpty()) continue; + int nmax = Math.min(limit_left, mvstack.getCount()); + ItemStack placed = mvstack.copy(); + placed.setCount(nmax); + mvstack.shrink(nmax); + inventory.setInventorySlotContents(sno, placed); + return checked(mvstack); + } + return checked(mvstack); + } + + /** + * Moves as much items from the slots in range [start_slot, end_slot] of the inventory into a new stack. + * Implicitly shrinks the inventory stacks and the `request_stack`. + */ + public ItemStack extract(final ItemStack request_stack) + { + if(request_stack.isEmpty()) return ItemStack.EMPTY; + final IInventory inventory = this.inventory; + List matches = new ArrayList<>(); + for(int i = start_slot; i < end_slot; ++i) { + final ItemStack stack = inventory.getStackInSlot(i); + if((!stack.isEmpty()) && (areItemStacksIdentical(stack, request_stack))) { + if(stack.hasTag()) { + final CompoundNBT nbt = stack.getTag(); + int n = nbt.size(); + if((n > 0) && (nbt.contains("Damage"))) --n; + if(n > 0) continue; + } + matches.add(stack); + } + } + matches.sort((a,b) -> Integer.compare(a.getCount(), b.getCount())); + if(matches.isEmpty()) return ItemStack.EMPTY; + int n_left = request_stack.getCount(); + ItemStack fetched_stack = matches.get(0).split(n_left); + n_left -= fetched_stack.getCount(); + for(int i=1; (i0); ++i) { + ItemStack stack = matches.get(i).split(n_left); + n_left -= stack.getCount(); + fetched_stack.grow(stack.getCount()); + } + return checked(fetched_stack); + } + } +} + diff --git a/meta/update.json b/meta/update.json index 6f0e466..f035b08 100644 --- a/meta/update.json +++ b/meta/update.json @@ -6,7 +6,7 @@ "1.14.4-recommended": "", "1.14.4-latest": "1.0.20-b2", "1.15.2-recommended": "", - "1.15.2-latest": "1.0.20-b1" + "1.15.2-latest": "1.0.20-b2" }, "1.12.2": { "1.0.20-b2": "[A] Backported Electrical Furnace GUI speed selection switch.\n[A] Backported Labeled Crate (storage crate with built-in item frame).", @@ -140,6 +140,7 @@ "1.0.7-b3": "[A] Initial 1.14.2 port of decorative blocks." }, "1.15.2": { + "1.0.20-b2": "[A] Added Labeled Crate (storage crate with built-in item frame).", "1.0.20-b1": "[A] Electrical Furnace: Added four-position speed switch (off, 100%, 150%, 200%), power consumption increases at higher rate (off, 100%, 200%, 400%).\n[A] Added Steel Mesh Fence Gate (single or double height gate fitting to the Steel Mesh Fence).\n[M] Waste Incinerator processing speed tweaked.\n[F] Fixed steel table visual glitch (thx Urbanxx001).\n[M] MCP/Forge mappings updated.", "1.0.19-b5": "[A] Added right-click display of power and progress information for Block Breaker, Solar Panel, and Tree Cutter.\n[A] Solar Panel power curve tuned.\n[A] Mod manual 1st edition release recipe added.\n[A] Factory Hopper: Resetting NBT when breaking with empty inventory (for stacking), enabled item cap for all sides.\n[M] Electrical Furnace model polished.", "1.0.19-b4": "[A] Ported primary Immersive Engineering dependent recipes (alternative recipes will still work if IE is not installed).\n[F] Blacklisted Treated Wood Crafting Table in inventorysorter mod (issue #88, thx Nachtflame).\n[M] Furni comparator output overrides reflect input slots and empty fuel state/power-cutoff.\n[M] Solar Panel config: Default value for internal battery capacity increased.\n[F] Block Placer: Shifted GUI player slots 1px to the right.\n[A] Added mod block tags for slabs, stairs, and walls (PR#89, thanks CrudeAustin for the data).\n[A] Added experimental Patchouli manual (creative only).",