1.14: Small Tree Cutter and Block Placer/Planter ported. Factory Hopper recipe added.

This commit is contained in:
stfwi 2019-10-29 18:08:50 +01:00
parent 297b840b65
commit 5d04509eca
36 changed files with 1915 additions and 13 deletions

View file

@ -5,4 +5,4 @@ version_minecraft=1.14.4
version_forge_minecraft=1.14.4-28.1.68
version_fml_mappings=20190719-1.14.3
version_jei=1.14.4:6.0.0.10
version_engineersdecor=1.0.15-b1
version_engineersdecor=1.0.15-b2

View file

@ -1,6 +1,7 @@
{
"homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/",
"1.14.4": {
"1.0.15-b2": "[!] Forge version requirement set to 1.14.4-28.1.68 or higher.\n[A] Added Factory Block Placer and Planter.\n[A] Added Small Tree Cutter.",
"1.0.15-b1": "[A] Added Floor Edge Light.\n[U] Updated to Forge1.14.4-28.1.68/20190719-1.14.3.",
"1.0.14-b1": "[U] Updated to Forge 1.14.4-28.1.40/20190719-1.14.3.\n[A] Factory Hopper added (configurable hopper and item collector).\n[M] Switched to integrated loot table generation.\n[M] Lang file zh_cn updated (scikirbypoke, PR#53).",
"1.0.13-b2": "[A] Added Steel Mesh Fence.\n[A] Added Broad Window Sill.",
@ -28,6 +29,6 @@
},
"promos": {
"1.14.4-recommended": "",
"1.14.4-latest": "1.0.15-b1"
"1.14.4-latest": "1.0.15-b2"
}
}

View file

@ -11,6 +11,10 @@ Mod sources for Minecraft version 1.14.4.
## Version history
- v1.0.15-b2 [!] Forge version requirement set to 1.14.4-28.1.68 or higher.
[A] Added Factory Block Placer and Planter.
[A] Added Small Tree Cutter.
- v1.0.15-b1 [A] Added Floor Edge Light.
[U] Updated to Forge1.14.4-28.1.68/20190719-1.14.3.

View file

@ -368,6 +368,12 @@ public class ModContent
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,15)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "factory_dropper"));
public static final BlockDecorPlacer FACTORY_PLACER = (BlockDecorPlacer)(new BlockDecorPlacer(
BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_REDSTONE_CONTROLLED,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.METAL),
ModAuxiliaries.getPixeledAABB(2,2,2, 14,14,14)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "factory_placer"));
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),
@ -392,6 +398,12 @@ public class ModContent
ModAuxiliaries.getPixeledAABB(0,0,0, 16,11.5,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_solar_panel"));
public static final BlockDecorTreeCutter SMALL_TREE_CUTTER = (BlockDecorTreeCutter)(new BlockDecorTreeCutter(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,8,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_tree_cutter"));
public static final BlockDecorPipeValve STRAIGHT_CHECK_VALVE = (BlockDecorPipeValve)(new BlockDecorPipeValve(
BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL),
@ -471,10 +483,12 @@ public class ModContent
TREATED_WOOD_CRAFTING_TABLE,
SMALL_LAB_FURNACE,
FACTORY_DROPPER,
FACTORY_PLACER,
FACTORY_HOPPER,
SMALL_ELECTRICAL_FURNACE,
SMALL_WASTE_INCINERATOR,
SMALL_MINERAL_SMELTER,
SMALL_TREE_CUTTER,
SMALL_SOLAR_PANEL,
CLINKER_BRICK_BLOCK,
CLINKER_BRICK_SLAB,
@ -567,6 +581,11 @@ public class ModContent
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_factory_dropper");
public static final TileEntityType<?> TET_FACTORY_PLACER = TileEntityType.Builder
.create(BlockDecorPlacer.BTileEntity::new, FACTORY_PLACER)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_factory_placer");
public static final TileEntityType<?> TET_FACTORY_HOPPER = TileEntityType.Builder
.create(BlockDecorHopper.BTileEntity::new, FACTORY_HOPPER)
.build(null)
@ -597,18 +616,25 @@ public class ModContent
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_solar_panel");
public static final TileEntityType<?> TET_SMALL_TREE_CUTTER = TileEntityType.Builder
.create(BlockDecorTreeCutter.BTileEntity::new, SMALL_TREE_CUTTER)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_tree_cutter");
private static final TileEntityType<?> tile_entity_types[] = {
TET_TREATED_WOOD_CRAFTING_TABLE,
TET_SMALL_LAB_FURNACE,
TET_FACTORY_DROPPER,
TET_FACTORY_PLACER,
TET_FACTORY_HOPPER,
TET_SMALL_ELECTRICAL_FURNACE,
TET_WASTE_INCINERATOR,
TET_STRAIGHT_PIPE_VALVE,
TET_PASSIVE_FLUID_ACCUMULATOR,
TET_MINERAL_SMELTER,
TET_SMALL_SOLAR_PANEL
TET_SMALL_SOLAR_PANEL,
TET_SMALL_TREE_CUTTER
};
//--------------------------------------------------------------------------------------------------------------------
@ -634,6 +660,7 @@ public class ModContent
public static final ContainerType<BlockDecorCraftingTable.BContainer> CT_TREATED_WOOD_CRAFTING_TABLE;
public static final ContainerType<BlockDecorDropper.BContainer> CT_FACTORY_DROPPER;
public static final ContainerType<BlockDecorPlacer.BContainer> CT_FACTORY_PLACER;
public static final ContainerType<BlockDecorHopper.BContainer> CT_FACTORY_HOPPER;
public static final ContainerType<BlockDecorFurnace.BContainer> CT_SMALL_LAB_FURNACE;
public static final ContainerType<BlockDecorFurnaceElectrical.BContainer> CT_SMALL_ELECTRICAL_FURNACE;
@ -644,6 +671,8 @@ public class ModContent
CT_TREATED_WOOD_CRAFTING_TABLE.setRegistryName(ModEngineersDecor.MODID,"ct_treated_wood_crafting_table");
CT_FACTORY_DROPPER = (new ContainerType<BlockDecorDropper.BContainer>(BlockDecorDropper.BContainer::new));
CT_FACTORY_DROPPER.setRegistryName(ModEngineersDecor.MODID,"ct_factory_dropper");
CT_FACTORY_PLACER = (new ContainerType<BlockDecorPlacer.BContainer>(BlockDecorPlacer.BContainer::new));
CT_FACTORY_PLACER.setRegistryName(ModEngineersDecor.MODID,"ct_factory_placer");
CT_FACTORY_HOPPER = (new ContainerType<BlockDecorHopper.BContainer>(BlockDecorHopper.BContainer::new));
CT_FACTORY_HOPPER.setRegistryName(ModEngineersDecor.MODID,"ct_factory_hopper");
CT_SMALL_LAB_FURNACE = (new ContainerType<BlockDecorFurnace.BContainer>(BlockDecorFurnace.BContainer::new));
@ -658,6 +687,7 @@ public class ModContent
private static final ContainerType<?> container_types[] = {
CT_TREATED_WOOD_CRAFTING_TABLE,
CT_FACTORY_DROPPER,
CT_FACTORY_PLACER,
CT_FACTORY_HOPPER,
CT_SMALL_LAB_FURNACE,
CT_SMALL_ELECTRICAL_FURNACE,
@ -740,6 +770,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_PLACER, BlockDecorPlacer.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);

View file

@ -0,0 +1,747 @@
/*
* @file BlockDecorPlacer.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Block placer and planter, factory automation suitable.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.Networking;
import net.minecraft.block.*;
import net.minecraft.state.StateContainer;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.tileentity.TileEntity;
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.nbt.CompoundNBT;
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.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.util.*;
import net.minecraft.util.math.*;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.util.SoundEvents;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.IPlantable;
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 net.minecraftforge.fml.network.NetworkHooks;
import com.mojang.blaze3d.platform.GlStateManager;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class BlockDecorPlacer extends BlockDecorDirected
{
public BlockDecorPlacer(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
@OnlyIn(Dist.CLIENT)
public BlockRenderLayer getRenderLayer()
{ return BlockRenderLayer.SOLID; }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return VoxelShapes.fullCube(); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context); }
@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 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<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{
final List<ItemStack> stacks = new ArrayList<ItemStack>();
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
@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 TICK_INTERVAL = 40;
public static final int NUM_OF_SLOTS = 18;
public static final int NUM_OF_FIELDS = 3;
///
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 logic_ = LOGIC_INVERTED|LOGIC_CONTINUOUS;
private int current_slot_index_ = 0;
private int tick_timer_ = 0;
protected NonNullList<ItemStack> stacks_;
public static void on_config(int cooldown_ticks)
{
// ModEngineersDecor.logger.info("Config factory placer:");
}
public BTileEntity()
{ this(ModContent.TET_FACTORY_PLACER); }
public BTileEntity(TileEntityType<?> te_type)
{
super(te_type);
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
reset_rtstate();
}
public CompoundNBT clear_getnbt()
{
CompoundNBT nbt = new CompoundNBT();
writenbt(nbt, false);
for(int i=0; i<stacks_.size(); ++i) stacks_.set(i, ItemStack.EMPTY);
reset_rtstate();
block_power_updated_ = false;
return nbt;
}
public void reset_rtstate()
{
block_power_signal_ = false;
block_power_updated_ = false;
}
public void readnbt(CompoundNBT nbt, boolean update_packet)
{
stacks_ = NonNullList.<ItemStack>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.getInt("act_slot_index");
logic_ = nbt.getInt("logic");
}
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("logic", logic_);
}
public void block_updated()
{
boolean powered = world.isBlockPowered(pos);
if(block_power_signal_ != powered) block_power_updated_ = true;
block_power_signal_ = powered;
if(block_power_updated_) {
tick_timer_ = 1;
} else if(tick_timer_ > 4) {
tick_timer_ = 4;
}
}
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 placer"); }
@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 < 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)
{
if((index<0) || (index >= NUM_OF_SLOTS)) return;
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 (index>=0) && (index<NUM_OF_SLOTS); }
@Override
public void clear()
{ for(int i=0; i<stacks_.size(); ++i) stacks_.set(i, ItemStack.EMPTY); } // should search a better vectorizing method here.
// Fields -----------------------------------------------------------------------------------------------
protected final IIntArray fields = new IntArray(BTileEntity.NUM_OF_FIELDS)
{
@Override
public int get(int id)
{
switch(id) {
case 0: return logic_;
case 1: return block_power_signal_ ? 1 : 0;
case 2: return MathHelper.clamp(current_slot_index_, 0, NUM_OF_SLOTS-1);
default: return 0;
}
}
@Override
public void set(int id, int value)
{
switch(id) {
case 0: logic_ = value; return;
case 1: block_power_signal_ = (value != 0); return;
case 2: current_slot_index_ = MathHelper.clamp(value, 0, NUM_OF_SLOTS-1); return;
default: return;
}
}
};
// ISidedInventory --------------------------------------------------------------------------------------
LazyOptional<? extends IItemHandler>[] 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<NUM_OF_SLOTS; ++i) SIDED_INV_SLOTS[i] = i;
}
@Override
public int[] getSlotsForFace(Direction side)
{ return SIDED_INV_SLOTS; }
@Override
public boolean canInsertItem(int index, ItemStack stack, Direction direction)
{ return is_input_slot(index) && isItemValidForSlot(index, stack); }
@Override
public boolean canExtractItem(int index, ItemStack stack, Direction direction)
{ return false; }
// Capability export ------------------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> 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<NUM_OF_SLOTS-1) ? (i+1) : 0; }
private boolean spit_out(Direction facing)
{
ItemStack stack = stacks_.get(current_slot_index_);
ItemStack drop = stack.copy();
stack.shrink(1);
stacks_.set(current_slot_index_, stack);
drop.setCount(1);
for(int i=0; i<8; ++i) {
BlockPos p = pos.offset(facing, i);
if(!world.isAirBlock(p)) continue;
world.addEntity(new ItemEntity(world, (p.getX()+0.5), (p.getY()+0.5), (p.getZ()+0.5), drop));
world.playSound(null, p, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, 0.7f, 0.8f);
break;
}
return true;
}
private boolean try_place(Direction facing)
{
if(world.isRemote) return false;
BlockPos placement_pos = pos.offset(facing);
if(world.getTileEntity(placement_pos) != null) return false;
ItemStack current_stack = ItemStack.EMPTY;
for(int i=0; i<NUM_OF_SLOTS; ++i) {
if(current_slot_index_ >= 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; }
boolean no_space = false;
final Item item = current_stack.getItem();
Block block = (item instanceof IPlantable) ? (((IPlantable)item).getPlant(world, pos).getBlock()) : Block.getBlockFromItem(item);
if(block == Blocks.AIR) {
if(item != null) {
return spit_out(facing); // Item not accepted
} else {
// try next slot
}
} else if(block instanceof IPlantable) {
if(world.isAirBlock(placement_pos)) {
// plant here, block below has to be valid soil.
BlockState soilstate = world.getBlockState(placement_pos.down());
if(!soilstate.getBlock().canSustainPlant(soilstate, world, pos, Direction.UP, (IPlantable)block)) {
block = Blocks.AIR;
}
} else {
// adjacent block is the soil, plant above if the soil is valid.
BlockState soilstate = world.getBlockState(placement_pos);
if(soilstate.getBlock() == block) {
// The plant is already planted from the case above.
block = Blocks.AIR;
no_space = true;
} else if(!world.isAirBlock(placement_pos.up())) {
// If this is the soil an air block is needed above, if that is blocked we can't plant.
block = Blocks.AIR;
no_space = true;
} else if(!soilstate.getBlock().canSustainPlant(soilstate, world, pos, Direction.UP, (IPlantable)block)) {
// Would be space above, but it's not the right soil for the plant.
block = Blocks.AIR;
} else {
// Ok, plant above.
placement_pos = placement_pos.up();
}
}
} else if(!world.getBlockState(placement_pos).getMaterial().isReplaceable()) {
block = Blocks.AIR;
no_space = true;
}
// System.out.println("PLACE " + current_stack + " --> " + block + " at " + placement_pos.subtract(pos) + "( item=" + item + ")");
if(block != Blocks.AIR) {
try {
BlockItemUseContext use_context = null;
{
final FakePlayer placer = net.minecraftforge.common.util.FakePlayerFactory.getMinecraft((ServerWorld)world);
if(placer != null) {
ItemStack placement_stack = current_stack.copy();
placement_stack.setCount(1);
ItemStack held = placer.getHeldItem(Hand.MAIN_HAND);
placer.setHeldItem(Hand.MAIN_HAND, placement_stack);
use_context = new BlockItemUseContext(new ItemUseContext(placer, Hand.MAIN_HAND, new BlockRayTraceResult(new Vec3d(0.5,0,0.5), Direction.DOWN, placement_pos, false)));
placer.setHeldItem(Hand.MAIN_HAND, held);
}
}
final BlockState placement_state = (use_context==null) ? (block.getDefaultState()) : (block.getStateForPlacement(use_context));
if(placement_state == null) {
return spit_out(facing);
} else if(item instanceof BlockItem) {
if(((BlockItem)item).tryPlace(use_context) == ActionResultType.SUCCESS) {
SoundType stype = block.getSoundType(placement_state, world, pos, null);
if(stype != null) world.playSound(null, placement_pos, stype.getPlaceSound(), SoundCategory.BLOCKS, stype.getVolume()*0.6f, stype.getPitch());
} else {
return spit_out(facing);
}
} else {
if(world.setBlockState(placement_pos, placement_state, 1|2|8)) {
SoundType stype = block.getSoundType(placement_state, world, pos, null);
if(stype != null) world.playSound(null, placement_pos, stype.getPlaceSound(), SoundCategory.BLOCKS, stype.getVolume()*0.6f, stype.getPitch());
}
}
current_stack.shrink(1);
stacks_.set(current_slot_index_, current_stack);
return true;
} catch(Throwable e) {
// The block really needs a player or other issues happened during placement.
// A hard crash should not be fired here, instead spit out the item to indicated that this
// block is not compatible.
System.out.println("Exception while trying to place " + e);
world.removeBlock(placement_pos, false);
return spit_out(facing);
}
}
if((!no_space) && (!current_stack.isEmpty())) {
// There is space, but the current plant cannot be planted there, so try next.
for(int i=0; i<NUM_OF_SLOTS; ++i) {
current_slot_index_ = next_slot(current_slot_index_);
if(!stacks_.get(current_slot_index_).isEmpty()) break;
}
}
return false;
}
@Override
public void tick()
{
// Tick cycle pre-conditions
if(world.isRemote) return;
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 BlockState state = world.getBlockState(pos);
if(state == null) { block_power_signal_= false; return; }
final Direction placer_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;
}
// Placing
if(trigger && try_place(placer_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_PLACER, cid);
fields_ = fields;
wpc_ = wpc;
player_ = player_inventory.player;
inventory_ = block_inventory;
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;
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)) {
// Device slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((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("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<BContainer>
{
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(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(0) ^ BTileEntity.LOGIC_INVERTED);
} else if(isPointInRegion(159, 49, 7, 9, mouseX, mouseY)) {
container.onGuiAction("logic", container.field(0) ^ 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_placer_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(2);
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);
}
// redstone input
{
if(container.field(1) != 0) {
blit(x0+133, y0+49, 217, 49, 9, 9);
}
}
// trigger logic
{
int inverter_offset = ((container.field(0) & BTileEntity.LOGIC_INVERTED) != 0) ? 11 : 0;
blit(x0+145, y0+49, 177+inverter_offset, 49, 9, 9);
int pulse_mode_offset = ((container.field(0) & BTileEntity.LOGIC_CONTINUOUS ) != 0) ? 9 : 0;
blit(x0+159, y0+49, 199+pulse_mode_offset, 49, 9, 9);
}
}
}
}

View file

@ -0,0 +1,194 @@
/*
* @file BlockDecorTreeCutter.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Small Tree Cutter
*/
package wile.engineersdecor.blocks;
import net.minecraft.item.BlockItemUseContext;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.*;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import wile.engineersdecor.detail.TreeCutting;
import javax.annotation.Nullable;
import java.util.Random;
public class BlockDecorTreeCutter extends BlockDecorDirectedHorizontal
{
public static final BooleanProperty ACTIVE = BooleanProperty.create("active");
public BlockDecorTreeCutter(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(ACTIVE); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context).with(ACTIVE, false); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BTileEntity(); }
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, World world, BlockPos pos, Random rnd)
{
if((state.getBlock()!=this) || (!state.get(ACTIVE))) return;
final double rv = rnd.nextDouble();
if(rv > 0.8) return;
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ();
final double xc=0.52, xr=rnd.nextDouble()*0.4-0.2, yr=(y-0.3+rnd.nextDouble()*0.2);
switch(state.get(HORIZONTAL_FACING)) {
case WEST: world.addParticle(ParticleTypes.SMOKE, x-xc, yr, z+xr, 0.0, 0.0, 0.0); break;
case EAST: world.addParticle(ParticleTypes.SMOKE, x+xc, yr, z+xr, 0.0, 0.0, 0.0); break;
case NORTH: world.addParticle(ParticleTypes.SMOKE, x+xr, yr, z-xc, 0.0, 0.0, 0.0); break;
default: world.addParticle(ParticleTypes.SMOKE, x+xr, yr, z+xc, 0.0, 0.0, 0.0); break;
}
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, IEnergyStorage
{
public static final int IDLE_TICK_INTERVAL = 40;
public static final int TICK_INTERVAL = 5;
public static final int BOOST_FACTOR = 6;
public static final int DEFAULT_BOOST_ENERGY = 64;
public static final int DEFAULT_CUTTING_TIME_NEEDED = 20 * 60; // 60 secs, so that people don't come to the bright idea to carry one with them.
private static int boost_energy_consumption = DEFAULT_BOOST_ENERGY;
private static int cutting_time_needed = DEFAULT_CUTTING_TIME_NEEDED;
private int tick_timer_;
private int proc_time_elapsed_; // small, not saved in nbt.
private int boost_energy_; // small, not saved in nbt.
public static void on_config(int boost_energy_per_tick)
{
boost_energy_consumption = TICK_INTERVAL * MathHelper.clamp(boost_energy_per_tick, 16, 512);
ModEngineersDecor.logger().info("Config tree cutter: Boost energy consumption:" + boost_energy_consumption + "rf/t");
}
public BTileEntity()
{ super(ModContent.TET_SMALL_TREE_CUTTER); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
// IEnergyStorage ----------------------------------------------------------------------------
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> (IEnergyStorage)this);
@Override
public boolean canExtract()
{ return false; }
@Override
public boolean canReceive()
{ return true; }
@Override
public int getMaxEnergyStored()
{ return boost_energy_consumption; }
@Override
public int getEnergyStored()
{ return boost_energy_; }
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{ return 0; }
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{ // only speedup support, no buffering, not in nbt -> no markdirty
if((boost_energy_ >= boost_energy_consumption) || (maxReceive < boost_energy_consumption)) return 0;
if(!simulate) boost_energy_ = boost_energy_consumption;
return boost_energy_consumption;
}
// Capability export ----------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability== CapabilityEnergy.ENERGY) {
return energy_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// ITickable ------------------------------------------------------------------------------------
@Override
public void tick()
{
if(--tick_timer_ > 0) return;
if(world.isRemote) {
if(!world.getBlockState(pos).get(ACTIVE)) {
tick_timer_ = TICK_INTERVAL;
} else {
tick_timer_ = 1;
world.playSound(pos.getX(), pos.getY(), pos.getZ(), SoundEvents.BLOCK_WOOD_HIT, SoundCategory.BLOCKS, 0.1f, 1.0f, false);
}
} else {
tick_timer_ = TICK_INTERVAL;
final BlockState device_state = world.getBlockState(pos);
final BlockPos tree_pos = pos.offset(device_state.get(HORIZONTAL_FACING));
final BlockState tree_state = world.getBlockState(tree_pos);
if(!TreeCutting.canChop(tree_state) || (world.isBlockPowered(pos))) {
if(device_state.get(ACTIVE)) world.setBlockState(pos, device_state.with(ACTIVE, false), 1|2);
proc_time_elapsed_ = 0;
tick_timer_ = IDLE_TICK_INTERVAL;
return;
}
proc_time_elapsed_ += TICK_INTERVAL;
if(boost_energy_ >= boost_energy_consumption) { boost_energy_ = 0; proc_time_elapsed_ += TICK_INTERVAL*BOOST_FACTOR; }
boolean active = true;
if(proc_time_elapsed_ >= cutting_time_needed) {
proc_time_elapsed_ = 0;
TreeCutting.chopTree(world, tree_state, tree_pos, 512, false);
world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), SoundEvents.BLOCK_WOOD_BREAK, SoundCategory.BLOCKS, 1.0f, 1.0f);
active = false;
}
if(device_state.get(ACTIVE) != active) {
world.setBlockState(pos, device_state.with(ACTIVE, active), 1|2);
}
}
}
}
}

View file

@ -109,6 +109,7 @@ public class ModConfig
public final ForgeConfigSpec.BooleanValue without_waste_incinerator;
public final ForgeConfigSpec.BooleanValue without_sign_plates;
public final ForgeConfigSpec.BooleanValue without_factory_dropper;
public final ForgeConfigSpec.BooleanValue without_factory_placer;
public final ForgeConfigSpec.BooleanValue without_slabs;
public final ForgeConfigSpec.BooleanValue without_halfslabs;
public final ForgeConfigSpec.BooleanValue without_direct_slab_pickup;
@ -247,6 +248,10 @@ public class ModConfig
.translation(ModEngineersDecor.MODID + ".config.without_factory_dropper")
.comment("Disable the factory dropper.")
.define("without_factory_dropper", false);
without_factory_placer = builder
.translation(ModEngineersDecor.MODID + ".config.without_factory_placer")
.comment("Disable the factory placer.")
.define("without_factory_placer", false);
without_slabs = builder
.translation(ModEngineersDecor.MODID + ".config.without_slabs")
.comment("Disable horizontal half-block slab.")
@ -419,6 +424,7 @@ public class ModConfig
if(block instanceof BlockDecorPassiveFluidAccumulator) return COMMON.without_passive_fluid_accumulator.get();
if(block instanceof BlockDecorWasteIncinerator) return COMMON.without_waste_incinerator.get();
if(block instanceof BlockDecorDropper) return COMMON.without_factory_dropper.get();
if(block instanceof BlockDecorPlacer) return COMMON.without_factory_placer.get();
if(block instanceof BlockDecorHalfSlab) return COMMON.without_halfslabs.get();
if(block instanceof BlockDecorLadder) return COMMON.without_ladders.get();
if(block instanceof BlockDecorWindow) return COMMON.without_windows.get();

View file

@ -0,0 +1,176 @@
/*
* @file TreeCutting.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Simple tree cutting algorithm.
*/
package wile.engineersdecor.detail;
import net.minecraft.block.*;
import net.minecraft.util.ResourceLocation;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import com.google.common.collect.ImmutableList;
import java.util.*;
public class TreeCutting
{
private static org.apache.logging.log4j.Logger LOGGER = ModEngineersDecor.logger();
public static boolean canChop(BlockState state)
{ return isLog(state); }
// -------------------------------------------------------------------------------------------------------------------
private static final List<Vec3i> hoffsets = ImmutableList.of(
new Vec3i( 1,0, 0), new Vec3i( 1,0, 1), new Vec3i( 0,0, 1),
new Vec3i(-1,0, 1), new Vec3i(-1,0, 0), new Vec3i(-1,0,-1),
new Vec3i( 0,0,-1), new Vec3i( 1,0,-1)
);
private static boolean isLog(BlockState state)
{ return (state.getBlock() instanceof LogBlock) || (state.getBlock().getTags().contains(new ResourceLocation("minecraft","logs"))); }
private static boolean isSameLog(BlockState a, BlockState b)
{ return (a.getBlock()==b.getBlock()); }
private static boolean isLeaves(BlockState state)
{
if(state.getBlock() instanceof LeavesBlock) return true;
if(state.getBlock().getTags().contains(new ResourceLocation("minecraft","leaves"))) return true;
return false;
}
private static List<BlockPos> findBlocksAround(final World world, final BlockPos centerPos, final BlockState leaf_type_state, final Set<BlockPos> checked, int recursion_left)
{
ArrayList<BlockPos> to_decay = new ArrayList<BlockPos>();
for(int y=-1; y<=1; ++y) {
final BlockPos layer = centerPos.add(0,y,0);
for(Vec3i v:hoffsets) {
BlockPos pos = layer.add(v);
if((!checked.contains(pos)) && (world.getBlockState(pos).getBlock()==leaf_type_state.getBlock())) {
checked.add(pos);
to_decay.add(pos);
if(recursion_left > 0) {
to_decay.addAll(findBlocksAround(world, pos, leaf_type_state, checked, recursion_left-1));
}
}
}
}
return to_decay;
}
private static void breakBlock(World world, BlockPos pos)
{
Block.spawnDrops(world.getBlockState(pos), world, pos);
if(world.setBlockState(pos, world.getFluidState(pos).getBlockState(), 1|2|8)) {} //state.getBlock().onPlayerDestroy(world, pos, state);
}
public static int chopTree(World world, BlockState broken_state, BlockPos startPos, int max_blocks_to_break, boolean without_target_block)
{
if(world.isRemote || !isLog(broken_state)) return 0;
final long ymin = startPos.getY();
final long max_leaf_distance = 6;
Set<BlockPos> checked = new HashSet<BlockPos>();
ArrayList<BlockPos> to_break = new ArrayList<BlockPos>();
ArrayList<BlockPos> to_decay = new ArrayList<BlockPos>();
checked.add(startPos);
// Initial simple layer-up search of same logs. This forms the base corpus, and only leaves and
// leaf-enclosed logs attached to this corpus may be broken/decayed.
{
LinkedList<BlockPos> queue = new LinkedList<BlockPos>();
LinkedList<BlockPos> upqueue = new LinkedList<BlockPos>();
queue.add(startPos);
int cutlevel = 0;
int steps_left = 64;
while(!queue.isEmpty() && (--steps_left >= 0)) {
final BlockPos pos = queue.removeFirst();
// Vertical search
final BlockPos uppos = pos.up();
final BlockState upstate = world.getBlockState(uppos);
if(!checked.contains(uppos)) {
checked.add(uppos);
if(isSameLog(upstate, broken_state)) {
// Up is log
upqueue.add(uppos);
to_break.add(uppos);
steps_left = 64;
} else {
boolean isleaf = isLeaves(upstate);
if(isleaf || world.isAirBlock(uppos) || (upstate.getBlock() instanceof VineBlock)) {
if(isleaf) to_decay.add(uppos);
// Up is air, check adjacent for diagonal up (e.g. Accacia)
for(Vec3i v:hoffsets) {
final BlockPos p = uppos.add(v);
if(checked.contains(p)) continue;
checked.add(p);
final BlockState st = world.getBlockState(p);
final Block bl = st.getBlock();
if(isSameLog(st, broken_state)) {
queue.add(p);
to_break.add(p);
} else if(isLeaves(st)) {
to_decay.add(p);
}
}
}
}
}
// Lateral search
for(Vec3i v:hoffsets) {
final BlockPos p = pos.add(v);
if(checked.contains(p)) continue;
checked.add(p);
if(p.distanceSq(new BlockPos(startPos.getX(), p.getY(), startPos.getZ())) > (3+cutlevel*cutlevel)) continue;
final BlockState st = world.getBlockState(p);
final Block bl = st.getBlock();
if(isSameLog(st, broken_state)) {
queue.add(p);
to_break.add(p);
} else if(isLeaves(st)) {
to_decay.add(p);
}
}
if(queue.isEmpty() && (!upqueue.isEmpty())) {
queue = upqueue;
upqueue = new LinkedList<BlockPos>();
++cutlevel;
}
}
}
{
// Determine lose logs between the leafs
for(BlockPos pos:to_decay) {
int dist = 1;
to_break.addAll(findBlocksAround(world, pos, broken_state, checked, dist));
}
}
if(!to_decay.isEmpty()) {
final BlockState leaf_type_state = world.getBlockState(to_decay.get(0));
final ArrayList<BlockPos> leafs = to_decay;
to_decay = new ArrayList<BlockPos>();
for(BlockPos pos:leafs) {
int dist = 2;
to_decay.add(pos);
to_decay.addAll(findBlocksAround(world, pos, leaf_type_state, checked, dist));
}
}
if(without_target_block) {
checked.remove(startPos);
} else {
to_break.add(startPos);
}
for(BlockPos pos:to_break) breakBlock(world, pos);
for(BlockPos pos:to_decay) breakBlock(world, pos);
{
// And now the bill.
return MathHelper.clamp(((to_break.size()*6/5)+(to_decay.size()/10)-1), 1, 65535);
}
}
}

View file

@ -18,7 +18,7 @@ logoFile="logo.png"
[[dependencies.engineersdecor]]
modId="forge"
mandatory=true
versionRange="[28.0.81,)"
versionRange="[28.1.68,)"
ordering="NONE"
side="BOTH"

View file

@ -0,0 +1,9 @@
{
"forge_marker": 1,
"defaults": {
"model": "engineersdecor:block/device/factory_placer_model"
},
"variants": {
"facing": { "north":{"y":0}, "south":{"y":180}, "west":{"y":270}, "east":{"y":90}, "up": {"x":-90}, "down": {"x":90} }
}
}

View file

@ -0,0 +1,8 @@
{
"forge_marker": 1,
"defaults": { "model": "engineersdecor:block/device/small_tree_cutter_model" },
"variants": {
"facing": { "north": {"y":0}, "south": {"y":180}, "west": {"y":-90}, "east": {"y":90} },
"active": { "true":{ "model": "engineersdecor:block/device/small_tree_cutter_model_active" }, "false":{}}
}
}

View file

@ -0,0 +1,170 @@
{
"parent": "block/cube",
"textures": {
"top": "engineersdecor:block/device/factory_placer_top",
"bottom": "engineersdecor:block/device/factory_placer_bottom",
"side": "engineersdecor:block/device/factory_placer_side",
"particle": "engineersdecor:block/device/factory_placer_side"
},
"elements": [
{
"from": [0, 0, 3],
"to": [16, 16, 16],
"faces": {
"north": {"uv": [0, 0, 16, 16], "texture": "#bottom"},
"east": {"uv": [3, 0, 16, 16], "rotation": 180, "texture": "#side"},
"south": {"uv": [0, 0, 16, 16], "texture": "#top"},
"west": {"uv": [3, 0, 16, 16], "texture": "#side"},
"up": {"uv": [3, 0, 16, 16], "rotation": 90, "texture": "#side"},
"down": {"uv": [3, 0, 16, 16], "rotation": 270, "texture": "#side"}
}
},
{
"from": [15, 0, 0],
"to": [16, 16, 1],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 7]},
"faces": {
"north": {"uv": [0, 0, 1, 16], "texture": "#bottom"},
"east": {"uv": [15, 0, 16, 16], "texture": "#side"},
"south": {"uv": [14, 0, 16, 16], "texture": "#top"},
"west": {"uv": [0, 0, 1, 16], "texture": "#side"},
"up": {"uv": [14, 0, 15, 1], "rotation": 90, "texture": "#side"},
"down": {"uv": [14, 15, 16, 16], "texture": "#side"}
}
},
{
"from": [15, 0, 2],
"to": [16, 16, 3],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 11]},
"faces": {
"north": {"uv": [0, 0, 1, 16], "texture": "#bottom"},
"east": {"uv": [2, 0, 3, 16], "rotation": 180, "texture": "#side"},
"south": {"uv": [15, 0, 16, 16], "texture": "#top"},
"west": {"uv": [2, 0, 4, 16], "texture": "#side"},
"up": {"uv": [15, 2, 16, 4], "rotation": 90, "texture": "#side"},
"down": {"uv": [15, 12, 16, 14], "rotation": 270, "texture": "#side"}
}
},
{
"from": [0, 0, 0],
"to": [1, 16, 1],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 7]},
"faces": {
"north": {"uv": [15, 0, 16, 16], "texture": "#bottom"},
"east": {"uv": [15, 0, 16, 16], "texture": "#side"},
"south": {"uv": [0, 0, 2, 16], "texture": "#top"},
"west": {"uv": [0, 0, 1, 16], "texture": "#side"},
"up": {"uv": [0, 0, 1, 1], "rotation": 90, "texture": "#side"},
"down": {"uv": [0, 15, 2, 16], "texture": "#side"}
}
},
{
"from": [0, 0, 2],
"to": [1, 16, 3],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 11]},
"faces": {
"north": {"uv": [15, 0, 16, 16], "texture": "#bottom"},
"east": {"uv": [2, 0, 3, 16], "texture": "#side"},
"south": {"uv": [0, 0, 1, 16], "texture": "#top"},
"west": {"uv": [2, 0, 3, 16], "texture": "#side"},
"up": {"uv": [0, 2, 1, 3], "rotation": 90, "texture": "#side"},
"down": {"uv": [0, 13, 1, 14], "rotation": 270, "texture": "#side"}
}
},
{
"from": [0, 15, 1],
"to": [1, 16, 2],
"faces": {
"north": {"uv": [15, 0, 16, 1], "texture": "#bottom"},
"east": {"uv": [14, 0, 15, 1], "texture": "#side"},
"south": {"uv": [0, 0, 1, 1], "texture": "#top"},
"west": {"uv": [1, 0, 2, 1], "texture": "#side"},
"up": {"uv": [1, 0, 2, 1], "rotation": 90, "texture": "#side"},
"down": {"uv": [0, 14, 1, 15], "rotation": 270, "texture": "#side"}
}
},
{
"from": [15, 15, 1],
"to": [16, 16, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [23, 8, 8]},
"faces": {
"north": {"uv": [0, 0, 1, 1], "texture": "#bottom"},
"east": {"uv": [14, 0, 15, 1], "texture": "#side"},
"south": {"uv": [15, 0, 16, 1], "texture": "#top"},
"west": {"uv": [1, 0, 2, 1], "texture": "#side"},
"up": {"uv": [15, 1, 16, 2], "rotation": 90, "texture": "#side"},
"down": {"uv": [15, 14, 16, 15], "rotation": 270, "texture": "#side"}
}
},
{
"from": [15, 0, 1],
"to": [16, 1, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [23, -7, 8]},
"faces": {
"north": {"uv": [0, 15, 1, 16], "texture": "#bottom"},
"east": {"uv": [14, 15, 15, 16], "texture": "#side"},
"south": {"uv": [15, 15, 16, 16], "texture": "#top"},
"west": {"uv": [1, 15, 2, 16], "texture": "#side"},
"up": {"uv": [15, 1, 16, 2], "rotation": 90, "texture": "#side"},
"down": {"uv": [15, 14, 16, 15], "rotation": 270, "texture": "#side"}
}
},
{
"from": [0, 0, 1],
"to": [1, 1, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, -7, 8]},
"faces": {
"north": {"uv": [15, 15, 16, 16], "texture": "#bottom"},
"east": {"uv": [14, 15, 15, 16], "texture": "#side"},
"south": {"uv": [0, 15, 1, 16], "texture": "#top"},
"west": {"uv": [1, 15, 2, 16], "texture": "#side"},
"up": {"uv": [0, 1, 1, 2], "rotation": 90, "texture": "#side"},
"down": {"uv": [0, 14, 1, 15], "texture": "#side"}
}
},
{
"from": [1, 15, 2],
"to": [15, 16, 3],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 11]},
"faces": {
"north": {"uv": [1, 0, 15, 1], "texture": "#bottom"},
"east": {"uv": [12, 0, 14, 1], "texture": "#side"},
"south": {"uv": [1, 0, 15, 1], "texture": "#top"},
"west": {"uv": [2, 0, 4, 1], "texture": "#side"},
"up": {"uv": [2, 1, 3, 15], "rotation": 90, "texture": "#side"},
"down": {"uv": [2, 1, 3, 15], "rotation": 270, "texture": "#side"}
}
},
{
"from": [1, 0, 2],
"to": [15, 1, 3],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 11]},
"faces": {
"north": {"uv": [1, 15, 15, 16], "texture": "#bottom"},
"east": {"uv": [12, 15, 14, 16], "texture": "#side"},
"south": {"uv": [1, 15, 15, 16], "texture": "#top"},
"west": {"uv": [2, 15, 4, 16], "texture": "#side"},
"up": {"uv": [2, 1, 3, 15], "rotation": 180, "texture": "#side"},
"down": {"uv": [2, 1, 3, 15], "rotation": 270, "texture": "#side"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [85, 3, -10],
"translation": [1.75, -0.75, -2.25],
"scale": [0.35, 0.35, 0.35]
},
"ground": {
"translation": [0, -0.75, 0],
"scale": [0.2, 0.2, 0.2]
},
"gui": {
"rotation": [30, 225, 0],
"scale": [0.625, 0.625, 0.625]
},
"fixed": {
"scale": [0.5, 0.5, 0.5]
}
}
}

View file

@ -0,0 +1,222 @@
{
"parent": "block/cube",
"textures": {
"2": "engineersdecor:block/device/tree_cutter_side",
"3": "engineersdecor:block/device/tree_cutter_top",
"particle": "engineersdecor:block/device/tree_cutter_side",
"b": "engineersdecor:block/device/tree_cutter_blade_off",
"top": "engineersdecor:block/device/tree_cutter_bottom"
},
"elements": [
{
"from": [0, 0, 0],
"to": [16, 3, 16],
"faces": {
"north": {"uv": [0, 13, 16, 16], "texture": "#2"},
"east": {"uv": [0, 13, 16, 16], "texture": "#2"},
"south": {"uv": [0, 13, 16, 16], "texture": "#2"},
"west": {"uv": [0, 13, 16, 16], "texture": "#2"},
"up": {"uv": [0, 0, 16, 16], "texture": "#3"},
"down": {"uv": [0, 0, 16, 16], "texture": "#top"}
}
},
{
"from": [0, 3, 0],
"to": [3, 8, 16],
"faces": {
"north": {"uv": [13, 0, 16, 5], "texture": "#2"},
"east": {"uv": [0, 3, 16, 8], "texture": "#2"},
"south": {"uv": [0, 8, 3, 13], "texture": "#2"},
"west": {"uv": [0, 8, 16, 13], "texture": "#2"},
"up": {"uv": [0, 0, 3, 16], "texture": "#3"},
"down": {"uv": [0, 0, 3, 16], "texture": "#top"}
}
},
{
"from": [3, 3, 13],
"to": [16, 8, 16],
"faces": {
"north": {"uv": [0, 3, 13, 8], "texture": "#2"},
"east": {"uv": [0, 8, 3, 13], "texture": "#2"},
"south": {"uv": [3, 8, 16, 13], "texture": "#2"},
"west": {"uv": [13, 8, 16, 13], "texture": "#b"},
"up": {"uv": [3, 13, 16, 16], "texture": "#3"},
"down": {"uv": [3, 0, 16, 3], "texture": "#top"}
}
},
{
"from": [15, 3, 0],
"to": [16, 6, 13],
"faces": {
"north": {"uv": [0, 10, 1, 13], "texture": "#2"},
"east": {"uv": [3, 10, 16, 13], "texture": "#2"},
"south": {"uv": [15, 10, 16, 13], "texture": "#b"},
"west": {"uv": [0, 0, 13, 3], "texture": "#2"},
"up": {"uv": [15, 0, 16, 13], "texture": "#3"},
"down": {"uv": [15, 3, 16, 16], "texture": "#top"}
}
},
{
"from": [3, 7, 0],
"to": [5, 8, 13],
"rotation": {"angle": 0, "axis": "y", "origin": [10, 13, 5]},
"faces": {
"north": {"uv": [11, 8, 13, 9], "texture": "#2"},
"east": {"uv": [3, 8, 16, 9], "texture": "#2"},
"south": {"uv": [3, 8, 5, 9], "texture": "#b"},
"west": {"uv": [0, 8, 13, 9], "texture": "#b"},
"up": {"uv": [3, 0, 5, 13], "texture": "#3"},
"down": {"uv": [3, 3, 5, 16], "texture": "#b"}
}
},
{
"from": [5, 6, 12],
"to": [16, 8, 13],
"rotation": {"angle": 0, "axis": "y", "origin": [11, 13, 5]},
"faces": {
"north": {"uv": [0, 0, 11, 2], "texture": "#2"},
"east": {"uv": [3, 8, 4, 10], "texture": "#2"},
"south": {"uv": [5, 8, 16, 10], "texture": "#b"},
"west": {"uv": [12, 8, 13, 10], "texture": "#b"},
"up": {"uv": [5, 12, 16, 13], "texture": "#3"},
"down": {"uv": [5, 3, 16, 4], "texture": "#top"}
}
},
{
"from": [5, 4.5, 4],
"to": [13, 5, 12],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 7.5, 8]},
"faces": {
"north": {"uv": [3, 11, 11, 11.5], "texture": "#b"},
"east": {"uv": [4, 11, 12, 11.5], "texture": "#b"},
"south": {"uv": [5, 11, 13, 11.5], "texture": "#b"},
"west": {"uv": [4, 11, 12, 11.5], "texture": "#b"},
"up": {"uv": [5, 4, 13, 12], "texture": "#b"},
"down": {"uv": [5, 4, 13, 12], "texture": "#b"}
}
},
{
"from": [8, 5, 7],
"to": [10, 5.5, 9],
"faces": {
"north": {"uv": [6, 10.5, 8, 11], "texture": "#2"},
"east": {"uv": [7, 10.5, 9, 11], "texture": "#b"},
"south": {"uv": [8, 10.5, 10, 11], "texture": "#b"},
"west": {"uv": [7, 10.5, 9, 11], "texture": "#b"},
"up": {"uv": [8, 7, 10, 9], "texture": "#b"},
"down": {"uv": [8, 7, 10, 9], "texture": "#b"}
}
},
{
"from": [8, 4, 7],
"to": [10, 4.5, 9],
"faces": {
"north": {"uv": [6, 11.5, 8, 12], "texture": "#b"},
"east": {"uv": [7, 11.5, 9, 12], "texture": "#b"},
"south": {"uv": [8, 11.5, 10, 12], "texture": "#b"},
"west": {"uv": [7, 11.5, 9, 12], "texture": "#b"},
"up": {"uv": [8, 7, 10, 9], "texture": "#b"},
"down": {"uv": [8, 7, 10, 9], "texture": "#b"}
}
},
{
"from": [3, 3.5, 7],
"to": [10, 4, 9],
"faces": {
"north": {"uv": [8, 6, 15, 6.5], "texture": "#2"},
"east": {"uv": [7, 12, 9, 12.5], "texture": "#2"},
"south": {"uv": [3, 12, 10, 12.5], "texture": "#2"},
"west": {"uv": [7, 12, 9, 12.5], "texture": "#2"},
"up": {"uv": [3, 7, 10, 9], "texture": "#2"},
"down": {"uv": [3, 7, 10, 9], "texture": "#2"}
}
},
{
"from": [3, 5.5, 7],
"to": [10, 6, 9],
"faces": {
"north": {"uv": [6, 10, 13, 10.5], "texture": "#2"},
"east": {"uv": [7, 10, 9, 10.5], "texture": "#2"},
"south": {"uv": [3, 10, 10, 10.5], "texture": "#2"},
"west": {"uv": [7, 10, 9, 10.5], "texture": "#2"},
"up": {"uv": [9, 0, 16, 2], "texture": "#2"},
"down": {"uv": [3, 7, 10, 9], "texture": "#2"}
}
},
{
"from": [6, 4.5, 3],
"to": [12, 5, 4],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 7.5, 8]},
"faces": {
"north": {"uv": [4, 11, 10, 11.5], "texture": "#b"},
"east": {"uv": [12, 11, 13, 11.5], "texture": "#b"},
"south": {"uv": [6, 11, 12, 11.5], "texture": "#b"},
"west": {"uv": [3, 11, 4, 11.5], "texture": "#b"},
"up": {"uv": [6, 3, 12, 4], "texture": "#b"},
"down": {"uv": [6, 12, 12, 13], "texture": "#b"}
}
},
{
"from": [4, 4.5, 5],
"to": [5, 5, 11],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 7.5, 8]},
"faces": {
"north": {"uv": [11, 11, 12, 11.5], "texture": "#b"},
"east": {"uv": [5, 11, 11, 11.5], "texture": "#b"},
"south": {"uv": [4, 11, 5, 11.5], "texture": "#b"},
"west": {"uv": [5, 11, 11, 11.5], "texture": "#b"},
"up": {"uv": [4, 5, 5, 11], "texture": "#b"},
"down": {"uv": [4, 5, 5, 11], "texture": "#b"}
}
},
{
"from": [13, 4.5, 5],
"to": [14, 5, 11],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 7.5, 8]},
"faces": {
"north": {"uv": [2, 11, 3, 11.5], "texture": "#b"},
"east": {"uv": [5, 11, 11, 11.5], "texture": "#b"},
"south": {"uv": [13, 11, 14, 11.5], "texture": "#b"},
"west": {"uv": [5, 11, 11, 11.5], "texture": "#b"},
"up": {"uv": [13, 5, 14, 11], "texture": "#b"},
"down": {"uv": [13, 5, 14, 11], "texture": "#b"}
}
},
{
"from": [6, 4.5, 12],
"to": [12, 5, 13],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 7.5, 8]},
"faces": {
"north": {"uv": [4, 11, 10, 11.5], "texture": "#b"},
"east": {"uv": [3, 11, 4, 11.5], "texture": "#b"},
"south": {"uv": [6, 11, 12, 11.5], "texture": "#b"},
"west": {"uv": [12, 11, 13, 11.5], "texture": "#b"},
"up": {"uv": [6, 12, 12, 13], "texture": "#b"},
"down": {"uv": [6, 3, 12, 4], "texture": "#b"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [85, 3, -10],
"translation": [0.75, 0.25, 0.5],
"scale": [0.35, 0.35, 0.35]
},
"firstperson_righthand": {
"rotation": [18, 22, 0],
"translation": [1.25, 0, 0],
"scale": [0.4, 0.4, 0.4]
},
"ground": {
"translation": [0, -1.25, 0],
"scale": [0.2, 0.2, 0.2]
},
"gui": {
"rotation": [30, 225, 0],
"scale": [0.625, 0.625, 0.625]
},
"fixed": {
"scale": [0.5, 0.5, 0.5]
}
}
}

View file

@ -0,0 +1,221 @@
{
"parent": "block/cube",
"textures": {
"2": "engineersdecor:block/device/tree_cutter_side",
"3": "engineersdecor:block/device/tree_cutter_top",
"particle": "engineersdecor:block/device/tree_cutter_side",
"b": "engineersdecor:block/device/tree_cutter_blade",
"top": "engineersdecor:block/device/tree_cutter_bottom"
},
"elements": [
{
"from": [0, 0, 0],
"to": [16, 3, 16],
"faces": {
"north": {"uv": [0, 13, 16, 16], "texture": "#2"},
"east": {"uv": [0, 13, 16, 16], "texture": "#2"},
"south": {"uv": [0, 13, 16, 16], "texture": "#2"},
"west": {"uv": [0, 13, 16, 16], "texture": "#2"},
"up": {"uv": [0, 0, 16, 16], "texture": "#3"},
"down": {"uv": [0, 0, 16, 16], "texture": "#top"}
}
},
{
"from": [0, 3, 0],
"to": [3, 8, 16],
"faces": {
"north": {"uv": [13, 0, 16, 5], "texture": "#2"},
"east": {"uv": [0, 3, 16, 8], "texture": "#2"},
"south": {"uv": [0, 8, 3, 13], "texture": "#2"},
"west": {"uv": [0, 8, 16, 13], "texture": "#2"},
"up": {"uv": [0, 0, 3, 16], "texture": "#3"},
"down": {"uv": [0, 0, 3, 16], "texture": "#top"}
}
},
{
"from": [3, 3, 13],
"to": [16, 8, 16],
"faces": {
"north": {"uv": [0, 3, 13, 8], "texture": "#2"},
"east": {"uv": [0, 8, 3, 13], "texture": "#2"},
"south": {"uv": [3, 8, 16, 13], "texture": "#2"},
"west": {"uv": [13, 8, 16, 13], "texture": "#b"},
"up": {"uv": [3, 13, 16, 16], "texture": "#3"},
"down": {"uv": [3, 0, 16, 3], "texture": "#top"}
}
},
{
"from": [15, 3, 0],
"to": [16, 6, 13],
"faces": {
"north": {"uv": [0, 10, 1, 13], "texture": "#2"},
"east": {"uv": [3, 10, 16, 13], "texture": "#2"},
"south": {"uv": [15, 10, 16, 13], "texture": "#b"},
"west": {"uv": [0, 0, 13, 3], "texture": "#2"},
"up": {"uv": [15, 0, 16, 13], "texture": "#3"},
"down": {"uv": [15, 3, 16, 16], "texture": "#top"}
}
},
{
"from": [3, 7, 0],
"to": [5, 8, 13],
"rotation": {"angle": 0, "axis": "y", "origin": [10, 13, 5]},
"faces": {
"north": {"uv": [11, 8, 13, 9], "texture": "#2"},
"east": {"uv": [3, 8, 16, 9], "texture": "#2"},
"south": {"uv": [3, 8, 5, 9], "texture": "#b"},
"west": {"uv": [0, 8, 13, 9], "texture": "#b"},
"up": {"uv": [3, 0, 5, 13], "texture": "#3"},
"down": {"uv": [3, 3, 5, 16], "texture": "#b"}
}
},
{
"from": [5, 6, 12],
"to": [16, 8, 13],
"rotation": {"angle": 0, "axis": "y", "origin": [11, 13, 5]},
"faces": {
"north": {"uv": [0, 0, 11, 2], "texture": "#2"},
"east": {"uv": [3, 8, 4, 10], "texture": "#2"},
"south": {"uv": [5, 8, 16, 10], "texture": "#b"},
"west": {"uv": [12, 8, 13, 10], "texture": "#b"},
"up": {"uv": [5, 12, 16, 13], "texture": "#3"},
"down": {"uv": [5, 3, 16, 4], "texture": "#top"}
}
},
{
"from": [5, 4.5, -3],
"to": [13, 5, 5],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 7.5, 1]},
"faces": {
"north": {"uv": [5, 13, 13, 13.5], "texture": "#b"},
"east": {"uv": [11, 11, 16, 11.5], "texture": "#b"},
"south": {"uv": [5, 11, 13, 11.5], "texture": "#b"},
"west": {"uv": [0, 11, 5, 11.5], "texture": "#b"},
"up": {"uv": [5, 4, 13, 12], "texture": "#b"},
"down": {"uv": [5, 4, 13, 12], "texture": "#b"}
}
},
{
"from": [8, 5, 0],
"to": [10, 5.5, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 1]},
"faces": {
"north": {"uv": [6, 10.5, 8, 11], "texture": "#2"},
"east": {"uv": [14, 10.5, 16, 11], "texture": "#b"},
"south": {"uv": [8, 10.5, 10, 11], "texture": "#b"},
"west": {"uv": [0, 10.5, 2, 11], "texture": "#b"},
"up": {"uv": [8, 0, 10, 2], "texture": "#b"},
"down": {"uv": [8, 14, 10, 16], "texture": "#b"}
}
},
{
"from": [8, 4, 0],
"to": [10, 4.5, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 1]},
"faces": {
"north": {"uv": [6, 11.5, 8, 12], "texture": "#b"},
"east": {"uv": [14, 11.5, 16, 12], "texture": "#b"},
"south": {"uv": [8, 11.5, 10, 12], "texture": "#b"},
"west": {"uv": [0, 11.5, 2, 12], "texture": "#b"},
"up": {"uv": [8, 0, 10, 2], "texture": "#b"},
"down": {"uv": [8, 14, 10, 16], "texture": "#b"}
}
},
{
"from": [3, 3.5, 0],
"to": [10, 4, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 1]},
"faces": {
"north": {"uv": [8, 6, 15, 6.5], "texture": "#2"},
"east": {"uv": [7, 12, 9, 12.5], "texture": "#2"},
"south": {"uv": [3, 12, 10, 12.5], "texture": "#2"},
"west": {"uv": [7, 12, 9, 12.5], "texture": "#2"},
"up": {"uv": [3, 7, 10, 9], "texture": "#2"},
"down": {"uv": [3, 7, 10, 9], "texture": "#2"}
}
},
{
"from": [3, 5.5, 0],
"to": [10, 6, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 1]},
"faces": {
"north": {"uv": [6, 10, 13, 10.5], "texture": "#2"},
"east": {"uv": [7, 10, 9, 10.5], "texture": "#2"},
"south": {"uv": [3, 10, 10, 10.5], "texture": "#2"},
"west": {"uv": [7, 10, 9, 10.5], "texture": "#2"},
"up": {"uv": [9, 0, 16, 2], "texture": "#2"},
"down": {"uv": [3, 7, 10, 9], "texture": "#2"}
}
},
{
"from": [6, 4.5, -4],
"to": [12, 5, -3],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 7.5, 1]},
"faces": {
"north": {"uv": [7, 12, 13, 12.5], "texture": "#b"},
"east": {"uv": [16, 11, 16, 11.5], "texture": "#b"},
"south": {"uv": [6, 11, 12, 11.5], "texture": "#b"},
"west": {"uv": [0, 11, 0, 11.5], "texture": "#b"},
"up": {"uv": [6, 12, 12, 13], "texture": "#b"},
"down": {"uv": [6, 3, 12, 4], "texture": "#b"}
}
},
{
"from": [4, 4.5, -2],
"to": [5, 5, 4],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 7.5, 1]},
"faces": {
"north": {"uv": [11, 12, 12, 12.5], "texture": "#b"},
"east": {"uv": [12, 11, 16, 11.5], "texture": "#b"},
"south": {"uv": [4, 11, 5, 11.5], "texture": "#b"},
"west": {"uv": [0, 11, 4, 11.5], "texture": "#b"},
"up": {"uv": [4, 4, 5, 12], "texture": "#b"},
"down": {"uv": [4, 5, 5, 11], "texture": "#b"}
}
},
{
"from": [13, 4.5, -2],
"to": [14, 5, 4],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 7.5, 1]},
"faces": {
"north": {"uv": [2, 11, 3, 11.5], "texture": "#b"},
"east": {"uv": [6, 12, 10, 12.5], "texture": "#b"},
"south": {"uv": [13, 11, 14, 11.5], "texture": "#b"},
"west": {"uv": [0, 11, 4, 11.5], "texture": "#b"},
"up": {"uv": [13, 5, 14, 11], "texture": "#b"},
"down": {"uv": [13, 5, 14, 11], "texture": "#b"}
}
},
{
"from": [6, 4.5, 5],
"to": [12, 5, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 7.5, 1]},
"faces": {
"north": {"uv": [4, 11, 10, 11.5], "texture": "#b"},
"east": {"uv": [10, 11, 11, 11.5], "texture": "#b"},
"south": {"uv": [6, 11, 12, 11.5], "texture": "#b"},
"west": {"uv": [5, 11, 6, 11.5], "texture": "#b"},
"up": {"uv": [6, 12, 12, 13], "texture": "#b"},
"down": {"uv": [6, 10, 12, 11], "texture": "#b"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [85, 3, -10],
"translation": [1.75, -0.75, -2.25],
"scale": [0.35, 0.35, 0.35]
},
"ground": {
"translation": [0, -0.75, 0],
"scale": [0.2, 0.2, 0.2]
},
"gui": {
"rotation": [30, 225, 0],
"scale": [0.625, 0.625, 0.625]
},
"fixed": {
"scale": [0.5, 0.5, 0.5]
}
}
}

View file

@ -0,0 +1 @@
{ "parent": "engineersdecor:block/device/factory_placer_model" }

View file

@ -0,0 +1 @@
{ "parent": "engineersdecor:block/device/small_tree_cutter_model" }

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

View file

@ -0,0 +1 @@
{ "animation":{ "frames": [0,1], "frametime":2, "interpolate":false }}

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,26 @@
{
"type": "minecraft:block",
"pools": [
{
"name": "small_tree_cutter_dlt",
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"functions": [
{
"function": "minecraft:copy_name",
"source": "block_entity"
},
{
"function": "minecraft:copy_nbt",
"source": "block_entity",
"ops": []
}
],
"name": "engineersdecor:small_tree_cutter"
}
]
}
]
}

View file

@ -0,0 +1,24 @@
{
"conditions": [
{
"type": "engineersdecor:optional",
"result": "engineersdecor:factory_hopper",
"missing": ["immersiveengineering:material"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"WWW",
"WHW",
"WPW"
],
"key": {
"H": { "item": "minecraft:hopper" },
"P": { "item": "minecraft:iron_ingot" },
"W": { "tag": "minecraft:planks" }
},
"result": {
"item": "engineersdecor:factory_hopper",
"count": 1
}
}

View file

@ -0,0 +1,24 @@
{
"conditions": [
{
"type": "engineersdecor:optional",
"result": "engineersdecor:factory_placer",
"missing": ["immersiveengineering:material"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"WWW",
"WDP",
"WWW"
],
"key": {
"D": { "item": "minecraft:dispenser" },
"P": { "item": "minecraft:iron_ingot" },
"W": { "tag": "minecraft:planks" }
},
"result": {
"item": "engineersdecor:factory_placer",
"count": 1
}
}

View file

@ -0,0 +1,33 @@
{
"conditions": [
{
"type": "engineersdecor:optional",
"result": "engineersdecor:small_solar_panel",
"missing": ["immersiveengineering:metal_device1"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"PPP",
"PAO",
"PRP"
],
"key": {
"O": {
"item": "minecraft:observer"
},
"P": {
"item": "minecraft:iron_ingot"
},
"A": {
"item": "minecraft:iron_axe"
},
"R": {
"item": "minecraft:redstone_block"
}
},
"result": {
"item": "engineersdecor:small_tree_cutter",
"count": 1
}
}