From 97ae2c3af12767d57d2b65227f754ee0a7ecfdae Mon Sep 17 00:00:00 2001 From: stfwi Date: Sat, 12 Oct 2019 10:21:28 +0200 Subject: [PATCH] Experimental Factory Hopper implementation. Lang file updates. --- 1.12/gradle.properties | 2 +- 1.12/readme.md | 4 + .../java/wile/engineersdecor/ModContent.java | 15 +- .../engineersdecor/ModEngineersDecor.java | 3 + .../blocks/BlockDecorDropper.java | 6 +- .../blocks/BlockDecorHopper.java | 873 +++++++++++++++++ .../blocks/BlockDecorWasteIncinerator.java | 12 +- .../wile/engineersdecor/detail/ModConfig.java | 6 + .../blockstates/factory_hopper.json | 18 + .../assets/engineersdecor/lang/en_us.lang | 4 +- .../assets/engineersdecor/lang/ru_ru.lang | 4 +- .../assets/engineersdecor/lang/zh_cn.lang | 444 ++++----- .../block/device/factory_hopper_model.json | 255 +++++ .../device/factory_hopper_model_down.json | 260 ++++++ .../block/device/factory_hopper_model_up.json | 255 +++++ .../recipes/device/factory_hopper_recipe.json | 33 + .../factory_hopper_recipe_standalone.json | 33 + .../blocks/device/factory_hopper_bottom.png | Bin 0 -> 438 bytes .../blocks/device/factory_hopper_front.png | Bin 0 -> 531 bytes .../blocks/device/factory_hopper_side.png | Bin 0 -> 524 bytes .../blocks/device/factory_hopper_top.png | Bin 0 -> 505 bytes .../textures/gui/factory_hopper_gui.png | Bin 0 -> 17059 bytes 1.14/gradle.properties | 2 +- 1.14/readme.md | 4 +- .../java/wile/engineersdecor/ModContent.java | 18 + .../blocks/BlockDecorDropper.java | 15 + .../blocks/BlockDecorFurnace.java | 6 +- .../blocks/BlockDecorHopper.java | 879 ++++++++++++++++++ .../blockstates/factory_hopper.json | 16 + .../assets/engineersdecor/lang/en_us.json | 5 +- .../assets/engineersdecor/lang/ru_ru.json | 1 + .../assets/engineersdecor/lang/zh_cn.json | 310 +++--- .../block/device/factory_hopper_model.json | 255 +++++ .../device/factory_hopper_model_down.json | 260 ++++++ .../block/device/factory_hopper_model_up.json | 255 +++++ .../models/item/factory_hopper.json | 1 + .../block/device/factory_hopper_bottom.png | Bin 0 -> 438 bytes .../block/device/factory_hopper_front.png | Bin 0 -> 531 bytes .../block/device/factory_hopper_side.png | Bin 0 -> 524 bytes .../block/device/factory_hopper_top.png | Bin 0 -> 505 bytes .../textures/gui/factory_hopper_gui.png | Bin 0 -> 17059 bytes readme.md | 29 +- 42 files changed, 3902 insertions(+), 381 deletions(-) create mode 100644 1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorHopper.java create mode 100644 1.12/src/main/resources/assets/engineersdecor/blockstates/factory_hopper.json create mode 100644 1.12/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model.json create mode 100644 1.12/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model_down.json create mode 100644 1.12/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model_up.json create mode 100644 1.12/src/main/resources/assets/engineersdecor/recipes/device/factory_hopper_recipe.json create mode 100644 1.12/src/main/resources/assets/engineersdecor/recipes/standalone/factory_hopper_recipe_standalone.json create mode 100644 1.12/src/main/resources/assets/engineersdecor/textures/blocks/device/factory_hopper_bottom.png create mode 100644 1.12/src/main/resources/assets/engineersdecor/textures/blocks/device/factory_hopper_front.png create mode 100644 1.12/src/main/resources/assets/engineersdecor/textures/blocks/device/factory_hopper_side.png create mode 100644 1.12/src/main/resources/assets/engineersdecor/textures/blocks/device/factory_hopper_top.png create mode 100644 1.12/src/main/resources/assets/engineersdecor/textures/gui/factory_hopper_gui.png create mode 100644 1.14/src/main/java/wile/engineersdecor/blocks/BlockDecorHopper.java create mode 100644 1.14/src/main/resources/assets/engineersdecor/blockstates/factory_hopper.json create mode 100644 1.14/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model.json create mode 100644 1.14/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model_down.json create mode 100644 1.14/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model_up.json create mode 100644 1.14/src/main/resources/assets/engineersdecor/models/item/factory_hopper.json create mode 100644 1.14/src/main/resources/assets/engineersdecor/textures/block/device/factory_hopper_bottom.png create mode 100644 1.14/src/main/resources/assets/engineersdecor/textures/block/device/factory_hopper_front.png create mode 100644 1.14/src/main/resources/assets/engineersdecor/textures/block/device/factory_hopper_side.png create mode 100644 1.14/src/main/resources/assets/engineersdecor/textures/block/device/factory_hopper_top.png create mode 100644 1.14/src/main/resources/assets/engineersdecor/textures/gui/factory_hopper_gui.png diff --git a/1.12/gradle.properties b/1.12/gradle.properties index 3a34e8b..961bd42 100644 --- a/1.12/gradle.properties +++ b/1.12/gradle.properties @@ -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.13 +version_engineersdecor=1.0.14-b1 diff --git a/1.12/readme.md b/1.12/readme.md index 6c48ee1..dfec0df 100644 --- a/1.12/readme.md +++ b/1.12/readme.md @@ -10,6 +10,10 @@ Mod sources for Minecraft version 1.12.2. ---- ## Version history + ~ v1.0.14-b1 [A] Factory Hopper added (configurable hopper and item collector). + [M] Small Waste Incinerator Fifo shifting improved. + [M] Lang file zh_cn updated (scikirbypoke, PR#53). + ------------------------------------------------------------------- - v1.0.13 [R] Release based on v1.0.13-b2. Release-to-release changes: * Small Tree Cutter device added. diff --git a/1.12/src/main/java/wile/engineersdecor/ModContent.java b/1.12/src/main/java/wile/engineersdecor/ModContent.java index 7de86b2..44c43e7 100644 --- a/1.12/src/main/java/wile/engineersdecor/ModContent.java +++ b/1.12/src/main/java/wile/engineersdecor/ModContent.java @@ -106,6 +106,13 @@ public class ModContent ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,15) ); + public static final BlockDecorHopper FACTORY_HOPPER = new BlockDecorHopper( + "factory_hopper", + BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_REDSTONE_CONTROLLED, + Material.IRON, 1f, 15f, SoundType.METAL, + ModAuxiliaries.getPixeledAABB(2,2,2, 14,14,14) + ); + public static final BlockDecorWasteIncinerator SMALL_WASTE_INCINERATOR = new BlockDecorWasteIncinerator( "small_waste_incinerator", BlockDecor.CFG_DEFAULT|BlockDecor.CFG_ELECTRICAL, @@ -442,19 +449,18 @@ public class ModContent private static final TileEntityRegistrationData FACTORY_DROPPER_TEI = new TileEntityRegistrationData( BlockDecorDropper.BTileEntity.class, "te_factory_dropper" ); - + private static final TileEntityRegistrationData FACTORY_HOPPER_TEI = new TileEntityRegistrationData( + BlockDecorHopper.BTileEntity.class, "te_factory_hopper" + ); private static final TileEntityRegistrationData SMALL_MINERAL_SMELTER_TEI = new TileEntityRegistrationData( BlockDecorMineralSmelter.BTileEntity.class, "te_small_mineral_smelter" ); - private static final TileEntityRegistrationData SMALL_SOLAR_PANEL_TEI = new TileEntityRegistrationData( BlockDecorSolarPanel.BTileEntity.class, "te_small_solar_panel" ); - private static final TileEntityRegistrationData SMALL_TREE_CUTTER_TEI = new TileEntityRegistrationData( BlockDecorTreeCutter.BTileEntity.class, "te_small_tree_cutter" ); - private static final TileEntityRegistrationData TEST_BLOCK_TEI = new TileEntityRegistrationData( BlockDecorTest.BTileEntity.class, "te_testblock" ); @@ -526,6 +532,7 @@ public class ModContent SIGN_MINDSTEP, PANZERGLASS_SLAB, // @todo: check if another class is needed due to is_side_visible TREATED_WOOD_FLOOR, // @todo: check if textures need improvement + FACTORY_HOPPER,FACTORY_HOPPER_TEI, TEST_BLOCK,TEST_BLOCK_TEI }; diff --git a/1.12/src/main/java/wile/engineersdecor/ModEngineersDecor.java b/1.12/src/main/java/wile/engineersdecor/ModEngineersDecor.java index 20cd067..0f790ba 100644 --- a/1.12/src/main/java/wile/engineersdecor/ModEngineersDecor.java +++ b/1.12/src/main/java/wile/engineersdecor/ModEngineersDecor.java @@ -158,6 +158,7 @@ public class ModEngineersDecor public static final int GUIID_ELECTRICAL_LAB_FURNACE = 213103; public static final int GUIID_SMALL_WASTE_INCINERATOR = 213104; public static final int GUIID_FACTORY_DROPPER = 213105; + public static final int GUIID_FACTORY_HOPPER = 213106; @Override public Object getServerGuiElement(final int guiid, final EntityPlayer player, final World world, int x, int y, int z) @@ -170,6 +171,7 @@ public class ModEngineersDecor case GUIID_ELECTRICAL_LAB_FURNACE: return BlockDecorFurnaceElectrical.getServerGuiElement(player, world, pos, te); case GUIID_SMALL_WASTE_INCINERATOR: return BlockDecorWasteIncinerator.getServerGuiElement(player, world, pos, te); case GUIID_FACTORY_DROPPER: return BlockDecorDropper.getServerGuiElement(player, world, pos, te); + case GUIID_FACTORY_HOPPER: return BlockDecorHopper.getServerGuiElement(player, world, pos, te); } return null; } @@ -186,6 +188,7 @@ public class ModEngineersDecor case GUIID_ELECTRICAL_LAB_FURNACE: return BlockDecorFurnaceElectrical.getClientGuiElement(player, world, pos, te); case GUIID_SMALL_WASTE_INCINERATOR: return BlockDecorWasteIncinerator.getClientGuiElement(player, world, pos, te); case GUIID_FACTORY_DROPPER: return BlockDecorDropper.getClientGuiElement(player, world, pos, te); + case GUIID_FACTORY_HOPPER: return BlockDecorHopper.getClientGuiElement(player, world, pos, te); } return null; } diff --git a/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorDropper.java b/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorDropper.java index 0fe6ea0..bc5fca2 100644 --- a/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorDropper.java +++ b/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorDropper.java @@ -4,15 +4,15 @@ * @copyright (C) 2019 Stefan Wilhelm * @license MIT (see https://opensource.org/licenses/MIT) * - * Dropper factory automation suitable. + * Dropper, factory automation suitable. */ package wile.engineersdecor.blocks; +import wile.engineersdecor.ModEngineersDecor; +import wile.engineersdecor.detail.Networking; import net.minecraft.block.state.BlockFaceShape; import net.minecraft.world.IBlockAccess; import net.minecraftforge.items.wrapper.SidedInvWrapper; -import wile.engineersdecor.ModEngineersDecor; -import wile.engineersdecor.detail.Networking; import net.minecraft.block.properties.PropertyBool; import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.Block; diff --git a/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorHopper.java b/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorHopper.java new file mode 100644 index 0000000..3ca9daa --- /dev/null +++ b/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorHopper.java @@ -0,0 +1,873 @@ +/* + * @file BlockDecorHopper.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2019 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Hopper, factory automation suitable. + */ +package wile.engineersdecor.blocks; + +import net.minecraft.entity.Entity; +import net.minecraft.util.math.*; +import wile.engineersdecor.ModEngineersDecor; +import wile.engineersdecor.detail.Networking; +import net.minecraft.block.state.BlockFaceShape; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.items.wrapper.SidedInvWrapper; +import net.minecraft.block.Block; +import net.minecraft.block.SoundType; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockHopper; +import net.minecraft.world.World; +import net.minecraft.world.Explosion; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityHopper; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.item.*; +import net.minecraft.inventory.*; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.*; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.IOException; +import java.util.List; + +public class BlockDecorHopper extends BlockDecorDirected +{ + public BlockDecorHopper(@Nonnull String registryName, long config, @Nullable Material material, float hardness, float resistance, @Nullable SoundType sound, @Nonnull AxisAlignedBB unrotatedAABB) + { super(registryName, config, material, hardness, resistance, sound, unrotatedAABB); } + + @Override + public BlockFaceShape getBlockFaceShape(IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing face) + { return BlockFaceShape.SOLID; } + + @Override + @SuppressWarnings("deprecation") + public boolean hasComparatorInputOverride(IBlockState state) + { return true; } + + @Override + @SuppressWarnings("deprecation") + public int getComparatorInputOverride(IBlockState blockState, World world, BlockPos pos) + { return Container.calcRedstone(world.getTileEntity(pos)); } + + @Override + public boolean hasTileEntity(IBlockState state) + { return true; } + + @Override + @Nullable + public TileEntity createTileEntity(World world, IBlockState state) + { return new BTileEntity(); } + + @Override + public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) + { + if(world.isRemote) return; + if((!stack.hasTagCompound()) || (!stack.getTagCompound().hasKey("tedata"))) return; + NBTTagCompound te_nbt = stack.getTagCompound().getCompoundTag("tedata"); + if(te_nbt.isEmpty()) return; + final TileEntity te = world.getTileEntity(pos); + if(!(te instanceof BTileEntity)) return; + ((BTileEntity)te).readnbt(te_nbt, false); + ((BTileEntity)te).reset_rtstate(); + ((BTileEntity)te).markDirty(); + } + + @Override + public boolean removedByPlayer(IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest) + { + if(world.isRemote) return true; + TileEntity te = world.getTileEntity(pos); + if(!(te instanceof BTileEntity)) return super.removedByPlayer(state, world, pos, player, willHarvest); + ItemStack stack = new ItemStack(this, 1); + NBTTagCompound te_nbt = new NBTTagCompound(); + ((BTileEntity) te).writenbt(te_nbt, false); + if(!te_nbt.isEmpty()) { + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setTag("tedata", te_nbt); + stack.setTagCompound(nbt); + } + world.spawnEntity(new EntityItem(world, pos.getX()+0.5, pos.getY()+0.5, pos.getZ()+0.5, stack)); + world.setBlockToAir(pos); + world.removeTileEntity(pos); + return false; + } + + @Override + public void onBlockExploded(World world, BlockPos pos, Explosion explosion) + { + if(world.isRemote) return; + TileEntity te = world.getTileEntity(pos); + if(!(te instanceof BTileEntity)) return; + for(ItemStack stack: ((BTileEntity)te).stacks_) { + if(!stack.isEmpty()) world.spawnEntity(new EntityItem(world, pos.getX(), pos.getY(), pos.getZ(), stack)); + } + ((BTileEntity)te).reset_rtstate(); + super.onBlockExploded(world, pos, explosion); + } + + @Override + public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) + { + if(world.isRemote) return true; + player.openGui(ModEngineersDecor.instance, ModEngineersDecor.GuiHandler.GUIID_FACTORY_HOPPER, world, pos.getX(), pos.getY(), pos.getZ()); + return true; + } + + @Override + public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block, BlockPos neighborPos) + { + if(!(world instanceof World) || (((World) world).isRemote)) return; + TileEntity te = world.getTileEntity(pos); + if(!(te instanceof BTileEntity)) return; + ((BTileEntity)te).block_updated(); + } + + @Override + public void onFallenUpon(World world, BlockPos pos, Entity entity, float fallDistance) + { + super.onFallenUpon(world, pos, entity, fallDistance); + if(!(entity instanceof EntityItem)) return; + TileEntity te = world.getTileEntity(pos); + if(!(te instanceof BTileEntity)) return; + ((BTileEntity)te).collection_timer_ = 0; + } + + //-------------------------------------------------------------------------------------------------------------------- + // ModEngineersDecor.GuiHandler connectors + //-------------------------------------------------------------------------------------------------------------------- + + public static Object getServerGuiElement(final EntityPlayer player, final World world, final BlockPos pos, final TileEntity te) + { return (te instanceof BTileEntity) ? (new BContainer(player.inventory, world, pos, (BTileEntity)te)) : null; } + + public static Object getClientGuiElement(final EntityPlayer player, final World world, final BlockPos pos, final TileEntity te) + { return (te instanceof BTileEntity) ? (new BGui(player.inventory, world, pos, (BTileEntity)te)) : null; } + + //-------------------------------------------------------------------------------------------------------------------- + // GUI + //-------------------------------------------------------------------------------------------------------------------- + + @SideOnly(Side.CLIENT) + private static class BGui extends GuiContainer + { + private final BTileEntity te; + + public BGui(InventoryPlayer playerInventory, World world, BlockPos pos, BTileEntity te) + { super(new BContainer(playerInventory, world, pos, te)); this.te = te; } + + @Override + public void initGui() + { super.initGui(); } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) + { + drawDefaultBackground(); + super.drawScreen(mouseX, mouseY, partialTicks); + renderHoveredToolTip(mouseX, mouseY); + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException + { + super.mouseClicked(mouseX, mouseY, mouseButton); + BContainer container = (BContainer)inventorySlots; + if(container.fields_.length != 7) return; + int mx = mouseX - getGuiLeft(), my = mouseY - getGuiTop(); + if(!isPointInRegion(126, 1, 49, 60, mouseX, mouseY)) { + return; + } else if(isPointInRegion(128, 9, 44, 10, mouseX, mouseY)) { + int range = (mx-133); + if(range < -1) { + range = container.fields_[0] - 1; // - + } else if(range >= 34) { + range = container.fields_[0] + 1; // + + } else { + range = (int)(0.5 + ((((double)BTileEntity.MAX_COLLECTION_RANGE) * range)/34)); // slider + range = MathHelper.clamp(range, 0, BTileEntity.MAX_COLLECTION_RANGE); + } + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setInteger("range", range); + Networking.PacketTileNotify.sendToServer(te, nbt); + } else if(isPointInRegion(128, 21, 44, 10, mouseX, mouseY)) { + int period = (mx-133); + if(period < -1) { + period = container.fields_[3] - 3; // - + } else if(period >= 35) { + period = container.fields_[3] + 3; // + + } else { + period = (int)(0.5 + ((100.0 * period)/34)); + } + period = MathHelper.clamp(period, 0, 100); + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setInteger("period", period); + Networking.PacketTileNotify.sendToServer(te, nbt); + } else if(isPointInRegion(128, 34, 44, 10, mouseX, mouseY)) { + int ndrop = (mx-134); + if(ndrop < -1) { + ndrop = container.fields_[1] - 1; // - + } else if(ndrop >= 34) { + ndrop = container.fields_[1] + 1; // + + } else { + ndrop = MathHelper.clamp(1+ndrop, 1, BTileEntity.MAX_TRANSFER_COUNT); // slider + } + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setInteger("xsize", ndrop); + Networking.PacketTileNotify.sendToServer(te, nbt); + } else if(isPointInRegion(133, 49, 9, 9, mouseX, mouseY)) { + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setInteger("manual_trigger", 1); + Networking.PacketTileNotify.sendToServer(te, nbt); + } else if(isPointInRegion(145, 49, 9, 9, mouseX, mouseY)) { + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setInteger("logic", container.fields_[2] ^ BTileEntity.LOGIC_INVERTED); + Networking.PacketTileNotify.sendToServer(te, nbt); + } else if(isPointInRegion(159, 49, 7, 9, mouseX, mouseY)) { + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setInteger("logic", container.fields_[2] ^ BTileEntity.LOGIC_CONTINUOUS); + Networking.PacketTileNotify.sendToServer(te, nbt); + } + } + + @Override + protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) + { + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/factory_hopper_gui.png")); + final int x0=getGuiLeft(), y0=getGuiTop(), w=getXSize(), h=getYSize(); + drawTexturedModalRect(x0, y0, 0, 0, w, h); + BContainer container = (BContainer)inventorySlots; + if(container.fields_.length != 7) return; // no init, no cake. + // active slot + { + int slot_index = container.fields_[6]; + if((slot_index < 0) || (slot_index >= BTileEntity.NUM_OF_SLOTS)) slot_index = 0; + int x = (x0+10+((slot_index % 6) * 18)); + int y = (y0+8+((slot_index / 6) * 17)); + drawTexturedModalRect(x, y, 200, 8, 18, 18); + } + // collection range + { + int lut[] = { 133, 141, 149, 157, 166 }; + int px = lut[MathHelper.clamp(container.fields_[0], 0, BTileEntity.MAX_COLLECTION_RANGE)]; + int x = x0 + px - 2; + int y = y0 + 14; + drawTexturedModalRect(x, y, 179, 40, 5, 5); + } + // transfer period + { + int px = (int)Math.round(((33.5 * container.fields_[3]) / 100) + 1); + int x = x0 + 132 - 2 + MathHelper.clamp(px, 0, 34); + int y = y0 + 27; + drawTexturedModalRect(x, y, 179, 40, 5, 5); + } + // transfer count + { + int x = x0 + 133 - 2 + (container.fields_[1]); + int y = y0 + 40; + drawTexturedModalRect(x, y, 179, 40, 5, 5); + } + // redstone input + { + if(container.fields_[5] != 0) { + drawTexturedModalRect(x0+133, y0+49, 217, 49, 9, 9); + } + } + // trigger logic + { + int inverter_offset = ((container.fields_[2] & BTileEntity.LOGIC_INVERTED) != 0) ? 11 : 0; + drawTexturedModalRect(x0+145, y0+49, 177+inverter_offset, 49, 9, 9); + int pulse_mode_offset = ((container.fields_[2] & BTileEntity.LOGIC_CONTINUOUS ) != 0) ? 9 : 0; + drawTexturedModalRect(x0+159, y0+49, 199+pulse_mode_offset, 49, 9, 9); + } + // delay timer running indicator + { + if((container.fields_[4] > BTileEntity.PERIOD_OFFSET) && ((System.currentTimeMillis() % 1000) < 500)) { + drawTexturedModalRect(x0+148, y0+22, 187, 22, 3, 3); + } + } + } + } + + //-------------------------------------------------------------------------------------------------------------------- + // container + //-------------------------------------------------------------------------------------------------------------------- + + public static class BContainer extends Container + { + private static final int PLAYER_INV_START_SLOTNO = BTileEntity.NUM_OF_SLOTS; + private final World world; + private final BlockPos pos; + private final EntityPlayer player; + private final BTileEntity te; + private int fields_[] = new int[7]; + + public BContainer(InventoryPlayer playerInventory, World world, BlockPos pos, BTileEntity te) + { + this.player = playerInventory.player; + this.world = world; + this.pos = pos; + this.te = te; + int i=-1; + // device slots (stacks 0 to 17) + for(int y=0; y<3; ++y) { + for(int x=0; x<6; ++x) { + int xpos = 11+x*18, ypos = 9+y*17; + addSlotToContainer(new Slot(te, ++i, xpos, ypos)); + } + } + // player slots + for(int x=0; x<9; ++x) { + addSlotToContainer(new Slot(playerInventory, x, 8+x*18, 129)); // player slots: 0..8 + } + for(int y=0; y<3; ++y) { + for(int x=0; x<9; ++x) { + addSlotToContainer(new Slot(playerInventory, x+y*9+9, 8+x*18, 71+y*18)); // player slots: 9..35 + } + } + } + + public BlockPos getPos() + { return pos; } + + @Override + public void addListener(IContainerListener listener) + { super.addListener(listener); listener.sendAllWindowProperties(this, te); } + + @Override + public void detectAndSendChanges() + { + super.detectAndSendChanges(); + for(int il=0; il= fields_.length)) return; + fields_[id] = value; + te.setField(id, value); + } + + @Override + public boolean canInteractWith(EntityPlayer player) + { return (world.getBlockState(pos).getBlock() instanceof BlockDecorHopper) && (player.getDistanceSq(pos) <= 64); } + + @Override + public ItemStack transferStackInSlot(EntityPlayer player, int index) + { + Slot slot = inventorySlots.get(index); + if((slot==null) || (!slot.getHasStack())) return ItemStack.EMPTY; + ItemStack slot_stack = slot.getStack(); + ItemStack transferred = slot_stack.copy(); + if((index>=0) && (index= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) { + // Player slot + if(!mergeItemStack(slot_stack, 0, BTileEntity.NUM_OF_SLOTS, false)) return ItemStack.EMPTY; + } else { + // invalid slot + return ItemStack.EMPTY; + } + if(slot_stack.isEmpty()) { + slot.putStack(ItemStack.EMPTY); + } else { + slot.onSlotChanged(); + } + if(slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY; + slot.onTake(player, slot_stack); + return transferred; + } + } + + //-------------------------------------------------------------------------------------------------------------------- + // Tile entity + //-------------------------------------------------------------------------------------------------------------------- + + public static class BTileEntity extends TileEntity implements ITickable, ISidedInventory, Networking.IPacketReceiver + { + public static final int TICK_INTERVAL = 10; + public static final int COLLECTION_INTERVAL = 25; + public static final int NUM_OF_SLOTS = 18; + public static final int MAX_TRANSFER_COUNT = 32; + public static final int MAX_COLLECTION_RANGE = 4; + public static final int PERIOD_OFFSET = 10; + /// + public static final int LOGIC_INVERTED = 0x01; + public static final int LOGIC_CONTINUOUS = 0x02; + /// + private boolean block_power_signal_ = false; + private boolean block_power_updated_ = false; + private int collection_timer_ = 0; + private int delay_timer_ = 0; + private int transfer_count_ = 1; + private int logic_ = LOGIC_INVERTED|LOGIC_CONTINUOUS; + private int transfer_period_ = 0; + private int collection_range_ = 0; + private int current_slot_index_ = 0; + private int tick_timer_ = 0; + protected NonNullList stacks_; + + public static void on_config(int cooldown_ticks) + { + // ModEngineersDecor.logger.info("Config factory hopper:"); + } + + public BTileEntity() + { + stacks_ = NonNullList.withSize(NUM_OF_SLOTS, ItemStack.EMPTY); + reset_rtstate(); + } + + public void reset_rtstate() + { + block_power_signal_ = false; + block_power_updated_ = false; + } + + public void readnbt(NBTTagCompound nbt, boolean update_packet) + { + stacks_ = NonNullList.withSize(NUM_OF_SLOTS, ItemStack.EMPTY); + ItemStackHelper.loadAllItems(nbt, stacks_); + while(stacks_.size() < NUM_OF_SLOTS) stacks_.add(ItemStack.EMPTY); + block_power_signal_ = nbt.getBoolean("powered"); + current_slot_index_ = nbt.getInteger("act_slot_index"); + transfer_count_ = MathHelper.clamp(nbt.getInteger("xsize"), 1, MAX_TRANSFER_COUNT); + logic_ = nbt.getInteger("logic"); + transfer_period_ = nbt.getInteger("period"); + collection_range_ = nbt.getInteger("range"); + } + + protected void writenbt(NBTTagCompound nbt, boolean update_packet) + { + ItemStackHelper.saveAllItems(nbt, stacks_); + nbt.setBoolean("powered", block_power_signal_); + nbt.setInteger("act_slot_index", current_slot_index_); + nbt.setInteger("xsize", transfer_count_); + nbt.setInteger("logic", logic_); + nbt.setInteger("period", transfer_period_); + nbt.setInteger("range", collection_range_); + } + + public void block_updated() + { + // RS power check, both edges + boolean powered = world.isBlockPowered(pos); + if(block_power_signal_ != powered) block_power_updated_ = true; + block_power_signal_ = powered; + tick_timer_ = 1; + } + + public boolean is_input_slot(int index) + { return (index >= 0) && (index < NUM_OF_SLOTS); } + + // TileEntity ------------------------------------------------------------------------------ + + @Override + public boolean shouldRefresh(World world, BlockPos pos, IBlockState os, IBlockState ns) + { return (os.getBlock() != ns.getBlock()) || (!(ns.getBlock() instanceof BlockDecorHopper)); } + + @Override + public void readFromNBT(NBTTagCompound nbt) + { super.readFromNBT(nbt); readnbt(nbt, false); } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound nbt) + { super.writeToNBT(nbt); writenbt(nbt, false); return nbt; } + + // IWorldNamable --------------------------------------------------------------------------- + + @Override + public String getName() + { final Block block=getBlockType(); return (block!=null) ? (block.getTranslationKey() + ".name") : (""); } + + @Override + public boolean hasCustomName() + { return false; } + + @Override + public ITextComponent getDisplayName() + { return new TextComponentTranslation(getName(), new Object[0]); } + + // IInventory ------------------------------------------------------------------------------ + + @Override + public int getSizeInventory() + { return stacks_.size(); } + + @Override + public boolean isEmpty() + { for(ItemStack stack: stacks_) { if(!stack.isEmpty()) return false; } return true; } + + @Override + public ItemStack getStackInSlot(int index) + { return (index < getSizeInventory()) ? stacks_.get(index) : ItemStack.EMPTY; } + + @Override + public ItemStack decrStackSize(int index, int count) + { return ItemStackHelper.getAndSplit(stacks_, index, count); } + + @Override + public ItemStack removeStackFromSlot(int index) + { return ItemStackHelper.getAndRemove(stacks_, index); } + + @Override + public void setInventorySlotContents(int index, ItemStack stack) + { + stacks_.set(index, stack); + if(stack.getCount() > getInventoryStackLimit()) stack.setCount(getInventoryStackLimit()); + if(tick_timer_ > 8) tick_timer_ = 8; + markDirty(); + } + + @Override + public int getInventoryStackLimit() + { return 64; } + + @Override + public void markDirty() + { super.markDirty(); } + + @Override + public boolean isUsableByPlayer(EntityPlayer player) + { return ((world.getTileEntity(pos) == this) && (player.getDistanceSq(pos.getX()+0.5d, pos.getY()+0.5d, pos.getZ()+0.5d) <= 64.0d)); } + + @Override + public void openInventory(EntityPlayer player) + {} + + @Override + public void closeInventory(EntityPlayer player) + { markDirty(); } + + @Override + public boolean isItemValidForSlot(int index, ItemStack stack) + { return true; } + + @Override + public int getField(int id) + { + switch(id) { + case 0: return collection_range_; + case 1: return transfer_count_; + case 2: return logic_; + case 3: return transfer_period_; + case 4: return delay_timer_; + case 5: return block_power_signal_ ? 1 : 0; + case 6: return current_slot_index_; + default: return 0; + } + } + + @Override + public void setField(int id, int value) + { + switch(id) { + case 0: collection_range_ = MathHelper.clamp(value,0, MAX_COLLECTION_RANGE); return; + case 1: transfer_count_ = MathHelper.clamp(value,1, MAX_TRANSFER_COUNT); return; + case 2: logic_ = value; return; + case 3: transfer_period_ = MathHelper.clamp(value,0, 100); return; + case 4: delay_timer_ = MathHelper.clamp(value,0, 400); return; + case 5: block_power_signal_ = (value != 0); return; + case 6: current_slot_index_ = MathHelper.clamp(value, 0, NUM_OF_SLOTS-1); return; + default: return; + } + } + + @Override + public int getFieldCount() + { return 7; } + + @Override + public void clear() + { stacks_.clear(); } + + // ISidedInventory ---------------------------------------------------------------------------- + + private final IItemHandler item_handler_ = new SidedInvWrapper(this, EnumFacing.UP); + private static final int[] SIDED_INV_SLOTS; + static { + SIDED_INV_SLOTS = new int[NUM_OF_SLOTS]; + for(int i=0; i cap, EnumFacing facing) + { return (cap==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) || super.hasCapability(cap, facing); } + + @Override + @SuppressWarnings("unchecked") + @Nullable + public T getCapability(Capability capability, @Nullable EnumFacing facing) + { + if(capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return (T)item_handler_; + return super.getCapability(capability, facing); + } + + // IPacketReceiver ------------------------------------------------------------------------------- + + @Override + public void onServerPacketReceived(NBTTagCompound nbt) + {} + + @Override + public void onClientPacketReceived(EntityPlayer player, NBTTagCompound nbt) + { + if(nbt.hasKey("xsize")) transfer_count_ = MathHelper.clamp(nbt.getInteger("xsize"), 1, MAX_TRANSFER_COUNT); + if(nbt.hasKey("period")) transfer_period_ = MathHelper.clamp(nbt.getInteger("period"), 0, 100); + if(nbt.hasKey("range")) collection_range_ = MathHelper.clamp(nbt.getInteger("range"), 0, MAX_COLLECTION_RANGE); + if(nbt.hasKey("logic")) logic_ = nbt.getInteger("logic"); + if(nbt.hasKey("manual_trigger") && (nbt.getInteger("manual_trigger")!=0)) { block_power_signal_=true; block_power_updated_=true; tick_timer_=1; } + markDirty(); + } + + // ITickable and aux methods --------------------------------------------------------------------- + + private static int next_slot(int i) + { return (i= n_to_insert) { + slotstack.grow(n_to_insert); + n_to_insert = 0; + break; + } else { + slotstack.grow(nspace); + n_to_insert -= nspace; + } + } + if((n_to_insert > 0) && (first_empty_slot >= 0)) { + ItemStack new_stack = stack.copy(); + new_stack.setCount(n_to_insert); + stacks_.set(first_empty_slot, new_stack); + n_to_insert = 0; + } + return max_to_insert - n_to_insert; + } + + private boolean try_insert(EnumFacing facing) + { + ItemStack current_stack = ItemStack.EMPTY; + for(int i=0; i= NUM_OF_SLOTS) current_slot_index_ = 0; + current_stack = stacks_.get(current_slot_index_); + if(!current_stack.isEmpty()) break; + current_slot_index_ = next_slot(current_slot_index_); + } + if(current_stack.isEmpty()) { + current_slot_index_ = 0; + return false; + } + final TileEntity te = world.getTileEntity(pos.offset(facing)); + if((te == null) || (!te.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite()))) { + delay_timer_ = TICK_INTERVAL+2; // no reason to recalculate this all the time if there is nothere to insert. + return false; + } else if(te instanceof TileEntityHopper) { + EnumFacing f = world.getBlockState(pos.offset(facing)).getValue(BlockHopper.FACING); + if(f==facing.getOpposite()) return false; // no back transfer + } else if(te instanceof BTileEntity) { + EnumFacing f = world.getBlockState(pos.offset(facing)).getValue(FACING); + if(f==facing.getOpposite()) return false; + } + ItemStack insert_stack = current_stack.copy(); + if(insert_stack.getCount() > transfer_count_) insert_stack.setCount(transfer_count_); + final int initial_insert_stack_size = insert_stack.getCount(); + final IItemHandler ih = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite()); + int first_empty_slot_index = -1; + if((ih == null) || ih.getSlots() <= 0) return false; + for(int i=0; i= 0) && (!insert_stack.isEmpty())) { + insert_stack = ih.insertItem(first_empty_slot_index, insert_stack.copy(), false); + } + final int num_inserted = initial_insert_stack_size-insert_stack.getCount(); + if(num_inserted > 0) { + current_stack.shrink(num_inserted); + stacks_.set(current_slot_index_, current_stack); + } + if(!insert_stack.isEmpty()) current_slot_index_ = next_slot(current_slot_index_); + return (num_inserted > 0); + } + + private boolean try_item_handler_extract(final IItemHandler ih) + { + final int end = ih.getSlots(); + int n_to_extract = transfer_count_; + for(int i=0; i 0) { + ItemStack test = ih.extractItem(i, n_accepted, false); + n_to_extract -= n_accepted; + if(n_to_extract <= 0) break; + } + } + return (n_to_extract < transfer_count_); + } + + private boolean try_inventory_extract(final IInventory inv) + { + final int end = inv.getSizeInventory(); + int n_to_extract = transfer_count_; + for(int i=0; i 0) { + stack.shrink(n_accepted); + n_to_extract -= n_accepted; + if(stack.isEmpty()) stack = ItemStack.EMPTY; + inv.setInventorySlotContents(i, stack); + if(n_to_extract <= 0) break; + } + } + if(n_to_extract < transfer_count_) { + inv.markDirty(); + return true; + } else { + return false; + } + } + + private boolean try_collect(EnumFacing facing) + { + AxisAlignedBB collection_volume; + BlockPos rpos; + if(facing==EnumFacing.UP) { + rpos = pos.add(0.5, 1.5,0.5); + collection_volume = (new AxisAlignedBB(pos.up())).grow(0.1+collection_range_, 0.6, 0.1+collection_range_); + } else { + rpos = pos.add(0.5, -1.5,0.5); + collection_volume = (new AxisAlignedBB(pos.down())).grow(0.1+collection_range_, 0.7, 0.1+collection_range_); + } + final List items = world.getEntitiesWithinAABB(EntityItem.class, collection_volume); + if(items.size() <= 0) return false; + final int max_to_collect = 3; + int n_collected = 0; + for(EntityItem ie:items) { + boolean is_direct_collection_tange = ie.getDistanceSq(rpos)<0.7; + if(!is_direct_collection_tange && (ie.cannotPickup() || (!ie.onGround))) continue; + ItemStack stack = ie.getItem(); + int n_accepted = try_insert_into_hopper(stack); + if(n_accepted <= 0) continue; + if(n_accepted == stack.getCount()) { + ie.setDead(); + } else { + stack.shrink(n_accepted); + } + if((!is_direct_collection_tange) && (++n_collected >= max_to_collect)) break; + } + return (n_collected > 0); + } + + @Override + public void update() + { + // Tick cycle pre-conditions + if(world.isRemote) return; + if((delay_timer_ > 0) && ((--delay_timer_) == 0)) markDirty(); + if(--tick_timer_ > 0) return; + tick_timer_ = TICK_INTERVAL; + // Cycle init + boolean dirty = block_power_updated_; + boolean rssignal = ((logic_ & LOGIC_INVERTED)!=0)==(!block_power_signal_); + boolean trigger = (rssignal && ((block_power_updated_) || ((logic_ & LOGIC_CONTINUOUS)!=0))); + final IBlockState state = world.getBlockState(pos); + if(state == null) { block_power_signal_= false; return; } + final EnumFacing hopper_facing = state.getValue(FACING); + // Trigger edge detection for next cycle + { + boolean tr = world.isBlockPowered(pos); + block_power_updated_ = (block_power_signal_ != tr); + block_power_signal_ = tr; + if(block_power_updated_) dirty = true; + } + // Collection + if(rssignal) { + EnumFacing hopper_input_facing = (hopper_facing==EnumFacing.UP) ? EnumFacing.DOWN : EnumFacing.UP; + TileEntity te = world.getTileEntity(pos.offset(hopper_input_facing)); + boolean has_item_handler = ((te!=null) && te.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, hopper_input_facing.getOpposite())); + if(has_item_handler || (te instanceof ISidedInventory)) { + // IItemHandler pulling + if(has_item_handler) { + final IItemHandler ih = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, hopper_facing.getOpposite()); + if((ih != null) && try_item_handler_extract(ih)) dirty = true; + } else { + try_inventory_extract((IInventory)te); + } + } else if((collection_timer_ -= TICK_INTERVAL) <= 0) { + // Ranged collection + collection_timer_ = COLLECTION_INTERVAL; + if(try_collect(hopper_input_facing)) dirty = true; + } + } + // Insertion + if(trigger && (delay_timer_ <= 0)) { + delay_timer_ = PERIOD_OFFSET + transfer_period_ * 2; + if(try_insert(hopper_facing)) dirty = true; + } + if(dirty) markDirty(); + if(trigger && (tick_timer_ > TICK_INTERVAL)) tick_timer_ = TICK_INTERVAL; + } + } +} diff --git a/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorWasteIncinerator.java b/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorWasteIncinerator.java index 31dacff..c6e8aaa 100644 --- a/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorWasteIncinerator.java +++ b/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorWasteIncinerator.java @@ -681,18 +681,12 @@ public class BlockDecorWasteIncinerator extends BlockDecor int max_shift_slot_no = BURN_SLOT_NO-1; for(int i=1; iL_t(I%WYG+jzTdE93P3EXpm?q z`8NKYnjYd~3uKekZlp+2;u+7_G2QR?BqEp@m>D7hcSmM|h~VyEW&i*Yp%yd4%%Bm0 zIVVH}03ad|ktVDS01*LZhPxvoKtxb?#~1^diTC@B%Bd3%u_j|YgTRTTJoy>^VMermwXeOXpA z6VKm8iSJ-5Xqcw^OYoqE=>RpH3C)?rqN5pgCvPV~o)WA_A)VA*ec3 z`!W-!(+Na`*XspUZI$~nvu_)#uSIydT>7`Iwf=ysxLN=aX`i>-tpOG2?)^XZHzpz+ z$I;*l+O1V^*)y{~>wZ}vX2x2pi&rzS*6M+)Sy2ET3;;D7{|!!&S38**Dk4~G{rdB} gntiAuqO%v-4XP)>Q?Z)+b#oYm@wX&`&5kYGW z5#j6WYs9tI9s&S=e}CL=H`a9pV87oJ5t!MaFf)FCf4Sf9qph4$A|h~i4u=D!6jYU3 zE3Gxm3=ttBNGT1m*4jhB-8r33BdA|hMO8^D0pRWx#Q$X58<0L}bkVnPi@4cDo&=6wK`5K@U__wrvC8d_E6cRpod*zVtp#(}N-+5E0Jj z^VqVEDI)B4J8G@;LeE|R8F%ON z^K;Od8SYN*JO51J?i`OtR24HDKDhfBbEn9CZJ*tKe}5mMs!Gn8x3{;kT-}G168~uE VW7bFI<=p@P002ovPDHLkV1lO-?R@|M literal 0 HcmV?d00001 diff --git a/1.12/src/main/resources/assets/engineersdecor/textures/blocks/device/factory_hopper_side.png b/1.12/src/main/resources/assets/engineersdecor/textures/blocks/device/factory_hopper_side.png new file mode 100644 index 0000000000000000000000000000000000000000..d88e148038222d1ea3ac5726b9cd9048d515427e GIT binary patch literal 524 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 CD&Two literal 0 HcmV?d00001 diff --git a/1.14/gradle.properties b/1.14/gradle.properties index 3eadd2d..7a91189 100644 --- a/1.14/gradle.properties +++ b/1.14/gradle.properties @@ -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.31 +version_forge_minecraft=1.14.4-28.1.44 version_fml_mappings=20190719-1.14.3 version_jei=1.14.4:6.0.0.10 version_engineersdecor=1.0.13-b3 diff --git a/1.14/readme.md b/1.14/readme.md index 3d4fd73..e01a9ba 100644 --- a/1.14/readme.md +++ b/1.14/readme.md @@ -11,8 +11,10 @@ Mod sources for Minecraft version 1.14.4. ## Version history - ~ v1.0.13-b3 [U] Updated to Forge 1.14.4-28.1.31/20190719-1.14.3. + ~ v1.0.13-b3 [U] Updated to Forge 1.14.4-28.1.40/20190719-1.14.3. + [A] Factory Hopper added (configurable hopper and item collector). [M] Switched to integrated loot table generation. + [M] Lang file zh_cn updated (scikirbypoke, PR#53). - v1.0.13-b2 [A] Added Steel Mesh Fence. [A] Added Broad Window Sill. diff --git a/1.14/src/main/java/wile/engineersdecor/ModContent.java b/1.14/src/main/java/wile/engineersdecor/ModContent.java index a2c3498..c6baa82 100644 --- a/1.14/src/main/java/wile/engineersdecor/ModContent.java +++ b/1.14/src/main/java/wile/engineersdecor/ModContent.java @@ -362,6 +362,12 @@ public class ModContent ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,15) )).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "factory_dropper")); + public static final BlockDecorHopper FACTORY_HOPPER = (BlockDecorHopper)(new BlockDecorHopper( + BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_REDSTONE_CONTROLLED, + Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL), + ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16) + )).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "factory_hopper")); + public static final BlockDecorWasteIncinerator SMALL_WASTE_INCINERATOR = (BlockDecorWasteIncinerator)(new BlockDecorWasteIncinerator( BlockDecor.CFG_DEFAULT|BlockDecor.CFG_ELECTRICAL, Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL), @@ -523,6 +529,7 @@ public class ModContent }; private static final Block devBlocks[] = { + FACTORY_HOPPER, STRAIGHT_CHECK_VALVE, STRAIGHT_REDSTONE_VALVE, STRAIGHT_REDSTONE_ANALOG_VALVE, @@ -553,6 +560,11 @@ public class ModContent .build(null) .setRegistryName(ModEngineersDecor.MODID, "te_factory_dropper"); + public static final TileEntityType TET_FACTORY_HOPPER = TileEntityType.Builder + .create(BlockDecorHopper.BTileEntity::new, FACTORY_HOPPER) + .build(null) + .setRegistryName(ModEngineersDecor.MODID, "te_factory_hopper"); + public static final TileEntityType TET_WASTE_INCINERATOR = TileEntityType.Builder .create(BlockDecorWasteIncinerator.BTileEntity::new, SMALL_WASTE_INCINERATOR) .build(null) @@ -583,6 +595,7 @@ public class ModContent TET_TREATED_WOOD_CRAFTING_TABLE, TET_SMALL_LAB_FURNACE, TET_FACTORY_DROPPER, + TET_FACTORY_HOPPER, TET_SMALL_ELECTRICAL_FURNACE, TET_WASTE_INCINERATOR, TET_STRAIGHT_PIPE_VALVE, @@ -614,6 +627,7 @@ public class ModContent public static final ContainerType CT_TREATED_WOOD_CRAFTING_TABLE; public static final ContainerType CT_FACTORY_DROPPER; + public static final ContainerType CT_FACTORY_HOPPER; public static final ContainerType CT_SMALL_LAB_FURNACE; public static final ContainerType CT_SMALL_ELECTRICAL_FURNACE; public static final ContainerType CT_WASTE_INCINERATOR; @@ -623,6 +637,8 @@ public class ModContent CT_TREATED_WOOD_CRAFTING_TABLE.setRegistryName(ModEngineersDecor.MODID,"ct_treated_wood_crafting_table"); CT_FACTORY_DROPPER = (new ContainerType(BlockDecorDropper.BContainer::new)); CT_FACTORY_DROPPER.setRegistryName(ModEngineersDecor.MODID,"ct_factory_dropper"); + CT_FACTORY_HOPPER = (new ContainerType(BlockDecorHopper.BContainer::new)); + CT_FACTORY_HOPPER.setRegistryName(ModEngineersDecor.MODID,"ct_factory_hopper"); CT_SMALL_LAB_FURNACE = (new ContainerType(BlockDecorFurnace.BContainer::new)); CT_SMALL_LAB_FURNACE.setRegistryName(ModEngineersDecor.MODID,"ct_small_lab_furnace"); CT_SMALL_ELECTRICAL_FURNACE = (new ContainerType(BlockDecorFurnaceElectrical.BContainer::new)); @@ -635,6 +651,7 @@ public class ModContent private static final ContainerType container_types[] = { CT_TREATED_WOOD_CRAFTING_TABLE, CT_FACTORY_DROPPER, + CT_FACTORY_HOPPER, CT_SMALL_LAB_FURNACE, CT_SMALL_ELECTRICAL_FURNACE, CT_WASTE_INCINERATOR @@ -716,6 +733,7 @@ public class ModContent { ScreenManager.registerFactory(CT_TREATED_WOOD_CRAFTING_TABLE, BlockDecorCraftingTable.BGui::new); ScreenManager.registerFactory(CT_FACTORY_DROPPER, BlockDecorDropper.BGui::new); + ScreenManager.registerFactory(CT_FACTORY_HOPPER, BlockDecorHopper.BGui::new); ScreenManager.registerFactory(CT_SMALL_LAB_FURNACE, BlockDecorFurnace.BGui::new); ScreenManager.registerFactory(CT_SMALL_ELECTRICAL_FURNACE, BlockDecorFurnaceElectrical.BGui::new); ScreenManager.registerFactory(CT_WASTE_INCINERATOR, BlockDecorWasteIncinerator.BGui::new); diff --git a/1.14/src/main/java/wile/engineersdecor/blocks/BlockDecorDropper.java b/1.14/src/main/java/wile/engineersdecor/blocks/BlockDecorDropper.java index e5e8d25..8f2a1f3 100644 --- a/1.14/src/main/java/wile/engineersdecor/blocks/BlockDecorDropper.java +++ b/1.14/src/main/java/wile/engineersdecor/blocks/BlockDecorDropper.java @@ -164,6 +164,21 @@ public class BlockDecorDropper extends BlockDecorDirected ((BTileEntity)te).block_updated(); } + @Override + @SuppressWarnings("deprecation") + public boolean canProvidePower(BlockState state) + { return true; } + + @Override + @SuppressWarnings("deprecation") + public int getWeakPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side) + { return 0; } + + @Override + @SuppressWarnings("deprecation") + public int getStrongPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side) + { return 0; } + //-------------------------------------------------------------------------------------------------------------------- // Tile entity //-------------------------------------------------------------------------------------------------------------------- diff --git a/1.14/src/main/java/wile/engineersdecor/blocks/BlockDecorFurnace.java b/1.14/src/main/java/wile/engineersdecor/blocks/BlockDecorFurnace.java index 238cca7..786075c 100644 --- a/1.14/src/main/java/wile/engineersdecor/blocks/BlockDecorFurnace.java +++ b/1.14/src/main/java/wile/engineersdecor/blocks/BlockDecorFurnace.java @@ -8,6 +8,7 @@ */ package wile.engineersdecor.blocks; +import net.minecraftforge.common.ForgeHooks; import wile.engineersdecor.ModContent; import wile.engineersdecor.ModEngineersDecor; import wile.engineersdecor.detail.ExtItems; @@ -671,9 +672,8 @@ public class BlockDecorFurnace extends BlockDecorDirected public static int getFuelBurntime(World world, ItemStack stack) { if(stack.isEmpty()) return 0; - Item item = stack.getItem(); - int t = stack.getBurnTime(); - return net.minecraftforge.event.ForgeEventFactory.getItemBurnTime(stack, (t>=0) ? t : AbstractFurnaceTileEntity.getBurnTimes().getOrDefault(item, 0)); + int t = ForgeHooks.getBurnTime(stack); + return (t<0) ? 0 : t; } public static boolean isFuel(World world, ItemStack stack) diff --git a/1.14/src/main/java/wile/engineersdecor/blocks/BlockDecorHopper.java b/1.14/src/main/java/wile/engineersdecor/blocks/BlockDecorHopper.java new file mode 100644 index 0000000..d6099f2 --- /dev/null +++ b/1.14/src/main/java/wile/engineersdecor/blocks/BlockDecorHopper.java @@ -0,0 +1,879 @@ +/* + * @file BlockDecorHopper.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2019 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Hopper, factory automation suitable. + */ +package wile.engineersdecor.blocks; + +import wile.engineersdecor.ModContent; +import wile.engineersdecor.ModEngineersDecor; +import wile.engineersdecor.detail.Networking; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.World; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.HopperBlock; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.tileentity.HopperTileEntity; +import net.minecraft.tileentity.ITickableTileEntity; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.*; +import net.minecraft.inventory.*; +import net.minecraft.inventory.container.INamedContainerProvider; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.Slot; +import net.minecraft.util.*; +import net.minecraft.util.math.*; +import net.minecraft.util.text.*; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.client.gui.screen.inventory.ContainerScreen; +import net.minecraftforge.fml.network.NetworkHooks; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.wrapper.SidedInvWrapper; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import com.mojang.blaze3d.platform.GlStateManager; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + + +public class BlockDecorHopper extends BlockDecorDirected +{ + public BlockDecorHopper(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB) + { super(config, builder, unrotatedAABB); } + + @Override + @SuppressWarnings("deprecation") + public boolean hasComparatorInputOverride(BlockState state) + { return true; } + + @Override + @SuppressWarnings("deprecation") + public int getComparatorInputOverride(BlockState blockState, World world, BlockPos pos) + { return Container.calcRedstone(world.getTileEntity(pos)); } + + @Override + public boolean hasTileEntity(BlockState state) + { return true; } + + @Override + @Nullable + public TileEntity createTileEntity(BlockState state, IBlockReader world) + { return new BlockDecorHopper.BTileEntity(); } + + @Override + public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) + { + if(world.isRemote) return; + if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return; + CompoundNBT te_nbt = stack.getTag().getCompound("tedata"); + if(te_nbt.isEmpty()) return; + final TileEntity te = world.getTileEntity(pos); + if(!(te instanceof BTileEntity)) return; + ((BTileEntity)te).readnbt(te_nbt, false); + ((BTileEntity)te).reset_rtstate(); + ((BTileEntity)te).markDirty(); + } + + @Override + public boolean hasDynamicDropList() + { return true; } + + @Override + public List dropList(BlockState state, World world, BlockPos pos, boolean explosion) + { + final List stacks = new ArrayList(); + if(world.isRemote) return stacks; + final TileEntity te = world.getTileEntity(pos); + if(!(te instanceof BTileEntity)) return stacks; + if(!explosion) { + ItemStack stack = new ItemStack(this, 1); + CompoundNBT te_nbt = ((BTileEntity)te).clear_getnbt(); + if(!te_nbt.isEmpty()) { + CompoundNBT nbt = new CompoundNBT(); + nbt.put("tedata", te_nbt); + stack.setTag(nbt); + } + stacks.add(stack); + } else { + for(ItemStack stack: ((BTileEntity)te).stacks_) { + if(!stack.isEmpty()) stacks.add(stack); + } + ((BTileEntity)te).reset_rtstate(); + } + return stacks; + } + + @Override + @SuppressWarnings("deprecation") + public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult) + { + if(world.isRemote) return true; + final TileEntity te = world.getTileEntity(pos); + if(!(te instanceof BTileEntity)) return true; + if((!(player instanceof ServerPlayerEntity) && (!(player instanceof FakePlayer)))) return true; + NetworkHooks.openGui((ServerPlayerEntity)player,(INamedContainerProvider)te); + return true; + } + + @Override + @SuppressWarnings("deprecation") + public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused) + { + if(!(world instanceof World) || (((World) world).isRemote)) return; + TileEntity te = world.getTileEntity(pos); + if(!(te instanceof BTileEntity)) return; + ((BTileEntity)te).block_updated(); + } + + @Override + public void onFallenUpon(World world, BlockPos pos, Entity entity, float fallDistance) + { + super.onFallenUpon(world, pos, entity, fallDistance); + if(!(entity instanceof ItemEntity)) return; + TileEntity te = world.getTileEntity(pos); + if(!(te instanceof BTileEntity)) return; + ((BTileEntity)te).collection_timer_ = 0; + } + + @Override + @SuppressWarnings("deprecation") + public boolean canProvidePower(BlockState state) + { return true; } + + @Override + @SuppressWarnings("deprecation") + public int getWeakPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side) + { return 0; } + + @Override + @SuppressWarnings("deprecation") + public int getStrongPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side) + { return 0; } + + //-------------------------------------------------------------------------------------------------------------------- + // Tile entity + //-------------------------------------------------------------------------------------------------------------------- + + public static class BTileEntity extends TileEntity implements ITickableTileEntity, INameable, IInventory, INamedContainerProvider, ISidedInventory + { + public static final int NUM_OF_FIELDS = 7; + public static final int TICK_INTERVAL = 10; + public static final int COLLECTION_INTERVAL = 50; + public static final int NUM_OF_SLOTS = 18; + public static final int MAX_TRANSFER_COUNT = 32; + public static final int MAX_COLLECTION_RANGE = 4; + public static final int PERIOD_OFFSET = 10; + /// + public static final int LOGIC_INVERTED = 0x01; + public static final int LOGIC_CONTINUOUS = 0x02; + /// + private boolean block_power_signal_ = false; + private boolean block_power_updated_ = false; + private int collection_timer_ = 0; + private int delay_timer_ = 0; + private int transfer_count_ = 1; + private int logic_ = LOGIC_INVERTED|LOGIC_CONTINUOUS; + private int transfer_period_ = 0; + private int collection_range_ = 0; + private int current_slot_index_ = 0; + private int tick_timer_ = 0; + protected NonNullList stacks_; + + public static void on_config(int cooldown_ticks) + { + // ModEngineersDecor.logger.info("Config factory hopper:"); + } + + public BTileEntity() + { + this(ModContent.TET_FACTORY_HOPPER); + stacks_ = NonNullList.withSize(NUM_OF_SLOTS, ItemStack.EMPTY); + reset_rtstate(); + } + + public BTileEntity(TileEntityType te_type) + { + super(te_type); + stacks_ = NonNullList.withSize(NUM_OF_SLOTS, ItemStack.EMPTY); + reset_rtstate(); + } + + public void reset_rtstate() + { + block_power_signal_ = false; + block_power_updated_ = false; + } + + public CompoundNBT clear_getnbt() + { + CompoundNBT nbt = new CompoundNBT(); + block_power_signal_ = false; + writenbt(nbt, false); + for(int i=0; iwithSize(NUM_OF_SLOTS, ItemStack.EMPTY); + ItemStackHelper.loadAllItems(nbt, stacks_); + while(stacks_.size() < NUM_OF_SLOTS) stacks_.add(ItemStack.EMPTY); + block_power_signal_ = nbt.getBoolean("powered"); + current_slot_index_ = nbt.getInt("act_slot_index"); + transfer_count_ = MathHelper.clamp(nbt.getInt("xsize"), 1, MAX_TRANSFER_COUNT); + logic_ = nbt.getInt("logic"); + transfer_period_ = nbt.getInt("period"); + collection_range_ = nbt.getInt("range"); + } + + protected void writenbt(CompoundNBT nbt, boolean update_packet) + { + ItemStackHelper.saveAllItems(nbt, stacks_); + nbt.putBoolean("powered", block_power_signal_); + nbt.putInt("act_slot_index", current_slot_index_); + nbt.putInt("xsize", transfer_count_); + nbt.putInt("logic", logic_); + nbt.putInt("period", transfer_period_); + nbt.putInt("range", collection_range_); + } + + public void block_updated() + { + // RS power check, both edges + boolean powered = world.isBlockPowered(pos); + if(block_power_signal_ != powered) block_power_updated_ = true; + block_power_signal_ = powered; + tick_timer_ = 1; + } + + public boolean is_input_slot(int index) + { return (index >= 0) && (index < NUM_OF_SLOTS); } + + // TileEntity -------------------------------------------------------------------------------------------- + + @Override + public void read(CompoundNBT nbt) + { super.read(nbt); readnbt(nbt, false); } + + @Override + public CompoundNBT write(CompoundNBT nbt) + { super.write(nbt); writenbt(nbt, false); return nbt; } + + // INamable ---------------------------------------------------------------------------------------------- + + @Override + public ITextComponent getName() + { final Block block=getBlockState().getBlock(); return new StringTextComponent((block!=null) ? block.getTranslationKey() : "Factory Hopper"); } + + @Override + public boolean hasCustomName() + { return false; } + + @Override + public ITextComponent getCustomName() + { return getName(); } + + // INamedContainerProvider ------------------------------------------------------------------------------ + + @Override + public ITextComponent getDisplayName() + { return INameable.super.getDisplayName(); } + + @Override + public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player ) + { return new BContainer(id, inventory, this, IWorldPosCallable.of(world, pos), fields); } + + // IInventory -------------------------------------------------------------------------------------------- + + @Override + public int getSizeInventory() + { return stacks_.size(); } + + @Override + public boolean isEmpty() + { for(ItemStack stack: stacks_) { if(!stack.isEmpty()) return false; } return true; } + + @Override + public ItemStack getStackInSlot(int index) + { return (index < stacks_.size()) ? stacks_.get(index) : ItemStack.EMPTY; } + + @Override + public ItemStack decrStackSize(int index, int count) + { return ItemStackHelper.getAndSplit(stacks_, index, count); } + + @Override + public ItemStack removeStackFromSlot(int index) + { return ItemStackHelper.getAndRemove(stacks_, index); } + + @Override + public void setInventorySlotContents(int index, ItemStack stack) + { + stacks_.set(index, stack); + if(stack.getCount() > getInventoryStackLimit()) stack.setCount(getInventoryStackLimit()); + if(tick_timer_ > 8) tick_timer_ = 8; + markDirty(); + } + + @Override + public int getInventoryStackLimit() + { return 64; } + + @Override + public void markDirty() + { super.markDirty(); } + + @Override + public boolean isUsableByPlayer(PlayerEntity player) + { return getPos().distanceSq(player.getPosition()) < 36; } + + @Override + public void openInventory(PlayerEntity player) + {} + + @Override + public void closeInventory(PlayerEntity player) + { markDirty(); } + + @Override + public boolean isItemValidForSlot(int index, ItemStack stack) + { return true; } + + @Override + public void clear() + { stacks_.clear(); } + + // Fields ----------------------------------------------------------------------------------------------- + + protected final IIntArray fields = new IntArray(BTileEntity.NUM_OF_FIELDS) + { + @Override + public int get(int id) + { + switch(id) { + case 0: return collection_range_; + case 1: return transfer_count_; + case 2: return logic_; + case 3: return transfer_period_; + case 4: return delay_timer_; + case 5: return block_power_signal_ ? 1 : 0; + case 6: return current_slot_index_; + default: return 0; + } + } + @Override + public void set(int id, int value) + { + switch(id) { + case 0: collection_range_ = MathHelper.clamp(value,0, MAX_COLLECTION_RANGE); return; + case 1: transfer_count_ = MathHelper.clamp(value,1, MAX_TRANSFER_COUNT); return; + case 2: logic_ = value; return; + case 3: transfer_period_ = MathHelper.clamp(value,0, 100); return; + case 4: delay_timer_ = MathHelper.clamp(value,0, 400); return; + case 5: block_power_signal_ = (value != 0); return; + case 6: current_slot_index_ = MathHelper.clamp(value, 0, NUM_OF_SLOTS-1); return; + default: return; + } + } + }; + + // ISidedInventory -------------------------------------------------------------------------------------- + + LazyOptional[] item_handlers = SidedInvWrapper.create(this, Direction.UP); + private static final int[] SIDED_INV_SLOTS; + static { + SIDED_INV_SLOTS = new int[NUM_OF_SLOTS]; + for(int i=0; i LazyOptional getCapability(net.minecraftforge.common.capabilities.Capability capability, @Nullable Direction facing) + { + if(!this.removed && (facing != null)) { + if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return item_handlers[0].cast(); + } + return super.getCapability(capability, facing); + } + + // ITickable and aux methods --------------------------------------------------------------------- + + private static int next_slot(int i) + { return (i= n_to_insert) { + slotstack.grow(n_to_insert); + n_to_insert = 0; + break; + } else { + slotstack.grow(nspace); + n_to_insert -= nspace; + } + } + if((n_to_insert > 0) && (first_empty_slot >= 0)) { + ItemStack new_stack = stack.copy(); + new_stack.setCount(n_to_insert); + stacks_.set(first_empty_slot, new_stack); + n_to_insert = 0; + } + return max_to_insert - n_to_insert; + } + + private boolean try_insert(Direction facing) + { + ItemStack current_stack = ItemStack.EMPTY; + for(int i=0; i= NUM_OF_SLOTS) current_slot_index_ = 0; + current_stack = stacks_.get(current_slot_index_); + if(!current_stack.isEmpty()) break; + current_slot_index_ = next_slot(current_slot_index_); + } + if(current_stack.isEmpty()) { + current_slot_index_ = 0; + return false; + } + final TileEntity te = world.getTileEntity(pos.offset(facing)); + if(te == null) { delay_timer_ = TICK_INTERVAL+2; return false; } // no reason to recalculate this all the time if there is nothere to insert. + final IItemHandler ih = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite()).orElse(null); + if(ih == null) { delay_timer_ = TICK_INTERVAL+2; return false; } + if(te instanceof HopperTileEntity) { + Direction f = world.getBlockState(pos.offset(facing)).get(HopperBlock.FACING); + if(f==facing.getOpposite()) return false; // no back transfer + } else if(te instanceof BTileEntity) { + Direction f = world.getBlockState(pos.offset(facing)).get(FACING); + if(f==facing.getOpposite()) return false; + } + ItemStack insert_stack = current_stack.copy(); + if(insert_stack.getCount() > transfer_count_) insert_stack.setCount(transfer_count_); + final int initial_insert_stack_size = insert_stack.getCount(); + int first_empty_slot_index = -1; + if((ih == null) || ih.getSlots() <= 0) return false; + for(int i=0; i= 0) && (!insert_stack.isEmpty())) { + insert_stack = ih.insertItem(first_empty_slot_index, insert_stack.copy(), false); + } + final int num_inserted = initial_insert_stack_size-insert_stack.getCount(); + if(num_inserted > 0) { + current_stack.shrink(num_inserted); + stacks_.set(current_slot_index_, current_stack); + } + if(!insert_stack.isEmpty()) current_slot_index_ = next_slot(current_slot_index_); + if(num_inserted == 0) { + delay_timer_ += transfer_period_ * 2; + return false; + } else { + return true; + } + } + + private boolean try_item_handler_extract(final IItemHandler ih) + { + final int end = ih.getSlots(); + int n_to_extract = transfer_count_; + for(int i=0; i 0) { + ItemStack test = ih.extractItem(i, n_accepted, false); + n_to_extract -= n_accepted; + if(n_to_extract <= 0) break; + } + } + return (n_to_extract < transfer_count_); + } + + private boolean try_inventory_extract(final IInventory inv) + { + final int end = inv.getSizeInventory(); + int n_to_extract = transfer_count_; + for(int i=0; i 0) { + stack.shrink(n_accepted); + n_to_extract -= n_accepted; + if(stack.isEmpty()) stack = ItemStack.EMPTY; + inv.setInventorySlotContents(i, stack); + if(n_to_extract <= 0) break; + } + } + if(n_to_extract < transfer_count_) { + inv.markDirty(); + return true; + } else { + return false; + } + } + + private boolean try_collect(Direction facing) + { + AxisAlignedBB collection_volume; + Vec3d rpos; + if(facing==EnumFacing.UP) { + rpos = new Vec3d(0.5+pos.getX(),1.5+pos.getY(),0.5+pos.getZ()); + collection_volume = (new AxisAlignedBB(pos.up())).grow(0.1+collection_range_, 0.5, 0.1+collection_range_); + } else { + rpos = new Vec3d(0.5+pos.getX(),-1.5+pos.getY(),0.5+pos.getZ()); + collection_volume = (new AxisAlignedBB(pos.down())).grow(0.1+collection_range_, 0.5, 0.1+collection_range_); + } + final List items = world.getEntitiesWithinAABB(ItemEntity.class, collection_volume); + if(items.size() <= 0) return false; + final int max_to_collect = 3; + int n_collected = 0; + for(ItemEntity ie:items) { + if((!ie.onGround) || (ie.cannotPickup() && ie.getDistanceSq(rpos)>=0.7)) continue; + ItemStack stack = ie.getItem(); + int n_accepted = try_insert_into_hopper(stack); + if(n_accepted <= 0) continue; + if(n_accepted == stack.getCount()) { + ie.remove(); + } else { + stack.shrink(n_accepted); + } + if(++n_collected >= max_to_collect) break; + } + return (n_collected > 0); + } + + @Override + public void tick() + { + // Tick cycle pre-conditions + if(world.isRemote) return; + if((delay_timer_ > 0) && ((--delay_timer_) == 0)) markDirty(); + if(--tick_timer_ > 0) return; + tick_timer_ = TICK_INTERVAL; + // Cycle init + boolean dirty = block_power_updated_; + final boolean rssignal = ((logic_ & LOGIC_INVERTED)!=0)==(!block_power_signal_); + final boolean pulse_mode = ((logic_ & LOGIC_CONTINUOUS)==0); + boolean trigger = (rssignal && ((block_power_updated_) || (!pulse_mode))); + final BlockState state = world.getBlockState(pos); + if(state == null) { block_power_signal_= false; return; } + final Direction hopper_facing = state.get(FACING); + // Trigger edge detection for next cycle + { + boolean tr = world.isBlockPowered(pos); + block_power_updated_ = (block_power_signal_ != tr); + block_power_signal_ = tr; + if(block_power_updated_) dirty = true; + } + // Collection + if(rssignal || pulse_mode) { + Direction hopper_input_facing = (hopper_facing==Direction.UP) ? Direction.DOWN : Direction.UP; + TileEntity te = world.getTileEntity(pos.offset(hopper_input_facing)); + final IItemHandler ih = (te==null) ? (null) : (te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, hopper_input_facing.getOpposite()).orElse(null)); + if((ih != null) || (te instanceof ISidedInventory)) { + // IItemHandler pulling + if((ih != null)) { + if(try_item_handler_extract(ih)) dirty = true; + } else { + if(try_inventory_extract((IInventory)te)) dirty = true; + } + } else if((collection_timer_ -= TICK_INTERVAL) <= 0) { + // Ranged collection + collection_timer_ = COLLECTION_INTERVAL; + if(try_collect(hopper_input_facing)) dirty = true; + } + } + // Insertion + if(trigger && (delay_timer_ <= 0)) { + delay_timer_ = PERIOD_OFFSET + transfer_period_ * 2; + if(try_insert(hopper_facing)) dirty = true; + } + if(dirty) markDirty(); + if(trigger && (tick_timer_ > TICK_INTERVAL)) tick_timer_ = TICK_INTERVAL; + } + } + + //-------------------------------------------------------------------------------------------------------------------- + // container + //-------------------------------------------------------------------------------------------------------------------- + + public static class BContainer extends Container implements Networking.INetworkSynchronisableContainer + { + private static final int PLAYER_INV_START_SLOTNO = BTileEntity.NUM_OF_SLOTS; + private final PlayerEntity player_; + private final IInventory inventory_; + private final IWorldPosCallable wpc_; + private final IIntArray fields_; + + public final int field(int index) { return fields_.get(index); } + + public BContainer(int cid, PlayerInventory player_inventory) + { this(cid, player_inventory, new Inventory(BTileEntity.NUM_OF_SLOTS), IWorldPosCallable.DUMMY, new IntArray(BTileEntity.NUM_OF_FIELDS)); } + + private BContainer(int cid, PlayerInventory player_inventory, IInventory block_inventory, IWorldPosCallable wpc, IIntArray fields) + { + super(ModContent.CT_FACTORY_HOPPER, cid); + fields_ = fields; + wpc_ = wpc; + player_ = player_inventory.player; + inventory_ = block_inventory; + int i=-1; + // input slots (stacks 0 to 17) + for(int y=0; y<3; ++y) { + for(int x=0; x<6; ++x) { + int xpos = 11+x*18, ypos = 9+y*17; + addSlot(new Slot(inventory_, ++i, xpos, ypos)); + } + } + // player slots + for(int x=0; x<9; ++x) { + addSlot(new Slot(player_inventory, x, 8+x*18, 129)); // player slots: 0..8 + } + for(int y=0; y<3; ++y) { + for(int x=0; x<9; ++x) { + addSlot(new Slot(player_inventory, x+y*9+9, 8+x*18, 71+y*18)); // player slots: 9..35 + } + } + this.trackIntArray(fields_); // === Add reference holders + } + + @Override + public boolean canInteractWith(PlayerEntity player) + { return inventory_.isUsableByPlayer(player); } + + @Override + public ItemStack transferStackInSlot(PlayerEntity player, int index) + { + Slot slot = getSlot(index); + if((slot==null) || (!slot.getHasStack())) return ItemStack.EMPTY; + ItemStack slot_stack = slot.getStack(); + ItemStack transferred = slot_stack.copy(); + if((index>=0) && (index= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) { + // Player slot + if(!mergeItemStack(slot_stack, 0, BTileEntity.NUM_OF_SLOTS, false)) return ItemStack.EMPTY; + } else { + // invalid slot + return ItemStack.EMPTY; + } + if(slot_stack.isEmpty()) { + slot.putStack(ItemStack.EMPTY); + } else { + slot.onSlotChanged(); + } + if(slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY; + slot.onTake(player, slot_stack); + return transferred; + } + + // INetworkSynchronisableContainer --------------------------------------------------------- + + @OnlyIn(Dist.CLIENT) + public void onGuiAction(CompoundNBT nbt) + { Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); } + + @OnlyIn(Dist.CLIENT) + public void onGuiAction(String key, int value) + { + CompoundNBT nbt = new CompoundNBT(); + nbt.putInt(key, value); + Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); + } + + @Override + public void onServerPacketReceived(int windowId, CompoundNBT nbt) + {} + + @Override + public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt) + { + if(!(inventory_ instanceof BTileEntity)) return; + BTileEntity te = (BTileEntity)inventory_; + if(nbt.contains("xsize")) te.transfer_count_ = MathHelper.clamp(nbt.getInt("xsize"), 1, BTileEntity.MAX_TRANSFER_COUNT); + if(nbt.contains("period")) te.transfer_period_ = MathHelper.clamp(nbt.getInt("period"), 0, 100); + if(nbt.contains("range")) te.collection_range_ = MathHelper.clamp(nbt.getInt("range"), 0, BTileEntity.MAX_COLLECTION_RANGE); + if(nbt.contains("logic")) te.logic_ = nbt.getInt("logic"); + if(nbt.contains("manual_trigger") && (nbt.getInt("manual_trigger")!=0)) { te.block_power_signal_=true; te.block_power_updated_=true; te.tick_timer_=1; } + te.markDirty(); + } + + } + + //-------------------------------------------------------------------------------------------------------------------- + // GUI + //-------------------------------------------------------------------------------------------------------------------- + + @OnlyIn(Dist.CLIENT) + public static class BGui extends ContainerScreen + { + protected final PlayerEntity player_; + + public BGui(BContainer container, PlayerInventory player_inventory, ITextComponent title) + { super(container, player_inventory, title); this.player_ = player_inventory.player; } + + @Override + public void init() + { super.init(); } + + @Override + public void render(int mouseX, int mouseY, float partialTicks) + { + renderBackground(); + super.render(mouseX, mouseY, partialTicks); + renderHoveredToolTip(mouseX, mouseY); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) + { + BContainer container = (BContainer)getContainer(); + int mx = (int)(mouseX - getGuiLeft() + .5), my = (int)(mouseY - getGuiTop() + .5); + if((!isPointInRegion(126, 1, 49, 60, mouseX, mouseY))) { + return super.mouseClicked(mouseX, mouseY, mouseButton); + } else if(isPointInRegion(128, 9, 44, 10, mouseX, mouseY)) { + int range = (mx-133); + if(range < -1) { + range = container.field(0) - 1; // - + } else if(range >= 34) { + range = container.field(0) + 1; // + + } else { + range = (int)(0.5 + ((((double)BTileEntity.MAX_COLLECTION_RANGE) * range)/34)); // slider + range = MathHelper.clamp(range, 0, BTileEntity.MAX_COLLECTION_RANGE); + } + container.onGuiAction("range", range); + } else if(isPointInRegion(128, 21, 44, 10, mouseX, mouseY)) { + int period = (mx-133); + if(period < -1) { + period = container.field(3) - 3; // - + } else if(period >= 35) { + period = container.field(3) + 3; // + + } else { + period = (int)(0.5 + ((100.0 * period)/34)); + } + period = MathHelper.clamp(period, 0, 100); + container.onGuiAction("period", period); + } else if(isPointInRegion(128, 34, 44, 10, mouseX, mouseY)) { + int ndrop = (mx-134); + if(ndrop < -1) { + ndrop = container.field(1) - 1; // - + } else if(ndrop >= 34) { + ndrop = container.field(1) + 1; // + + } else { + ndrop = MathHelper.clamp(1+ndrop, 1, BTileEntity.MAX_TRANSFER_COUNT); // slider + } + container.onGuiAction("xsize", ndrop); + } else if(isPointInRegion(133, 49, 9, 9, mouseX, mouseY)) { + container.onGuiAction("manual_trigger", 1); + } else if(isPointInRegion(145, 49, 9, 9, mouseX, mouseY)) { + container.onGuiAction("logic", container.field(2) ^ BTileEntity.LOGIC_INVERTED); + } else if(isPointInRegion(159, 49, 7, 9, mouseX, mouseY)) { + container.onGuiAction("logic", container.field(2) ^ BTileEntity.LOGIC_CONTINUOUS); + } + return true; + } + + @Override + protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) + { + GlStateManager.color4f(1f, 1f, 1f, 1f); + this.minecraft.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/factory_hopper_gui.png")); + final int x0=getGuiLeft(), y0=getGuiTop(), w=getXSize(), h=getYSize(); + blit(x0, y0, 0, 0, w, h); + BContainer container = (BContainer)getContainer(); + // active slot + { + int slot_index = container.field(6); + if((slot_index < 0) || (slot_index >= BTileEntity.NUM_OF_SLOTS)) slot_index = 0; + int x = (x0+10+((slot_index % 6) * 18)); + int y = (y0+8+((slot_index / 6) * 17)); + blit(x, y, 200, 8, 18, 18); + } + // collection range + { + int lut[] = { 133, 141, 149, 157, 166 }; + int px = lut[MathHelper.clamp(container.field(0), 0, BTileEntity.MAX_COLLECTION_RANGE)]; + int x = x0 + px - 2; + int y = y0 + 14; + blit(x, y, 179, 40, 5, 5); + } + // transfer period + { + int px = (int)Math.round(((33.5 * container.field(3)) / 100) + 1); + int x = x0 + 132 - 2 + MathHelper.clamp(px, 0, 34); + int y = y0 + 27; + blit(x, y, 179, 40, 5, 5); + } + // transfer count + { + int x = x0 + 133 - 2 + (container.field(1)); + int y = y0 + 40; + blit(x, y, 179, 40, 5, 5); + } + // redstone input + { + if(container.field(5) != 0) { + blit(x0+133, y0+49, 217, 49, 9, 9); + } + } + // trigger logic + { + int inverter_offset = ((container.field(2) & BTileEntity.LOGIC_INVERTED) != 0) ? 11 : 0; + blit(x0+145, y0+49, 177+inverter_offset, 49, 9, 9); + int pulse_mode_offset = ((container.field(2) & BTileEntity.LOGIC_CONTINUOUS ) != 0) ? 9 : 0; + blit(x0+159, y0+49, 199+pulse_mode_offset, 49, 9, 9); + } + // delay timer running indicator + { + if((container.field(4) > BTileEntity.PERIOD_OFFSET) && ((System.currentTimeMillis() % 1000) < 500)) { + blit(x0+148, y0+22, 187, 22, 3, 3); + } + } + } + } + +} diff --git a/1.14/src/main/resources/assets/engineersdecor/blockstates/factory_hopper.json b/1.14/src/main/resources/assets/engineersdecor/blockstates/factory_hopper.json new file mode 100644 index 0000000..c8e41a5 --- /dev/null +++ b/1.14/src/main/resources/assets/engineersdecor/blockstates/factory_hopper.json @@ -0,0 +1,16 @@ +{ + "forge_marker": 1, + "defaults": { + "model": "engineersdecor:block/device/factory_hopper_model" + }, + "variants": { + "facing": { + "north":{"y":0}, + "south":{"y":180}, + "west":{"y":270}, + "east":{"y":90}, + "up": { "model": "engineersdecor:block/device/factory_hopper_model_up" }, + "down": { "model": "engineersdecor:block/device/factory_hopper_model_down" } + } + } +} diff --git a/1.14/src/main/resources/assets/engineersdecor/lang/en_us.json b/1.14/src/main/resources/assets/engineersdecor/lang/en_us.json index 8a109e3..e1ae1bf 100644 --- a/1.14/src/main/resources/assets/engineersdecor/lang/en_us.json +++ b/1.14/src/main/resources/assets/engineersdecor/lang/en_us.json @@ -155,6 +155,8 @@ "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.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 in the GUI. Three stack compare slots with logical AND or OR can be used as internal trigger source. 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. 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", "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. Due to the miniturized device size the process is rather inefficient - much time and energy is needed to liquefy a stone block.", "block.engineersdecor.small_solar_panel": "Small Solar Panel", @@ -172,8 +174,9 @@ "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": "§6There's the door, please ...", + "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", diff --git a/1.14/src/main/resources/assets/engineersdecor/lang/ru_ru.json b/1.14/src/main/resources/assets/engineersdecor/lang/ru_ru.json index 6e639fe..ab4689c 100644 --- a/1.14/src/main/resources/assets/engineersdecor/lang/ru_ru.json +++ b/1.14/src/main/resources/assets/engineersdecor/lang/ru_ru.json @@ -152,6 +152,7 @@ "block.engineersdecor.passive_fluid_accumulator.help": "§6Вакуумный всасывающий жидкостный коллектор.§r Имеет один выход, все остальные стороны входные. Сливает жидкости из соседних резервуаров при выкачивании жидкости из выходного порта.", "block.engineersdecor.factory_dropper": "Фабричный выбрасыватель", "block.engineersdecor.factory_dropper.help": "§6Выбрасыватель подходит для продвинутой автоматизации производства.§r Имеет 12 выборочных слотов. Сила броска, угол, размер стопки и задержка настраиваются в GUI. 3 слота сравнения стека с логическим И или ИЛИ могут использоваться в качестве внутреннего источника запуска. Внутренний триггер может быть И или ИЛИ с внешним триггерным сигналом красного камня. Триггерные кнопки симуляции для тестирования. Предварительно открывает дверцу затвора, когда выполняются условия внутреннего запуска. Сбрасывает все соответствующие стеки одновременно. Нажмите на все элементы в GUI, чтобы увидеть, как это работает.", + "block.engineersdecor.factory_hopper": "Factory Hopper", "block.engineersdecor.small_mineral_smelter": "Small Mineral Melting Furnace", "block.engineersdecor.small_solar_panel": "Small Solar Panel", "block.engineersdecor.small_tree_cutter": "Small Tree Cutter", diff --git a/1.14/src/main/resources/assets/engineersdecor/lang/zh_cn.json b/1.14/src/main/resources/assets/engineersdecor/lang/zh_cn.json index 318abf5..652efb5 100644 --- a/1.14/src/main/resources/assets/engineersdecor/lang/zh_cn.json +++ b/1.14/src/main/resources/assets/engineersdecor/lang/zh_cn.json @@ -4,133 +4,193 @@ "language.region": "China", "itemGroup.tabengineersdecor": "工程师的装饰", "engineersdecor.config.title": "工程师的装饰配置", - "engineersdecor.tooltip.hint.extended": "§6[按§9SHIFT§r获取更多信息§6]§r", - "engineersdecor.tooltip.hint.help": "§6[按§9CTRL-SHIFT§r获取帮助§6]§r", - "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": "熟料砖", - "block.engineersdecor.clinker_brick_block.help": "§6具有位置相关纹理变化的砖块.§r\n看起来比原版砖块稍暗,颜色更浓.", - "block.engineersdecor.clinker_brick_stained_block": "Stained Clinker Brick Block", - "block.engineersdecor.slag_brick_block": "炉渣砖", - "block.engineersdecor.slag_brick_block.help": "§6灰褐色砖块,具有位置相关的纹理变化.", + "engineersdecor.tooltip.hint.extended": "§6[§9SHIFT§r 查看更多信息§6]§r", + "engineersdecor.tooltip.hint.help": "§6[§9CTRL-SHIFT§r 查看帮助§6]§r", + "engineersdecor.tooltip.slabpickup.help": "§r手持同类台阶往上/下看时单击该台阶可无需破坏快速拾起。", + "engineersdecor.config.pattern_excludes": "模式不包括", + "engineersdecor.config.pattern_includes": "模式包括", + "engineersdecor.config.without_clinker_bricks": "不要过烧砖", + "engineersdecor.config.without_slag_bricks": "不要炉渣砖", + "engineersdecor.config.without_rebar_concrete": "不要强化混凝土", + "engineersdecor.config.without_walls": "不要墙", + "engineersdecor.config.without_stairs": "不要楼梯", + "engineersdecor.config.without_ie_concrete_wall": "不要混凝土墙", + "engineersdecor.config.without_panzer_glass": "不要装甲玻璃", + "engineersdecor.config.without_crafting_table": "不要合成台", + "engineersdecor.config.without_lab_furnace": "不要实验室炉", + "engineersdecor.config.without_electrical_furnace": "不要电炉", + "engineersdecor.config.without_treated_wood_furniture": "不要防腐木家具", + "engineersdecor.config.without_windows": "不要窗户", + "engineersdecor.config.without_light_sources": "不要灯", + "engineersdecor.config.without_ladders": "不要梯子", + "engineersdecor.config.without_chair_sitting": "椅子不能坐", + "engineersdecor.config.without_mob_chair_sitting": "椅子不能给其他生物坐", + "engineersdecor.config.without_ladder_speed_boost": "不要爬梯加速", + "engineersdecor.config.without_crafting_table_history": "不要合成台历史", + "engineersdecor.config.without_valves": "不要阀门", + "engineersdecor.config.without_passive_fluid_accumulator": "不要流体积累器", + "engineersdecor.config.without_waste_incinerator": "不要焚烧炉", + "engineersdecor.config.without_sign_plates": "不要标志牌", + "engineersdecor.config.without_factory_dropper": "不要工厂掉落器", + "engineersdecor.config.without_slabs": "不要台阶", + "engineersdecor.config.without_halfslabs": "不要台阶切片", + "engineersdecor.config.without_direct_slab_pickup": "不要快速捡起台阶", + "engineersdecor.config.without_poles": "不要杆", + "engineersdecor.config.without_hsupports": "不要支撑", + "engineersdecor.config.without_tooltips": "不要工具提示", + "engineersdecor.config.without_recipes": "不要配方", + "engineersdecor.config.furnace_smelting_speed_percent": "熔炉:熔炼速度 %", + "engineersdecor.config.furnace_fuel_efficiency_percent": "熔炉:燃料效率 %", + "engineersdecor.config.furnace_boost_energy_consumption": "熔炉:能量加速", + "engineersdecor.config.chair_mob_sitting_probability_percent": "椅子:坐下机率 %", + "engineersdecor.config.chair_mob_standup_probability_percent": "\"椅子:站起机率 %\"", + "engineersdecor.config.with_crafting_quickmove_buttons": "合成台:移动按钮", + "engineersdecor.config.pipevalve_max_flowrate": "阀门:最大流速", + "engineersdecor.config.pipevalve_redstone_gain": "阀门:红石斜率", + "engineersdecor.config.e_furnace_speed_percent": "电炉:熔炉速度 %", + "engineersdecor.config.e_furnace_power_consumption": "电炉:能量消耗", + "block.engineersdecor.clinker_brick_block": "过烧砖块", + "block.engineersdecor.clinker_brick_block.help": "§6一种放在不同位置贴图有不同变化的砖块。§r\n比原版砖看起来颜色更深,色度也更高。", + "block.engineersdecor.clinker_brick_stained_block": "污渍过烧砖块", + "block.engineersdecor.clinker_brick_stained_block.help": "§6一种放在不同位置贴图有不同变化的砖块。§r\n比原版砖看起来颜色更深,色度也更高。有更多可见的污垢或污迹。", + "block.engineersdecor.slag_brick_block": "炉渣砖块", + "block.engineersdecor.slag_brick_block.help": "§6一种放在不同位置贴图有不同变化的灰棕色砖块。", "block.engineersdecor.rebar_concrete": "钢筋混凝土", - "block.engineersdecor.rebar_concrete.help": "§6钢筋混凝土砌块.§r 昂贵,但像黑曜石一样防苦力怕.", - "block.engineersdecor.panzerglass_block": "Panzer Glass Block", - "block.engineersdecor.rebar_concrete_tile": "Rebar Concrete Tile", - "block.engineersdecor.clinker_brick_slab": "Clinker Brick Slab", - "block.engineersdecor.clinker_brick_stained_slab": "Stained Clinker Brick Slab", - "block.engineersdecor.slag_brick_slab": "Slag Brick Slab", - "block.engineersdecor.rebar_concrete_slab": "Rebar Concrete Slab", - "block.engineersdecor.rebar_concrete_tile_slab": "Rebar Concrete Tile Slab", - "block.engineersdecor.panzerglass_slab": "Panzer Glass Slab", - "block.engineersdecor.treated_wood_floor": "Treated Wood Floor", + "block.engineersdecor.rebar_concrete.help": "§6钢强化的混凝土。§r昂贵但像黑曜石一样防爬行者爆炸。", + "block.engineersdecor.panzerglass_block": "装甲玻璃块", + "block.engineersdecor.panzerglass_block.help": "§6强化的玻璃方块。§r昂贵,防爆。深灰色调,有隐约可见的结构线和多种纹理,外观无光泽。", + "block.engineersdecor.rebar_concrete_tile": "钢筋混凝土砖", + "block.engineersdecor.rebar_concrete_tile.help": "§6钢强化的混凝土砖。§r昂贵但像黑曜石一样防爬行者爆炸。", + "block.engineersdecor.clinker_brick_slab": "过烧砖台阶", + "block.engineersdecor.clinker_brick_slab.help": "§6过烧砖块制造的台阶。§r\n比原版砖看起来颜色更深,色度也更高。", + "block.engineersdecor.clinker_brick_stained_slab": "污渍过烧砖台阶", + "block.engineersdecor.clinker_brick_stained_slab.help": "§6污渍过烧砖块制造的台阶。", + "block.engineersdecor.slag_brick_slab": "炉渣砖台阶", + "block.engineersdecor.slag_brick_slab.help": "§6一种灰棕色砖块台阶。", + "block.engineersdecor.rebar_concrete_slab": "钢筋混凝土台阶", + "block.engineersdecor.rebar_concrete_slab.help": "§6钢强化的混凝土台阶。§r昂贵但像黑曜石一样防爬行者爆炸。", + "block.engineersdecor.rebar_concrete_tile_slab": "钢筋混凝土砖台阶", + "block.engineersdecor.rebar_concrete_tile_slab.help": "§6钢强化的混凝土砖台阶。§r昂贵但像黑曜石一样防爬行者爆炸。", + "block.engineersdecor.panzerglass_slab": "装甲玻璃台阶", + "block.engineersdecor.panzerglass_slab.help": "§6强化的玻璃台阶。§r昂贵,防爆。深灰色调,有隐约可见的结构线和多种纹理。", + "block.engineersdecor.treated_wood_floor": "防腐木地板", + "block.engineersdecor.treated_wood_floor.help": "§6装饰性地板砖,有可变的贴图。§r", "block.engineersdecor.rebar_concrete_wall": "钢筋混凝土墙", - "block.engineersdecor.rebar_concrete_wall.help": "§6钢筋混凝土墙.§r 昂贵,但像黑曜石一样防苦力怕.", - "block.engineersdecor.concrete_wall": "水泥墙", - "block.engineersdecor.concrete_wall.help": "§6墙由坚固的混凝土制成.", - "block.engineersdecor.clinker_brick_wall": "Clinker Brick Wall", - "block.engineersdecor.slag_brick_wall": "Slag Brick Wall", - "block.engineersdecor.metal_rung_ladder": "金属环梯", - "block.engineersdecor.metal_rung_ladder.help": "§6典型的工业墙梯,包括水平金属杆横档.", - "block.engineersdecor.metal_rung_steps": "交错的金属台阶", - "block.engineersdecor.metal_rung_steps.help": "§6贴在墙上的交错的杆横档,允许爬上,爬下等等.", - "block.engineersdecor.treated_wood_ladder": "经过处理的木梯", - "block.engineersdecor.treated_wood_ladder.help": "§6防风雨的木梯.", - "block.engineersdecor.clinker_brick_stairs": "熟料砖楼梯", - "block.engineersdecor.clinker_brick_stairs.help": "§6看起来比原版砖块稍暗,颜色更浓.", - "block.engineersdecor.clinker_brick_stained_stairs": "Stained Clinker Brick Stairs", + "block.engineersdecor.rebar_concrete_wall.help": "§6钢强化的混凝土墙。§r 昂贵但像黑曜石一样防爬行者爆炸。", + "block.engineersdecor.concrete_wall": "混凝土墙", + "block.engineersdecor.concrete_wall.help": "§6用坚固混凝土制造的墙。", + "block.engineersdecor.clinker_brick_wall": "过烧砖墙", + "block.engineersdecor.clinker_brick_wall.help": "§6简单的过烧砖墙。", + "block.engineersdecor.slag_brick_wall": "炉渣砖墙", + "block.engineersdecor.slag_brick_wall.help": "§6简单的炉渣砖墙。", + "block.engineersdecor.metal_rung_ladder": "金属蹬梯子", + "block.engineersdecor.metal_rung_ladder.help": "§6典型的工业墙梯,由水平的金属杆蹬组成。§r往上/下看会爬得更快。", + "block.engineersdecor.metal_rung_steps": "交错金属台阶", + "block.engineersdecor.metal_rung_steps.help": "§6贴在墙上的交错金属杆蹬,能够爬上或爬下。§r往上/下看会爬得更快。", + "block.engineersdecor.treated_wood_ladder": "防腐木梯", + "block.engineersdecor.treated_wood_ladder.help": "§6防风雨的木梯。§r往上/下看会爬得更快。", + "block.engineersdecor.clinker_brick_stairs": "过烧砖楼梯", + "block.engineersdecor.clinker_brick_stairs.help": "§6比原版砖看起来颜色更深,色度也更高。", + "block.engineersdecor.clinker_brick_stained_stairs": "污渍过烧砖楼梯", + "block.engineersdecor.clinker_brick_stained_stairs.help": "§6比原版砖看起来颜色更深,色度也更高。有更多可见的污垢或污迹。", "block.engineersdecor.slag_brick_stairs": "炉渣砖楼梯", - "block.engineersdecor.slag_brick_stairs.help": "§6灰褐色砖块楼梯.", + "block.engineersdecor.slag_brick_stairs.help": "§6一种灰棕色砖块楼梯。", "block.engineersdecor.rebar_concrete_stairs": "钢筋混凝土楼梯", - "block.engineersdecor.rebar_concrete_stairs.help": "§6钢筋混凝土楼梯.§r 昂贵,但像黑曜石一样防苦力怕.", - "block.engineersdecor.rebar_concrete_tile_stairs": "Rebar Concrete Tile Stairs", - "block.engineersdecor.treated_wood_pole": "直立处理木杆", - "block.engineersdecor.treated_wood_pole.help": "§6具有导线继电器直径的直极片段.§r\n如果需要特殊的特殊长度,或作为结构的支撑,可以作为线柱的替代品.", - "block.engineersdecor.treated_wood_pole_head": "Straight Treated Wood Pole Head/Foot", - "block.engineersdecor.treated_wood_pole_support": "Straight Treated Wood Pole Support", - "block.engineersdecor.thick_steel_pole": "Straight Thick Steel Pole", - "block.engineersdecor.thin_steel_pole": "Straight Thin Steel Pole", - "block.engineersdecor.thin_steel_pole_head": "Straight Thin Steel Pole head/foot", - "block.engineersdecor.thick_steel_pole_head": "Straight Thick Steel Pole Head/Foot", - "block.engineersdecor.steel_double_t_support": "Steel Double T Support", - "block.engineersdecor.treated_wood_table": "经过处理的木桌", - "block.engineersdecor.treated_wood_table.help": "§6坚固的四足木桌.", - "block.engineersdecor.steel_table": "Steel Table", - "block.engineersdecor.steel_floor_grating": "Steel Floor Grating", - "block.engineersdecor.treated_wood_stool": "Treated Wood Stool", - "block.engineersdecor.treated_wood_crafting_table": "Treated Wood Crafting Table", - "block.engineersdecor.treated_wood_side_table": "Treated Wood Side Table", - "block.engineersdecor.iron_inset_light": "Inset Light", - "block.engineersdecor.treated_wood_window": "Treated Wood Window", - "block.engineersdecor.treated_wood_windowsill": "Treated Wood Window Sill", - "block.engineersdecor.treated_wood_broad_windowsill": "Broad Treated Wood Window Sill", - "block.engineersdecor.steel_framed_window": "Steel Framed Window", - "block.engineersdecor.steel_mesh_fence": "Steel Mesh Fence", - "block.engineersdecor.small_lab_furnace": "Small Laboratory Furnace", - "block.engineersdecor.small_electrical_furnace": "Small Electrical Furnace", - "block.engineersdecor.small_waste_incinerator": "Small Waste Incinerator", - "block.engineersdecor.straight_pipe_valve": "Fluid Pipe Check Valve", - "block.engineersdecor.straight_pipe_valve_redstone": "Redstone Controlled Fluid Valve", - "block.engineersdecor.straight_pipe_valve_redstone_analog": "Redstone Analog Fluid Valve", - "block.engineersdecor.passive_fluid_accumulator": "Passive Fluid Accumulator", - "block.engineersdecor.factory_dropper": "Factory Dropper", - "block.engineersdecor.small_mineral_smelter": "Small Mineral Melting Furnace", - "block.engineersdecor.small_solar_panel": "Small Solar Panel", - "block.engineersdecor.small_tree_cutter": "Small Tree Cutter", - "block.engineersdecor.sign_decor": "Sign Plate (Engineer's decor)", - "block.engineersdecor.sign_hotwire": "Sign \"Caution Hot Wire\"", - "block.engineersdecor.sign_mindstep": "Sign \"Mind The Step\"", - "block.engineersdecor.sign_danger": "Sign \"Caution Really Dangerous There\"", - "block.engineersdecor.sign_defense": "Sign \"Caution Defense System Ahead\"", - "block.engineersdecor.sign_factoryarea": "Sign \"Factory Area\"", - "block.engineersdecor.sign_exit": "Exit Sign", - "block.engineersdecor.halfslab_rebar_concrete": "Rebar Concrete Slice", - "block.engineersdecor.halfslab_concrete": "Concrete Slice", - "block.engineersdecor.halfslab_treated_wood": "Treated Wood Slice", - "block.engineersdecor.halfslab_sheetmetal_iron": "Iron Sheet Metal Slice", - "block.engineersdecor.halfslab_sheetmetal_steel": "Steel Sheet Metal Slice", - "block.engineersdecor.halfslab_sheetmetal_copper": "Copper Sheet Metal Slice", - "block.engineersdecor.halfslab_sheetmetal_gold": "Gold Sheet Metal Slice", - "block.engineersdecor.halfslab_sheetmetal_aluminum": "Aluminum Sheet Metal Slice", - "block.engineersdecor.testblock": "ED Test Block (do NOT use)" + "block.engineersdecor.rebar_concrete_stairs.help": "§6钢强化的混凝土楼梯。§r昂贵但像黑曜石一样防爬行者爆炸。", + "block.engineersdecor.rebar_concrete_tile_stairs": "钢筋混凝土砖楼梯", + "block.engineersdecor.rebar_concrete_tile_stairs.help": "§6钢强化的混凝土砖楼梯。§r昂贵但像黑曜石一样防爬行者爆炸。", + "block.engineersdecor.treated_wood_pole": "直防腐木杆", + "block.engineersdecor.treated_wood_pole.help": "§6直杆的一段,有着继电器的直径。§r\n 在需要特殊长度电线杆的时候很有用, 也可以作为结构的柱子。", + "block.engineersdecor.treated_wood_pole_head": "直防腐木杆头/尾", + "block.engineersdecor.treated_wood_pole_head.help": "§6木制部件,适合作为直杆的头或尾。", + "block.engineersdecor.treated_wood_pole_support": "直防腐木杆支撑", + "block.engineersdecor.treated_wood_pole_support.help": "§6重型木制支撑部件,适合作为直杆的头或尾。", + "block.engineersdecor.thick_steel_pole": "直粗钢杆", + "block.engineersdecor.thick_steel_pole.help": "§6一段直空心杆(6x6x16),适合用于结构支撑。", + "block.engineersdecor.thin_steel_pole": "直细钢杆", + "block.engineersdecor.thin_steel_pole.help": "§6一段直空心杆(4x4x16),适合用于结构支撑。", + "block.engineersdecor.thin_steel_pole_head": "直细钢杆头/尾", + "block.engineersdecor.thin_steel_pole_head.help": "§6钢制部件,适合作为细钢杆(4x4x16)的头或尾。", + "block.engineersdecor.thick_steel_pole_head": "直粗钢杆头/尾", + "block.engineersdecor.thick_steel_pole_head.help": "§6钢制部件,适合作为粗钢杆(6x6x16)的头或尾。", + "block.engineersdecor.steel_double_t_support": "钢制双T型支架", + "block.engineersdecor.steel_double_t_support.help": "§6一段水平吊顶支撑梁。", + "block.engineersdecor.treated_wood_table": "防腐木桌", + "block.engineersdecor.treated_wood_table.help": "§6结实的四脚木桌。§r适用于室内和室外使用。", + "block.engineersdecor.steel_table": "钢桌", + "block.engineersdecor.steel_table.help": "§6结实的四脚钢桌。", + "block.engineersdecor.steel_floor_grating": "钢地板格栅", + "block.engineersdecor.steel_floor_grating.help": "§6装饰用钢制地板盖。§r顶端对齐。掉落物会穿过。", + "block.engineersdecor.treated_wood_stool": "防腐木凳", + "block.engineersdecor.treated_wood_stool.help": "§6坚固的木凳。§r适用于室内和室外使用。", + "block.engineersdecor.treated_wood_crafting_table": "防腐木合成台", + "block.engineersdecor.treated_wood_crafting_table.help": "§6坚固,防风防雨。§r内含八个存储格,破坏后保留内容物,没有原版合成书。\n 单击上/下箭头按钮可选择合成历史,单击输出格自动放置物品,单击X按钮 清除合成栏和历史。Shift单击一叠物品:合成格空时转移到存储格, 非空时到合成栏。会自动分配转移的物品。", + "block.engineersdecor.treated_wood_side_table": "防腐木茶几", + "block.engineersdecor.treated_wood_side_table.help": "§6干完活后需要喝杯茶。", + "block.engineersdecor.iron_inset_light": "嵌入灯", + "block.engineersdecor.iron_inset_light.help": "§6小型荧石光源,能嵌入地板、天花板或墙里。§r\n 用于照亮电力光源难以安装的地方。 亮度与火把一样。", + "block.engineersdecor.treated_wood_window": "防腐木窗", + "block.engineersdecor.treated_wood_window.help": "§6木框三层玻璃窗。绝缘良好。§r不像玻璃板一样连接到相邻方块。", + "block.engineersdecor.treated_wood_windowsill": "防腐木窗台", + "block.engineersdecor.treated_wood_windowsill.help": "§6简单的窗户装饰。", + "block.engineersdecor.treated_wood_broad_windowsill": "宽防腐木窗台", + "block.engineersdecor.treated_wood_broad_windowsill.help": "§6简单的窗户装饰。", + "block.engineersdecor.steel_framed_window": "钢框窗", + "block.engineersdecor.steel_framed_window.help": "§6钢框三层玻璃窗。绝缘良好。§r不像玻璃板一样连接到相邻方块。", + "block.engineersdecor.steel_mesh_fence": "钢丝栅栏", + "block.engineersdecor.steel_mesh_fence.help": "§6工业式栅栏。§r\n不与普通栅栏连接。", + "block.engineersdecor.small_lab_furnace": "小型实验室炉", + "block.engineersdecor.small_lab_furnace.help": "§6小型金属壳实验室窑。§r消耗固体燃料,向上排气。 比圆石炉稍微热一点,隔热性也更好,因此效率更高。 有两个用于储存的辅助格。两个堆叠的内部漏斗对输入、输出和燃料进行队列管理。 在辅助格放置一个外置加热器并通入电力可以加快熔炼速度。", + "block.engineersdecor.small_electrical_furnace": "小型电炉", + "block.engineersdecor.small_electrical_furnace.help": "§6小型金属封装穿过式熔炉。§r 自动从输入端获取物品并在输出端物品栏放置物品。 物品能从所有面使用漏斗插入或提取。无法熔炼或烹饪的物品会直接送到出口。 比加热的圆石炉有稍微高的能效比和更快。 先进先出和自动输出一次移动一组物品。自动输出需要一点能量。", + "block.engineersdecor.small_waste_incinerator": "小型垃圾焚烧炉", + "block.engineersdecor.small_waste_incinerator.help": "§6有内部先进先出队列的垃圾桶。§r物品可以从任何一面插入,而且 直到队列满都会保留。一旦超过队列上限,最老的物品会被焚毁。 通入RF/FE会增加处理速度。破坏时保留内部未销毁的物品。", + "block.engineersdecor.straight_pipe_valve": "输液管止回阀", + "block.engineersdecor.straight_pipe_valve.help": "§6一段直输液管。§r单向传递流体。 侧面不会与管道连接。会减少流速。潜行能反方向放置。", + "block.engineersdecor.straight_pipe_valve_redstone": "红石控制流体阀", + "block.engineersdecor.straight_pipe_valve_redstone.help": "§6一段直输液管。§r单向传递流体。 侧面不会与管道连接。会减少流速。潜行能反方向放置。 没有红石信号时断流。", + "block.engineersdecor.straight_pipe_valve_redstone_analog": "红石模拟流体阀", + "block.engineersdecor.straight_pipe_valve_redstone_analog.help": "§6一段直输液管。§r单向传递流体。 侧面不会与管道连接。会减少流速。潜行能反方向放置。 没有红石信号时断流,流速与红石信号强度从1到14线性增长, 15时流速上限达到最大。", + "block.engineersdecor.passive_fluid_accumulator": "被动流体累积器。", + "block.engineersdecor.passive_fluid_accumulator.help": "§6基于真空吸力的流体收集器。§r有一个输出面,其他面都是输入。 当从输出面被泵抽取时,从输入面邻接储罐抽取液体。", + "block.engineersdecor.factory_dropper": "工厂掉落器", + "block.engineersdecor.factory_dropper.help": "§6适用于高级工厂自动化的掉落器。§r有十二个轮询选择的储物格。 掉落的力度、角度、一叠数量和冷却延时可在GUI调节。三个 内部比较槽带有逻辑与或逻辑或功能,可用作内部触发源。内部触发 还能和外部红石信号触发再进行逻辑与或逻辑或。触发模拟按钮仅作测试用途。 当内部触发条件满足时,预先打开卷帘门。所有符合条件的物品 会同时掉落。点击GUI的各处来了解如何运作。", + "block.engineersdecor.factory_hopper": "Factory Hopper", + "block.engineersdecor.small_mineral_smelter": "小型矿物熔炼炉", + "block.engineersdecor.small_mineral_smelter.help": "§6高温、高绝缘电熔石炉。§r\n 把矿物块加热成岩浆块,最后变成熔岩。由于 小型化的设备大小,该过程效率不高,需要大量时间和能源 来液化一块石头。", + "block.engineersdecor.small_solar_panel": "小型太阳能板", + "block.engineersdecor.small_solar_panel.help": "§6暴露在阳光下时产生少量能量。§r\n 用于低消耗地在远程系统给低压电容器充电。 内部电荷泵电路积累并频繁输出RF。产出取决于时间 和天气。", + "block.engineersdecor.small_tree_cutter": "小型砍树机", + "block.engineersdecor.small_tree_cutter.help": "§6砍倒正前方的树。§r\n 不收集木材。通入红石信号停用。 提供RF来加快砍树速度。(没有的话会很慢。)", + "block.engineersdecor.sign_decor": "标志板(工程师的装饰)", + "block.engineersdecor.sign_decor.help": "§6这不应该可合成或在JEI看到。用于创造模式的物品栏标签和截屏。", + "block.engineersdecor.sign_hotwire": "指示牌 \"小心电线\"", + "block.engineersdecor.sign_hotwire.help": "§6电气危害警告。不要忘记在高压线周围放置,否则下次审计时你会发现不合格。", + "block.engineersdecor.sign_mindstep": "指示牌 \"小心脚滑\"", + "block.engineersdecor.sign_mindstep.help": "§6能(水平)放在墙上。", + "block.engineersdecor.sign_danger": "指示牌 \"小心危险\"", + "block.engineersdecor.sign_danger.help": "§6通用危险警告。", + "block.engineersdecor.sign_defense": "指示牌 \"小心防御系统\"", + "block.engineersdecor.sign_defense.help": "§6用于警告炮塔、特斯拉线圈和陷阱。", + "block.engineersdecor.sign_factoryarea": "指示牌 \"工厂区域\"", + "block.engineersdecor.sign_factoryarea.help": "§6用于指示真的很大的机器所在的建筑和区域。", + "block.engineersdecor.sign_exit": "出口指示牌", + "block.engineersdecor.halfslab_rebar_concrete": "强化混凝土切片", + "block.engineersdecor.halfslab_rebar_concrete.help": "§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。", + "block.engineersdecor.halfslab_concrete": "混凝土切片", + "block.engineersdecor.halfslab_concrete.help": "§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。", + "block.engineersdecor.halfslab_treated_wood": "防腐木切片", + "block.engineersdecor.halfslab_treated_wood.help": "§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。", + "block.engineersdecor.halfslab_sheetmetal_iron": "铁板金属块切片", + "block.engineersdecor.halfslab_sheetmetal_iron.help": "§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。", + "block.engineersdecor.halfslab_sheetmetal_steel": "钢板金属块切片", + "block.engineersdecor.halfslab_sheetmetal_steel.help": "§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。", + "block.engineersdecor.halfslab_sheetmetal_copper": "铜板金属块切片", + "block.engineersdecor.halfslab_sheetmetal_copper.help": "§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。", + "block.engineersdecor.halfslab_sheetmetal_gold": "金板金属块切片", + "block.engineersdecor.halfslab_sheetmetal_gold.help": "§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。", + "block.engineersdecor.halfslab_sheetmetal_aluminum": "铝板金属块切片", + "block.engineersdecor.halfslab_sheetmetal_aluminum.help": "§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。", + "block.engineersdecor.testblock": "ED测试方块(不要使用)(do NOT use)", + "block.engineersdecor.testblock.help": "§6不可合成的测试方块,有着经常变动的测试功能,不要使用,最坏可能会游戏崩溃!!" } \ No newline at end of file diff --git a/1.14/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model.json b/1.14/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model.json new file mode 100644 index 0000000..5ccc628 --- /dev/null +++ b/1.14/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model.json @@ -0,0 +1,255 @@ +{ + "parent": "block/cube", + "textures": { + "t": "engineersdecor:block/device/factory_hopper_top", + "b": "engineersdecor:block/device/factory_hopper_bottom", + "s": "engineersdecor:block/device/factory_hopper_side", + "f": "engineersdecor:block/device/factory_hopper_front", + "particle": "engineersdecor:block/device/factory_hopper_side" + }, + "elements": [ + { + "from": [2, 7, 2], + "to": [14, 11, 14], + "faces": { + "north": {"uv": [2, 5, 14, 9], "texture": "#f"}, + "east": {"uv": [2, 5, 14, 9], "texture": "#s"}, + "south": {"uv": [2, 5, 14, 9], "texture": "#s"}, + "west": {"uv": [2, 5, 14, 9], "texture": "#s"}, + "up": {"uv": [2, 2, 14, 14], "texture": "#t"}, + "down": {"uv": [2, 2, 14, 14], "texture": "#b"} + } + }, + { + "from": [4, 1, 4], + "to": [12, 7, 12], + "faces": { + "north": {"uv": [4, 9, 12, 15], "texture": "#f"}, + "east": {"uv": [4, 9, 12, 15], "texture": "#s"}, + "south": {"uv": [4, 9, 12, 15], "texture": "#s"}, + "west": {"uv": [4, 9, 12, 15], "texture": "#s"}, + "up": {"uv": [4, 4, 12, 12], "texture": "#s"}, + "down": {"uv": [4, 4, 12, 12], "texture": "#b"} + } + }, + { + "from": [0, 4, 5], + "to": [2, 10, 11], + "faces": { + "north": {"uv": [14, 6, 16, 12], "texture": "#f"}, + "east": {"uv": [5, 6, 11, 12], "texture": "#s"}, + "south": {"uv": [0, 6, 2, 12], "texture": "#s"}, + "west": {"uv": [5, 6, 11, 12], "texture": "#s"}, + "up": {"uv": [0, 5, 2, 11], "texture": "#s"}, + "down": {"uv": [0, 5, 2, 11], "texture": "#b"} + } + }, + { + "from": [14, 4, 5], + "to": [16, 10, 11], + "faces": { + "north": {"uv": [0, 6, 2, 12], "texture": "#f"}, + "east": {"uv": [5, 6, 11, 12], "texture": "#s"}, + "south": {"uv": [14, 6, 16, 12], "texture": "#s"}, + "west": {"uv": [5, 6, 11, 12], "texture": "#s"}, + "up": {"uv": [14, 5, 16, 11], "texture": "#s"}, + "down": {"uv": [14, 5, 16, 11], "texture": "#b"} + } + }, + { + "from": [2, 3, 5], + "to": [4, 5, 11], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [12, 11, 14, 13], "texture": "#f"}, + "east": {"uv": [5, 11, 11, 13], "texture": "#s"}, + "south": {"uv": [2, 11, 4, 13], "texture": "#s"}, + "west": {"uv": [5, 11, 11, 13], "texture": "#s"}, + "up": {"uv": [2, 5, 4, 11], "texture": "#s"}, + "down": {"uv": [2, 5, 4, 11], "texture": "#b"} + } + }, + { + "from": [12, 3, 5], + "to": [14, 5, 11], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [2, 11, 4, 13], "texture": "#f"}, + "east": {"uv": [5, 11, 11, 13], "texture": "#s"}, + "south": {"uv": [12, 11, 14, 13], "texture": "#s"}, + "west": {"uv": [5, 11, 11, 13], "texture": "#s"}, + "up": {"uv": [12, 5, 14, 11], "texture": "#s"}, + "down": {"uv": [12, 5, 14, 11], "texture": "#b"} + } + }, + { + "from": [5, 4, 14], + "to": [11, 10, 16], + "faces": { + "north": {"uv": [5, 6, 11, 12], "texture": "#s"}, + "east": {"uv": [0, 6, 2, 12], "texture": "#s"}, + "south": {"uv": [5, 6, 11, 12], "texture": "#s"}, + "west": {"uv": [14, 6, 16, 12], "texture": "#s"}, + "up": {"uv": [5, 14, 11, 16], "texture": "#s"}, + "down": {"uv": [5, 0, 11, 2], "texture": "#b"} + } + }, + { + "from": [5, 3, 12], + "to": [11, 5, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [5, 11, 11, 13], "texture": "#s"}, + "east": {"uv": [2, 11, 4, 13], "texture": "#s"}, + "south": {"uv": [5, 11, 11, 13], "texture": "#s"}, + "west": {"uv": [12, 11, 14, 13], "texture": "#s"}, + "up": {"uv": [5, 12, 11, 14], "texture": "#s"}, + "down": {"uv": [5, 2, 11, 4], "texture": "#b"} + } + }, + { + "from": [5, 0, 5], + "to": [11, 1, 11], + "faces": { + "north": {"uv": [5, 15, 11, 16], "texture": "#f"}, + "east": {"uv": [5, 15, 11, 16], "texture": "#s"}, + "south": {"uv": [5, 15, 11, 16], "texture": "#s"}, + "west": {"uv": [5, 15, 11, 16], "texture": "#s"}, + "up": {"uv": [5, 5, 11, 11], "texture": "#s"}, + "down": {"uv": [5, 5, 11, 11], "texture": "#b"} + } + }, + { + "from": [5, 1, 1], + "to": [11, 7, 4], + "faces": { + "north": {"uv": [5, 9, 11, 15], "texture": "#f"}, + "east": {"uv": [12, 9, 15, 15], "texture": "#s"}, + "south": {"uv": [5, 9, 11, 15], "texture": "#t"}, + "west": {"uv": [1, 9, 4, 15], "texture": "#s"}, + "up": {"uv": [5, 1, 11, 4], "texture": "#s"}, + "down": {"uv": [5, 12, 11, 15], "texture": "#b"} + } + }, + { + "from": [5, 1, 0], + "to": [11, 2, 1], + "faces": { + "north": {"uv": [5, 14, 11, 15], "texture": "#f"}, + "east": {"uv": [15, 14, 16, 15], "texture": "#s"}, + "south": {"uv": [5, 14, 11, 15], "texture": "#t"}, + "west": {"uv": [0, 14, 1, 15], "texture": "#s"}, + "up": {"uv": [5, 0, 11, 1], "texture": "#s"}, + "down": {"uv": [5, 15, 11, 16], "texture": "#b"} + } + }, + { + "from": [5, 6, 0], + "to": [11, 7, 1], + "faces": { + "north": {"uv": [5, 9, 11, 10], "texture": "#f"}, + "east": {"uv": [15, 9, 16, 10], "texture": "#s"}, + "south": {"uv": [5, 9, 11, 10], "texture": "#t"}, + "west": {"uv": [0, 9, 1, 10], "texture": "#s"}, + "up": {"uv": [5, 0, 11, 1], "texture": "#s"}, + "down": {"uv": [5, 15, 11, 16], "texture": "#s"} + } + }, + { + "from": [5, 2, 0], + "to": [6, 6, 1], + "faces": { + "north": {"uv": [10, 10, 11, 14], "texture": "#f"}, + "east": {"uv": [15, 10, 16, 14], "texture": "#s"}, + "south": {"uv": [5, 10, 6, 14], "texture": "#t"}, + "west": {"uv": [0, 10, 1, 14], "texture": "#s"}, + "up": {"uv": [5, 0, 6, 1], "texture": "#s"}, + "down": {"uv": [5, 15, 6, 16], "texture": "#s"} + } + }, + { + "from": [10, 2, 0], + "to": [11, 6, 1], + "faces": { + "north": {"uv": [5, 10, 6, 14], "texture": "#f"}, + "east": {"uv": [15, 10, 16, 14], "texture": "#s"}, + "south": {"uv": [10, 10, 11, 14], "texture": "#t"}, + "west": {"uv": [0, 10, 1, 14], "texture": "#s"}, + "up": {"uv": [10, 0, 11, 1], "texture": "#s"}, + "down": {"uv": [10, 15, 11, 16], "texture": "#s"} + } + }, + { + "from": [14, 10, 2], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 2, 6], "texture": "#b"}, + "east": {"uv": [0, 0, 14, 6], "texture": "#s"}, + "south": {"uv": [14, 0, 16, 6], "texture": "#s"}, + "west": {"uv": [2, 2, 16, 8], "texture": "#t"}, + "up": {"uv": [14, 2, 16, 16], "texture": "#t"}, + "down": {"uv": [14, 0, 16, 14], "texture": "#b"} + } + }, + { + "from": [0, 10, 0], + "to": [16, 16, 2], + "faces": { + "north": {"uv": [0, 0, 16, 6], "texture": "#f"}, + "east": {"uv": [14, 0, 16, 6], "texture": "#s"}, + "south": {"uv": [0, 2, 16, 8], "texture": "#t"}, + "west": {"uv": [0, 0, 2, 6], "texture": "#s"}, + "up": {"uv": [0, 0, 16, 2], "texture": "#t"}, + "down": {"uv": [0, 14, 16, 16], "texture": "#b"} + } + }, + { + "from": [0, 10, 14], + "to": [14, 16, 16], + "faces": { + "north": {"uv": [2, 2, 16, 8], "texture": "#t"}, + "east": {"uv": [0, 0, 2, 6], "texture": "#s"}, + "south": {"uv": [0, 0, 14, 6], "texture": "#s"}, + "west": {"uv": [14, 0, 16, 6], "texture": "#s"}, + "up": {"uv": [0, 14, 14, 16], "texture": "#t"}, + "down": {"uv": [0, 0, 14, 2], "texture": "#b"} + } + }, + { + "from": [0, 10, 2], + "to": [2, 16, 14], + "faces": { + "north": {"uv": [14, 0, 16, 6], "texture": "#b"}, + "east": {"uv": [2, 2, 14, 8], "texture": "#t"}, + "south": {"uv": [0, 0, 2, 6], "texture": "#t"}, + "west": {"uv": [2, 0, 14, 6], "texture": "#s"}, + "up": {"uv": [0, 2, 2, 14], "texture": "#t"}, + "down": {"uv": [0, 2, 2, 14], "texture": "#b"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [85, 3, -10], + "translation": [1.75, -2.25, -2.25], + "scale": [0.35, 0.35, 0.35] + }, + "firstperson_righthand": { + "rotation": [22, 65, -44], + "translation": [0.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, -0.75, 0], + "scale": [0.2, 0.2, 0.2] + }, + "gui": { + "rotation": [30, 225, 0], + "translation": [0, -0.25, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/1.14/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model_down.json b/1.14/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model_down.json new file mode 100644 index 0000000..7bef361 --- /dev/null +++ b/1.14/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model_down.json @@ -0,0 +1,260 @@ +{ + "parent": "block/cube", + "textures": { + "t": "engineersdecor:block/device/factory_hopper_top", + "b": "engineersdecor:block/device/factory_hopper_bottom", + "s": "engineersdecor:block/device/factory_hopper_side", + "particle": "engineersdecor:block/device/factory_hopper_side" + }, + "elements": [ + { + "from": [2, 7, 2], + "to": [14, 11, 14], + "faces": { + "north": {"uv": [2, 5, 14, 9], "texture": "#s"}, + "east": {"uv": [2, 5, 14, 9], "texture": "#s"}, + "south": {"uv": [2, 5, 14, 9], "texture": "#s"}, + "west": {"uv": [2, 5, 14, 9], "texture": "#s"}, + "up": {"uv": [2, 2, 14, 14], "texture": "#t"}, + "down": {"uv": [2, 2, 14, 14], "texture": "#b"} + } + }, + { + "from": [4, 1, 4], + "to": [12, 7, 12], + "faces": { + "north": {"uv": [4, 9, 12, 15], "texture": "#s"}, + "east": {"uv": [4, 9, 12, 15], "texture": "#s"}, + "south": {"uv": [4, 9, 12, 15], "texture": "#s"}, + "west": {"uv": [4, 9, 12, 15], "texture": "#s"}, + "up": {"uv": [4, 4, 12, 12], "texture": "#s"}, + "down": {"uv": [4, 4, 12, 12], "texture": "#b"} + } + }, + { + "from": [0, 4, 5], + "to": [2, 10, 11], + "faces": { + "north": {"uv": [14, 6, 16, 12], "texture": "#s"}, + "east": {"uv": [5, 6, 11, 12], "texture": "#s"}, + "south": {"uv": [0, 6, 2, 12], "texture": "#s"}, + "west": {"uv": [5, 6, 11, 12], "texture": "#s"}, + "up": {"uv": [0, 5, 2, 11], "texture": "#s"}, + "down": {"uv": [0, 5, 2, 11], "texture": "#b"} + } + }, + { + "from": [14, 4, 5], + "to": [16, 10, 11], + "faces": { + "north": {"uv": [0, 6, 2, 12], "texture": "#s"}, + "east": {"uv": [5, 6, 11, 12], "texture": "#s"}, + "south": {"uv": [14, 6, 16, 12], "texture": "#s"}, + "west": {"uv": [5, 6, 11, 12], "texture": "#s"}, + "up": {"uv": [14, 5, 16, 11], "texture": "#s"}, + "down": {"uv": [14, 5, 16, 11], "texture": "#b"} + } + }, + { + "from": [2, 3, 5], + "to": [4, 5, 11], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [12, 10, 14, 12], "texture": "#s"}, + "east": {"uv": [5, 10, 11, 12], "texture": "#s"}, + "south": {"uv": [2, 10, 4, 12], "texture": "#s"}, + "west": {"uv": [5, 10, 11, 12], "texture": "#s"}, + "up": {"uv": [2, 5, 4, 11], "texture": "#s"}, + "down": {"uv": [2, 5, 4, 11], "texture": "#b"} + } + }, + { + "from": [12, 3, 5], + "to": [14, 5, 11], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [2, 10, 4, 12], "texture": "#s"}, + "east": {"uv": [5, 10, 11, 12], "texture": "#s"}, + "south": {"uv": [12, 10, 14, 12], "texture": "#s"}, + "west": {"uv": [5, 10, 11, 12], "texture": "#s"}, + "up": {"uv": [12, 5, 14, 11], "texture": "#s"}, + "down": {"uv": [12, 5, 14, 11], "texture": "#b"} + } + }, + { + "from": [5, 4, 14], + "to": [11, 10, 16], + "faces": { + "north": {"uv": [5, 6, 11, 12], "texture": "#s"}, + "east": {"uv": [0, 6, 2, 12], "texture": "#s"}, + "south": {"uv": [5, 6, 11, 12], "texture": "#s"}, + "west": {"uv": [14, 6, 16, 12], "texture": "#s"}, + "up": {"uv": [5, 14, 11, 16], "texture": "#s"}, + "down": {"uv": [5, 0, 11, 2], "texture": "#b"} + } + }, + { + "from": [5, 4, 0], + "to": [11, 10, 2], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 8, -6]}, + "faces": { + "north": {"uv": [5, 6, 11, 12], "texture": "#s"}, + "east": {"uv": [14, 6, 16, 12], "texture": "#s"}, + "south": {"uv": [5, 6, 11, 12], "texture": "#s"}, + "west": {"uv": [0, 6, 2, 12], "texture": "#s"}, + "up": {"uv": [5, 0, 11, 2], "texture": "#s"}, + "down": {"uv": [5, 14, 11, 16], "texture": "#b"} + } + }, + { + "from": [5, 3, 12], + "to": [11, 5, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [5, 10, 11, 12], "texture": "#s"}, + "east": {"uv": [2, 10, 4, 12], "texture": "#s"}, + "south": {"uv": [5, 10, 11, 12], "texture": "#s"}, + "west": {"uv": [12, 10, 14, 12], "texture": "#s"}, + "up": {"uv": [5, 12, 11, 14], "texture": "#s"}, + "down": {"uv": [5, 2, 11, 4], "texture": "#s"} + } + }, + { + "from": [5, 3, 2], + "to": [11, 5, 4], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, -2]}, + "faces": { + "north": {"uv": [5, 10, 11, 12], "texture": "#s"}, + "east": {"uv": [12, 10, 14, 12], "texture": "#s"}, + "south": {"uv": [5, 10, 11, 12], "texture": "#s"}, + "west": {"uv": [2, 10, 4, 12], "texture": "#s"}, + "up": {"uv": [5, 2, 11, 4], "texture": "#s"}, + "down": {"uv": [5, 12, 11, 14], "texture": "#b"} + } + }, + { + "from": [5, 0, 10], + "to": [11, 1, 11], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 18]}, + "faces": { + "north": {"uv": [5, 15, 11, 16], "texture": "#b"}, + "east": {"uv": [5, 15, 6, 16], "texture": "#s"}, + "south": {"uv": [5, 15, 11, 16], "texture": "#s"}, + "west": {"uv": [10, 15, 11, 16], "texture": "#s"}, + "up": {"uv": [5, 10, 11, 11], "texture": "#s"}, + "down": {"uv": [5, 5, 11, 6], "texture": "#b"} + } + }, + { + "from": [5, 0, 5], + "to": [11, 1, 6], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 2, 13]}, + "faces": { + "north": {"uv": [5, 15, 11, 16], "texture": "#s"}, + "east": {"uv": [10, 15, 11, 16], "texture": "#s"}, + "south": {"uv": [5, 15, 11, 16], "texture": "#t"}, + "west": {"uv": [5, 15, 6, 16], "texture": "#s"}, + "up": {"uv": [5, 5, 11, 6], "texture": "#s"}, + "down": {"uv": [5, 10, 11, 11], "texture": "#b"} + } + }, + { + "from": [5, 0, 6], + "to": [6, 1, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 6, 14]}, + "faces": { + "north": {"uv": [10, 15, 11, 16], "texture": "#b"}, + "east": {"uv": [6, 15, 10, 16], "texture": "#s"}, + "south": {"uv": [5, 15, 6, 16], "texture": "#t"}, + "west": {"uv": [6, 15, 10, 16], "texture": "#s"}, + "up": {"uv": [5, 6, 6, 10], "texture": "#s"}, + "down": {"uv": [5, 6, 6, 10], "texture": "#b"} + } + }, + { + "from": [10, 0, 6], + "to": [11, 1, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 6, 14]}, + "faces": { + "north": {"uv": [5, 15, 6, 16], "texture": "#b"}, + "east": {"uv": [6, 15, 10, 16], "texture": "#s"}, + "south": {"uv": [10, 15, 11, 16], "texture": "#t"}, + "west": {"uv": [6, 15, 10, 16], "texture": "#s"}, + "up": {"uv": [10, 6, 11, 10], "texture": "#s"}, + "down": {"uv": [10, 6, 11, 10], "texture": "#b"} + } + }, + { + "from": [14, 10, 2], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 2, 6], "texture": "#b"}, + "east": {"uv": [0, 0, 14, 6], "texture": "#s"}, + "south": {"uv": [14, 0, 16, 6], "texture": "#s"}, + "west": {"uv": [2, 2, 16, 8], "texture": "#t"}, + "up": {"uv": [14, 2, 16, 16], "texture": "#t"}, + "down": {"uv": [14, 0, 16, 14], "texture": "#b"} + } + }, + { + "from": [0, 10, 0], + "to": [16, 16, 2], + "faces": { + "north": {"uv": [0, 0, 16, 6], "texture": "#s"}, + "east": {"uv": [14, 0, 16, 6], "texture": "#s"}, + "south": {"uv": [0, 2, 16, 8], "texture": "#t"}, + "west": {"uv": [0, 0, 2, 6], "texture": "#s"}, + "up": {"uv": [0, 0, 16, 2], "texture": "#t"}, + "down": {"uv": [0, 14, 16, 16], "texture": "#b"} + } + }, + { + "from": [0, 10, 14], + "to": [14, 16, 16], + "faces": { + "north": {"uv": [2, 2, 16, 8], "texture": "#t"}, + "east": {"uv": [0, 0, 2, 6], "texture": "#s"}, + "south": {"uv": [0, 0, 14, 6], "texture": "#s"}, + "west": {"uv": [14, 0, 16, 6], "texture": "#s"}, + "up": {"uv": [0, 14, 14, 16], "texture": "#t"}, + "down": {"uv": [0, 0, 14, 2], "texture": "#b"} + } + }, + { + "from": [0, 10, 2], + "to": [2, 16, 14], + "faces": { + "north": {"uv": [14, 0, 16, 6], "texture": "#b"}, + "east": {"uv": [2, 2, 14, 8], "texture": "#t"}, + "south": {"uv": [0, 0, 2, 6], "texture": "#t"}, + "west": {"uv": [2, 0, 14, 6], "texture": "#s"}, + "up": {"uv": [0, 2, 2, 14], "texture": "#t"}, + "down": {"uv": [0, 2, 2, 14], "texture": "#b"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [85, 3, -10], + "translation": [1.75, -2.25, -2.25], + "scale": [0.35, 0.35, 0.35] + }, + "firstperson_righthand": { + "rotation": [22, 65, -44], + "translation": [0.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, -0.75, 0], + "scale": [0.2, 0.2, 0.2] + }, + "gui": { + "rotation": [30, 225, 0], + "translation": [0, -0.25, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/1.14/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model_up.json b/1.14/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model_up.json new file mode 100644 index 0000000..d7f6bed --- /dev/null +++ b/1.14/src/main/resources/assets/engineersdecor/models/block/device/factory_hopper_model_up.json @@ -0,0 +1,255 @@ +{ + "parent": "block/cube", + "textures": { + "t": "engineersdecor:block/device/factory_hopper_top", + "b": "engineersdecor:block/device/factory_hopper_bottom", + "s": "engineersdecor:block/device/factory_hopper_side", + "particle": "engineersdecor:block/device/factory_hopper_side" + }, + "elements": [ + { + "from": [2, 5, 2], + "to": [14, 9, 14], + "faces": { + "north": {"uv": [2, 5, 14, 9], "rotation": 180, "texture": "#s"}, + "east": {"uv": [2, 5, 14, 9], "rotation": 180, "texture": "#s"}, + "south": {"uv": [2, 5, 14, 9], "rotation": 180, "texture": "#s"}, + "west": {"uv": [2, 5, 14, 9], "rotation": 180, "texture": "#s"}, + "up": {"uv": [2, 2, 14, 14], "texture": "#b"}, + "down": {"uv": [2, 2, 14, 14], "texture": "#t"} + } + }, + { + "from": [4, 9, 4], + "to": [12, 15, 12], + "faces": { + "north": {"uv": [4, 9, 12, 15], "rotation": 180, "texture": "#s"}, + "east": {"uv": [4, 9, 12, 15], "rotation": 180, "texture": "#s"}, + "south": {"uv": [4, 9, 12, 15], "rotation": 180, "texture": "#s"}, + "west": {"uv": [4, 9, 12, 15], "rotation": 180, "texture": "#s"}, + "up": {"uv": [4, 4, 12, 12], "texture": "#b"}, + "down": {"uv": [4, 4, 12, 12], "texture": "#s"} + } + }, + { + "from": [0, 6, 5], + "to": [2, 12, 11], + "faces": { + "north": {"uv": [0, 6, 2, 12], "rotation": 180, "texture": "#s"}, + "east": {"uv": [5, 6, 11, 12], "rotation": 180, "texture": "#s"}, + "south": {"uv": [14, 6, 16, 12], "rotation": 180, "texture": "#s"}, + "west": {"uv": [5, 6, 11, 12], "rotation": 180, "texture": "#s"}, + "up": {"uv": [0, 5, 2, 11], "texture": "#b"}, + "down": {"uv": [0, 5, 2, 11], "texture": "#s"} + } + }, + { + "from": [14, 6, 5], + "to": [16, 12, 11], + "faces": { + "north": {"uv": [14, 6, 16, 12], "rotation": 180, "texture": "#s"}, + "east": {"uv": [5, 6, 11, 12], "rotation": 180, "texture": "#s"}, + "south": {"uv": [0, 6, 2, 12], "rotation": 180, "texture": "#s"}, + "west": {"uv": [5, 6, 11, 12], "rotation": 180, "texture": "#s"}, + "up": {"uv": [14, 5, 16, 11], "texture": "#b"}, + "down": {"uv": [14, 5, 16, 11], "texture": "#s"} + } + }, + { + "from": [2, 11, 5], + "to": [4, 13, 11], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 9, 8]}, + "faces": { + "north": {"uv": [2, 10, 4, 12], "rotation": 180, "texture": "#s"}, + "east": {"uv": [5, 10, 11, 12], "rotation": 180, "texture": "#s"}, + "south": {"uv": [12, 10, 14, 12], "rotation": 180, "texture": "#s"}, + "west": {"uv": [5, 10, 11, 12], "rotation": 180, "texture": "#s"}, + "up": {"uv": [2, 5, 4, 11], "texture": "#b"}, + "down": {"uv": [2, 5, 4, 11], "texture": "#s"} + } + }, + { + "from": [12, 11, 5], + "to": [14, 13, 11], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 9, 8]}, + "faces": { + "north": {"uv": [12, 10, 14, 12], "rotation": 180, "texture": "#s"}, + "east": {"uv": [5, 10, 11, 12], "rotation": 180, "texture": "#s"}, + "south": {"uv": [2, 10, 4, 12], "rotation": 180, "texture": "#s"}, + "west": {"uv": [5, 10, 11, 12], "rotation": 180, "texture": "#s"}, + "up": {"uv": [12, 5, 14, 11], "texture": "#b"}, + "down": {"uv": [12, 5, 14, 11], "texture": "#s"} + } + }, + { + "from": [5, 6, 0], + "to": [11, 12, 2], + "faces": { + "north": {"uv": [5, 6, 11, 12], "rotation": 180, "texture": "#s"}, + "east": {"uv": [0, 6, 2, 12], "rotation": 180, "texture": "#s"}, + "south": {"uv": [5, 6, 11, 12], "rotation": 180, "texture": "#s"}, + "west": {"uv": [14, 6, 16, 12], "rotation": 180, "texture": "#s"}, + "up": {"uv": [5, 0, 11, 2], "texture": "#s"}, + "down": {"uv": [5, 14, 11, 16], "texture": "#s"} + } + }, + { + "from": [5, 6, 14], + "to": [11, 12, 16], + "faces": { + "north": {"uv": [5, 6, 11, 12], "rotation": 180, "texture": "#s"}, + "east": {"uv": [14, 6, 16, 12], "rotation": 180, "texture": "#s"}, + "south": {"uv": [5, 6, 11, 12], "rotation": 180, "texture": "#s"}, + "west": {"uv": [0, 6, 2, 12], "rotation": 180, "texture": "#s"}, + "up": {"uv": [5, 14, 11, 16], "texture": "#b"}, + "down": {"uv": [5, 0, 11, 2], "texture": "#s"} + } + }, + { + "from": [5, 11, 2], + "to": [11, 13, 4], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 9, 8]}, + "faces": { + "north": {"uv": [5, 10, 11, 12], "rotation": 180, "texture": "#s"}, + "east": {"uv": [2, 10, 4, 12], "rotation": 180, "texture": "#s"}, + "south": {"uv": [5, 10, 11, 12], "rotation": 180, "texture": "#s"}, + "west": {"uv": [12, 10, 14, 12], "rotation": 180, "texture": "#s"}, + "up": {"uv": [5, 2, 11, 4], "texture": "#s"}, + "down": {"uv": [5, 12, 11, 14], "texture": "#s"} + } + }, + { + "from": [5, 11, 12], + "to": [11, 13, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 9, 8]}, + "faces": { + "north": {"uv": [5, 10, 11, 12], "rotation": 180, "texture": "#s"}, + "east": {"uv": [12, 10, 14, 12], "rotation": 180, "texture": "#s"}, + "south": {"uv": [5, 10, 11, 12], "rotation": 180, "texture": "#s"}, + "west": {"uv": [2, 10, 4, 12], "rotation": 180, "texture": "#s"}, + "up": {"uv": [5, 12, 11, 14], "texture": "#b"}, + "down": {"uv": [5, 2, 11, 4], "texture": "#s"} + } + }, + { + "from": [5, 15, 5], + "to": [11, 16, 6], + "faces": { + "north": {"uv": [5, 15, 11, 16], "rotation": 180, "texture": "#t"}, + "east": {"uv": [5, 15, 6, 16], "rotation": 180, "texture": "#s"}, + "south": {"uv": [5, 15, 11, 16], "rotation": 180, "texture": "#b"}, + "west": {"uv": [10, 15, 11, 16], "rotation": 180, "texture": "#s"}, + "up": {"uv": [5, 5, 11, 6], "texture": "#b"}, + "down": {"uv": [5, 10, 11, 11], "texture": "#s"} + } + }, + { + "from": [5, 15, 10], + "to": [11, 16, 11], + "faces": { + "north": {"uv": [5, 15, 11, 16], "rotation": 180, "texture": "#t"}, + "east": {"uv": [10, 15, 11, 16], "rotation": 180, "texture": "#s"}, + "south": {"uv": [5, 15, 11, 16], "rotation": 180, "texture": "#s"}, + "west": {"uv": [5, 15, 6, 16], "rotation": 180, "texture": "#s"}, + "up": {"uv": [5, 10, 11, 11], "texture": "#b"}, + "down": {"uv": [5, 5, 11, 6], "texture": "#s"} + } + }, + { + "from": [5, 15, 6], + "to": [6, 16, 10], + "faces": { + "north": {"uv": [5, 15, 6, 16], "rotation": 180, "texture": "#t"}, + "east": {"uv": [6, 15, 10, 16], "rotation": 180, "texture": "#s"}, + "south": {"uv": [10, 15, 11, 16], "rotation": 180, "texture": "#b"}, + "west": {"uv": [6, 15, 10, 16], "rotation": 180, "texture": "#s"}, + "up": {"uv": [5, 6, 6, 10], "texture": "#b"}, + "down": {"uv": [5, 6, 6, 10], "texture": "#s"} + } + }, + { + "from": [10, 15, 6], + "to": [11, 16, 10], + "faces": { + "north": {"uv": [10, 15, 11, 16], "rotation": 180, "texture": "#t"}, + "east": {"uv": [6, 15, 10, 16], "rotation": 180, "texture": "#s"}, + "south": {"uv": [5, 15, 6, 16], "rotation": 180, "texture": "#b"}, + "west": {"uv": [6, 15, 10, 16], "rotation": 180, "texture": "#s"}, + "up": {"uv": [10, 6, 11, 10], "texture": "#b"}, + "down": {"uv": [10, 6, 11, 10], "texture": "#s"} + } + }, + { + "from": [14, 0, 0], + "to": [16, 6, 14], + "faces": { + "north": {"uv": [14, 0, 16, 6], "rotation": 180, "texture": "#s"}, + "east": {"uv": [0, 0, 14, 6], "rotation": 180, "texture": "#s"}, + "south": {"uv": [0, 0, 2, 6], "rotation": 180, "texture": "#b"}, + "west": {"uv": [2, 2, 16, 8], "rotation": 180, "texture": "#t"}, + "up": {"uv": [14, 0, 16, 14], "texture": "#b"}, + "down": {"uv": [14, 2, 16, 16], "texture": "#t"} + } + }, + { + "from": [0, 0, 14], + "to": [16, 6, 16], + "faces": { + "north": {"uv": [0, 2, 16, 8], "rotation": 180, "texture": "#t"}, + "east": {"uv": [14, 0, 16, 6], "rotation": 180, "texture": "#s"}, + "south": {"uv": [0, 0, 16, 6], "rotation": 180, "texture": "#s"}, + "west": {"uv": [0, 0, 2, 6], "rotation": 180, "texture": "#s"}, + "up": {"uv": [0, 14, 16, 16], "texture": "#b"}, + "down": {"uv": [0, 0, 16, 2], "texture": "#t"} + } + }, + { + "from": [0, 0, 0], + "to": [14, 6, 2], + "faces": { + "north": {"uv": [0, 0, 14, 6], "rotation": 180, "texture": "#s"}, + "east": {"uv": [0, 0, 2, 6], "rotation": 180, "texture": "#s"}, + "south": {"uv": [2, 2, 16, 8], "rotation": 180, "texture": "#t"}, + "west": {"uv": [14, 0, 16, 6], "rotation": 180, "texture": "#s"}, + "up": {"uv": [0, 0, 14, 2], "texture": "#b"}, + "down": {"uv": [0, 14, 14, 16], "texture": "#t"} + } + }, + { + "from": [0, 0, 2], + "to": [2, 6, 14], + "faces": { + "north": {"uv": [0, 0, 2, 6], "rotation": 180, "texture": "#t"}, + "east": {"uv": [2, 2, 14, 8], "rotation": 180, "texture": "#t"}, + "south": {"uv": [14, 0, 16, 6], "rotation": 180, "texture": "#b"}, + "west": {"uv": [2, 0, 14, 6], "rotation": 180, "texture": "#s"}, + "up": {"uv": [0, 2, 2, 14], "texture": "#b"}, + "down": {"uv": [0, 2, 2, 14], "texture": "#t"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [85, 3, -10], + "translation": [1.75, -2.25, -2.25], + "scale": [0.35, 0.35, 0.35] + }, + "firstperson_righthand": { + "rotation": [22, 65, -44], + "translation": [0.5, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, -0.75, 0], + "scale": [0.2, 0.2, 0.2] + }, + "gui": { + "rotation": [30, 225, 0], + "translation": [0, -0.25, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/1.14/src/main/resources/assets/engineersdecor/models/item/factory_hopper.json b/1.14/src/main/resources/assets/engineersdecor/models/item/factory_hopper.json new file mode 100644 index 0000000..f20cb92 --- /dev/null +++ b/1.14/src/main/resources/assets/engineersdecor/models/item/factory_hopper.json @@ -0,0 +1 @@ +{ "parent": "engineersdecor:block/device/factory_hopper_model" } \ No newline at end of file diff --git a/1.14/src/main/resources/assets/engineersdecor/textures/block/device/factory_hopper_bottom.png b/1.14/src/main/resources/assets/engineersdecor/textures/block/device/factory_hopper_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..17a4f18fc4edd2850054db05d06e50074c989ba4 GIT binary patch literal 438 zcmV;n0ZIOeP)L_t(I%WYG+jzTdE93P3EXpm?q z`8NKYnjYd~3uKekZlp+2;u+7_G2QR?BqEp@m>D7hcSmM|h~VyEW&i*Yp%yd4%%Bm0 zIVVH}03ad|ktVDS01*LZhPxvoKtxb?#~1^diTC@B%Bd3%u_j|YgTRTTJoy>^VMermwXeOXpA z6VKm8iSJ-5Xqcw^OYoqE=>RpH3C)?rqN5pgCvPV~o)WA_A)VA*ec3 z`!W-!(+Na`*XspUZI$~nvu_)#uSIydT>7`Iwf=ysxLN=aX`i>-tpOG2?)^XZHzpz+ z$I;*l+O1V^*)y{~>wZ}vX2x2pi&rzS*6M+)Sy2ET3;;D7{|!!&S38**Dk4~G{rdB} gntiAuqO%v-4XP)>Q?Z)+b#oYm@wX&`&5kYGW z5#j6WYs9tI9s&S=e}CL=H`a9pV87oJ5t!MaFf)FCf4Sf9qph4$A|h~i4u=D!6jYU3 zE3Gxm3=ttBNGT1m*4jhB-8r33BdA|hMO8^D0pRWx#Q$X58<0L}bkVnPi@4cDo&=6wK`5K@U__wrvC8d_E6cRpod*zVtp#(}N-+5E0Jj z^VqVEDI)B4J8G@;LeE|R8F%ON z^K;Od8SYN*JO51J?i`OtR24HDKDhfBbEn9CZJ*tKe}5mMs!Gn8x3{;kT-}G168~uE VW7bFI<=p@P002ovPDHLkV1lO-?R@|M literal 0 HcmV?d00001 diff --git a/1.14/src/main/resources/assets/engineersdecor/textures/block/device/factory_hopper_side.png b/1.14/src/main/resources/assets/engineersdecor/textures/block/device/factory_hopper_side.png new file mode 100644 index 0000000000000000000000000000000000000000..d88e148038222d1ea3ac5726b9cd9048d515427e GIT binary patch literal 524 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 CD&Two literal 0 HcmV?d00001 diff --git a/readme.md b/readme.md index 3e66384..072c1bd 100644 --- a/readme.md +++ b/readme.md @@ -55,6 +55,18 @@ looking manufacturing contraptions. Current feature set: Provides redstone pulse mode (drop like a vanilla dropper) or continuous mode (continue dropping as long as the redstone signal is on). +- *Factory Hopper*: Hopper with configurable stack transfer size (1 to 32), transfer + delay, and collection range (default like hopper, area max 9x9). Can also be placed + upwards. Has 24 slots, keeps its inventory when being broken and relocated. Tries + to insert smartly, so that existing stacks in the target inventory are filled up first + before empty slots are used. The redstone signal polarity can be inverted to enable + the hopper instead of blocking it, and the reaction to redstone signal can be selected + between "continuous" (like the vanilla hopper) or "pulsed" (means "edge detection", + insertion like a dispenser or dropper). Default behaviour when placing is vanilla + hopper behaviour. Note that, when collecting items, it waits until the items are + allowed to be picked up and on the ground. This prevents that the hopper snatches + blocks that you break when building before you can pick them up yourself. + - *Small Waste Incinerator*: Buffered and delayed item disposal device. 16 fifo slots are filled when new items are pushed in from any side. A GUI allows to take out accidentally trashed items or put in items to get rid of. When the fifo @@ -86,19 +98,16 @@ looking manufacturing contraptions. Current feature set: - *Concrete Wall*: Solid concrete wall (not the vanilla wall design). -- *Treated Wood Ladder*: Stylish ladder, climbing is faster if looking up/down and not - sneaking (but not OP-fast). - -- *Metal Rung Ladder*: Industrial wall-fixed ladder with horizontal bent rods. Climbing - is faster if looking up/down and not sneaking. - -- *Staggered Metal Steps*: Industrial wall-fixed sparse ladder with steps in a zip pattern. - Climbing is faster when looking up/down and not sneaking. +- *Ladders*: *Metal Rung Ladder*: Industrial wall-fixed ladder with horizontal bent + rods. Climbing is faster if looking up/down and not sneaking. *Staggered Metal Steps*: + Industrial wall-fixed sparse ladder with steps in a zip pattern. *Treated Wood Ladder*: + Stylish wood ladder, also with faster climbing. - *Panzer Glass*: Reinforced, dark gray tinted glass block. Explosion-proof. Faint structural lines are visible, multiple texture variations for seemless look. -- *Treated Wood Table*: Four leg table made out of treated wood. +- *Tables*: *Treated Wood Table*: Four leg table made out of treated wood. *Steel table*: + Metal table known from industrial assembly lines or Clean Rooms. - *Treated Wood Stool*: Simple small stool fitting to the table. You can sit on it, and also mobs will occationally do that (only mobs which actually can sit). @@ -145,7 +154,7 @@ looking manufacturing contraptions. Current feature set: - *Small Tree Cutter*: A slab sized device that chops a tree in front of it. Needs by default about one minute, with RF power less than 10 seconds. Useful to build a contraptive automated - tree farm. + tree farm. Also chops trees of the *Dynamic Trees* mod. - *Small Mineral Smelter*: Device that slowly converts most stones or sands to magma blocks and finally to lava. Needs a lot of power. When the lava is cooled down in the smelter by removing