Crafting Table shift-ctrl tweaks added. Crafting table mouse wheel stack inc/dec added. Lang file en_en updated (issue #76). Fixed tree cutter progress reset (issue #77). Added Solar Panel energy cap export (issue #78). Build system json-lang sanatized added.

This commit is contained in:
stfwi 2020-01-10 07:49:58 +01:00
parent 11e985b8db
commit d4488df2b7
39 changed files with 1339 additions and 569 deletions

View file

@ -4,4 +4,4 @@ org.gradle.jvmargs=-Xmx8G
version_minecraft=1.12.2
version_forge=14.23.5.2768
version_jei=4.10.0.198
version_engineersdecor=1.0.18-b1
version_engineersdecor=1.0.18-b2

View file

@ -1,6 +1,7 @@
{
"homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/",
"1.12.2": {
"1.0.18-b2": "[A] Added Treated Wood Crafting table tweaks (ctrl-shift moves all same stacks from the inventory, mouse wheel over crafting slot increases/decreases crafting grid stacks).\n[F] EN Lang file fixed (issue #76, thx Riverstar907).\n[F] Fixed Tree Cutter not respecting power-required config (thx federsavo, issue #77).",
"1.0.18-b1": "[M] Lang ru_ru updated (Smollet777).",
"1.0.17": "[R] Release based on v1.0.17-b3. Release-to-release changes: * Milking machine added. * Reverse recipes for slab slices added. * Texture and model improvements. * Lang file updates. * Minor bug fixes. * Config options added.\n[M] Updated zh_cn lang file (scikirbypoke).\n[A] Added opt-out config for the Small Tree Cutter.",
"1.0.17-b3": "[F] Fixed Small Block Breaker facings to the horizontal range (issue #70, thx JimMiningWorm).",
@ -75,6 +76,6 @@
},
"promos": {
"1.12.2-recommended": "1.0.17",
"1.12.2-latest": "1.0.18-b1"
"1.12.2-latest": "1.0.18-b2"
}
}

View file

@ -10,6 +10,11 @@ Mod sources for Minecraft version 1.12.2.
----
## Version history
- v1.0.18-b2 [A] Added Treated Wood Crafting table tweaks (ctrl-shift moves all same stacks from the
inventory, mouse wheel over crafting slot increases/decreases crafting grid stacks).
[F] EN Lang file fixed (issue #76, thx Riverstar907).
[F] Fixed Tree Cutter not respecting power-required config (thx federsavo, issue #77).
- v1.0.18-b1 [M] Lang ru_ru updated (Smollet777).
-------------------------------------------------------------------

View file

@ -11,7 +11,10 @@ package wile.engineersdecor.blocks;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
import org.lwjgl.Sys;
import org.lwjgl.input.Mouse;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.ModAuxiliaries;
import wile.engineersdecor.detail.Networking;
import net.minecraft.world.World;
import net.minecraft.world.Explosion;
@ -52,6 +55,8 @@ import net.minecraftforge.registries.IForgeRegistry;
import com.google.common.collect.ImmutableList;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.sound.midi.SysexMessage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -62,12 +67,15 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
public static boolean with_assist = true;
public static boolean with_assist_direct_history_refab = false;
public static boolean with_assist_quickmove_buttons = false;
public static boolean with_crafting_slot_mouse_scrolling = true;
public static final void on_config(boolean without_crafting_assist, boolean with_assist_immediate_history_refab, boolean with_quickmove_buttons)
public static final void on_config(boolean without_crafting_assist, boolean with_assist_immediate_history_refab,
boolean with_quickmove_buttons, boolean without_crafting_slot_mouse_scrolling)
{
with_assist = !without_crafting_assist;
with_assist_direct_history_refab = with_assist_immediate_history_refab;
with_assist_quickmove_buttons = with_quickmove_buttons;
with_crafting_slot_mouse_scrolling = !without_crafting_slot_mouse_scrolling;
CraftingHistory.max_history_size(32);
}
@ -354,6 +362,9 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
protected static final int BUTTON_TO_PLAYER = 7;
protected static final int ACTION_PLACE_CURRENT_HISTORY_SEL = 8;
protected static final int ACTION_PLACE_SHIFTCLICKED_STACK = 9;
protected static final int ACTION_MOVE_ALL_STACKS = 10;
protected static final int ACTION_INCREASE_CRAFTING_STACKS = 11;
protected static final int ACTION_DECREASE_CRAFTING_STACKS = 12;
protected static final ResourceLocation BACKGROUND = new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/treated_wood_crafting_table.png");
protected final BTileEntity te;
@ -385,6 +396,18 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
}
}
@Override
public void handleMouseInput() throws IOException
{
super.handleMouseInput();
final int wheel = Mouse.getDWheel();
if(wheel != 0) {
int x = Mouse.getEventX() * width / mc.displayWidth;
int y = this.height - Mouse.getEventY() * height / mc.displayHeight - 1;
if(wheel != 0) mouseScrolled(x, y, (wheel>0) ? 1 : -1);
}
}
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks)
{
@ -507,25 +530,75 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
if(place_refab && (!with_assist_direct_history_refab)) onHistoryItemPlacement(); // place after crafting -> confirmation first
return;
}
if((type == ClickType.QUICK_MOVE) && (slotId > 9) && (slot.getHasStack())) { // container slots 0..9 are crafting output and grid
List<ItemStack> history = te.history.current();
boolean palce_in_crafting_grid = (!history.isEmpty());
if(!palce_in_crafting_grid) {
for(int i=0; i<9; ++i) {
if(!(te.getStackInSlot(i).isEmpty())) { palce_in_crafting_grid = true; break; }
if((type == ClickType.QUICK_MOVE) && (slotId > 0) && (slot.getHasStack())) { // container slots 0 is crafting output
if(with_assist) {
List<ItemStack> history = te.history.current();
boolean palce_in_crafting_grid = false;
if(slotId > 9) { // container slots 1..9 are crafting grid
palce_in_crafting_grid = (!history.isEmpty());
if(!palce_in_crafting_grid) {
for(int i = 0; i < 9; ++i) {
if(!(te.getStackInSlot(i).isEmpty())) {
palce_in_crafting_grid = true;
break;
}
}
}
}
if(palce_in_crafting_grid) {
// Explicit grid placement.
NBTTagCompound nbt = new NBTTagCompound();
nbt.setInteger("action", ACTION_PLACE_SHIFTCLICKED_STACK);
nbt.setInteger("containerslot", slotId);
if(ModAuxiliaries.isCtrlDown()) nbt.setBoolean("move-all", true);
Networking.PacketTileNotify.sendToServer(te, nbt);
return;
} else if(ModAuxiliaries.isCtrlDown()) {
// Move all same items from the inventory of the clicked slot
// (or the crafting grid) to the corresponding target inventory.
NBTTagCompound nbt = new NBTTagCompound();
nbt.setInteger("action", ACTION_MOVE_ALL_STACKS);
nbt.setInteger("containerslot", slotId);
Networking.PacketTileNotify.sendToServer(te, nbt);
return;
} else {
// Let the normal slot click handle that.
}
}
if(palce_in_crafting_grid) {
NBTTagCompound nbt = new NBTTagCompound();
nbt.setInteger("action", ACTION_PLACE_SHIFTCLICKED_STACK);
nbt.setInteger("containerslot", slotId);
Networking.PacketTileNotify.sendToServer(te, nbt);
return;
}
}
super.handleMouseClick(slot, slotId, mouseButton, type);
}
private boolean mouseScrolled(int mouseX, int mouseY, int wheel_inc)
{
final Slot resultSlot = getSlotUnderMouse();
if((!with_crafting_slot_mouse_scrolling) || (!(resultSlot instanceof BSlotCrafting))) return false;
int count = resultSlot.getStack().getCount();
int limit = (ModAuxiliaries.isShiftDown() ? 2 : 1) * (ModAuxiliaries.isCtrlDown() ? 4 : 1);
if(wheel_inc > 0) {
if(count > 0) {
if((count < resultSlot.getStack().getMaxStackSize()) && (count < resultSlot.getSlotStackLimit())) {
NBTTagCompound nbt = new NBTTagCompound();
nbt.setInteger("action", ACTION_INCREASE_CRAFTING_STACKS);
if(limit > 1) nbt.setInteger("limit", limit);
Networking.PacketTileNotify.sendToServer(te, nbt);
}
} else if(!te.history.current().isEmpty()) {
NBTTagCompound nbt = new NBTTagCompound();
nbt.setInteger("action", ACTION_PLACE_CURRENT_HISTORY_SEL);
Networking.PacketTileNotify.sendToServer(te, nbt);
}
} else if(wheel_inc < 0) {
if(count > 0) {
NBTTagCompound nbt = new NBTTagCompound();
if(limit > 1) nbt.setInteger("limit", limit);
nbt.setInteger("action", ACTION_DECREASE_CRAFTING_STACKS);
Networking.PacketTileNotify.sendToServer(te, nbt);
}
}
return true;
}
private void onHistoryItemPlacement()
{
if(te.history.current().isEmpty()) return;
@ -790,6 +863,13 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
}
}
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; }
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
@ -826,6 +906,8 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
// private aux methods ---------------------------------------------------------------------
enum PlacementResult { UNCHANGED, INCOMPLETE, PLACED }
private boolean has_recipe_collision()
{ return has_recipe_collision_; }
@ -845,7 +927,7 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
return false;
}
private List<ItemStack> crafting_slot_stacks_to_add()
private List<ItemStack> refab_crafting_stacks()
{
final ArrayList<ItemStack> slots = new ArrayList<ItemStack>();
final List<ItemStack> tocraft = history.current();
@ -887,30 +969,46 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
return slots;
}
private List<ItemStack> incr_crafting_grid_stacks(int count)
{
final ArrayList<ItemStack> stacks = new ArrayList<ItemStack>();
for(int i=0; i<9; ++i) {
final ItemStack palced = getStackInSlot(i+CRAFTING_SLOTS_BEGIN).copy();
if(!palced.isEmpty()) palced.setCount(count);
stacks.add(palced);
}
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, IInventory inventory, final int slot_begin, final int slot_end, boolean only_fillup)
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()) || (!isItemExactlyEqual(stack,mvstack))) continue;
int nmax = stack.getMaxStackSize() - stack.getCount();
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.setCount(stack.getMaxStackSize());
stack.grow(nmax);
mvstack.shrink(nmax);
inventory.setInventorySlotContents(i, stack);
limit_left -= nmax;
}
}
if(only_fillup) return mvstack;
@ -920,8 +1018,11 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
final ItemStack stack = inventory.getStackInSlot(i);
if(!stack.isEmpty()) continue;
if((!inventory.getStackInSlot(i+1).isItemEqual(mvstack)) && (!inventory.getStackInSlot(i-1).isItemEqual(mvstack))) continue;
inventory.setInventorySlotContents(i, mvstack.copy());
mvstack.setCount(0);
int nmax = Math.min(limit_left, mvstack.getCount());
ItemStack placed = mvstack.copy();
placed.setCount(nmax);
mvstack.shrink(nmax);
inventory.setInventorySlotContents(i, placed);
return mvstack;
}
}
@ -929,8 +1030,11 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
for(int i = slot_begin; i < slot_end; ++i) {
final ItemStack stack = inventory.getStackInSlot(i);
if(!stack.isEmpty()) continue;
inventory.setInventorySlotContents(i, mvstack.copy());
mvstack.setCount(0);
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;
@ -958,8 +1062,11 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
* 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(IInventory inventory, final ItemStack request_stack, final int slot_begin, final int slot_end)
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();
@ -968,10 +1075,16 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
int smallest_stack_index = -1;
for(int i = slot_begin; i < slot_end; ++i) {
final ItemStack stack = inventory.getStackInSlot(i);
if((!stack.isEmpty()) && (isItemExactlyEqual(stack, request_stack))) {
if((!stack.isEmpty()) && (stack.isItemEqual(request_stack))) {
// Never automatically place stuff with nbt (except a few allowed like "Damage"),
// as this could be a full crate, a valuable tool item, etc. For these recipes
// the user has to place this item manually.
if(stack.hasTagCompound()) {
final NBTTagCompound nbt = stack.getTagCompound();
int n = nbt.getSize();
if((n > 0) && (nbt.hasKey("Damage"))) --n;
if(n > 0) continue;
}
fetched_stack = stack.copy(); // copy exact stack with nbt and tool damage, otherwise we have an automagical repair of items.
fetched_stack.setCount(0);
int n = stack.getCount();
@ -998,10 +1111,10 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
private boolean clear_grid_to_storage(EntityPlayer player)
{
boolean changed = false;
for(int grid_i = CRAFTING_SLOTS_BEGIN; grid_i < (CRAFTING_SLOTS_BEGIN + NUM_OF_CRAFTING_SLOTS); ++grid_i) {
for(int grid_i = CRAFTING_SLOTS_BEGIN; grid_i < (CRAFTING_SLOTS_BEGIN+NUM_OF_CRAFTING_SLOTS); ++grid_i) {
ItemStack stack = getStackInSlot(grid_i);
if(stack.isEmpty()) continue;
ItemStack remaining = move_stack_to_inventory(stack, this, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS, false);
ItemStack remaining = move_stack_to_inventory(stack, new SlotRange(this, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS), false, 0);
setInventorySlotContents(grid_i, remaining);
changed = true;
}
@ -1011,67 +1124,72 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
private boolean clear_grid_to_player(EntityPlayer player)
{
boolean changed = false;
for(int grid_i = CRAFTING_SLOTS_BEGIN; grid_i < (CRAFTING_SLOTS_BEGIN + NUM_OF_CRAFTING_SLOTS); ++grid_i) {
for(int grid_i = CRAFTING_SLOTS_BEGIN; grid_i < (CRAFTING_SLOTS_BEGIN+NUM_OF_CRAFTING_SLOTS); ++grid_i) {
ItemStack remaining = getStackInSlot(grid_i);
if(remaining.isEmpty()) continue;
remaining = move_stack_to_inventory(remaining, player.inventory,9, 36, true); // prefer filling up inventory stacks
remaining = move_stack_to_inventory(remaining, player.inventory,0, 9, true); // then fill up the hotbar stacks
remaining = move_stack_to_inventory(remaining, player.inventory,9, 36, false); // then allow empty stacks in inventory
remaining = move_stack_to_inventory(remaining, player.inventory,0, 9, false); // then new stacks in the hotbar
this.setInventorySlotContents(grid_i, remaining);
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
setInventorySlotContents(grid_i, remaining);
changed = true;
}
return changed;
}
enum EnumRefabPlacement { UNCHANGED, INCOMPLETE, PLACED }
private EnumRefabPlacement place_refab_stacks(IInventory inventory, final int slot_begin, final int slot_end, @Nullable EntityPlayer player)
private PlacementResult place_stacks(final SlotRange[] ranges, final List<ItemStack> to_fill, @Nullable EntityPlayer player)
{
List<ItemStack> to_fill = crafting_slot_stacks_to_add();
boolean slots_changed = false;
boolean missing_item = false;
int num_slots_placed = 0;
if(!to_fill.isEmpty()) {
for(int it_guard=63; it_guard>=0; --it_guard) {
boolean slots_updated = false;
for(int i = 0; i < 9; ++i) {
final ItemStack req_stack = to_fill.get(i).copy();
if(req_stack.isEmpty()) continue;
req_stack.setCount(1);
to_fill.get(i).shrink(1);
final ItemStack mv_stack = move_stack_from_inventory(inventory, req_stack, slot_begin, slot_end);
if(mv_stack.isEmpty()) { missing_item=true; continue; }
// sizes already checked
ItemStack grid_stack = getStackInSlot(i + CRAFTING_SLOTS_BEGIN).copy();
if(grid_stack.isEmpty()) {
grid_stack = mv_stack.copy();
} else {
grid_stack.grow(mv_stack.getCount());
for(SlotRange slot_range: ranges) {
for(int it_guard=63; it_guard>=0; --it_guard) {
boolean slots_updated = false;
for(int i = 0; i < 9; ++i) {
if(to_fill.get(i).isEmpty()) continue;
ItemStack grid_stack = getStackInSlot(i + CRAFTING_SLOTS_BEGIN).copy();
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);
if(mv_stack.isEmpty()) continue;
to_fill.get(i).shrink(1);
if(grid_stack.isEmpty()) {
grid_stack = mv_stack.copy();
} else {
grid_stack.grow(mv_stack.getCount());
}
setInventorySlotContents(i + CRAFTING_SLOTS_BEGIN, grid_stack);
slots_changed = true;
slots_updated = true;
}
setInventorySlotContents(i + CRAFTING_SLOTS_BEGIN, grid_stack);
slots_changed = true;
slots_updated = true;
if(!slots_updated) break;
}
if(!slots_updated) break;
}
}
boolean missing_item = false;
for(ItemStack st:to_fill) {
if(!st.isEmpty()) {
missing_item = true;
break;
}
}
if((history.current_recipe() != null) && (player!=null) && (player.openContainer instanceof BContainer)) {
((BContainer)player.openContainer).craftResult.setRecipeUsed(history.current_recipe());
}
if(!slots_changed) {
return EnumRefabPlacement.UNCHANGED;
return PlacementResult.UNCHANGED;
} else if(missing_item) {
return EnumRefabPlacement.INCOMPLETE;
return PlacementResult.INCOMPLETE;
} else {
return EnumRefabPlacement.PLACED;
return PlacementResult.PLACED;
}
}
private EnumRefabPlacement distribute_stack(IInventory inventory, final int slotno)
private PlacementResult distribute_stack(IInventory inventory, final int slotno)
{
List<ItemStack> to_refab = crafting_slot_stacks_to_add();
List<ItemStack> to_refab = refab_crafting_stacks();
ItemStack to_distribute = inventory.getStackInSlot(slotno).copy();
if(to_distribute.isEmpty()) return EnumRefabPlacement.UNCHANGED;
if(to_distribute.isEmpty()) return PlacementResult.UNCHANGED;
int matching_grid_stack_sizes[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1};
int max_matching_stack_size = -1;
int min_matching_stack_size = 65;
@ -1098,9 +1216,9 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
}
}
}
if(min_matching_stack_size < 0) return EnumRefabPlacement.UNCHANGED;
if(min_matching_stack_size < 0) return PlacementResult.UNCHANGED;
final int stack_limit_size = Math.min(to_distribute.getMaxStackSize(), getInventoryStackLimit());
if(min_matching_stack_size >= stack_limit_size) return EnumRefabPlacement.UNCHANGED;
if(min_matching_stack_size >= stack_limit_size) return PlacementResult.UNCHANGED;
int n_to_distribute = to_distribute.getCount();
for(int it_guard=63; it_guard>=0; --it_guard) {
if(n_to_distribute <= 0) break;
@ -1119,7 +1237,7 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
}
if(min_matching_stack_size >= stack_limit_size) break; // all full
}
if(n_to_distribute == to_distribute.getCount()) return EnumRefabPlacement.UNCHANGED; // was already full
if(n_to_distribute == to_distribute.getCount()) return PlacementResult.UNCHANGED; // was already full
if(n_to_distribute <= 0) {
inventory.setInventorySlotContents(slotno, ItemStack.EMPTY);
} else {
@ -1133,9 +1251,30 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
grid_stack.setCount(matching_grid_stack_sizes[i]);
setInventorySlotContents(i + CRAFTING_SLOTS_BEGIN, grid_stack);
}
return EnumRefabPlacement.PLACED;
return PlacementResult.PLACED;
}
private boolean decrease_grid_stacks(SlotRange[] ranges, int limit)
{
boolean changed = false;
for(int i=0; i<9; ++i) {
ItemStack stack = getStackInSlot(i+CRAFTING_SLOTS_BEGIN).copy();
if(stack.isEmpty()) continue;
for(SlotRange range:ranges) {
ItemStack remaining = move_stack_to_inventory(stack, range, false, limit);
if(remaining.getCount() < stack.getCount()) changed = true;
boolean stop = (remaining.getCount() <= Math.max(0, (stack.getCount()-limit)));
stack = remaining;
if(stop) break;
}
setInventorySlotContents(i+CRAFTING_SLOTS_BEGIN, stack.isEmpty() ? ItemStack.EMPTY : stack);
}
return changed;
}
private boolean increase_grid_stacks(SlotRange[] ranges, int limit, EntityPlayer player)
{ return place_stacks(ranges, incr_crafting_grid_stacks(limit), player) != PlacementResult.UNCHANGED; }
// Networking.IPacketReceiver --------------------------------------------------------------
@Override
@ -1174,42 +1313,99 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
if(clear_grid_to_player(player)) { te_changed = true; player_inventory_changed = true; }
} break;
case BGui.BUTTON_FROM_STORAGE: {
EnumRefabPlacement from_storage = place_refab_stacks(this, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN + NUM_OF_STORAGE_SLOTS, player);
if(from_storage != EnumRefabPlacement.UNCHANGED) te_changed = true;
if(place_stacks(new SlotRange[]{
new SlotRange(this, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)
}, refab_crafting_stacks(), player) != PlacementResult.UNCHANGED) {
te_changed = true;
}
} break;
case BGui.BUTTON_FROM_PLAYER: {
EnumRefabPlacement from_player_inv = place_refab_stacks(player.inventory, 9, 36, player);
if(from_player_inv != EnumRefabPlacement.UNCHANGED) { te_changed = true; player_inventory_changed = true; }
if(from_player_inv != EnumRefabPlacement.PLACED) {
EnumRefabPlacement from_hotbar = place_refab_stacks(player.inventory, 0, 9, player);
if(from_hotbar != EnumRefabPlacement.UNCHANGED) { te_changed = true; player_inventory_changed = true; }
if(place_stacks(new SlotRange[]{
new SlotRange(player.inventory, 9, 36),
new SlotRange(player.inventory, 0, 9)
}, refab_crafting_stacks(), player) != PlacementResult.UNCHANGED) {
te_changed = true; player_inventory_changed = true;
}
} break;
case BGui.ACTION_PLACE_CURRENT_HISTORY_SEL: {
EnumRefabPlacement from_storage = place_refab_stacks(this, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN + NUM_OF_STORAGE_SLOTS, player);
if(from_storage != EnumRefabPlacement.UNCHANGED) te_changed = true;
if(from_storage != EnumRefabPlacement.PLACED) {
EnumRefabPlacement from_player_inv = place_refab_stacks(player.inventory, 9, 36, player);
if(from_player_inv != EnumRefabPlacement.UNCHANGED) { te_changed = true; player_inventory_changed = true; }
if(from_player_inv != EnumRefabPlacement.PLACED) {
EnumRefabPlacement from_hotbar = place_refab_stacks(player.inventory, 0, 9, player);
if(from_hotbar != EnumRefabPlacement.UNCHANGED) { te_changed = true; player_inventory_changed = true; }
}
if(place_stacks(new SlotRange[]{
new SlotRange(player.inventory, 0, 9),
new SlotRange(player.inventory, 9, 36),
new SlotRange(this, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)
}, refab_crafting_stacks(), player) != PlacementResult.UNCHANGED) {
te_changed = true;
}
} break;
case BGui.ACTION_PLACE_SHIFTCLICKED_STACK: {
final int container_slot_id = nbt.getInteger("containerslot");
if((container_slot_id < 10) || (container_slot_id > 53)) break; // out of range
if((container_slot_id < 10) || (container_slot_id > 53)) {
break; // out of range
}
if(container_slot_id >= 46) {
// from storage
final int storage_slot = container_slot_id - 46 + STORAGE_SLOTS_BEGIN;
EnumRefabPlacement stat = distribute_stack(this, storage_slot);
if(stat != EnumRefabPlacement.UNCHANGED) te_changed = true;
PlacementResult stat = distribute_stack(this, storage_slot);
if(stat != PlacementResult.UNCHANGED) te_changed = true;
} else {
// from player
int player_slot = (container_slot_id >= 37) ? (container_slot_id-37) : (container_slot_id-10+9);
EnumRefabPlacement stat = distribute_stack(player.inventory, player_slot);
if(stat != EnumRefabPlacement.UNCHANGED) { player_inventory_changed = true; te_changed = true; }
final ItemStack reference_stack = player.inventory.getStackInSlot(player_slot).copy();
if((!reference_stack.isEmpty()) && (distribute_stack(player.inventory, player_slot) != PlacementResult.UNCHANGED)) {
player_inventory_changed = true;
te_changed = true;
if(nbt.hasKey("move-all")) {
for(int i=0; i < player.inventory.getSizeInventory(); ++i) {
final ItemStack stack = player.inventory.getStackInSlot(i);
if(!reference_stack.isItemEqual(stack)) continue;
if(distribute_stack(player.inventory, i) == PlacementResult.UNCHANGED) break; // grid is full
}
}
}
}
} break;
case BGui.ACTION_MOVE_ALL_STACKS: {
final int container_slot_id = nbt.getInteger("containerslot");
if((container_slot_id < 1) || (container_slot_id > 53)) {
break; // out of range
} else if(container_slot_id < 10) {
// from crafting grid to player inventory, we clear the grid here as this is most likely
// what is wanted in the end. Saves clicking the other grid stacks.
if(clear_grid_to_player(player)) { te_changed = true; player_inventory_changed = true; }
if(clear_grid_to_storage(player)) te_changed = true;
break;
}
IInventory from_inventory;
SlotRange[] to_ranges;
int from_slot;
if(container_slot_id >= 46) {
// from storage to player inventory
from_inventory = this;
from_slot = container_slot_id - 46 + STORAGE_SLOTS_BEGIN;
to_ranges = new SlotRange[] {new SlotRange(player.inventory, 9, 36), new SlotRange(player.inventory, 0, 9)};
} else {
// from player to storage (otherwise ACTION_PLACE_SHIFTCLICKED_STACK would have been used)
from_inventory = player.inventory;
from_slot = (container_slot_id >= 37) ? (container_slot_id-37) : (container_slot_id-10+9);
to_ranges = new SlotRange[] {new SlotRange(this, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)};
}
final ItemStack reference_stack = from_inventory.getStackInSlot(from_slot).copy();
if(!reference_stack.isEmpty()) {
boolean abort = false;
for(int i=0; (i < from_inventory.getSizeInventory()) && (!abort); ++i) {
final ItemStack stack = from_inventory.getStackInSlot(i);
if(!reference_stack.isItemEqual(stack)) continue;
ItemStack remaining = from_inventory.getStackInSlot(i);
for(SlotRange range:to_ranges) {
remaining = move_stack_to_inventory(remaining, range, false, 0);
if(!remaining.isEmpty()) {
abort = true; // no space left
break;
} else {
te_changed = player_inventory_changed = true;
}
}
from_inventory.setInventorySlotContents(i, remaining);
}
}
} break;
case BGui.BUTTON_NEXT_COLLISION_RECIPE: {
@ -1217,6 +1413,20 @@ public class BlockDecorCraftingTable extends BlockDecorDirected
((BContainer)player.openContainer).select_next_collision_recipe(this, player);
}
} break;
case BGui.ACTION_DECREASE_CRAFTING_STACKS: {
te_changed = player_inventory_changed = decrease_grid_stacks(new SlotRange[]{
new SlotRange(player.inventory, 9, 36),
new SlotRange(player.inventory, 0, 9),
new SlotRange(this, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)
}, MathHelper.clamp(nbt.getInteger("limit"), 1, 8));
} break;
case BGui.ACTION_INCREASE_CRAFTING_STACKS: {
te_changed = player_inventory_changed = increase_grid_stacks(new SlotRange[]{
new SlotRange(player.inventory, 9, 36),
new SlotRange(player.inventory, 0, 9),
new SlotRange(this, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)
}, MathHelper.clamp(nbt.getInteger("limit"), 1, 8), player);
} break;
}
}
if(te_changed) markDirty();

View file

@ -207,6 +207,9 @@ public class BlockDecorTreeCutter extends BlockDecorDirectedHorizontal
--active_timer_;
}
boolean active = (active_timer_ > 0);
if(requires_power && !active) {
proc_time_elapsed_ = Math.max(0, proc_time_elapsed_ - 2*TICK_INTERVAL);
}
if(proc_time_elapsed_ >= cutting_time_needed) {
proc_time_elapsed_ = 0;
TreeCutting.chopTree(world, tree_state, tree_pos, 2048, false);

View file

@ -76,6 +76,14 @@ public class ModAuxiliaries
}
}
@SideOnly(Side.CLIENT)
public static final boolean isShiftDown()
{ return (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)||Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)); }
@SideOnly(Side.CLIENT)
public static final boolean isCtrlDown()
{ return ((Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)||Keyboard.isKeyDown(Keyboard.KEY_RCONTROL))); }
/**
* Returns true if a given key is translated for the current language.
*/
@ -87,11 +95,11 @@ public class ModAuxiliaries
{
@SideOnly(Side.CLIENT)
public static boolean extendedTipCondition()
{ return (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)||Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)); }
{ return isShiftDown(); }
@SideOnly(Side.CLIENT)
public static boolean helpCondition()
{ return extendedTipCondition() && ((Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)||Keyboard.isKeyDown(Keyboard.KEY_RCONTROL))); }
{ return isShiftDown() && isCtrlDown(); }
/**
* Adds an extended tooltip or help tooltip depending on the key states of CTRL and SHIFT.

View file

@ -328,11 +328,15 @@ public class ModConfig
@Config.RangeDouble(min=0.001, max=10)
public double chair_mob_standup_probability_percent = 1;
@Config.Comment({"Disables increasing/decreasing the crafting grid items by scrolling over the crafting result slot."})
@Config.Name("Crafting table: Move buttons")
public boolean with_crafting_quickmove_buttons = false;
@Config.Comment({"Enables small quick-move arrows from/to player/block storage. " +
"Makes the UI a bit too busy, therefore disabled by default."
})
@Config.Name("Crafting table: Move buttons")
public boolean with_crafting_quickmove_buttons = false;
@Config.Name("Crafting table: Mouse scrolling")
public boolean without_crafting_mouse_scrolling = false;
@Config.Comment({
"Defines how many millibuckets can be transferred (per tick) through the valves. " +
@ -600,7 +604,7 @@ public class ModConfig
BlockDecorFurnace.BTileEntity.on_config(tweaks.furnace_smelting_speed_percent, tweaks.furnace_fuel_efficiency_percent, tweaks.furnace_boost_energy_consumption);
BlockDecorChair.on_config(optout.without_chair_sitting, optout.without_mob_chair_sitting, tweaks.chair_mob_sitting_probability_percent, tweaks.chair_mob_standup_probability_percent);
BlockDecorLadder.on_config(optout.without_ladder_speed_boost);
BlockDecorCraftingTable.on_config(optout.without_crafting_table_history, false, tweaks.with_crafting_quickmove_buttons);
BlockDecorCraftingTable.on_config(optout.without_crafting_table_history, false, tweaks.with_crafting_quickmove_buttons, tweaks.without_crafting_mouse_scrolling);
BlockDecorPipeValve.on_config(tweaks.pipevalve_max_flowrate, tweaks.pipevalve_redstone_slope);
BlockDecorFurnaceElectrical.BTileEntity.on_config(tweaks.e_furnace_speed_percent, tweaks.e_furnace_power_consumption);
BlockDecorSolarPanel.BTileEntity.on_config(tweaks.solar_panel_peak_power);

View file

@ -66,8 +66,8 @@ tile.engineersdecor.clinker_brick_stairs.name=Clinker Brick Stairs
tile.engineersdecor.clinker_brick_stairs.help=§6Looks slightly darker and more color intensive than the vanilla brick block.
tile.engineersdecor.clinker_brick_stained_stairs.name=Stained Clinker Brick Stairs
tile.engineersdecor.clinker_brick_stained_stairs.help=§6Looks slightly darker and more color intensive than the vanilla brick block. Has more visible traces of grime or stain.
tile.engineersdecor.slag_brick_stairs.name=Clinker Brick Stairs
tile.engineersdecor.slag_brick_stairs.help=§6Looks slightly darker and more color intensive than the vanilla brick block.
tile.engineersdecor.slag_brick_stairs.name=Slag Brick Stairs
tile.engineersdecor.slag_brick_stairs.help=§6Gray-brown brick stairs.
tile.engineersdecor.rebar_concrete_stairs.name=Rebar Concrete Stairs
tile.engineersdecor.rebar_concrete_stairs.help=§6Steel reinforced concrete stairs.§r Expensive but Creeper-proof like obsidian.
tile.engineersdecor.rebar_concrete_tile_stairs.name=Rebar Concrete Tile Stairs
@ -106,7 +106,8 @@ tile.engineersdecor.treated_wood_crafting_table.name=Treated Wood Crafting Table
tile.engineersdecor.treated_wood_crafting_table.help=§6Robust and weather-proof.§r Eight storage slots, keeps inventory, no vanilla recipe book.\n\
Click up/down arrow buttons for crafting history selection, output slot for item placement, X-button \
to clear crafting grid and history. Shift-click stack: player-to-storage stack transfer when crafting \
grid empty, otherwise player-to-grid stack transfer. Automatically distributes the clicked stack.
grid empty, otherwise player-to-grid stack transfer. Automatically distributes the clicked stack. \
Shift-Ctrl-click stack: Move all same stacks. Mouse wheel over crafting slot: Increase/decrease crafting grid items.
tile.engineersdecor.treated_wood_side_table.name=Treated Wood Side Table
tile.engineersdecor.treated_wood_side_table.help=§6Needed after the work's done.
tile.engineersdecor.iron_inset_light.name=Inset Light

View file

@ -68,6 +68,7 @@ sanatize:
@echo "[1.14] Running sanatising tasks ..."
@djs tasks.js trailing-whitespaces
@djs tasks.js tabs-to-spaces
@djs tasks.js lang-json-fixes
@djs tasks.js sync-languages
@djs tasks.js version-check
@djs tasks.js update-json

View file

@ -70,7 +70,7 @@ dependencies {
processResources {
outputs.upToDateWhen { false } // thx to @tterrag for this hint
doLast { file("${sourceSets.main.output.resourcesDir}/.gitversion").text = 'git log "-1" "--format=%h"'.execute().in.text.trim() }
doLast { file("${sourceSets.main.output.resourcesDir}/.gitversion-engineersdecor").text = 'git log "-1" "--format=%h"'.execute().in.text.trim() }
}
jar {

View file

@ -2,7 +2,7 @@
org.gradle.daemon=false
org.gradle.jvmargs=-Xmx8G
version_minecraft=1.14.4
version_forge_minecraft=1.14.4-28.1.109
version_forge_minecraft=1.14.4-28.1.111
version_fml_mappings=20190719-1.14.3
version_jei=1.14.4:6.0.0.10
version_engineersdecor=1.0.18-b2
version_engineersdecor=1.0.18-b3

View file

@ -1,6 +1,7 @@
{
"homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/",
"1.14.4": {
"1.0.18-b3": "[A] Added Treated Wood Crafting table tweaks (ctrl-shift moves all same stacks from the inventory, mouse wheel over crafting slot increases/decreases crafting grid stacks).\n[F] EN Lang file fixed (issue #76, thx Riverstar907).\n[F] Fixed Tree Cutter not respecting power-required config (thx federsavo, issue #77).\n[F] Fixed Small Solar Panel not exposing energy capability (thx MatthiasMann, issue #78).",
"1.0.18-b2": "[F] Fixed JEI integration warning if nothing is opt'ed out (thx @SDUBZ for reporting).\n[M] Lang ru_ru updated (Smollet777).",
"1.0.18-b1": "[U] Updated to Forge 1.14.4-28.1.109/20190719-1.14.3.\n[A] Added opt-out config for the Small Tree Cutter.",
"1.0.17-b3": "[F] Double newline escapes in lang files fixed (\"\\n\" in a tooltip).\n[M] Updated zh_cn lang file (scikirbypoke).",
@ -42,6 +43,6 @@
},
"promos": {
"1.14.4-recommended": "",
"1.14.4-latest": "1.0.18-b2"
"1.14.4-latest": "1.0.18-b3"
}
}

View file

@ -11,6 +11,12 @@ Mod sources for Minecraft version 1.14.4.
## Version history
- v1.0.18-b3 [A] Added Treated Wood Crafting table tweaks (ctrl-shift moves all same stacks from the
inventory, mouse wheel over crafting slot increases/decreases crafting grid stacks).
[F] EN Lang file fixed (issue #76, thx Riverstar907).
[F] Fixed Tree Cutter not respecting power-required config (thx federsavo, issue #77).
[F] Fixed Small Solar Panel not exposing energy capability (thx MatthiasMann, issue #78).
- v1.0.18-b2 [F] Fixed JEI integration warning if nothing is opt'ed out (thx @SDUBZ for reporting).
[M] Lang ru_ru updated (Smollet777).

View file

@ -1,5 +1,7 @@
package wile.engineersdecor;
import net.minecraft.client.util.InputMappings;
import org.lwjgl.glfw.GLFW;
import wile.engineersdecor.detail.ModAuxiliaries;
import wile.engineersdecor.detail.ModConfig;
import wile.engineersdecor.detail.Networking;
@ -33,6 +35,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable;
import java.util.Optional;
@Mod("engineersdecor")
@ -146,19 +149,17 @@ public class ModEngineersDecor
default @Nullable PlayerEntity getPlayerClientSide() { return null; }
default @Nullable World getWorldClientSide() { return null; }
default @Nullable Minecraft mc() { return null; }
default Optional<Boolean> isCtrlDown() { return Optional.empty(); }
}
public static final class ClientProxy implements ISidedProxy
{
public @Nullable PlayerEntity getPlayerClientSide() { return Minecraft.getInstance().player; }
public @Nullable World getWorldClientSide() { return Minecraft.getInstance().world; }
public @Nullable Minecraft mc() { return Minecraft.getInstance(); }
public Optional<Boolean> isCtrlDown() { return Optional.of(ModAuxiliaries.isCtrlDown()); }
}
public static final class ServerProxy implements ISidedProxy
{
public @Nullable PlayerEntity getPlayerClientSide() { return null; }
public @Nullable World getWorldClientSide() { return null; }
public @Nullable Minecraft mc() { return null; }
}
{}
//
// Item group / creative tab

View file

@ -10,6 +10,7 @@ package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.ModAuxiliaries;
import wile.engineersdecor.detail.Networking;
import net.minecraft.inventory.container.*;
import net.minecraft.network.play.server.SSetSlotPacket;
@ -61,12 +62,15 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
public static boolean with_assist = true;
public static boolean with_assist_direct_history_refab = false;
public static boolean with_assist_quickmove_buttons = false;
public static boolean with_crafting_slot_mouse_scrolling = true;
public static final void on_config(boolean without_crafting_assist, boolean with_assist_immediate_history_refab, boolean with_quickmove_buttons)
public static final void on_config(boolean without_crafting_assist, boolean with_assist_immediate_history_refab,
boolean with_quickmove_buttons, boolean without_crafting_slot_mouse_scrolling)
{
with_assist = !without_crafting_assist;
with_assist_direct_history_refab = with_assist_immediate_history_refab;
with_assist_quickmove_buttons = with_quickmove_buttons;
with_crafting_slot_mouse_scrolling = !without_crafting_slot_mouse_scrolling;
CraftingHistory.max_history_size(32);
}
@ -295,6 +299,8 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
public static class BContainer extends Container implements Networking.INetworkSynchronisableContainer
{
public enum PlacementResult { UNCHANGED, INCOMPLETE, PLACED }
// Crafting slot of container --------------------------------------------------------------------------------------
public static class BSlotCrafting extends CraftingResultSlot
{
@ -368,6 +374,13 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
}
}
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; }
}
//------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
public static final int CRAFTING_SLOTS_BEGIN = 0;
@ -576,7 +589,7 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
return false;
}
private List<ItemStack> crafting_slot_stacks_to_add()
private List<ItemStack> refab_crafting_stacks()
{
final ArrayList<ItemStack> slots = new ArrayList<ItemStack>();
final List<ItemStack> tocraft = history_.current();
@ -618,30 +631,46 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
return slots;
}
private List<ItemStack> incr_crafting_grid_stacks(int count)
{
final ArrayList<ItemStack> stacks = new ArrayList<ItemStack>();
for(int i=0; i<9; ++i) {
final ItemStack palced = inventory_.getStackInSlot(i+CRAFTING_SLOTS_BEGIN).copy();
if(!palced.isEmpty()) palced.setCount(count);
stacks.add(palced);
}
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, IInventory inventory, final int slot_begin, final int slot_end, boolean only_fillup)
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 = stack.getMaxStackSize() - stack.getCount();
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.setCount(stack.getMaxStackSize());
stack.grow(nmax);
mvstack.shrink(nmax);
inventory.setInventorySlotContents(i, stack);
limit_left -= nmax;
}
}
if(only_fillup) return mvstack;
@ -651,8 +680,11 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
final ItemStack stack = inventory.getStackInSlot(i);
if(!stack.isEmpty()) continue;
if((!inventory.getStackInSlot(i+1).isItemEqual(mvstack)) && (!inventory.getStackInSlot(i-1).isItemEqual(mvstack))) continue;
inventory.setInventorySlotContents(i, mvstack.copy());
mvstack.setCount(0);
int nmax = Math.min(limit_left, mvstack.getCount());
ItemStack placed = mvstack.copy();
placed.setCount(nmax);
mvstack.shrink(nmax);
inventory.setInventorySlotContents(i, placed);
return mvstack;
}
}
@ -660,8 +692,11 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
for(int i = slot_begin; i < slot_end; ++i) {
final ItemStack stack = inventory.getStackInSlot(i);
if(!stack.isEmpty()) continue;
inventory.setInventorySlotContents(i, mvstack.copy());
mvstack.setCount(0);
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;
@ -671,8 +706,11 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
* 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(IInventory inventory, final ItemStack request_stack, final int slot_begin, final int slot_end)
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();
@ -687,8 +725,8 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
// the user has to place this item manually.
if(stack.hasTag()) {
final CompoundNBT nbt = stack.getTag();
int n = stack.getTag().size();
if((n > 0) && (stack.getTag().contains("Damage"))) --n;
int n = nbt.size();
if((n > 0) && (nbt.contains("Damage"))) --n;
if(n > 0) continue;
}
fetched_stack = stack.copy(); // copy exact stack with nbt and tool damage, otherwise we have an automagical repair of items.
@ -720,7 +758,7 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
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, inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS, false);
ItemStack remaining = move_stack_to_inventory(stack, new SlotRange(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS), false, 0);
inventory_.setInventorySlotContents(grid_i, remaining);
changed = true;
}
@ -733,63 +771,68 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
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, player.inventory,9, 36, true); // prefer filling up inventory stacks
remaining = move_stack_to_inventory(remaining, player.inventory,0, 9, true); // then fill up the hotbar stacks
remaining = move_stack_to_inventory(remaining, player.inventory,9, 36, false); // then allow empty stacks in inventory
remaining = move_stack_to_inventory(remaining, player.inventory,0, 9, false); // then new stacks in the hotbar
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
inventory_.setInventorySlotContents(grid_i, remaining);
changed = true;
}
return changed;
}
enum EnumRefabPlacement { UNCHANGED, INCOMPLETE, PLACED }
private EnumRefabPlacement place_refab_stacks(IInventory inventory, final int slot_begin, final int slot_end)
private PlacementResult place_stacks(final SlotRange[] ranges, final List<ItemStack> to_fill)
{
List<ItemStack> to_fill = crafting_slot_stacks_to_add();
if(history_.current_recipe() != null) result_.setRecipeUsed(history_.current_recipe());
boolean slots_changed = false;
boolean missing_item = false;
int num_slots_placed = 0;
if(!to_fill.isEmpty()) {
for(int it_guard=63; it_guard>=0; --it_guard) {
boolean slots_updated = false;
for(int i = 0; i < 9; ++i) {
final ItemStack req_stack = to_fill.get(i).copy();
if(req_stack.isEmpty()) continue;
req_stack.setCount(1);
to_fill.get(i).shrink(1);
final ItemStack mv_stack = move_stack_from_inventory(inventory, req_stack, slot_begin, slot_end);
if(mv_stack.isEmpty()) { missing_item=true; continue; }
// sizes already checked
ItemStack grid_stack = inventory_.getStackInSlot(i + CRAFTING_SLOTS_BEGIN).copy();
if(grid_stack.isEmpty()) {
grid_stack = mv_stack.copy();
} else {
grid_stack.grow(mv_stack.getCount());
for(SlotRange slot_range: ranges) {
for(int it_guard=63; it_guard>=0; --it_guard) {
boolean slots_updated = false;
for(int i = 0; i < 9; ++i) {
if(to_fill.get(i).isEmpty()) continue;
ItemStack grid_stack = inventory_.getStackInSlot(i + CRAFTING_SLOTS_BEGIN).copy();
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);
if(mv_stack.isEmpty()) continue;
to_fill.get(i).shrink(1);
if(grid_stack.isEmpty()) {
grid_stack = mv_stack.copy();
} else {
grid_stack.grow(mv_stack.getCount());
}
inventory_.setInventorySlotContents(i + CRAFTING_SLOTS_BEGIN, grid_stack);
slots_changed = true;
slots_updated = true;
}
inventory_.setInventorySlotContents(i + CRAFTING_SLOTS_BEGIN, grid_stack);
slots_changed = true;
slots_updated = true;
if(!slots_updated) break;
}
if(!slots_updated) break;
}
}
boolean missing_item = false;
for(ItemStack st:to_fill) {
if(!st.isEmpty()) {
missing_item = true;
break;
}
}
if(!slots_changed) {
return EnumRefabPlacement.UNCHANGED;
return PlacementResult.UNCHANGED;
} else if(missing_item) {
return EnumRefabPlacement.INCOMPLETE;
return PlacementResult.INCOMPLETE;
} else {
return EnumRefabPlacement.PLACED;
return PlacementResult.PLACED;
}
}
private EnumRefabPlacement distribute_stack(IInventory inventory, final int slotno)
private PlacementResult distribute_stack(IInventory inventory, final int slotno)
{
List<ItemStack> to_refab = crafting_slot_stacks_to_add();
List<ItemStack> to_refab = refab_crafting_stacks();
if(history_.current_recipe() != null) result_.setRecipeUsed(history_.current_recipe());
ItemStack to_distribute = inventory.getStackInSlot(slotno).copy();
if(to_distribute.isEmpty()) return EnumRefabPlacement.UNCHANGED;
if(to_distribute.isEmpty()) return PlacementResult.UNCHANGED;
int matching_grid_stack_sizes[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1};
int max_matching_stack_size = -1;
int min_matching_stack_size = 65;
@ -816,9 +859,9 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
}
}
}
if(min_matching_stack_size < 0) return EnumRefabPlacement.UNCHANGED;
if(min_matching_stack_size < 0) return PlacementResult.UNCHANGED;
final int stack_limit_size = Math.min(to_distribute.getMaxStackSize(), inventory_.getInventoryStackLimit());
if(min_matching_stack_size >= stack_limit_size) return EnumRefabPlacement.UNCHANGED;
if(min_matching_stack_size >= stack_limit_size) return PlacementResult.UNCHANGED;
int n_to_distribute = to_distribute.getCount();
for(int it_guard=63; it_guard>=0; --it_guard) {
if(n_to_distribute <= 0) break;
@ -837,7 +880,7 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
}
if(min_matching_stack_size >= stack_limit_size) break; // all full
}
if(n_to_distribute == to_distribute.getCount()) return EnumRefabPlacement.UNCHANGED; // was already full
if(n_to_distribute == to_distribute.getCount()) return PlacementResult.UNCHANGED; // was already full
if(n_to_distribute <= 0) {
inventory.setInventorySlotContents(slotno, ItemStack.EMPTY);
} else {
@ -851,9 +894,30 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
grid_stack.setCount(matching_grid_stack_sizes[i]);
inventory_.setInventorySlotContents(i + CRAFTING_SLOTS_BEGIN, grid_stack);
}
return EnumRefabPlacement.PLACED;
return PlacementResult.PLACED;
}
private boolean decrease_grid_stacks(SlotRange[] ranges, int limit)
{
boolean changed = false;
for(int i=0; i<9; ++i) {
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);
if(remaining.getCount() < stack.getCount()) changed = true;
boolean stop = (remaining.getCount() <= Math.max(0, (stack.getCount()-limit)));
stack = remaining;
if(stop) break;
}
inventory_.setInventorySlotContents(i+CRAFTING_SLOTS_BEGIN, stack.isEmpty() ? ItemStack.EMPTY : stack);
}
return changed;
}
private boolean increase_grid_stacks(SlotRange[] ranges, int limit)
{ return place_stacks(ranges, incr_crafting_grid_stacks(limit)) != PlacementResult.UNCHANGED; }
// Container client/server synchronisation --------------------------------------------------
@OnlyIn(Dist.CLIENT)
@ -901,47 +965,118 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
if(clear_grid_to_player(player)) { changed = true; player_inventory_changed = true; }
} break;
case BGui.BUTTON_FROM_STORAGE: {
EnumRefabPlacement from_storage = place_refab_stacks(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS);
if(from_storage != EnumRefabPlacement.UNCHANGED) changed = true;
if(place_stacks(new SlotRange[]{
new SlotRange(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)
}, refab_crafting_stacks()) != PlacementResult.UNCHANGED) {
changed = true;
}
} break;
case BGui.BUTTON_FROM_PLAYER: {
EnumRefabPlacement from_player_inv = place_refab_stacks(player.inventory, 9, 36);
if(from_player_inv != EnumRefabPlacement.UNCHANGED) { changed = true; player_inventory_changed = true; }
if(from_player_inv != EnumRefabPlacement.PLACED) {
EnumRefabPlacement from_hotbar = place_refab_stacks(player.inventory, 0, 9);
if(from_hotbar != EnumRefabPlacement.UNCHANGED) { changed = true; player_inventory_changed = true; }
if(place_stacks(new SlotRange[]{
new SlotRange(player.inventory, 9, 36),
new SlotRange(player.inventory, 0, 9)
}, refab_crafting_stacks()) != PlacementResult.UNCHANGED) {
changed = true; player_inventory_changed = true;
}
} break;
case BGui.ACTION_PLACE_CURRENT_HISTORY_SEL: {
EnumRefabPlacement from_storage = place_refab_stacks(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS);
if(from_storage != EnumRefabPlacement.UNCHANGED) changed = true;
if(from_storage != EnumRefabPlacement.PLACED) {
EnumRefabPlacement from_player_inv = place_refab_stacks(player.inventory, 9, 36);
if(from_player_inv != EnumRefabPlacement.UNCHANGED) { changed = true; player_inventory_changed = true; }
if(from_player_inv != EnumRefabPlacement.PLACED) {
EnumRefabPlacement from_hotbar = place_refab_stacks(player.inventory, 0, 9);
if(from_hotbar != EnumRefabPlacement.UNCHANGED) { changed = true; player_inventory_changed = true; }
}
if(place_stacks(new SlotRange[]{
new SlotRange(player.inventory, 0, 9),
new SlotRange(player.inventory, 9, 36),
new SlotRange(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)
}, refab_crafting_stacks()) != PlacementResult.UNCHANGED) {
changed = true;
}
} break;
case BGui.ACTION_PLACE_SHIFTCLICKED_STACK: {
final int container_slot_id = nbt.getInt("containerslot");
if((container_slot_id < 10) || (container_slot_id > 53)) break; // out of range
if((container_slot_id < 10) || (container_slot_id > 53)) {
break; // out of range
}
if(container_slot_id >= 46) {
// from storage
final int storage_slot = container_slot_id - 46 + STORAGE_SLOTS_BEGIN;
EnumRefabPlacement stat = distribute_stack(inventory_, storage_slot);
if(stat != EnumRefabPlacement.UNCHANGED) changed = true;
PlacementResult stat = distribute_stack(inventory_, storage_slot);
if(stat != PlacementResult.UNCHANGED) changed = true;
} else {
// from player
int player_slot = (container_slot_id >= 37) ? (container_slot_id-37) : (container_slot_id-10+9);
EnumRefabPlacement stat = distribute_stack(player.inventory, player_slot);
if(stat != EnumRefabPlacement.UNCHANGED) { player_inventory_changed = true; changed = true; }
final ItemStack reference_stack = player.inventory.getStackInSlot(player_slot).copy();
if((!reference_stack.isEmpty()) && (distribute_stack(player.inventory, player_slot) != PlacementResult.UNCHANGED)) {
player_inventory_changed = true;
changed = true;
if(nbt.contains("move-all")) {
for(int i=0; i < player.inventory.getSizeInventory(); ++i) {
final ItemStack stack = player.inventory.getStackInSlot(i);
if(!reference_stack.isItemEqual(stack)) continue;
if(distribute_stack(player.inventory, i) == PlacementResult.UNCHANGED) break; // grid is full
}
}
}
}
} break;
case BGui.ACTION_MOVE_ALL_STACKS: {
final int container_slot_id = nbt.getInt("containerslot");
if((container_slot_id < 1) || (container_slot_id > 53)) {
break; // out of range
} else if(container_slot_id < 10) {
// from crafting grid to player inventory, we clear the grid here as this is most likely
// what is wanted in the end. Saves clicking the other grid stacks.
if(clear_grid_to_player(player)) { changed = true; player_inventory_changed = true; }
if(clear_grid_to_storage(player)) changed = true;
break;
}
IInventory from_inventory;
SlotRange[] to_ranges;
int from_slot;
if(container_slot_id >= 46) {
// from storage to player inventory
from_inventory = inventory_;
from_slot = container_slot_id - 46 + STORAGE_SLOTS_BEGIN;
to_ranges = new SlotRange[] {new SlotRange(player.inventory, 9, 36), new SlotRange(player.inventory, 0, 9)};
} else {
// from player to storage (otherwise ACTION_PLACE_SHIFTCLICKED_STACK would have been used)
from_inventory = player.inventory;
from_slot = (container_slot_id >= 37) ? (container_slot_id-37) : (container_slot_id-10+9);
to_ranges = new SlotRange[] {new SlotRange(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)};
}
final ItemStack reference_stack = from_inventory.getStackInSlot(from_slot).copy();
if(!reference_stack.isEmpty()) {
boolean abort = false;
for(int i=0; (i < from_inventory.getSizeInventory()) && (!abort); ++i) {
final ItemStack stack = from_inventory.getStackInSlot(i);
if(!reference_stack.isItemEqual(stack)) continue;
ItemStack remaining = from_inventory.getStackInSlot(i);
for(SlotRange range:to_ranges) {
remaining = move_stack_to_inventory(remaining, range, false, 0);
if(!remaining.isEmpty()) {
abort = true; // no space left
break;
} else {
changed = player_inventory_changed = true;
}
}
from_inventory.setInventorySlotContents(i, remaining);
}
}
} break;
case BGui.BUTTON_NEXT_COLLISION_RECIPE: {
select_next_collision_recipe(inventory_);
} break;
case BGui.ACTION_DECREASE_CRAFTING_STACKS: {
changed = player_inventory_changed = decrease_grid_stacks(new SlotRange[]{
new SlotRange(player.inventory, 9, 36),
new SlotRange(player.inventory, 0, 9),
new SlotRange(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)
}, MathHelper.clamp(nbt.getInt("limit"), 1, 8));
} break;
case BGui.ACTION_INCREASE_CRAFTING_STACKS: {
changed = player_inventory_changed = increase_grid_stacks(new SlotRange[]{
new SlotRange(player.inventory, 9, 36),
new SlotRange(player.inventory, 0, 9),
new SlotRange(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)
}, MathHelper.clamp(nbt.getInt("limit"), 1, 8));
} break;
}
}
if(changed) inventory_.markDirty();
@ -955,7 +1090,6 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
public CraftingHistory history()
{ return history_; }
// todo: somehow hook into the container listeners for syncing all clients having that container open.
private void syncHistory(PlayerEntity player)
{
if((!with_assist) || (player.world.isRemote)) return;
@ -967,7 +1101,7 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
final CompoundNBT nbt = new CompoundNBT();
nbt.put("history", hist_nbt);
nbt.putBoolean("hascollision", has_recipe_collision_);
Networking.PacketContainerSyncServerToClient.sendToPlayer(player, windowId, nbt);
Networking.PacketContainerSyncServerToClient.sendToListeners(player.world, this, nbt);
}
private void syncProperties(PlayerEntity player)
@ -995,6 +1129,9 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
protected static final String BUTTON_NEXT_COLLISION_RECIPE = "next-recipe";
protected static final String ACTION_PLACE_CURRENT_HISTORY_SEL = "place-refab";
protected static final String ACTION_PLACE_SHIFTCLICKED_STACK = "place-stack";
protected static final String ACTION_MOVE_ALL_STACKS = "move-stacks";
protected static final String ACTION_INCREASE_CRAFTING_STACKS = "inc-crafting-stacks";
protected static final String ACTION_DECREASE_CRAFTING_STACKS = "dec-crafting-stacks";
protected static final ResourceLocation BACKGROUND = new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/treated_wood_crafting_table.png");
protected final PlayerEntity player;
protected final ArrayList<Button> buttons = new ArrayList<Button>();
@ -1134,29 +1271,74 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
if(place_refab && (!with_assist_direct_history_refab)) on_history_item_placement(); // place after crafting -> confirmation first
return;
}
if((type == ClickType.QUICK_MOVE) && (slotId > 9) && (slot.getHasStack())) { // container slots 0..9 are crafting output and grid
if((type == ClickType.QUICK_MOVE) && (slotId > 0) && (slot.getHasStack())) { // container slots 0 is crafting output
if(with_assist) {
List<ItemStack> history = getContainer().history().current();
boolean palce_in_crafting_grid = (!history.isEmpty());
if(!palce_in_crafting_grid) {
for(int i = 0; i < 9; ++i) {
if(!(getContainer().getSlot(i).getStack().isEmpty())) {
palce_in_crafting_grid = true;
break;
boolean palce_in_crafting_grid = false;
if(slotId > 9) { // container slots 1..9 are crafting grid
palce_in_crafting_grid = (!history.isEmpty());
if(!palce_in_crafting_grid) {
for(int i = 0; i < 9; ++i) {
if(!(getContainer().getSlot(i).getStack().isEmpty())) {
palce_in_crafting_grid = true;
break;
}
}
}
}
if(palce_in_crafting_grid) {
// Explicit grid placement.
CompoundNBT nbt = new CompoundNBT();
nbt.putInt("containerslot", slotId);
if(ModAuxiliaries.isCtrlDown()) nbt.putBoolean("move-all", true);
action(ACTION_PLACE_SHIFTCLICKED_STACK, nbt);
return;
} else if(ModAuxiliaries.isCtrlDown()) {
// Move all same items from the inventory of the clicked slot
// (or the crafting grid) to the corresponding target inventory.
CompoundNBT nbt = new CompoundNBT();
nbt.putInt("containerslot", slotId);
action(ACTION_MOVE_ALL_STACKS, nbt);
return;
} else {
// Let the normal slot click handle that.
}
}
}
super.handleMouseClick(slot, slotId, mouseButton, type);
}
@Override
public boolean mouseScrolled(double mouseX, double mouseY, double wheel_inc)
{
final Slot resultSlot = this.getSlotUnderMouse();
if((!with_crafting_slot_mouse_scrolling) || (!(resultSlot instanceof CraftingResultSlot))) {
return this.func_212930_a(mouseX, mouseY).filter((evl) -> {
return evl.mouseScrolled(mouseX, mouseY, wheel_inc);
}).isPresent();
}
int count = resultSlot.getStack().getCount();
int limit = (ModAuxiliaries.isShiftDown() ? 2 : 1) * (ModAuxiliaries.isCtrlDown() ? 4 : 1);
if(wheel_inc > 0.1) {
if(count > 0) {
if((count < resultSlot.getStack().getMaxStackSize()) && (count < resultSlot.getSlotStackLimit())) {
CompoundNBT nbt = new CompoundNBT();
if(limit > 1) nbt.putInt("limit", limit);
action(ACTION_INCREASE_CRAFTING_STACKS, nbt);
}
} else if(!getContainer().history().current().isEmpty()) {
action(ACTION_PLACE_CURRENT_HISTORY_SEL);
}
} else if(wheel_inc < -0.1) {
if(count > 0) {
CompoundNBT nbt = new CompoundNBT();
if(limit > 1) nbt.putInt("limit", limit);
action(ACTION_DECREASE_CRAFTING_STACKS, nbt);
}
}
return true;
}
private void on_history_item_placement()
{
if((getContainer().history().current().isEmpty())) return;

View file

@ -25,6 +25,8 @@ import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import javax.annotation.Nullable;
@ -61,7 +63,7 @@ public class BlockDecorSolarPanel extends BlockDecor
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity
public static class BTileEntity extends TileEntity implements ITickableTileEntity, ICapabilityProvider, IEnergyStorage
{
public static final int DEFAULT_PEAK_POWER = 45;
public static final int TICK_INTERVAL = 8;
@ -93,6 +95,51 @@ public class BlockDecorSolarPanel extends BlockDecor
protected void writenbt(CompoundNBT nbt, boolean update_packet)
{ nbt.putInt("energy", accumulated_power_); }
// IEnergyStorage --------------------------------------------------------------------------
@Override
public boolean canExtract()
{ return true; }
@Override
public boolean canReceive()
{ return false; }
@Override
public int getMaxEnergyStored()
{ return max_power_storage_; }
@Override
public int getEnergyStored()
{ return accumulated_power_; }
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{
int p = Math.min(accumulated_power_, maxExtract);
if(!simulate) accumulated_power_ -= p;
return p;
}
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{ return 0; }
// ICapabilityProvider ---------------------------------------------------------------------
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> (IEnergyStorage)this);
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability== CapabilityEnergy.ENERGY) {
return energy_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// TileEntity ------------------------------------------------------------------------------
@Override

View file

@ -192,6 +192,9 @@ public class BlockDecorTreeCutter extends BlockDecorDirectedHorizontal
--active_timer_;
}
boolean active = (active_timer_ > 0);
if(requires_power && !active) {
proc_time_elapsed_ = Math.max(0, proc_time_elapsed_ - 2*TICK_INTERVAL);
}
if(proc_time_elapsed_ >= cutting_time_needed) {
proc_time_elapsed_ = 0;
TreeCutting.chopTree(world, tree_state, tree_pos, 512, false);

View file

@ -5,8 +5,6 @@
* @license MIT (see https://opensource.org/licenses/MIT)
*
* General commonly used functionality.
*
* @TODO KEYBOARD INPUT
*/
package wile.engineersdecor.detail;
@ -26,6 +24,7 @@ import net.minecraft.util.math.AxisAlignedBB;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.apache.logging.log4j.Logger;
import org.lwjgl.glfw.GLFW;
import javax.annotation.Nullable;
import java.io.BufferedReader;
@ -40,6 +39,8 @@ import java.util.stream.Collectors;
public class ModAuxiliaries
{
public static final String MODID = ModEngineersDecor.MODID;
public static final Logger LOGGER = ModEngineersDecor.logger();
public static final ModEngineersDecor.ISidedProxy PROXY = ModEngineersDecor.proxy;
// -------------------------------------------------------------------------------------------------------------------
// Sideness, system/environment, tagging interfaces
@ -53,30 +54,44 @@ public class ModAuxiliaries
public static final boolean isDevelopmentMode()
{ return SharedConstants.developmentMode; }
@OnlyIn(Dist.CLIENT)
public static final boolean isShiftDown()
{
return (InputMappings.isKeyDown(PROXY.mc().mainWindow.getHandle(), GLFW.GLFW_KEY_LEFT_SHIFT) ||
InputMappings.isKeyDown(PROXY.mc().mainWindow.getHandle(), GLFW.GLFW_KEY_RIGHT_SHIFT));
}
@OnlyIn(Dist.CLIENT)
public static final boolean isCtrlDown()
{
return (InputMappings.isKeyDown(PROXY.mc().mainWindow.getHandle(), GLFW.GLFW_KEY_LEFT_CONTROL) ||
InputMappings.isKeyDown(PROXY.mc().mainWindow.getHandle(), GLFW.GLFW_KEY_RIGHT_CONTROL));
}
// -------------------------------------------------------------------------------------------------------------------
// Logging
// -------------------------------------------------------------------------------------------------------------------
public static final void logInfo(final String msg)
{ ModEngineersDecor.logger().info(msg); }
{ LOGGER.info(msg); }
public static final void logWarn(final String msg)
{ ModEngineersDecor.logger().warn(msg); }
{ LOGGER.warn(msg); }
public static final void logError(final String msg)
{ ModEngineersDecor.logger().error(msg); }
{ LOGGER.error(msg); }
// -------------------------------------------------------------------------------------------------------------------
// Localization, text formatting
// -------------------------------------------------------------------------------------------------------------------
/**
* Text localisation wrapper, implicitly prepends `ModEngineersDecor.MODID` to the
* Text localisation wrapper, implicitly prepends `MODID` to the
* translation keys. Forces formatting argument, nullable if no special formatting shall be applied..
*/
public static TranslationTextComponent localizable(String modtrkey, @Nullable TextFormatting color, Object... args)
{
TranslationTextComponent tr = new TranslationTextComponent(ModEngineersDecor.MODID+"."+modtrkey, args);
TranslationTextComponent tr = new TranslationTextComponent(MODID+"."+modtrkey, args);
if(color!=null) tr.getStyle().setColor(color);
return tr;
}
@ -85,7 +100,7 @@ public class ModAuxiliaries
{ return localizable(modtrkey, null); }
public static TranslationTextComponent localizable_block_key(String blocksubkey)
{ return new TranslationTextComponent("block."+ModEngineersDecor.MODID+"."+blocksubkey); }
{ return new TranslationTextComponent("block."+MODID+"."+blocksubkey); }
@OnlyIn(Dist.CLIENT)
public static String localize(String translationKey, Object... args)
@ -134,21 +149,11 @@ public class ModAuxiliaries
{
@OnlyIn(Dist.CLIENT)
public static boolean extendedTipCondition()
{
return (
InputMappings.isKeyDown(ModEngineersDecor.proxy.mc().mainWindow.getHandle(), GLFW.GLFW_KEY_LEFT_SHIFT) ||
InputMappings.isKeyDown(ModEngineersDecor.proxy.mc().mainWindow.getHandle(), GLFW.GLFW_KEY_RIGHT_SHIFT)
);
}
{ return isShiftDown(); }
@OnlyIn(Dist.CLIENT)
public static boolean helpCondition()
{
return extendedTipCondition() && (
InputMappings.isKeyDown(ModEngineersDecor.proxy.mc().mainWindow.getHandle(), GLFW.GLFW_KEY_LEFT_CONTROL) ||
InputMappings.isKeyDown(ModEngineersDecor.proxy.mc().mainWindow.getHandle(), GLFW.GLFW_KEY_RIGHT_CONTROL)
);
}
{ return isShiftDown() && isCtrlDown(); }
/**
* Adds an extended tooltip or help tooltip depending on the key states of CTRL and SHIFT.
@ -177,8 +182,8 @@ public class ModAuxiliaries
return true;
} else if(addAdvancedTooltipHints) {
String s = "";
if(tip_available) s += localize(ModEngineersDecor.MODID + ".tooltip.hint.extended") + (help_available ? " " : "");
if(help_available) s += localize(ModEngineersDecor.MODID + ".tooltip.hint.help");
if(tip_available) s += localize(MODID + ".tooltip.hint.extended") + (help_available ? " " : "");
if(help_available) s += localize(MODID + ".tooltip.hint.help");
tooltip.add(new StringTextComponent(s));
}
return false;
@ -252,7 +257,7 @@ public class ModAuxiliaries
{
try {
// Done during construction to have an exact version in case of a crash while registering.
String version = ModAuxiliaries.loadResourceText("/.gitversion").trim();
String version = ModAuxiliaries.loadResourceText("/.gitversion-" + MODID).trim();
logInfo(mod_name+((version.isEmpty())?(" (dev build)"):(" GIT id #"+version)) + ".");
} catch(Throwable e) {
// (void)e; well, then not. Priority is not to get unneeded crashes because of version logging.

View file

@ -143,6 +143,7 @@ public class ModConfig
public final ForgeConfigSpec.DoubleValue chair_mob_sitting_probability_percent;
public final ForgeConfigSpec.DoubleValue chair_mob_standup_probability_percent;
public final ForgeConfigSpec.BooleanValue with_crafting_quickmove_buttons;
public final ForgeConfigSpec.BooleanValue without_crafting_mouse_scrolling;
public final ForgeConfigSpec.IntValue pipevalve_max_flowrate;
public final ForgeConfigSpec.IntValue pipevalve_redstone_gain;
public final ForgeConfigSpec.IntValue block_breaker_power_consumption;
@ -389,6 +390,10 @@ public class ModConfig
.comment("Enables small quick-move arrows from/to player/block storage. " +
"Makes the UI a bit too busy, therefore disabled by default.")
.define("with_crafting_quickmove_buttons", false);
without_crafting_mouse_scrolling = builder
.translation(ModEngineersDecor.MODID + ".config.without_crafting_mouse_scrolling")
.comment("Disables increasing/decreasing the crafting grid items by scrolling over the crafting result slot.")
.define("without_crafting_mouse_scrolling", false);
pipevalve_max_flowrate = builder
.translation(ModEngineersDecor.MODID + ".config.pipevalve_max_flowrate")
.comment("Defines how many millibuckets can be transferred (per tick) through the valves. " +
@ -598,7 +603,7 @@ public class ModConfig
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());
BlockDecorCraftingTable.on_config(COMMON.without_crafting_table_history.get(), false, COMMON.with_crafting_quickmove_buttons.get());
BlockDecorCraftingTable.on_config(COMMON.without_crafting_table_history.get(), false, COMMON.with_crafting_quickmove_buttons.get(), COMMON.without_crafting_mouse_scrolling.get());
BlockDecorPipeValve.on_config(COMMON.pipevalve_max_flowrate.get(), COMMON.pipevalve_redstone_gain.get());
BlockDecorFurnaceElectrical.BTileEntity.on_config(COMMON.e_furnace_speed_percent.get(), COMMON.e_furnace_power_consumption.get(), COMMON.e_furnace_automatic_pulling.get());
BlockDecorSolarPanel.BTileEntity.on_config(COMMON.small_solar_panel_peak_production.get());

View file

@ -204,16 +204,14 @@ public class Networking
DEFAULT_CHANNEL.sendTo(new PacketContainerSyncServerToClient(container.windowId, nbt), ((ServerPlayerEntity)player).connection.netManager, NetworkDirection.PLAY_TO_CLIENT);
}
// Container listners are private, and add/remove listener overriding seems not too nice, as
// removeListner is client only???
//public static <C extends Container & INetworkSynchronisableContainer> void sendToListeners(C container, CompoundNBT nbt)
//{
// for(IContainerListener listener: container.getListeners()) {
// if(!(listener instanceof ServerPlayerEntity)) continue;
// DEFAULT_CHANNEL.sendTo(new PacketContainerSyncServerToClient(container.windowId, nbt), ((ServerPlayerEntity)listener).connection.netManager, NetworkDirection.PLAY_TO_CLIENT);
// }
//}
public static <C extends Container & INetworkSynchronisableContainer>
void sendToListeners(World world, C container, CompoundNBT nbt)
{
for(PlayerEntity player: world.getPlayers()) {
if(player.openContainer.windowId != container.windowId) continue;
sendToPlayer(player, container.windowId, nbt);
}
}
public PacketContainerSyncServerToClient()
{}

View file

@ -8,12 +8,12 @@
*/
package wile.engineersdecor.eapi.jei;
import mezz.jei.api.constants.VanillaRecipeCategoryUid;
import mezz.jei.api.registration.IRecipeTransferRegistration;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.blocks.BlockDecorCraftingTable;
import wile.engineersdecor.detail.ModConfig;
import wile.engineersdecor.ModContent;
import mezz.jei.api.constants.VanillaRecipeCategoryUid;
import mezz.jei.api.registration.IRecipeTransferRegistration;
import mezz.jei.api.constants.VanillaTypes;
import mezz.jei.api.runtime.IJeiRuntime;
import net.minecraft.block.Block;

View file

@ -101,8 +101,8 @@
"block.engineersdecor.clinker_brick_stairs.help": "§6Looks slightly darker and more color intensive than the vanilla brick block.",
"block.engineersdecor.clinker_brick_stained_stairs": "Stained Clinker Brick Stairs",
"block.engineersdecor.clinker_brick_stained_stairs.help": "§6Looks slightly darker and more color intensive than the vanilla brick block. Has more visible traces of grime or stain.",
"block.engineersdecor.slag_brick_stairs": "Clinker Brick Stairs",
"block.engineersdecor.slag_brick_stairs.help": "§6Looks slightly darker and more color intensive than the vanilla brick block.",
"block.engineersdecor.slag_brick_stairs": "Slag Brick Stairs",
"block.engineersdecor.slag_brick_stairs.help": "§6Gray-brown brick stairs.",
"block.engineersdecor.rebar_concrete_stairs": "Rebar Concrete Stairs",
"block.engineersdecor.rebar_concrete_stairs.help": "§6Steel reinforced concrete stairs.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.rebar_concrete_tile_stairs": "Rebar Concrete Tile Stairs",
@ -134,7 +134,7 @@
"block.engineersdecor.treated_wood_stool": "Treated Wood Stool",
"block.engineersdecor.treated_wood_stool.help": "§6Robust Wood Stool.§r Indoor and outdoor use.",
"block.engineersdecor.treated_wood_crafting_table": "Treated Wood Crafting Table",
"block.engineersdecor.treated_wood_crafting_table.help": "§6Robust and weather-proof.§r Eight storage slots, keeps inventory, no vanilla recipe book.\n Click up/down arrow buttons for crafting history selection, output slot for item placement, X-button to clear crafting grid and history. Shift-click stack: player-to-storage stack transfer when crafting grid empty, otherwise player-to-grid stack transfer. Automatically distributes the clicked stack.",
"block.engineersdecor.treated_wood_crafting_table.help": "§6Robust and weather-proof.§r Eight storage slots, keeps inventory, no vanilla recipe book.\n Click up/down arrow buttons for crafting history selection, output slot for item placement, X-button to clear crafting grid and history. Shift-click stack: player-to-storage stack transfer when crafting grid empty, otherwise player-to-grid stack transfer. Automatically distributes the clicked stack. Shift-Ctrl-click stack: Move all same stacks. Mouse wheel over crafting slot: Increase/decrease crafting grid items.",
"block.engineersdecor.treated_wood_side_table": "Treated Wood Side Table",
"block.engineersdecor.treated_wood_side_table.help": "§6Needed after the work's done.",
"block.engineersdecor.iron_inset_light": "Inset Light",

View file

@ -48,4 +48,8 @@ tasks["create-half-slab-assets"] = function() {
for(var i in block_data) halfslab_assets.create(block_data[i]);
}
tasks["lang-json-fixes"] = function() {
libtask114.stdtasks["lang-json-fixes"]();
};
libtask.run(tasks, sys.args);

View file

@ -68,6 +68,7 @@ sanatize:
@echo "[1.15] Running sanatising tasks ..."
@djs tasks.js trailing-whitespaces
@djs tasks.js tabs-to-spaces
@djs tasks.js lang-json-fixes
@djs tasks.js sync-languages
@djs tasks.js version-check
@djs tasks.js update-json

View file

@ -70,7 +70,7 @@ dependencies {
processResources {
outputs.upToDateWhen { false } // thx to @tterrag for this hint
doLast { file("${sourceSets.main.output.resourcesDir}/.gitversion").text = 'git log "-1" "--format=%h"'.execute().in.text.trim() }
doLast { file("${sourceSets.main.output.resourcesDir}/.gitversion-engineersdecor").text = 'git log "-1" "--format=%h"'.execute().in.text.trim() }
}
jar {
@ -88,7 +88,7 @@ jar {
}
def reobfFile = file("$buildDir/reobfJar/output.jar")
def reobfArtifact = artifacts.add('default', reobfFile) { type 'jar'; builtBy 'reobfJar'; }
def reobfArtifact = artifacts.add('default', reobfFile) { type 'jar'; builtBy 'reobfJar' }
publishing {
publications { mavenJava(MavenPublication) { artifact reobfArtifact } }

View file

@ -2,7 +2,7 @@
org.gradle.daemon=false
org.gradle.jvmargs=-Xmx8G
version_minecraft=1.15.1
version_forge_minecraft=1.15.1-30.0.16
version_fml_mappings=20190719-1.14.3
version_jei=1.14.4:6.0.0.10
version_engineersdecor=1.0.18-b2
version_forge_minecraft=1.15.1-30.0.35
version_fml_mappings=20191105-1.14.3
version_jei=1.15.1-6.0.0.1
version_engineersdecor=1.0.18-b3

View file

@ -1,12 +1,13 @@
{
"homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/",
"1.15.1": {
"1.0.18-b3": "[A] Added Treated Wood Crafting table tweaks (ctrl-shift moves all same stacks from the inventory, mouse wheel over crafting slot increases/decreases crafting grid stacks).\n[F] EN Lang file fixed (issue #76, thx Riverstar907).\n[F] Fixed Tree Cutter not respecting power-required config (thx federsavo, issue #77).\n[F] Fixed Small Solar Panel not exposing energy capability (thx MatthiasMann, issue #78).",
"1.0.18-b2": "[M] Lang ru_ru updated (Smollet777).",
"1.0.18-b1": "[U] Updated to Forge 1.15.1-30.0.16/20190719-1.14.3.\n[F] Client setup Dist annotation fixed (issue #73, thx hitsu420).\n[F] Double newline escapes in lang files fixed (\"\\n\" in a tooltip).\n[M] Updated zh_cn lang file (scikirbypoke).\n[A] Added opt-out config for the Small Tree Cutter",
"1.0.17-b2": "[A] Initial port."
},
"promos": {
"1.15.1-recommended": "",
"1.15.1-latest": "1.0.18-b2"
"1.15.1-latest": "1.0.18-b3"
}
}

View file

@ -11,6 +11,12 @@ Mod sources for Minecraft version 1.15.1.
## Version history
- v1.0.18-b3 [A] Added Treated Wood Crafting table tweaks (ctrl-shift moves all same stacks from the
inventory, mouse wheel over crafting slot increases/decreases crafting grid stacks).
[F] EN Lang file fixed (issue #76, thx Riverstar907).
[F] Fixed Tree Cutter not respecting power-required config (thx federsavo, issue #77).
[F] Fixed Small Solar Panel not exposing energy capability (thx MatthiasMann, issue #78).
- v1.0.18-b2 [M] Lang ru_ru updated (Smollet777).
- v1.0.18-b1 [U] Updated to Forge 1.15.1-30.0.16/20190719-1.14.3.

View file

@ -10,6 +10,7 @@ package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.ModAuxiliaries;
import wile.engineersdecor.detail.Networking;
import net.minecraft.inventory.container.*;
import net.minecraft.network.play.server.SSetSlotPacket;
@ -60,12 +61,15 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
public static boolean with_assist = true;
public static boolean with_assist_direct_history_refab = false;
public static boolean with_assist_quickmove_buttons = false;
public static boolean with_crafting_slot_mouse_scrolling = true;
public static final void on_config(boolean without_crafting_assist, boolean with_assist_immediate_history_refab, boolean with_quickmove_buttons)
public static final void on_config(boolean without_crafting_assist, boolean with_assist_immediate_history_refab,
boolean with_quickmove_buttons, boolean without_crafting_slot_mouse_scrolling)
{
with_assist = !without_crafting_assist;
with_assist_direct_history_refab = with_assist_immediate_history_refab;
with_assist_quickmove_buttons = with_quickmove_buttons;
with_crafting_slot_mouse_scrolling = !without_crafting_slot_mouse_scrolling;
CraftingHistory.max_history_size(32);
}
@ -294,6 +298,8 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
public static class BContainer extends Container implements Networking.INetworkSynchronisableContainer
{
public enum PlacementResult { UNCHANGED, INCOMPLETE, PLACED }
// Crafting slot of container --------------------------------------------------------------------------------------
public static class BSlotCrafting extends CraftingResultSlot
{
@ -367,6 +373,13 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
}
}
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; }
}
//------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
public static final int CRAFTING_SLOTS_BEGIN = 0;
@ -575,7 +588,7 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
return false;
}
private List<ItemStack> crafting_slot_stacks_to_add()
private List<ItemStack> refab_crafting_stacks()
{
final ArrayList<ItemStack> slots = new ArrayList<ItemStack>();
final List<ItemStack> tocraft = history_.current();
@ -617,30 +630,46 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
return slots;
}
private List<ItemStack> incr_crafting_grid_stacks(int count)
{
final ArrayList<ItemStack> stacks = new ArrayList<ItemStack>();
for(int i=0; i<9; ++i) {
final ItemStack palced = inventory_.getStackInSlot(i+CRAFTING_SLOTS_BEGIN).copy();
if(!palced.isEmpty()) palced.setCount(count);
stacks.add(palced);
}
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, IInventory inventory, final int slot_begin, final int slot_end, boolean only_fillup)
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 = stack.getMaxStackSize() - stack.getCount();
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.setCount(stack.getMaxStackSize());
stack.grow(nmax);
mvstack.shrink(nmax);
inventory.setInventorySlotContents(i, stack);
limit_left -= nmax;
}
}
if(only_fillup) return mvstack;
@ -650,8 +679,11 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
final ItemStack stack = inventory.getStackInSlot(i);
if(!stack.isEmpty()) continue;
if((!inventory.getStackInSlot(i+1).isItemEqual(mvstack)) && (!inventory.getStackInSlot(i-1).isItemEqual(mvstack))) continue;
inventory.setInventorySlotContents(i, mvstack.copy());
mvstack.setCount(0);
int nmax = Math.min(limit_left, mvstack.getCount());
ItemStack placed = mvstack.copy();
placed.setCount(nmax);
mvstack.shrink(nmax);
inventory.setInventorySlotContents(i, placed);
return mvstack;
}
}
@ -659,8 +691,11 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
for(int i = slot_begin; i < slot_end; ++i) {
final ItemStack stack = inventory.getStackInSlot(i);
if(!stack.isEmpty()) continue;
inventory.setInventorySlotContents(i, mvstack.copy());
mvstack.setCount(0);
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;
@ -670,8 +705,11 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
* 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(IInventory inventory, final ItemStack request_stack, final int slot_begin, final int slot_end)
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();
@ -686,8 +724,8 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
// the user has to place this item manually.
if(stack.hasTag()) {
final CompoundNBT nbt = stack.getTag();
int n = stack.getTag().size();
if((n > 0) && (stack.getTag().contains("Damage"))) --n;
int n = nbt.size();
if((n > 0) && (nbt.contains("Damage"))) --n;
if(n > 0) continue;
}
fetched_stack = stack.copy(); // copy exact stack with nbt and tool damage, otherwise we have an automagical repair of items.
@ -719,7 +757,7 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
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, inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS, false);
ItemStack remaining = move_stack_to_inventory(stack, new SlotRange(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS), false, 0);
inventory_.setInventorySlotContents(grid_i, remaining);
changed = true;
}
@ -732,63 +770,68 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
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, player.inventory,9, 36, true); // prefer filling up inventory stacks
remaining = move_stack_to_inventory(remaining, player.inventory,0, 9, true); // then fill up the hotbar stacks
remaining = move_stack_to_inventory(remaining, player.inventory,9, 36, false); // then allow empty stacks in inventory
remaining = move_stack_to_inventory(remaining, player.inventory,0, 9, false); // then new stacks in the hotbar
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
inventory_.setInventorySlotContents(grid_i, remaining);
changed = true;
}
return changed;
}
enum EnumRefabPlacement { UNCHANGED, INCOMPLETE, PLACED }
private EnumRefabPlacement place_refab_stacks(IInventory inventory, final int slot_begin, final int slot_end)
private PlacementResult place_stacks(final SlotRange[] ranges, final List<ItemStack> to_fill)
{
List<ItemStack> to_fill = crafting_slot_stacks_to_add();
if(history_.current_recipe() != null) result_.setRecipeUsed(history_.current_recipe());
boolean slots_changed = false;
boolean missing_item = false;
int num_slots_placed = 0;
if(!to_fill.isEmpty()) {
for(int it_guard=63; it_guard>=0; --it_guard) {
boolean slots_updated = false;
for(int i = 0; i < 9; ++i) {
final ItemStack req_stack = to_fill.get(i).copy();
if(req_stack.isEmpty()) continue;
req_stack.setCount(1);
to_fill.get(i).shrink(1);
final ItemStack mv_stack = move_stack_from_inventory(inventory, req_stack, slot_begin, slot_end);
if(mv_stack.isEmpty()) { missing_item=true; continue; }
// sizes already checked
ItemStack grid_stack = inventory_.getStackInSlot(i + CRAFTING_SLOTS_BEGIN).copy();
if(grid_stack.isEmpty()) {
grid_stack = mv_stack.copy();
} else {
grid_stack.grow(mv_stack.getCount());
for(SlotRange slot_range: ranges) {
for(int it_guard=63; it_guard>=0; --it_guard) {
boolean slots_updated = false;
for(int i = 0; i < 9; ++i) {
if(to_fill.get(i).isEmpty()) continue;
ItemStack grid_stack = inventory_.getStackInSlot(i + CRAFTING_SLOTS_BEGIN).copy();
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);
if(mv_stack.isEmpty()) continue;
to_fill.get(i).shrink(1);
if(grid_stack.isEmpty()) {
grid_stack = mv_stack.copy();
} else {
grid_stack.grow(mv_stack.getCount());
}
inventory_.setInventorySlotContents(i + CRAFTING_SLOTS_BEGIN, grid_stack);
slots_changed = true;
slots_updated = true;
}
inventory_.setInventorySlotContents(i + CRAFTING_SLOTS_BEGIN, grid_stack);
slots_changed = true;
slots_updated = true;
if(!slots_updated) break;
}
if(!slots_updated) break;
}
}
boolean missing_item = false;
for(ItemStack st:to_fill) {
if(!st.isEmpty()) {
missing_item = true;
break;
}
}
if(!slots_changed) {
return EnumRefabPlacement.UNCHANGED;
return PlacementResult.UNCHANGED;
} else if(missing_item) {
return EnumRefabPlacement.INCOMPLETE;
return PlacementResult.INCOMPLETE;
} else {
return EnumRefabPlacement.PLACED;
return PlacementResult.PLACED;
}
}
private EnumRefabPlacement distribute_stack(IInventory inventory, final int slotno)
private PlacementResult distribute_stack(IInventory inventory, final int slotno)
{
List<ItemStack> to_refab = crafting_slot_stacks_to_add();
List<ItemStack> to_refab = refab_crafting_stacks();
if(history_.current_recipe() != null) result_.setRecipeUsed(history_.current_recipe());
ItemStack to_distribute = inventory.getStackInSlot(slotno).copy();
if(to_distribute.isEmpty()) return EnumRefabPlacement.UNCHANGED;
if(to_distribute.isEmpty()) return PlacementResult.UNCHANGED;
int matching_grid_stack_sizes[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1};
int max_matching_stack_size = -1;
int min_matching_stack_size = 65;
@ -815,9 +858,9 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
}
}
}
if(min_matching_stack_size < 0) return EnumRefabPlacement.UNCHANGED;
if(min_matching_stack_size < 0) return PlacementResult.UNCHANGED;
final int stack_limit_size = Math.min(to_distribute.getMaxStackSize(), inventory_.getInventoryStackLimit());
if(min_matching_stack_size >= stack_limit_size) return EnumRefabPlacement.UNCHANGED;
if(min_matching_stack_size >= stack_limit_size) return PlacementResult.UNCHANGED;
int n_to_distribute = to_distribute.getCount();
for(int it_guard=63; it_guard>=0; --it_guard) {
if(n_to_distribute <= 0) break;
@ -836,7 +879,7 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
}
if(min_matching_stack_size >= stack_limit_size) break; // all full
}
if(n_to_distribute == to_distribute.getCount()) return EnumRefabPlacement.UNCHANGED; // was already full
if(n_to_distribute == to_distribute.getCount()) return PlacementResult.UNCHANGED; // was already full
if(n_to_distribute <= 0) {
inventory.setInventorySlotContents(slotno, ItemStack.EMPTY);
} else {
@ -850,9 +893,30 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
grid_stack.setCount(matching_grid_stack_sizes[i]);
inventory_.setInventorySlotContents(i + CRAFTING_SLOTS_BEGIN, grid_stack);
}
return EnumRefabPlacement.PLACED;
return PlacementResult.PLACED;
}
private boolean decrease_grid_stacks(SlotRange[] ranges, int limit)
{
boolean changed = false;
for(int i=0; i<9; ++i) {
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);
if(remaining.getCount() < stack.getCount()) changed = true;
boolean stop = (remaining.getCount() <= Math.max(0, (stack.getCount()-limit)));
stack = remaining;
if(stop) break;
}
inventory_.setInventorySlotContents(i+CRAFTING_SLOTS_BEGIN, stack.isEmpty() ? ItemStack.EMPTY : stack);
}
return changed;
}
private boolean increase_grid_stacks(SlotRange[] ranges, int limit)
{ return place_stacks(ranges, incr_crafting_grid_stacks(limit)) != PlacementResult.UNCHANGED; }
// Container client/server synchronisation --------------------------------------------------
@OnlyIn(Dist.CLIENT)
@ -900,47 +964,118 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
if(clear_grid_to_player(player)) { changed = true; player_inventory_changed = true; }
} break;
case BGui.BUTTON_FROM_STORAGE: {
EnumRefabPlacement from_storage = place_refab_stacks(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS);
if(from_storage != EnumRefabPlacement.UNCHANGED) changed = true;
if(place_stacks(new SlotRange[]{
new SlotRange(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)
}, refab_crafting_stacks()) != PlacementResult.UNCHANGED) {
changed = true;
}
} break;
case BGui.BUTTON_FROM_PLAYER: {
EnumRefabPlacement from_player_inv = place_refab_stacks(player.inventory, 9, 36);
if(from_player_inv != EnumRefabPlacement.UNCHANGED) { changed = true; player_inventory_changed = true; }
if(from_player_inv != EnumRefabPlacement.PLACED) {
EnumRefabPlacement from_hotbar = place_refab_stacks(player.inventory, 0, 9);
if(from_hotbar != EnumRefabPlacement.UNCHANGED) { changed = true; player_inventory_changed = true; }
if(place_stacks(new SlotRange[]{
new SlotRange(player.inventory, 9, 36),
new SlotRange(player.inventory, 0, 9)
}, refab_crafting_stacks()) != PlacementResult.UNCHANGED) {
changed = true; player_inventory_changed = true;
}
} break;
case BGui.ACTION_PLACE_CURRENT_HISTORY_SEL: {
EnumRefabPlacement from_storage = place_refab_stacks(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS);
if(from_storage != EnumRefabPlacement.UNCHANGED) changed = true;
if(from_storage != EnumRefabPlacement.PLACED) {
EnumRefabPlacement from_player_inv = place_refab_stacks(player.inventory, 9, 36);
if(from_player_inv != EnumRefabPlacement.UNCHANGED) { changed = true; player_inventory_changed = true; }
if(from_player_inv != EnumRefabPlacement.PLACED) {
EnumRefabPlacement from_hotbar = place_refab_stacks(player.inventory, 0, 9);
if(from_hotbar != EnumRefabPlacement.UNCHANGED) { changed = true; player_inventory_changed = true; }
}
if(place_stacks(new SlotRange[]{
new SlotRange(player.inventory, 0, 9),
new SlotRange(player.inventory, 9, 36),
new SlotRange(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)
}, refab_crafting_stacks()) != PlacementResult.UNCHANGED) {
changed = true;
}
} break;
case BGui.ACTION_PLACE_SHIFTCLICKED_STACK: {
final int container_slot_id = nbt.getInt("containerslot");
if((container_slot_id < 10) || (container_slot_id > 53)) break; // out of range
if((container_slot_id < 10) || (container_slot_id > 53)) {
break; // out of range
}
if(container_slot_id >= 46) {
// from storage
final int storage_slot = container_slot_id - 46 + STORAGE_SLOTS_BEGIN;
EnumRefabPlacement stat = distribute_stack(inventory_, storage_slot);
if(stat != EnumRefabPlacement.UNCHANGED) changed = true;
PlacementResult stat = distribute_stack(inventory_, storage_slot);
if(stat != PlacementResult.UNCHANGED) changed = true;
} else {
// from player
int player_slot = (container_slot_id >= 37) ? (container_slot_id-37) : (container_slot_id-10+9);
EnumRefabPlacement stat = distribute_stack(player.inventory, player_slot);
if(stat != EnumRefabPlacement.UNCHANGED) { player_inventory_changed = true; changed = true; }
final ItemStack reference_stack = player.inventory.getStackInSlot(player_slot).copy();
if((!reference_stack.isEmpty()) && (distribute_stack(player.inventory, player_slot) != PlacementResult.UNCHANGED)) {
player_inventory_changed = true;
changed = true;
if(nbt.contains("move-all")) {
for(int i=0; i < player.inventory.getSizeInventory(); ++i) {
final ItemStack stack = player.inventory.getStackInSlot(i);
if(!reference_stack.isItemEqual(stack)) continue;
if(distribute_stack(player.inventory, i) == PlacementResult.UNCHANGED) break; // grid is full
}
}
}
}
} break;
case BGui.ACTION_MOVE_ALL_STACKS: {
final int container_slot_id = nbt.getInt("containerslot");
if((container_slot_id < 1) || (container_slot_id > 53)) {
break; // out of range
} else if(container_slot_id < 10) {
// from crafting grid to player inventory, we clear the grid here as this is most likely
// what is wanted in the end. Saves clicking the other grid stacks.
if(clear_grid_to_player(player)) { changed = true; player_inventory_changed = true; }
if(clear_grid_to_storage(player)) changed = true;
break;
}
IInventory from_inventory;
SlotRange[] to_ranges;
int from_slot;
if(container_slot_id >= 46) {
// from storage to player inventory
from_inventory = inventory_;
from_slot = container_slot_id - 46 + STORAGE_SLOTS_BEGIN;
to_ranges = new SlotRange[] {new SlotRange(player.inventory, 9, 36), new SlotRange(player.inventory, 0, 9)};
} else {
// from player to storage (otherwise ACTION_PLACE_SHIFTCLICKED_STACK would have been used)
from_inventory = player.inventory;
from_slot = (container_slot_id >= 37) ? (container_slot_id-37) : (container_slot_id-10+9);
to_ranges = new SlotRange[] {new SlotRange(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)};
}
final ItemStack reference_stack = from_inventory.getStackInSlot(from_slot).copy();
if(!reference_stack.isEmpty()) {
boolean abort = false;
for(int i=0; (i < from_inventory.getSizeInventory()) && (!abort); ++i) {
final ItemStack stack = from_inventory.getStackInSlot(i);
if(!reference_stack.isItemEqual(stack)) continue;
ItemStack remaining = from_inventory.getStackInSlot(i);
for(SlotRange range:to_ranges) {
remaining = move_stack_to_inventory(remaining, range, false, 0);
if(!remaining.isEmpty()) {
abort = true; // no space left
break;
} else {
changed = player_inventory_changed = true;
}
}
from_inventory.setInventorySlotContents(i, remaining);
}
}
} break;
case BGui.BUTTON_NEXT_COLLISION_RECIPE: {
select_next_collision_recipe(inventory_);
} break;
case BGui.ACTION_DECREASE_CRAFTING_STACKS: {
changed = player_inventory_changed = decrease_grid_stacks(new SlotRange[]{
new SlotRange(player.inventory, 9, 36),
new SlotRange(player.inventory, 0, 9),
new SlotRange(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)
}, MathHelper.clamp(nbt.getInt("limit"), 1, 8));
} break;
case BGui.ACTION_INCREASE_CRAFTING_STACKS: {
changed = player_inventory_changed = increase_grid_stacks(new SlotRange[]{
new SlotRange(player.inventory, 9, 36),
new SlotRange(player.inventory, 0, 9),
new SlotRange(inventory_, STORAGE_SLOTS_BEGIN, STORAGE_SLOTS_BEGIN+NUM_OF_STORAGE_SLOTS)
}, MathHelper.clamp(nbt.getInt("limit"), 1, 8));
} break;
}
}
if(changed) inventory_.markDirty();
@ -994,6 +1129,9 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
protected static final String BUTTON_NEXT_COLLISION_RECIPE = "next-recipe";
protected static final String ACTION_PLACE_CURRENT_HISTORY_SEL = "place-refab";
protected static final String ACTION_PLACE_SHIFTCLICKED_STACK = "place-stack";
protected static final String ACTION_MOVE_ALL_STACKS = "move-stacks";
protected static final String ACTION_INCREASE_CRAFTING_STACKS = "inc-crafting-stacks";
protected static final String ACTION_DECREASE_CRAFTING_STACKS = "dec-crafting-stacks";
protected static final ResourceLocation BACKGROUND = new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/treated_wood_crafting_table.png");
protected final PlayerEntity player;
protected final ArrayList<Button> buttons = new ArrayList<Button>();
@ -1138,29 +1276,74 @@ public class BlockDecorCraftingTable extends BlockDecorDirected.WaterLoggable
if(place_refab && (!with_assist_direct_history_refab)) on_history_item_placement(); // place after crafting -> confirmation first
return;
}
if((type == ClickType.QUICK_MOVE) && (slotId > 9) && (slot.getHasStack())) { // container slots 0..9 are crafting output and grid
if((type == ClickType.QUICK_MOVE) && (slotId > 0) && (slot.getHasStack())) { // container slots 0 is crafting output
if(with_assist) {
List<ItemStack> history = getContainer().history().current();
boolean palce_in_crafting_grid = (!history.isEmpty());
if(!palce_in_crafting_grid) {
for(int i = 0; i < 9; ++i) {
if(!(getContainer().getSlot(i).getStack().isEmpty())) {
palce_in_crafting_grid = true;
break;
boolean palce_in_crafting_grid = false;
if(slotId > 9) { // container slots 1..9 are crafting grid
palce_in_crafting_grid = (!history.isEmpty());
if(!palce_in_crafting_grid) {
for(int i = 0; i < 9; ++i) {
if(!(getContainer().getSlot(i).getStack().isEmpty())) {
palce_in_crafting_grid = true;
break;
}
}
}
}
if(palce_in_crafting_grid) {
// Explicit grid placement.
CompoundNBT nbt = new CompoundNBT();
nbt.putInt("containerslot", slotId);
if(ModAuxiliaries.isCtrlDown()) nbt.putBoolean("move-all", true);
action(ACTION_PLACE_SHIFTCLICKED_STACK, nbt);
return;
} else if(ModAuxiliaries.isCtrlDown()) {
// Move all same items from the inventory of the clicked slot
// (or the crafting grid) to the corresponding target inventory.
CompoundNBT nbt = new CompoundNBT();
nbt.putInt("containerslot", slotId);
action(ACTION_MOVE_ALL_STACKS, nbt);
return;
} else {
// Let the normal slot click handle that.
}
}
}
super.handleMouseClick(slot, slotId, mouseButton, type);
}
@Override
public boolean mouseScrolled(double mouseX, double mouseY, double wheel_inc)
{
final Slot resultSlot = this.getSlotUnderMouse();
if((!with_crafting_slot_mouse_scrolling) || (!(resultSlot instanceof CraftingResultSlot))) {
return this.getEventListenerForPos(mouseX, mouseY).filter((evl) -> {
return evl.mouseScrolled(mouseX, mouseY, wheel_inc);
}).isPresent();
}
int count = resultSlot.getStack().getCount();
int limit = (ModAuxiliaries.isShiftDown() ? 2 : 1) * (ModAuxiliaries.isCtrlDown() ? 4 : 1);
if(wheel_inc > 0.1) {
if(count > 0) {
if((count < resultSlot.getStack().getMaxStackSize()) && (count < resultSlot.getSlotStackLimit())) {
CompoundNBT nbt = new CompoundNBT();
if(limit > 1) nbt.putInt("limit", limit);
action(ACTION_INCREASE_CRAFTING_STACKS, nbt);
}
} else if(!getContainer().history().current().isEmpty()) {
action(ACTION_PLACE_CURRENT_HISTORY_SEL);
}
} else if(wheel_inc < -0.1) {
if(count > 0) {
CompoundNBT nbt = new CompoundNBT();
if(limit > 1) nbt.putInt("limit", limit);
action(ACTION_DECREASE_CRAFTING_STACKS, nbt);
}
}
return true;
}
private void on_history_item_placement()
{
if((getContainer().history().current().isEmpty())) return;

View file

@ -26,6 +26,8 @@ import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import javax.annotation.Nullable;
@ -62,7 +64,7 @@ public class BlockDecorSolarPanel extends BlockDecor
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity
public static class BTileEntity extends TileEntity implements ITickableTileEntity, ICapabilityProvider, IEnergyStorage
{
public static final int DEFAULT_PEAK_POWER = 45;
public static final int TICK_INTERVAL = 8;
@ -94,6 +96,51 @@ public class BlockDecorSolarPanel extends BlockDecor
protected void writenbt(CompoundNBT nbt, boolean update_packet)
{ nbt.putInt("energy", accumulated_power_); }
// IEnergyStorage --------------------------------------------------------------------------
@Override
public boolean canExtract()
{ return true; }
@Override
public boolean canReceive()
{ return false; }
@Override
public int getMaxEnergyStored()
{ return max_power_storage_; }
@Override
public int getEnergyStored()
{ return accumulated_power_; }
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{
int p = Math.min(accumulated_power_, maxExtract);
if(!simulate) accumulated_power_ -= p;
return p;
}
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{ return 0; }
// ICapabilityProvider ---------------------------------------------------------------------
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> (IEnergyStorage)this);
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability== CapabilityEnergy.ENERGY) {
return energy_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// TileEntity ------------------------------------------------------------------------------
@Override

View file

@ -192,6 +192,9 @@ public class BlockDecorTreeCutter extends BlockDecorDirectedHorizontal
--active_timer_;
}
boolean active = (active_timer_ > 0);
if(requires_power && !active) {
proc_time_elapsed_ = Math.max(0, proc_time_elapsed_ - 2*TICK_INTERVAL);
}
if(proc_time_elapsed_ >= cutting_time_needed) {
proc_time_elapsed_ = 0;
TreeCutting.chopTree(world, tree_state, tree_pos, 512, false);

View file

@ -82,7 +82,7 @@ public class ModLootTables extends LootTableProvider
private LootTable.Builder defaultBlockDrops(String rl_path, Block block)
{
ItemLootEntry.Builder iltb = ItemLootEntry.builder(block);
iltb.acceptFunction(CopyName.func_215893_a(Source.BLOCK_ENTITY));
iltb.acceptFunction(CopyName.builder(Source.BLOCK_ENTITY));
if(block.hasTileEntity(block.getDefaultState())) {
iltb.acceptFunction(CopyNbt.func_215881_a(CopyNbt.Source.BLOCK_ENTITY));
}

View file

@ -24,6 +24,7 @@ import net.minecraft.util.math.AxisAlignedBB;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.apache.logging.log4j.Logger;
import org.lwjgl.glfw.GLFW;
import javax.annotation.Nullable;
import java.io.BufferedReader;
@ -35,9 +36,12 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class ModAuxiliaries
{
public static final String MODID = ModEngineersDecor.MODID;
public static final Logger LOGGER = ModEngineersDecor.logger();
public static final ModEngineersDecor.ISidedProxy PROXY = ModEngineersDecor.proxy;
// -------------------------------------------------------------------------------------------------------------------
// Sideness, system/environment, tagging interfaces
@ -51,18 +55,32 @@ public class ModAuxiliaries
public static final boolean isDevelopmentMode()
{ return SharedConstants.developmentMode; }
@OnlyIn(Dist.CLIENT)
public static final boolean isShiftDown()
{
return (InputMappings.isKeyDown(PROXY.mc().func_228018_at_()/*getMainWindow()*/.getHandle(), GLFW.GLFW_KEY_LEFT_SHIFT) ||
InputMappings.isKeyDown(PROXY.mc().func_228018_at_()/*getMainWindow()*/.getHandle(), GLFW.GLFW_KEY_RIGHT_SHIFT));
}
@OnlyIn(Dist.CLIENT)
public static final boolean isCtrlDown()
{
return (InputMappings.isKeyDown(PROXY.mc().func_228018_at_()/*getMainWindow()*/.getHandle(), GLFW.GLFW_KEY_LEFT_CONTROL) ||
InputMappings.isKeyDown(PROXY.mc().func_228018_at_()/*getMainWindow()*/.getHandle(), GLFW.GLFW_KEY_RIGHT_CONTROL));
}
// -------------------------------------------------------------------------------------------------------------------
// Logging
// -------------------------------------------------------------------------------------------------------------------
public static final void logInfo(final String msg)
{ ModEngineersDecor.logger().info(msg); }
{ LOGGER.info(msg); }
public static final void logWarn(final String msg)
{ ModEngineersDecor.logger().warn(msg); }
{ LOGGER.warn(msg); }
public static final void logError(final String msg)
{ ModEngineersDecor.logger().error(msg); }
{ LOGGER.error(msg); }
// -------------------------------------------------------------------------------------------------------------------
// Block handling
@ -100,12 +118,12 @@ public class ModAuxiliaries
// -------------------------------------------------------------------------------------------------------------------
/**
* Text localisation wrapper, implicitly prepends `ModEngineersDecor.MODID` to the
* Text localisation wrapper, implicitly prepends `MODID` to the
* translation keys. Forces formatting argument, nullable if no special formatting shall be applied..
*/
public static TranslationTextComponent localizable(String modtrkey, @Nullable TextFormatting color, Object... args)
{
TranslationTextComponent tr = new TranslationTextComponent(ModEngineersDecor.MODID+"."+modtrkey, args);
TranslationTextComponent tr = new TranslationTextComponent(MODID+"."+modtrkey, args);
if(color!=null) tr.getStyle().setColor(color);
return tr;
}
@ -114,7 +132,7 @@ public class ModAuxiliaries
{ return localizable(modtrkey, null); }
public static TranslationTextComponent localizable_block_key(String blocksubkey)
{ return new TranslationTextComponent("block."+ModEngineersDecor.MODID+"."+blocksubkey); }
{ return new TranslationTextComponent("block."+MODID+"."+blocksubkey); }
@OnlyIn(Dist.CLIENT)
public static String localize(String translationKey, Object... args)
@ -163,21 +181,11 @@ public class ModAuxiliaries
{
@OnlyIn(Dist.CLIENT)
public static boolean extendedTipCondition()
{
return (
InputMappings.isKeyDown(ModEngineersDecor.proxy.mc().func_228018_at_()/*getMainWindow()*/.getHandle(), GLFW.GLFW_KEY_LEFT_SHIFT) ||
InputMappings.isKeyDown(ModEngineersDecor.proxy.mc().func_228018_at_()/*getMainWindow()*/.getHandle(), GLFW.GLFW_KEY_RIGHT_SHIFT)
);
}
{ return isShiftDown(); }
@OnlyIn(Dist.CLIENT)
public static boolean helpCondition()
{
return extendedTipCondition() && (
InputMappings.isKeyDown(ModEngineersDecor.proxy.mc().func_228018_at_()/*getMainWindow()*/.getHandle(), GLFW.GLFW_KEY_LEFT_CONTROL) ||
InputMappings.isKeyDown(ModEngineersDecor.proxy.mc().func_228018_at_()/*getMainWindow()*/.getHandle(), GLFW.GLFW_KEY_RIGHT_CONTROL)
);
}
{ return isShiftDown() && isCtrlDown(); }
/**
* Adds an extended tooltip or help tooltip depending on the key states of CTRL and SHIFT.
@ -206,8 +214,8 @@ public class ModAuxiliaries
return true;
} else if(addAdvancedTooltipHints) {
String s = "";
if(tip_available) s += localize(ModEngineersDecor.MODID + ".tooltip.hint.extended") + (help_available ? " " : "");
if(help_available) s += localize(ModEngineersDecor.MODID + ".tooltip.hint.help");
if(tip_available) s += localize(MODID + ".tooltip.hint.extended") + (help_available ? " " : "");
if(help_available) s += localize(MODID + ".tooltip.hint.help");
tooltip.add(new StringTextComponent(s));
}
return false;
@ -250,7 +258,7 @@ public class ModAuxiliaries
{
try {
// Done during construction to have an exact version in case of a crash while registering.
String version = ModAuxiliaries.loadResourceText("/.gitversion").trim();
String version = ModAuxiliaries.loadResourceText("/.gitversion-" + MODID).trim();
logInfo(mod_name+((version.isEmpty())?(" (dev build)"):(" GIT id #"+version)) + ".");
} catch(Throwable e) {
// (void)e; well, then not. Priority is not to get unneeded crashes because of version logging.

View file

@ -143,6 +143,7 @@ public class ModConfig
public final ForgeConfigSpec.DoubleValue chair_mob_sitting_probability_percent;
public final ForgeConfigSpec.DoubleValue chair_mob_standup_probability_percent;
public final ForgeConfigSpec.BooleanValue with_crafting_quickmove_buttons;
public final ForgeConfigSpec.BooleanValue without_crafting_mouse_scrolling;
public final ForgeConfigSpec.IntValue pipevalve_max_flowrate;
public final ForgeConfigSpec.IntValue pipevalve_redstone_gain;
public final ForgeConfigSpec.IntValue block_breaker_power_consumption;
@ -389,6 +390,10 @@ public class ModConfig
.comment("Enables small quick-move arrows from/to player/block storage. " +
"Makes the UI a bit too busy, therefore disabled by default.")
.define("with_crafting_quickmove_buttons", false);
without_crafting_mouse_scrolling = builder
.translation(ModEngineersDecor.MODID + ".config.without_crafting_mouse_scrolling")
.comment("Disables increasing/decreasing the crafting grid items by scrolling over the crafting result slot.")
.define("without_crafting_mouse_scrolling", false);
pipevalve_max_flowrate = builder
.translation(ModEngineersDecor.MODID + ".config.pipevalve_max_flowrate")
.comment("Defines how many millibuckets can be transferred (per tick) through the valves. " +
@ -598,7 +603,7 @@ public class ModConfig
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());
BlockDecorCraftingTable.on_config(COMMON.without_crafting_table_history.get(), false, COMMON.with_crafting_quickmove_buttons.get());
BlockDecorCraftingTable.on_config(COMMON.without_crafting_table_history.get(), false, COMMON.with_crafting_quickmove_buttons.get(), COMMON.without_crafting_mouse_scrolling.get());
BlockDecorPipeValve.on_config(COMMON.pipevalve_max_flowrate.get(), COMMON.pipevalve_redstone_gain.get());
BlockDecorFurnaceElectrical.BTileEntity.on_config(COMMON.e_furnace_speed_percent.get(), COMMON.e_furnace_power_consumption.get(), COMMON.e_furnace_automatic_pulling.get());
BlockDecorSolarPanel.BTileEntity.on_config(COMMON.small_solar_panel_peak_production.get());

View file

@ -204,16 +204,14 @@ public class Networking
DEFAULT_CHANNEL.sendTo(new PacketContainerSyncServerToClient(container.windowId, nbt), ((ServerPlayerEntity)player).connection.netManager, NetworkDirection.PLAY_TO_CLIENT);
}
// Container listners are private, and add/remove listener overriding seems not too nice, as
// removeListner is client only???
//public static <C extends Container & INetworkSynchronisableContainer> void sendToListeners(C container, CompoundNBT nbt)
//{
// for(IContainerListener listener: container.getListeners()) {
// if(!(listener instanceof ServerPlayerEntity)) continue;
// DEFAULT_CHANNEL.sendTo(new PacketContainerSyncServerToClient(container.windowId, nbt), ((ServerPlayerEntity)listener).connection.netManager, NetworkDirection.PLAY_TO_CLIENT);
// }
//}
public static <C extends Container & INetworkSynchronisableContainer>
void sendToListeners(World world, C container, CompoundNBT nbt)
{
for(PlayerEntity player: world.getPlayers()) {
if(player.openContainer.windowId != container.windowId) continue;
sendToPlayer(player, container.windowId, nbt);
}
}
public PacketContainerSyncServerToClient()
{}

View file

@ -1,220 +1,220 @@
{
"language": "English",
"language.code": "en_us",
"language.region": "United States",
"itemGroup.tabengineersdecor": "Engineer's Decor",
"engineersdecor.config.title": "Engineer's Decor Config",
"engineersdecor.tooltip.hint.extended": "§6[§9SHIFT§r More Info§6]§r",
"engineersdecor.tooltip.hint.help": "§6[§9CTRL-SHIFT§r Help§6]§r",
"engineersdecor.tooltip.slabpickup.help": "§rFast pickup by left-clicking while looking up/down and holding this slab.",
"engineersdecor.tooltip.requires_rf_power": "Requires RF power.",
"engineersdecor.tooltip.massive_speed_boost_with_rf_power": "Apply RF power to magnificently increase the speed.",
"engineersdecor.config.pattern_excludes": "Pattern excludes",
"engineersdecor.config.pattern_includes": "Pattern includes",
"engineersdecor.config.without_clinker_bricks": "Without clinker bricks",
"engineersdecor.config.without_slag_bricks": "Without slag bricks",
"engineersdecor.config.without_rebar_concrete": "Without rebar concrete",
"engineersdecor.config.without_walls": "Without walls",
"engineersdecor.config.without_stairs": "Without stairs",
"engineersdecor.config.without_ie_concrete_wall": "Without concrete wall",
"engineersdecor.config.without_panzer_glass": "Without panzer glass",
"engineersdecor.config.without_crafting_table": "Without crafting table",
"engineersdecor.config.without_lab_furnace": "Without lab furnace",
"engineersdecor.config.without_electrical_furnace": "Without electrical furnace",
"engineersdecor.config.without_treated_wood_furniture": "Without tr. wood furniture",
"engineersdecor.config.without_windows": "Without windows",
"engineersdecor.config.without_light_sources": "Without lights",
"engineersdecor.config.without_ladders": "Without ladders",
"engineersdecor.config.without_chair_sitting": "Without chair sitting",
"engineersdecor.config.without_mob_chair_sitting": "Without chair mob sitting",
"engineersdecor.config.without_ladder_speed_boost": "Without ladder speed boost",
"engineersdecor.config.without_crafting_table_history": "Without crafting table history",
"engineersdecor.config.without_valves": "Without valves",
"engineersdecor.config.without_passive_fluid_accumulator": "Without fluid accumulator",
"engineersdecor.config.without_waste_incinerator": "Without waste incinerator",
"engineersdecor.config.without_sign_plates": "Without signs",
"engineersdecor.config.without_factory_dropper": "Without factory dropper",
"engineersdecor.config.without_slabs": "Without slabs",
"engineersdecor.config.without_halfslabs": "Without slab slices",
"engineersdecor.config.without_direct_slab_pickup": "Without slab pickup",
"engineersdecor.config.without_poles": "Without poles",
"engineersdecor.config.without_hsupports": "Without h. supports",
"engineersdecor.config.without_tooltips": "Without tooltips",
"engineersdecor.config.without_recipes": "Without recipes",
"engineersdecor.config.furnace_smelting_speed_percent": "Furnace: Smelting speed %",
"engineersdecor.config.furnace_fuel_efficiency_percent": "Furnace: Fuel efficiency %",
"engineersdecor.config.furnace_boost_energy_consumption": "Furnace: Boost energy",
"engineersdecor.config.chair_mob_sitting_probability_percent": "Chairs: Sitting chance %",
"engineersdecor.config.chair_mob_standup_probability_percent": "\"Chairs: Stand up chance %\"",
"engineersdecor.config.with_crafting_quickmove_buttons": "Crafting table: Move buttons",
"engineersdecor.config.pipevalve_max_flowrate": "Valves: Max flow rate",
"engineersdecor.config.pipevalve_redstone_gain": "Valves: Redstone slope",
"engineersdecor.config.e_furnace_speed_percent": "E-furnace: Smelting speed %",
"engineersdecor.config.e_furnace_power_consumption": "E-furnace: Power consumption",
"block.engineersdecor.clinker_brick_block": "Clinker Brick Block",
"block.engineersdecor.clinker_brick_block.help": "§6A brick block with position dependent texture variations.§r\nLooks slightly darker and more color intensive than the vanilla brick block.",
"block.engineersdecor.clinker_brick_stained_block": "Stained Clinker Brick Block",
"block.engineersdecor.clinker_brick_stained_block.help": "§6A brick block with position dependent texture variations.§r\nLooks slightly darker and more color intensive than the vanilla brick block. Has more visible traces of grime or stain.",
"block.engineersdecor.slag_brick_block": "Slag Brick Block",
"block.engineersdecor.slag_brick_block.help": "§6A gray-brown brick block with position dependent texture variations.",
"block.engineersdecor.rebar_concrete": "Rebar Concrete Block",
"block.engineersdecor.rebar_concrete.help": "§6Steel reinforced concrete block.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.gas_concrete": "Gas Concrete Block",
"block.engineersdecor.gas_concrete.help": "§6Low hardness, high production yield concrete.§r Easy to break decorative concrete block.",
"block.engineersdecor.panzerglass_block": "Panzer Glass Block",
"block.engineersdecor.panzerglass_block.help": "§6Reinforced glass block.§r Expensive, explosion-proof. Dark gray tint, faint structural lines visible, multi texture for seemless look.",
"block.engineersdecor.rebar_concrete_tile": "Rebar Concrete Tile",
"block.engineersdecor.rebar_concrete_tile.help": "§6Steel reinforced concrete tile.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.clinker_brick_slab": "Clinker Brick Slab",
"block.engineersdecor.clinker_brick_slab.help": "§6Slab made from a Clinker Block.§r\nLooks slightly darker and more color intensive than the vanilla brick.",
"block.engineersdecor.clinker_brick_stained_slab": "Stained Clinker Brick Slab",
"block.engineersdecor.clinker_brick_stained_slab.help": "§6Slab made from a Stained Clinker Block.",
"block.engineersdecor.slag_brick_slab": "Slag Brick Slab",
"block.engineersdecor.slag_brick_slab.help": "§6A gray-brown brick slab.",
"block.engineersdecor.rebar_concrete_slab": "Rebar Concrete Slab",
"block.engineersdecor.rebar_concrete_slab.help": "§6Steel reinforced concrete slab.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.rebar_concrete_tile_slab": "Rebar Concrete Tile Slab",
"block.engineersdecor.rebar_concrete_tile_slab.help": "§6Steel reinforced concrete tile slab.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.gas_concrete_slab": "Gas Concrete Slab",
"block.engineersdecor.gas_concrete_slab.help": "§6Low hardness concrete slab.§r Easy to break decorative concrete.",
"block.engineersdecor.panzerglass_slab": "Panzer Glass Slab",
"block.engineersdecor.panzerglass_slab.help": "§6Reinforced glass slab.§r Expensive, explosion-proof. Dark gray tint, faint structural lines visible.",
"block.engineersdecor.treated_wood_floor": "Treated Wood Floor",
"block.engineersdecor.treated_wood_floor.help": "§6Decorative floor tiles with texture variations.§r",
"block.engineersdecor.rebar_concrete_wall": "Rebar Concrete Wall",
"block.engineersdecor.rebar_concrete_wall.help": "§6Steel reinforced concrete wall.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.concrete_wall": "Concrete Wall",
"block.engineersdecor.concrete_wall.help": "§6Wall made of solid concrete.",
"block.engineersdecor.gas_concrete_wall": "Gas Concrete Wall",
"block.engineersdecor.gas_concrete_wall.help": "§6Low hardness concrete wall.§r Easy to break decorative concrete.",
"block.engineersdecor.clinker_brick_wall": "Clinker Brick Wall",
"block.engineersdecor.clinker_brick_wall.help": "§6Simplistic Clinker Brick Wall.",
"block.engineersdecor.slag_brick_wall": "Slag Brick Wall",
"block.engineersdecor.slag_brick_wall.help": "§6Simplistic Slag Brick Wall.",
"block.engineersdecor.metal_rung_ladder": "Metal Rung Ladder",
"block.engineersdecor.metal_rung_ladder.help": "§6Typical industrial wall ladder, consisting of horizontal metal rod rungs.§r Look up/down to climb faster.",
"block.engineersdecor.metal_rung_steps": "Staggered Metal Steps",
"block.engineersdecor.metal_rung_steps.help": "§6Staggered rod rungs affixed to a wall, allowing to climb up, fall down, and so on.§r Look up/down to climb faster.",
"block.engineersdecor.treated_wood_ladder": "Treated Wood Ladder",
"block.engineersdecor.treated_wood_ladder.help": "§6Weather-proof wooden ladder.§r Look up/down to climb faster.",
"block.engineersdecor.clinker_brick_stairs": "Clinker Brick Stairs",
"block.engineersdecor.clinker_brick_stairs.help": "§6Looks slightly darker and more color intensive than the vanilla brick block.",
"block.engineersdecor.clinker_brick_stained_stairs": "Stained Clinker Brick Stairs",
"block.engineersdecor.clinker_brick_stained_stairs.help": "§6Looks slightly darker and more color intensive than the vanilla brick block. Has more visible traces of grime or stain.",
"block.engineersdecor.slag_brick_stairs": "Clinker Brick Stairs",
"block.engineersdecor.slag_brick_stairs.help": "§6Looks slightly darker and more color intensive than the vanilla brick block.",
"block.engineersdecor.rebar_concrete_stairs": "Rebar Concrete Stairs",
"block.engineersdecor.rebar_concrete_stairs.help": "§6Steel reinforced concrete stairs.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.rebar_concrete_tile_stairs": "Rebar Concrete Tile Stairs",
"block.engineersdecor.rebar_concrete_tile_stairs.help": "§6Steel reinforced concrete tile stairs.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.gas_concrete_stairs": "Gas Concrete Stairs",
"block.engineersdecor.gas_concrete_stairs.help": "§6Low hardness concrete stairs.§r Easy to break decorative concrete.",
"block.engineersdecor.treated_wood_pole": "Straight Treated Wood Pole",
"block.engineersdecor.treated_wood_pole.help": "§6Straight pole fragment with a diameter of a wire relay.§r\n Can be useful as alternative to the wire posts if special lengths are needed, or as support for structures.",
"block.engineersdecor.treated_wood_pole_head": "Straight Treated Wood Pole Head/Foot",
"block.engineersdecor.treated_wood_pole_head.help": "§6Wooden part fitting as foot or head of straight poles.",
"block.engineersdecor.treated_wood_pole_support": "Straight Treated Wood Pole Support",
"block.engineersdecor.treated_wood_pole_support.help": "§6Heavy duty wooden support part fitting as foot or head of straight poles.",
"block.engineersdecor.thick_steel_pole": "Straight Thick Steel Pole",
"block.engineersdecor.thick_steel_pole.help": "§6Straight hollow pole fragment (6x6x16) for structural support purposes.",
"block.engineersdecor.thin_steel_pole": "Straight Thin Steel Pole",
"block.engineersdecor.thin_steel_pole.help": "§6Straight hollow pole fragment (4x4x16) for structural support purposes.",
"block.engineersdecor.thin_steel_pole_head": "Straight Thin Steel Pole head/foot",
"block.engineersdecor.thin_steel_pole_head.help": "§6Steel part fitting as foot or head of the thin steel pole (4x4x16).",
"block.engineersdecor.thick_steel_pole_head": "Straight Thick Steel Pole Head/Foot",
"block.engineersdecor.thick_steel_pole_head.help": "§6Steel part fitting as foot or head of the thick steel pole (6x6x16).",
"block.engineersdecor.steel_double_t_support": "Steel Double T Support",
"block.engineersdecor.steel_double_t_support.help": "§6Horizontal ceiling support beam fragment.",
"block.engineersdecor.treated_wood_table": "Treated Wood Table",
"block.engineersdecor.treated_wood_table.help": "§6Robust four-legged wood table.§r Indoor and outdoor use.",
"block.engineersdecor.steel_table": "Steel Table",
"block.engineersdecor.steel_table.help": "§6Robust four-legged steel table.",
"block.engineersdecor.steel_floor_grating": "Steel Floor Grating",
"block.engineersdecor.steel_floor_grating.help": "§6Decorative steel floor covering.§r Top aligned. Items fall through.",
"block.engineersdecor.treated_wood_stool": "Treated Wood Stool",
"block.engineersdecor.treated_wood_stool.help": "§6Robust Wood Stool.§r Indoor and outdoor use.",
"block.engineersdecor.treated_wood_crafting_table": "Treated Wood Crafting Table",
"block.engineersdecor.treated_wood_crafting_table.help": "§6Robust and weather-proof.§r Eight storage slots, keeps inventory, no vanilla recipe book.\n Click up/down arrow buttons for crafting history selection, output slot for item placement, X-button to clear crafting grid and history. Shift-click stack: player-to-storage stack transfer when crafting grid empty, otherwise player-to-grid stack transfer. Automatically distributes the clicked stack.",
"block.engineersdecor.treated_wood_side_table": "Treated Wood Side Table",
"block.engineersdecor.treated_wood_side_table.help": "§6Needed after the work's done.",
"block.engineersdecor.iron_inset_light": "Inset Light",
"block.engineersdecor.iron_inset_light.help": "§6Small glowstone light source, sunk into the floor, ceiling or wall.§r\n Useful to light up places where electrical light installations are problematic.",
"block.engineersdecor.iron_floor_edge_light": "Inset Floor Edge Light",
"block.engineersdecor.iron_floor_edge_light.help": "§6Small glowstone light source, placed at the edge of a floor block.§r\n Useful to light up places where electrical light installations are problematic.",
"block.engineersdecor.treated_wood_window": "Treated Wood Window",
"block.engineersdecor.treated_wood_window.help": "§6Wood framed triple glazed window. Well insulating.§r Does not connect to adjacent blocks like glass panes.",
"block.engineersdecor.treated_wood_windowsill": "Treated Wood Window Sill",
"block.engineersdecor.treated_wood_windowsill.help": "§6Simple window decoration.",
"block.engineersdecor.treated_wood_broad_windowsill": "Broad Treated Wood Window Sill",
"block.engineersdecor.treated_wood_broad_windowsill.help": "§6Simple window decoration.",
"block.engineersdecor.steel_framed_window": "Steel Framed Window",
"block.engineersdecor.steel_framed_window.help": "§6Steel framed triple glazed window. Well insulating. §r Does not connect to adjacent blocks like glass panes.",
"block.engineersdecor.steel_mesh_fence": "Steel Mesh Fence",
"block.engineersdecor.steel_mesh_fence.help": "§6Industrial style fence.§r\nDoes not connect do regular fences.",
"block.engineersdecor.small_lab_furnace": "Small Laboratory Furnace",
"block.engineersdecor.small_lab_furnace.help": "§6Small metal cased lab kiln.§r Solid fuel consuming, updraught. Slightly hotter and better isolated than a cobblestone furnace, therefore more efficient. Two auxiliary slots e.g. for storage. Two stack internal hopper fifos for input, output, and fuel. Place an external heater into a aux slot and connect power for electrical smelting speed boost.",
"block.engineersdecor.small_electrical_furnace": "Small Electrical Furnace",
"block.engineersdecor.small_electrical_furnace.help": "§6Small metal cased pass-through furnace.§r Automatically draws items from the input side and puts items into the inventory at the output side. Items can be inserted or drawn from all sides using hoppers. Implicitly bypasses items that cannot be smelted or cooked to the output. Slightly more energy efficient and faster than a heated cobblestone furnace. Fifos and feeders transfer whole stacks. Feeders require a bit of power.",
"block.engineersdecor.small_waste_incinerator": "Small Waste Incinerator",
"block.engineersdecor.small_waste_incinerator.help": "§6Trash with internal fifo slots.§r Items can be inserted on all sides, and are kept until there is no space left in the fifo. After that the oldest stack will be incinerated. Apply electrical RF/FE power to increase the processing speed. Keeps its inventory when being relocated.",
"block.engineersdecor.straight_pipe_valve": "Fluid Pipe Check Valve",
"block.engineersdecor.straight_pipe_valve.help": "§6Straight fluid pipe fragment.§r Conducts fluids only in one direction. Does not connect to the sides. Reduces flow rate. Sneak to place in reverse direction.",
"block.engineersdecor.straight_pipe_valve_redstone": "Redstone Controlled Fluid Valve",
"block.engineersdecor.straight_pipe_valve_redstone.help": "§6Straight fluid pipe fragment.§r Conducts fluids only in one direction. Does not connect to the sides. Sneak to place in reverse direction. Blocks if not redstone powered.",
"block.engineersdecor.straight_pipe_valve_redstone_analog": "Redstone Analog Fluid Valve",
"block.engineersdecor.straight_pipe_valve_redstone_analog.help": "§6Straight fluid pipe fragment.§r Conducts fluids only in one direction. Does not connect to the sides. Sneak to place in reverse direction. Blocks if not redstone powered, reduces the flow rate linear from power 1 to 14, opens to maximum possible valve flow rate for power 15.",
"block.engineersdecor.passive_fluid_accumulator": "Passive Fluid Accumulator",
"block.engineersdecor.passive_fluid_accumulator.help": "§6Vacuum suction based fluid collector.§r Has one output, all other sides are input. Drains fluids from adjacent tanks when being drained from the output port by a pump.",
"block.engineersdecor.small_fluid_funnel": "Small Fluid Collection Funnel",
"block.engineersdecor.small_fluid_funnel.help": "§6Collects fluids above it.§r Has an internal tank with three buckets capacity. Traces flowing fluids to nearby source blocks. The fluid can be obtained with fluid transfer systems or a bucket. Fills only tanks below (gravity transfer). Compatible with vanilla infinite-water-source creation.",
"block.engineersdecor.factory_dropper": "Factory Dropper",
"block.engineersdecor.factory_dropper.help": "§6Dropper suitable for advanced factory automation.§r Has twelve round-robin selected slots. Drop force, angle, stack size, and cool-down delay adjustable using sliders in the GUI. Three stack compare slots (below the inventory slots) with logical AND or OR can be used as internal trigger source. The internal trigger can be AND'ed or OR'ed with the external redstone signal trigger. Trigger simulation buttons for testing. Pre-opens shutter door when internal trigger conditions are met. Drops all matching stacks simultaneously. Simply click on all elements in the GUI to see how it works.",
"block.engineersdecor.factory_hopper": "Factory Hopper",
"block.engineersdecor.factory_hopper.help": "§6Hopper suitable for advanced factory automation.§r Can transfer half-stacks, max collection range 9x9.\n GUI Slider controls: Collection range (0 to 4), insertion delay (0.5s to 10s), insertion stack size (1 to 32).\n GUI Redstone controls: Not inverted / inverted (default), pulse mode / continuous mode (default).",
"block.engineersdecor.factory_placer": "Factory Block Placer",
"block.engineersdecor.factory_placer.help": "§6Allows placing blocks and planting crops or trees.§r\n GUI Redstone controls: Not inverted / inverted (default), pulse mode / continuous mode (default).\n Also supports spike planing from underneath the soil. Spits out items that it cannot place or plant.",
"block.engineersdecor.small_block_breaker": "Small Block Breaker",
"block.engineersdecor.small_block_breaker.help": "§6Breaks blocks in front of it.§r\n Can be disabled by applying a redstone signal. The time needed to destroy a block depends on the hardness of that block. ${!block_breaker_requires_power?engineersdecor.tooltip.massive_speed_boost_with_rf_power} ${block_breaker_requires_power?engineersdecor.tooltip.requires_rf_power}",
"block.engineersdecor.small_mineral_smelter": "Small Mineral Melting Furnace",
"block.engineersdecor.small_mineral_smelter.help": "§6High temperature, high insulation electrical stone melting furnace.§r\n Heats up mineral blocks to magma blocks, and finally to lava. Click with a mineral block (stone, cobble, etc) or use item insertion to place a block in the melter. Use bucket or fluid extraction to retrieve the lava. When cooling down lava, obsidian is generated. Remove the RF power or apply a redstone signal to disable the furnace. For automation, use a redstone comparator to see in which melting phase the mineral is a moment.",
"block.engineersdecor.small_solar_panel": "Small Solar Panel",
"block.engineersdecor.small_solar_panel.help": "§6Produces a small amount of power when exposed to sunlight.§r\n Useful for charging LF capacitors in remote systems with low consumption. The internal charge pump circuit accumulates and frequently transfers RF. Production depends on day time and the weather.",
"block.engineersdecor.small_tree_cutter": "Small Tree Cutter",
"block.engineersdecor.small_tree_cutter.help": "§6Chops grown trees in front of it.§r\n Does not collect the lumbers. Deactivate with a redstone signal. ${!tree_cuttter_requires_power?engineersdecor.tooltip.massive_speed_boost_with_rf_power} ${tree_cuttter_requires_power?engineersdecor.tooltip.requires_rf_power}",
"block.engineersdecor.small_milking_machine": "Small Milking Machine",
"block.engineersdecor.small_milking_machine.help": "§6Occasionally grooms and milks cows.§r\n Has an internal fluid tank. Does not feed the animals. Use buckets to retrieve the milk. Pulls/stores milk container items from/to inventories at the back or bottom (preferrs extracting from the back and inserting below, but can also put filled vessels back into the same inventory). Supports fluid output to tanks or pipes below (only if milk exists as fluid). Care that it's not too crowdy in the cow pen, only happy animals stroll by voluntarily.",
"block.engineersdecor.sign_decor": "Sign Plate (Engineer's decor)",
"block.engineersdecor.sign_decor.help": "§6This should not be craftable or visible in JEI. Used for creative tab and screenshots.",
"block.engineersdecor.sign_hotwire": "Sign \"Caution Hot Wire\"",
"block.engineersdecor.sign_hotwire.help": "§6Electrical hazard warning. Don't forget to place around HV, or you will have a nonconformity in the next audit.",
"block.engineersdecor.sign_mindstep": "Sign \"Mind The Step\"",
"block.engineersdecor.sign_mindstep.help": "§6Placable on walls (horizontally).",
"block.engineersdecor.sign_danger": "Sign \"Caution Really Dangerous There\"",
"block.engineersdecor.sign_danger.help": "§6General danger warning.",
"block.engineersdecor.sign_defense": "Sign \"Caution Defense System Ahead\"",
"block.engineersdecor.sign_defense.help": "§6Warning sign for turrets, Tesla Coils, and traps.",
"block.engineersdecor.sign_factoryarea": "Sign \"Factory Area\"",
"block.engineersdecor.sign_factoryarea.help": "§6Marker sign for buildings or areas where the really big machines are located.",
"block.engineersdecor.sign_exit": "Exit Sign",
"block.engineersdecor.sign_exit.help": "§6There's the door, please ...",
"block.engineersdecor.halfslab_rebar_concrete": "Rebar Concrete Slice",
"block.engineersdecor.halfslab_rebar_concrete.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_concrete": "Concrete Slice",
"block.engineersdecor.halfslab_concrete.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_gas_concrete": "Gas Concrete Slice",
"block.engineersdecor.halfslab_gas_concrete.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_treated_wood": "Treated Wood Slice",
"block.engineersdecor.halfslab_treated_wood.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_sheetmetal_iron": "Iron Sheet Metal Slice",
"block.engineersdecor.halfslab_sheetmetal_iron.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_sheetmetal_steel": "Steel Sheet Metal Slice",
"block.engineersdecor.halfslab_sheetmetal_steel.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_sheetmetal_copper": "Copper Sheet Metal Slice",
"block.engineersdecor.halfslab_sheetmetal_copper.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_sheetmetal_gold": "Gold Sheet Metal Slice",
"block.engineersdecor.halfslab_sheetmetal_gold.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_sheetmetal_aluminum": "Aluminum Sheet Metal Slice",
"block.engineersdecor.halfslab_sheetmetal_aluminum.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.testblock": "ED Test Block (do NOT use)",
"block.engineersdecor.testblock.help": "§6Uncraftable mod testing block with changing experimental functionality. DO NOT USE, may even cause a crash in the worst case!!"
"language": "English",
"language.code": "en_us",
"language.region": "United States",
"itemGroup.tabengineersdecor": "Engineer's Decor",
"engineersdecor.config.title": "Engineer's Decor Config",
"engineersdecor.tooltip.hint.extended": "§6[§9SHIFT§r More Info§6]§r",
"engineersdecor.tooltip.hint.help": "§6[§9CTRL-SHIFT§r Help§6]§r",
"engineersdecor.tooltip.slabpickup.help": "§rFast pickup by left-clicking while looking up/down and holding this slab.",
"engineersdecor.tooltip.requires_rf_power": "Requires RF power.",
"engineersdecor.tooltip.massive_speed_boost_with_rf_power": "Apply RF power to magnificently increase the speed.",
"engineersdecor.config.pattern_excludes": "Pattern excludes",
"engineersdecor.config.pattern_includes": "Pattern includes",
"engineersdecor.config.without_clinker_bricks": "Without clinker bricks",
"engineersdecor.config.without_slag_bricks": "Without slag bricks",
"engineersdecor.config.without_rebar_concrete": "Without rebar concrete",
"engineersdecor.config.without_walls": "Without walls",
"engineersdecor.config.without_stairs": "Without stairs",
"engineersdecor.config.without_ie_concrete_wall": "Without concrete wall",
"engineersdecor.config.without_panzer_glass": "Without panzer glass",
"engineersdecor.config.without_crafting_table": "Without crafting table",
"engineersdecor.config.without_lab_furnace": "Without lab furnace",
"engineersdecor.config.without_electrical_furnace": "Without electrical furnace",
"engineersdecor.config.without_treated_wood_furniture": "Without tr. wood furniture",
"engineersdecor.config.without_windows": "Without windows",
"engineersdecor.config.without_light_sources": "Without lights",
"engineersdecor.config.without_ladders": "Without ladders",
"engineersdecor.config.without_chair_sitting": "Without chair sitting",
"engineersdecor.config.without_mob_chair_sitting": "Without chair mob sitting",
"engineersdecor.config.without_ladder_speed_boost": "Without ladder speed boost",
"engineersdecor.config.without_crafting_table_history": "Without crafting table history",
"engineersdecor.config.without_valves": "Without valves",
"engineersdecor.config.without_passive_fluid_accumulator": "Without fluid accumulator",
"engineersdecor.config.without_waste_incinerator": "Without waste incinerator",
"engineersdecor.config.without_sign_plates": "Without signs",
"engineersdecor.config.without_factory_dropper": "Without factory dropper",
"engineersdecor.config.without_slabs": "Without slabs",
"engineersdecor.config.without_halfslabs": "Without slab slices",
"engineersdecor.config.without_direct_slab_pickup": "Without slab pickup",
"engineersdecor.config.without_poles": "Without poles",
"engineersdecor.config.without_hsupports": "Without h. supports",
"engineersdecor.config.without_tooltips": "Without tooltips",
"engineersdecor.config.without_recipes": "Without recipes",
"engineersdecor.config.furnace_smelting_speed_percent": "Furnace: Smelting speed %",
"engineersdecor.config.furnace_fuel_efficiency_percent": "Furnace: Fuel efficiency %",
"engineersdecor.config.furnace_boost_energy_consumption": "Furnace: Boost energy",
"engineersdecor.config.chair_mob_sitting_probability_percent": "Chairs: Sitting chance %",
"engineersdecor.config.chair_mob_standup_probability_percent": "\"Chairs: Stand up chance %\"",
"engineersdecor.config.with_crafting_quickmove_buttons": "Crafting table: Move buttons",
"engineersdecor.config.pipevalve_max_flowrate": "Valves: Max flow rate",
"engineersdecor.config.pipevalve_redstone_gain": "Valves: Redstone slope",
"engineersdecor.config.e_furnace_speed_percent": "E-furnace: Smelting speed %",
"engineersdecor.config.e_furnace_power_consumption": "E-furnace: Power consumption",
"block.engineersdecor.clinker_brick_block": "Clinker Brick Block",
"block.engineersdecor.clinker_brick_block.help": "§6A brick block with position dependent texture variations.§r\nLooks slightly darker and more color intensive than the vanilla brick block.",
"block.engineersdecor.clinker_brick_stained_block": "Stained Clinker Brick Block",
"block.engineersdecor.clinker_brick_stained_block.help": "§6A brick block with position dependent texture variations.§r\nLooks slightly darker and more color intensive than the vanilla brick block. Has more visible traces of grime or stain.",
"block.engineersdecor.slag_brick_block": "Slag Brick Block",
"block.engineersdecor.slag_brick_block.help": "§6A gray-brown brick block with position dependent texture variations.",
"block.engineersdecor.rebar_concrete": "Rebar Concrete Block",
"block.engineersdecor.rebar_concrete.help": "§6Steel reinforced concrete block.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.gas_concrete": "Gas Concrete Block",
"block.engineersdecor.gas_concrete.help": "§6Low hardness, high production yield concrete.§r Easy to break decorative concrete block.",
"block.engineersdecor.panzerglass_block": "Panzer Glass Block",
"block.engineersdecor.panzerglass_block.help": "§6Reinforced glass block.§r Expensive, explosion-proof. Dark gray tint, faint structural lines visible, multi texture for seemless look.",
"block.engineersdecor.rebar_concrete_tile": "Rebar Concrete Tile",
"block.engineersdecor.rebar_concrete_tile.help": "§6Steel reinforced concrete tile.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.clinker_brick_slab": "Clinker Brick Slab",
"block.engineersdecor.clinker_brick_slab.help": "§6Slab made from a Clinker Block.§r\nLooks slightly darker and more color intensive than the vanilla brick.",
"block.engineersdecor.clinker_brick_stained_slab": "Stained Clinker Brick Slab",
"block.engineersdecor.clinker_brick_stained_slab.help": "§6Slab made from a Stained Clinker Block.",
"block.engineersdecor.slag_brick_slab": "Slag Brick Slab",
"block.engineersdecor.slag_brick_slab.help": "§6A gray-brown brick slab.",
"block.engineersdecor.rebar_concrete_slab": "Rebar Concrete Slab",
"block.engineersdecor.rebar_concrete_slab.help": "§6Steel reinforced concrete slab.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.rebar_concrete_tile_slab": "Rebar Concrete Tile Slab",
"block.engineersdecor.rebar_concrete_tile_slab.help": "§6Steel reinforced concrete tile slab.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.gas_concrete_slab": "Gas Concrete Slab",
"block.engineersdecor.gas_concrete_slab.help": "§6Low hardness concrete slab.§r Easy to break decorative concrete.",
"block.engineersdecor.panzerglass_slab": "Panzer Glass Slab",
"block.engineersdecor.panzerglass_slab.help": "§6Reinforced glass slab.§r Expensive, explosion-proof. Dark gray tint, faint structural lines visible.",
"block.engineersdecor.treated_wood_floor": "Treated Wood Floor",
"block.engineersdecor.treated_wood_floor.help": "§6Decorative floor tiles with texture variations.§r",
"block.engineersdecor.rebar_concrete_wall": "Rebar Concrete Wall",
"block.engineersdecor.rebar_concrete_wall.help": "§6Steel reinforced concrete wall.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.concrete_wall": "Concrete Wall",
"block.engineersdecor.concrete_wall.help": "§6Wall made of solid concrete.",
"block.engineersdecor.gas_concrete_wall": "Gas Concrete Wall",
"block.engineersdecor.gas_concrete_wall.help": "§6Low hardness concrete wall.§r Easy to break decorative concrete.",
"block.engineersdecor.clinker_brick_wall": "Clinker Brick Wall",
"block.engineersdecor.clinker_brick_wall.help": "§6Simplistic Clinker Brick Wall.",
"block.engineersdecor.slag_brick_wall": "Slag Brick Wall",
"block.engineersdecor.slag_brick_wall.help": "§6Simplistic Slag Brick Wall.",
"block.engineersdecor.metal_rung_ladder": "Metal Rung Ladder",
"block.engineersdecor.metal_rung_ladder.help": "§6Typical industrial wall ladder, consisting of horizontal metal rod rungs.§r Look up/down to climb faster.",
"block.engineersdecor.metal_rung_steps": "Staggered Metal Steps",
"block.engineersdecor.metal_rung_steps.help": "§6Staggered rod rungs affixed to a wall, allowing to climb up, fall down, and so on.§r Look up/down to climb faster.",
"block.engineersdecor.treated_wood_ladder": "Treated Wood Ladder",
"block.engineersdecor.treated_wood_ladder.help": "§6Weather-proof wooden ladder.§r Look up/down to climb faster.",
"block.engineersdecor.clinker_brick_stairs": "Clinker Brick Stairs",
"block.engineersdecor.clinker_brick_stairs.help": "§6Looks slightly darker and more color intensive than the vanilla brick block.",
"block.engineersdecor.clinker_brick_stained_stairs": "Stained Clinker Brick Stairs",
"block.engineersdecor.clinker_brick_stained_stairs.help": "§6Looks slightly darker and more color intensive than the vanilla brick block. Has more visible traces of grime or stain.",
"block.engineersdecor.slag_brick_stairs": "Slag Brick Stairs",
"block.engineersdecor.slag_brick_stairs.help": "§6Gray-brown brick stairs.",
"block.engineersdecor.rebar_concrete_stairs": "Rebar Concrete Stairs",
"block.engineersdecor.rebar_concrete_stairs.help": "§6Steel reinforced concrete stairs.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.rebar_concrete_tile_stairs": "Rebar Concrete Tile Stairs",
"block.engineersdecor.rebar_concrete_tile_stairs.help": "§6Steel reinforced concrete tile stairs.§r Expensive but Creeper-proof like obsidian.",
"block.engineersdecor.gas_concrete_stairs": "Gas Concrete Stairs",
"block.engineersdecor.gas_concrete_stairs.help": "§6Low hardness concrete stairs.§r Easy to break decorative concrete.",
"block.engineersdecor.treated_wood_pole": "Straight Treated Wood Pole",
"block.engineersdecor.treated_wood_pole.help": "§6Straight pole fragment with a diameter of a wire relay.§r\n Can be useful as alternative to the wire posts if special lengths are needed, or as support for structures.",
"block.engineersdecor.treated_wood_pole_head": "Straight Treated Wood Pole Head/Foot",
"block.engineersdecor.treated_wood_pole_head.help": "§6Wooden part fitting as foot or head of straight poles.",
"block.engineersdecor.treated_wood_pole_support": "Straight Treated Wood Pole Support",
"block.engineersdecor.treated_wood_pole_support.help": "§6Heavy duty wooden support part fitting as foot or head of straight poles.",
"block.engineersdecor.thick_steel_pole": "Straight Thick Steel Pole",
"block.engineersdecor.thick_steel_pole.help": "§6Straight hollow pole fragment (6x6x16) for structural support purposes.",
"block.engineersdecor.thin_steel_pole": "Straight Thin Steel Pole",
"block.engineersdecor.thin_steel_pole.help": "§6Straight hollow pole fragment (4x4x16) for structural support purposes.",
"block.engineersdecor.thin_steel_pole_head": "Straight Thin Steel Pole head/foot",
"block.engineersdecor.thin_steel_pole_head.help": "§6Steel part fitting as foot or head of the thin steel pole (4x4x16).",
"block.engineersdecor.thick_steel_pole_head": "Straight Thick Steel Pole Head/Foot",
"block.engineersdecor.thick_steel_pole_head.help": "§6Steel part fitting as foot or head of the thick steel pole (6x6x16).",
"block.engineersdecor.steel_double_t_support": "Steel Double T Support",
"block.engineersdecor.steel_double_t_support.help": "§6Horizontal ceiling support beam fragment.",
"block.engineersdecor.treated_wood_table": "Treated Wood Table",
"block.engineersdecor.treated_wood_table.help": "§6Robust four-legged wood table.§r Indoor and outdoor use.",
"block.engineersdecor.steel_table": "Steel Table",
"block.engineersdecor.steel_table.help": "§6Robust four-legged steel table.",
"block.engineersdecor.steel_floor_grating": "Steel Floor Grating",
"block.engineersdecor.steel_floor_grating.help": "§6Decorative steel floor covering.§r Top aligned. Items fall through.",
"block.engineersdecor.treated_wood_stool": "Treated Wood Stool",
"block.engineersdecor.treated_wood_stool.help": "§6Robust Wood Stool.§r Indoor and outdoor use.",
"block.engineersdecor.treated_wood_crafting_table": "Treated Wood Crafting Table",
"block.engineersdecor.treated_wood_crafting_table.help": "§6Robust and weather-proof.§r Eight storage slots, keeps inventory, no vanilla recipe book.\n Click up/down arrow buttons for crafting history selection, output slot for item placement, X-button to clear crafting grid and history. Shift-click stack: player-to-storage stack transfer when crafting grid empty, otherwise player-to-grid stack transfer. Automatically distributes the clicked stack. Shift-Ctrl-click stack: Move all same stacks. Mouse wheel over crafting slot: Increase/decrease crafting grid items.",
"block.engineersdecor.treated_wood_side_table": "Treated Wood Side Table",
"block.engineersdecor.treated_wood_side_table.help": "§6Needed after the work's done.",
"block.engineersdecor.iron_inset_light": "Inset Light",
"block.engineersdecor.iron_inset_light.help": "§6Small glowstone light source, sunk into the floor, ceiling or wall.§r\n Useful to light up places where electrical light installations are problematic.",
"block.engineersdecor.iron_floor_edge_light": "Inset Floor Edge Light",
"block.engineersdecor.iron_floor_edge_light.help": "§6Small glowstone light source, placed at the edge of a floor block.§r\n Useful to light up places where electrical light installations are problematic.",
"block.engineersdecor.treated_wood_window": "Treated Wood Window",
"block.engineersdecor.treated_wood_window.help": "§6Wood framed triple glazed window. Well insulating.§r Does not connect to adjacent blocks like glass panes.",
"block.engineersdecor.treated_wood_windowsill": "Treated Wood Window Sill",
"block.engineersdecor.treated_wood_windowsill.help": "§6Simple window decoration.",
"block.engineersdecor.treated_wood_broad_windowsill": "Broad Treated Wood Window Sill",
"block.engineersdecor.treated_wood_broad_windowsill.help": "§6Simple window decoration.",
"block.engineersdecor.steel_framed_window": "Steel Framed Window",
"block.engineersdecor.steel_framed_window.help": "§6Steel framed triple glazed window. Well insulating. §r Does not connect to adjacent blocks like glass panes.",
"block.engineersdecor.steel_mesh_fence": "Steel Mesh Fence",
"block.engineersdecor.steel_mesh_fence.help": "§6Industrial style fence.§r\nDoes not connect do regular fences.",
"block.engineersdecor.small_lab_furnace": "Small Laboratory Furnace",
"block.engineersdecor.small_lab_furnace.help": "§6Small metal cased lab kiln.§r Solid fuel consuming, updraught. Slightly hotter and better isolated than a cobblestone furnace, therefore more efficient. Two auxiliary slots e.g. for storage. Two stack internal hopper fifos for input, output, and fuel. Place an external heater into a aux slot and connect power for electrical smelting speed boost.",
"block.engineersdecor.small_electrical_furnace": "Small Electrical Furnace",
"block.engineersdecor.small_electrical_furnace.help": "§6Small metal cased pass-through furnace.§r Automatically draws items from the input side and puts items into the inventory at the output side. Items can be inserted or drawn from all sides using hoppers. Implicitly bypasses items that cannot be smelted or cooked to the output. Slightly more energy efficient and faster than a heated cobblestone furnace. Fifos and feeders transfer whole stacks. Feeders require a bit of power.",
"block.engineersdecor.small_waste_incinerator": "Small Waste Incinerator",
"block.engineersdecor.small_waste_incinerator.help": "§6Trash with internal fifo slots.§r Items can be inserted on all sides, and are kept until there is no space left in the fifo. After that the oldest stack will be incinerated. Apply electrical RF/FE power to increase the processing speed. Keeps its inventory when being relocated.",
"block.engineersdecor.straight_pipe_valve": "Fluid Pipe Check Valve",
"block.engineersdecor.straight_pipe_valve.help": "§6Straight fluid pipe fragment.§r Conducts fluids only in one direction. Does not connect to the sides. Reduces flow rate. Sneak to place in reverse direction.",
"block.engineersdecor.straight_pipe_valve_redstone": "Redstone Controlled Fluid Valve",
"block.engineersdecor.straight_pipe_valve_redstone.help": "§6Straight fluid pipe fragment.§r Conducts fluids only in one direction. Does not connect to the sides. Sneak to place in reverse direction. Blocks if not redstone powered.",
"block.engineersdecor.straight_pipe_valve_redstone_analog": "Redstone Analog Fluid Valve",
"block.engineersdecor.straight_pipe_valve_redstone_analog.help": "§6Straight fluid pipe fragment.§r Conducts fluids only in one direction. Does not connect to the sides. Sneak to place in reverse direction. Blocks if not redstone powered, reduces the flow rate linear from power 1 to 14, opens to maximum possible valve flow rate for power 15.",
"block.engineersdecor.passive_fluid_accumulator": "Passive Fluid Accumulator",
"block.engineersdecor.passive_fluid_accumulator.help": "§6Vacuum suction based fluid collector.§r Has one output, all other sides are input. Drains fluids from adjacent tanks when being drained from the output port by a pump.",
"block.engineersdecor.small_fluid_funnel": "Small Fluid Collection Funnel",
"block.engineersdecor.small_fluid_funnel.help": "§6Collects fluids above it.§r Has an internal tank with three buckets capacity. Traces flowing fluids to nearby source blocks. The fluid can be obtained with fluid transfer systems or a bucket. Fills only tanks below (gravity transfer). Compatible with vanilla infinite-water-source creation.",
"block.engineersdecor.factory_dropper": "Factory Dropper",
"block.engineersdecor.factory_dropper.help": "§6Dropper suitable for advanced factory automation.§r Has twelve round-robin selected slots. Drop force, angle, stack size, and cool-down delay adjustable using sliders in the GUI. Three stack compare slots (below the inventory slots) with logical AND or OR can be used as internal trigger source. The internal trigger can be AND'ed or OR'ed with the external redstone signal trigger. Trigger simulation buttons for testing. Pre-opens shutter door when internal trigger conditions are met. Drops all matching stacks simultaneously. Simply click on all elements in the GUI to see how it works.",
"block.engineersdecor.factory_hopper": "Factory Hopper",
"block.engineersdecor.factory_hopper.help": "§6Hopper suitable for advanced factory automation.§r Can transfer half-stacks, max collection range 9x9.\n GUI Slider controls: Collection range (0 to 4), insertion delay (0.5s to 10s), insertion stack size (1 to 32).\n GUI Redstone controls: Not inverted / inverted (default), pulse mode / continuous mode (default).",
"block.engineersdecor.factory_placer": "Factory Block Placer",
"block.engineersdecor.factory_placer.help": "§6Allows placing blocks and planting crops or trees.§r\n GUI Redstone controls: Not inverted / inverted (default), pulse mode / continuous mode (default).\n Also supports spike planing from underneath the soil. Spits out items that it cannot place or plant.",
"block.engineersdecor.small_block_breaker": "Small Block Breaker",
"block.engineersdecor.small_block_breaker.help": "§6Breaks blocks in front of it.§r\n Can be disabled by applying a redstone signal. The time needed to destroy a block depends on the hardness of that block. ${!block_breaker_requires_power?engineersdecor.tooltip.massive_speed_boost_with_rf_power} ${block_breaker_requires_power?engineersdecor.tooltip.requires_rf_power}",
"block.engineersdecor.small_mineral_smelter": "Small Mineral Melting Furnace",
"block.engineersdecor.small_mineral_smelter.help": "§6High temperature, high insulation electrical stone melting furnace.§r\n Heats up mineral blocks to magma blocks, and finally to lava. Click with a mineral block (stone, cobble, etc) or use item insertion to place a block in the melter. Use bucket or fluid extraction to retrieve the lava. When cooling down lava, obsidian is generated. Remove the RF power or apply a redstone signal to disable the furnace. For automation, use a redstone comparator to see in which melting phase the mineral is a moment.",
"block.engineersdecor.small_solar_panel": "Small Solar Panel",
"block.engineersdecor.small_solar_panel.help": "§6Produces a small amount of power when exposed to sunlight.§r\n Useful for charging LF capacitors in remote systems with low consumption. The internal charge pump circuit accumulates and frequently transfers RF. Production depends on day time and the weather.",
"block.engineersdecor.small_tree_cutter": "Small Tree Cutter",
"block.engineersdecor.small_tree_cutter.help": "§6Chops grown trees in front of it.§r\n Does not collect the lumbers. Deactivate with a redstone signal. ${!tree_cuttter_requires_power?engineersdecor.tooltip.massive_speed_boost_with_rf_power} ${tree_cuttter_requires_power?engineersdecor.tooltip.requires_rf_power}",
"block.engineersdecor.small_milking_machine": "Small Milking Machine",
"block.engineersdecor.small_milking_machine.help": "§6Occasionally grooms and milks cows.§r\n Has an internal fluid tank. Does not feed the animals. Use buckets to retrieve the milk. Pulls/stores milk container items from/to inventories at the back or bottom (preferrs extracting from the back and inserting below, but can also put filled vessels back into the same inventory). Supports fluid output to tanks or pipes below (only if milk exists as fluid). Care that it's not too crowdy in the cow pen, only happy animals stroll by voluntarily.",
"block.engineersdecor.sign_decor": "Sign Plate (Engineer's decor)",
"block.engineersdecor.sign_decor.help": "§6This should not be craftable or visible in JEI. Used for creative tab and screenshots.",
"block.engineersdecor.sign_hotwire": "Sign \"Caution Hot Wire\"",
"block.engineersdecor.sign_hotwire.help": "§6Electrical hazard warning. Don't forget to place around HV, or you will have a nonconformity in the next audit.",
"block.engineersdecor.sign_mindstep": "Sign \"Mind The Step\"",
"block.engineersdecor.sign_mindstep.help": "§6Placable on walls (horizontally).",
"block.engineersdecor.sign_danger": "Sign \"Caution Really Dangerous There\"",
"block.engineersdecor.sign_danger.help": "§6General danger warning.",
"block.engineersdecor.sign_defense": "Sign \"Caution Defense System Ahead\"",
"block.engineersdecor.sign_defense.help": "§6Warning sign for turrets, Tesla Coils, and traps.",
"block.engineersdecor.sign_factoryarea": "Sign \"Factory Area\"",
"block.engineersdecor.sign_factoryarea.help": "§6Marker sign for buildings or areas where the really big machines are located.",
"block.engineersdecor.sign_exit": "Exit Sign",
"block.engineersdecor.sign_exit.help": "§6There's the door, please ...",
"block.engineersdecor.halfslab_rebar_concrete": "Rebar Concrete Slice",
"block.engineersdecor.halfslab_rebar_concrete.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_concrete": "Concrete Slice",
"block.engineersdecor.halfslab_concrete.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_gas_concrete": "Gas Concrete Slice",
"block.engineersdecor.halfslab_gas_concrete.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_treated_wood": "Treated Wood Slice",
"block.engineersdecor.halfslab_treated_wood.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_sheetmetal_iron": "Iron Sheet Metal Slice",
"block.engineersdecor.halfslab_sheetmetal_iron.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_sheetmetal_steel": "Steel Sheet Metal Slice",
"block.engineersdecor.halfslab_sheetmetal_steel.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_sheetmetal_copper": "Copper Sheet Metal Slice",
"block.engineersdecor.halfslab_sheetmetal_copper.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_sheetmetal_gold": "Gold Sheet Metal Slice",
"block.engineersdecor.halfslab_sheetmetal_gold.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.halfslab_sheetmetal_aluminum": "Aluminum Sheet Metal Slice",
"block.engineersdecor.halfslab_sheetmetal_aluminum.help": "§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.",
"block.engineersdecor.testblock": "ED Test Block (do NOT use)",
"block.engineersdecor.testblock.help": "§6Uncraftable mod testing block with changing experimental functionality. DO NOT USE, may even cause a crash in the worst case!!"
}

View file

@ -48,4 +48,8 @@ tasks["create-half-slab-assets"] = function() {
for(var i in block_data) halfslab_assets.create(block_data[i]);
}
tasks["lang-json-fixes"] = function() {
libtask114.stdtasks["lang-json-fixes"]();
};
libtask.run(tasks, sys.args);

View file

@ -330,6 +330,28 @@
}
};
me.tasks.lang_json_text_replacements = function() {
var file_list = (function() {
var ls = [];
const dir = "./" + constants.local_assets_root() + "/lang";
if(fs.isdir(dir)) {
ls = ls.concat(fs.find(dir, '*.json'));
for(var i in ls) ls[i] = ls[i].replace(/\\/g,"/");
}
ls.sort();
return ls;
})();
for(var file_i in file_list) {
var file = file_list[file_i];
var txt = fs.readfile(file);
if(txt===undefined) throw new Error("Failed to read '" + file + "'");
txt = txt.replace(/\\\\n/g,"\\n");
fs.writefile(file, txt);
}
};
me.stdtasks = {};
me.stdtasks["assets"] = function() {
me.tasks.map_regnames_blockstate_filenames();
@ -367,6 +389,10 @@
}
};
me.stdtasks["lang-json-fixes"] = function() {
me.tasks.lang_json_text_replacements();
}
Object.freeze(me);
Object.freeze(me.tasks);
Object.freeze(me.parsing);

View file

@ -2,13 +2,14 @@
"homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/",
"promos": {
"1.12.2-recommended": "1.0.17",
"1.12.2-latest": "1.0.18-b1",
"1.12.2-latest": "1.0.18-b2",
"1.14.4-recommended": "",
"1.14.4-latest": "1.0.18-b2",
"1.14.4-latest": "1.0.18-b3",
"1.15.1-recommended": "",
"1.15.1-latest": "1.0.18-b2"
"1.15.1-latest": "1.0.18-b3"
},
"1.12.2": {
"1.0.18-b2": "[A] Added Treated Wood Crafting table tweaks (ctrl-shift moves all same stacks from the inventory, mouse wheel over crafting slot increases/decreases crafting grid stacks).\n[F] EN Lang file fixed (issue #76, thx Riverstar907).\n[F] Fixed Tree Cutter not respecting power-required config (thx federsavo, issue #77).",
"1.0.18-b1": "[M] Lang ru_ru updated (Smollet777).",
"1.0.17": "[R] Release based on v1.0.17-b3. Release-to-release changes: * Milking machine added. * Reverse recipes for slab slices added. * Texture and model improvements. * Lang file updates. * Minor bug fixes. * Config options added.\n[M] Updated zh_cn lang file (scikirbypoke).\n[A] Added opt-out config for the Small Tree Cutter.",
"1.0.17-b3": "[F] Fixed Small Block Breaker facings to the horizontal range (issue #70, thx JimMiningWorm).",
@ -82,6 +83,7 @@
"1.0.0-b1": "[A] Initial structure.\n[A] Added clinker bricks and clinker brick stairs.\n[A] Added slag bricks and slag brick stairs.\n[A] Added metal rung ladder.\n[A] Added staggered metal steps ladder.\n[A] Added treated wood ladder.\n[A] Added treated wood pole.\n[A] Added treated wood table."
},
"1.14.4": {
"1.0.18-b3": "[A] Added Treated Wood Crafting table tweaks (ctrl-shift moves all same stacks from the inventory, mouse wheel over crafting slot increases/decreases crafting grid stacks).\n[F] EN Lang file fixed (issue #76, thx Riverstar907).\n[F] Fixed Tree Cutter not respecting power-required config (thx federsavo, issue #77).\n[F] Fixed Small Solar Panel not exposing energy capability (thx MatthiasMann, issue #78).",
"1.0.18-b2": "[F] Fixed JEI integration warning if nothing is opt'ed out (thx @SDUBZ for reporting).\n[M] Lang ru_ru updated (Smollet777).",
"1.0.18-b1": "[U] Updated to Forge 1.14.4-28.1.109/20190719-1.14.3.\n[A] Added opt-out config for the Small Tree Cutter.",
"1.0.17-b3": "[F] Double newline escapes in lang files fixed (\"\\n\" in a tooltip).\n[M] Updated zh_cn lang file (scikirbypoke).",
@ -122,6 +124,7 @@
"1.0.7-b3": "[A] Initial 1.14.2 port of decorative blocks."
},
"1.15.1": {
"1.0.18-b3": "[A] Added Treated Wood Crafting table tweaks (ctrl-shift moves all same stacks from the inventory, mouse wheel over crafting slot increases/decreases crafting grid stacks).\n[F] EN Lang file fixed (issue #76, thx Riverstar907).\n[F] Fixed Tree Cutter not respecting power-required config (thx federsavo, issue #77).\n[F] Fixed Small Solar Panel not exposing energy capability (thx MatthiasMann, issue #78).",
"1.0.18-b2": "[M] Lang ru_ru updated (Smollet777).",
"1.0.18-b1": "[U] Updated to Forge 1.15.1-30.0.16/20190719-1.14.3.\n[F] Client setup Dist annotation fixed (issue #73, thx hitsu420).\n[F] Double newline escapes in lang files fixed (\"\\n\" in a tooltip).\n[M] Updated zh_cn lang file (scikirbypoke).\n[A] Added opt-out config for the Small Tree Cutter",
"1.0.17-b2": "[A] Initial port."